@@ -118,6 +118,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
118118 let data = self . confirm_builtin_unsize_candidate ( obligation) ?;
119119 Ok ( ImplSource :: Builtin ( data) )
120120 }
121+
122+ TraitUpcastingUnsizeCandidate ( idx) => {
123+ let data = self . confirm_trait_upcasting_unsize_candidate ( obligation, idx) ?;
124+ Ok ( ImplSource :: Builtin ( data) )
125+ }
121126 }
122127 }
123128
@@ -685,9 +690,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
685690 . map_err ( |e| OutputTypeParameterMismatch ( expected_trait_ref, obligation_trait_ref, e) )
686691 }
687692
688- fn confirm_builtin_unsize_candidate (
693+ fn confirm_trait_upcasting_unsize_candidate (
689694 & mut self ,
690695 obligation : & TraitObligation < ' tcx > ,
696+ idx : usize ,
691697 ) -> Result < ImplSourceBuiltinData < PredicateObligation < ' tcx > > , SelectionError < ' tcx > > {
692698 let tcx = self . tcx ( ) ;
693699
@@ -697,62 +703,91 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
697703 let target = obligation. predicate . skip_binder ( ) . trait_ref . substs . type_at ( 1 ) ;
698704 let target = self . infcx . shallow_resolve ( target) ;
699705
700- debug ! ( ?source, ?target, "confirm_builtin_unsize_candidate " ) ;
706+ debug ! ( ?source, ?target, "confirm_trait_upcasting_unsize_candidate " ) ;
701707
702708 let mut nested = vec ! [ ] ;
703709 match ( source. kind ( ) , target. kind ( ) ) {
704- // Trait +Kx+'a -> Trait +Ky+'b (upcasts ).
710+ // TraitA +Kx+'a -> TraitB +Ky+'b (trait upcasting coercion ).
705711 ( & 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.
718713 // 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) ;
719738
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+ }
754767
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 ) )
756791 . into_iter ( )
757792 . chain (
758793 data_a
0 commit comments