Add trait_item_def_id to AssocItem

This allows avoiding some lookups by name
This commit is contained in:
Matthew Jasper 2021-11-18 21:35:42 +00:00 committed by Noah Lev
parent 0b1ab91d66
commit d7595853a2
11 changed files with 197 additions and 204 deletions

View file

@ -1008,6 +1008,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
self.get_impl_data(id).constness
}
fn get_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> {
self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
}
fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
self.get_impl_data(id).coerce_unsized_info
}
@ -1289,6 +1293,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
vis: self.get_visibility(id),
defaultness: container.defaultness(),
def_id: self.local_def_id(id),
trait_item_def_id: self.get_trait_item_def_id(id),
container: container.with_def_id(parent),
fn_has_self_parameter: has_self,
}

View file

@ -1294,6 +1294,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
self.encode_ident_span(def_id, impl_item.ident);
self.encode_item_type(def_id);
if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
}
if impl_item.kind == ty::AssocKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
}

View file

@ -302,6 +302,7 @@ define_tables! {
ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
variances: Table<DefIndex, Lazy<[ty::Variance]>>,
generics: Table<DefIndex, Lazy<ty::Generics>>,

View file

@ -40,6 +40,7 @@ impl AssocItemContainer {
}
}
/// Information about an associated item
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
pub struct AssocItem {
pub def_id: DefId,
@ -50,6 +51,10 @@ pub struct AssocItem {
pub defaultness: hir::Defaultness,
pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements.
pub trait_item_def_id: Option<DefId>,
/// Whether this is a method with an explicit self
/// as its first parameter, allowing method calls.
pub fn_has_self_parameter: bool,

View file

@ -794,19 +794,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
}
}
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
for impl_item_ref in items {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
let trait_item_def_id = self
.tcx
.associated_items(trait_did)
.filter_by_name_unhygienic(impl_item.ident.name)
.next()
.map(|item| item.def_id);
if let Some(def_id) = trait_item_def_id {
// Pass `None` to skip deprecation warnings.
self.tcx.check_stability(def_id, None, impl_item.span, None);
}
for impl_item_ref in items {
let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
if let Some(def_id) = impl_item.trait_item_def_id {
// Pass `None` to skip deprecation warnings.
self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
}
}
}

View file

@ -710,13 +710,11 @@ impl<'tcx> SaveContext<'tcx> {
}
Res::Def(HirDefKind::AssocFn, decl_id) => {
let def_id = if decl_id.is_local() {
let ti = self.tcx.associated_item(decl_id);
self.tcx
.associated_items(ti.container.id())
.filter_by_name_unhygienic(ti.ident.name)
.find(|item| item.defaultness.has_value())
.map(|item| item.def_id)
if self.tcx.associated_item(decl_id).defaultness.has_value() {
Some(decl_id)
} else {
None
}
} else {
None
};

View file

@ -436,23 +436,13 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
let def_id = associated_ty_id.0;
let assoc_item = self.interner.tcx.associated_item(def_id);
let (impl_id, trait_id) = match assoc_item.container {
AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
AssocItemContainer::ImplContainer(def_id) => {
(def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
}
};
let impl_id = assoc_item.container.id();
match assoc_item.kind {
AssocKind::Type => {}
_ => unimplemented!("Not possible??"),
}
let trait_item = self
.interner
.tcx
.associated_items(trait_id)
.find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
.unwrap();
let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version");
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
let binders = binders_for(self.interner, bound_vars);
let ty = self
@ -464,7 +454,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
impl_id: chalk_ir::ImplId(impl_id),
associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
associated_ty_id: chalk_ir::AssocTypeId(trait_item_id),
value: chalk_ir::Binders::new(
binders,
chalk_solve::rust_ir::AssociatedTyValueBound { ty },

View file

@ -1,8 +1,11 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
use rustc_middle::ty::{
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::{sym, Span};
use rustc_trait_selection::traits;
@ -89,6 +92,7 @@ fn associated_item_from_trait_item_ref(
vis: tcx.visibility(def_id),
defaultness: trait_item_ref.defaultness,
def_id: def_id.to_def_id(),
trait_item_def_id: Some(def_id.to_def_id()),
container: ty::TraitContainer(parent_def_id.to_def_id()),
fn_has_self_parameter: has_self,
}
@ -106,17 +110,119 @@ fn associated_item_from_impl_item_ref(
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
};
let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
ty::AssocItem {
ident: impl_item_ref.ident,
kind,
vis: tcx.visibility(def_id),
defaultness: impl_item_ref.defaultness,
def_id: def_id.to_def_id(),
trait_item_def_id,
container: ty::ImplContainer(parent_def_id.to_def_id()),
fn_has_self_parameter: has_self,
}
}
fn impl_item_base_id<'tcx>(
tcx: TyCtxt<'tcx>,
parent_def_id: LocalDefId,
impl_item: &hir::ImplItemRef,
) -> Option<DefId> {
let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
// If the trait reference itself is erroneous (so the compilation is going
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
// isn't populated for such impls.
if impl_trait_ref.references_error() {
return None;
}
// Locate trait items
let associated_items = tcx.associated_items(impl_trait_ref.def_id);
// Match item against trait
let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
let mut trait_item = items.next()?;
let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
(ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
(ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
(ty::AssocKind::Type, hir::AssocItemKind::Type) => true,
_ => false,
};
// If we don't have a compatible item, we'll use the first one whose name matches
// to report an error.
let mut compatible_kind = is_compatible(&trait_item);
if !compatible_kind {
if let Some(ty_trait_item) = items.find(is_compatible) {
compatible_kind = true;
trait_item = ty_trait_item;
}
}
if compatible_kind {
Some(trait_item.def_id)
} else {
report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
None
}
}
#[inline(never)]
#[cold]
fn report_mismatch_error<'tcx>(
tcx: TyCtxt<'tcx>,
trait_item_def_id: DefId,
impl_trait_ref: ty::TraitRef<'tcx>,
impl_item: &hir::ImplItemRef,
) {
let mut err = match impl_item.kind {
hir::AssocItemKind::Const => {
// Find associated const definition.
struct_span_err!(
tcx.sess,
impl_item.span,
E0323,
"item `{}` is an associated const, which doesn't match its trait `{}`",
impl_item.ident,
impl_trait_ref.print_only_trait_path()
)
}
hir::AssocItemKind::Fn { .. } => {
struct_span_err!(
tcx.sess,
impl_item.span,
E0324,
"item `{}` is an associated method, which doesn't match its trait `{}`",
impl_item.ident,
impl_trait_ref.print_only_trait_path()
)
}
hir::AssocItemKind::Type => {
struct_span_err!(
tcx.sess,
impl_item.span,
E0325,
"item `{}` is an associated type, which doesn't match its trait `{}`",
impl_item.ident,
impl_trait_ref.print_only_trait_path()
)
}
};
err.span_label(impl_item.span, "does not match trait");
if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
err.span_label(trait_span, "item in trait");
}
err.emit();
}
fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let parent_id = tcx.hir().get_parent_item(id);

View file

@ -841,14 +841,8 @@ pub(super) fn check_specialization_validity<'tcx>(
trait_def: &ty::TraitDef,
trait_item: &ty::AssocItem,
impl_id: DefId,
impl_item: &hir::ImplItem<'_>,
impl_item: &hir::ImplItemRef,
) {
let kind = match impl_item.kind {
hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
};
let ancestors = match trait_def.ancestors(tcx, impl_id) {
Ok(ancestors) => ancestors,
Err(_) => return,
@ -857,7 +851,7 @@ pub(super) fn check_specialization_validity<'tcx>(
if parent.is_from_trait() {
None
} else {
Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
Some((parent, parent.item(tcx, trait_item.def_id)))
}
});
@ -894,7 +888,7 @@ pub(super) fn check_specialization_validity<'tcx>(
}
}
pub(super) fn check_impl_items_against_trait<'tcx>(
fn check_impl_items_against_trait<'tcx>(
tcx: TyCtxt<'tcx>,
full_impl_span: Span,
impl_id: LocalDefId,
@ -926,174 +920,81 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
}
}
// Locate trait definition and items
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
let associated_items = tcx.associated_items(impl_trait_ref.def_id);
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
for impl_item in impl_items {
let ty_impl_item = tcx.associated_item(impl_item.def_id);
let mut items =
associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
(ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
(ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
(ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
_ => false,
};
// If we don't have a compatible item, we'll use the first one whose name matches
// to report an error.
let mut compatible_kind = is_compatible(&ty_trait_item);
let mut trait_item = ty_trait_item;
if !compatible_kind {
if let Some(ty_trait_item) = items.find(is_compatible) {
compatible_kind = true;
trait_item = ty_trait_item;
}
}
(compatible_kind, trait_item)
for impl_item in impl_item_refs {
let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
tcx.associated_item(trait_item_id)
} else {
// Checked in `associated_item`.
tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
continue;
};
if compatible_kind {
match impl_item.kind {
hir::ImplItemKind::Const(..) => {
// Find associated const definition.
compare_const_impl(
tcx,
&ty_impl_item,
impl_item.span,
&ty_trait_item,
impl_trait_ref,
);
}
hir::ImplItemKind::Fn(..) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_impl_method(
tcx,
&ty_impl_item,
impl_item.span,
&ty_trait_item,
impl_trait_ref,
opt_trait_span,
);
}
hir::ImplItemKind::TyAlias(impl_ty) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_ty_impl(
tcx,
&ty_impl_item,
impl_ty.span,
&ty_trait_item,
impl_trait_ref,
opt_trait_span,
);
}
match impl_item.kind {
hir::AssocItemKind::Const => {
// Find associated const definition.
compare_const_impl(
tcx,
&ty_impl_item,
impl_item.span,
&ty_trait_item,
impl_trait_ref,
);
}
hir::AssocItemKind::Fn { .. } => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_impl_method(
tcx,
&ty_impl_item,
impl_item.span,
&ty_trait_item,
impl_trait_ref,
opt_trait_span,
);
}
hir::AssocItemKind::Type => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_ty_impl(
tcx,
&ty_impl_item,
impl_item.span,
&ty_trait_item,
impl_trait_ref,
opt_trait_span,
);
}
check_specialization_validity(
tcx,
trait_def,
&ty_trait_item,
impl_id.to_def_id(),
impl_item,
);
} else {
report_mismatch_error(
tcx,
ty_trait_item.def_id,
impl_trait_ref,
impl_item,
&ty_impl_item,
);
}
check_specialization_validity(
tcx,
trait_def,
&ty_trait_item,
impl_id.to_def_id(),
impl_item,
);
}
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
// Check for missing items from trait
let mut missing_items = Vec::new();
for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
let is_implemented = ancestors
.leaf_def(tcx, trait_item.ident, trait_item.kind)
.map(|node_item| !node_item.defining_node.is_from_trait())
.unwrap_or(false);
.leaf_def(tcx, trait_item_id)
.map_or(false, |node_item| node_item.item.defaultness.has_value());
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
if !trait_item.defaultness.has_value() {
missing_items.push(*trait_item);
}
missing_items.push(tcx.associated_item(trait_item_id));
}
}
if !missing_items.is_empty() {
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
}
}
}
#[inline(never)]
#[cold]
fn report_mismatch_error<'tcx>(
tcx: TyCtxt<'tcx>,
trait_item_def_id: DefId,
impl_trait_ref: ty::TraitRef<'tcx>,
impl_item: &hir::ImplItem<'_>,
ty_impl_item: &ty::AssocItem,
) {
let mut err = match impl_item.kind {
hir::ImplItemKind::Const(..) => {
// Find associated const definition.
struct_span_err!(
tcx.sess,
impl_item.span,
E0323,
"item `{}` is an associated const, which doesn't match its trait `{}`",
ty_impl_item.ident,
impl_trait_ref.print_only_trait_path()
)
}
hir::ImplItemKind::Fn(..) => {
struct_span_err!(
tcx.sess,
impl_item.span,
E0324,
"item `{}` is an associated method, which doesn't match its trait `{}`",
ty_impl_item.ident,
impl_trait_ref.print_only_trait_path()
)
}
hir::ImplItemKind::TyAlias(_) => {
struct_span_err!(
tcx.sess,
impl_item.span,
E0325,
"item `{}` is an associated type, which doesn't match its trait `{}`",
ty_impl_item.ident,
impl_trait_ref.print_only_trait_path()
)
}
};
err.span_label(impl_item.span, "does not match trait");
if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
err.span_label(trait_span, "item in trait");
}
err.emit();
}
/// Checks whether a type can be represented in memory. In particular, it
/// identifies types that contain themselves without indirection through a
/// pointer, which would mean their size is unbounded.

View file

@ -566,7 +566,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
fn report_forbidden_specialization(
tcx: TyCtxt<'_>,
impl_item: &hir::ImplItem<'_>,
impl_item: &hir::ImplItemRef,
parent_impl: DefId,
) {
let mut err = struct_span_err!(
@ -598,7 +598,7 @@ fn report_forbidden_specialization(
fn missing_items_err(
tcx: TyCtxt<'_>,
impl_span: Span,
missing_items: &[ty::AssocItem],
missing_items: &[&ty::AssocItem],
full_impl_span: Span,
) {
let missing_items_msg = missing_items

View file

@ -3150,21 +3150,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(impl_item) = tcx.opt_associated_item(def_id) {
if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
if let Some(trait_item) = tcx
.associated_items(trait_def_id)
.filter_by_name_unhygienic(impl_item.ident.name)
.find(move |trait_item| {
trait_item.kind == ty::AssocKind::Fn
&& tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
})
{
return tcx
.codegen_fn_attrs(trait_item.def_id)
.flags
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
}
if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container {
if let Some(trait_item) = impl_item.trait_item_def_id {
return tcx
.codegen_fn_attrs(trait_item)
.flags
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
}
}
}