about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs15
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs31
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs12
-rw-r--r--compiler/rustc_mir/src/interpret/cast.rs11
-rw-r--r--compiler/rustc_query_impl/src/keys.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs51
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs3
11 files changed, 137 insertions, 87 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index d9c4647cba3..fd96858010e 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -31,21 +31,10 @@ pub(crate) fn unsized_info<'tcx>(
             if data_a.principal_def_id() == data_b.principal_def_id() {
                 return old_info;
             }
-            // trait upcasting coercion
 
-            // if both of the two `principal`s are `None`, this function would have returned early above.
-            // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
-            let principal_a = data_a
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-            let principal_b = data_b
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-
-            let vptr_entry_idx = fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
-                principal_a.with_self_ty(fx.tcx, source),
-                principal_b.with_self_ty(fx.tcx, source),
-            ));
+            // trait upcasting coercion
+            let vptr_entry_idx =
+                fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
 
             if let Some(entry_idx) = vptr_entry_idx {
                 let entry_idx = u32::try_from(entry_idx).unwrap();
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 064a51c8f60..a5143a755fe 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -150,19 +150,8 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             // trait upcasting coercion
 
-            // if both of the two `principal`s are `None`, this function would have returned early above.
-            // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
-            let principal_a = data_a
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-            let principal_b = data_b
-                .principal()
-                .expect("unsized_info: missing principal trait for trait upcasting coercion");
-
-            let vptr_entry_idx = cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((
-                principal_a.with_self_ty(cx.tcx(), source),
-                principal_b.with_self_ty(cx.tcx(), source),
-            ));
+            let vptr_entry_idx =
+                cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
 
             if let Some(entry_idx) = vptr_entry_idx {
                 let ptr_ty = cx.type_i8p();
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5b37556985b..85b1274da10 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -987,9 +987,9 @@ rustc_queries! {
         desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
     }
 
-    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>)) -> Option<usize> {
-        desc { |tcx| "finding the slot within vtable for trait {} vtable ptr during trait upcasting coercion from {} vtable",
-            tcx.def_path_str(key.1.def_id()), tcx.def_path_str(key.0.def_id()) }
+    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
+        desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+            key.1, key.0 }
     }
 
     query codegen_fulfill_obligation(
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a4a2e824637..5d2244a5961 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -503,6 +503,9 @@ pub enum ImplSource<'tcx, N> {
     /// Successful resolution for a builtin trait.
     Builtin(ImplSourceBuiltinData<N>),
 
+    /// ImplSource for trait upcasting coercion
+    TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
+
     /// ImplSource automatically generated for a closure. The `DefId` is the ID
     /// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the
     /// impl is generated by the compiler and does not appear in the source.
@@ -538,6 +541,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
             ImplSource::TraitAlias(d) => d.nested,
+            ImplSource::TraitUpcasting(d) => d.nested,
         }
     }
 
@@ -554,6 +558,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             | ImplSource::Pointee(ImplSourcePointeeData) => &[],
             ImplSource::TraitAlias(d) => &d.nested[..],
+            ImplSource::TraitUpcasting(d) => &d.nested[..],
         }
     }
 
@@ -605,6 +610,13 @@ impl<'tcx, N> ImplSource<'tcx, N> {
                 substs: d.substs,
                 nested: d.nested.into_iter().map(f).collect(),
             }),
+            ImplSource::TraitUpcasting(d) => {
+                ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
+                    upcast_trait_ref: d.upcast_trait_ref,
+                    vtable_vptr_slot: d.vtable_vptr_slot,
+                    nested: d.nested.into_iter().map(f).collect(),
+                })
+            }
         }
     }
 }
@@ -651,6 +663,20 @@ pub struct ImplSourceAutoImplData<N> {
 }
 
 #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+pub struct ImplSourceTraitUpcastingData<'tcx, N> {
+    /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
+    pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
+
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
+    /// within that vtable.
+    pub vtable_vptr_slot: Option<usize>,
+
+    pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceBuiltinData<N> {
     pub nested: Vec<N>,
 }
@@ -661,8 +687,9 @@ pub struct ImplSourceObjectData<'tcx, N> {
     pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
 
     /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits; this is the start of
-    /// `upcast_trait_ref`'s methods in that vtable.
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
+    /// in that vtable.
     pub vtable_base: usize,
 
     pub nested: Vec<N>,
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index 4f978e63630..aa16e14fedc 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -30,6 +30,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
             super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
 
             super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
+
+            super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
         }
     }
 }
@@ -70,6 +72,16 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> {
     }
 }
 
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
+            self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
+        )
+    }
+}
+
 impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index cee4c2e30aa..697e98311e2 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -275,16 +275,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     return self.write_immediate(*val, dest);
                 }
                 // trait upcasting coercion
-                let principal_a = data_a.principal().expect(
-                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
-                );
-                let principal_b = data_b.principal().expect(
-                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
-                );
-
                 let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
-                    principal_a.with_self_ty(*self.tcx, src_pointee_ty),
-                    principal_b.with_self_ty(*self.tcx, src_pointee_ty),
+                    src_pointee_ty,
+                    dest_pointee_ty,
                 ));
 
                 if let Some(entry_idx) = vptr_entry_idx {
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index ace7cffd16d..38ab26d66ac 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -332,6 +332,16 @@ impl<'tcx> Key for Ty<'tcx> {
     }
 }
 
+impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 585fcf795b7..3acac504cff 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -28,6 +28,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
@@ -759,48 +760,38 @@ fn vtable_trait_first_method_offset<'tcx>(
 pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
     tcx: TyCtxt<'tcx>,
     key: (
-        ty::PolyTraitRef<'tcx>, // trait owning vtable
-        ty::PolyTraitRef<'tcx>, // super trait ref
+        Ty<'tcx>, // trait object type whose trait owning vtable
+        Ty<'tcx>, // trait object for supertrait
     ),
 ) -> Option<usize> {
-    let (trait_owning_vtable, super_trait_ref) = key;
-    let super_trait_did = super_trait_ref.def_id();
-    // FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur
-    // multiple times.
+    let (source, target) = key;
+    debug_assert!(matches!(&source.kind(), &ty::Dynamic(..)));
+    debug_assert!(matches!(&target.kind(), &ty::Dynamic(..)));
 
-    let vtable_segment_callback = {
-        let mut vptr_offset = 0;
-        move |segment| {
-            match segment {
-                VtblSegment::MetadataDSA => {
-                    vptr_offset += COMMON_VTABLE_ENTRIES.len();
-                }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
-                    if trait_ref.def_id() == super_trait_did {
-                        if emit_vptr {
-                            return ControlFlow::Break(Some(vptr_offset));
-                        } else {
-                            return ControlFlow::Break(None);
-                        }
-                    }
+    // this has been typecked-before, so diagnostics is not really needed.
+    let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
 
-                    if emit_vptr {
-                        vptr_offset += 1;
-                    }
-                }
-            }
-            ControlFlow::Continue(())
-        }
+    let trait_ref = ty::TraitRef {
+        def_id: unsize_trait_did,
+        substs: tcx.mk_substs_trait(source, &[target.into()]),
     };
+    let obligation = Obligation::new(
+        ObligationCause::dummy(),
+        ty::ParamEnv::reveal_all(),
+        ty::Binder::dummy(ty::TraitPredicate { trait_ref, constness: hir::Constness::NotConst }),
+    );
 
-    if let Some(vptr_offset) =
-        prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
-    {
-        vptr_offset
-    } else {
-        bug!("Failed to find info for expected trait in vtable");
-    }
+    let implsrc = tcx.infer_ctxt().enter(|infcx| {
+        let mut selcx = SelectionContext::new(&infcx);
+        selcx.select(&obligation).unwrap()
+    });
+
+    let implsrc_traitcasting = match implsrc {
+        Some(ImplSource::TraitUpcasting(data)) => data,
+        _ => bug!(),
+    };
+
+    implsrc_traitcasting.vtable_vptr_slot
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d1ab9fa025e..f75f7b887a5 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1483,7 +1483,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // why we special case object types.
                 false
             }
-            super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
+            super::ImplSource::AutoImpl(..)
+            | super::ImplSource::Builtin(..)
+            | super::ImplSource::TraitUpcasting(_) => {
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
                     obligation.cause.span,
@@ -1554,6 +1556,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
         | super::ImplSource::AutoImpl(..)
         | super::ImplSource::Param(..)
         | super::ImplSource::Builtin(..)
+        | super::ImplSource::TraitUpcasting(_)
         | super::ImplSource::TraitAlias(..) => {
             // we don't create Select candidates with this kind of resolution
             span_bug!(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 9dc9c21b519..0f2f5357eb7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -26,12 +26,13 @@ use crate::traits::Normalized;
 use crate::traits::OutputTypeParameterMismatch;
 use crate::traits::Selection;
 use crate::traits::TraitNotObjectSafe;
+use crate::traits::VtblSegment;
 use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
 use crate::traits::{
     ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
     ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
     ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
-    ImplSourceUserDefinedData,
+    ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
 };
 use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
 use crate::traits::{Obligation, ObligationCause};
@@ -42,6 +43,7 @@ use super::SelectionCandidate::{self, *};
 use super::SelectionContext;
 
 use std::iter;
+use std::ops::ControlFlow;
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     #[instrument(level = "debug", skip(self))]
@@ -121,7 +123,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             TraitUpcastingUnsizeCandidate(idx) => {
                 let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
-                Ok(ImplSource::Builtin(data))
+                Ok(ImplSource::TraitUpcasting(data))
             }
         }
     }
@@ -694,7 +696,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
         idx: usize,
-    ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
+    {
         let tcx = self.tcx();
 
         // `assemble_candidates_for_unsizing` should ensure there are no late-bound
@@ -706,16 +709,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
 
         let mut nested = vec![];
+        let source_trait_ref;
+        let upcast_trait_ref;
         match (source.kind(), target.kind()) {
             // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
             (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
                 // See `assemble_candidates_for_unsizing` for more info.
                 // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
                 let principal_a = data_a.principal().unwrap();
-                let source_trait_ref = principal_a.with_self_ty(tcx, source);
-                let target_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
-                assert_eq!(data_b.principal_def_id(), Some(target_trait_ref.def_id()));
-                let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
+                source_trait_ref = principal_a.with_self_ty(tcx, source);
+                upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
+                assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id()));
+                let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| {
                     ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
                         tcx, trait_ref,
                     ))
@@ -762,7 +767,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!(),
         };
 
-        Ok(ImplSourceBuiltinData { nested })
+        let vtable_segment_callback = {
+            let mut vptr_offset = 0;
+            move |segment| {
+                match segment {
+                    VtblSegment::MetadataDSA => {
+                        vptr_offset += ty::COMMON_VTABLE_ENTRIES.len();
+                    }
+                    VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+                        vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
+                        if trait_ref == upcast_trait_ref {
+                            if emit_vptr {
+                                return ControlFlow::Break(Some(vptr_offset));
+                            } else {
+                                return ControlFlow::Break(None);
+                            }
+                        }
+
+                        if emit_vptr {
+                            vptr_offset += 1;
+                        }
+                    }
+                }
+                ControlFlow::Continue(())
+            }
+        };
+
+        let vtable_vptr_slot =
+            super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback)
+                .unwrap();
+
+        Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
     }
 
     fn confirm_builtin_unsize_candidate(
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 469ac04e545..4c03abb38ca 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -381,7 +381,8 @@ fn resolve_associated_item<'tcx>(
         | traits::ImplSource::Param(..)
         | traits::ImplSource::TraitAlias(..)
         | traits::ImplSource::DiscriminantKind(..)
-        | traits::ImplSource::Pointee(..) => None,
+        | traits::ImplSource::Pointee(..)
+        | traits::ImplSource::TraitUpcasting(_) => None,
     })
 }