@@ -221,21 +221,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
221221 }
222222 }
223223
224- // Examine the supertype and consider type-specific coercions, such
225- // as auto-borrowing, coercing pointer mutability, a `dyn*` coercion,
226- // or pin-ergonomics.
224+ // Examine the target type and consider type-specific coercions, such
225+ // as auto-borrowing, coercing pointer mutability, or pin-ergonomics.
227226 match * b. kind ( ) {
228227 ty:: RawPtr ( _, b_mutbl) => {
229- return self . coerce_raw_ptr ( a, b, b_mutbl) ;
228+ return self . coerce_to_raw_ptr ( a, b, b_mutbl) ;
230229 }
231- ty:: Ref ( r_b , _, mutbl_b) => {
232- return self . coerce_borrowed_pointer ( a, b, r_b , mutbl_b) ;
230+ ty:: Ref ( _ , _, mutbl_b) => {
231+ return self . coerce_to_ref ( a, b, mutbl_b) ;
233232 }
234233 ty:: Adt ( pin, _)
235234 if self . tcx . features ( ) . pin_ergonomics ( )
236235 && self . tcx . is_lang_item ( pin. did ( ) , hir:: LangItem :: Pin ) =>
237236 {
238- let pin_coerce = self . commit_if_ok ( |_| self . coerce_pin_ref ( a, b) ) ;
237+ let pin_coerce = self . commit_if_ok ( |_| self . coerce_to_pin_ref ( a, b) ) ;
239238 if pin_coerce. is_ok ( ) {
240239 return pin_coerce;
241240 }
@@ -308,26 +307,23 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
308307 }
309308 }
310309
311- /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
312- /// To match `A` with `B`, autoderef will be performed,
313- /// calling `deref`/`deref_mut` where necessary.
314- fn coerce_borrowed_pointer (
310+ /// Handles coercing some arbitrary type `a` to some reference (`b`). This
311+ /// handles a few cases:
312+ /// - Introducing reborrows to give more flexible lifetimes
313+ /// - Deref coercions to allow `&T` to coerce to `&T::Target`
314+ /// - Coercing mutable references to immutable references
315+ /// These coercions can be freely intermixed, for example we are able to
316+ /// coerce `&mut T` to `&mut T::Target`.
317+ fn coerce_to_ref (
315318 & self ,
316319 a : Ty < ' tcx > ,
317320 b : Ty < ' tcx > ,
318- r_b : ty:: Region < ' tcx > ,
319321 mutbl_b : hir:: Mutability ,
320322 ) -> CoerceResult < ' tcx > {
321- debug ! ( "coerce_borrowed_pointer (a={:?}, b={:?})" , a, b) ;
323+ debug ! ( "coerce_to_ref (a={:?}, b={:?})" , a, b) ;
322324 debug_assert ! ( self . shallow_resolve( a) == a) ;
323325 debug_assert ! ( self . shallow_resolve( b) == b) ;
324326
325- // If we have a parameter of type `&M T_a` and the value
326- // provided is `expr`, we will be adding an implicit borrow,
327- // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
328- // to type check, we will construct the type that `&M*expr` would
329- // yield.
330-
331327 let ( r_a, mt_a) = match * a. kind ( ) {
332328 ty:: Ref ( r_a, ty, mutbl) => {
333329 let mt_a = ty:: TypeAndMut { ty, mutbl } ;
@@ -337,130 +333,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
337333 _ => return self . unify ( a, b) ,
338334 } ;
339335
340- let span = self . cause . span ;
341-
336+ // Look at each step in the `Deref` chain and check if
337+ // any of the autoref'd `Target` types unify with the
338+ // coercion target.
339+ //
340+ // For example when coercing from `&mut Vec<T>` to `&M [T]` we
341+ // have three deref steps:
342+ // 1. `&mut Vec<T>`, skip autoref
343+ // 2. `Vec<T>`, autoref'd ty: `&M Vec<T>`
344+ // - `&M Vec<T>` does not unify with `&M [T]`
345+ // 3. `[T]`, autoref'd ty: `&M [T]`
346+ // - `&M [T]` does unify with `&M [T]`
342347 let mut first_error = None ;
343- let mut r_borrow_var = None ;
344- let mut autoderef = self . autoderef ( span, a) ;
345- let mut found = None ;
346-
347- for ( referent_ty, autoderefs) in autoderef. by_ref ( ) {
348+ let mut autoderef = self . autoderef ( self . cause . span , a) ;
349+ let found = autoderef. by_ref ( ) . find_map ( |( deref_ty, autoderefs) | {
348350 if autoderefs == 0 {
349- // Don't let this pass, otherwise it would cause
350- // &T to autoref to &&T.
351- continue ;
351+ // Don't autoref the first step as otherwise we'd allow
352+ // coercing `&T` to ` &&T` .
353+ return None ;
352354 }
353355
354- // At this point, we have deref'd `a` to `referent_ty`. So
355- // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
356- // In the autoderef loop for `&'a mut Vec<T>`, we would get
357- // three callbacks:
358- //
359- // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
360- // - `Vec<T>` -- 1 deref
361- // - `[T]` -- 2 deref
362- //
363- // At each point after the first callback, we want to
364- // check to see whether this would match out target type
365- // (`&'b mut [T]`) if we autoref'd it. We can't just
366- // compare the referent types, though, because we still
367- // have to consider the mutability. E.g., in the case
368- // we've been considering, we have an `&mut` reference, so
369- // the `T` in `[T]` needs to be unified with equality.
370- //
371- // Therefore, we construct reference types reflecting what
372- // the types will be after we do the final auto-ref and
373- // compare those. Note that this means we use the target
374- // mutability [1], since it may be that we are coercing
375- // from `&mut T` to `&U`.
376- //
377- // One fine point concerns the region that we use. We
378- // choose the region such that the region of the final
379- // type that results from `unify` will be the region we
380- // want for the autoref:
381- //
382- // - if in sub mode, that means we want to use `'b` (the
383- // region from the target reference) for both
384- // pointers [2]. This is because sub mode (somewhat
385- // arbitrarily) returns the subtype region. In the case
386- // where we are coercing to a target type, we know we
387- // want to use that target type region (`'b`) because --
388- // for the program to type-check -- it must be the
389- // smaller of the two.
390- // - One fine point. It may be surprising that we can
391- // use `'b` without relating `'a` and `'b`. The reason
392- // that this is ok is that what we produce is
393- // effectively a `&'b *x` expression (if you could
394- // annotate the region of a borrow), and regionck has
395- // code that adds edges from the region of a borrow
396- // (`'b`, here) into the regions in the borrowed
397- // expression (`*x`, here). (Search for "link".)
398- // - if in lub mode, things can get fairly complicated. The
399- // easiest thing is just to make a fresh
400- // region variable [4], which effectively means we defer
401- // the decision to region inference (and regionck, which will add
402- // some more edges to this variable). However, this can wind up
403- // creating a crippling number of variables in some cases --
404- // e.g., #32278 -- so we optimize one particular case [3].
405- // Let me try to explain with some examples:
406- // - The "running example" above represents the simple case,
407- // where we have one `&` reference at the outer level and
408- // ownership all the rest of the way down. In this case,
409- // we want `LUB('a, 'b)` as the resulting region.
410- // - However, if there are nested borrows, that region is
411- // too strong. Consider a coercion from `&'a &'x Rc<T>` to
412- // `&'b T`. In this case, `'a` is actually irrelevant.
413- // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)`
414- // we get spurious errors (`ui/regions-lub-ref-ref-rc.rs`).
415- // (The errors actually show up in borrowck, typically, because
416- // this extra edge causes the region `'a` to be inferred to something
417- // too big, which then results in borrowck errors.)
418- // - We could track the innermost shared reference, but there is already
419- // code in regionck that has the job of creating links between
420- // the region of a borrow and the regions in the thing being
421- // borrowed (here, `'a` and `'x`), and it knows how to handle
422- // all the various cases. So instead we just make a region variable
423- // and let regionck figure it out.
424- let r = if !self . use_lub {
425- r_b // [2] above
426- } else if autoderefs == 1 {
427- r_a // [3] above
428- } else {
429- if r_borrow_var. is_none ( ) {
430- // create var lazily, at most once
431- let coercion = RegionVariableOrigin :: Coercion ( span) ;
432- let r = self . next_region_var ( coercion) ;
433- r_borrow_var = Some ( r) ; // [4] above
434- }
435- r_borrow_var. unwrap ( )
436- } ;
437- let derefd_ty_a = Ty :: new_ref (
438- self . tcx ,
439- r,
440- referent_ty,
441- mutbl_b, // [1] above
442- ) ;
443- match self . unify_raw ( derefd_ty_a, b) {
444- Ok ( ok) => {
445- found = Some ( ok) ;
446- break ;
447- }
356+ let coercion = RegionVariableOrigin :: Coercion ( self . cause . span ) ;
357+ let r_borrow = self . next_region_var ( coercion) ;
358+ let autorefd_deref_ty = Ty :: new_ref ( self . tcx , r_borrow, deref_ty, mutbl_b) ;
359+
360+ // Note that we unify the autoref'd `Target` type with `b` rather than
361+ // the `Target` type with the pointee of `b`. This is necessary
362+ // to properly account for the differing variances of the pointees
363+ // of `&` vs `&mut` references.
364+ match self . unify_raw ( autorefd_deref_ty, b) {
365+ Ok ( ok) => Some ( ok) ,
448366 Err ( err) => {
449367 if first_error. is_none ( ) {
450368 first_error = Some ( err) ;
451369 }
370+ None
452371 }
453372 }
454- }
373+ } ) ;
455374
456375 // Extract type or return an error. We return the first error
457376 // we got, which should be from relating the "base" type
458377 // (e.g., in example above, the failure from relating `Vec<T>`
459378 // to the target type), since that should be the least
460379 // confusing.
461- let Some ( InferOk { value : ty , mut obligations } ) = found else {
380+ let Some ( InferOk { value : coerced_a , mut obligations } ) = found else {
462381 if let Some ( first_error) = first_error {
463- debug ! ( "coerce_borrowed_pointer : failed with err = {:?}" , first_error) ;
382+ debug ! ( "coerce_to_ref : failed with err = {:?}" , first_error) ;
464383 return Err ( first_error) ;
465384 } else {
466385 // This may happen in the new trait solver since autoderef requires
@@ -472,7 +391,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
472391 }
473392 } ;
474393
475- if ty == a && mt_a. mutbl . is_not ( ) && autoderef. step_count ( ) == 1 {
394+ if coerced_a == a && mt_a. mutbl . is_not ( ) && autoderef. step_count ( ) == 1 {
476395 // As a special case, if we would produce `&'a *x`, that's
477396 // a total no-op. We end up with the type `&'a T` just as
478397 // we started with. In that case, just skip it
@@ -485,7 +404,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
485404 // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
486405 // which is a borrow.
487406 assert ! ( mutbl_b. is_not( ) ) ; // can only coerce &T -> &U
488- return success ( vec ! [ ] , ty , obligations) ;
407+ return success ( vec ! [ ] , coerced_a , obligations) ;
489408 }
490409
491410 let InferOk { value : mut adjustments, obligations : o } =
@@ -495,15 +414,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
495414
496415 // Now apply the autoref. We have to extract the region out of
497416 // the final ref type we got.
498- let ty:: Ref ( ..) = ty . kind ( ) else {
499- span_bug ! ( span, "expected a ref type, got {:?}" , ty ) ;
417+ let ty:: Ref ( ..) = coerced_a . kind ( ) else {
418+ span_bug ! ( self . cause . span, "expected a ref type, got {:?}" , coerced_a ) ;
500419 } ;
501420 let mutbl = AutoBorrowMutability :: new ( mutbl_b, self . allow_two_phase ) ;
502- adjustments. push ( Adjustment { kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) , target : ty } ) ;
421+ adjustments
422+ . push ( Adjustment { kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) , target : coerced_a } ) ;
503423
504- debug ! ( "coerce_borrowed_pointer : succeeded ty ={:?} adjustments={:?}" , ty , adjustments) ;
424+ debug ! ( "coerce_to_ref : succeeded coerced_a ={:?} adjustments={:?}" , coerced_a , adjustments) ;
505425
506- success ( adjustments, ty , obligations)
426+ success ( adjustments, coerced_a , obligations)
507427 }
508428
509429 /// Performs [unsized coercion] by emulating a fulfillment loop on a
@@ -566,9 +486,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
566486 | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
567487 _ => { }
568488 }
569- // Additionally, we ignore `&str -> &str` coercions, which happen very
570- // commonly since strings are one of the most used argument types in Rust,
571- // we do coercions when type checking call expressions.
489+ // `&str: CoerceUnsized<&str>` does not hold but is encountered frequently
490+ // so we fast path bail out here
572491 if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
573492 && source_pointee. is_str ( )
574493 && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
@@ -780,7 +699,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
780699 /// - `Pin<Box<T>>` as `Pin<&T>`
781700 /// - `Pin<Box<T>>` as `Pin<&mut T>`
782701 #[ instrument( skip( self ) , level = "trace" ) ]
783- fn coerce_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
702+ fn coerce_to_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
784703 debug_assert ! ( self . shallow_resolve( a) == a) ;
785704 debug_assert ! ( self . shallow_resolve( b) == b) ;
786705
@@ -983,13 +902,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
983902 }
984903 }
985904
986- fn coerce_raw_ptr (
905+ fn coerce_to_raw_ptr (
987906 & self ,
988907 a : Ty < ' tcx > ,
989908 b : Ty < ' tcx > ,
990909 mutbl_b : hir:: Mutability ,
991910 ) -> CoerceResult < ' tcx > {
992- debug ! ( "coerce_raw_ptr (a={:?}, b={:?})" , a, b) ;
911+ debug ! ( "coerce_to_raw_ptr (a={:?}, b={:?})" , a, b) ;
993912 debug_assert ! ( self . shallow_resolve( a) == a) ;
994913 debug_assert ! ( self . shallow_resolve( b) == b) ;
995914
0 commit comments