diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer/expr.rs')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 116 |
1 files changed, 95 insertions, 21 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index efc60986b..b28724f0e 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,18 @@ 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::{ |
25 | BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, | ||
26 | TypeMismatch, | ||
27 | }; | ||
25 | 28 | ||
26 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
27 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 30 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
28 | let ty = self.infer_expr_inner(tgt_expr, expected); | 31 | let ty = self.infer_expr_inner(tgt_expr, expected); |
32 | if ty.is_never() { | ||
33 | // Any expression that produces a value of type `!` must have diverged | ||
34 | self.diverges = Diverges::Always; | ||
35 | } | ||
29 | let could_unify = self.unify(&ty, &expected.ty); | 36 | let could_unify = self.unify(&ty, &expected.ty); |
30 | if !could_unify { | 37 | if !could_unify { |
31 | self.result.type_mismatches.insert( | 38 | self.result.type_mismatches.insert( |
@@ -64,34 +71,68 @@ impl<'a> InferenceContext<'a> { | |||
64 | // if let is desugared to match, so this is always simple if | 71 | // if let is desugared to match, so this is always simple if |
65 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 72 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
66 | 73 | ||
74 | let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); | ||
75 | let mut both_arms_diverge = Diverges::Always; | ||
76 | |||
67 | let then_ty = self.infer_expr_inner(*then_branch, &expected); | 77 | let then_ty = self.infer_expr_inner(*then_branch, &expected); |
78 | both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); | ||
68 | let else_ty = match else_branch { | 79 | let else_ty = match else_branch { |
69 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | 80 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), |
70 | None => Ty::unit(), | 81 | None => Ty::unit(), |
71 | }; | 82 | }; |
83 | both_arms_diverge &= self.diverges; | ||
84 | |||
85 | self.diverges = condition_diverges | both_arms_diverge; | ||
72 | 86 | ||
73 | self.coerce_merge_branch(&then_ty, &else_ty) | 87 | self.coerce_merge_branch(&then_ty, &else_ty) |
74 | } | 88 | } |
75 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 89 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), |
90 | Expr::TryBlock { body } => { | ||
91 | let _inner = self.infer_expr(*body, expected); | ||
92 | // FIXME should be std::result::Result<{inner}, _> | ||
93 | Ty::Unknown | ||
94 | } | ||
76 | Expr::Loop { body } => { | 95 | Expr::Loop { body } => { |
96 | self.breakables.push(BreakableContext { | ||
97 | may_break: false, | ||
98 | break_ty: self.table.new_type_var(), | ||
99 | }); | ||
77 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
78 | // FIXME handle break with value | 101 | |
79 | Ty::simple(TypeCtor::Never) | 102 | let ctxt = self.breakables.pop().expect("breakable stack broken"); |
103 | if ctxt.may_break { | ||
104 | self.diverges = Diverges::Maybe; | ||
105 | } | ||
106 | |||
107 | if ctxt.may_break { | ||
108 | ctxt.break_ty | ||
109 | } else { | ||
110 | Ty::simple(TypeCtor::Never) | ||
111 | } | ||
80 | } | 112 | } |
81 | Expr::While { condition, body } => { | 113 | Expr::While { condition, body } => { |
114 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | ||
82 | // while let is desugared to a match loop, so this is always simple while | 115 | // while let is desugared to a match loop, so this is always simple while |
83 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 116 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
84 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 117 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
118 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
119 | // the body may not run, so it diverging doesn't mean we diverge | ||
120 | self.diverges = Diverges::Maybe; | ||
85 | Ty::unit() | 121 | Ty::unit() |
86 | } | 122 | } |
87 | Expr::For { iterable, body, pat } => { | 123 | Expr::For { iterable, body, pat } => { |
88 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 124 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
89 | 125 | ||
126 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | ||
90 | let pat_ty = | 127 | let pat_ty = |
91 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 128 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
92 | 129 | ||
93 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); | 130 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); |
131 | |||
94 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 132 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
133 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
134 | // the body may not run, so it diverging doesn't mean we diverge | ||
135 | self.diverges = Diverges::Maybe; | ||
95 | Ty::unit() | 136 | Ty::unit() |
96 | } | 137 | } |
97 | Expr::Lambda { body, args, ret_type, arg_types } => { | 138 | Expr::Lambda { body, args, ret_type, arg_types } => { |
@@ -127,10 +168,12 @@ impl<'a> InferenceContext<'a> { | |||
127 | // infer the body. | 168 | // infer the body. |
128 | self.coerce(&closure_ty, &expected.ty); | 169 | self.coerce(&closure_ty, &expected.ty); |
129 | 170 | ||
130 | let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); | 171 | let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); |
172 | let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); | ||
131 | 173 | ||
132 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); | 174 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); |
133 | 175 | ||
176 | self.diverges = prev_diverges; | ||
134 | self.return_ty = prev_ret_ty; | 177 | self.return_ty = prev_ret_ty; |
135 | 178 | ||
136 | closure_ty | 179 | closure_ty |
@@ -160,7 +203,11 @@ impl<'a> InferenceContext<'a> { | |||
160 | self.table.new_type_var() | 203 | self.table.new_type_var() |
161 | }; | 204 | }; |
162 | 205 | ||
206 | let matchee_diverges = self.diverges; | ||
207 | let mut all_arms_diverge = Diverges::Always; | ||
208 | |||
163 | for arm in arms { | 209 | for arm in arms { |
210 | self.diverges = Diverges::Maybe; | ||
164 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); | 211 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); |
165 | if let Some(guard_expr) = arm.guard { | 212 | if let Some(guard_expr) = arm.guard { |
166 | self.infer_expr( | 213 | self.infer_expr( |
@@ -170,9 +217,12 @@ impl<'a> InferenceContext<'a> { | |||
170 | } | 217 | } |
171 | 218 | ||
172 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); | 219 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); |
220 | all_arms_diverge &= self.diverges; | ||
173 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); | 221 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); |
174 | } | 222 | } |
175 | 223 | ||
224 | self.diverges = matchee_diverges | all_arms_diverge; | ||
225 | |||
176 | result_ty | 226 | result_ty |
177 | } | 227 | } |
178 | Expr::Path(p) => { | 228 | Expr::Path(p) => { |
@@ -182,10 +232,29 @@ impl<'a> InferenceContext<'a> { | |||
182 | } | 232 | } |
183 | Expr::Continue => Ty::simple(TypeCtor::Never), | 233 | Expr::Continue => Ty::simple(TypeCtor::Never), |
184 | Expr::Break { expr } => { | 234 | Expr::Break { expr } => { |
185 | if let Some(expr) = expr { | 235 | let val_ty = if let Some(expr) = expr { |
186 | // FIXME handle break with value | 236 | self.infer_expr(*expr, &Expectation::none()) |
187 | self.infer_expr(*expr, &Expectation::none()); | 237 | } else { |
238 | Ty::unit() | ||
239 | }; | ||
240 | |||
241 | let last_ty = if let Some(ctxt) = self.breakables.last() { | ||
242 | ctxt.break_ty.clone() | ||
243 | } else { | ||
244 | Ty::Unknown | ||
245 | }; | ||
246 | |||
247 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | ||
248 | |||
249 | if let Some(ctxt) = self.breakables.last_mut() { | ||
250 | ctxt.break_ty = merged_type; | ||
251 | ctxt.may_break = true; | ||
252 | } else { | ||
253 | self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { | ||
254 | expr: tgt_expr, | ||
255 | }); | ||
188 | } | 256 | } |
257 | |||
189 | Ty::simple(TypeCtor::Never) | 258 | Ty::simple(TypeCtor::Never) |
190 | } | 259 | } |
191 | Expr::Return { expr } => { | 260 | Expr::Return { expr } => { |
@@ -496,8 +565,8 @@ impl<'a> InferenceContext<'a> { | |||
496 | } | 565 | } |
497 | Literal::ByteString(..) => { | 566 | Literal::ByteString(..) => { |
498 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); | 567 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); |
499 | let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); | 568 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); |
500 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) | 569 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) |
501 | } | 570 | } |
502 | Literal::Char(..) => Ty::simple(TypeCtor::Char), | 571 | Literal::Char(..) => Ty::simple(TypeCtor::Char), |
503 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), | 572 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), |
@@ -517,7 +586,6 @@ impl<'a> InferenceContext<'a> { | |||
517 | tail: Option<ExprId>, | 586 | tail: Option<ExprId>, |
518 | expected: &Expectation, | 587 | expected: &Expectation, |
519 | ) -> Ty { | 588 | ) -> Ty { |
520 | let mut diverges = false; | ||
521 | for stmt in statements { | 589 | for stmt in statements { |
522 | match stmt { | 590 | match stmt { |
523 | Statement::Let { pat, type_ref, initializer } => { | 591 | Statement::Let { pat, type_ref, initializer } => { |
@@ -539,9 +607,7 @@ impl<'a> InferenceContext<'a> { | |||
539 | self.infer_pat(*pat, &ty, BindingMode::default()); | 607 | self.infer_pat(*pat, &ty, BindingMode::default()); |
540 | } | 608 | } |
541 | Statement::Expr(expr) => { | 609 | Statement::Expr(expr) => { |
542 | if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { | 610 | self.infer_expr(*expr, &Expectation::none()); |
543 | diverges = true; | ||
544 | } | ||
545 | } | 611 | } |
546 | } | 612 | } |
547 | } | 613 | } |
@@ -549,14 +615,22 @@ impl<'a> InferenceContext<'a> { | |||
549 | let ty = if let Some(expr) = tail { | 615 | let ty = if let Some(expr) = tail { |
550 | self.infer_expr_coerce(expr, expected) | 616 | self.infer_expr_coerce(expr, expected) |
551 | } else { | 617 | } else { |
552 | self.coerce(&Ty::unit(), expected.coercion_target()); | 618 | // Citing rustc: if there is no explicit tail expression, |
553 | Ty::unit() | 619 | // that is typically equivalent to a tail expression |
620 | // of `()` -- except if the block diverges. In that | ||
621 | // case, there is no value supplied from the tail | ||
622 | // expression (assuming there are no other breaks, | ||
623 | // this implies that the type of the block will be | ||
624 | // `!`). | ||
625 | if self.diverges.is_always() { | ||
626 | // we don't even make an attempt at coercion | ||
627 | self.table.new_maybe_never_type_var() | ||
628 | } else { | ||
629 | self.coerce(&Ty::unit(), expected.coercion_target()); | ||
630 | Ty::unit() | ||
631 | } | ||
554 | }; | 632 | }; |
555 | if diverges { | 633 | ty |
556 | Ty::simple(TypeCtor::Never) | ||
557 | } else { | ||
558 | ty | ||
559 | } | ||
560 | } | 634 | } |
561 | 635 | ||
562 | fn infer_method_call( | 636 | fn infer_method_call( |