Auto merge of #126505 - compiler-errors:no-vtable, r=lcnr
Only compute vtable information during codegen This PR removes vtable information from the `Object` and `TraitUpcasting` candidate sources in the trait solvers, and defers the computation of relevant information to `Instance::resolve`. This is because vtables really aren't a thing in the trait world -- they're an implementation detail in codegen. Previously it was just easiest to tangle this information together since we were already doing the work of looking at all the supertraits in the trait solver, and specifically because we use traits to represent when it's possible to call a method via a vtable (`Object` candidate) and do upcasting (`Unsize` candidate). but I am somewhat suspicious we're doing a *lot* of extra work, especially in polymorphic contexts, so let's see what perf says.
This commit is contained in:
@@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult};
|
||||
@@ -744,14 +745,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// a projection goal.
|
||||
if let Some(principal) = bounds.principal() {
|
||||
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(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }),
|
||||
self,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
|
||||
goal,
|
||||
assumption.upcast(tcx),
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::traits::coherence;
|
||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
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`
|
||||
|
||||
@@ -114,8 +114,8 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
|
||||
// In the old trait solver, we arbitrarily choose lower vtable candidates
|
||||
// over higher ones.
|
||||
(
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }),
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }),
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)),
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)),
|
||||
) => a >= b,
|
||||
// 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`.
|
||||
|
||||
@@ -9,6 +9,7 @@ use rustc_hir::{LangItem, Movability};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::MaybeCause;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||
@@ -756,24 +757,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
a_data.principal(),
|
||||
));
|
||||
} else if let Some(a_principal) = a_data.principal() {
|
||||
self.walk_vtable(
|
||||
a_principal.with_self_ty(tcx, a_ty),
|
||||
|ecx, new_a_principal, _, vtable_vptr_slot| {
|
||||
responses.extend(ecx.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting {
|
||||
vtable_vptr_slot,
|
||||
}),
|
||||
a_data,
|
||||
a_region,
|
||||
b_data,
|
||||
b_region,
|
||||
Some(new_a_principal.map_bound(|trait_ref| {
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
})),
|
||||
));
|
||||
},
|
||||
);
|
||||
for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) {
|
||||
responses.extend(self.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
|
||||
a_data,
|
||||
a_region,
|
||||
b_data,
|
||||
b_region,
|
||||
Some(new_a_principal.map_bound(|trait_ref| {
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
})),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
responses
|
||||
|
||||
Reference in New Issue
Block a user