@@ -118,6 +118,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
118
118
let data = self . confirm_builtin_unsize_candidate ( obligation) ?;
119
119
Ok ( ImplSource :: Builtin ( data) )
120
120
}
121
+
122
+ TraitUpcastingUnsizeCandidate ( idx) => {
123
+ let data = self . confirm_trait_upcasting_unsize_candidate ( obligation, idx) ?;
124
+ Ok ( ImplSource :: Builtin ( data) )
125
+ }
121
126
}
122
127
}
123
128
@@ -685,9 +690,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
685
690
. map_err ( |e| OutputTypeParameterMismatch ( expected_trait_ref, obligation_trait_ref, e) )
686
691
}
687
692
688
- fn confirm_builtin_unsize_candidate (
693
+ fn confirm_trait_upcasting_unsize_candidate (
689
694
& mut self ,
690
695
obligation : & TraitObligation < ' tcx > ,
696
+ idx : usize ,
691
697
) -> Result < ImplSourceBuiltinData < PredicateObligation < ' tcx > > , SelectionError < ' tcx > > {
692
698
let tcx = self . tcx ( ) ;
693
699
@@ -697,62 +703,91 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
697
703
let target = obligation. predicate . skip_binder ( ) . trait_ref . substs . type_at ( 1 ) ;
698
704
let target = self . infcx . shallow_resolve ( target) ;
699
705
700
- debug ! ( ?source, ?target, "confirm_builtin_unsize_candidate " ) ;
706
+ debug ! ( ?source, ?target, "confirm_trait_upcasting_unsize_candidate " ) ;
701
707
702
708
let mut nested = vec ! [ ] ;
703
709
match ( source. kind ( ) , target. kind ( ) ) {
704
- // Trait +Kx+'a -> Trait +Ky+'b (upcasts ).
710
+ // TraitA +Kx+'a -> TraitB +Ky+'b (trait upcasting coercion ).
705
711
( & ty:: Dynamic ( ref data_a, r_a) , & ty:: Dynamic ( ref data_b, r_b) ) => {
706
- // Upcast coercions permit several things:
707
- //
708
- // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
709
- // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
710
- // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
711
- //
712
- // Note that neither of the first two of these changes requires any
713
- // change at runtime. The third needs to change pointer metadata at runtime.
714
- //
715
- // We always perform upcasting coercions when we can because of reason
716
- // #2 (region bounds).
717
-
712
+ // See `assemble_candidates_for_unsizing` for more info.
718
713
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
714
+ let principal_a = data_a. principal ( ) . unwrap ( ) ;
715
+ let source_trait_ref = principal_a. with_self_ty ( tcx, source) ;
716
+ let target_trait_ref = util:: supertraits ( tcx, source_trait_ref) . nth ( idx) . unwrap ( ) ;
717
+ assert_eq ! ( data_b. principal_def_id( ) , Some ( target_trait_ref. def_id( ) ) ) ;
718
+ let existential_predicate = target_trait_ref. map_bound ( |trait_ref| {
719
+ ty:: ExistentialPredicate :: Trait ( ty:: ExistentialTraitRef :: erase_self_ty (
720
+ tcx, trait_ref,
721
+ ) )
722
+ } ) ;
723
+ let iter = Some ( existential_predicate)
724
+ . into_iter ( )
725
+ . chain (
726
+ data_a
727
+ . projection_bounds ( )
728
+ . map ( |b| b. map_bound ( ty:: ExistentialPredicate :: Projection ) ) ,
729
+ )
730
+ . chain (
731
+ data_b
732
+ . auto_traits ( )
733
+ . map ( ty:: ExistentialPredicate :: AutoTrait )
734
+ . map ( ty:: Binder :: dummy) ,
735
+ ) ;
736
+ let existential_predicates = tcx. mk_poly_existential_predicates ( iter) ;
737
+ let source_trait = tcx. mk_dynamic ( existential_predicates, r_b) ;
719
738
720
- let principal_a = data_a. principal ( ) ;
721
- let principal_def_id_b = data_b. principal_def_id ( ) ;
722
-
723
- let existential_predicate = if let Some ( principal_a) = principal_a {
724
- let source_trait_ref = principal_a. with_self_ty ( tcx, source) ;
725
- let target_trait_did = principal_def_id_b. ok_or_else ( || Unimplemented ) ?;
726
- let upcast_idx = util:: supertraits ( tcx, source_trait_ref)
727
- . position ( |upcast_trait_ref| upcast_trait_ref. def_id ( ) == target_trait_did)
728
- . ok_or_else ( || Unimplemented ) ?;
729
- // FIXME(crlf0710): This is less than ideal, for example,
730
- // if the trait is defined as `trait Foo: Bar<u32> + Bar<i32>`,
731
- // the coercion from Box<Foo> to Box<dyn Bar<_>> is actually ambiguous.
732
- // We currently make this coercion fail for now.
733
- //
734
- // see #65991 for more information.
735
- if util:: supertraits ( tcx, source_trait_ref)
736
- . skip ( upcast_idx + 1 )
737
- . any ( |upcast_trait_ref| upcast_trait_ref. def_id ( ) == target_trait_did)
738
- {
739
- return Err ( Unimplemented ) ;
740
- }
741
- let target_trait_ref =
742
- util:: supertraits ( tcx, source_trait_ref) . nth ( upcast_idx) . unwrap ( ) ;
743
- let existential_predicate = target_trait_ref. map_bound ( |trait_ref| {
744
- ty:: ExistentialPredicate :: Trait ( ty:: ExistentialTraitRef :: erase_self_ty (
745
- tcx, trait_ref,
746
- ) )
747
- } ) ;
748
- Some ( existential_predicate)
749
- } else if principal_def_id_b. is_none ( ) {
750
- None
751
- } else {
752
- return Err ( Unimplemented ) ;
753
- } ;
739
+ // Require that the traits involved in this upcast are **equal**;
740
+ // only the **lifetime bound** is changed.
741
+ let InferOk { obligations, .. } = self
742
+ . infcx
743
+ . at ( & obligation. cause , obligation. param_env )
744
+ . sup ( target, source_trait)
745
+ . map_err ( |_| Unimplemented ) ?;
746
+ nested. extend ( obligations) ;
747
+
748
+ // Register one obligation for 'a: 'b.
749
+ let cause = ObligationCause :: new (
750
+ obligation. cause . span ,
751
+ obligation. cause . body_id ,
752
+ ObjectCastObligation ( target) ,
753
+ ) ;
754
+ let outlives = ty:: OutlivesPredicate ( r_a, r_b) ;
755
+ nested. push ( Obligation :: with_depth (
756
+ cause,
757
+ obligation. recursion_depth + 1 ,
758
+ obligation. param_env ,
759
+ obligation. predicate . rebind ( outlives) . to_predicate ( tcx) ,
760
+ ) ) ;
761
+ }
762
+ _ => bug ! ( ) ,
763
+ } ;
764
+
765
+ Ok ( ImplSourceBuiltinData { nested } )
766
+ }
754
767
755
- let iter = existential_predicate
768
+ fn confirm_builtin_unsize_candidate (
769
+ & mut self ,
770
+ obligation : & TraitObligation < ' tcx > ,
771
+ ) -> Result < ImplSourceBuiltinData < PredicateObligation < ' tcx > > , SelectionError < ' tcx > > {
772
+ let tcx = self . tcx ( ) ;
773
+
774
+ // `assemble_candidates_for_unsizing` should ensure there are no late-bound
775
+ // regions here. See the comment there for more details.
776
+ let source = self . infcx . shallow_resolve ( obligation. self_ty ( ) . no_bound_vars ( ) . unwrap ( ) ) ;
777
+ let target = obligation. predicate . skip_binder ( ) . trait_ref . substs . type_at ( 1 ) ;
778
+ let target = self . infcx . shallow_resolve ( target) ;
779
+
780
+ debug ! ( ?source, ?target, "confirm_builtin_unsize_candidate" ) ;
781
+
782
+ let mut nested = vec ! [ ] ;
783
+ match ( source. kind ( ) , target. kind ( ) ) {
784
+ // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
785
+ ( & ty:: Dynamic ( ref data_a, r_a) , & ty:: Dynamic ( ref data_b, r_b) ) => {
786
+ // See `assemble_candidates_for_unsizing` for more info.
787
+ // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
788
+ let iter = data_a
789
+ . principal ( )
790
+ . map ( |b| b. map_bound ( ty:: ExistentialPredicate :: Trait ) )
756
791
. into_iter ( )
757
792
. chain (
758
793
data_a
0 commit comments