From: Niko Matsakis Date: Thu, 17 Jun 2021 10:10:38 +0000 (-0400) Subject: WIP: Find the imports that were used to reach a method X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=dbc9da7962b7282c5752a7bc2c9907694b7c158c;p=rust.git WIP: Find the imports that were used to reach a method And add tests for some corner cases we have to consider. --- diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index b7e41525bde..987ec032476 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -1,3 +1,5 @@ +use hir::def_id::DefId; +use hir::HirId; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir as hir; @@ -48,7 +50,8 @@ pub(super) fn lint_dot_call_from_2018( call_expr.span, |lint| { let sp = call_expr.span; - let trait_name = self.tcx.def_path_str(pick.item.container.id()); + let trait_name = + self.trait_path_or_bare_name(call_expr.hir_id, pick.item.container.id()); let mut lint = lint.build(&format!( "trait method `{}` will become ambiguous in Rust 2021", @@ -144,16 +147,16 @@ pub(super) fn lint_fully_qualified_call_from_2018( self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| { // "type" refers to either a type or, more likely, a trait from which // the associated function or method is from. - let type_name = self.tcx.def_path_str(pick.item.container.id()); - let type_generics = self.tcx.generics_of(pick.item.container.id()); + let trait_path = self.trait_path_or_bare_name(expr_id, pick.item.container.id()); + let trait_generics = self.tcx.generics_of(pick.item.container.id()); - let parameter_count = type_generics.count() - (type_generics.has_self as usize); + let parameter_count = trait_generics.count() - (trait_generics.has_self as usize); let trait_name = if parameter_count == 0 { - type_name + trait_path } else { format!( "{}<{}>", - type_name, + trait_path, std::iter::repeat("_").take(parameter_count).collect::>().join(", ") ) }; @@ -179,4 +182,28 @@ pub(super) fn lint_fully_qualified_call_from_2018( lint.emit(); }); } + + fn trait_path_or_bare_name(&self, expr_hir_id: HirId, trait_def_id: DefId) -> String { + self.trait_path(expr_hir_id, trait_def_id).unwrap_or_else(|| { + let key = self.tcx.def_key(trait_def_id); + format!("{}", key.disambiguated_data.data) + }) + } + + fn trait_path(&self, expr_hir_id: HirId, trait_def_id: DefId) -> Option { + let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?; + let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?; + if applicable_trait.import_ids.is_empty() { + // The trait was declared within the module, we only need to use its name. + return None; + } + + for &import_id in &applicable_trait.import_ids { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id); + let item = self.tcx.hir().expect_item(hir_id); + debug!(?item, ?import_id, "import_id"); + } + + return None; + } } diff --git a/src/test/ui/rust-2021/future-prelude-collision-imported.rs b/src/test/ui/rust-2021/future-prelude-collision-imported.rs new file mode 100644 index 00000000000..e85a0bd725d --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-imported.rs @@ -0,0 +1,52 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(future_prelude_collision)] +#![allow(dead_code)] + +mod m { + pub trait TryIntoU32 { + fn try_into(self) -> Result; + } + + impl TryIntoU32 for u8 { + fn try_into(self) -> Result { + Ok(self as u32) + } + } + + pub trait AnotherTrick {} +} + +mod a { + use crate::m::TryIntoU32; + + fn main() { + // In this case, we can just use `TryIntoU32` + let _: u32 = 3u8.try_into().unwrap(); + } +} + +mod b { + use crate::m::AnotherTrick as TryIntoU32; + use crate::m::TryIntoU32 as _; + + fn main() { + // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use + // the path `crate::m::TryIntoU32` (with which it was imported). + let _: u32 = 3u8.try_into().unwrap(); + } +} + +mod c { + use super::m::TryIntoU32 as _; + use crate::m::AnotherTrick as TryIntoU32; + + fn main() { + // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use + // the path `super::m::TryIntoU32` (with which it was imported). + let _: u32 = 3u8.try_into().unwrap(); + } +} + +fn main() {} diff --git a/src/test/ui/rust-2021/future-prelude-collision-shadow.rs b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs new file mode 100644 index 00000000000..ef19cf4d1e6 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs @@ -0,0 +1,33 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(future_prelude_collision)] +#![allow(dead_code)] + +mod m { + pub trait TryIntoU32 { + fn try_into(self) -> Result; + } + + impl TryIntoU32 for u8 { + fn try_into(self) -> Result { + Ok(self as u32) + } + } + + pub trait AnotherTrick {} +} + +mod d { + use crate::m::AnotherTrick as TryIntoU32; + use crate::m::*; + + fn main() { + // Here, `TryIntoU32` is imported but shadowed, but in that case we don't permit its methods + // to be available. + let _: u32 = 3u8.try_into().unwrap(); + //~^ ERROR no method name `try_into` found + } +} + +fn main() {}