Skip to content

Commit 70db57c

Browse files
bors[bot]Veykril
andauthored
Merge #6839
6839: Infer labeled blocks r=flodiebold a=Veykril The test should cover all the interesting cases I believe(main part of it is copied from the loop label break test above it). The test is indented to stay consistent with the rest of the tests in the file, I can dedent all the tests in the file in a follow up PR if desired. Co-authored-by: Lukas Wirth <[email protected]>
2 parents 4998807 + 378ec28 commit 70db57c

File tree

2 files changed

+74
-4
lines changed

2 files changed

+74
-4
lines changed

crates/hir_ty/src/infer/expr.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,24 @@ impl<'a> InferenceContext<'a> {
137137

138138
self.coerce_merge_branch(&then_ty, &else_ty)
139139
}
140-
Expr::Block { statements, tail, .. } => {
141-
// FIXME: Breakable block inference
142-
self.infer_block(statements, *tail, expected)
143-
}
140+
Expr::Block { statements, tail, label } => match label {
141+
Some(_) => {
142+
let break_ty = self.table.new_type_var();
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+
},
144158
Expr::Unsafe { body } => self.infer_expr(*body, expected),
145159
Expr::TryBlock { body } => {
146160
let _inner = self.infer_expr(*body, expected);

crates/hir_ty/src/tests/simple.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,6 +2074,62 @@ fn infer_labelled_break_with_val() {
20742074
);
20752075
}
20762076

2077+
#[test]
2078+
fn 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+
20772133
#[test]
20782134
fn generic_default() {
20792135
check_infer(

0 commit comments

Comments
 (0)