Skip to content

Commit 1b057a3

Browse files
matthewjaspercamelid
authored andcommitted
Move associated_item* providers to their own module
1 parent d759585 commit 1b057a3

File tree

3 files changed

+234
-225
lines changed

3 files changed

+234
-225
lines changed

compiler/rustc_ty_utils/src/assoc.rs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
use rustc_errors::struct_span_err;
2+
use rustc_hir as hir;
3+
use rustc_hir::def_id::{DefId, LocalDefId};
4+
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
5+
6+
pub fn provide(providers: &mut ty::query::Providers) {
7+
*providers = ty::query::Providers {
8+
associated_item,
9+
associated_item_def_ids,
10+
associated_items,
11+
trait_of_item,
12+
..*providers
13+
};
14+
}
15+
16+
fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
17+
let item = tcx.hir().expect_item(def_id.expect_local());
18+
match item.kind {
19+
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
20+
trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
21+
),
22+
hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
23+
impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
24+
),
25+
hir::ItemKind::TraitAlias(..) => &[],
26+
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
27+
}
28+
}
29+
30+
fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
31+
let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
32+
ty::AssocItems::new(items)
33+
}
34+
35+
/// If the given `DefId` describes an item belonging to a trait,
36+
/// returns the `DefId` of the trait that the trait item belongs to;
37+
/// otherwise, returns `None`.
38+
fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
39+
tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
40+
ty::TraitContainer(def_id) => Some(def_id),
41+
ty::ImplContainer(_) => None,
42+
})
43+
}
44+
45+
fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
46+
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
47+
let parent_id = tcx.hir().get_parent_item(id);
48+
let parent_def_id = tcx.hir().local_def_id(parent_id);
49+
let parent_item = tcx.hir().expect_item(parent_def_id);
50+
match parent_item.kind {
51+
hir::ItemKind::Impl(ref impl_) => {
52+
if let Some(impl_item_ref) =
53+
impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
54+
{
55+
let assoc_item =
56+
associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
57+
debug_assert_eq!(assoc_item.def_id, def_id);
58+
return assoc_item;
59+
}
60+
}
61+
62+
hir::ItemKind::Trait(.., ref trait_item_refs) => {
63+
if let Some(trait_item_ref) =
64+
trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
65+
{
66+
let assoc_item =
67+
associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
68+
debug_assert_eq!(assoc_item.def_id, def_id);
69+
return assoc_item;
70+
}
71+
}
72+
73+
_ => {}
74+
}
75+
76+
span_bug!(
77+
parent_item.span,
78+
"unexpected parent of trait or impl item or item not found: {:?}",
79+
parent_item.kind
80+
)
81+
}
82+
83+
fn associated_item_from_trait_item_ref(
84+
tcx: TyCtxt<'_>,
85+
parent_def_id: LocalDefId,
86+
trait_item_ref: &hir::TraitItemRef,
87+
) -> ty::AssocItem {
88+
let def_id = trait_item_ref.id.def_id;
89+
let (kind, has_self) = match trait_item_ref.kind {
90+
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
91+
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
92+
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
93+
};
94+
95+
ty::AssocItem {
96+
ident: trait_item_ref.ident,
97+
kind,
98+
vis: tcx.visibility(def_id),
99+
defaultness: trait_item_ref.defaultness,
100+
def_id: def_id.to_def_id(),
101+
trait_item_def_id: Some(def_id.to_def_id()),
102+
container: ty::TraitContainer(parent_def_id.to_def_id()),
103+
fn_has_self_parameter: has_self,
104+
}
105+
}
106+
107+
fn associated_item_from_impl_item_ref(
108+
tcx: TyCtxt<'_>,
109+
parent_def_id: LocalDefId,
110+
impl_item_ref: &hir::ImplItemRef,
111+
) -> ty::AssocItem {
112+
let def_id = impl_item_ref.id.def_id;
113+
let (kind, has_self) = match impl_item_ref.kind {
114+
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
115+
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
116+
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
117+
};
118+
119+
let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
120+
121+
ty::AssocItem {
122+
ident: impl_item_ref.ident,
123+
kind,
124+
vis: tcx.visibility(def_id),
125+
defaultness: impl_item_ref.defaultness,
126+
def_id: def_id.to_def_id(),
127+
trait_item_def_id,
128+
container: ty::ImplContainer(parent_def_id.to_def_id()),
129+
fn_has_self_parameter: has_self,
130+
}
131+
}
132+
133+
fn impl_item_base_id<'tcx>(
134+
tcx: TyCtxt<'tcx>,
135+
parent_def_id: LocalDefId,
136+
impl_item: &hir::ImplItemRef,
137+
) -> Option<DefId> {
138+
let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
139+
140+
// If the trait reference itself is erroneous (so the compilation is going
141+
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
142+
// isn't populated for such impls.
143+
if impl_trait_ref.references_error() {
144+
return None;
145+
}
146+
147+
// Locate trait items
148+
let associated_items = tcx.associated_items(impl_trait_ref.def_id);
149+
150+
// Match item against trait
151+
let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
152+
153+
let mut trait_item = items.next()?;
154+
155+
let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
156+
(ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
157+
(ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
158+
(ty::AssocKind::Type, hir::AssocItemKind::Type) => true,
159+
_ => false,
160+
};
161+
162+
// If we don't have a compatible item, we'll use the first one whose name matches
163+
// to report an error.
164+
let mut compatible_kind = is_compatible(&trait_item);
165+
166+
if !compatible_kind {
167+
if let Some(ty_trait_item) = items.find(is_compatible) {
168+
compatible_kind = true;
169+
trait_item = ty_trait_item;
170+
}
171+
}
172+
173+
if compatible_kind {
174+
Some(trait_item.def_id)
175+
} else {
176+
report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
177+
None
178+
}
179+
}
180+
181+
#[inline(never)]
182+
#[cold]
183+
fn report_mismatch_error<'tcx>(
184+
tcx: TyCtxt<'tcx>,
185+
trait_item_def_id: DefId,
186+
impl_trait_ref: ty::TraitRef<'tcx>,
187+
impl_item: &hir::ImplItemRef,
188+
) {
189+
let mut err = match impl_item.kind {
190+
hir::AssocItemKind::Const => {
191+
// Find associated const definition.
192+
struct_span_err!(
193+
tcx.sess,
194+
impl_item.span,
195+
E0323,
196+
"item `{}` is an associated const, which doesn't match its trait `{}`",
197+
impl_item.ident,
198+
impl_trait_ref.print_only_trait_path()
199+
)
200+
}
201+
202+
hir::AssocItemKind::Fn { .. } => {
203+
struct_span_err!(
204+
tcx.sess,
205+
impl_item.span,
206+
E0324,
207+
"item `{}` is an associated method, which doesn't match its trait `{}`",
208+
impl_item.ident,
209+
impl_trait_ref.print_only_trait_path()
210+
)
211+
}
212+
213+
hir::AssocItemKind::Type => {
214+
struct_span_err!(
215+
tcx.sess,
216+
impl_item.span,
217+
E0325,
218+
"item `{}` is an associated type, which doesn't match its trait `{}`",
219+
impl_item.ident,
220+
impl_trait_ref.print_only_trait_path()
221+
)
222+
}
223+
};
224+
225+
err.span_label(impl_item.span, "does not match trait");
226+
if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
227+
err.span_label(trait_span, "item in trait");
228+
}
229+
err.emit();
230+
}

compiler/rustc_ty_utils/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ extern crate tracing;
1616

1717
use rustc_middle::ty::query::Providers;
1818

19+
mod assoc;
1920
mod common_traits;
2021
pub mod instance;
2122
mod needs_drop;
2223
pub mod representability;
2324
mod ty;
2425

2526
pub fn provide(providers: &mut Providers) {
27+
assoc::provide(providers);
2628
common_traits::provide(providers);
2729
needs_drop::provide(providers);
2830
ty::provide(providers);

0 commit comments

Comments
 (0)