Skip to content

Commit d759585

Browse files
matthewjaspercamelid
authored andcommitted
Add trait_item_def_id to AssocItem
This allows avoiding some lookups by name
1 parent 0b1ab91 commit d759585

File tree

11 files changed

+197
-204
lines changed

11 files changed

+197
-204
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 5 additions & 0 deletions
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
}
@@ -1289,6 +1293,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
12891293
vis: self.get_visibility(id),
12901294
defaultness: container.defaultness(),
12911295
def_id: self.local_def_id(id),
1296+
trait_item_def_id: self.get_trait_item_def_id(id),
12921297
container: container.with_def_id(parent),
12931298
fn_has_self_parameter: has_self,
12941299
}

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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/ty/assoc.rs

Lines changed: 5 additions & 0 deletions
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_passes/src/stability.rs

Lines changed: 6 additions & 13 deletions
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

Lines changed: 5 additions & 7 deletions
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_traits/src/chalk/db.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -436,23 +436,13 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
436436
) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
437437
let def_id = associated_ty_id.0;
438438
let assoc_item = self.interner.tcx.associated_item(def_id);
439-
let (impl_id, trait_id) = match assoc_item.container {
440-
AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
441-
AssocItemContainer::ImplContainer(def_id) => {
442-
(def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
443-
}
444-
};
439+
let impl_id = assoc_item.container.id();
445440
match assoc_item.kind {
446441
AssocKind::Type => {}
447442
_ => unimplemented!("Not possible??"),
448443
}
449444

450-
let trait_item = self
451-
.interner
452-
.tcx
453-
.associated_items(trait_id)
454-
.find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
455-
.unwrap();
445+
let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version");
456446
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
457447
let binders = binders_for(self.interner, bound_vars);
458448
let ty = self
@@ -464,7 +454,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
464454

465455
Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
466456
impl_id: chalk_ir::ImplId(impl_id),
467-
associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
457+
associated_ty_id: chalk_ir::AssocTypeId(trait_item_id),
468458
value: chalk_ir::Binders::new(
469459
binders,
470460
chalk_solve::rust_ir::AssociatedTyValueBound { ty },

compiler/rustc_ty_utils/src/ty.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use rustc_data_structures::fx::FxIndexSet;
2+
use rustc_errors::struct_span_err;
23
use rustc_hir as hir;
34
use rustc_hir::def_id::{DefId, LocalDefId};
45
use rustc_middle::ty::subst::Subst;
5-
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
6+
use rustc_middle::ty::{
7+
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
8+
};
69
use rustc_span::{sym, Span};
710
use rustc_trait_selection::traits;
811

@@ -89,6 +92,7 @@ fn associated_item_from_trait_item_ref(
8992
vis: tcx.visibility(def_id),
9093
defaultness: trait_item_ref.defaultness,
9194
def_id: def_id.to_def_id(),
95+
trait_item_def_id: Some(def_id.to_def_id()),
9296
container: ty::TraitContainer(parent_def_id.to_def_id()),
9397
fn_has_self_parameter: has_self,
9498
}
@@ -106,17 +110,119 @@ fn associated_item_from_impl_item_ref(
106110
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
107111
};
108112

113+
let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
114+
109115
ty::AssocItem {
110116
ident: impl_item_ref.ident,
111117
kind,
112118
vis: tcx.visibility(def_id),
113119
defaultness: impl_item_ref.defaultness,
114120
def_id: def_id.to_def_id(),
121+
trait_item_def_id,
115122
container: ty::ImplContainer(parent_def_id.to_def_id()),
116123
fn_has_self_parameter: has_self,
117124
}
118125
}
119126

127+
fn impl_item_base_id<'tcx>(
128+
tcx: TyCtxt<'tcx>,
129+
parent_def_id: LocalDefId,
130+
impl_item: &hir::ImplItemRef,
131+
) -> Option<DefId> {
132+
let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
133+
134+
// If the trait reference itself is erroneous (so the compilation is going
135+
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
136+
// isn't populated for such impls.
137+
if impl_trait_ref.references_error() {
138+
return None;
139+
}
140+
141+
// Locate trait items
142+
let associated_items = tcx.associated_items(impl_trait_ref.def_id);
143+
144+
// Match item against trait
145+
let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
146+
147+
let mut trait_item = items.next()?;
148+
149+
let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
150+
(ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
151+
(ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
152+
(ty::AssocKind::Type, hir::AssocItemKind::Type) => true,
153+
_ => false,
154+
};
155+
156+
// If we don't have a compatible item, we'll use the first one whose name matches
157+
// to report an error.
158+
let mut compatible_kind = is_compatible(&trait_item);
159+
160+
if !compatible_kind {
161+
if let Some(ty_trait_item) = items.find(is_compatible) {
162+
compatible_kind = true;
163+
trait_item = ty_trait_item;
164+
}
165+
}
166+
167+
if compatible_kind {
168+
Some(trait_item.def_id)
169+
} else {
170+
report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
171+
None
172+
}
173+
}
174+
175+
#[inline(never)]
176+
#[cold]
177+
fn report_mismatch_error<'tcx>(
178+
tcx: TyCtxt<'tcx>,
179+
trait_item_def_id: DefId,
180+
impl_trait_ref: ty::TraitRef<'tcx>,
181+
impl_item: &hir::ImplItemRef,
182+
) {
183+
let mut err = match impl_item.kind {
184+
hir::AssocItemKind::Const => {
185+
// Find associated const definition.
186+
struct_span_err!(
187+
tcx.sess,
188+
impl_item.span,
189+
E0323,
190+
"item `{}` is an associated const, which doesn't match its trait `{}`",
191+
impl_item.ident,
192+
impl_trait_ref.print_only_trait_path()
193+
)
194+
}
195+
196+
hir::AssocItemKind::Fn { .. } => {
197+
struct_span_err!(
198+
tcx.sess,
199+
impl_item.span,
200+
E0324,
201+
"item `{}` is an associated method, which doesn't match its trait `{}`",
202+
impl_item.ident,
203+
impl_trait_ref.print_only_trait_path()
204+
)
205+
}
206+
207+
hir::AssocItemKind::Type => {
208+
struct_span_err!(
209+
tcx.sess,
210+
impl_item.span,
211+
E0325,
212+
"item `{}` is an associated type, which doesn't match its trait `{}`",
213+
impl_item.ident,
214+
impl_trait_ref.print_only_trait_path()
215+
)
216+
}
217+
};
218+
219+
err.span_label(impl_item.span, "does not match trait");
220+
if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
221+
err.span_label(trait_span, "item in trait");
222+
}
223+
err.emit();
224+
}
225+
120226
fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
121227
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
122228
let parent_id = tcx.hir().get_parent_item(id);

0 commit comments

Comments
 (0)