+use hir::def_id::DefId;
+use hir::HirId;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
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",
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::<Vec<_>>().join(", ")
)
};
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<String> {
+ 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;
+ }
}
--- /dev/null
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(future_prelude_collision)]
+#![allow(dead_code)]
+
+mod m {
+ pub trait TryIntoU32 {
+ fn try_into(self) -> Result<u32, ()>;
+ }
+
+ impl TryIntoU32 for u8 {
+ fn try_into(self) -> Result<u32, ()> {
+ 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() {}
--- /dev/null
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(future_prelude_collision)]
+#![allow(dead_code)]
+
+mod m {
+ pub trait TryIntoU32 {
+ fn try_into(self) -> Result<u32, ()>;
+ }
+
+ impl TryIntoU32 for u8 {
+ fn try_into(self) -> Result<u32, ()> {
+ 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() {}