diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index adfe8aeb5c539..7fa9975565419 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -308,7 +308,12 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx - .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal()))) + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx.instantiate_bound_regions_with_erased(principal) + }), + ))) .unwrap_memory(); let init = const_alloc_to_llvm(self, alloc, /*static*/ false); let value = self.static_addr_of(init, alloc.inner().align, None); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 88e43e1c678ad..08d8f626c51ae 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1406,7 +1406,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); - let trait_ref = tcx.erase_regions(trait_ref); + let trait_ref = tcx.erase_regions(tcx.instantiate_bound_regions_with_erased(trait_ref)); tcx.vtable_entries(trait_ref) } else { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 64cd4c38937e7..c51a57be71cec 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -96,24 +96,28 @@ fn dyn_trait_in_self(ty: Ty<'_>) -> Option> { pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx: &Cx, ty: Ty<'tcx>, - trait_ref: Option>, + poly_trait_ref: Option>, ) -> Cx::Value { let tcx = cx.tcx(); // Check the cache. - if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) { + if let Some(&val) = cx.vtables().borrow().get(&(ty, poly_trait_ref)) { return val; } + // FIXME(trait_upcasting): Take a non-higher-ranked vtable as arg. + let trait_ref = + poly_trait_ref.map(|trait_ref| tcx.instantiate_bound_regions_with_erased(trait_ref)); + let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref)); let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); let vtable_const = cx.const_data_from_alloc(vtable_allocation); let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); - cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); - cx.create_vtable_debuginfo(ty, trait_ref, vtable); - cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); + cx.apply_vcall_visibility_metadata(ty, poly_trait_ref, vtable); + cx.create_vtable_debuginfo(ty, poly_trait_ref, vtable); + cx.vtables().borrow_mut().insert((ty, poly_trait_ref), vtable); vtable } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index ef3e96784ce86..b05efd10e6666 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -419,8 +419,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty)); let vtable_entries = self.vtable_entries(data_a.principal(), ty); if let Some(entry_idx) = vptr_entry_idx { - let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) = - vtable_entries.get(entry_idx) + let Some(&ty::VtblEntry::TraitVPtr(_)) = vtable_entries.get(entry_idx) else { span_bug!( self.cur_span(), @@ -429,13 +428,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest_pointee_ty ); }; - let erased_trait_ref = upcast_trait_ref - .map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r)); - assert!( - data_b - .principal() - .is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b)) - ); } else { // In this case codegen would keep using the old vtable. We don't want to do // that as it has the wrong trait. The reason codegen can do this is that diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index af8d618b6b5e5..4cfaacebfcd0e 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -54,7 +54,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> &'tcx [VtblEntry<'tcx>] { if let Some(trait_) = trait_ { let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty); - let trait_ref = self.tcx.erase_regions(trait_ref); + let trait_ref = + self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); self.tcx.vtable_entries(trait_ref) } else { TyCtxt::COMMON_VTABLE_ENTRIES diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aff66e48fbbee..ed02a059b0ef7 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1003,7 +1003,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { // Number of vtable entries needed solely for upcasting let mut entries_for_upcasting = 0; - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr)); + let trait_ref = ty::TraitRef::identity(tcx, tr); // A slightly edited version of the code in // `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self @@ -1041,7 +1041,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { // Lookup the shape of vtable for the trait. let own_existential_entries = - tcx.own_existential_vtable_entries(trait_ref.def_id()); + tcx.own_existential_vtable_entries(trait_ref.def_id); // The original code here ignores the method if its predicates are // impossible. We can't really do that as, for example, all not trivial diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index e243425c0b7ba..03fe0a300c081 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -95,7 +95,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { } } -impl<'tcx> Key for (Ty<'tcx>, Option>) { +impl<'tcx> Key for (Ty<'tcx>, Option>) { type Cache = DefaultCache; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 283675573d4e5..6218e29121419 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1435,9 +1435,9 @@ rustc_queries! { desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) } } - query vtable_entries(key: ty::PolyTraitRef<'tcx>) + query vtable_entries(key: ty::TraitRef<'tcx>) -> &'tcx [ty::VtblEntry<'tcx>] { - desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) } + desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id) } } query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize { @@ -1449,7 +1449,7 @@ rustc_queries! { key.1, key.0 } } - query vtable_allocation(key: (Ty<'tcx>, Option>)) -> mir::interpret::AllocId { + query vtable_allocation(key: (Ty<'tcx>, Option>)) -> mir::interpret::AllocId { desc { |tcx| "vtable const allocation for <{} as {}>", key.0, key.1.map(|trait_ref| format!("{trait_ref}")).unwrap_or("_".to_owned()) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6e6da6de749a1..075b32e49444f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -848,7 +848,12 @@ where } let mk_dyn_vtable = |principal: Option>| { - let min_count = ty::vtable_min_entries(tcx, principal); + let min_count = ty::vtable_min_entries( + tcx, + principal.map(|principal| { + tcx.instantiate_bound_regions_with_erased(principal) + }), + ); Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 09a05104e490a..6d97b85d46b2c 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -4,7 +4,7 @@ use rustc_ast::Mutability; use rustc_macros::HashStable; use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range}; -use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; +use crate::ty::{self, Instance, TraitRef, Ty, TyCtxt}; #[derive(Clone, Copy, PartialEq, HashStable)] pub enum VtblEntry<'tcx> { @@ -19,7 +19,7 @@ pub enum VtblEntry<'tcx> { /// dispatchable associated function Method(Instance<'tcx>), /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion - TraitVPtr(PolyTraitRef<'tcx>), + TraitVPtr(TraitRef<'tcx>), } impl<'tcx> fmt::Debug for VtblEntry<'tcx> { @@ -56,7 +56,7 @@ pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; // function is an accurate approximation. We verify this when actually computing the vtable below. pub(crate) fn vtable_min_entries<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: Option>, + trait_ref: Option>, ) -> usize { let mut count = TyCtxt::COMMON_VTABLE_ENTRIES.len(); let Some(trait_ref) = trait_ref else { @@ -64,7 +64,7 @@ pub(crate) fn vtable_min_entries<'tcx>( }; // This includes self in supertraits. - for def_id in tcx.supertrait_def_ids(trait_ref.def_id()) { + for def_id in tcx.supertrait_def_ids(trait_ref.def_id) { count += tcx.own_existential_vtable_entries(def_id).len(); } @@ -80,7 +80,7 @@ pub(crate) fn vtable_min_entries<'tcx>( /// initial contents.) pub(super) fn vtable_allocation_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: (Ty<'tcx>, Option>), + key: (Ty<'tcx>, Option>), ) -> AllocId { let (ty, poly_trait_ref) = key; @@ -115,7 +115,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( for (idx, entry) in vtable_entries.iter().enumerate() { let idx: u64 = u64::try_from(idx).unwrap(); - let scalar = match entry { + let scalar = match *entry { VtblEntry::MetadataDropInPlace => { if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) { let instance = ty::Instance::resolve_drop_in_place(tcx, ty); @@ -131,13 +131,12 @@ pub(super) fn vtable_allocation_provider<'tcx>( VtblEntry::Vacant => continue, VtblEntry::Method(instance) => { // Prepare the fn ptr we write into the vtable. - let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT); + let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT); let fn_ptr = Pointer::from(fn_alloc_id); Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::TraitVPtr(trait_ref) => { - let super_trait_ref = trait_ref - .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let super_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref); let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref))); let vptr = Pointer::from(supertrait_alloc_id); Scalar::from_pointer(vptr, &tcx) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 00aae03704fb6..6a58ba725744b 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1129,11 +1129,12 @@ fn create_mono_items_for_vtable_methods<'tcx>( bug!("create_mono_items_for_vtable_methods: {trait_ty:?} not a trait type"); }; if let Some(principal) = trait_ty.principal() { - let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); - assert!(!poly_trait_ref.has_escaping_bound_vars()); + let trait_ref = + tcx.instantiate_bound_regions_with_erased(principal.with_self_ty(tcx, impl_ty)); + assert!(!trait_ref.has_escaping_bound_vars()); // Walk all methods of the trait, including those of its supertraits - let entries = tcx.vtable_entries(poly_trait_ref); + let entries = tcx.vtable_entries(trait_ref); debug!(?entries); let methods = entries .iter() @@ -1188,7 +1189,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } GlobalAlloc::VTable(ty, dyn_ty) => { - let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal())); + let alloc_id = tcx.vtable_allocation(( + ty, + dyn_ty + .principal() + .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), + )); collect_alloc(tcx, alloc_id, output) } } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 9793a4d416239..172b75a444292 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -751,7 +751,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let alloc_id = tables.tcx.vtable_allocation(( ty.internal(&mut *tables, tcx), - trait_ref.internal(&mut *tables, tcx), + trait_ref + .internal(&mut *tables, tcx) + .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), )); Some(alloc_id.stable(&mut *tables)) } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index a8fddff4e4a87..3648fa28befad 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -13,7 +13,7 @@ use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; -use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt}; +use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt}; use rustc_span::{BytePos, Ident, Span, Symbol, kw}; use crate::error_reporting::infer::ObligationCauseAsDiagArg; @@ -28,7 +28,7 @@ pub mod note_and_explain; pub struct DumpVTableEntries<'a> { #[primary_span] pub span: Span, - pub trait_ref: PolyTraitRef<'a>, + pub trait_ref: ty::TraitRef<'a>, pub entries: String, } diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index b5bc8364c7b69..09d2ca621fac1 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -2,8 +2,8 @@ use std::fmt::Debug; use std::ops::ControlFlow; use rustc_hir::def_id::DefId; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; @@ -21,7 +21,7 @@ use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method #[derive(Clone, Debug)] pub enum VtblSegment<'tcx> { MetadataDSA, - TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool }, + TraitOwnEntries { trait_ref: ty::TraitRef<'tcx>, emit_vptr: bool }, } /// Prepare the segments for a vtable @@ -29,7 +29,7 @@ pub enum VtblSegment<'tcx> { // about our `Self` type here. pub fn prepare_vtable_segments<'tcx, T>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow, ) -> Option { prepare_vtable_segments_inner(tcx, trait_ref, segment_visitor).break_value() @@ -39,7 +39,7 @@ pub fn prepare_vtable_segments<'tcx, T>( /// such that we can use `?` in the body. fn prepare_vtable_segments_inner<'tcx, T>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow, ) -> ControlFlow { // The following constraints holds for the final arrangement. @@ -92,7 +92,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( let mut emit_vptr_on_new_entry = false; let mut visited = PredicateSet::new(tcx); let predicate = trait_ref.upcast(tcx); - let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> = + let mut stack: SmallVec<[(ty::TraitRef<'tcx>, _, _); 5]> = smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))]; visited.insert(predicate); @@ -125,10 +125,19 @@ fn prepare_vtable_segments_inner<'tcx, T>( let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); let mut direct_super_traits_iter = tcx - .explicit_super_predicates_of(inner_most_trait_ref.def_id()) + .explicit_super_predicates_of(inner_most_trait_ref.def_id) .iter_identity_copied() .filter_map(move |(pred, _)| { - pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause() + Some( + tcx.instantiate_bound_regions_with_erased( + pred.instantiate_supertrait( + tcx, + ty::Binder::dummy(inner_most_trait_ref), + ) + .as_trait_clause()?, + ) + .trait_ref, + ) }); // Find an unvisited supertrait @@ -136,16 +145,11 @@ fn prepare_vtable_segments_inner<'tcx, T>( .find(|&super_trait| visited.insert(super_trait.upcast(tcx))) { // Push it to the stack for the next iteration of 'diving_in to pick up - Some(unvisited_super_trait) => { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_super_trait = unvisited_super_trait.map_bound(|t| t.trait_ref); - stack.push(( - next_super_trait, - emit_vptr_on_new_entry, - maybe_iter(Some(direct_super_traits_iter)), - )) - } + Some(next_super_trait) => stack.push(( + next_super_trait, + emit_vptr_on_new_entry, + maybe_iter(Some(direct_super_traits_iter)), + )), // There are no more unvisited direct super traits, dive-in finished None => break 'diving_in, @@ -154,8 +158,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { - let has_entries = - has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id()); + let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id); segment_visitor(VtblSegment::TraitOwnEntries { trait_ref: inner_most_trait_ref, @@ -169,11 +172,6 @@ fn prepare_vtable_segments_inner<'tcx, T>( if let Some(next_inner_most_trait_ref) = siblings.find(|&sibling| visited.insert(sibling.upcast(tcx))) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_inner_most_trait_ref = - next_inner_most_trait_ref.map_bound(|t| t.trait_ref); - stack.push((next_inner_most_trait_ref, emit_vptr_on_new_entry, siblings)); // just pushed a new trait onto the stack, so we need to go through its super traits @@ -195,7 +193,7 @@ fn maybe_iter(i: Option) -> impl Iterator { fn dump_vtable_entries<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { tcx.dcx().emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") }); @@ -239,7 +237,7 @@ fn own_existential_vtable_entries_iter( /// that come from `trait_ref`, including its supertraits. fn vtable_entries<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, ) -> &'tcx [VtblEntry<'tcx>] { debug!("vtable_entries({:?})", trait_ref); @@ -251,33 +249,26 @@ fn vtable_entries<'tcx>( entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES); } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - let existential_trait_ref = trait_ref - .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref); // Lookup the shape of vtable for the trait. let own_existential_entries = - tcx.own_existential_vtable_entries(existential_trait_ref.def_id()); + tcx.own_existential_vtable_entries(existential_trait_ref.def_id); let own_entries = own_existential_entries.iter().copied().map(|def_id| { debug!("vtable_entries: trait_method={:?}", def_id); // The method may have some early-bound lifetimes; add regions for those. - let args = trait_ref.map_bound(|trait_ref| { + // FIXME: Is this normalize needed? + let args = tcx.normalize_erasing_regions( + ty::TypingEnv::fully_monomorphized(), GenericArgs::for_item(tcx, def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { trait_ref.args[param.index as usize] } - }) - }); - - // The trait type may have higher-ranked lifetimes in it; - // erase them if they appear, so that we get the type - // at some particular call site. - let args = tcx.normalize_erasing_late_bound_regions( - ty::TypingEnv::fully_monomorphized(), - args, + }), ); // It's possible that the method relies on where-clauses that @@ -317,8 +308,8 @@ fn vtable_entries<'tcx>( let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback); - if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) { - let sp = tcx.def_span(trait_ref.def_id()); + if tcx.has_attr(trait_ref.def_id, sym::rustc_dump_vtable) { + let sp = tcx.def_span(trait_ref.def_id); dump_vtable_entries(tcx, sp, trait_ref, &entries); } @@ -333,10 +324,11 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe let ty::Dynamic(source, _, _) = *key.self_ty().kind() else { bug!(); }; - let source_principal = - source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = tcx.instantiate_bound_regions_with_erased( + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self), + ); - let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key)); + let target_principal = ty::ExistentialTraitRef::erase_self_ty(tcx, key); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -348,15 +340,14 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { if trait_refs_are_compatible( tcx, - vtable_principal - .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), + ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal), target_principal, ) { return ControlFlow::Break(vptr_offset); } vptr_offset += - tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); + tcx.own_existential_vtable_entries(vtable_principal.def_id).len(); if emit_vptr { vptr_offset += 1; @@ -388,14 +379,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( let ty::Dynamic(target, _, _) = *target.kind() else { bug!(); }; - let target_principal = target.principal()?; + let target_principal = tcx.instantiate_bound_regions_with_erased(target.principal()?); // Given that we have a target principal, it is a bug for there not to be a source principal. let ty::Dynamic(source, _, _) = *source.kind() else { bug!(); }; - let source_principal = - source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = tcx.instantiate_bound_regions_with_erased( + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self), + ); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -406,11 +398,10 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( } VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { vptr_offset += - tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); + tcx.own_existential_vtable_entries(vtable_principal.def_id).len(); if trait_refs_are_compatible( tcx, - vtable_principal - .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), + ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal), target_principal, ) { if emit_vptr { @@ -434,37 +425,32 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( fn trait_refs_are_compatible<'tcx>( tcx: TyCtxt<'tcx>, - hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>, - hr_target_principal: ty::PolyExistentialTraitRef<'tcx>, + vtable_principal: ty::ExistentialTraitRef<'tcx>, + target_principal: ty::ExistentialTraitRef<'tcx>, ) -> bool { - if hr_vtable_principal.def_id() != hr_target_principal.def_id() { + if vtable_principal.def_id != target_principal.def_id { return false; } let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let ocx = ObligationCtxt::new(&infcx); - let hr_source_principal = - ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal); - let hr_target_principal = - ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal); - infcx.enter_forall(hr_target_principal, |target_principal| { - let source_principal = infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - hr_source_principal, - ); - let Ok(()) = ocx.eq_trace( + let source_principal = ocx.normalize(&ObligationCause::dummy(), param_env, vtable_principal); + let target_principal = ocx.normalize(&ObligationCause::dummy(), param_env, target_principal); + let Ok(()) = ocx.eq_trace( + &ObligationCause::dummy(), + param_env, + ToTrace::to_trace( &ObligationCause::dummy(), - param_env, - ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal), - target_principal, - source_principal, - ) else { - return false; - }; - ocx.select_all_or_error().is_empty() - }) + ty::Binder::dummy(target_principal), + ty::Binder::dummy(source_principal), + ), + target_principal, + source_principal, + ) else { + return false; + }; + ocx.select_all_or_error().is_empty() } pub(super) fn provide(providers: &mut Providers) { diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs new file mode 100644 index 0000000000000..7bc069f4f4407 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs @@ -0,0 +1,24 @@ +//@ run-pass +//@ check-run-results + +#![feature(trait_upcasting)] + +trait Supertrait { + fn _print_numbers(&self, mem: &[usize; 100]) { + println!("{mem:?}"); + } +} +impl Supertrait for () {} + +trait Trait: Supertrait + Supertrait { + fn say_hello(&self, _: &usize) { + println!("Hello!"); + } +} +impl Trait for () {} + +fn main() { + (&() as &'static dyn for<'a> Trait<&'static (), &'a ()> + as &'static dyn Trait<&'static (), &'static ()>) + .say_hello(&0); +} diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout new file mode 100644 index 0000000000000..10ddd6d257e01 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout @@ -0,0 +1 @@ +Hello!