@@ -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 }
@@ -281,22 +280,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
281280 debug_assert ! ( self . shallow_resolve( b) == b) ;
282281
283282 if b. is_ty_var ( ) {
284- // Two unresolved type variables: create a `Coerce` predicate.
285- let target_ty = if self . use_lub { self . next_ty_var ( self . cause . span ) } else { b } ;
286-
287283 let mut obligations = PredicateObligations :: with_capacity ( 2 ) ;
288- for & source_ty in & [ a, b] {
289- if source_ty != target_ty {
290- obligations. push ( Obligation :: new (
291- self . tcx ( ) ,
292- self . cause . clone ( ) ,
293- self . param_env ,
294- ty:: Binder :: dummy ( ty:: PredicateKind :: Coerce ( ty:: CoercePredicate {
295- a : source_ty,
296- b : target_ty,
297- } ) ) ,
298- ) ) ;
299- }
284+ let mut push_coerce_obligation = |a, b| {
285+ obligations. push ( Obligation :: new (
286+ self . tcx ( ) ,
287+ self . cause . clone ( ) ,
288+ self . param_env ,
289+ ty:: Binder :: dummy ( ty:: PredicateKind :: Coerce ( ty:: CoercePredicate { a, b } ) ) ,
290+ ) ) ;
291+ } ;
292+
293+ let target_ty = self . use_lub . then ( || self . next_ty_var ( self . cause . span ) ) . unwrap_or ( b) ;
294+
295+ push_coerce_obligation ( a, target_ty) ;
296+ if self . use_lub {
297+ push_coerce_obligation ( b, target_ty) ;
300298 }
301299
302300 debug ! (
@@ -311,159 +309,99 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
311309 }
312310 }
313311
314- /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
315- /// To match `A` with `B`, autoderef will be performed,
316- /// calling `deref`/`deref_mut` where necessary.
317- 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 (
318320 & self ,
319321 a : Ty < ' tcx > ,
320322 b : Ty < ' tcx > ,
321- r_b : ty:: Region < ' tcx > ,
322323 mutbl_b : hir:: Mutability ,
324+ r_b : ty:: Region < ' tcx > ,
323325 ) -> CoerceResult < ' tcx > {
324- debug ! ( "coerce_borrowed_pointer (a={:?}, b={:?})" , a, b) ;
326+ debug ! ( "coerce_to_ref (a={:?}, b={:?})" , a, b) ;
325327 debug_assert ! ( self . shallow_resolve( a) == a) ;
326328 debug_assert ! ( self . shallow_resolve( b) == b) ;
327329
328- // If we have a parameter of type `&M T_a` and the value
329- // provided is `expr`, we will be adding an implicit borrow,
330- // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
331- // to type check, we will construct the type that `&M*expr` would
332- // yield.
333-
334330 let ( r_a, mt_a) = match * a. kind ( ) {
335331 ty:: Ref ( r_a, ty, mutbl) => {
336- let mt_a = ty:: TypeAndMut { ty, mutbl } ;
337- coerce_mutbls ( mt_a. mutbl , mutbl_b) ?;
338- ( r_a, mt_a)
332+ coerce_mutbls ( mutbl, mutbl_b) ?;
333+ ( r_a, ty:: TypeAndMut { ty, mutbl } )
339334 }
340335 _ => return self . unify ( a, b) ,
341336 } ;
342337
343- let span = self . cause . span ;
344-
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]`
345349 let mut first_error = None ;
346350 let mut r_borrow_var = None ;
347- let mut autoderef = self . autoderef ( span, a) ;
348- let mut found = None ;
349-
350- 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) | {
351353 if autoderefs == 0 {
352- // Don't let this pass, otherwise it would cause
353- // &T to autoref to &&T.
354- continue ;
354+ // Don't autoref the first step as otherwise we'd allow
355+ // coercing `&T` to ` &&T` .
356+ return None ;
355357 }
356358
357- // At this point, we have deref'd `a` to `referent_ty`. So
358- // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
359- // In the autoderef loop for `&'a mut Vec<T>`, we would get
360- // three callbacks:
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.
361362 //
362- // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
363- // - `Vec<T>` -- 1 deref
364- // - `[T]` -- 2 deref
365- //
366- // At each point after the first callback, we want to
367- // check to see whether this would match out target type
368- // (`&'b mut [T]`) if we autoref'd it. We can't just
369- // compare the referent types, though, because we still
370- // have to consider the mutability. E.g., in the case
371- // we've been considering, we have an `&mut` reference, so
372- // the `T` in `[T]` needs to be unified with equality.
373- //
374- // Therefore, we construct reference types reflecting what
375- // the types will be after we do the final auto-ref and
376- // compare those. Note that this means we use the target
377- // mutability [1], since it may be that we are coercing
378- // from `&mut T` to `&U`.
379- //
380- // One fine point concerns the region that we use. We
381- // choose the region such that the region of the final
382- // type that results from `unify` will be the region we
383- // want for the autoref:
384- //
385- // - if in sub mode, that means we want to use `'b` (the
386- // region from the target reference) for both
387- // pointers [2]. This is because sub mode (somewhat
388- // arbitrarily) returns the subtype region. In the case
389- // where we are coercing to a target type, we know we
390- // want to use that target type region (`'b`) because --
391- // for the program to type-check -- it must be the
392- // smaller of the two.
393- // - One fine point. It may be surprising that we can
394- // use `'b` without relating `'a` and `'b`. The reason
395- // that this is ok is that what we produce is
396- // effectively a `&'b *x` expression (if you could
397- // annotate the region of a borrow), and regionck has
398- // code that adds edges from the region of a borrow
399- // (`'b`, here) into the regions in the borrowed
400- // expression (`*x`, here). (Search for "link".)
401- // - if in lub mode, things can get fairly complicated. The
402- // easiest thing is just to make a fresh
403- // region variable [4], which effectively means we defer
404- // the decision to region inference (and regionck, which will add
405- // some more edges to this variable). However, this can wind up
406- // creating a crippling number of variables in some cases --
407- // e.g., #32278 -- so we optimize one particular case [3].
408- // Let me try to explain with some examples:
409- // - The "running example" above represents the simple case,
410- // where we have one `&` reference at the outer level and
411- // ownership all the rest of the way down. In this case,
412- // we want `LUB('a, 'b)` as the resulting region.
413- // - However, if there are nested borrows, that region is
414- // too strong. Consider a coercion from `&'a &'x Rc<T>` to
415- // `&'b T`. In this case, `'a` is actually irrelevant.
416- // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)`
417- // we get spurious errors (`ui/regions-lub-ref-ref-rc.rs`).
418- // (The errors actually show up in borrowck, typically, because
419- // this extra edge causes the region `'a` to be inferred to something
420- // too big, which then results in borrowck errors.)
421- // - We could track the innermost shared reference, but there is already
422- // code in regionck that has the job of creating links between
423- // the region of a borrow and the regions in the thing being
424- // borrowed (here, `'a` and `'x`), and it knows how to handle
425- // all the various cases. So instead we just make a region variable
426- // 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).
427366 let r = if !self . use_lub {
428- r_b // [2] above
367+ r_b
429368 } else if autoderefs == 1 {
430- r_a // [3] above
369+ r_a
431370 } else {
432371 if r_borrow_var. is_none ( ) {
433372 // create var lazily, at most once
434- let coercion = RegionVariableOrigin :: Coercion ( span) ;
373+ let coercion = RegionVariableOrigin :: Coercion ( self . cause . span ) ;
435374 let r = self . next_region_var ( coercion) ;
436- r_borrow_var = Some ( r) ; // [4] above
375+ r_borrow_var = Some ( r) ;
437376 }
438377 r_borrow_var. unwrap ( )
439378 } ;
440- let derefd_ty_a = Ty :: new_ref (
441- self . tcx ,
442- r,
443- referent_ty,
444- mutbl_b, // [1] above
445- ) ;
446- match self . unify_raw ( derefd_ty_a, b) {
447- Ok ( ok) => {
448- found = Some ( ok) ;
449- break ;
450- }
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) ,
451388 Err ( err) => {
452389 if first_error. is_none ( ) {
453390 first_error = Some ( err) ;
454391 }
392+ None
455393 }
456394 }
457- }
395+ } ) ;
458396
459397 // Extract type or return an error. We return the first error
460398 // we got, which should be from relating the "base" type
461399 // (e.g., in example above, the failure from relating `Vec<T>`
462400 // to the target type), since that should be the least
463401 // confusing.
464- let Some ( InferOk { value : ty , mut obligations } ) = found else {
402+ let Some ( InferOk { value : coerced_a , mut obligations } ) = found else {
465403 if let Some ( first_error) = first_error {
466- debug ! ( "coerce_borrowed_pointer : failed with err = {:?}" , first_error) ;
404+ debug ! ( "coerce_to_ref : failed with err = {:?}" , first_error) ;
467405 return Err ( first_error) ;
468406 } else {
469407 // This may happen in the new trait solver since autoderef requires
@@ -475,11 +413,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
475413 }
476414 } ;
477415
478- 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 {
479417 // As a special case, if we would produce `&'a *x`, that's
480418 // a total no-op. We end up with the type `&'a T` just as
481- // we started with. In that case, just skip it
482- // 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
483425 //
484426 // Note that for `&mut`, we DO want to reborrow --
485427 // otherwise, this would be a move, which might be an
@@ -488,25 +430,25 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
488430 // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
489431 // which is a borrow.
490432 assert ! ( mutbl_b. is_not( ) ) ; // can only coerce &T -> &U
491- return success ( vec ! [ ] , ty , obligations) ;
433+ return success ( vec ! [ ] , coerced_a , obligations) ;
492434 }
493435
494436 let InferOk { value : mut adjustments, obligations : o } =
495437 self . adjust_steps_as_infer_ok ( & autoderef) ;
496438 obligations. extend ( o) ;
497439 obligations. extend ( autoderef. into_obligations ( ) ) ;
498440
499- // Now apply the autoref. We have to extract the region out of
500- // the final ref type we got.
501- let ty:: Ref ( ..) = ty. kind ( ) else {
502- 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) ;
503444 } ;
504445 let mutbl = AutoBorrowMutability :: new ( mutbl_b, self . allow_two_phase ) ;
505- 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 } ) ;
506448
507- debug ! ( "coerce_borrowed_pointer : succeeded ty ={:?} adjustments={:?}" , ty , adjustments) ;
449+ debug ! ( "coerce_to_ref : succeeded coerced_a ={:?} adjustments={:?}" , coerced_a , adjustments) ;
508450
509- success ( adjustments, ty , obligations)
451+ success ( adjustments, coerced_a , obligations)
510452 }
511453
512454 /// Performs [unsized coercion] by emulating a fulfillment loop on a
@@ -569,9 +511,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
569511 | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
570512 _ => { }
571513 }
572- // Additionally, we ignore `&str -> &str` coercions, which happen very
573- // commonly since strings are one of the most used argument types in Rust,
574- // 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
575516 if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
576517 && source_pointee. is_str ( )
577518 && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
@@ -810,7 +751,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
810751 /// - `Pin<Box<T>>` as `Pin<&T>`
811752 /// - `Pin<Box<T>>` as `Pin<&mut T>`
812753 #[ instrument( skip( self ) , level = "trace" ) ]
813- 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 > {
814755 debug_assert ! ( self . shallow_resolve( a) == a) ;
815756 debug_assert ! ( self . shallow_resolve( b) == b) ;
816757
@@ -1013,13 +954,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1013954 }
1014955 }
1015956
1016- fn coerce_raw_ptr (
957+ fn coerce_to_raw_ptr (
1017958 & self ,
1018959 a : Ty < ' tcx > ,
1019960 b : Ty < ' tcx > ,
1020961 mutbl_b : hir:: Mutability ,
1021962 ) -> CoerceResult < ' tcx > {
1022- debug ! ( "coerce_raw_ptr (a={:?}, b={:?})" , a, b) ;
963+ debug ! ( "coerce_to_raw_ptr (a={:?}, b={:?})" , a, b) ;
1023964 debug_assert ! ( self . shallow_resolve( a) == a) ;
1024965 debug_assert ! ( self . shallow_resolve( b) == b) ;
1025966
0 commit comments