@@ -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 }
233- ty:: Ref ( r_b , _, mutbl_b) => {
234- return self . coerce_borrowed_pointer ( a, b, r_b , mutbl_b) ;
232+ ty:: Ref ( _ , _, mutbl_b) => {
233+ return self . coerce_to_ref ( a, b, mutbl_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,26 +309,23 @@ 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 ,
322324 ) -> CoerceResult < ' tcx > {
323- debug ! ( "coerce_borrowed_pointer (a={:?}, b={:?})" , a, b) ;
325+ debug ! ( "coerce_to_ref (a={:?}, b={:?})" , a, b) ;
324326 debug_assert ! ( self . shallow_resolve( a) == a) ;
325327 debug_assert ! ( self . shallow_resolve( b) == b) ;
326328
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-
333329 let ( r_a, mt_a) = match * a. kind ( ) {
334330 ty:: Ref ( r_a, ty, mutbl) => {
335331 let mt_a = ty:: TypeAndMut { ty, mutbl } ;
@@ -339,130 +335,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
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 ;
345- 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 ( ) {
350+ let mut autoderef = self . autoderef ( self . cause . span , a) ;
351+ let found = autoderef. by_ref ( ) . find_map ( |( deref_ty, autoderefs) | {
350352 if autoderefs == 0 {
351- // Don't let this pass, otherwise it would cause
352- // &T to autoref to &&T.
353- continue ;
353+ // Don't autoref the first step as otherwise we'd allow
354+ // coercing `&T` to ` &&T` .
355+ return None ;
354356 }
355357
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`.
378- //
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.
426- let r = if !self . use_lub {
427- r_b // [2] above
428- } else if autoderefs == 1 {
429- r_a // [3] above
430- } else {
431- if r_borrow_var. is_none ( ) {
432- // create var lazily, at most once
433- let coercion = RegionVariableOrigin :: Coercion ( span) ;
434- let r = self . next_region_var ( coercion) ;
435- r_borrow_var = Some ( r) ; // [4] above
436- }
437- r_borrow_var. unwrap ( )
438- } ;
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- }
358+ let coercion = RegionVariableOrigin :: Coercion ( self . cause . span ) ;
359+ let r_borrow = self . next_region_var ( coercion) ;
360+ let autorefd_deref_ty = Ty :: new_ref ( self . tcx , r_borrow, deref_ty, mutbl_b) ;
361+
362+ // Note that we unify the autoref'd `Target` type with `b` rather than
363+ // the `Target` type with the pointee of `b`. This is necessary
364+ // to properly account for the differing variances of the pointees
365+ // of `&` vs `&mut` references.
366+ match self . unify_raw ( autorefd_deref_ty, b) {
367+ Ok ( ok) => Some ( ok) ,
450368 Err ( err) => {
451369 if first_error. is_none ( ) {
452370 first_error = Some ( err) ;
453371 }
372+ None
454373 }
455374 }
456- }
375+ } ) ;
457376
458377 // Extract type or return an error. We return the first error
459378 // we got, which should be from relating the "base" type
460379 // (e.g., in example above, the failure from relating `Vec<T>`
461380 // to the target type), since that should be the least
462381 // confusing.
463- let Some ( InferOk { value : ty , mut obligations } ) = found else {
382+ let Some ( InferOk { value : coerced_a , mut obligations } ) = found else {
464383 if let Some ( first_error) = first_error {
465- debug ! ( "coerce_borrowed_pointer : failed with err = {:?}" , first_error) ;
384+ debug ! ( "coerce_to_ref : failed with err = {:?}" , first_error) ;
466385 return Err ( first_error) ;
467386 } else {
468387 // This may happen in the new trait solver since autoderef requires
@@ -474,7 +393,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
474393 }
475394 } ;
476395
477- if ty == a && mt_a. mutbl . is_not ( ) && autoderef. step_count ( ) == 1 {
396+ if coerced_a == a && mt_a. mutbl . is_not ( ) && autoderef. step_count ( ) == 1 {
478397 // As a special case, if we would produce `&'a *x`, that's
479398 // a total no-op. We end up with the type `&'a T` just as
480399 // we started with. In that case, just skip it
@@ -487,7 +406,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
487406 // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
488407 // which is a borrow.
489408 assert ! ( mutbl_b. is_not( ) ) ; // can only coerce &T -> &U
490- return success ( vec ! [ ] , ty , obligations) ;
409+ return success ( vec ! [ ] , coerced_a , obligations) ;
491410 }
492411
493412 let InferOk { value : mut adjustments, obligations : o } =
@@ -497,15 +416,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
497416
498417 // Now apply the autoref. We have to extract the region out of
499418 // the final ref type we got.
500- let ty:: Ref ( ..) = ty . kind ( ) else {
501- span_bug ! ( span, "expected a ref type, got {:?}" , ty ) ;
419+ let ty:: Ref ( ..) = coerced_a . kind ( ) else {
420+ span_bug ! ( self . cause . span, "expected a ref type, got {:?}" , coerced_a ) ;
502421 } ;
503422 let mutbl = AutoBorrowMutability :: new ( mutbl_b, self . allow_two_phase ) ;
504- adjustments. push ( Adjustment { kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) , target : ty } ) ;
423+ adjustments
424+ . push ( Adjustment { kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) , target : coerced_a } ) ;
505425
506- debug ! ( "coerce_borrowed_pointer : succeeded ty ={:?} adjustments={:?}" , ty , adjustments) ;
426+ debug ! ( "coerce_to_ref : succeeded coerced_a ={:?} adjustments={:?}" , coerced_a , adjustments) ;
507427
508- success ( adjustments, ty , obligations)
428+ success ( adjustments, coerced_a , obligations)
509429 }
510430
511431 /// Performs [unsized coercion] by emulating a fulfillment loop on a
@@ -568,9 +488,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
568488 | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
569489 _ => { }
570490 }
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.
491+ // `&str: CoerceUnsized<&str>` does not hold but is encountered frequently
492+ // so we fast path bail out here
574493 if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
575494 && source_pointee. is_str ( )
576495 && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
@@ -809,7 +728,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
809728 /// - `Pin<Box<T>>` as `Pin<&T>`
810729 /// - `Pin<Box<T>>` as `Pin<&mut T>`
811730 #[ instrument( skip( self ) , level = "trace" ) ]
812- fn coerce_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
731+ fn coerce_to_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
813732 debug_assert ! ( self . shallow_resolve( a) == a) ;
814733 debug_assert ! ( self . shallow_resolve( b) == b) ;
815734
@@ -1012,13 +931,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1012931 }
1013932 }
1014933
1015- fn coerce_raw_ptr (
934+ fn coerce_to_raw_ptr (
1016935 & self ,
1017936 a : Ty < ' tcx > ,
1018937 b : Ty < ' tcx > ,
1019938 mutbl_b : hir:: Mutability ,
1020939 ) -> CoerceResult < ' tcx > {
1021- debug ! ( "coerce_raw_ptr (a={:?}, b={:?})" , a, b) ;
940+ debug ! ( "coerce_to_raw_ptr (a={:?}, b={:?})" , a, b) ;
1022941 debug_assert ! ( self . shallow_resolve( a) == a) ;
1023942 debug_assert ! ( self . shallow_resolve( b) == b) ;
1024943
0 commit comments