diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-05-31 13:03:24 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-05-31 13:03:24 +0100 |
commit | 5579ba8af5a31591a16b8f0f43053f73d07fb8b8 (patch) | |
tree | 2a0f7e55e01edc9edb2c49c3a94d07da172b1b40 /crates/ra_hir_ty/src | |
parent | d7071eae2cb78547b8345d4c6ba2731a5151c049 (diff) | |
parent | cc6ba84c400417af873462364ba5cd4f6b5ab1f6 (diff) |
Merge #4667
4667: Infer labelled breaks correctly r=flodiebold a=robojumper
Fixes #4663.
Co-authored-by: robojumper <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 45 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/simple.rs | 54 |
3 files changed, 94 insertions, 16 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 957d6e0b5..dc77e88e5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -219,6 +219,17 @@ struct InferenceContext<'a> { | |||
219 | struct BreakableContext { | 219 | struct BreakableContext { |
220 | pub may_break: bool, | 220 | pub may_break: bool, |
221 | pub break_ty: Ty, | 221 | pub break_ty: Ty, |
222 | pub label: Option<name::Name>, | ||
223 | } | ||
224 | |||
225 | fn find_breakable<'c>( | ||
226 | ctxs: &'c mut [BreakableContext], | ||
227 | label: Option<&name::Name>, | ||
228 | ) -> Option<&'c mut BreakableContext> { | ||
229 | match label { | ||
230 | Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), | ||
231 | None => ctxs.last_mut(), | ||
232 | } | ||
222 | } | 233 | } |
223 | 234 | ||
224 | impl<'a> InferenceContext<'a> { | 235 | impl<'a> InferenceContext<'a> { |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 78084cb57..4a98e2deb 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -22,8 +22,8 @@ use crate::{ | |||
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
25 | BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, | 25 | find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, |
26 | TypeMismatch, | 26 | InferenceDiagnostic, TypeMismatch, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
@@ -86,16 +86,20 @@ impl<'a> InferenceContext<'a> { | |||
86 | 86 | ||
87 | self.coerce_merge_branch(&then_ty, &else_ty) | 87 | self.coerce_merge_branch(&then_ty, &else_ty) |
88 | } | 88 | } |
89 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 89 | Expr::Block { statements, tail, .. } => { |
90 | // FIXME: Breakable block inference | ||
91 | self.infer_block(statements, *tail, expected) | ||
92 | } | ||
90 | Expr::TryBlock { body } => { | 93 | Expr::TryBlock { body } => { |
91 | let _inner = self.infer_expr(*body, expected); | 94 | let _inner = self.infer_expr(*body, expected); |
92 | // FIXME should be std::result::Result<{inner}, _> | 95 | // FIXME should be std::result::Result<{inner}, _> |
93 | Ty::Unknown | 96 | Ty::Unknown |
94 | } | 97 | } |
95 | Expr::Loop { body } => { | 98 | Expr::Loop { body, label } => { |
96 | self.breakables.push(BreakableContext { | 99 | self.breakables.push(BreakableContext { |
97 | may_break: false, | 100 | may_break: false, |
98 | break_ty: self.table.new_type_var(), | 101 | break_ty: self.table.new_type_var(), |
102 | label: label.clone(), | ||
99 | }); | 103 | }); |
100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 104 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
101 | 105 | ||
@@ -110,8 +114,12 @@ impl<'a> InferenceContext<'a> { | |||
110 | Ty::simple(TypeCtor::Never) | 114 | Ty::simple(TypeCtor::Never) |
111 | } | 115 | } |
112 | } | 116 | } |
113 | Expr::While { condition, body } => { | 117 | Expr::While { condition, body, label } => { |
114 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 118 | self.breakables.push(BreakableContext { |
119 | may_break: false, | ||
120 | break_ty: Ty::Unknown, | ||
121 | label: label.clone(), | ||
122 | }); | ||
115 | // while let is desugared to a match loop, so this is always simple while | 123 | // while let is desugared to a match loop, so this is always simple while |
116 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 124 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
117 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 125 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
@@ -120,10 +128,14 @@ impl<'a> InferenceContext<'a> { | |||
120 | self.diverges = Diverges::Maybe; | 128 | self.diverges = Diverges::Maybe; |
121 | Ty::unit() | 129 | Ty::unit() |
122 | } | 130 | } |
123 | Expr::For { iterable, body, pat } => { | 131 | Expr::For { iterable, body, pat, label } => { |
124 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 132 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
125 | 133 | ||
126 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 134 | self.breakables.push(BreakableContext { |
135 | may_break: false, | ||
136 | break_ty: Ty::Unknown, | ||
137 | label: label.clone(), | ||
138 | }); | ||
127 | let pat_ty = | 139 | let pat_ty = |
128 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 140 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
129 | 141 | ||
@@ -236,23 +248,24 @@ impl<'a> InferenceContext<'a> { | |||
236 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); | 248 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); |
237 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) | 249 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
238 | } | 250 | } |
239 | Expr::Continue => Ty::simple(TypeCtor::Never), | 251 | Expr::Continue { .. } => Ty::simple(TypeCtor::Never), |
240 | Expr::Break { expr } => { | 252 | Expr::Break { expr, label } => { |
241 | let val_ty = if let Some(expr) = expr { | 253 | let val_ty = if let Some(expr) = expr { |
242 | self.infer_expr(*expr, &Expectation::none()) | 254 | self.infer_expr(*expr, &Expectation::none()) |
243 | } else { | 255 | } else { |
244 | Ty::unit() | 256 | Ty::unit() |
245 | }; | 257 | }; |
246 | 258 | ||
247 | let last_ty = if let Some(ctxt) = self.breakables.last() { | 259 | let last_ty = |
248 | ctxt.break_ty.clone() | 260 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { |
249 | } else { | 261 | ctxt.break_ty.clone() |
250 | Ty::Unknown | 262 | } else { |
251 | }; | 263 | Ty::Unknown |
264 | }; | ||
252 | 265 | ||
253 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | 266 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); |
254 | 267 | ||
255 | if let Some(ctxt) = self.breakables.last_mut() { | 268 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { |
256 | ctxt.break_ty = merged_type; | 269 | ctxt.break_ty = merged_type; |
257 | ctxt.may_break = true; | 270 | ctxt.may_break = true; |
258 | } else { | 271 | } else { |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 839491b9e..88309157b 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -1943,3 +1943,57 @@ fn test() { | |||
1943 | "### | 1943 | "### |
1944 | ); | 1944 | ); |
1945 | } | 1945 | } |
1946 | |||
1947 | #[test] | ||
1948 | fn infer_labelled_break_with_val() { | ||
1949 | assert_snapshot!( | ||
1950 | infer(r#" | ||
1951 | fn foo() { | ||
1952 | let _x = || 'outer: loop { | ||
1953 | let inner = 'inner: loop { | ||
1954 | let i = Default::default(); | ||
1955 | if (break 'outer i) { | ||
1956 | loop { break 'inner 5i8; }; | ||
1957 | } else if true { | ||
1958 | break 'inner 6; | ||
1959 | } | ||
1960 | break 7; | ||
1961 | }; | ||
1962 | break inner < 8; | ||
1963 | }; | ||
1964 | } | ||
1965 | "#), | ||
1966 | @r###" | ||
1967 | 10..336 '{ ... }; }': () | ||
1968 | 20..22 '_x': || -> bool | ||
1969 | 25..333 '|| 'ou... }': || -> bool | ||
1970 | 28..333 ''outer... }': bool | ||
1971 | 41..333 '{ ... }': () | ||
1972 | 55..60 'inner': i8 | ||
1973 | 63..301 ''inner... }': i8 | ||
1974 | 76..301 '{ ... }': () | ||
1975 | 94..95 'i': bool | ||
1976 | 98..114 'Defaul...efault': {unknown} | ||
1977 | 98..116 'Defaul...ault()': bool | ||
1978 | 130..270 'if (br... }': () | ||
1979 | 134..148 'break 'outer i': ! | ||
1980 | 147..148 'i': bool | ||
1981 | 150..209 '{ ... }': () | ||
1982 | 168..194 'loop {...5i8; }': ! | ||
1983 | 173..194 '{ brea...5i8; }': () | ||
1984 | 175..191 'break ...er 5i8': ! | ||
1985 | 188..191 '5i8': i8 | ||
1986 | 215..270 'if tru... }': () | ||
1987 | 218..222 'true': bool | ||
1988 | 223..270 '{ ... }': () | ||
1989 | 241..255 'break 'inner 6': ! | ||
1990 | 254..255 '6': i8 | ||
1991 | 283..290 'break 7': ! | ||
1992 | 289..290 '7': i8 | ||
1993 | 311..326 'break inner < 8': ! | ||
1994 | 317..322 'inner': i8 | ||
1995 | 317..326 'inner < 8': bool | ||
1996 | 325..326 '8': i8 | ||
1997 | "### | ||
1998 | ); | ||
1999 | } | ||