@@ -703,10 +703,56 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
703
703
match ( source. kind ( ) , target. kind ( ) ) {
704
704
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
705
705
( & 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
710
756
. into_iter ( )
711
757
. chain (
712
758
data_a
0 commit comments