WIP: Find the imports that were used to reach a method
And add tests for some corner cases we have to consider.
This commit is contained in:
parent
56108f67b1
commit
dbc9da7962
3 changed files with 118 additions and 6 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use hir::def_id::DefId;
|
||||||
|
use hir::HirId;
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -48,7 +50,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
call_expr.span,
|
call_expr.span,
|
||||||
|lint| {
|
|lint| {
|
||||||
let sp = call_expr.span;
|
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!(
|
let mut lint = lint.build(&format!(
|
||||||
"trait method `{}` will become ambiguous in Rust 2021",
|
"trait method `{}` will become ambiguous in Rust 2021",
|
||||||
|
@ -144,16 +147,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
|
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
|
// "type" refers to either a type or, more likely, a trait from which
|
||||||
// the associated function or method is from.
|
// the associated function or method is from.
|
||||||
let type_name = self.tcx.def_path_str(pick.item.container.id());
|
let trait_path = self.trait_path_or_bare_name(expr_id, pick.item.container.id());
|
||||||
let type_generics = self.tcx.generics_of(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 {
|
let trait_name = if parameter_count == 0 {
|
||||||
type_name
|
trait_path
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"{}<{}>",
|
"{}<{}>",
|
||||||
type_name,
|
trait_path,
|
||||||
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
|
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -179,4 +182,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
lint.emit();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
52
src/test/ui/rust-2021/future-prelude-collision-imported.rs
Normal file
52
src/test/ui/rust-2021/future-prelude-collision-imported.rs
Normal file
|
@ -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<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() {}
|
33
src/test/ui/rust-2021/future-prelude-collision-shadow.rs
Normal file
33
src/test/ui/rust-2021/future-prelude-collision-shadow.rs
Normal file
|
@ -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<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() {}
|
Loading…
Add table
Add a link
Reference in a new issue