@@ -71,7 +71,7 @@ use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
71
71
use middle:: ty:: { self , LvaluePreference , TypeAndMut , Ty , TyCtxt } ;
72
72
use middle:: ty:: fold:: TypeFoldable ;
73
73
use middle:: ty:: error:: TypeError ;
74
- use middle:: ty:: relate:: { relate_substs, RelateResult , TypeRelation } ;
74
+ use middle:: ty:: relate:: { relate_substs, Relate , RelateResult , TypeRelation } ;
75
75
use util:: common:: indent;
76
76
77
77
use std:: cell:: RefCell ;
@@ -112,8 +112,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
112
112
self . fcx . tcx ( )
113
113
}
114
114
115
- /// Unify two types (using sub or lub) and produce a noop coercion.
116
- fn unify_and_identity ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
115
+ fn unify ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
117
116
let infcx = self . fcx . infcx ( ) ;
118
117
infcx. commit_if_ok ( |_| {
119
118
let trace = TypeTrace :: types ( self . origin , false , a, b) ;
@@ -122,7 +121,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
122
121
} else {
123
122
infcx. sub ( false , trace) . relate ( & a, & b)
124
123
}
125
- } ) . and_then ( |ty| self . identity ( ty) )
124
+ } )
125
+ }
126
+
127
+ /// Unify two types (using sub or lub) and produce a noop coercion.
128
+ fn unify_and_identity ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
129
+ self . unify ( & a, & b) . and_then ( |ty| self . identity ( ty) )
126
130
}
127
131
128
132
/// Synthesize an identity adjustment.
@@ -167,7 +171,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
167
171
}
168
172
169
173
ty:: TyRef ( r_b, mt_b) => {
170
- return self . coerce_borrowed_pointer ( exprs, a, b, r_b, mt_b. mutbl ) ;
174
+ return self . coerce_borrowed_pointer ( exprs, a, b, r_b, mt_b) ;
171
175
}
172
176
173
177
_ => { }
@@ -200,7 +204,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
200
204
a : Ty < ' tcx > ,
201
205
b : Ty < ' tcx > ,
202
206
r_b : & ' tcx ty:: Region ,
203
- mutbl_b : hir :: Mutability )
207
+ mt_b : TypeAndMut < ' tcx > )
204
208
-> CoerceResult < ' tcx >
205
209
// FIXME(eddyb) use copyable iterators when that becomes ergonomic.
206
210
where E : Fn ( ) -> I ,
@@ -214,68 +218,107 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
214
218
// to type check, we will construct the type that `&M*expr` would
215
219
// yield.
216
220
217
- let ( _r_a , _mutbl_a ) = match a. sty {
221
+ let r_a = match a. sty {
218
222
ty:: TyRef ( r_a, mt_a) => {
219
- try!( coerce_mutbls ( mt_a. mutbl , mutbl_b ) ) ;
220
- ( r_a, mt_a . mutbl )
223
+ try!( coerce_mutbls ( mt_a. mutbl , mt_b . mutbl ) ) ;
224
+ r_a
221
225
}
222
226
_ => return self . unify_and_identity ( a, b)
223
227
} ;
224
228
225
229
let span = self . origin . span ( ) ;
226
- let coercion = Coercion ( span) ;
227
- let r_borrow = {
228
- // If are coercing from `&'a T` to `&'b U`, then we want to
229
- // reborrow the contents of `'a` for the lifetime `'b`
230
- // (which ought to be a sublifetime of `'a`).
231
- if !self . use_lub {
232
- r_b
233
- } else {
234
- // With LUB, we need more flexibility.
235
- let r_borrow = self . fcx . infcx ( ) . next_region_var ( coercion) ;
236
- self . tcx ( ) . mk_region ( r_borrow)
237
- }
238
- } ;
239
- let autoref = Some ( AutoPtr ( r_borrow, mutbl_b) ) ;
240
230
241
- let lvalue_pref = LvaluePreference :: from_mutbl ( mutbl_b ) ;
231
+ let lvalue_pref = LvaluePreference :: from_mutbl ( mt_b . mutbl ) ;
242
232
let mut first_error = None ;
243
233
let ( _, autoderefs, success) = autoderef ( self . fcx , span, a, exprs,
244
234
UnresolvedTypeAction :: Ignore ,
245
235
lvalue_pref,
246
- |inner_ty, autoderef| {
236
+ |referent_ty, autoderef|
237
+ {
247
238
if autoderef == 0 {
248
239
// Don't let this pass, otherwise it would cause
249
240
// &T to autoref to &&T.
250
241
return None ;
251
242
}
252
- let ty = self . tcx ( ) . mk_ref ( r_borrow,
253
- TypeAndMut { ty : inner_ty, mutbl : mutbl_b} ) ;
254
- match self . unify_and_identity ( ty, b) {
243
+
244
+ // At this point, we have deref'd `a` to `referent_ty`. So
245
+ // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
246
+ // In the autoderef loop for `&'a mut Vec<T>`, we would get
247
+ // three callbacks:
248
+ //
249
+ // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
250
+ // - `Vec<T>` -- 1 deref
251
+ // - `[T]` -- 2 deref
252
+ //
253
+ // At each point after the first callback, we want to
254
+ // check to see whether this would match out target type
255
+ // (`&'b mut [T]`) if we autoref'd it. We can't just
256
+ // compare the referent types, though, because we still
257
+ // have to consider the mutability. E.g., in the case
258
+ // we've been considering, we have an `&mut` reference, so
259
+ // the `T` in `[T]` needs to be unified with equality.
260
+ //
261
+ // Therefore, we construct reference types reflecting what
262
+ // the types will be after we do the final auto-ref and
263
+ // compare those. Note that this means we use the target
264
+ // mutability [1], since it may be that we are coercing
265
+ // from `&mut T` to `&U`.
266
+ //
267
+ // One fine point concerns the region that we use [2]. We
268
+ // choose the region such that the region of the final
269
+ // type that results from `unify` will be the region we
270
+ // want for the autoref:
271
+ //
272
+ // - if in lub mode, that means we want to unify `&'a mut [T]`
273
+ // (from source) and `&'b mut [T]` (target).
274
+ // - if in sub mode, that means we want to use `'b` for
275
+ // both pointers. This is because sub mode (somewhat
276
+ // arbitrarily) returns the subtype region. In the case
277
+ // where we are coercing to a target type, we know we
278
+ // want to use that target type region (`'b`) because --
279
+ // for the program to type-check -- it must be the
280
+ // smaller of the two.
281
+ let r = if self . use_lub { r_a} else { r_b} ; // [2] above
282
+ let derefd_ty_a = self . tcx ( ) . mk_ref ( r, TypeAndMut {
283
+ ty : referent_ty,
284
+ mutbl : mt_b. mutbl // [1] above
285
+ } ) ;
286
+ match self . unify ( derefd_ty_a, b) {
287
+ Ok ( ty) => Some ( ty) ,
255
288
Err ( err) => {
256
289
if first_error. is_none ( ) {
257
290
first_error = Some ( err) ;
258
291
}
259
292
None
260
293
}
261
- Ok ( ( ty, _) ) => Some ( ty)
262
294
}
263
295
} ) ;
264
296
265
- match success {
266
- Some ( ty) => {
267
- Ok ( ( ty, AdjustDerefRef ( AutoDerefRef {
268
- autoderefs : autoderefs,
269
- autoref : autoref,
270
- unsize : None
271
- } ) ) )
272
- }
297
+ // Extract type or return an error. We return the first error
298
+ // we got, which should be from relating the "base" type
299
+ // (e.g., in example above, the failure from relating `Vec<T>`
300
+ // to the target type), since that should be the least
301
+ // confusing.
302
+ let ty = match success {
303
+ Some ( ty) => ty,
273
304
None => {
274
- // Return original error as if overloaded deref was never
275
- // attempted, to avoid irrelevant/confusing error messages.
276
- Err ( first_error. expect ( "coerce_borrowed_pointer failed with no error?" ) )
305
+ return Err ( first_error. expect ( "coerce_borrowed_pointer had no error" ) ) ;
277
306
}
278
- }
307
+ } ;
308
+
309
+ // Now apply the autoref. We have to extract the region out of
310
+ // the final ref type we got.
311
+ let r_borrow = match ty. sty {
312
+ ty:: TyRef ( r, _) => r,
313
+ _ => self . tcx ( ) . sess . span_bug ( span,
314
+ & format ! ( "expected a ref type, got {:?}" , ty) )
315
+ } ;
316
+ let autoref = Some ( AutoPtr ( r_borrow, mt_b. mutbl ) ) ;
317
+ Ok ( ( ty, AdjustDerefRef ( AutoDerefRef {
318
+ autoderefs : autoderefs,
319
+ autoref : autoref,
320
+ unsize : None
321
+ } ) ) )
279
322
}
280
323
281
324
0 commit comments