From b85e2af898546f9c7a7b58b02b43ba0ae0c948c9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 4 Mar 2023 19:39:00 +0100 Subject: [PATCH] Correctly handle non-semi statement expressions for never coercions --- crates/hir-ty/src/infer/expr.rs | 45 ++++++++++++++++++++------- crates/hir-ty/src/tests/patterns.rs | 2 +- crates/hir-ty/src/tests/regression.rs | 4 +-- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 023e19d25ed..8895dc095f9 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -84,6 +84,30 @@ impl<'a> InferenceContext<'a> { } } + pub(super) fn infer_expr_coerce_never(&mut self, expr: ExprId, expected: &Expectation) -> Ty { + let ty = self.infer_expr_inner(expr, expected); + // While we don't allow *arbitrary* coercions here, we *do* allow + // coercions from ! to `expected`. + if ty.is_never() { + if let Some(adjustments) = self.result.expr_adjustments.get(&expr) { + return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments { + target.clone() + } else { + self.err_ty() + }; + } + + let adj_ty = self.table.new_type_var(); + self.write_expr_adj( + expr, + vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty.clone() }], + ); + adj_ty + } else { + ty + } + } + fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { self.db.unwind_if_cancelled(); @@ -91,7 +115,7 @@ impl<'a> InferenceContext<'a> { Expr::Missing => self.err_ty(), &Expr::If { condition, then_branch, else_branch } => { let expected = &expected.adjust_for_branches(&mut self.table); - self.infer_expr( + self.infer_expr_coerce_never( condition, &Expectation::HasType(self.result.standard_types.bool_.clone()), ); @@ -415,7 +439,7 @@ impl<'a> InferenceContext<'a> { for arm in arms.iter() { if let Some(guard_expr) = arm.guard { self.diverges = Diverges::Maybe; - self.infer_expr( + self.infer_expr_coerce_never( guard_expr, &Expectation::HasType(self.result.standard_types.bool_.clone()), ); @@ -1146,7 +1170,6 @@ impl<'a> InferenceContext<'a> { let coerce_ty = expected.coercion_target_type(&mut self.table); let old_resolver = mem::replace(&mut self.resolver, resolver_for_expr(self.db.upcast(), self.owner, expr)); - let (break_ty, ty) = self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| { for stmt in statements { @@ -1188,14 +1211,14 @@ impl<'a> InferenceContext<'a> { } } &Statement::Expr { expr, has_semi } => { - this.infer_expr( - expr, - &if has_semi { - Expectation::none() - } else { - Expectation::HasType(this.result.standard_types.unit.clone()) - }, - ); + if has_semi { + this.infer_expr(expr, &Expectation::none()); + } else { + this.infer_expr_coerce( + expr, + &Expectation::HasType(this.result.standard_types.unit.clone()), + ); + } } } } diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index be67329fee4..74bcab6caa9 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -476,7 +476,7 @@ fn infer_adt_pattern() { 183..184 'x': usize 190..191 'x': usize 201..205 'E::B': E - 209..212 'foo': bool + 209..212 'foo': {unknown} 216..217 '1': usize 227..231 'E::B': E 235..237 '10': usize diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 5fc2f46d560..2fa6234da1e 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -270,7 +270,7 @@ fn infer_std_crash_5() { 61..320 '{ ... }': () 75..79 'name': &{unknown} 82..166 'if doe... }': &{unknown} - 85..98 'doesnt_matter': bool + 85..98 'doesnt_matter': {unknown} 99..128 '{ ... }': &{unknown} 113..118 'first': &{unknown} 134..166 '{ ... }': &{unknown} @@ -279,7 +279,7 @@ fn infer_std_crash_5() { 181..188 'content': &{unknown} 191..313 'if ICE... }': &{unknown} 194..231 'ICE_RE..._VALUE': {unknown} - 194..247 'ICE_RE...&name)': bool + 194..247 'ICE_RE...&name)': {unknown} 241..246 '&name': &&{unknown} 242..246 'name': &{unknown} 248..276 '{ ... }': &{unknown}