Skip to content

Commit 5639c21

Browse files
committed
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.
2 parents cd0c944 + 3b9adbe commit 5639c21

File tree

14 files changed

+141
-195
lines changed

14 files changed

+141
-195
lines changed

compiler/rustc_codegen_cranelift/src/unsize.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ pub(crate) fn unsized_info<'tcx>(
3939
}
4040

4141
// trait upcasting coercion
42-
let vptr_entry_idx =
43-
fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
42+
let vptr_entry_idx = fx.tcx.supertrait_vtable_slot((source, target));
4443

4544
if let Some(entry_idx) = vptr_entry_idx {
4645
let entry_idx = u32::try_from(entry_idx).unwrap();

compiler/rustc_codegen_ssa/src/base.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
163163

164164
// trait upcasting coercion
165165

166-
let vptr_entry_idx =
167-
cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
166+
let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target));
168167

169168
if let Some(entry_idx) = vptr_entry_idx {
170169
let ptr_size = bx.data_layout().pointer_size;

compiler/rustc_middle/src/query/keys.rs

+8
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) {
360360
}
361361
}
362362

363+
impl<'tcx> Key for ty::TraitRef<'tcx> {
364+
type Cache<V> = DefaultCache<Self, V>;
365+
366+
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
367+
tcx.def_span(self.def_id)
368+
}
369+
}
370+
363371
impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
364372
type Cache<V> = DefaultCache<Self, V>;
365373

compiler/rustc_middle/src/query/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use crate::traits::{
4646
};
4747
use crate::ty::fast_reject::SimplifiedType;
4848
use crate::ty::layout::ValidityRequirement;
49+
use crate::ty::print::PrintTraitRefExt;
4950
use crate::ty::util::AlwaysRequiresDrop;
5051
use crate::ty::TyCtxtFeed;
5152
use crate::ty::{
@@ -1271,7 +1272,11 @@ rustc_queries! {
12711272
desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
12721273
}
12731274

1274-
query vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> {
1275+
query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize {
1276+
desc { |tcx| "finding the slot within the vtable of `{}` for the implementation of `{}`", key.self_ty(), key.print_only_trait_name() }
1277+
}
1278+
1279+
query supertrait_vtable_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> {
12751280
desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable",
12761281
key.1, key.0 }
12771282
}

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
55
use rustc_hir::LangItem;
66
use rustc_infer::infer::InferCtxt;
77
use rustc_infer::traits::query::NoSolution;
8+
use rustc_infer::traits::util::supertraits;
89
use rustc_middle::bug;
910
use rustc_middle::traits::solve::inspect::ProbeKind;
1011
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult};
@@ -744,14 +745,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
744745
// a projection goal.
745746
if let Some(principal) = bounds.principal() {
746747
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
747-
self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
748+
for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() {
748749
candidates.extend(G::probe_and_consider_object_bound_candidate(
749-
ecx,
750-
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }),
750+
self,
751+
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
751752
goal,
752753
assumption.upcast(tcx),
753754
));
754-
});
755+
}
755756
}
756757
}
757758

compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

-36
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
2424
use std::ops::ControlFlow;
2525

2626
use crate::traits::coherence;
27-
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
2827

2928
use super::inspect::ProofTreeBuilder;
3029
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
@@ -1022,41 +1021,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
10221021
}
10231022
}
10241023
}
1025-
1026-
/// Walk through the vtable of a principal trait ref, executing a `supertrait_visitor`
1027-
/// for every trait ref encountered (including the principal). Passes both the vtable
1028-
/// base and the (optional) vptr slot.
1029-
pub(super) fn walk_vtable(
1030-
&mut self,
1031-
principal: ty::PolyTraitRef<'tcx>,
1032-
mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option<usize>),
1033-
) {
1034-
let tcx = self.interner();
1035-
let mut offset = 0;
1036-
prepare_vtable_segments::<()>(tcx, principal, |segment| {
1037-
match segment {
1038-
VtblSegment::MetadataDSA => {
1039-
offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
1040-
}
1041-
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
1042-
let own_vtable_entries = count_own_vtable_entries(tcx, trait_ref);
1043-
1044-
supertrait_visitor(
1045-
self,
1046-
trait_ref,
1047-
offset,
1048-
emit_vptr.then(|| offset + own_vtable_entries),
1049-
);
1050-
1051-
offset += own_vtable_entries;
1052-
if emit_vptr {
1053-
offset += 1;
1054-
}
1055-
}
1056-
}
1057-
ControlFlow::Continue(())
1058-
});
1059-
}
10601024
}
10611025

10621026
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`

compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs

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

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_hir::{LangItem, Movability};
99
use rustc_infer::infer::InferCtxt;
1010
use rustc_infer::traits::query::NoSolution;
1111
use rustc_infer::traits::solve::MaybeCause;
12+
use rustc_infer::traits::util::supertraits;
1213
use rustc_middle::bug;
1314
use rustc_middle::traits::solve::inspect::ProbeKind;
1415
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
@@ -756,24 +757,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
756757
a_data.principal(),
757758
));
758759
} else if let Some(a_principal) = a_data.principal() {
759-
self.walk_vtable(
760-
a_principal.with_self_ty(tcx, a_ty),
761-
|ecx, new_a_principal, _, vtable_vptr_slot| {
762-
responses.extend(ecx.consider_builtin_upcast_to_principal(
763-
goal,
764-
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting {
765-
vtable_vptr_slot,
766-
}),
767-
a_data,
768-
a_region,
769-
b_data,
770-
b_region,
771-
Some(new_a_principal.map_bound(|trait_ref| {
772-
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
773-
})),
774-
));
775-
},
776-
);
760+
for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) {
761+
responses.extend(self.consider_builtin_upcast_to_principal(
762+
goal,
763+
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
764+
a_data,
765+
a_region,
766+
b_data,
767+
b_region,
768+
Some(new_a_principal.map_bound(|trait_ref| {
769+
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
770+
})),
771+
));
772+
}
777773
}
778774

779775
responses

compiler/rustc_trait_selection/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub use self::structural_match::search_for_structural_match_violation;
6565
pub use self::structural_normalize::StructurallyNormalizeExt;
6666
pub use self::util::elaborate;
6767
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
68-
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
68+
pub use self::util::{impl_item_is_final, upcast_choices};
6969
pub use self::util::{supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item};
7070
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
7171

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+2-41
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ use rustc_span::def_id::DefId;
2222

2323
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
2424
use crate::traits::util::{self, closure_trait_ref_and_return_type};
25-
use crate::traits::vtable::{
26-
count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
27-
VtblSegment,
28-
};
2925
use crate::traits::{
3026
ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation,
3127
ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError,
@@ -689,13 +685,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
689685

690686
debug!(?nested, "object nested obligations");
691687

692-
let vtable_base = vtable_trait_first_method_offset(
693-
tcx,
694-
unnormalized_upcast_trait_ref,
695-
ty::Binder::dummy(object_trait_ref),
696-
);
697-
698-
Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested))
688+
Ok(ImplSource::Builtin(BuiltinImplSource::Object(index), nested))
699689
}
700690

701691
fn confirm_fn_pointer_candidate(
@@ -1125,36 +1115,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11251115
)?
11261116
.expect("did not expect ambiguity during confirmation");
11271117

1128-
let vtable_segment_callback = {
1129-
let mut vptr_offset = 0;
1130-
move |segment| {
1131-
match segment {
1132-
VtblSegment::MetadataDSA => {
1133-
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
1134-
}
1135-
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
1136-
vptr_offset += count_own_vtable_entries(tcx, trait_ref);
1137-
if trait_ref == unnormalized_upcast_principal {
1138-
if emit_vptr {
1139-
return ControlFlow::Break(Some(vptr_offset));
1140-
} else {
1141-
return ControlFlow::Break(None);
1142-
}
1143-
}
1144-
1145-
if emit_vptr {
1146-
vptr_offset += 1;
1147-
}
1148-
}
1149-
}
1150-
ControlFlow::Continue(())
1151-
}
1152-
};
1153-
1154-
let vtable_vptr_slot =
1155-
prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap();
1156-
1157-
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested))
1118+
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting, nested))
11581119
}
11591120

11601121
fn confirm_builtin_unsize_candidate(

compiler/rustc_trait_selection/src/traits/util.rs

-17
Original file line numberDiff line numberDiff line change
@@ -208,23 +208,6 @@ pub fn upcast_choices<'tcx>(
208208
supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
209209
}
210210

211-
/// Given an upcast trait object described by `object`, returns the
212-
/// index of the method `method_def_id` (which should be part of
213-
/// `object.upcast_trait_ref`) within the vtable for `object`.
214-
pub fn get_vtable_index_of_object_method<'tcx>(
215-
tcx: TyCtxt<'tcx>,
216-
vtable_base: usize,
217-
method_def_id: DefId,
218-
) -> Option<usize> {
219-
// Count number of methods preceding the one we are selecting and
220-
// add them to the total offset.
221-
tcx.own_existential_vtable_entries(tcx.parent(method_def_id))
222-
.iter()
223-
.copied()
224-
.position(|def_id| def_id == method_def_id)
225-
.map(|index| vtable_base + index)
226-
}
227-
228211
pub fn closure_trait_ref_and_return_type<'tcx>(
229212
tcx: TyCtxt<'tcx>,
230213
fn_trait_def_id: DefId,

0 commit comments

Comments
 (0)