aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/infer
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-05-08 16:36:11 +0100
committerFlorian Diebold <[email protected]>2020-05-08 17:15:24 +0100
commitfe7bf993aa8d64668707e348f2ea69918cfda9a4 (patch)
tree9d3fc4f969dbd06d982dda6dadc6325a668e7eb1 /crates/ra_hir_ty/src/infer
parentd3eb9d8eafbebca7da95fa8a4813b92eb5080500 (diff)
Implement better handling of divergence
Divergence here means that for some reason, the end of a block will not be reached. We tried to model this just using the never type, but that doesn't work fully (e.g. in `let x = { loop {}; "foo" };` x should still have type `&str`); so this introduces a `diverges` flag that the type checker keeps track of, like rustc does.
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs53
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
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::sync::Arc; 4use std::{mem, sync::Arc};
5 5
6use hir_def::{ 6use 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
24use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 24use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, Diverges};
25 25
26impl<'a> InferenceContext<'a> { 26impl<'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(