@@ -179,7 +179,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
179179 } )
180180 }
181181
182- #[ instrument( skip( self ) ) ]
182+ #[ instrument( skip( self ) , ret ) ]
183183 fn coerce ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
184184 // First, remove any resolved type variables (at the top level, at least):
185185 let a = self . shallow_resolve ( a) ;
@@ -223,21 +223,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
223223 }
224224 }
225225
226- // Examine the supertype and consider type-specific coercions, such
227- // as auto-borrowing, coercing pointer mutability, a `dyn*` coercion,
228- // or pin-ergonomics.
226+ // Examine the target type and consider type-specific coercions, such
227+ // as auto-borrowing, coercing pointer mutability, or pin-ergonomics.
229228 match * b. kind ( ) {
230229 ty:: RawPtr ( _, b_mutbl) => {
231- return self . coerce_raw_ptr ( a, b, b_mutbl) ;
230+ return self . coerce_to_raw_ptr ( a, b, b_mutbl) ;
232231 }
233232 ty:: Ref ( r_b, _, mutbl_b) => {
234- return self . coerce_borrowed_pointer ( a, b, r_b , mutbl_b ) ;
233+ return self . coerce_to_ref ( a, b, mutbl_b , r_b ) ;
235234 }
236235 ty:: Adt ( pin, _)
237236 if self . tcx . features ( ) . pin_ergonomics ( )
238237 && self . tcx . is_lang_item ( pin. did ( ) , hir:: LangItem :: Pin ) =>
239238 {
240- let pin_coerce = self . commit_if_ok ( |_| self . coerce_pin_ref ( a, b) ) ;
239+ let pin_coerce = self . commit_if_ok ( |_| self . coerce_to_pin_ref ( a, b) ) ;
241240 if pin_coerce. is_ok ( ) {
242241 return pin_coerce;
243242 }
@@ -310,159 +309,99 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
310309 }
311310 }
312311
313- /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
314- /// To match `A` with `B`, autoderef will be performed,
315- /// calling `deref`/`deref_mut` where necessary.
316- fn coerce_borrowed_pointer (
312+ /// Handles coercing some arbitrary type `a` to some reference (`b`). This
313+ /// handles a few cases:
314+ /// - Introducing reborrows to give more flexible lifetimes
315+ /// - Deref coercions to allow `&T` to coerce to `&T::Target`
316+ /// - Coercing mutable references to immutable references
317+ /// These coercions can be freely intermixed, for example we are able to
318+ /// coerce `&mut T` to `&mut T::Target`.
319+ fn coerce_to_ref (
317320 & self ,
318321 a : Ty < ' tcx > ,
319322 b : Ty < ' tcx > ,
320- r_b : ty:: Region < ' tcx > ,
321323 mutbl_b : hir:: Mutability ,
324+ r_b : ty:: Region < ' tcx > ,
322325 ) -> CoerceResult < ' tcx > {
323- debug ! ( "coerce_borrowed_pointer (a={:?}, b={:?})" , a, b) ;
326+ debug ! ( "coerce_to_ref (a={:?}, b={:?})" , a, b) ;
324327 debug_assert ! ( self . shallow_resolve( a) == a) ;
325328 debug_assert ! ( self . shallow_resolve( b) == b) ;
326329
327- // If we have a parameter of type `&M T_a` and the value
328- // provided is `expr`, we will be adding an implicit borrow,
329- // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
330- // to type check, we will construct the type that `&M*expr` would
331- // yield.
332-
333330 let ( r_a, mt_a) = match * a. kind ( ) {
334331 ty:: Ref ( r_a, ty, mutbl) => {
335- let mt_a = ty:: TypeAndMut { ty, mutbl } ;
336- coerce_mutbls ( mt_a. mutbl , mutbl_b) ?;
337- ( r_a, mt_a)
332+ coerce_mutbls ( mutbl, mutbl_b) ?;
333+ ( r_a, ty:: TypeAndMut { ty, mutbl } )
338334 }
339335 _ => return self . unify ( a, b) ,
340336 } ;
341337
342- let span = self . cause . span ;
343-
338+ // Look at each step in the `Deref` chain and check if
339+ // any of the autoref'd `Target` types unify with the
340+ // coercion target.
341+ //
342+ // For example when coercing from `&mut Vec<T>` to `&M [T]` we
343+ // have three deref steps:
344+ // 1. `&mut Vec<T>`, skip autoref
345+ // 2. `Vec<T>`, autoref'd ty: `&M Vec<T>`
346+ // - `&M Vec<T>` does not unify with `&M [T]`
347+ // 3. `[T]`, autoref'd ty: `&M [T]`
348+ // - `&M [T]` does unify with `&M [T]`
344349 let mut first_error = None ;
345350 let mut r_borrow_var = None ;
346- let mut autoderef = self . autoderef ( span, a) ;
347- let mut found = None ;
348-
349- for ( referent_ty, autoderefs) in autoderef. by_ref ( ) {
351+ let mut autoderef = self . autoderef ( self . cause . span , a) ;
352+ let found = autoderef. by_ref ( ) . find_map ( |( deref_ty, autoderefs) | {
350353 if autoderefs == 0 {
351- // Don't let this pass, otherwise it would cause
352- // &T to autoref to &&T.
353- continue ;
354+ // Don't autoref the first step as otherwise we'd allow
355+ // coercing `&T` to ` &&T` .
356+ return None ;
354357 }
355358
356- // At this point, we have deref'd `a` to `referent_ty`. So
357- // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
358- // In the autoderef loop for `&'a mut Vec<T>`, we would get
359- // three callbacks:
360- //
361- // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
362- // - `Vec<T>` -- 1 deref
363- // - `[T]` -- 2 deref
364- //
365- // At each point after the first callback, we want to
366- // check to see whether this would match out target type
367- // (`&'b mut [T]`) if we autoref'd it. We can't just
368- // compare the referent types, though, because we still
369- // have to consider the mutability. E.g., in the case
370- // we've been considering, we have an `&mut` reference, so
371- // the `T` in `[T]` needs to be unified with equality.
372- //
373- // Therefore, we construct reference types reflecting what
374- // the types will be after we do the final auto-ref and
375- // compare those. Note that this means we use the target
376- // mutability [1], since it may be that we are coercing
377- // from `&mut T` to `&U`.
359+ // The logic here really shouldn't exist. We don't care about free
360+ // lifetimes during HIR typeck. Unfortunately later parts of this
361+ // function rely on structural identity of the autoref'd deref'd ty.
378362 //
379- // One fine point concerns the region that we use. We
380- // choose the region such that the region of the final
381- // type that results from `unify` will be the region we
382- // want for the autoref:
383- //
384- // - if in sub mode, that means we want to use `'b` (the
385- // region from the target reference) for both
386- // pointers [2]. This is because sub mode (somewhat
387- // arbitrarily) returns the subtype region. In the case
388- // where we are coercing to a target type, we know we
389- // want to use that target type region (`'b`) because --
390- // for the program to type-check -- it must be the
391- // smaller of the two.
392- // - One fine point. It may be surprising that we can
393- // use `'b` without relating `'a` and `'b`. The reason
394- // that this is ok is that what we produce is
395- // effectively a `&'b *x` expression (if you could
396- // annotate the region of a borrow), and regionck has
397- // code that adds edges from the region of a borrow
398- // (`'b`, here) into the regions in the borrowed
399- // expression (`*x`, here). (Search for "link".)
400- // - if in lub mode, things can get fairly complicated. The
401- // easiest thing is just to make a fresh
402- // region variable [4], which effectively means we defer
403- // the decision to region inference (and regionck, which will add
404- // some more edges to this variable). However, this can wind up
405- // creating a crippling number of variables in some cases --
406- // e.g., #32278 -- so we optimize one particular case [3].
407- // Let me try to explain with some examples:
408- // - The "running example" above represents the simple case,
409- // where we have one `&` reference at the outer level and
410- // ownership all the rest of the way down. In this case,
411- // we want `LUB('a, 'b)` as the resulting region.
412- // - However, if there are nested borrows, that region is
413- // too strong. Consider a coercion from `&'a &'x Rc<T>` to
414- // `&'b T`. In this case, `'a` is actually irrelevant.
415- // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)`
416- // we get spurious errors (`ui/regions-lub-ref-ref-rc.rs`).
417- // (The errors actually show up in borrowck, typically, because
418- // this extra edge causes the region `'a` to be inferred to something
419- // too big, which then results in borrowck errors.)
420- // - We could track the innermost shared reference, but there is already
421- // code in regionck that has the job of creating links between
422- // the region of a borrow and the regions in the thing being
423- // borrowed (here, `'a` and `'x`), and it knows how to handle
424- // all the various cases. So instead we just make a region variable
425- // and let regionck figure it out.
363+ // This means that what region we use here actually impacts whether
364+ // we emit a reborrow coercion or not which can affect diagnostics
365+ // and capture analysis (which in turn affects borrowck).
426366 let r = if !self . use_lub {
427- r_b // [2] above
367+ r_b
428368 } else if autoderefs == 1 {
429- r_a // [3] above
369+ r_a
430370 } else {
431371 if r_borrow_var. is_none ( ) {
432372 // create var lazily, at most once
433- let coercion = RegionVariableOrigin :: Coercion ( span) ;
373+ let coercion = RegionVariableOrigin :: Coercion ( self . cause . span ) ;
434374 let r = self . next_region_var ( coercion) ;
435- r_borrow_var = Some ( r) ; // [4] above
375+ r_borrow_var = Some ( r) ;
436376 }
437377 r_borrow_var. unwrap ( )
438378 } ;
439- let derefd_ty_a = Ty :: new_ref (
440- self . tcx ,
441- r,
442- referent_ty,
443- mutbl_b, // [1] above
444- ) ;
445- match self . unify_raw ( derefd_ty_a, b) {
446- Ok ( ok) => {
447- found = Some ( ok) ;
448- break ;
449- }
379+
380+ let autorefd_deref_ty = Ty :: new_ref ( self . tcx , r, deref_ty, mutbl_b) ;
381+
382+ // Note that we unify the autoref'd `Target` type with `b` rather than
383+ // the `Target` type with the pointee of `b`. This is necessary
384+ // to properly account for the differing variances of the pointees
385+ // of `&` vs `&mut` references.
386+ match self . unify_raw ( autorefd_deref_ty, b) {
387+ Ok ( ok) => Some ( ok) ,
450388 Err ( err) => {
451389 if first_error. is_none ( ) {
452390 first_error = Some ( err) ;
453391 }
392+ None
454393 }
455394 }
456- }
395+ } ) ;
457396
458397 // Extract type or return an error. We return the first error
459398 // we got, which should be from relating the "base" type
460399 // (e.g., in example above, the failure from relating `Vec<T>`
461400 // to the target type), since that should be the least
462401 // confusing.
463- let Some ( InferOk { value : ty , mut obligations } ) = found else {
402+ let Some ( InferOk { value : coerced_a , mut obligations } ) = found else {
464403 if let Some ( first_error) = first_error {
465- debug ! ( "coerce_borrowed_pointer : failed with err = {:?}" , first_error) ;
404+ debug ! ( "coerce_to_ref : failed with err = {:?}" , first_error) ;
466405 return Err ( first_error) ;
467406 } else {
468407 // This may happen in the new trait solver since autoderef requires
@@ -474,11 +413,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
474413 }
475414 } ;
476415
477- if ty == a && mt_a. mutbl . is_not ( ) && autoderef. step_count ( ) == 1 {
416+ if coerced_a == a && mt_a. mutbl . is_not ( ) && autoderef. step_count ( ) == 1 {
478417 // As a special case, if we would produce `&'a *x`, that's
479418 // a total no-op. We end up with the type `&'a T` just as
480- // we started with. In that case, just skip it
481- // altogether. This is just an optimization.
419+ // we started with. In that case, just skip it altogether.
420+ //
421+ // Unfortunately, this can actually effect capture analysis
422+ // which in turn means this effects borrow checking. This can
423+ // also effect diagnostics.
424+ // FIXME(BoxyUwU): we should always emit reborrow coercions
482425 //
483426 // Note that for `&mut`, we DO want to reborrow --
484427 // otherwise, this would be a move, which might be an
@@ -487,25 +430,25 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
487430 // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
488431 // which is a borrow.
489432 assert ! ( mutbl_b. is_not( ) ) ; // can only coerce &T -> &U
490- return success ( vec ! [ ] , ty , obligations) ;
433+ return success ( vec ! [ ] , coerced_a , obligations) ;
491434 }
492435
493436 let InferOk { value : mut adjustments, obligations : o } =
494437 self . adjust_steps_as_infer_ok ( & autoderef) ;
495438 obligations. extend ( o) ;
496439 obligations. extend ( autoderef. into_obligations ( ) ) ;
497440
498- // Now apply the autoref. We have to extract the region out of
499- // the final ref type we got.
500- let ty:: Ref ( ..) = ty. kind ( ) else {
501- span_bug ! ( span, "expected a ref type, got {:?}" , ty) ;
441+ // Now apply the autoref
442+ let ty:: Ref ( ..) = coerced_a. kind ( ) else {
443+ span_bug ! ( self . cause. span, "expected a ref type, got {:?}" , coerced_a) ;
502444 } ;
503445 let mutbl = AutoBorrowMutability :: new ( mutbl_b, self . allow_two_phase ) ;
504- adjustments. push ( Adjustment { kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) , target : ty } ) ;
446+ adjustments
447+ . push ( Adjustment { kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) , target : coerced_a } ) ;
505448
506- debug ! ( "coerce_borrowed_pointer : succeeded ty ={:?} adjustments={:?}" , ty , adjustments) ;
449+ debug ! ( "coerce_to_ref : succeeded coerced_a ={:?} adjustments={:?}" , coerced_a , adjustments) ;
507450
508- success ( adjustments, ty , obligations)
451+ success ( adjustments, coerced_a , obligations)
509452 }
510453
511454 /// Performs [unsized coercion] by emulating a fulfillment loop on a
@@ -568,9 +511,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
568511 | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
569512 _ => { }
570513 }
571- // Additionally, we ignore `&str -> &str` coercions, which happen very
572- // commonly since strings are one of the most used argument types in Rust,
573- // we do coercions when type checking call expressions.
514+ // `&str: CoerceUnsized<&str>` does not hold but is encountered frequently
515+ // so we fast path bail out here
574516 if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
575517 && source_pointee. is_str ( )
576518 && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
@@ -809,7 +751,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
809751 /// - `Pin<Box<T>>` as `Pin<&T>`
810752 /// - `Pin<Box<T>>` as `Pin<&mut T>`
811753 #[ instrument( skip( self ) , level = "trace" ) ]
812- fn coerce_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
754+ fn coerce_to_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
813755 debug_assert ! ( self . shallow_resolve( a) == a) ;
814756 debug_assert ! ( self . shallow_resolve( b) == b) ;
815757
@@ -1012,13 +954,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1012954 }
1013955 }
1014956
1015- fn coerce_raw_ptr (
957+ fn coerce_to_raw_ptr (
1016958 & self ,
1017959 a : Ty < ' tcx > ,
1018960 b : Ty < ' tcx > ,
1019961 mutbl_b : hir:: Mutability ,
1020962 ) -> CoerceResult < ' tcx > {
1021- debug ! ( "coerce_raw_ptr (a={:?}, b={:?})" , a, b) ;
963+ debug ! ( "coerce_to_raw_ptr (a={:?}, b={:?})" , a, b) ;
1022964 debug_assert ! ( self . shallow_resolve( a) == a) ;
1023965 debug_assert ! ( self . shallow_resolve( b) == b) ;
1024966
0 commit comments