about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-03-04 19:39:00 +0100
committerLukas Wirth <lukastw97@gmail.com>2023-03-04 19:48:03 +0100
commitb85e2af898546f9c7a7b58b02b43ba0ae0c948c9 (patch)
tree30ec05b28f0d476a4c3e97b12fa79f4c255bc933
parent95c4cb991f02841ef15898370640aa47491d9456 (diff)
downloadrust-b85e2af898546f9c7a7b58b02b43ba0ae0c948c9.tar.gz
rust-b85e2af898546f9c7a7b58b02b43ba0ae0c948c9.zip
Correctly handle non-semi statement expressions for never coercions
-rw-r--r--crates/hir-ty/src/infer/expr.rs45
-rw-r--r--crates/hir-ty/src/tests/patterns.rs2
-rw-r--r--crates/hir-ty/src/tests/regression.rs4
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}