Unnamed repository; edit this file 'description' to name the repository.
Port block and loop inference from rustc
This fixes one diagnostic on self.
| -rw-r--r-- | crates/hir-def/src/expr_store.rs | 2 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/lower.rs | 19 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/pretty.rs | 2 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/scope.rs | 2 | ||||
| -rw-r--r-- | crates/hir-def/src/hir.rs | 12 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 113 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/mutability.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/lower.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/macros.rs | 6 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/never_type.rs | 38 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/patterns.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/regression.rs | 36 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/regression/new_solver.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/simple.rs | 56 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/traits.rs | 10 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs | 3 |
16 files changed, 181 insertions, 126 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index fa33a00a80..8768413ce5 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -720,7 +720,7 @@ impl ExpressionStore { } visitor.on_expr_opt(*tail); } - Expr::Loop { body, label: _ } => visitor.on_expr(*body), + Expr::Loop { body, label: _, source: _ } => visitor.on_expr(*body), Expr::Call { callee, args } => { visitor.on_expr(*callee); visitor.on_exprs(args); diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 21b5b19986..242a0b0b4f 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -49,9 +49,9 @@ use crate::{ }, hir::{ Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, - CoroutineKind, CoroutineSource, Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, - Movability, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, Statement, - generics::GenericParams, + CoroutineKind, CoroutineSource, Expr, ExprId, Item, Label, LabelId, Literal, LoopSource, + MatchArm, Movability, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, + Statement, generics::GenericParams, }, item_scope::BuiltinShadowMode, item_tree::FieldsShape, @@ -1351,7 +1351,7 @@ impl<'db> ExprCollector<'db> { (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label)) }); let body = self.collect_labelled_block_opt(label, e.loop_body()); - self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr) + self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1), source: LoopSource::Loop }, syntax_ptr) } ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), @@ -2133,7 +2133,10 @@ impl<'db> ExprCollector<'db> { Expr::If { condition, then_branch: body, else_branch: Some(break_expr) }, syntax_ptr, ); - self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr) + self.alloc_expr( + Expr::Loop { body: if_expr, label: label.map(|it| it.1), source: LoopSource::While }, + syntax_ptr, + ) } /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into: @@ -2215,7 +2218,11 @@ impl<'db> ExprCollector<'db> { syntax_ptr, ); let loop_outer = self.alloc_expr_desugared_with_ptr( - Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, + Expr::Loop { + body: loop_inner, + label: label.map(|it| it.1), + source: LoopSource::ForLoop, + }, syntax_ptr, ); let iter_binding = diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 35e3fc44c3..293adfc9bd 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -567,7 +567,7 @@ impl Printer<'_> { w!(self, " = "); self.print_expr_in(prec, *expr); } - Expr::Loop { body, label } => { + Expr::Loop { body, label, source: _ } => { if let Some(lbl) = label { w!(self, "{}: ", self.store[*lbl].name.display(self.db, self.edition)); } diff --git a/crates/hir-def/src/expr_store/scope.rs b/crates/hir-def/src/expr_store/scope.rs index ddb8285137..7a2c8dc3ff 100644 --- a/crates/hir-def/src/expr_store/scope.rs +++ b/crates/hir-def/src/expr_store/scope.rs @@ -350,7 +350,7 @@ fn compute_expr_scopes( Expr::Unsafe { id, statements, tail } => { handle_block(*id, statements, *tail, None, scopes, scope, const_scope); } - Expr::Loop { body: body_expr, label } => { + Expr::Loop { body: body_expr, label, source: _ } => { let mut scope = scopes.new_labeled_scope(*scope, make_label(*label)); compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); } diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 4c8d835ad7..2f7724c72e 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -224,6 +224,7 @@ pub enum Expr { Loop { body: ExprId, label: Option<LabelId>, + source: LoopSource, }, Call { callee: ExprId, @@ -389,6 +390,17 @@ impl Expr { } } +/// The loop type that yielded an `Expr::Loop`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LoopSource { + /// A `loop { .. }` loop. + Loop, + /// A `while _ { .. }` loop. + While, + /// A `for _ in _ { .. }` loop. + ForLoop, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct OffsetOf { pub container: TypeRefId, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index c7562567ef..75e6440334 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -8,7 +8,8 @@ use hir_def::{ expr_store::path::{GenericArgs as HirGenericArgs, Path}, hir::{ Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId, - InlineAsmKind, LabelId, Pat, PatId, RecordLitField, RecordSpread, Statement, UnaryOp, + InlineAsmKind, LabelId, LoopSource, Pat, PatId, RecordLitField, RecordSpread, Statement, + UnaryOp, }, resolver::ValueNs, signatures::VariantFields, @@ -401,24 +402,29 @@ impl<'db> InferenceContext<'_, 'db> { }) .1 } - &Expr::Loop { body, label } => { - let ty = expected.coercion_target_type(&mut self.table, tgt_expr.into()); + &Expr::Loop { body, label, source } => { + let coerce = match source { + // you can only use break with a value from a normal `loop { }` + LoopSource::Loop => { + Some(expected.coercion_target_type(&mut self.table, body.into())) + } + LoopSource::While | LoopSource::ForLoop => None, + }; let (breaks, ()) = - self.with_breakable_ctx(BreakableKind::Loop, Some(ty), label, |this| { - this.infer_expr( + self.with_breakable_ctx(BreakableKind::Loop, coerce, label, |this| { + this.infer_expr_suptype_coerce_never( body, &Expectation::HasType(this.types.types.unit), ExprIsRead::Yes, ); }); - match breaks { - Some(breaks) => { - self.diverges = Diverges::Maybe; - breaks - } - None => self.types.types.never, + if breaks.may_break { + self.diverges = Diverges::Maybe; + } else { + self.diverges = Diverges::Always; } + breaks.coerce.map(|c| c.complete(self)).unwrap_or(self.types.types.unit) } Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => self .infer_closure( @@ -1499,10 +1505,11 @@ impl<'db> InferenceContext<'_, 'db> { label: Option<LabelId>, expected: &Expectation<'db>, ) -> Ty<'db> { + let prev_diverges = self.diverges; let coerce_ty = expected.coercion_target_type(&mut self.table, expr.into()); let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, expr); - let (break_ty, ty) = + let (ctxt, tail_expr_ty) = self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| { for stmt in statements { match stmt { @@ -1570,42 +1577,54 @@ impl<'db> InferenceContext<'_, 'db> { } } - // FIXME: This should make use of the breakable CoerceMany - if let Some(expr) = tail { - this.infer_expr_coerce(expr, expected, ExprIsRead::Yes) - } else { - // Citing rustc: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - if this.diverges.is_always() { - // we don't even make an attempt at coercion - this.table.new_maybe_never_var(expr.into()) - } else if let Some(t) = expected.only_has_type(&mut this.table) { - if this - .coerce( - expr, - this.types.types.unit, - t, - AllowTwoPhase::No, - ExprIsRead::Yes, - ) - .is_err() - { - this.emit_type_mismatch(expr.into(), t, this.types.types.unit); - } - t - } else { - this.types.types.unit - } - } + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + tail.map(|expr| (expr, this.infer_expr_inner(expr, expected, ExprIsRead::Yes))) }); + + let mut coerce = ctxt.coerce.unwrap(); + if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty { + let cause = ObligationCause::new(tail_expr); + coerce.coerce_inner( + self, + &cause, + tail_expr, + tail_expr_ty, + false, + false, + ExprIsRead::Yes, + ); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + // + // #41425 -- label the implicit `()` as being the + // "found type" here, rather than the "expected type". + if !self.diverges.is_always() { + coerce.coerce_forced_unit( + self, + expr, + &ObligationCause::new(expr), + false, + ExprIsRead::Yes, + ); + } + } + + if ctxt.may_break { + // If we can break from the block, then the block's exit is always reachable + // (... as long as the entry is reachable) - regardless of the tail of the block. + self.diverges = prev_diverges; + } + self.resolver.reset_to_guard(g); - break_ty.unwrap_or(ty) + coerce.complete(self) } fn lookup_field( @@ -2178,13 +2197,13 @@ impl<'db> InferenceContext<'_, 'db> { ty: Option<Ty<'db>>, label: Option<LabelId>, cb: impl FnOnce(&mut Self) -> T, - ) -> (Option<Ty<'db>>, T) { + ) -> (BreakableContext<'db>, T) { self.breakables.push({ BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), label } }); let res = cb(self); let ctx = self.breakables.pop().expect("breakable stack broken"); - (if ctx.may_break { ctx.coerce.map(|ctx| ctx.complete(self)) } else { None }, res) + (ctx, res) } } diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index c3b532638f..483f54a227 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -160,7 +160,7 @@ impl<'db> InferenceContext<'_, 'db> { | Expr::Range { rhs: Some(expr), lhs: None, range_type: _ } | Expr::Await { expr } | Expr::Box { expr } - | Expr::Loop { body: expr, label: _ } + | Expr::Loop { body: expr, label: _, source: _ } | Expr::Cast { expr, type_ref: _ } => { self.infer_mut_expr(*expr, Mutability::Not); } diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 68612c2ce2..394cac8065 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -669,7 +669,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) } } - Expr::Loop { body, label } => { + Expr::Loop { body, label, source: _ } => { self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { let scope = this.push_drop_scope(); if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? { diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index f81028c174..c0da6cfd30 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -194,7 +194,7 @@ fn expr_macro_def_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - 39..442 '{ ...!(); }': {unknown} + 39..442 '{ ...!(); }': ! 73..94 'spam!(...am!())': {unknown} 100..119 'for _ ...!() {}': ! 100..119 'for _ ...!() {}': {unknown} @@ -288,7 +288,7 @@ fn expr_macro_rules_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - 53..456 '{ ...!(); }': {unknown} + 53..456 '{ ...!(); }': ! 87..108 'spam!(...am!())': {unknown} 114..133 'for _ ...!() {}': ! 114..133 'for _ ...!() {}': {unknown} @@ -1493,7 +1493,7 @@ fn main() { !0..136 'builti...tack))': () !0..449 'builti...urn),)': ! 10..1236 '{ ... } }': () - 16..1234 'unsafe... }': () + 16..1234 'unsafe... }': ! 37..40 'foo': i32 43..44 '1': i32 58..63 'mut o': i32 diff --git a/crates/hir-ty/src/tests/never_type.rs b/crates/hir-ty/src/tests/never_type.rs index 19a6a6b486..fd21286d50 100644 --- a/crates/hir-ty/src/tests/never_type.rs +++ b/crates/hir-ty/src/tests/never_type.rs @@ -262,42 +262,42 @@ fn diverging_expression_1() { let x: u32 = { let y: u32 = { loop {}; }; }; } ", - expect![[r" - 11..39 '{ ...urn; }': () + expect![[r#" + 11..39 '{ ...urn; }': ! 21..22 'x': u32 30..36 'return': ! - 51..84 '{ ...; }; }': () + 51..84 '{ ...; }; }': ! 61..62 'x': u32 - 70..81 '{ return; }': u32 + 70..81 '{ return; }': ! 72..78 'return': ! - 96..125 '{ ... {}; }': () + 96..125 '{ ... {}; }': ! 106..107 'x': u32 115..122 'loop {}': ! 120..122 '{}': () - 137..170 '{ ...} }; }': () + 137..170 '{ ...} }; }': ! 147..148 'x': u32 156..167 '{ loop {} }': u32 158..165 'loop {}': ! 163..165 '{}': () - 182..246 '{ ...} }; }': () + 182..246 '{ ...} }; }': ! 192..193 'x': u32 201..243 '{ if t...}; } }': u32 203..241 'if tru... {}; }': u32 206..210 'true': bool - 211..223 '{ loop {}; }': u32 + 211..223 '{ loop {}; }': ! 213..220 'loop {}': ! 218..220 '{}': () - 229..241 '{ loop {}; }': u32 + 229..241 '{ loop {}; }': ! 231..238 'loop {}': ! 236..238 '{}': () - 258..310 '{ ...; }; }': () + 258..310 '{ ...; }; }': ! 268..269 'x': u32 - 277..307 '{ let ...; }; }': u32 + 277..307 '{ let ...; }; }': ! 283..284 'y': u32 - 292..304 '{ loop {}; }': u32 + 292..304 '{ loop {}; }': ! 294..301 'loop {}': ! 299..301 '{}': () - "]], + "#]], ); } @@ -312,7 +312,7 @@ fn diverging_expression_2() { } "#, expect![[r#" - 11..84 '{ ..." }; }': () + 11..84 '{ ..." }; }': ! 54..55 'x': u32 63..81 '{ loop...foo" }': u32 65..72 'loop {}': ! @@ -355,7 +355,7 @@ fn diverging_expression_3_break() { 54..55 'x': u32 63..82 '{ loop...k; } }': u32 65..80 'loop { break; }': u32 - 70..80 '{ break; }': () + 70..80 '{ break; }': ! 72..77 'break': ! 72..77: expected u32, got () 97..343 '{ ...; }; }': () @@ -374,7 +374,7 @@ fn diverging_expression_3_break() { 160..161 'b': {unknown} 160..161 'b': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 160..161 'b': <{unknown} as IntoIterator>::IntoIter - 162..172 '{ break; }': () + 162..172 '{ break; }': ! 164..169 'break': ! 226..227 'x': u32 235..253 '{ for ... {}; }': u32 @@ -407,7 +407,7 @@ fn diverging_expression_3_break() { 324..325 'b': {unknown} 324..325 'b': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 324..325 'b': <{unknown} as IntoIterator>::IntoIter - 326..337 '{ return; }': () + 326..337 '{ return; }': ! 328..334 'return': ! 149..175: expected u32, got () 235..253: expected u32, got () @@ -419,7 +419,7 @@ fn diverging_expression_3_break() { 409..430 'while ...eak; }': () 409..430 'while ...eak; }': () 415..419 'true': bool - 420..430 '{ break; }': () + 420..430 '{ break; }': ! 422..427 'break': ! 537..538 'x': u32 546..564 '{ whil... {}; }': u32 @@ -434,7 +434,7 @@ fn diverging_expression_3_break() { 626..648 'while ...urn; }': () 626..648 'while ...urn; }': () 632..636 'true': bool - 637..648 '{ return; }': () + 637..648 '{ return; }': ! 639..645 'return': ! 407..433: expected u32, got () 546..564: expected u32, got () diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index c48112ee81..a6e864916f 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -606,7 +606,7 @@ fn enum_variant_through_self_in_pattern() { } "#, expect![[r#" - 75..217 '{ ... }': () + 75..217 '{ ... }': ! 85..210 'match ... }': () 92..99 'loop {}': ! 97..99 '{}': () diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index c1c714f8d4..22404087bf 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -279,29 +279,29 @@ fn infer_std_crash_5() { 32..320 'for co... }': () 32..320 'for co... }': () 32..320 'for co... }': () - 36..43 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 36..43 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} 47..60 'doesnt_matter': {unknown} 47..60 'doesnt_matter': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 47..60 'doesnt_matter': <{unknown} as IntoIterator>::IntoIter 61..320 '{ ... }': () - 75..79 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 82..166 'if doe... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 75..79 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 82..166 'if doe... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} 85..98 'doesnt_matter': bool 99..128 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} 113..118 'first': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 134..166 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 148..156 '&content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 149..156 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 181..188 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 191..313 'if ICE... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 134..166 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 148..156 '&content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 149..156 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 181..188 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 191..313 'if ICE... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} 194..231 'ICE_RE..._VALUE': {unknown} 194..247 'ICE_RE...&name)': bool - 241..246 '&name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 242..246 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 248..276 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 262..266 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 282..313 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} - 296..303 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 241..246 '&name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 242..246 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 248..276 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 262..266 'name': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 282..313 '{ ... }': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} + 296..303 'content': &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? &'? {unknown} "#]], ); } @@ -416,7 +416,7 @@ fn issue_2669() { 120..215 '{ ... }': () 130..133 'end': fn end<{unknown}>() 130..135 'end()': () - 164..209 '{ ... }': () + 164..209 '{ ... }': ! 182..184 '_x': ! 191..198 'loop {}': ! 196..198 '{}': () @@ -631,7 +631,7 @@ fn issue_4053_diesel_where_clauses() { 65..69 'self': Self 267..271 'self': Self 466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> - 488..522 '{ ... }': {unknown} + 488..522 '{ ... }': () 498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> 498..508 'self.order': O 498..515 'self.o...into()': dyn QueryFragment<DB> + 'static @@ -1059,7 +1059,7 @@ fn cfg_tail() { 216..227 '{ "third" }': () 218..225 '"third"': &'static str 293..357 '{ ...] 15 }': () - 299..311 '{ "fourth" }': &'static str + 299..311 '{ "fourth" }': &'? str 301..309 '"fourth"': &'static str "#]], ) @@ -2238,7 +2238,7 @@ type Bar = impl Foo; async fn f<A, B, C>() -> Bar {} "#, expect![[r#" - 64..66 '{}': impl Foo + ?Sized + 64..66 '{}': () "#]], ); } diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs index 33a12fcd1e..c77b20f4b5 100644 --- a/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/crates/hir-ty/src/tests/regression/new_solver.rs @@ -357,7 +357,7 @@ where "#, expect![[r#" 182..183 't': T - 230..280 '{ ... {}; }': () + 230..280 '{ ... {}; }': ! 240..241 't': <T as DimMax<U>>::Output 270..277 'loop {}': ! 275..277 '{}': () diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index c0b8d93b47..b54ed08031 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -135,7 +135,7 @@ fn test(a: u32, b: isize, c: !, d: &str) { 16..17 'b': isize 26..27 'c': ! 32..33 'd': &'? str - 41..120 '{ ...f32; }': () + 41..120 '{ ...f32; }': ! 47..48 'a': u32 54..55 'b': isize 61..62 'c': ! @@ -1018,14 +1018,14 @@ fn foo() { 28..32 'true': bool 33..50 '{ ... }': i32 43..44 '1': i32 - 56..79 '{ ... }': i32 + 56..79 '{ ... }': ! 66..72 'return': ! 89..92 '_x2': i32 95..148 'if tru... }': i32 98..102 'true': bool 103..120 '{ ... }': i32 113..114 '2': i32 - 126..148 '{ ... }': ! + 126..148 '{ ... }': i32 136..142 'return': ! 158..161 '_x3': i32 164..246 'match ... }': i32 @@ -1034,7 +1034,7 @@ fn foo() { 185..189 'true': bool 193..194 '3': i32 204..205 '_': bool - 209..240 '{ ... }': i32 + 209..240 '{ ... }': ! 223..229 'return': ! 256..259 '_x4': i32 262..319 'match ... }': i32 @@ -1939,7 +1939,7 @@ fn closure_return() { 16..58 '{ ...; }; }': u32 26..27 'x': impl Fn() -> usize 30..55 '|| -> ...n 1; }': impl Fn() -> usize - 42..55 '{ return 1; }': usize + 42..55 '{ return 1; }': ! 44..52 'return 1': ! 51..52 '1': usize "#]], @@ -1958,7 +1958,7 @@ fn closure_return_unit() { 16..47 '{ ...; }; }': u32 26..27 'x': impl Fn() 30..44 '|| { return; }': impl Fn() - 33..44 '{ return; }': () + 33..44 '{ return; }': ! 35..41 'return': ! "#]], ); @@ -2434,10 +2434,10 @@ fn infer_loop_break_with_val() { 59..168 '{ ... }; }': () 69..70 'x': Option<bool> 73..165 'loop {... }': Option<bool> - 78..165 '{ ... }': () + 78..165 '{ ... }': ! 88..132 'if fal... }': () 91..96 'false': bool - 97..132 '{ ... }': () + 97..132 '{ ... }': ! 111..121 'break None': ! 117..121 'None': Option<bool> 142..158 'break ...(true)': ! @@ -2470,7 +2470,7 @@ fn infer_loop_break_without_val() { 78..133 '{ ... }': () 88..127 'if fal... }': () 91..96 'false': bool - 97..127 '{ ... }': () + 97..127 '{ ... }': ! 111..116 'break': ! "#]], ); @@ -2500,24 +2500,24 @@ fn infer_labelled_break_with_val() { 19..21 '_x': impl Fn() -> bool 24..332 '|| 'ou... }': impl Fn() -> bool 27..332 ''outer... }': bool - 40..332 '{ ... }': () + 40..332 '{ ... }': ! 54..59 'inner': i8 62..300 ''inner... }': i8 - 75..300 '{ ... }': () + 75..300 '{ ... }': ! 93..94 'i': bool 97..113 'Defaul...efault': {unknown} 97..115 'Defaul...ault()': bool 129..269 'if (br... }': () 133..147 'break 'outer i': ! 146..147 'i': bool - 149..208 '{ ... }': () + 149..208 '{ ... }': ! 167..193 'loop {...5i8; }': ! - 172..193 '{ brea...5i8; }': () + 172..193 '{ brea...5i8; }': ! 174..190 'break ...er 5i8': ! 187..190 '5i8': i8 214..269 'if tru... }': () 217..221 'true': bool - 222..269 '{ ... }': () + 222..269 '{ ... }': ! 240..254 'break 'inner 6': ! 253..254 '6': i8 282..289 'break 7': ! @@ -2566,12 +2566,12 @@ fn foo() { 140..270 'if (br... }': () 144..158 'break 'outer i': ! 157..158 'i': bool - 160..209 '{ ... }': () + 160..209 '{ ... }': ! 178..194 'break ...er 5i8': ! 191..194 '5i8': i8 215..270 'if tru... }': () 218..222 'true': bool - 223..270 '{ ... }': () + 223..270 '{ ... }': ! 241..255 'break 'inner 6': ! 254..255 '6': i8 283..313 'break ... { 0 }': ! @@ -2666,7 +2666,7 @@ fn generic_default_in_struct_literal() { } "#, expect![[r#" - 99..319 '{ ...32); }': () + 99..319 '{ ...32); }': ! 109..110 'x': Thing<!> 113..133 'Thing ...p {} }': Thing<!> 124..131 'loop {}': ! @@ -3254,9 +3254,9 @@ fn main() { expect![[r#" 104..108 'self': &'? Box<T> 188..192 'self': &'a Box<Foo<T>> - 218..220 '{}': &'a T + 218..220 '{}': &'? T 242..246 'self': &'a Box<Foo<T>> - 275..277 '{}': &'a Foo<T> + 275..277 '{}': &'? Foo<T> 297..301 'self': Box<Foo<T>> 322..324 '{}': Foo<T> 338..559 '{ ...r(); }': () @@ -4305,3 +4305,21 @@ enum Enum { "#]], ); } + +#[test] +fn labelled_block_break() { + check_types( + r#" +//- minicore: option +fn foo() { + 'a: { + if false { + break 'a Some(1); + } + None + // ^^^^ Option<i32> + }; +} + "#, + ); +} diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 4eab1d6314..85c93abcf9 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1490,7 +1490,7 @@ fn test(x: Box<dyn Trait<u64>>, y: &dyn Trait<u64>) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 206..208 '{}': Box<dyn Trait<u64> + 'static> + 206..208 '{}': Box<dyn Trait<u64> + '?> 218..219 'x': Box<dyn Trait<u64> + 'static> 242..243 'y': &'? (dyn Trait<u64> + 'static) 262..379 '{ ...2(); }': () @@ -1571,7 +1571,7 @@ fn test(x: Trait, y: &Trait) -> u64 { }"#, expect![[r#" 26..30 'self': &'? Self - 60..62 '{}': dyn Trait + 'static + 60..62 '{}': dyn Trait + '? 72..73 'x': dyn Trait + 'static 82..83 'y': &'? (dyn Trait + 'static) 100..175 '{ ...o(); }': u64 @@ -1712,7 +1712,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { }"#, expect![[r#" 81..82 't': T - 109..111 '{}': <T as Trait>::Type + 109..111 '{}': () 143..144 't': T 154..156 '{}': U 186..187 't': T @@ -5018,7 +5018,7 @@ where "#, expect![[r#" 84..86 'de': D - 135..138 '{ }': <D as Deserializer<'de>>::Error + 135..138 '{ }': () "#]], ); } @@ -5083,7 +5083,7 @@ fn main() { let _ = iter.into_iter(); }"#, expect![[r#" - 10..313 '{ ...r(); }': () + 10..313 '{ ...r(); }': ! 223..227 'iter': Box<dyn Iterator<Item = &'? [u8]> + 'static> 273..280 'loop {}': ! 278..280 '{}': () diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index b7265c47b6..43eb4ab8e0 100644 --- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -126,14 +126,13 @@ fn foo() { #[test] fn value_break_in_for_loop() { - // FIXME: the error is correct, but the message is terrible check_diagnostics( r#" //- minicore: iterator fn test() { for _ in [()] { break 3; - // ^ error: expected (), found i32 + // ^^^^^^^ error: can't break with a value in this position } } "#, |