1
Fork 0

Only compute vtable information during codegen

This commit is contained in:
Michael Goulet 2024-06-14 20:35:45 -04:00
parent f8e5660532
commit 3b9adbec32
14 changed files with 141 additions and 195 deletions

View file

@ -39,8 +39,7 @@ pub(crate) fn unsized_info<'tcx>(
} }
// trait upcasting coercion // trait upcasting coercion
let vptr_entry_idx = let vptr_entry_idx = fx.tcx.supertrait_vtable_slot((source, target));
fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
if let Some(entry_idx) = vptr_entry_idx { if let Some(entry_idx) = vptr_entry_idx {
let entry_idx = u32::try_from(entry_idx).unwrap(); let entry_idx = u32::try_from(entry_idx).unwrap();

View file

@ -163,8 +163,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// trait upcasting coercion // trait upcasting coercion
let vptr_entry_idx = let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target));
cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
if let Some(entry_idx) = vptr_entry_idx { if let Some(entry_idx) = vptr_entry_idx {
let ptr_size = bx.data_layout().pointer_size; let ptr_size = bx.data_layout().pointer_size;

View file

@ -360,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) {
} }
} }
impl<'tcx> Key for ty::TraitRef<'tcx> {
type Cache<V> = DefaultCache<Self, V>;
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(self.def_id)
}
}
impl<'tcx> Key for ty::PolyTraitRef<'tcx> { impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
type Cache<V> = DefaultCache<Self, V>; type Cache<V> = DefaultCache<Self, V>;

View file

@ -46,6 +46,7 @@ use crate::traits::{
}; };
use crate::ty::fast_reject::SimplifiedType; use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::ValidityRequirement; use crate::ty::layout::ValidityRequirement;
use crate::ty::print::PrintTraitRefExt;
use crate::ty::util::AlwaysRequiresDrop; use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::TyCtxtFeed; use crate::ty::TyCtxtFeed;
use crate::ty::{ use crate::ty::{
@ -1271,7 +1272,11 @@ rustc_queries! {
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 vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> { query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize {
desc { |tcx| "finding the slot within the vtable of `{}` for the implementation of `{}`", key.self_ty(), key.print_only_trait_name() }
}
query supertrait_vtable_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> {
desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable", desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable",
key.1, key.0 } key.1, key.0 }
} }

View file

@ -3,6 +3,7 @@
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::supertraits;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::inspect::ProbeKind;
use rustc_middle::traits::solve::{ use rustc_middle::traits::solve::{
@ -743,14 +744,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
// a projection goal. // a projection goal.
if let Some(principal) = bounds.principal() { if let Some(principal) = bounds.principal() {
let principal_trait_ref = principal.with_self_ty(tcx, self_ty); let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| { for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() {
candidates.extend(G::probe_and_consider_object_bound_candidate( candidates.extend(G::probe_and_consider_object_bound_candidate(
ecx, self,
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }), CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
goal, goal,
assumption.upcast(tcx), assumption.upcast(tcx),
)); ));
}); }
} }
} }

View file

@ -24,7 +24,6 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
use std::ops::ControlFlow; use std::ops::ControlFlow;
use crate::traits::coherence; use crate::traits::coherence;
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
use super::inspect::ProofTreeBuilder; use super::inspect::ProofTreeBuilder;
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
@ -1022,41 +1021,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
} }
} }
} }
/// Walk through the vtable of a principal trait ref, executing a `supertrait_visitor`
/// for every trait ref encountered (including the principal). Passes both the vtable
/// base and the (optional) vptr slot.
pub(super) fn walk_vtable(
&mut self,
principal: ty::PolyTraitRef<'tcx>,
mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option<usize>),
) {
let tcx = self.interner();
let mut offset = 0;
prepare_vtable_segments::<()>(tcx, principal, |segment| {
match segment {
VtblSegment::MetadataDSA => {
offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
let own_vtable_entries = count_own_vtable_entries(tcx, trait_ref);
supertrait_visitor(
self,
trait_ref,
offset,
emit_vptr.then(|| offset + own_vtable_entries),
);
offset += own_vtable_entries;
if emit_vptr {
offset += 1;
}
}
}
ControlFlow::Continue(())
});
}
} }
/// Eagerly replace aliases with inference variables, emitting `AliasRelate` /// Eagerly replace aliases with inference variables, emitting `AliasRelate`

View file

@ -114,8 +114,8 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
// In the old trait solver, we arbitrarily choose lower vtable candidates // In the old trait solver, we arbitrarily choose lower vtable candidates
// over higher ones. // over higher ones.
( (
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }), CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)),
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }), CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)),
) => a >= b, ) => a >= b,
// Prefer dyn candidates over non-dyn candidates. This is necessary to // Prefer dyn candidates over non-dyn candidates. This is necessary to
// handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`. // handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.

View file

@ -9,6 +9,7 @@ use rustc_hir::{LangItem, Movability};
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::solve::MaybeCause;
use rustc_infer::traits::util::supertraits;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::inspect::ProbeKind;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
@ -756,24 +757,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
a_data.principal(), a_data.principal(),
)); ));
} else if let Some(a_principal) = a_data.principal() { } else if let Some(a_principal) = a_data.principal() {
self.walk_vtable( for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) {
a_principal.with_self_ty(tcx, a_ty), responses.extend(self.consider_builtin_upcast_to_principal(
|ecx, new_a_principal, _, vtable_vptr_slot| { goal,
responses.extend(ecx.consider_builtin_upcast_to_principal( CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
goal, a_data,
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting { a_region,
vtable_vptr_slot, b_data,
}), b_region,
a_data, Some(new_a_principal.map_bound(|trait_ref| {
a_region, ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
b_data, })),
b_region, ));
Some(new_a_principal.map_bound(|trait_ref| { }
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
})),
));
},
);
} }
responses responses

View file

@ -65,7 +65,7 @@ pub use self::structural_match::search_for_structural_match_violation;
pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::structural_normalize::StructurallyNormalizeExt;
pub use self::util::elaborate; pub use self::util::elaborate;
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo}; pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{impl_item_is_final, upcast_choices};
pub use self::util::{supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item}; pub use self::util::{supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item};
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};

View file

@ -22,10 +22,6 @@ use rustc_span::def_id::DefId;
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::vtable::{
count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
VtblSegment,
};
use crate::traits::{ use crate::traits::{
ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation,
ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError,
@ -689,13 +685,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?nested, "object nested obligations"); debug!(?nested, "object nested obligations");
let vtable_base = vtable_trait_first_method_offset( Ok(ImplSource::Builtin(BuiltinImplSource::Object(index), nested))
tcx,
unnormalized_upcast_trait_ref,
ty::Binder::dummy(object_trait_ref),
);
Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested))
} }
fn confirm_fn_pointer_candidate( fn confirm_fn_pointer_candidate(
@ -1125,36 +1115,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)? )?
.expect("did not expect ambiguity during confirmation"); .expect("did not expect ambiguity during confirmation");
let vtable_segment_callback = { Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting, nested))
let mut vptr_offset = 0;
move |segment| {
match segment {
VtblSegment::MetadataDSA => {
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
vptr_offset += count_own_vtable_entries(tcx, trait_ref);
if trait_ref == unnormalized_upcast_principal {
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 =
prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap();
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested))
} }
fn confirm_builtin_unsize_candidate( fn confirm_builtin_unsize_candidate(

View file

@ -208,23 +208,6 @@ pub fn upcast_choices<'tcx>(
supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
} }
/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<'tcx>(
tcx: TyCtxt<'tcx>,
vtable_base: usize,
method_def_id: DefId,
) -> Option<usize> {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
tcx.own_existential_vtable_entries(tcx.parent(method_def_id))
.iter()
.copied()
.position(|def_id| def_id == method_def_id)
.map(|index| vtable_base + index)
}
pub fn closure_trait_ref_and_return_type<'tcx>( pub fn closure_trait_ref_and_return_type<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId, fn_trait_def_id: DefId,

View file

@ -1,15 +1,11 @@
use crate::errors::DumpVTableEntries; use crate::errors::DumpVTableEntries;
use crate::traits::{impossible_predicates, is_vtable_safe_method}; use crate::traits::{impossible_predicates, is_vtable_safe_method};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::util::PredicateSet;
use rustc_infer::traits::ImplSource;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry}; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
use rustc_middle::ty::{GenericArgs, TypeVisitableExt};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -320,30 +316,42 @@ fn vtable_entries<'tcx>(
tcx.arena.alloc_from_iter(entries) tcx.arena.alloc_from_iter(entries)
} }
/// Find slot base for trait methods within vtable entries of another trait // Given a `dyn Subtrait: Supertrait` trait ref, find corresponding first slot
pub(super) fn vtable_trait_first_method_offset<'tcx>( // for `Supertrait`'s methods in the vtable of `Subtrait`.
tcx: TyCtxt<'tcx>, pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRef<'tcx>) -> usize {
trait_to_be_found: ty::PolyTraitRef<'tcx>, debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param());
trait_owning_vtable: ty::PolyTraitRef<'tcx>,
) -> usize { let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
// #90177 bug!();
let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found); };
let source_principal = tcx
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap())
.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
let target_principal = tcx
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), key)
// We don't care about the self type, since it will always be the same thing.
.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
let vtable_segment_callback = { let vtable_segment_callback = {
let mut vtable_base = 0; let mut vptr_offset = 0;
move |segment| { move |segment| {
match segment { match segment {
VtblSegment::MetadataDSA => { VtblSegment::MetadataDSA => {
vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len(); vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
} }
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
if tcx.erase_regions(trait_ref) == trait_to_be_found_erased { if tcx
return ControlFlow::Break(vtable_base); .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref)
== target_principal
{
return ControlFlow::Break(vptr_offset);
} }
vtable_base += count_own_vtable_entries(tcx, trait_ref);
vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
if emit_vptr { if emit_vptr {
vtable_base += 1; vptr_offset += 1;
} }
} }
} }
@ -351,55 +359,72 @@ pub(super) fn vtable_trait_first_method_offset<'tcx>(
} }
}; };
if let Some(vtable_base) = prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
{
vtable_base
} else {
bug!("Failed to find info for expected trait in vtable");
}
} }
/// Find slot offset for trait vptr within vtable entries of another trait /// Given a `dyn Subtrait` and `dyn Supertrait` trait object, find the slot of
pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( /// // the trait vptr in the subtrait's vtable.
pub(crate) fn supertrait_vtable_slot<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
key: ( key: (
Ty<'tcx>, // trait object type whose trait owning vtable Ty<'tcx>, // Source -- `dyn Subtrait`.
Ty<'tcx>, // trait object for supertrait Ty<'tcx>, // Target -- `dyn Supertrait` being coerced to.
), ),
) -> Option<usize> { ) -> Option<usize> {
debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param());
let (source, target) = key; let (source, target) = key;
assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.has_infer()); let ty::Dynamic(source, _, _) = *source.kind() else {
assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.has_infer()); bug!();
};
let source_principal = tcx
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap())
.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
// this has been typecked-before, so diagnostics is not really needed. let ty::Dynamic(target, _, _) = *target.kind() else {
let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None); bug!();
};
let target_principal = tcx
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal().unwrap())
.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]); let vtable_segment_callback = {
let mut vptr_offset = 0;
move |segment| {
match segment {
VtblSegment::MetadataDSA => {
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref)
== target_principal
{
if emit_vptr {
return ControlFlow::Break(Some(vptr_offset));
} else {
return ControlFlow::Break(None);
}
}
match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { if emit_vptr {
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => { vptr_offset += 1;
*vtable_vptr_slot }
}
}
ControlFlow::Continue(())
} }
otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"), };
}
}
/// Given a trait `trait_ref`, returns the number of vtable entries prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub(crate) fn count_own_vtable_entries<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
) -> usize {
tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
} }
pub(super) fn provide(providers: &mut Providers) { pub(super) fn provide(providers: &mut Providers) {
*providers = Providers { *providers = Providers {
own_existential_vtable_entries, own_existential_vtable_entries,
vtable_entries, vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot, first_method_vtable_slot,
supertrait_vtable_slot,
..*providers ..*providers
}; };
} }

View file

@ -212,13 +212,23 @@ fn resolve_associated_item<'tcx>(
Some(ty::Instance::new(leaf_def.item.def_id, args)) Some(ty::Instance::new(leaf_def.item.def_id, args))
} }
traits::ImplSource::Builtin(BuiltinImplSource::Object { vtable_base }, _) => { traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map( let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args);
|index| Instance { if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
def: ty::InstanceDef::Virtual(trait_item_id, index), // We only resolve totally substituted vtable entries.
None
} else {
let vtable_base = tcx.first_method_vtable_slot(trait_ref);
let offset = tcx
.own_existential_vtable_entries(trait_id)
.iter()
.copied()
.position(|def_id| def_id == trait_item_id);
offset.map(|offset| Instance {
def: ty::InstanceDef::Virtual(trait_item_id, vtable_base + offset),
args: rcvr_args, args: rcvr_args,
}, })
) }
} }
traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => { traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
let lang_items = tcx.lang_items(); let lang_items = tcx.lang_items();

View file

@ -171,25 +171,20 @@ pub enum CandidateSource<I: Interner> {
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))]
pub enum BuiltinImplSource { pub enum BuiltinImplSource {
/// Some builtin impl we don't need to differentiate. This should be used /// Some built-in impl we don't need to differentiate. This should be used
/// unless more specific information is necessary. /// unless more specific information is necessary.
Misc, Misc,
/// A builtin impl for trait objects. /// A built-in impl for trait objects. The index is only used in winnowing.
Object(usize),
/// A built-in implementation of `Upcast` for trait objects to other trait objects.
/// ///
/// The vtable is formed by concatenating together the method lists of /// This can be removed when `feature(dyn_upcasting)` is stabilized, since we only
/// the base object trait and all supertraits, pointers to supertrait vtable will /// use it to detect when upcasting traits in hir typeck.
/// be provided when necessary; this is the start of `upcast_trait_ref`'s methods TraitUpcasting,
/// in that vtable.
Object { vtable_base: usize },
/// 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.
TraitUpcasting { vtable_vptr_slot: Option<usize> },
/// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
/// ///
/// This needs to be a separate variant as it is still unstable and we need to emit /// This can be removed when `feature(tuple_unsizing)` is stabilized, since we only
/// a feature error when using it on stable. /// use it to detect when unsizing tuples in hir typeck.
TupleUnsizing, TupleUnsizing,
} }