diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 614c352a0..f2f9883b2 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Type inference for expressions. | 1 | //! Type inference for expressions. |
2 | 2 | ||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::sync::Arc; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | builtin_type::Signedness, | 7 | builtin_type::Signedness, |
@@ -21,11 +21,15 @@ use crate::{ | |||
21 | Ty, TypeCtor, Uncertain, | 21 | Ty, TypeCtor, Uncertain, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; | 24 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, Diverges}; |
25 | 25 | ||
26 | impl<'a> InferenceContext<'a> { | 26 | impl<'a> InferenceContext<'a> { |
27 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 27 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
28 | let ty = self.infer_expr_inner(tgt_expr, expected); | 28 | let ty = self.infer_expr_inner(tgt_expr, expected); |
29 | if ty.is_never() { | ||
30 | // Any expression that produces a value of type `!` must have diverged | ||
31 | self.diverges = Diverges::Always; | ||
32 | } | ||
29 | let could_unify = self.unify(&ty, &expected.ty); | 33 | let could_unify = self.unify(&ty, &expected.ty); |
30 | if !could_unify { | 34 | if !could_unify { |
31 | self.result.type_mismatches.insert( | 35 | self.result.type_mismatches.insert( |
@@ -64,11 +68,18 @@ impl<'a> InferenceContext<'a> { | |||
64 | // if let is desugared to match, so this is always simple if | 68 | // if let is desugared to match, so this is always simple if |
65 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 69 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
66 | 70 | ||
71 | let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); | ||
72 | let mut both_arms_diverge = Diverges::Always; | ||
73 | |||
67 | let then_ty = self.infer_expr_inner(*then_branch, &expected); | 74 | let then_ty = self.infer_expr_inner(*then_branch, &expected); |
75 | both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); | ||
68 | let else_ty = match else_branch { | 76 | let else_ty = match else_branch { |
69 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | 77 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), |
70 | None => Ty::unit(), | 78 | None => Ty::unit(), |
71 | }; | 79 | }; |
80 | both_arms_diverge &= self.diverges; | ||
81 | |||
82 | self.diverges = condition_diverges | both_arms_diverge; | ||
72 | 83 | ||
73 | self.coerce_merge_branch(&then_ty, &else_ty) | 84 | self.coerce_merge_branch(&then_ty, &else_ty) |
74 | } | 85 | } |
@@ -132,10 +143,12 @@ impl<'a> InferenceContext<'a> { | |||
132 | // infer the body. | 143 | // infer the body. |
133 | self.coerce(&closure_ty, &expected.ty); | 144 | self.coerce(&closure_ty, &expected.ty); |
134 | 145 | ||
135 | let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); | 146 | let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); |
147 | let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); | ||
136 | 148 | ||
137 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); | 149 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); |
138 | 150 | ||
151 | self.diverges = prev_diverges; | ||
139 | self.return_ty = prev_ret_ty; | 152 | self.return_ty = prev_ret_ty; |
140 | 153 | ||
141 | closure_ty | 154 | closure_ty |
@@ -165,7 +178,11 @@ impl<'a> InferenceContext<'a> { | |||
165 | self.table.new_type_var() | 178 | self.table.new_type_var() |
166 | }; | 179 | }; |
167 | 180 | ||
181 | let matchee_diverges = self.diverges; | ||
182 | let mut all_arms_diverge = Diverges::Always; | ||
183 | |||
168 | for arm in arms { | 184 | for arm in arms { |
185 | self.diverges = Diverges::Maybe; | ||
169 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); | 186 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); |
170 | if let Some(guard_expr) = arm.guard { | 187 | if let Some(guard_expr) = arm.guard { |
171 | self.infer_expr( | 188 | self.infer_expr( |
@@ -175,9 +192,12 @@ impl<'a> InferenceContext<'a> { | |||
175 | } | 192 | } |
176 | 193 | ||
177 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); | 194 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); |
195 | all_arms_diverge &= self.diverges; | ||
178 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); | 196 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); |
179 | } | 197 | } |
180 | 198 | ||
199 | self.diverges = matchee_diverges | all_arms_diverge; | ||
200 | |||
181 | result_ty | 201 | result_ty |
182 | } | 202 | } |
183 | Expr::Path(p) => { | 203 | Expr::Path(p) => { |
@@ -522,7 +542,6 @@ impl<'a> InferenceContext<'a> { | |||
522 | tail: Option<ExprId>, | 542 | tail: Option<ExprId>, |
523 | expected: &Expectation, | 543 | expected: &Expectation, |
524 | ) -> Ty { | 544 | ) -> Ty { |
525 | let mut diverges = false; | ||
526 | for stmt in statements { | 545 | for stmt in statements { |
527 | match stmt { | 546 | match stmt { |
528 | Statement::Let { pat, type_ref, initializer } => { | 547 | Statement::Let { pat, type_ref, initializer } => { |
@@ -544,9 +563,7 @@ impl<'a> InferenceContext<'a> { | |||
544 | self.infer_pat(*pat, &ty, BindingMode::default()); | 563 | self.infer_pat(*pat, &ty, BindingMode::default()); |
545 | } | 564 | } |
546 | Statement::Expr(expr) => { | 565 | Statement::Expr(expr) => { |
547 | if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { | 566 | self.infer_expr(*expr, &Expectation::none()); |
548 | diverges = true; | ||
549 | } | ||
550 | } | 567 | } |
551 | } | 568 | } |
552 | } | 569 | } |
@@ -554,14 +571,22 @@ impl<'a> InferenceContext<'a> { | |||
554 | let ty = if let Some(expr) = tail { | 571 | let ty = if let Some(expr) = tail { |
555 | self.infer_expr_coerce(expr, expected) | 572 | self.infer_expr_coerce(expr, expected) |
556 | } else { | 573 | } else { |
557 | self.coerce(&Ty::unit(), expected.coercion_target()); | 574 | // Citing rustc: if there is no explicit tail expression, |
558 | Ty::unit() | 575 | // that is typically equivalent to a tail expression |
576 | // of `()` -- except if the block diverges. In that | ||
577 | // case, there is no value supplied from the tail | ||
578 | // expression (assuming there are no other breaks, | ||
579 | // this implies that the type of the block will be | ||
580 | // `!`). | ||
581 | if self.diverges.is_always() { | ||
582 | // we don't even make an attempt at coercion | ||
583 | self.table.new_maybe_never_type_var() | ||
584 | } else { | ||
585 | self.coerce(&Ty::unit(), expected.coercion_target()); | ||
586 | Ty::unit() | ||
587 | } | ||
559 | }; | 588 | }; |
560 | if diverges { | 589 | ty |
561 | Ty::simple(TypeCtor::Never) | ||
562 | } else { | ||
563 | ty | ||
564 | } | ||
565 | } | 590 | } |
566 | 591 | ||
567 | fn infer_method_call( | 592 | fn infer_method_call( |