@@ -703,10 +703,56 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
703703 match ( source. kind ( ) , target. kind ( ) ) {
704704 // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
705705 ( & ty:: Dynamic ( ref data_a, r_a) , & ty:: Dynamic ( ref data_b, r_b) ) => {
706- // See `assemble_candidates_for_unsizing` for more info.
707- let iter = data_a
708- . principal ( )
709- . map ( |b| b. map_bound ( ty:: ExistentialPredicate :: Trait ) )
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+
718+ // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
719+
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+ } ;
754+
755+ let iter = existential_predicate
710756 . into_iter ( )
711757 . chain (
712758 data_a
0 commit comments