@@ -444,7 +444,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
444
444
Err ( NoSolution ) => vec ! [ ] ,
445
445
} ;
446
446
447
- ecx. probe ( |_| CandidateKind :: DynUpcastingAssembly ) . enter ( |ecx| {
447
+ ecx. probe ( |_| CandidateKind :: UnsizeAssembly ) . enter ( |ecx| {
448
448
let a_ty = goal. predicate . self_ty ( ) ;
449
449
// We need to normalize the b_ty since it's matched structurally
450
450
// in the other functions below.
@@ -526,7 +526,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
526
526
b_region : ty:: Region < ' tcx > ,
527
527
) -> Vec < ( CanonicalResponse < ' tcx > , BuiltinImplSource ) > {
528
528
let tcx = self . tcx ( ) ;
529
- let Goal { predicate : ( a_ty, b_ty ) , .. } = goal;
529
+ let Goal { predicate : ( a_ty, _b_ty ) , .. } = goal;
530
530
531
531
// All of a's auto traits need to be in b's auto traits.
532
532
let auto_traits_compatible =
@@ -535,51 +535,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
535
535
return vec ! [ ] ;
536
536
}
537
537
538
- // Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with
539
- // the supertrait principal and subtyping the types.
540
- let unsize_dyn_to_principal =
541
- |ecx : & mut Self , principal : Option < ty:: PolyExistentialTraitRef < ' tcx > > | {
542
- ecx. probe_candidate ( "upcast dyn to principle" ) . enter (
543
- |ecx| -> Result < _ , NoSolution > {
544
- // Require that all of the trait predicates from A match B, except for
545
- // the auto traits. We do this by constructing a new A type with B's
546
- // auto traits, and equating these types.
547
- let new_a_data = principal
548
- . into_iter ( )
549
- . map ( |trait_ref| trait_ref. map_bound ( ty:: ExistentialPredicate :: Trait ) )
550
- . chain ( a_data. iter ( ) . filter ( |a| {
551
- matches ! ( a. skip_binder( ) , ty:: ExistentialPredicate :: Projection ( _) )
552
- } ) )
553
- . chain (
554
- b_data
555
- . auto_traits ( )
556
- . map ( ty:: ExistentialPredicate :: AutoTrait )
557
- . map ( ty:: Binder :: dummy) ,
558
- ) ;
559
- let new_a_data = tcx. mk_poly_existential_predicates_from_iter ( new_a_data) ;
560
- let new_a_ty = Ty :: new_dynamic ( tcx, new_a_data, b_region, ty:: Dyn ) ;
561
-
562
- // We also require that A's lifetime outlives B's lifetime.
563
- ecx. eq ( goal. param_env , new_a_ty, b_ty) ?;
564
- ecx. add_goal ( goal. with ( tcx, ty:: OutlivesPredicate ( a_region, b_region) ) ) ;
565
- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
566
- } ,
567
- )
568
- } ;
569
-
570
538
let mut responses = vec ! [ ] ;
571
539
// If the principal def ids match (or are both none), then we're not doing
572
540
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
573
541
if a_data. principal_def_id ( ) == b_data. principal_def_id ( ) {
574
- if let Ok ( resp) = unsize_dyn_to_principal ( self , a_data. principal ( ) ) {
542
+ if let Ok ( resp) = self . consider_builtin_upcast_to_principal (
543
+ goal,
544
+ a_data,
545
+ a_region,
546
+ b_data,
547
+ b_region,
548
+ a_data. principal ( ) ,
549
+ ) {
575
550
responses. push ( ( resp, BuiltinImplSource :: Misc ) ) ;
576
551
}
577
552
} else if let Some ( a_principal) = a_data. principal ( ) {
578
553
self . walk_vtable (
579
554
a_principal. with_self_ty ( tcx, a_ty) ,
580
555
|ecx, new_a_principal, _, vtable_vptr_slot| {
581
- if let Ok ( resp) = unsize_dyn_to_principal (
582
- ecx,
556
+ if let Ok ( resp) = ecx. consider_builtin_upcast_to_principal (
557
+ goal,
558
+ a_data,
559
+ a_region,
560
+ b_data,
561
+ b_region,
583
562
Some ( new_a_principal. map_bound ( |trait_ref| {
584
563
ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref)
585
564
} ) ) ,
@@ -631,6 +610,83 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
631
610
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
632
611
}
633
612
613
+ fn consider_builtin_upcast_to_principal (
614
+ & mut self ,
615
+ goal : Goal < ' tcx , ( Ty < ' tcx > , Ty < ' tcx > ) > ,
616
+ a_data : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
617
+ a_region : ty:: Region < ' tcx > ,
618
+ b_data : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
619
+ b_region : ty:: Region < ' tcx > ,
620
+ upcast_principal : Option < ty:: PolyExistentialTraitRef < ' tcx > > ,
621
+ ) -> QueryResult < ' tcx > {
622
+ let param_env = goal. param_env ;
623
+
624
+ // More than one projection in a_ty's bounds may match the projection
625
+ // in b_ty's bound. Use this to first determine *which* apply without
626
+ // having any inference side-effects. We process obligations because
627
+ // unification may initially succeed due to deferred projection equality.
628
+ let projection_may_match =
629
+ |ecx : & mut Self ,
630
+ source_projection : ty:: PolyExistentialProjection < ' tcx > ,
631
+ target_projection : ty:: PolyExistentialProjection < ' tcx > | {
632
+ source_projection. item_def_id ( ) == target_projection. item_def_id ( )
633
+ && ecx
634
+ . probe ( |_| CandidateKind :: UpcastProbe )
635
+ . enter ( |ecx| -> Result < ( ) , NoSolution > {
636
+ ecx. eq ( param_env, source_projection, target_projection) ?;
637
+ let _ = ecx. try_evaluate_added_goals ( ) ?;
638
+ Ok ( ( ) )
639
+ } )
640
+ . is_ok ( )
641
+ } ;
642
+
643
+ for bound in b_data {
644
+ match bound. skip_binder ( ) {
645
+ // Check that a's supertrait (upcast_principal) is compatible
646
+ // with the target (b_ty).
647
+ ty:: ExistentialPredicate :: Trait ( target_principal) => {
648
+ self . eq ( param_env, upcast_principal. unwrap ( ) , bound. rebind ( target_principal) ) ?;
649
+ }
650
+ // Check that b_ty's projection is satisfied by exactly one of
651
+ // a_ty's projections. First, we look through the list to see if
652
+ // any match. If not, error. Then, if *more* than one matches, we
653
+ // return ambiguity. Otherwise, if exactly one matches, equate
654
+ // it with b_ty's projection.
655
+ ty:: ExistentialPredicate :: Projection ( target_projection) => {
656
+ let target_projection = bound. rebind ( target_projection) ;
657
+ let mut matching_projections =
658
+ a_data. projection_bounds ( ) . filter ( |source_projection| {
659
+ projection_may_match ( self , * source_projection, target_projection)
660
+ } ) ;
661
+ let Some ( source_projection) = matching_projections. next ( ) else {
662
+ return Err ( NoSolution ) ;
663
+ } ;
664
+ if matching_projections. next ( ) . is_some ( ) {
665
+ return self . evaluate_added_goals_and_make_canonical_response (
666
+ Certainty :: AMBIGUOUS ,
667
+ ) ;
668
+ }
669
+ self . eq ( param_env, source_projection, target_projection) ?;
670
+ }
671
+ // Check that b_ty's auto traits are present in a_ty's bounds.
672
+ ty:: ExistentialPredicate :: AutoTrait ( def_id) => {
673
+ if !a_data. auto_traits ( ) . any ( |source_def_id| source_def_id == def_id) {
674
+ return Err ( NoSolution ) ;
675
+ }
676
+ }
677
+ }
678
+ }
679
+
680
+ // Also require that a_ty's lifetime outlives b_ty's lifetime.
681
+ self . add_goal ( Goal :: new (
682
+ self . tcx ( ) ,
683
+ param_env,
684
+ ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_region, b_region) ) ,
685
+ ) ) ;
686
+
687
+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
688
+ }
689
+
634
690
/// We have the following builtin impls for arrays:
635
691
/// ```ignore (builtin impl example)
636
692
/// impl<T: ?Sized, const N: usize> Unsize<[T]> for [T; N] {}
0 commit comments