1 //! Detecting language items.
3 //! Language items are items that represent concepts intrinsic to the language
4 //! itself. Examples are:
6 //! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
7 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
8 //! * Functions called by the compiler itself.
10 use crate::check_attr
::target_from_impl_item
;
11 use crate::weak_lang_items
;
13 use rustc_ast
::Attribute
;
14 use rustc_errors
::{pluralize, struct_span_err}
;
16 use rustc_hir
::def_id
::DefId
;
17 use rustc_hir
::itemlikevisit
::ItemLikeVisitor
;
18 use rustc_hir
::lang_items
::{extract, GenericRequirement, ITEM_REFS}
;
19 use rustc_hir
::{HirId, LangItem, LanguageItems, Target}
;
20 use rustc_middle
::ty
::TyCtxt
;
21 use rustc_session
::cstore
::ExternCrate
;
24 use rustc_middle
::ty
::query
::Providers
;
26 struct LanguageItemCollector
<'tcx
> {
31 impl ItemLikeVisitor
<'v
> for LanguageItemCollector
<'tcx
> {
32 fn visit_item(&mut self, item
: &hir
::Item
<'_
>) {
33 self.check_for_lang(Target
::from_item(item
), item
.hir_id());
35 if let hir
::ItemKind
::Enum(def
, ..) = &item
.kind
{
36 for variant
in def
.variants
{
37 self.check_for_lang(Target
::Variant
, variant
.id
);
42 fn visit_trait_item(&mut self, trait_item
: &hir
::TraitItem
<'_
>) {
43 self.check_for_lang(Target
::from_trait_item(trait_item
), trait_item
.hir_id())
46 fn visit_impl_item(&mut self, impl_item
: &hir
::ImplItem
<'_
>) {
47 self.check_for_lang(target_from_impl_item(self.tcx
, impl_item
), impl_item
.hir_id())
50 fn visit_foreign_item(&mut self, _
: &hir
::ForeignItem
<'_
>) {}
53 impl LanguageItemCollector
<'tcx
> {
54 fn new(tcx
: TyCtxt
<'tcx
>) -> LanguageItemCollector
<'tcx
> {
55 LanguageItemCollector { tcx, items: LanguageItems::new() }
58 fn check_for_lang(&mut self, actual_target
: Target
, hir_id
: HirId
) {
59 let attrs
= self.tcx
.hir().attrs(hir_id
);
60 let check_name
= |attr
: &Attribute
, sym
| attr
.has_name(sym
);
61 if let Some((value
, span
)) = extract(check_name
, &attrs
) {
62 match ITEM_REFS
.get(&value
).cloned() {
63 // Known lang item with attribute on correct target.
64 Some((item_index
, expected_target
)) if actual_target
== expected_target
=> {
65 self.collect_item_extended(item_index
, hir_id
, span
);
67 // Known lang item with attribute on incorrect target.
68 Some((_
, expected_target
)) => {
73 "`{}` language item must be applied to a {}",
80 "attribute should be applied to a {}, not a {}",
81 expected_target
, actual_target
,
92 "definition of an unknown language item: `{}`",
95 .span_label(span
, format
!("definition of unknown language item `{}`", value
))
102 fn collect_item(&mut self, item_index
: usize, item_def_id
: DefId
) {
103 // Check for duplicates.
104 if let Some(original_def_id
) = self.items
.items
[item_index
] {
105 if original_def_id
!= item_def_id
{
106 let lang_item
= LangItem
::from_u32(item_index
as u32).unwrap();
107 let name
= lang_item
.name();
108 let mut err
= match self.tcx
.hir().span_if_local(item_def_id
) {
109 Some(span
) => struct_span_err
!(
113 "found duplicate lang item `{}`",
116 None
=> match self.tcx
.extern_crate(item_def_id
) {
117 Some(ExternCrate { dependency_of, .. }
) => {
118 self.tcx
.sess
.struct_err(&format
!(
119 "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
120 self.tcx
.crate_name(item_def_id
.krate
),
121 self.tcx
.crate_name(*dependency_of
),
125 _
=> self.tcx
.sess
.struct_err(&format
!(
126 "duplicate lang item in crate `{}`: `{}`.",
127 self.tcx
.crate_name(item_def_id
.krate
),
132 if let Some(span
) = self.tcx
.hir().span_if_local(original_def_id
) {
133 err
.span_note(span
, "the lang item is first defined here");
135 match self.tcx
.extern_crate(original_def_id
) {
136 Some(ExternCrate { dependency_of, .. }
) => {
138 "the lang item is first defined in crate `{}` (which `{}` depends on)",
139 self.tcx
.crate_name(original_def_id
.krate
),
140 self.tcx
.crate_name(*dependency_of
)
145 "the lang item is first defined in crate `{}`.",
146 self.tcx
.crate_name(original_def_id
.krate
)
150 let mut note_def
= |which
, def_id
: DefId
| {
151 let crate_name
= self.tcx
.crate_name(def_id
.krate
);
152 let note
= if def_id
.is_local() {
153 format
!("{} definition in the local crate (`{}`)", which
, crate_name
)
155 let paths
: Vec
<_
> = self
157 .crate_extern_paths(def_id
.krate
)
159 .map(|p
| p
.display().to_string())
162 "{} definition in `{}` loaded from {}",
170 note_def("first", original_def_id
);
171 note_def("second", item_def_id
);
178 self.items
.items
[item_index
] = Some(item_def_id
);
179 if let Some(group
) = LangItem
::from_u32(item_index
as u32).unwrap().group() {
180 self.items
.groups
[group
as usize].push(item_def_id
);
184 // Like collect_item() above, but also checks whether the lang item is declared
185 // with the right number of generic arguments.
186 fn collect_item_extended(&mut self, item_index
: usize, hir_id
: HirId
, span
: Span
) {
187 let item_def_id
= self.tcx
.hir().local_def_id(hir_id
).to_def_id();
188 let lang_item
= LangItem
::from_u32(item_index
as u32).unwrap();
189 let name
= lang_item
.name();
191 // Now check whether the lang_item has the expected number of generic
192 // arguments. Generally speaking, binary and indexing operations have
193 // one (for the RHS/index), unary operations have none, the closure
194 // traits have one for the argument list, generators have one for the
195 // resume argument, and ordering/equality relations have one for the RHS
196 // Some other types like Box and various functions like drop_in_place
197 // have minimum requirements.
199 if let hir
::Node
::Item(hir
::Item { kind, span: item_span, .. }
) = self.tcx
.hir().get(hir_id
)
201 let (actual_num
, generics_span
) = match kind
.generics() {
202 Some(generics
) => (generics
.params
.len(), generics
.span
),
203 None
=> (0, *item_span
),
206 let required
= match lang_item
.required_generics() {
207 GenericRequirement
::Exact(num
) if num
!= actual_num
=> {
208 Some((format
!("{}", num
), pluralize
!(num
)))
210 GenericRequirement
::Minimum(num
) if actual_num
< num
=> {
211 Some((format
!("at least {}", num
), pluralize
!(num
)))
213 // If the number matches, or there is no requirement, handle it normally
217 if let Some((range_str
, pluralized
)) = required
{
218 // We are issuing E0718 "incorrect target" here, because while the
219 // item kind of the target is correct, the target is still wrong
220 // because of the wrong number of generic arguments.
225 "`{}` language item must be applied to a {} with {} generic argument{}",
234 "this {} has {} generic argument{}",
237 pluralize
!(actual_num
),
242 // return early to not collect the lang item
247 self.collect_item(item_index
, item_def_id
);
251 /// Traverses and collects all the lang items in all crates.
252 fn get_lang_items(tcx
: TyCtxt
<'_
>, (): ()) -> LanguageItems
{
253 // Initialize the collector.
254 let mut collector
= LanguageItemCollector
::new(tcx
);
256 // Collect lang items in other crates.
257 for &cnum
in tcx
.crates(()).iter() {
258 for &(def_id
, item_index
) in tcx
.defined_lang_items(cnum
).iter() {
259 collector
.collect_item(item_index
, def_id
);
263 // Collect lang items in this crate.
264 tcx
.hir().visit_all_item_likes(&mut collector
);
266 // Extract out the found lang items.
267 let LanguageItemCollector { mut items, .. }
= collector
;
269 // Find all required but not-yet-defined lang items.
270 weak_lang_items
::check_crate(tcx
, &mut items
);
275 pub fn provide(providers
: &mut Providers
) {
276 providers
.get_lang_items
= get_lang_items
;