@@ -230,6 +230,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
230230
231231 let lvalue_pref = LvaluePreference :: from_mutbl ( mt_b. mutbl ) ;
232232 let mut first_error = None ;
233+ let mut r_borrow_var = None ;
233234 let ( _, autoderefs, success) = autoderef ( self . fcx , span, a, exprs,
234235 UnresolvedTypeAction :: Ignore ,
235236 lvalue_pref,
@@ -264,21 +265,57 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
264265 // mutability [1], since it may be that we are coercing
265266 // from `&mut T` to `&U`.
266267 //
267- // One fine point concerns the region that we use [2] . We
268+ // One fine point concerns the region that we use. We
268269 // choose the region such that the region of the final
269270 // type that results from `unify` will be the region we
270271 // want for the autoref:
271272 //
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
276276 // arbitrarily) returns the subtype region. In the case
277277 // where we are coercing to a target type, we know we
278278 // want to use that target type region (`'b`) because --
279279 // for the program to type-check -- it must be the
280280 // 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+ } ;
282319 let derefd_ty_a = self . tcx ( ) . mk_ref ( r, TypeAndMut {
283320 ty : referent_ty,
284321 mutbl : mt_b. mutbl // [1] above
@@ -302,18 +339,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
302339 let ty = match success {
303340 Some ( ty) => ty,
304341 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) ;
306345 }
307346 } ;
308347
309348 // Now apply the autoref. We have to extract the region out of
310349 // the final ref type we got.
311350 let r_borrow = match ty. sty {
312- ty:: TyRef ( r , _) => r ,
351+ ty:: TyRef ( r_borrow , _) => r_borrow ,
313352 _ => self . tcx ( ) . sess . span_bug ( span,
314353 & format ! ( "expected a ref type, got {:?}" , ty) )
315354 } ;
316355 let autoref = Some ( AutoPtr ( r_borrow, mt_b. mutbl ) ) ;
356+ debug ! ( "coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}" ,
357+ ty, autoderefs, autoref) ;
317358 Ok ( ( ty, AdjustDerefRef ( AutoDerefRef {
318359 autoderefs : autoderefs,
319360 autoref : autoref,
0 commit comments