|
8 | 8 | //! * Functions called by the compiler itself. |
9 | 9 |
|
10 | 10 | use crate::check_attr::target_from_impl_item; |
11 | | -use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; |
| 11 | +use crate::errors::{ |
| 12 | + DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem, |
| 13 | +}; |
12 | 14 | use crate::weak_lang_items; |
13 | 15 |
|
14 | | -use rustc_errors::{pluralize, struct_span_err}; |
15 | 16 | use rustc_hir as hir; |
16 | 17 | use rustc_hir::def::DefKind; |
17 | 18 | use rustc_hir::def_id::DefId; |
18 | 19 | use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS}; |
19 | 20 | use rustc_hir::{HirId, LangItem, LanguageItems, Target}; |
20 | 21 | use rustc_middle::ty::TyCtxt; |
21 | 22 | use rustc_session::cstore::ExternCrate; |
22 | | -use rustc_span::Span; |
| 23 | +use rustc_span::{Span, Symbol}; |
23 | 24 |
|
24 | 25 | use rustc_middle::ty::query::Providers; |
25 | 26 |
|
@@ -62,74 +63,72 @@ impl<'tcx> LanguageItemCollector<'tcx> { |
62 | 63 | // Check for duplicates. |
63 | 64 | if let Some(original_def_id) = self.items.items[item_index] { |
64 | 65 | if original_def_id != item_def_id { |
65 | | - let lang_item = LangItem::from_u32(item_index as u32).unwrap(); |
66 | | - let name = lang_item.name(); |
67 | | - let mut err = match self.tcx.hir().span_if_local(item_def_id) { |
68 | | - Some(span) => struct_span_err!( |
69 | | - self.tcx.sess, |
70 | | - span, |
71 | | - E0152, |
72 | | - "found duplicate lang item `{}`", |
73 | | - name |
74 | | - ), |
75 | | - None => match self.tcx.extern_crate(item_def_id) { |
76 | | - Some(ExternCrate { dependency_of, .. }) => { |
77 | | - self.tcx.sess.struct_err(&format!( |
78 | | - "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.", |
79 | | - self.tcx.crate_name(item_def_id.krate), |
80 | | - self.tcx.crate_name(*dependency_of), |
81 | | - name |
82 | | - )) |
83 | | - } |
84 | | - _ => self.tcx.sess.struct_err(&format!( |
85 | | - "duplicate lang item in crate `{}`: `{}`.", |
86 | | - self.tcx.crate_name(item_def_id.krate), |
87 | | - name |
88 | | - )), |
89 | | - }, |
| 66 | + let local_span = self.tcx.hir().span_if_local(item_def_id); |
| 67 | + let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name(); |
| 68 | + let crate_name = self.tcx.crate_name(item_def_id.krate); |
| 69 | + let mut dependency_of = Symbol::intern(""); |
| 70 | + let is_local = item_def_id.is_local(); |
| 71 | + let path = if is_local { |
| 72 | + String::new() |
| 73 | + } else { |
| 74 | + self.tcx |
| 75 | + .crate_extern_paths(item_def_id.krate) |
| 76 | + .iter() |
| 77 | + .map(|p| p.display().to_string()) |
| 78 | + .collect::<Vec<_>>() |
| 79 | + .join(", ") |
| 80 | + .into() |
90 | 81 | }; |
91 | | - if let Some(span) = self.tcx.hir().span_if_local(original_def_id) { |
92 | | - err.span_note(span, "the lang item is first defined here"); |
| 82 | + let first_defined_span = self.tcx.hir().span_if_local(original_def_id); |
| 83 | + let mut orig_crate_name = Symbol::intern(""); |
| 84 | + let mut orig_dependency_of = Symbol::intern(""); |
| 85 | + let orig_is_local = original_def_id.is_local(); |
| 86 | + let orig_path = if orig_is_local { |
| 87 | + String::new() |
93 | 88 | } else { |
94 | | - match self.tcx.extern_crate(original_def_id) { |
95 | | - Some(ExternCrate { dependency_of, .. }) => { |
96 | | - err.note(&format!( |
97 | | - "the lang item is first defined in crate `{}` (which `{}` depends on)", |
98 | | - self.tcx.crate_name(original_def_id.krate), |
99 | | - self.tcx.crate_name(*dependency_of) |
100 | | - )); |
101 | | - } |
102 | | - _ => { |
103 | | - err.note(&format!( |
104 | | - "the lang item is first defined in crate `{}`.", |
105 | | - self.tcx.crate_name(original_def_id.krate) |
106 | | - )); |
107 | | - } |
| 89 | + self.tcx |
| 90 | + .crate_extern_paths(original_def_id.krate) |
| 91 | + .iter() |
| 92 | + .map(|p| p.display().to_string()) |
| 93 | + .collect::<Vec<_>>() |
| 94 | + .join(", ") |
| 95 | + .into() |
| 96 | + }; |
| 97 | + if first_defined_span.is_none() { |
| 98 | + orig_crate_name = self.tcx.crate_name(original_def_id.krate); |
| 99 | + if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) = |
| 100 | + self.tcx.extern_crate(original_def_id) |
| 101 | + { |
| 102 | + orig_dependency_of = self.tcx.crate_name(*inner_dependency_of); |
108 | 103 | } |
109 | | - let mut note_def = |which, def_id: DefId| { |
110 | | - let crate_name = self.tcx.crate_name(def_id.krate); |
111 | | - let note = if def_id.is_local() { |
112 | | - format!("{} definition in the local crate (`{}`)", which, crate_name) |
113 | | - } else { |
114 | | - let paths: Vec<_> = self |
115 | | - .tcx |
116 | | - .crate_extern_paths(def_id.krate) |
117 | | - .iter() |
118 | | - .map(|p| p.display().to_string()) |
119 | | - .collect(); |
120 | | - format!( |
121 | | - "{} definition in `{}` loaded from {}", |
122 | | - which, |
123 | | - crate_name, |
124 | | - paths.join(", ") |
125 | | - ) |
126 | | - }; |
127 | | - err.note(¬e); |
128 | | - }; |
129 | | - note_def("first", original_def_id); |
130 | | - note_def("second", item_def_id); |
131 | 104 | } |
132 | | - err.emit(); |
| 105 | + |
| 106 | + let message = if local_span.is_some() { |
| 107 | + "duplicate" |
| 108 | + } else { |
| 109 | + match self.tcx.extern_crate(item_def_id) { |
| 110 | + Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => { |
| 111 | + dependency_of = self.tcx.crate_name(*inner_dependency_of); |
| 112 | + "duplicate_in_crate_depends" |
| 113 | + } |
| 114 | + _ => "duplicate_in_crate", |
| 115 | + } |
| 116 | + }; |
| 117 | + |
| 118 | + self.tcx.sess.emit_err(DuplicateLangItem { |
| 119 | + local_span, |
| 120 | + lang_item_name, |
| 121 | + crate_name, |
| 122 | + dependency_of, |
| 123 | + is_local, |
| 124 | + path, |
| 125 | + first_defined_span, |
| 126 | + orig_crate_name, |
| 127 | + orig_dependency_of, |
| 128 | + orig_is_local, |
| 129 | + orig_path, |
| 130 | + message, |
| 131 | + }); |
133 | 132 | } |
134 | 133 | } |
135 | 134 |
|
@@ -162,41 +161,30 @@ impl<'tcx> LanguageItemCollector<'tcx> { |
162 | 161 | None => (0, *item_span), |
163 | 162 | }; |
164 | 163 |
|
| 164 | + let mut at_least = false; |
165 | 165 | let required = match lang_item.required_generics() { |
166 | | - GenericRequirement::Exact(num) if num != actual_num => { |
167 | | - Some((format!("{}", num), pluralize!(num))) |
168 | | - } |
| 166 | + GenericRequirement::Exact(num) if num != actual_num => Some(num), |
169 | 167 | GenericRequirement::Minimum(num) if actual_num < num => { |
170 | | - Some((format!("at least {}", num), pluralize!(num))) |
171 | | - } |
| 168 | + at_least = true; |
| 169 | + Some(num)} |
| 170 | + , |
172 | 171 | // If the number matches, or there is no requirement, handle it normally |
173 | 172 | _ => None, |
174 | 173 | }; |
175 | 174 |
|
176 | | - if let Some((range_str, pluralized)) = required { |
| 175 | + if let Some(num) = required { |
177 | 176 | // We are issuing E0718 "incorrect target" here, because while the |
178 | 177 | // item kind of the target is correct, the target is still wrong |
179 | 178 | // because of the wrong number of generic arguments. |
180 | | - struct_span_err!( |
181 | | - self.tcx.sess, |
| 179 | + self.tcx.sess.emit_err(IncorrectTarget { |
182 | 180 | span, |
183 | | - E0718, |
184 | | - "`{}` language item must be applied to a {} with {} generic argument{}", |
185 | | - name, |
186 | | - kind.descr(), |
187 | | - range_str, |
188 | | - pluralized, |
189 | | - ) |
190 | | - .span_label( |
191 | 181 | generics_span, |
192 | | - format!( |
193 | | - "this {} has {} generic argument{}", |
194 | | - kind.descr(), |
195 | | - actual_num, |
196 | | - pluralize!(actual_num), |
197 | | - ), |
198 | | - ) |
199 | | - .emit(); |
| 182 | + name: name.as_str(), |
| 183 | + kind: kind.descr(), |
| 184 | + num, |
| 185 | + actual_num, |
| 186 | + at_least, |
| 187 | + }); |
200 | 188 |
|
201 | 189 | // return early to not collect the lang item |
202 | 190 | return; |
|
0 commit comments