60
60
//! sort of a minor point so I've opted to leave it for later---after all
61
61
//! we may want to adjust precisely when coercions occur.
62
62
63
- use check:: { autoderef, FnCtxt , LvaluePreference , UnresolvedTypeAction } ;
63
+ use check:: { autoderef, impl_self_ty , FnCtxt , LvaluePreference , UnresolvedTypeAction } ;
64
64
65
65
use middle:: infer:: { self , Coercion } ;
66
+ use middle:: subst:: Substs ;
66
67
use middle:: traits:: { self , ObligationCause } ;
67
68
use middle:: traits:: { predicate_for_trait_def, report_selection_error} ;
68
69
use middle:: ty:: { AutoDerefRef , AdjustDerefRef } ;
@@ -79,6 +80,24 @@ struct Coerce<'a, 'tcx: 'a> {
79
80
80
81
type CoerceResult < ' tcx > = RelateResult < ' tcx , Option < ty:: AutoAdjustment < ' tcx > > > ;
81
82
83
+ /// The result of an attempt at coercing a Source type to a
84
+ /// Target type via unsizing (`Source: CoerceUnsized<Target>`).
85
+ /// If successful, all `CoerceUnsized` and `Unsized` obligations were selected.
86
+ /// Other obligations, such as `T: Trait` for `&T -> &Trait`, are provided
87
+ /// alongside the adjustment, to be enforced later.
88
+ type CoerceUnsizedResult < ' tcx > = Result < ( AutoDerefRef < ' tcx > ,
89
+ Vec < traits:: PredicateObligation < ' tcx > > ) ,
90
+ CoerceUnsizedError > ;
91
+
92
+ #[ derive( PartialEq , Eq ) ]
93
+ enum CoerceUnsizedError {
94
+ /// Source definitely does not implement `CoerceUnsized<Target>`.
95
+ Unapplicable ,
96
+
97
+ /// Source might implement `CoerceUnsized<Target>`.
98
+ Ambiguous ,
99
+ }
100
+
82
101
impl < ' f , ' tcx > Coerce < ' f , ' tcx > {
83
102
fn tcx ( & self ) -> & ty:: ctxt < ' tcx > {
84
103
self . fcx . tcx ( )
@@ -99,8 +118,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
99
118
100
119
// Consider coercing the subtype to a DST
101
120
let unsize = self . fcx . infcx ( ) . commit_if_ok ( |_| self . coerce_unsized ( a, b) ) ;
102
- if unsize. is_ok ( ) {
103
- return unsize;
121
+ if let Ok ( ( adjustment, leftover_predicates) ) = unsize {
122
+ for obligation in leftover_predicates {
123
+ self . fcx . register_predicate ( obligation) ;
124
+ }
125
+ return Ok ( Some ( AdjustDerefRef ( adjustment) ) ) ;
104
126
}
105
127
106
128
// Examine the supertype and consider auto-borrowing.
@@ -119,23 +141,97 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
119
141
_ => { }
120
142
}
121
143
144
+ let b = self . fcx . infcx ( ) . shallow_resolve ( b) ;
122
145
match a. sty {
123
146
ty:: TyBareFn ( Some ( _) , a_f) => {
124
147
// Function items are coercible to any closure
125
148
// type; function pointers are not (that would
126
149
// require double indirection).
127
- self . coerce_from_fn_item ( a, a_f, b)
150
+ return self . coerce_from_fn_item ( a, a_f, b) ;
128
151
}
129
152
ty:: TyBareFn ( None , a_f) => {
130
153
// We permit coercion of fn pointers to drop the
131
154
// unsafe qualifier.
132
- self . coerce_from_fn_pointer ( a, a_f, b)
155
+ return self . coerce_from_fn_pointer ( a, a_f, b) ;
133
156
}
134
- _ => {
135
- // Otherwise, just use subtyping rules.
136
- self . subtype ( a, b)
157
+ _ => { }
158
+ }
159
+
160
+ // Attempt to generalize the expected type in hopes of an unsizing
161
+ // coercion, where an intermediary stop-gap is usually necessary.
162
+ // This is the case with trait method calls where the returned type
163
+ // was not inferred, e.g. `Make::make(x: T): Box<Trait>`, if `Make`
164
+ // has many implementations. Unsizing coercion will be ambiguous
165
+ // and subtyping would result in a selection failure, if `Box<Trait>`
166
+ // does not implement `Make`, but `Box<T>` does. The stop-gap fix
167
+ // is `Make::make(x: T): Box<T>: Box<Trait>`.
168
+ // In that same case, the following generalization will attempt to
169
+ // apply `Box<_>` to the otherwise unconstrained `Make::make` return
170
+ // type and trigger selection, hoping to get the unambiguous source
171
+ // type `Box<T>` for the coercion to `Box<Trait>`.
172
+ // Subtyping rules are used if the generalization and second attempt
173
+ // at coercions through unsizing do not apply.
174
+
175
+ // The first unsizing coercion must have failed due to ambiguity.
176
+ if unsize. err ( ) != Some ( CoerceUnsizedError :: Ambiguous ) {
177
+ return self . subtype ( a, b) ;
178
+ }
179
+
180
+ // The target type needs to be a structure or Box<T>.
181
+ // The only other types that implement CoerceUnsized are
182
+ // references and pointers and those have multiple forms,
183
+ // such as `*mut T -> *const Trait`.
184
+ match b. sty {
185
+ ty:: TyBox ( _) | ty:: TyStruct ( ..) => { }
186
+ _ => return self . subtype ( a, b)
187
+ }
188
+
189
+ // Construct a `Target: CoerceUnsized<Target>` predicate.
190
+ let trait_predicate = ty:: Binder ( ty:: TraitRef {
191
+ def_id : self . tcx ( ) . lang_items . coerce_unsized_trait ( ) . unwrap ( ) ,
192
+ substs : self . tcx ( ) . mk_substs ( Substs :: new_trait ( vec ! [ b] , vec ! [ ] , b) )
193
+ } ) . to_poly_trait_predicate ( ) ;
194
+
195
+ // Select `Target: CoerceUnsized<Target>`.
196
+ let mut selcx = traits:: SelectionContext :: new ( self . fcx . infcx ( ) ) ;
197
+ let cause = ObligationCause :: misc ( self . origin . span ( ) , self . fcx . body_id ) ;
198
+ let obligation = traits:: Obligation :: new ( cause, trait_predicate) ;
199
+ if let Ok ( Some ( traits:: VtableImpl ( i) ) ) = selcx. select ( & obligation) {
200
+ // There is a single applicable impl. If `Target = P<Trait>`, then
201
+ // the `Self` of this impl is some kind of supertype of `P<Trait>`,
202
+ // most likely `P<T> forall T: Unsize<U>`.
203
+ // This `Self` type, when all impl type parameters have been
204
+ // substituted with fresh inference variables (e.g. `P<_>`),
205
+ // will unify with the target type and all possible source types
206
+ // for a coercion.
207
+ // It can thus be used as a supertype of the source type,
208
+ // the generalized form that can allow fulfilling pending
209
+ // obligations and ultimately an unsizing coercion.
210
+ let success = self . fcx . infcx ( ) . commit_if_ok ( |_| {
211
+ self . subtype ( a, impl_self_ty ( self . fcx ,
212
+ self . origin . span ( ) ,
213
+ i. impl_def_id ) . ty )
214
+ } ) ;
215
+
216
+ if success. is_ok ( ) {
217
+ // Select pending obligations to constrain the
218
+ // source type further, and resolve it again.
219
+ self . fcx . select_obligations_where_possible ( ) ;
220
+ let a = self . fcx . infcx ( ) . shallow_resolve ( a) ;
221
+
222
+ // Finally, attempt a coercion by unsizing again,
223
+ // now that the types are (hopefully) better known.
224
+ let unsize = self . fcx . infcx ( ) . commit_if_ok ( |_| self . coerce_unsized ( a, b) ) ;
225
+ if let Ok ( ( adjustment, leftover_predicates) ) = unsize {
226
+ for obligation in leftover_predicates {
227
+ self . fcx . register_predicate ( obligation) ;
228
+ }
229
+ return Ok ( Some ( AdjustDerefRef ( adjustment) ) ) ;
230
+ }
137
231
}
138
232
}
233
+
234
+ self . subtype ( a, b)
139
235
}
140
236
141
237
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
@@ -218,7 +314,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
218
314
fn coerce_unsized ( & self ,
219
315
source : Ty < ' tcx > ,
220
316
target : Ty < ' tcx > )
221
- -> CoerceResult < ' tcx > {
317
+ -> CoerceUnsizedResult < ' tcx > {
222
318
debug ! ( "coerce_unsized(source={:?}, target={:?})" ,
223
319
source,
224
320
target) ;
@@ -229,7 +325,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
229
325
( u, cu)
230
326
} else {
231
327
debug ! ( "Missing Unsize or CoerceUnsized traits" ) ;
232
- return Err ( TypeError :: Mismatch ) ;
328
+ return Err ( CoerceUnsizedError :: Unapplicable ) ;
233
329
} ;
234
330
235
331
// Note, we want to avoid unnecessary unsizing. We don't want to coerce to
@@ -240,15 +336,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
240
336
// Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
241
337
let ( source, reborrow) = match ( & source. sty , & target. sty ) {
242
338
( & ty:: TyRef ( _, mt_a) , & ty:: TyRef ( _, mt_b) ) => {
243
- try!( coerce_mutbls ( mt_a. mutbl , mt_b. mutbl ) ) ;
339
+ if coerce_mutbls ( mt_a. mutbl , mt_b. mutbl ) . is_err ( ) {
340
+ return Err ( CoerceUnsizedError :: Unapplicable ) ;
341
+ }
244
342
245
343
let coercion = Coercion ( self . origin . span ( ) ) ;
246
344
let r_borrow = self . fcx . infcx ( ) . next_region_var ( coercion) ;
247
345
let region = self . tcx ( ) . mk_region ( r_borrow) ;
248
346
( mt_a. ty , Some ( ty:: AutoPtr ( region, mt_b. mutbl ) ) )
249
347
}
250
348
( & ty:: TyRef ( _, mt_a) , & ty:: TyRawPtr ( mt_b) ) => {
251
- try!( coerce_mutbls ( mt_a. mutbl , mt_b. mutbl ) ) ;
349
+ if coerce_mutbls ( mt_a. mutbl , mt_b. mutbl ) . is_err ( ) {
350
+ return Err ( CoerceUnsizedError :: Unapplicable ) ;
351
+ }
252
352
( mt_a. ty , Some ( ty:: AutoUnsafe ( mt_b. mutbl ) ) )
253
353
}
254
354
_ => ( source, None )
@@ -287,9 +387,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
287
387
} ;
288
388
match selcx. select ( & obligation. with ( trait_ref) ) {
289
389
// Uncertain or unimplemented.
290
- Ok ( None ) | Err ( traits:: Unimplemented ) => {
291
- debug ! ( "coerce_unsized: early return - can't prove obligation" ) ;
292
- return Err ( TypeError :: Mismatch ) ;
390
+ Ok ( None ) => {
391
+ debug ! ( "coerce_unsized: early return (Ambiguous)" ) ;
392
+ return Err ( CoerceUnsizedError :: Ambiguous ) ;
393
+ }
394
+ Err ( traits:: Unimplemented ) => {
395
+ debug ! ( "coerce_unsized: early return (Unapplicable)" ) ;
396
+ return Err ( CoerceUnsizedError :: Unapplicable ) ;
293
397
}
294
398
295
399
// Object safety violations or miscellaneous.
@@ -308,18 +412,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
308
412
}
309
413
}
310
414
311
- // Save all the obligations that are not for CoerceUnsized or Unsize.
312
- for obligation in leftover_predicates {
313
- self . fcx . register_predicate ( obligation) ;
314
- }
315
-
316
415
let adjustment = AutoDerefRef {
317
416
autoderefs : if reborrow. is_some ( ) { 1 } else { 0 } ,
318
417
autoref : reborrow,
319
418
unsize : Some ( target)
320
419
} ;
321
420
debug ! ( "Success, coerced with {:?}" , adjustment) ;
322
- Ok ( Some ( AdjustDerefRef ( adjustment) ) )
421
+ Ok ( ( adjustment, leftover_predicates ) )
323
422
}
324
423
325
424
fn coerce_from_fn_pointer ( & self ,
@@ -333,7 +432,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
333
432
* into a closure or a `proc`.
334
433
*/
335
434
336
- let b = self . fcx . infcx ( ) . shallow_resolve ( b) ;
337
435
debug ! ( "coerce_from_fn_pointer(a={:?}, b={:?})" ,
338
436
a, b) ;
339
437
@@ -360,7 +458,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
360
458
* into a closure or a `proc`.
361
459
*/
362
460
363
- let b = self . fcx . infcx ( ) . shallow_resolve ( b) ;
364
461
debug ! ( "coerce_from_fn_item(a={:?}, b={:?})" ,
365
462
a, b) ;
366
463
0 commit comments