mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Fix future_prelude_collision for object calls and use as _
This commit is contained in:
parent
9bee7f0d0e
commit
b18704dd58
@ -4,7 +4,7 @@ use hir::ItemKind;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{Ref, Ty};
|
||||
use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
|
||||
use rustc_span::symbol::kw::Underscore;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
@ -46,21 +46,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.tcx.struct_span_lint_hir(
|
||||
FUTURE_PRELUDE_COLLISION,
|
||||
call_expr.hir_id,
|
||||
call_expr.span,
|
||||
|lint| {
|
||||
let sp = call_expr.span;
|
||||
let trait_name =
|
||||
self.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container.id());
|
||||
if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
|
||||
// avoid repeatedly adding unneeded `&*`s
|
||||
if pick.autoderefs == 1
|
||||
&& matches!(
|
||||
pick.autoref_or_ptr_adjustment,
|
||||
Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
|
||||
)
|
||||
&& matches!(self_ty.kind(), Ref(..))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Inherent impls only require not relying on autoref and autoderef in order to
|
||||
// ensure that the trait implementation won't be used
|
||||
self.tcx.struct_span_lint_hir(
|
||||
FUTURE_PRELUDE_COLLISION,
|
||||
self_expr.hir_id,
|
||||
self_expr.span,
|
||||
|lint| {
|
||||
let sp = self_expr.span;
|
||||
|
||||
let mut lint = lint.build(&format!(
|
||||
"trait method `{}` will become ambiguous in Rust 2021",
|
||||
segment.ident.name
|
||||
));
|
||||
let mut lint = lint.build(&format!(
|
||||
"trait method `{}` will become ambiguous in Rust 2021",
|
||||
segment.ident.name
|
||||
));
|
||||
|
||||
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
|
||||
let derefs = "*".repeat(pick.autoderefs);
|
||||
|
||||
let autoref = match pick.autoref_or_ptr_adjustment {
|
||||
@ -74,46 +84,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}) => "&",
|
||||
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
|
||||
};
|
||||
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
||||
pick.autoref_or_ptr_adjustment
|
||||
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
|
||||
{
|
||||
format!("{}{} as *const _", derefs, self_expr)
|
||||
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
||||
pick.autoref_or_ptr_adjustment
|
||||
{
|
||||
format!("{}{} as *const _", derefs, self_expr)
|
||||
} else {
|
||||
format!("{}{}{}", autoref, derefs, self_expr)
|
||||
};
|
||||
|
||||
lint.span_suggestion(
|
||||
sp,
|
||||
"disambiguate the method call",
|
||||
format!("({})", self_adjusted),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
format!("{}{}{}", autoref, derefs, self_expr)
|
||||
};
|
||||
let args = args
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|arg| {
|
||||
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
||||
pick.autoref_or_ptr_adjustment
|
||||
{
|
||||
format!("{}(...) as *const _", derefs)
|
||||
} else {
|
||||
format!("{}{}...", autoref, derefs)
|
||||
};
|
||||
lint.span_help(
|
||||
sp,
|
||||
&format!("disambiguate the method call with `({})`", self_adjusted,),
|
||||
);
|
||||
}
|
||||
|
||||
lint.emit();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// trait implementations require full disambiguation to not clash with the new prelude
|
||||
// additions (i.e. convert from dot-call to fully-qualified call)
|
||||
self.tcx.struct_span_lint_hir(
|
||||
FUTURE_PRELUDE_COLLISION,
|
||||
call_expr.hir_id,
|
||||
call_expr.span,
|
||||
|lint| {
|
||||
let sp = call_expr.span;
|
||||
let trait_name = self.trait_path_or_bare_name(
|
||||
span,
|
||||
call_expr.hir_id,
|
||||
pick.item.container.id(),
|
||||
);
|
||||
|
||||
let mut lint = lint.build(&format!(
|
||||
"trait method `{}` will become ambiguous in Rust 2021",
|
||||
segment.ident.name
|
||||
));
|
||||
|
||||
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
|
||||
{
|
||||
let derefs = "*".repeat(pick.autoderefs);
|
||||
|
||||
let autoref = match pick.autoref_or_ptr_adjustment {
|
||||
Some(probe::AutorefOrPtrAdjustment::Autoref {
|
||||
mutbl: Mutability::Mut,
|
||||
..
|
||||
}) => "&mut ",
|
||||
Some(probe::AutorefOrPtrAdjustment::Autoref {
|
||||
mutbl: Mutability::Not,
|
||||
..
|
||||
}) => "&",
|
||||
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
|
||||
};
|
||||
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
||||
pick.autoref_or_ptr_adjustment
|
||||
{
|
||||
format!("{}{} as *const _", derefs, self_expr)
|
||||
} else {
|
||||
format!("{}{}{}", autoref, derefs, self_expr)
|
||||
};
|
||||
let args = args
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|arg| {
|
||||
format!(
|
||||
", {}",
|
||||
self.sess().source_map().span_to_snippet(arg.span).unwrap()
|
||||
)
|
||||
})
|
||||
.collect::<String>();
|
||||
|
||||
lint.span_suggestion(
|
||||
sp,
|
||||
"disambiguate the associated function",
|
||||
format!(
|
||||
", {}",
|
||||
self.sess().source_map().span_to_snippet(arg.span).unwrap()
|
||||
)
|
||||
})
|
||||
.collect::<String>();
|
||||
"{}::{}({}{})",
|
||||
trait_name, segment.ident.name, self_adjusted, args
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
lint.span_help(
|
||||
sp,
|
||||
&format!(
|
||||
"disambiguate the associated function with `{}::{}(...)`",
|
||||
trait_name, segment.ident,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
lint.span_suggestion(
|
||||
sp,
|
||||
"disambiguate the associated function",
|
||||
format!(
|
||||
"{}::{}({}{})",
|
||||
trait_name, segment.ident.name, self_adjusted, args
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
lint.span_help(
|
||||
sp,
|
||||
&format!(
|
||||
"disambiguate the associated function with `{}::{}(...)`",
|
||||
trait_name, segment.ident,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
lint.emit();
|
||||
},
|
||||
);
|
||||
lint.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lint_fully_qualified_call_from_2018(
|
||||
@ -226,11 +305,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
|
||||
// so just take the first one.
|
||||
match import_items[0].kind {
|
||||
ItemKind::Use(path, _) => {
|
||||
// FIXME: serialize path into something readable like a::b, there must be a fn for this
|
||||
debug!("no name for trait, found import of path: {:?}", path);
|
||||
return None;
|
||||
}
|
||||
ItemKind::Use(path, _) => Some(
|
||||
path.segments
|
||||
.iter()
|
||||
.map(|segment| segment.ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("::"),
|
||||
),
|
||||
_ => {
|
||||
span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
// check-pass
|
||||
#![warn(future_prelude_collision)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
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 = TryIntoU32::try_into(3u8).unwrap();
|
||||
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
|
||||
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
}
|
||||
}
|
||||
|
||||
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 = crate::m::TryIntoU32::try_into(3u8).unwrap();
|
||||
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
|
||||
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
}
|
||||
}
|
||||
|
||||
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 = super::m::TryIntoU32::try_into(3u8).unwrap();
|
||||
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
|
||||
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -3,6 +3,7 @@
|
||||
// check-pass
|
||||
#![warn(future_prelude_collision)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod m {
|
||||
pub trait TryIntoU32 {
|
||||
@ -24,6 +25,8 @@ mod a {
|
||||
fn main() {
|
||||
// In this case, we can just use `TryIntoU32`
|
||||
let _: u32 = 3u8.try_into().unwrap();
|
||||
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
|
||||
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +38,8 @@ mod b {
|
||||
// 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();
|
||||
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
|
||||
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +51,8 @@ mod c {
|
||||
// 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();
|
||||
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
|
||||
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
warning: trait method `try_into` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision-imported.rs:27:22
|
||||
|
|
||||
LL | let _: u32 = 3u8.try_into().unwrap();
|
||||
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/future-prelude-collision-imported.rs:4:9
|
||||
|
|
||||
LL | #![warn(future_prelude_collision)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
= note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>
|
||||
|
||||
warning: trait method `try_into` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision-imported.rs:40:22
|
||||
|
|
||||
LL | let _: u32 = 3u8.try_into().unwrap();
|
||||
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `crate::m::TryIntoU32::try_into(3u8)`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
= note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>
|
||||
|
||||
warning: trait method `try_into` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision-imported.rs:53:22
|
||||
|
|
||||
LL | let _: u32 = 3u8.try_into().unwrap();
|
||||
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `super::m::TryIntoU32::try_into(3u8)`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
|
||||
= note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>
|
||||
|
||||
warning: 3 warnings emitted
|
||||
|
33
src/test/ui/rust-2021/future-prelude-collision-shadow.fixed
Normal file
33
src/test/ui/rust-2021/future-prelude-collision-shadow.fixed
Normal file
@ -0,0 +1,33 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
#![warn(future_prelude_collision)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
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 named `try_into` found for type `u8` in the current scope
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,8 +1,8 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
// check-pass
|
||||
#![warn(future_prelude_collision)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod m {
|
||||
pub trait TryIntoU32 {
|
||||
@ -26,7 +26,7 @@ mod d {
|
||||
// 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
|
||||
//~^ ERROR no method named `try_into` found for type `u8` in the current scope
|
||||
}
|
||||
}
|
||||
|
||||
|
40
src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
Normal file
40
src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
Normal file
@ -0,0 +1,40 @@
|
||||
error[E0599]: no method named `try_into` found for type `u8` in the current scope
|
||||
--> $DIR/future-prelude-collision-shadow.rs:28:26
|
||||
|
|
||||
LL | let _: u32 = 3u8.try_into().unwrap();
|
||||
| ^^^^^^^^ method not found in `u8`
|
||||
|
|
||||
::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
||||
|
|
||||
LL | fn try_into(self) -> Result<T, Self::Error>;
|
||||
| --------
|
||||
| |
|
||||
| the method is available for `Box<u8>` here
|
||||
| the method is available for `Pin<u8>` here
|
||||
| the method is available for `Arc<u8>` here
|
||||
| the method is available for `Rc<u8>` here
|
||||
|
|
||||
= help: items from traits can only be used if the trait is in scope
|
||||
= note: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
|
||||
candidate #1: `use crate::m::TryIntoU32;`
|
||||
candidate #2: `use std::convert::TryInto;`
|
||||
help: consider wrapping the receiver expression with the appropriate type
|
||||
|
|
||||
LL | let _: u32 = Box::new(3u8).try_into().unwrap();
|
||||
| ^^^^^^^^^ ^
|
||||
help: consider wrapping the receiver expression with the appropriate type
|
||||
|
|
||||
LL | let _: u32 = Pin::new(3u8).try_into().unwrap();
|
||||
| ^^^^^^^^^ ^
|
||||
help: consider wrapping the receiver expression with the appropriate type
|
||||
|
|
||||
LL | let _: u32 = Arc::new(3u8).try_into().unwrap();
|
||||
| ^^^^^^^^^ ^
|
||||
help: consider wrapping the receiver expression with the appropriate type
|
||||
|
|
||||
LL | let _: u32 = Rc::new(3u8).try_into().unwrap();
|
||||
| ^^^^^^^^ ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in New Issue
Block a user