From 378ec2841bf344c05fe6119c0013edeabcf33a35 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 12 Dec 2020 00:03:36 +0100 Subject: [PATCH] Infer labeled blocks --- crates/hir_ty/src/infer/expr.rs | 22 +++++++++--- crates/hir_ty/src/tests/simple.rs | 56 +++++++++++++++++++++++++++++++ 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 605951b1032..d7ad198b34b 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -137,10 +137,24 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 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); diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 4f72582b6bd..a569223b4b2 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs @@ -2074,6 +2074,62 @@ fn foo() { ); } +#[test] +fn infer_labelled_block_break_with_val() { + check_infer( + r#" + fn default() -> 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 + 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(