aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-12-11 23:03:36 +0000
committerLukas Wirth <[email protected]>2020-12-11 23:06:48 +0000
commit378ec2841bf344c05fe6119c0013edeabcf33a35 (patch)
tree25ed5a326f41e6f6a2057e797bbbecddacb3dc71 /crates
parent91bf15a2f53629209bd13d2e46121b9be8af1f94 (diff)
Infer labeled blocks
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_ty/src/infer/expr.rs22
-rw-r--r--crates/hir_ty/src/tests/simple.rs56
2 files changed, 74 insertions, 4 deletions
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 605951b10..d7ad198b3 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -137,10 +137,24 @@ impl<'a> InferenceContext<'a> {
137 137
138 self.coerce_merge_branch(&then_ty, &else_ty) 138 self.coerce_merge_branch(&then_ty, &else_ty)
139 } 139 }
140 Expr::Block { statements, tail, .. } => { 140 Expr::Block { statements, tail, label } => match label {
141 // FIXME: Breakable block inference 141 Some(_) => {
142 self.infer_block(statements, *tail, expected) 142 let break_ty = self.table.new_type_var();
143 } 143 self.breakables.push(BreakableContext {
144 may_break: false,
145 break_ty: break_ty.clone(),
146 label: label.clone(),
147 });
148 let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
149 let ctxt = self.breakables.pop().expect("breakable stack broken");
150 if ctxt.may_break {
151 ctxt.break_ty
152 } else {
153 ty
154 }
155 }
156 None => self.infer_block(statements, *tail, expected),
157 },
144 Expr::Unsafe { body } => self.infer_expr(*body, expected), 158 Expr::Unsafe { body } => self.infer_expr(*body, expected),
145 Expr::TryBlock { body } => { 159 Expr::TryBlock { body } => {
146 let _inner = self.infer_expr(*body, expected); 160 let _inner = self.infer_expr(*body, expected);
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 4f72582b6..a569223b4 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2075,6 +2075,62 @@ fn infer_labelled_break_with_val() {
2075} 2075}
2076 2076
2077#[test] 2077#[test]
2078fn infer_labelled_block_break_with_val() {
2079 check_infer(
2080 r#"
2081 fn default<T>() -> T { loop {} }
2082 fn foo() {
2083 let _x = 'outer: {
2084 let inner = 'inner: {
2085 let i = default();
2086 if (break 'outer i) {
2087 break 'inner 5i8;
2088 } else if true {
2089 break 'inner 6;
2090 }
2091 break 'inner 'innermost: { 0 };
2092 42
2093 };
2094 break 'outer inner < 8;
2095 };
2096 }
2097 "#,
2098 expect![[r#"
2099 21..32 '{ loop {} }': T
2100 23..30 'loop {}': !
2101 28..30 '{}': ()
2102 42..381 '{ ... }; }': ()
2103 52..54 '_x': bool
2104 65..378 '{ ... }': bool
2105 79..84 'inner': i8
2106 95..339 '{ ... }': i8
2107 113..114 'i': bool
2108 117..124 'default': fn default<bool>() -> bool
2109 117..126 'default()': bool
2110 140..270 'if (br... }': ()
2111 144..158 'break 'outer i': !
2112 157..158 'i': bool
2113 160..209 '{ ... }': ()
2114 178..194 'break ...er 5i8': !
2115 191..194 '5i8': i8
2116 215..270 'if tru... }': ()
2117 218..222 'true': bool
2118 223..270 '{ ... }': ()
2119 241..255 'break 'inner 6': !
2120 254..255 '6': i8
2121 283..313 'break ... { 0 }': !
2122 308..313 '{ 0 }': i8
2123 310..311 '0': i8
2124 327..329 '42': i8
2125 349..371 'break ...er < 8': !
2126 362..367 'inner': i8
2127 362..371 'inner < 8': bool
2128 370..371 '8': i8
2129 "#]],
2130 );
2131}
2132
2133#[test]
2078fn generic_default() { 2134fn generic_default() {
2079 check_infer( 2135 check_infer(
2080 r#" 2136 r#"