@@ -72,6 +72,7 @@ mod compare_method;
72
72
pub mod demand;
73
73
mod diverges;
74
74
pub mod dropck;
75
+ mod expectation;
75
76
mod expr;
76
77
mod fn_ctxt;
77
78
mod gather_locals;
@@ -88,6 +89,7 @@ mod wfcheck;
88
89
pub mod writeback;
89
90
90
91
pub use diverges:: Diverges ;
92
+ pub use expectation:: Expectation ;
91
93
pub use fn_ctxt:: FnCtxt ;
92
94
pub use inherited:: { Inherited , InheritedBuilder } ;
93
95
@@ -153,117 +155,6 @@ pub struct LocalTy<'tcx> {
153
155
revealed_ty : Ty < ' tcx > ,
154
156
}
155
157
156
- /// When type-checking an expression, we propagate downward
157
- /// whatever type hint we are able in the form of an `Expectation`.
158
- #[ derive( Copy , Clone , Debug ) ]
159
- pub enum Expectation < ' tcx > {
160
- /// We know nothing about what type this expression should have.
161
- NoExpectation ,
162
-
163
- /// This expression should have the type given (or some subtype).
164
- ExpectHasType ( Ty < ' tcx > ) ,
165
-
166
- /// This expression will be cast to the `Ty`.
167
- ExpectCastableToType ( Ty < ' tcx > ) ,
168
-
169
- /// This rvalue expression will be wrapped in `&` or `Box` and coerced
170
- /// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
171
- ExpectRvalueLikeUnsized ( Ty < ' tcx > ) ,
172
- }
173
-
174
- impl < ' a , ' tcx > Expectation < ' tcx > {
175
- // Disregard "castable to" expectations because they
176
- // can lead us astray. Consider for example `if cond
177
- // {22} else {c} as u8` -- if we propagate the
178
- // "castable to u8" constraint to 22, it will pick the
179
- // type 22u8, which is overly constrained (c might not
180
- // be a u8). In effect, the problem is that the
181
- // "castable to" expectation is not the tightest thing
182
- // we can say, so we want to drop it in this case.
183
- // The tightest thing we can say is "must unify with
184
- // else branch". Note that in the case of a "has type"
185
- // constraint, this limitation does not hold.
186
-
187
- // If the expected type is just a type variable, then don't use
188
- // an expected type. Otherwise, we might write parts of the type
189
- // when checking the 'then' block which are incompatible with the
190
- // 'else' branch.
191
- fn adjust_for_branches ( & self , fcx : & FnCtxt < ' a , ' tcx > ) -> Expectation < ' tcx > {
192
- match * self {
193
- ExpectHasType ( ety) => {
194
- let ety = fcx. shallow_resolve ( ety) ;
195
- if !ety. is_ty_var ( ) { ExpectHasType ( ety) } else { NoExpectation }
196
- }
197
- ExpectRvalueLikeUnsized ( ety) => ExpectRvalueLikeUnsized ( ety) ,
198
- _ => NoExpectation ,
199
- }
200
- }
201
-
202
- /// Provides an expectation for an rvalue expression given an *optional*
203
- /// hint, which is not required for type safety (the resulting type might
204
- /// be checked higher up, as is the case with `&expr` and `box expr`), but
205
- /// is useful in determining the concrete type.
206
- ///
207
- /// The primary use case is where the expected type is a fat pointer,
208
- /// like `&[isize]`. For example, consider the following statement:
209
- ///
210
- /// let x: &[isize] = &[1, 2, 3];
211
- ///
212
- /// In this case, the expected type for the `&[1, 2, 3]` expression is
213
- /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
214
- /// expectation `ExpectHasType([isize])`, that would be too strong --
215
- /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
216
- /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
217
- /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
218
- /// which still is useful, because it informs integer literals and the like.
219
- /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
220
- /// for examples of where this comes up,.
221
- fn rvalue_hint ( fcx : & FnCtxt < ' a , ' tcx > , ty : Ty < ' tcx > ) -> Expectation < ' tcx > {
222
- match fcx. tcx . struct_tail_without_normalization ( ty) . kind ( ) {
223
- ty:: Slice ( _) | ty:: Str | ty:: Dynamic ( ..) => ExpectRvalueLikeUnsized ( ty) ,
224
- _ => ExpectHasType ( ty) ,
225
- }
226
- }
227
-
228
- // Resolves `expected` by a single level if it is a variable. If
229
- // there is no expected type or resolution is not possible (e.g.,
230
- // no constraints yet present), just returns `None`.
231
- fn resolve ( self , fcx : & FnCtxt < ' a , ' tcx > ) -> Expectation < ' tcx > {
232
- match self {
233
- NoExpectation => NoExpectation ,
234
- ExpectCastableToType ( t) => ExpectCastableToType ( fcx. resolve_vars_if_possible ( & t) ) ,
235
- ExpectHasType ( t) => ExpectHasType ( fcx. resolve_vars_if_possible ( & t) ) ,
236
- ExpectRvalueLikeUnsized ( t) => ExpectRvalueLikeUnsized ( fcx. resolve_vars_if_possible ( & t) ) ,
237
- }
238
- }
239
-
240
- fn to_option ( self , fcx : & FnCtxt < ' a , ' tcx > ) -> Option < Ty < ' tcx > > {
241
- match self . resolve ( fcx) {
242
- NoExpectation => None ,
243
- ExpectCastableToType ( ty) | ExpectHasType ( ty) | ExpectRvalueLikeUnsized ( ty) => Some ( ty) ,
244
- }
245
- }
246
-
247
- /// It sometimes happens that we want to turn an expectation into
248
- /// a **hard constraint** (i.e., something that must be satisfied
249
- /// for the program to type-check). `only_has_type` will return
250
- /// such a constraint, if it exists.
251
- fn only_has_type ( self , fcx : & FnCtxt < ' a , ' tcx > ) -> Option < Ty < ' tcx > > {
252
- match self . resolve ( fcx) {
253
- ExpectHasType ( ty) => Some ( ty) ,
254
- NoExpectation | ExpectCastableToType ( _) | ExpectRvalueLikeUnsized ( _) => None ,
255
- }
256
- }
257
-
258
- /// Like `only_has_type`, but instead of returning `None` if no
259
- /// hard constraint exists, creates a fresh type variable.
260
- fn coercion_target_type ( self , fcx : & FnCtxt < ' a , ' tcx > , span : Span ) -> Ty < ' tcx > {
261
- self . only_has_type ( fcx) . unwrap_or_else ( || {
262
- fcx. next_ty_var ( TypeVariableOrigin { kind : TypeVariableOriginKind :: MiscVariable , span } )
263
- } )
264
- }
265
- }
266
-
267
158
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
268
159
pub enum Needs {
269
160
MutPlace ,
0 commit comments