Unnamed repository; edit this file 'description' to name the repository.
Correctly handle non-semi statement expressions for never coercions
Lukas Wirth 2023-03-05
parent 95c4cb9 · commit b85e2af
-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 023e19d25e..8895dc095f 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 be67329fee..74bcab6caa 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 5fc2f46d56..2fa6234da1 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}