1
1
//! Type inference for expressions.
2
2
3
3
use std:: iter:: { repeat, repeat_with} ;
4
- use std:: sync:: Arc ;
4
+ use std:: { mem , sync:: Arc } ;
5
5
6
6
use hir_def:: {
7
7
builtin_type:: Signedness ,
@@ -21,11 +21,18 @@ use crate::{
21
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
29
impl < ' a > InferenceContext < ' a > {
27
30
pub ( super ) fn infer_expr ( & mut self , tgt_expr : ExprId , expected : & Expectation ) -> Ty {
28
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
36
let could_unify = self . unify ( & ty, & expected. ty ) ;
30
37
if !could_unify {
31
38
self . result . type_mismatches . insert (
@@ -64,11 +71,18 @@ impl<'a> InferenceContext<'a> {
64
71
// if let is desugared to match, so this is always simple if
65
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
77
let then_ty = self . infer_expr_inner ( * then_branch, & expected) ;
78
+ both_arms_diverge &= mem:: replace ( & mut self . diverges , Diverges :: Maybe ) ;
68
79
let else_ty = match else_branch {
69
80
Some ( else_branch) => self . infer_expr_inner ( * else_branch, & expected) ,
70
81
None => Ty :: unit ( ) ,
71
82
} ;
83
+ both_arms_diverge &= self . diverges ;
84
+
85
+ self . diverges = condition_diverges | both_arms_diverge;
72
86
73
87
self . coerce_merge_branch ( & then_ty, & else_ty)
74
88
}
@@ -79,24 +93,43 @@ impl<'a> InferenceContext<'a> {
79
93
Ty :: Unknown
80
94
}
81
95
Expr :: Loop { body } => {
96
+ self . breakables . push ( BreakableContext { may_break : false } ) ;
82
97
self . infer_expr ( * body, & Expectation :: has_type ( Ty :: unit ( ) ) ) ;
98
+
99
+ let ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
100
+ if ctxt. may_break {
101
+ self . diverges = Diverges :: Maybe ;
102
+ }
83
103
// FIXME handle break with value
84
- Ty :: simple ( TypeCtor :: Never )
104
+ if ctxt. may_break {
105
+ Ty :: unit ( )
106
+ } else {
107
+ Ty :: simple ( TypeCtor :: Never )
108
+ }
85
109
}
86
110
Expr :: While { condition, body } => {
111
+ self . breakables . push ( BreakableContext { may_break : false } ) ;
87
112
// while let is desugared to a match loop, so this is always simple while
88
113
self . infer_expr ( * condition, & Expectation :: has_type ( Ty :: simple ( TypeCtor :: Bool ) ) ) ;
89
114
self . infer_expr ( * body, & Expectation :: has_type ( Ty :: unit ( ) ) ) ;
115
+ let _ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
116
+ // the body may not run, so it diverging doesn't mean we diverge
117
+ self . diverges = Diverges :: Maybe ;
90
118
Ty :: unit ( )
91
119
}
92
120
Expr :: For { iterable, body, pat } => {
93
121
let iterable_ty = self . infer_expr ( * iterable, & Expectation :: none ( ) ) ;
94
122
123
+ self . breakables . push ( BreakableContext { may_break : false } ) ;
95
124
let pat_ty =
96
125
self . resolve_associated_type ( iterable_ty, self . resolve_into_iter_item ( ) ) ;
97
126
98
127
self . infer_pat ( * pat, & pat_ty, BindingMode :: default ( ) ) ;
128
+
99
129
self . infer_expr ( * body, & Expectation :: has_type ( Ty :: unit ( ) ) ) ;
130
+ let _ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
131
+ // the body may not run, so it diverging doesn't mean we diverge
132
+ self . diverges = Diverges :: Maybe ;
100
133
Ty :: unit ( )
101
134
}
102
135
Expr :: Lambda { body, args, ret_type, arg_types } => {
@@ -132,10 +165,12 @@ impl<'a> InferenceContext<'a> {
132
165
// infer the body.
133
166
self . coerce ( & closure_ty, & expected. ty ) ;
134
167
135
- let prev_ret_ty = std:: mem:: replace ( & mut self . return_ty , ret_ty. clone ( ) ) ;
168
+ let prev_diverges = mem:: replace ( & mut self . diverges , Diverges :: Maybe ) ;
169
+ let prev_ret_ty = mem:: replace ( & mut self . return_ty , ret_ty. clone ( ) ) ;
136
170
137
171
self . infer_expr_coerce ( * body, & Expectation :: has_type ( ret_ty) ) ;
138
172
173
+ self . diverges = prev_diverges;
139
174
self . return_ty = prev_ret_ty;
140
175
141
176
closure_ty
@@ -165,7 +200,11 @@ impl<'a> InferenceContext<'a> {
165
200
self . table . new_type_var ( )
166
201
} ;
167
202
203
+ let matchee_diverges = self . diverges ;
204
+ let mut all_arms_diverge = Diverges :: Always ;
205
+
168
206
for arm in arms {
207
+ self . diverges = Diverges :: Maybe ;
169
208
let _pat_ty = self . infer_pat ( arm. pat , & input_ty, BindingMode :: default ( ) ) ;
170
209
if let Some ( guard_expr) = arm. guard {
171
210
self . infer_expr (
@@ -175,9 +214,12 @@ impl<'a> InferenceContext<'a> {
175
214
}
176
215
177
216
let arm_ty = self . infer_expr_inner ( arm. expr , & expected) ;
217
+ all_arms_diverge &= self . diverges ;
178
218
result_ty = self . coerce_merge_branch ( & result_ty, & arm_ty) ;
179
219
}
180
220
221
+ self . diverges = matchee_diverges | all_arms_diverge;
222
+
181
223
result_ty
182
224
}
183
225
Expr :: Path ( p) => {
@@ -191,6 +233,13 @@ impl<'a> InferenceContext<'a> {
191
233
// FIXME handle break with value
192
234
self . infer_expr ( * expr, & Expectation :: none ( ) ) ;
193
235
}
236
+ if let Some ( ctxt) = self . breakables . last_mut ( ) {
237
+ ctxt. may_break = true ;
238
+ } else {
239
+ self . push_diagnostic ( InferenceDiagnostic :: BreakOutsideOfLoop {
240
+ expr : tgt_expr,
241
+ } ) ;
242
+ }
194
243
Ty :: simple ( TypeCtor :: Never )
195
244
}
196
245
Expr :: Return { expr } => {
@@ -522,7 +571,6 @@ impl<'a> InferenceContext<'a> {
522
571
tail : Option < ExprId > ,
523
572
expected : & Expectation ,
524
573
) -> Ty {
525
- let mut diverges = false ;
526
574
for stmt in statements {
527
575
match stmt {
528
576
Statement :: Let { pat, type_ref, initializer } => {
@@ -544,24 +592,30 @@ impl<'a> InferenceContext<'a> {
544
592
self . infer_pat ( * pat, & ty, BindingMode :: default ( ) ) ;
545
593
}
546
594
Statement :: Expr ( expr) => {
547
- if let ty_app ! ( TypeCtor :: Never ) = self . infer_expr ( * expr, & Expectation :: none ( ) ) {
548
- diverges = true ;
549
- }
595
+ self . infer_expr ( * expr, & Expectation :: none ( ) ) ;
550
596
}
551
597
}
552
598
}
553
599
554
600
let ty = if let Some ( expr) = tail {
555
601
self . infer_expr_coerce ( expr, expected)
556
602
} else {
557
- self . coerce ( & Ty :: unit ( ) , expected. coercion_target ( ) ) ;
558
- Ty :: unit ( )
603
+ // Citing rustc: if there is no explicit tail expression,
604
+ // that is typically equivalent to a tail expression
605
+ // of `()` -- except if the block diverges. In that
606
+ // case, there is no value supplied from the tail
607
+ // expression (assuming there are no other breaks,
608
+ // this implies that the type of the block will be
609
+ // `!`).
610
+ if self . diverges . is_always ( ) {
611
+ // we don't even make an attempt at coercion
612
+ self . table . new_maybe_never_type_var ( )
613
+ } else {
614
+ self . coerce ( & Ty :: unit ( ) , expected. coercion_target ( ) ) ;
615
+ Ty :: unit ( )
616
+ }
559
617
} ;
560
- if diverges {
561
- Ty :: simple ( TypeCtor :: Never )
562
- } else {
563
- ty
564
- }
618
+ ty
565
619
}
566
620
567
621
fn infer_method_call (
0 commit comments