Skip to content

Commit 488acf8

Browse files
committed
Auto merge of #90639 - matthewjasper:leaf-def-cache, r=cjgillot
Add a query for resolving an impl item from the trait item This makes finding the item in an impl that implements a given trait item a query. This is for a few reasons: - To slightly improve performance - To avoid having to do name resolution during monomorphisation - To make it easier to implement potential future features that create anonymous associated items
2 parents 66f64a4 + 9d625bc commit 488acf8

File tree

25 files changed

+483
-448
lines changed

25 files changed

+483
-448
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
10081008
self.get_impl_data(id).constness
10091009
}
10101010

1011+
fn get_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> {
1012+
self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
1013+
}
1014+
10111015
fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
10121016
self.get_impl_data(id).coerce_unsized_info
10131017
}
@@ -1258,6 +1262,16 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
12581262
}
12591263
}
12601264

1265+
fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
1266+
if let Some(children) = self.root.tables.children.get(self, id) {
1267+
tcx.arena.alloc_from_iter(
1268+
children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)),
1269+
)
1270+
} else {
1271+
&[]
1272+
}
1273+
}
1274+
12611275
fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
12621276
let def_key = self.def_key(id);
12631277
let parent = self.local_def_id(def_key.parent.unwrap());
@@ -1279,6 +1293,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
12791293
vis: self.get_visibility(id),
12801294
defaultness: container.defaultness(),
12811295
def_id: self.local_def_id(id),
1296+
trait_item_def_id: self.get_trait_item_def_id(id),
12821297
container: container.with_def_id(parent),
12831298
fn_has_self_parameter: has_self,
12841299
}

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
103103
tcx.calculate_dtor(def_id, |_,_| Ok(()))
104104
}
105105
variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
106-
associated_item_def_ids => {
107-
let mut result = SmallVec::<[_; 8]>::new();
108-
cdata.each_child_of_item(def_id.index,
109-
|child| result.push(child.res.def_id()), tcx.sess);
110-
tcx.arena.alloc_slice(&result)
111-
}
106+
associated_item_def_ids => { cdata.get_associated_item_def_ids(tcx, def_id.index) }
112107
associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
113108
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
114109
impl_polarity => { cdata.get_impl_polarity(def_id.index) }

compiler/rustc_metadata/src/rmeta/encoder.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
12941294
}
12951295
self.encode_ident_span(def_id, impl_item.ident);
12961296
self.encode_item_type(def_id);
1297+
if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
1298+
record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
1299+
}
12971300
if impl_item.kind == ty::AssocKind::Fn {
12981301
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
12991302
}

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ define_tables! {
302302
ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
303303
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
304304
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
305+
trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
305306
inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
306307
variances: Table<DefIndex, Lazy<[ty::Variance]>>,
307308
generics: Table<DefIndex, Lazy<ty::Generics>>,

compiler/rustc_middle/src/query/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,32 @@ rustc_queries! {
630630
desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
631631
}
632632

633+
/// Maps from associated items on a trait to the corresponding associated
634+
/// item on the impl specified by `impl_id`.
635+
///
636+
/// For example, with the following code
637+
///
638+
/// ```
639+
/// struct Type {}
640+
/// // DefId
641+
/// trait Trait { // trait_id
642+
/// fn f(); // trait_f
643+
/// fn g() {} // trait_g
644+
/// }
645+
///
646+
/// impl Trait for Type { // impl_id
647+
/// fn f() {} // impl_f
648+
/// fn g() {} // impl_g
649+
/// }
650+
/// ```
651+
///
652+
/// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
653+
///`{ trait_f: impl_f, trait_g: impl_g }`
654+
query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
655+
desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
656+
storage(ArenaCacheSelector<'tcx>)
657+
}
658+
633659
/// Given an `impl_id`, return the trait it implements.
634660
/// Return `None` if this is an inherent impl.
635661
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {

compiler/rustc_middle/src/traits/specialization_graph.rs

+16-29
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::ty::{self, TyCtxt};
44
use rustc_data_structures::fx::FxIndexMap;
55
use rustc_errors::ErrorReported;
66
use rustc_hir::def_id::{DefId, DefIdMap};
7-
use rustc_span::symbol::Ident;
87

98
/// A per-trait graph of impls in specialization order. At the moment, this
109
/// graph forms a tree rooted with the trait itself, with all other nodes
@@ -75,34 +74,28 @@ pub enum Node {
7574
Trait(DefId),
7675
}
7776

78-
impl<'tcx> Node {
77+
impl Node {
7978
pub fn is_from_trait(&self) -> bool {
8079
matches!(self, Node::Trait(..))
8180
}
8281

83-
/// Iterate over the items defined directly by the given (impl or trait) node.
84-
pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> {
85-
tcx.associated_items(self.def_id()).in_definition_order()
86-
}
87-
88-
/// Finds an associated item defined in this node.
82+
/// Trys to find the associated item that implements `trait_item_def_id`
83+
/// defined in this node.
8984
///
9085
/// If this returns `None`, the item can potentially still be found in
9186
/// parents of this node.
92-
pub fn item(
87+
pub fn item<'tcx>(
9388
&self,
9489
tcx: TyCtxt<'tcx>,
95-
trait_item_name: Ident,
96-
trait_item_kind: ty::AssocKind,
97-
trait_def_id: DefId,
98-
) -> Option<ty::AssocItem> {
99-
tcx.associated_items(self.def_id())
100-
.filter_by_name_unhygienic(trait_item_name.name)
101-
.find(move |impl_item| {
102-
trait_item_kind == impl_item.kind
103-
&& tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
104-
})
105-
.copied()
90+
trait_item_def_id: DefId,
91+
) -> Option<&'tcx ty::AssocItem> {
92+
match *self {
93+
Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)),
94+
Node::Impl(impl_def_id) => {
95+
let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?;
96+
Some(tcx.associated_item(*id))
97+
}
98+
}
10699
}
107100

108101
pub fn def_id(&self) -> DefId {
@@ -181,17 +174,11 @@ impl LeafDef {
181174
impl<'tcx> Ancestors<'tcx> {
182175
/// Finds the bottom-most (ie. most specialized) definition of an associated
183176
/// item.
184-
pub fn leaf_def(
185-
mut self,
186-
tcx: TyCtxt<'tcx>,
187-
trait_item_name: Ident,
188-
trait_item_kind: ty::AssocKind,
189-
) -> Option<LeafDef> {
190-
let trait_def_id = self.trait_def_id;
177+
pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option<LeafDef> {
191178
let mut finalizing_node = None;
192179

193180
self.find_map(|node| {
194-
if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) {
181+
if let Some(item) = node.item(tcx, trait_item_def_id) {
195182
if finalizing_node.is_none() {
196183
let is_specializable = item.defaultness.is_default()
197184
|| tcx.impl_defaultness(node.def_id()).is_default();
@@ -201,7 +188,7 @@ impl<'tcx> Ancestors<'tcx> {
201188
}
202189
}
203190

204-
Some(LeafDef { item, defining_node: node, finalizing_node })
191+
Some(LeafDef { item: *item, defining_node: node, finalizing_node })
205192
} else {
206193
// Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
207194
finalizing_node = Some(node);

compiler/rustc_middle/src/ty/assoc.rs

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ impl AssocItemContainer {
4040
}
4141
}
4242

43+
/// Information about an associated item
4344
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
4445
pub struct AssocItem {
4546
pub def_id: DefId,
@@ -50,6 +51,10 @@ pub struct AssocItem {
5051
pub defaultness: hir::Defaultness,
5152
pub container: AssocItemContainer,
5253

54+
/// If this is an item in an impl of a trait then this is the `DefId` of
55+
/// the associated item on the trait that this implements.
56+
pub trait_item_def_id: Option<DefId>,
57+
5358
/// Whether this is a method with an explicit self
5459
/// as its first parameter, allowing method calls.
5560
pub fn_has_self_parameter: bool,

compiler/rustc_monomorphize/src/collector.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1310,10 +1310,9 @@ fn create_mono_items_for_default_impls<'tcx>(
13101310
if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
13111311
let param_env = ty::ParamEnv::reveal_all();
13121312
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
1313-
let overridden_methods: FxHashSet<_> =
1314-
impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
1313+
let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
13151314
for method in tcx.provided_trait_methods(trait_ref.def_id) {
1316-
if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) {
1315+
if overridden_methods.contains_key(&method.def_id) {
13171316
continue;
13181317
}
13191318

compiler/rustc_passes/src/check_const.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -93,26 +93,29 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
9393
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
9494
{
9595
if let ty::AssocItem {
96-
kind: ty::AssocKind::Fn, ident, defaultness, ..
97-
} = trait_item
96+
kind: ty::AssocKind::Fn,
97+
defaultness,
98+
def_id: trait_item_id,
99+
..
100+
} = *trait_item
98101
{
99102
// we can ignore functions that do not have default bodies:
100103
// if those are unimplemented it will be catched by typeck.
101104
if !defaultness.has_value()
102105
|| self
103106
.tcx
104-
.has_attr(trait_item.def_id, sym::default_method_body_is_const)
107+
.has_attr(trait_item_id, sym::default_method_body_is_const)
105108
{
106109
continue;
107110
}
108111

109112
let is_implemented = ancestors
110-
.leaf_def(self.tcx, trait_item.ident, trait_item.kind)
113+
.leaf_def(self.tcx, trait_item_id)
111114
.map(|node_item| !node_item.defining_node.is_from_trait())
112115
.unwrap_or(false);
113116

114117
if !is_implemented {
115-
to_implement.push(ident.to_string());
118+
to_implement.push(self.tcx.item_name(trait_item_id).to_string());
116119
}
117120
}
118121
}

compiler/rustc_passes/src/stability.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -794,19 +794,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
794794
}
795795
}
796796

797-
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
798-
for impl_item_ref in items {
799-
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
800-
let trait_item_def_id = self
801-
.tcx
802-
.associated_items(trait_did)
803-
.filter_by_name_unhygienic(impl_item.ident.name)
804-
.next()
805-
.map(|item| item.def_id);
806-
if let Some(def_id) = trait_item_def_id {
807-
// Pass `None` to skip deprecation warnings.
808-
self.tcx.check_stability(def_id, None, impl_item.span, None);
809-
}
797+
for impl_item_ref in items {
798+
let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
799+
800+
if let Some(def_id) = impl_item.trait_item_def_id {
801+
// Pass `None` to skip deprecation warnings.
802+
self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
810803
}
811804
}
812805
}

compiler/rustc_save_analysis/src/lib.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -710,13 +710,11 @@ impl<'tcx> SaveContext<'tcx> {
710710
}
711711
Res::Def(HirDefKind::AssocFn, decl_id) => {
712712
let def_id = if decl_id.is_local() {
713-
let ti = self.tcx.associated_item(decl_id);
714-
715-
self.tcx
716-
.associated_items(ti.container.id())
717-
.filter_by_name_unhygienic(ti.ident.name)
718-
.find(|item| item.defaultness.has_value())
719-
.map(|item| item.def_id)
713+
if self.tcx.associated_item(decl_id).defaultness.has_value() {
714+
Some(decl_id)
715+
} else {
716+
None
717+
}
720718
} else {
721719
None
722720
};

compiler/rustc_trait_selection/src/traits/project.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -1883,7 +1883,6 @@ fn assoc_ty_def(
18831883
assoc_ty_def_id: DefId,
18841884
) -> Result<specialization_graph::LeafDef, ErrorReported> {
18851885
let tcx = selcx.tcx();
1886-
let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
18871886
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
18881887
let trait_def = tcx.trait_def(trait_def_id);
18891888

@@ -1893,21 +1892,18 @@ fn assoc_ty_def(
18931892
// for the associated item at the given impl.
18941893
// If there is no such item in that impl, this function will fail with a
18951894
// cycle error if the specialization graph is currently being built.
1896-
let impl_node = specialization_graph::Node::Impl(impl_def_id);
1897-
for item in impl_node.items(tcx) {
1898-
if matches!(item.kind, ty::AssocKind::Type)
1899-
&& tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
1900-
{
1901-
return Ok(specialization_graph::LeafDef {
1902-
item: *item,
1903-
defining_node: impl_node,
1904-
finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
1905-
});
1906-
}
1895+
if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) {
1896+
let item = tcx.associated_item(impl_item_id);
1897+
let impl_node = specialization_graph::Node::Impl(impl_def_id);
1898+
return Ok(specialization_graph::LeafDef {
1899+
item: *item,
1900+
defining_node: impl_node,
1901+
finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
1902+
});
19071903
}
19081904

19091905
let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
1910-
if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
1906+
if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) {
19111907
Ok(assoc_item)
19121908
} else {
19131909
// This is saying that neither the trait nor
@@ -1916,7 +1912,11 @@ fn assoc_ty_def(
19161912
// could only arise through a compiler bug --
19171913
// if the user wrote a bad item name, it
19181914
// should have failed in astconv.
1919-
bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id))
1915+
bug!(
1916+
"No associated type `{}` for {}",
1917+
tcx.item_name(assoc_ty_def_id),
1918+
tcx.def_path_str(impl_def_id)
1919+
)
19201920
}
19211921
}
19221922

0 commit comments

Comments
 (0)