@@ -230,6 +230,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
230
230
231
231
let lvalue_pref = LvaluePreference :: from_mutbl ( mt_b. mutbl ) ;
232
232
let mut first_error = None ;
233
+ let mut r_borrow_var = None ;
233
234
let ( _, autoderefs, success) = autoderef ( self . fcx , span, a, exprs,
234
235
UnresolvedTypeAction :: Ignore ,
235
236
lvalue_pref,
@@ -264,21 +265,57 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
264
265
// mutability [1], since it may be that we are coercing
265
266
// from `&mut T` to `&U`.
266
267
//
267
- // One fine point concerns the region that we use [2] . We
268
+ // One fine point concerns the region that we use. We
268
269
// choose the region such that the region of the final
269
270
// type that results from `unify` will be the region we
270
271
// want for the autoref:
271
272
//
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
273
+ // - if in sub mode, that means we want to use `'b` (the
274
+ // region from the target reference) for both
275
+ // pointers [2]. This is because sub mode (somewhat
276
276
// arbitrarily) returns the subtype region. In the case
277
277
// where we are coercing to a target type, we know we
278
278
// want to use that target type region (`'b`) because --
279
279
// for the program to type-check -- it must be the
280
280
// smaller of the two.
281
- let r = if self . use_lub { r_a} else { r_b} ; // [2] above
281
+ // - if in lub mode, things can get fairly complicated. The
282
+ // easiest thing is just to make a fresh
283
+ // region variable [4], which effectively means we defer
284
+ // the decision to region inference (and regionck, which will add
285
+ // some more edges to this variable). However, this can wind up
286
+ // creating a crippling number of variables in some cases --
287
+ // e.g. #32278 -- so we optimize one particular case [3].
288
+ // Let me try to explain with some examples:
289
+ // - The "running example" above represents the simple case,
290
+ // where we have one `&` reference at the outer level and
291
+ // ownership all the rest of the way down. In this case,
292
+ // we want `LUB('a, 'b)` as the resulting region.
293
+ // - However, if there are nested borrows, that region is
294
+ // too strong. Consider a coercion from `&'a &'x Rc<T>` to
295
+ // `&'b T`. In this case, `'a` is actually irrelevant.
296
+ // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)`
297
+ // we get spurious errors (`run-pass/regions-lub-ref-ref-rc.rs`).
298
+ // (The errors actually show up in borrowck, typically, because
299
+ // this extra edge causes the region `'a` to be inferred to something
300
+ // too big, which then results in borrowck errors.)
301
+ // - We could track the innermost shared reference, but there is already
302
+ // code in regionck that has the job of creating links between
303
+ // the region of a borrow and the regions in the thing being
304
+ // borrowed (here, `'a` and `'x`), and it knows how to handle
305
+ // all the various cases. So instead we just make a region variable
306
+ // and let regionck figure it out.
307
+ let r = if !self . use_lub {
308
+ r_b // [2] above
309
+ } else if autoderef == 1 {
310
+ r_a // [3] above
311
+ } else {
312
+ if r_borrow_var. is_none ( ) { // create var lazilly, at most once
313
+ let coercion = Coercion ( span) ;
314
+ let r = self . fcx . infcx ( ) . next_region_var ( coercion) ;
315
+ r_borrow_var = Some ( self . tcx ( ) . mk_region ( r) ) ; // [4] above
316
+ }
317
+ r_borrow_var. unwrap ( )
318
+ } ;
282
319
let derefd_ty_a = self . tcx ( ) . mk_ref ( r, TypeAndMut {
283
320
ty : referent_ty,
284
321
mutbl : mt_b. mutbl // [1] above
@@ -302,18 +339,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
302
339
let ty = match success {
303
340
Some ( ty) => ty,
304
341
None => {
305
- return Err ( first_error. expect ( "coerce_borrowed_pointer had no error" ) ) ;
342
+ let err = first_error. expect ( "coerce_borrowed_pointer had no error" ) ;
343
+ debug ! ( "coerce_borrowed_pointer: failed with err = {:?}" , err) ;
344
+ return Err ( err) ;
306
345
}
307
346
} ;
308
347
309
348
// Now apply the autoref. We have to extract the region out of
310
349
// the final ref type we got.
311
350
let r_borrow = match ty. sty {
312
- ty:: TyRef ( r , _) => r ,
351
+ ty:: TyRef ( r_borrow , _) => r_borrow ,
313
352
_ => self . tcx ( ) . sess . span_bug ( span,
314
353
& format ! ( "expected a ref type, got {:?}" , ty) )
315
354
} ;
316
355
let autoref = Some ( AutoPtr ( r_borrow, mt_b. mutbl ) ) ;
356
+ debug ! ( "coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}" ,
357
+ ty, autoderefs, autoref) ;
317
358
Ok ( ( ty, AdjustDerefRef ( AutoDerefRef {
318
359
autoderefs : autoderefs,
319
360
autoref : autoref,
0 commit comments