|
1 | 1 | use hir::def_id::DefId;
|
2 | 2 | use hir::HirId;
|
| 3 | +use hir::ItemKind; |
3 | 4 | use rustc_ast::Mutability;
|
4 | 5 | use rustc_errors::Applicability;
|
5 | 6 | use rustc_hir as hir;
|
6 | 7 | use rustc_middle::ty::Ty;
|
7 | 8 | use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
|
| 9 | +use rustc_span::symbol::kw::Underscore; |
8 | 10 | use rustc_span::symbol::{sym, Ident};
|
9 | 11 | use rustc_span::Span;
|
10 | 12 |
|
@@ -51,7 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
51 | 53 | |lint| {
|
52 | 54 | let sp = call_expr.span;
|
53 | 55 | let trait_name =
|
54 |
| - self.trait_path_or_bare_name(call_expr.hir_id, pick.item.container.id()); |
| 56 | + self.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container.id()); |
55 | 57 |
|
56 | 58 | let mut lint = lint.build(&format!(
|
57 | 59 | "trait method `{}` will become ambiguous in Rust 2021",
|
@@ -147,7 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
147 | 149 | self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
|
148 | 150 | // "type" refers to either a type or, more likely, a trait from which
|
149 | 151 | // the associated function or method is from.
|
150 |
| - let trait_path = self.trait_path_or_bare_name(expr_id, pick.item.container.id()); |
| 152 | + let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id()); |
151 | 153 | let trait_generics = self.tcx.generics_of(pick.item.container.id());
|
152 | 154 |
|
153 | 155 | let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
|
@@ -183,27 +185,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
183 | 185 | });
|
184 | 186 | }
|
185 | 187 |
|
186 |
| - fn trait_path_or_bare_name(&self, expr_hir_id: HirId, trait_def_id: DefId) -> String { |
187 |
| - self.trait_path(expr_hir_id, trait_def_id).unwrap_or_else(|| { |
| 188 | + fn trait_path_or_bare_name( |
| 189 | + &self, |
| 190 | + span: Span, |
| 191 | + expr_hir_id: HirId, |
| 192 | + trait_def_id: DefId, |
| 193 | + ) -> String { |
| 194 | + self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| { |
188 | 195 | let key = self.tcx.def_key(trait_def_id);
|
189 | 196 | format!("{}", key.disambiguated_data.data)
|
190 | 197 | })
|
191 | 198 | }
|
192 | 199 |
|
193 |
| - fn trait_path(&self, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> { |
| 200 | + fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> { |
194 | 201 | let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
|
195 | 202 | let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
|
196 | 203 | if applicable_trait.import_ids.is_empty() {
|
197 | 204 | // The trait was declared within the module, we only need to use its name.
|
198 | 205 | return None;
|
199 | 206 | }
|
200 | 207 |
|
201 |
| - for &import_id in &applicable_trait.import_ids { |
202 |
| - let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id); |
203 |
| - let item = self.tcx.hir().expect_item(hir_id); |
204 |
| - debug!(?item, ?import_id, "import_id"); |
| 208 | + let import_items: Vec<_> = applicable_trait |
| 209 | + .import_ids |
| 210 | + .iter() |
| 211 | + .map(|&import_id| { |
| 212 | + let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id); |
| 213 | + self.tcx.hir().expect_item(hir_id) |
| 214 | + }) |
| 215 | + .collect(); |
| 216 | + |
| 217 | + // Find an identifier with which this trait was imported (note that `_` doesn't count). |
| 218 | + let any_id = import_items |
| 219 | + .iter() |
| 220 | + .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None }) |
| 221 | + .next(); |
| 222 | + if let Some(any_id) = any_id { |
| 223 | + return Some(format!("{}", any_id)); |
205 | 224 | }
|
206 | 225 |
|
207 |
| - return None; |
| 226 | + // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick, |
| 227 | + // so just take the first one. |
| 228 | + match import_items[0].kind { |
| 229 | + ItemKind::Use(path, _) => { |
| 230 | + // FIXME: serialize path into something readable like a::b, there must be a fn for this |
| 231 | + debug!("no name for trait, found import of path: {:?}", path); |
| 232 | + return None; |
| 233 | + } |
| 234 | + _ => { |
| 235 | + span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind); |
| 236 | + } |
| 237 | + } |
208 | 238 | }
|
209 | 239 | }
|
0 commit comments