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 <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2020-12-12 10:18:16 +00:00 committed by GitHub
commit 70db57cc59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 4 deletions

View file

@ -137,10 +137,24 @@ impl<'a> InferenceContext<'a> {
self.coerce_merge_branch(&then_ty, &else_ty)
}
Expr::Block { statements, tail, .. } => {
// FIXME: Breakable block inference
self.infer_block(statements, *tail, expected)
}
Expr::Block { statements, tail, label } => match label {
Some(_) => {
let break_ty = self.table.new_type_var();
self.breakables.push(BreakableContext {
may_break: false,
break_ty: break_ty.clone(),
label: label.clone(),
});
let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
let ctxt = self.breakables.pop().expect("breakable stack broken");
if ctxt.may_break {
ctxt.break_ty
} else {
ty
}
}
None => self.infer_block(statements, *tail, expected),
},
Expr::Unsafe { body } => self.infer_expr(*body, expected),
Expr::TryBlock { body } => {
let _inner = self.infer_expr(*body, expected);

View file

@ -2074,6 +2074,62 @@ fn infer_labelled_break_with_val() {
);
}
#[test]
fn infer_labelled_block_break_with_val() {
check_infer(
r#"
fn default<T>() -> T { loop {} }
fn foo() {
let _x = 'outer: {
let inner = 'inner: {
let i = default();
if (break 'outer i) {
break 'inner 5i8;
} else if true {
break 'inner 6;
}
break 'inner 'innermost: { 0 };
42
};
break 'outer inner < 8;
};
}
"#,
expect![[r#"
21..32 '{ loop {} }': T
23..30 'loop {}': !
28..30 '{}': ()
42..381 '{ ... }; }': ()
52..54 '_x': bool
65..378 '{ ... }': bool
79..84 'inner': i8
95..339 '{ ... }': i8
113..114 'i': bool
117..124 'default': fn default<bool>() -> bool
117..126 'default()': bool
140..270 'if (br... }': ()
144..158 'break 'outer i': !
157..158 'i': bool
160..209 '{ ... }': ()
178..194 'break ...er 5i8': !
191..194 '5i8': i8
215..270 'if tru... }': ()
218..222 'true': bool
223..270 '{ ... }': ()
241..255 'break 'inner 6': !
254..255 '6': i8
283..313 'break ... { 0 }': !
308..313 '{ 0 }': i8
310..311 '0': i8
327..329 '42': i8
349..371 'break ...er < 8': !
362..367 'inner': i8
362..371 'inner < 8': bool
370..371 '8': i8
"#]],
);
}
#[test]
fn generic_default() {
check_infer(