diff options
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/unsize.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/base.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/traits/mod.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/traits/structural_impls.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/cast.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/keys.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/mod.rs | 63 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/project.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/confirmation.rs | 51 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/instance.rs | 3 |
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, }) } |
