Auto merge of #85707 - jam1garner:future_prelude_collision_lint, r=nikomatsakis
Add `future_prelude_collision` lint Implements #84594. (RFC rust-lang/rfcs#3114 ([rendered](https://github.com/rust-lang/rfcs/blob/master/text/3114-prelude-2021.md))) Not entirely complete but wanted to have my progress decently available while I finish off the last little bits. Things left to implement: * [x] UI tests for lints * [x] Only emit lint for 2015 and 2018 editions * [ ] Lint name/message bikeshedding * [x] Implement for `FromIterator` (from best I can tell, the current approach as mentioned from [this comment](https://github.com/rust-lang/rust/issues/84594#issuecomment-847288288) won't work due to `FromIterator` instances not using dot-call syntax, but if I'm correct about this then that would also need to be fixed for `TryFrom`/`TryInto`)* * [x] Add to `rust-2021-migration` group? (See #85512) (added to `rust-2021-compatibility` group) * [ ] Link to edition guide in lint docs *edit: looked into it, `lookup_method` will also not be hit for `TryFrom`/`TryInto` for non-dotcall syntax. If anyone who is more familiar with typecheck knows the equivalent for looking up associated functions, feel free to chime in.
This commit is contained in:
commit
44f4a87d70
@ -3001,6 +3001,7 @@ declare_lint_pass! {
|
||||
PROC_MACRO_BACK_COMPAT,
|
||||
OR_PATTERNS_BACK_COMPAT,
|
||||
LARGE_ASSIGNMENTS,
|
||||
FUTURE_PRELUDE_COLLISION,
|
||||
]
|
||||
}
|
||||
|
||||
@ -3244,3 +3245,52 @@ declare_lint! {
|
||||
edition: Some(Edition::Edition2021),
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `future_prelude_collision` lint detects the usage of trait methods which are ambiguous
|
||||
/// with traits added to the prelude in future editions.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(future_prelude_collision)]
|
||||
///
|
||||
/// trait Foo {
|
||||
/// fn try_into(self) -> Result<String, !>;
|
||||
/// }
|
||||
///
|
||||
/// impl Foo for &str {
|
||||
/// fn try_into(self) -> Result<String, !> {
|
||||
/// Ok(String::from(self))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let x: String = "3".try_into().unwrap();
|
||||
/// // ^^^^^^^^
|
||||
/// // This call to try_into matches both Foo:try_into and TryInto::try_into as
|
||||
/// // `TryInto` has been added to the Rust prelude in 2021 edition.
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In Rust 2021, one of the important introductions is the [prelude changes], which add
|
||||
/// `TryFrom`, `TryInto`, and `FromIterator` into the standard library's prelude. Since this
|
||||
/// results in an amiguity as to which method/function to call when an existing `try_into`
|
||||
/// method is called via dot-call syntax or a `try_from`/`from_iter` associated function
|
||||
/// is called directly on a type.
|
||||
///
|
||||
/// [prelude changes]: https://blog.rust-lang.org/inside-rust/2021/03/04/planning-rust-2021.html#prelude-changes
|
||||
pub FUTURE_PRELUDE_COLLISION,
|
||||
Allow,
|
||||
"detects the usage of trait methods which are ambiguous with traits added to the \
|
||||
prelude in future editions",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reference: "issue #85684 <https://github.com/rust-lang/rust/issues/85684>",
|
||||
edition: Some(Edition::Edition2021),
|
||||
};
|
||||
}
|
||||
|
@ -586,6 +586,7 @@ symbols! {
|
||||
from,
|
||||
from_desugaring,
|
||||
from_generator,
|
||||
from_iter,
|
||||
from_method,
|
||||
from_output,
|
||||
from_residual,
|
||||
@ -1238,7 +1239,9 @@ symbols! {
|
||||
truncf32,
|
||||
truncf64,
|
||||
try_blocks,
|
||||
try_from,
|
||||
try_from_trait,
|
||||
try_into,
|
||||
try_into_trait,
|
||||
try_trait_v2,
|
||||
tt,
|
||||
|
@ -466,7 +466,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
|
||||
let (res, opt_ty, segs) =
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
|
||||
let ty = match res {
|
||||
Res::Err => {
|
||||
self.set_tainted_by_errors();
|
||||
@ -940,7 +941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// no need to check for bot/err -- callee does that
|
||||
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
|
||||
|
||||
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
|
||||
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
|
||||
Ok(method) => {
|
||||
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
|
||||
// trigger this codepath causing `structuraly_resolved_type` to emit an error.
|
||||
|
@ -906,13 +906,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
/// Resolves an associated value path into a base type and associated constant, or method
|
||||
/// resolution. The newly resolved definition is written into `type_dependent_defs`.
|
||||
pub fn resolve_ty_and_res_ufcs(
|
||||
pub fn resolve_ty_and_res_fully_qualified_call(
|
||||
&self,
|
||||
qpath: &'tcx QPath<'tcx>,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
|
||||
debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
|
||||
debug!(
|
||||
"resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
|
||||
qpath, hir_id, span
|
||||
);
|
||||
let (ty, qself, item_segment) = match *qpath {
|
||||
QPath::Resolved(ref opt_qself, ref path) => {
|
||||
return (
|
||||
@ -922,7 +925,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
|
||||
QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
|
||||
QPath::LangItem(..) => {
|
||||
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
|
||||
}
|
||||
};
|
||||
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
|
||||
{
|
||||
@ -932,25 +937,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return (def, Some(ty), slice::from_ref(&**item_segment));
|
||||
}
|
||||
let item_name = item_segment.ident;
|
||||
let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
|
||||
let result = match error {
|
||||
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
|
||||
_ => Err(ErrorReported),
|
||||
};
|
||||
if item_name.name != kw::Empty {
|
||||
if let Some(mut e) = self.report_method_error(
|
||||
span,
|
||||
ty,
|
||||
item_name,
|
||||
SelfSource::QPath(qself),
|
||||
error,
|
||||
None,
|
||||
) {
|
||||
e.emit();
|
||||
let result = self
|
||||
.resolve_fully_qualified_call(span, item_name, ty, qself.span, hir_id)
|
||||
.or_else(|error| {
|
||||
let result = match error {
|
||||
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
|
||||
_ => Err(ErrorReported),
|
||||
};
|
||||
if item_name.name != kw::Empty {
|
||||
if let Some(mut e) = self.report_method_error(
|
||||
span,
|
||||
ty,
|
||||
item_name,
|
||||
SelfSource::QPath(qself),
|
||||
error,
|
||||
None,
|
||||
) {
|
||||
e.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
});
|
||||
result
|
||||
});
|
||||
|
||||
if result.is_ok() {
|
||||
self.maybe_lint_bare_trait(qpath, hir_id);
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
|
||||
|
||||
mod confirm;
|
||||
mod prelude2021;
|
||||
pub mod probe;
|
||||
mod suggest;
|
||||
|
||||
@ -173,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// Given a method call like `foo.bar::<T1,...Tn>(...)`:
|
||||
/// Given a method call like `foo.bar::<T1,...Tn>(a, b + 1, ...)`:
|
||||
///
|
||||
/// * `self`: the surrounding `FnCtxt` (!)
|
||||
/// * `self_ty`: the (unadjusted) type of the self expression (`foo`)
|
||||
@ -181,6 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// * `span`: the span for the method call
|
||||
/// * `call_expr`: the complete method call: (`foo.bar::<T1,...Tn>(...)`)
|
||||
/// * `self_expr`: the self expression (`foo`)
|
||||
/// * `args`: the expressions of the arguments (`a, b + 1, ...`)
|
||||
#[instrument(level = "debug", skip(self, call_expr, self_expr))]
|
||||
pub fn lookup_method(
|
||||
&self,
|
||||
@ -189,6 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span: Span,
|
||||
call_expr: &'tcx hir::Expr<'tcx>,
|
||||
self_expr: &'tcx hir::Expr<'tcx>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
|
||||
debug!(
|
||||
"lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
|
||||
@ -198,6 +201,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let pick =
|
||||
self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
|
||||
|
||||
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
|
||||
|
||||
for import_id in &pick.import_ids {
|
||||
debug!("used_trait_import: {:?}", import_id);
|
||||
Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports)
|
||||
@ -417,16 +422,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Some(InferOk { obligations, value: callee })
|
||||
}
|
||||
|
||||
/// Performs a [full-qualified function call] (formerly "universal function call") lookup. If
|
||||
/// lookup is successful, it will return the type of definition and the [`DefId`] of the found
|
||||
/// function definition.
|
||||
///
|
||||
/// [full-qualified function call]: https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// Given a function call like `Foo::bar::<T1,...Tn>(...)`:
|
||||
///
|
||||
/// * `self`: the surrounding `FnCtxt` (!)
|
||||
/// * `span`: the span of the call, excluding arguments (`Foo::bar::<T1, ...Tn>`)
|
||||
/// * `method_name`: the identifier of the function within the container type (`bar`)
|
||||
/// * `self_ty`: the type to search within (`Foo`)
|
||||
/// * `self_ty_span` the span for the type being searched within (span of `Foo`)
|
||||
/// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn resolve_ufcs(
|
||||
pub fn resolve_fully_qualified_call(
|
||||
&self,
|
||||
span: Span,
|
||||
method_name: Ident,
|
||||
self_ty: Ty<'tcx>,
|
||||
self_ty_span: Span,
|
||||
expr_id: hir::HirId,
|
||||
) -> Result<(DefKind, DefId), MethodError<'tcx>> {
|
||||
debug!(
|
||||
"resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
|
||||
"resolve_fully_qualified_call: method_name={:?} self_ty={:?} expr_id={:?}",
|
||||
method_name, self_ty, expr_id,
|
||||
);
|
||||
|
||||
@ -463,18 +485,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expr_id,
|
||||
ProbeScope::TraitsInScope,
|
||||
)?;
|
||||
debug!("resolve_ufcs: pick={:?}", pick);
|
||||
|
||||
self.lint_fully_qualified_call_from_2018(
|
||||
span,
|
||||
method_name,
|
||||
self_ty,
|
||||
self_ty_span,
|
||||
expr_id,
|
||||
&pick,
|
||||
);
|
||||
|
||||
debug!("resolve_fully_qualified_call: pick={:?}", pick);
|
||||
{
|
||||
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||
let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
|
||||
for import_id in pick.import_ids {
|
||||
debug!("resolve_ufcs: used_trait_import: {:?}", import_id);
|
||||
debug!("resolve_fully_qualified_call: used_trait_import: {:?}", import_id);
|
||||
used_trait_imports.insert(import_id);
|
||||
}
|
||||
}
|
||||
|
||||
let def_kind = pick.item.kind.as_def_kind();
|
||||
debug!("resolve_ufcs: def_kind={:?}, def_id={:?}", def_kind, pick.item.def_id);
|
||||
debug!(
|
||||
"resolve_fully_qualified_call: def_kind={:?}, def_id={:?}",
|
||||
def_kind, pick.item.def_id
|
||||
);
|
||||
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
|
||||
Ok((def_kind, pick.item.def_id))
|
||||
}
|
||||
|
330
compiler/rustc_typeck/src/check/method/prelude2021.rs
Normal file
330
compiler/rustc_typeck/src/check/method/prelude2021.rs
Normal file
@ -0,0 +1,330 @@
|
||||
use hir::def_id::DefId;
|
||||
use hir::HirId;
|
||||
use hir::ItemKind;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
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};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::check::{
|
||||
method::probe::{self, Pick},
|
||||
FnCtxt,
|
||||
};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(super) fn lint_dot_call_from_2018(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
segment: &hir::PathSegment<'_>,
|
||||
span: Span,
|
||||
call_expr: &'tcx hir::Expr<'tcx>,
|
||||
self_expr: &'tcx hir::Expr<'tcx>,
|
||||
pick: &Pick<'tcx>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
) {
|
||||
debug!(
|
||||
"lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
|
||||
segment.ident, self_ty, call_expr, self_expr
|
||||
);
|
||||
|
||||
// Rust 2021 and later is already using the new prelude
|
||||
if span.rust_2021() {
|
||||
return;
|
||||
}
|
||||
|
||||
// These are the method names that were added to prelude in Rust 2021
|
||||
if !matches!(segment.ident.name, sym::try_into) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to lint if method came from std/core, as that will now be in the prelude
|
||||
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 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 => "",
|
||||
};
|
||||
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
|
||||
{
|
||||
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 {
|
||||
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
|
||||
));
|
||||
|
||||
let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
|
||||
if precise {
|
||||
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!(
|
||||
"{}::{}({}{})",
|
||||
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();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lint_fully_qualified_call_from_2018(
|
||||
&self,
|
||||
span: Span,
|
||||
method_name: Ident,
|
||||
self_ty: Ty<'tcx>,
|
||||
self_ty_span: Span,
|
||||
expr_id: hir::HirId,
|
||||
pick: &Pick<'tcx>,
|
||||
) {
|
||||
// Rust 2021 and later is already using the new prelude
|
||||
if span.rust_2021() {
|
||||
return;
|
||||
}
|
||||
|
||||
// These are the fully qualified methods added to prelude in Rust 2021
|
||||
if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to lint if method came from std/core, as that will now be in the prelude
|
||||
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
|
||||
// since such methods take precedence over trait methods.
|
||||
if matches!(pick.kind, probe::PickKind::InherentImplPick) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
|
||||
let trait_generics = self.tcx.generics_of(pick.item.container.id());
|
||||
|
||||
let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
|
||||
let trait_name = if parameter_count == 0 {
|
||||
trait_path
|
||||
} else {
|
||||
format!(
|
||||
"{}<{}>",
|
||||
trait_path,
|
||||
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
};
|
||||
|
||||
let mut lint = lint.build(&format!(
|
||||
"trait-associated function `{}` will become ambiguous in Rust 2021",
|
||||
method_name.name
|
||||
));
|
||||
|
||||
let self_ty = self
|
||||
.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(self_ty_span)
|
||||
.unwrap_or_else(|_| self_ty.to_string());
|
||||
|
||||
lint.span_suggestion(
|
||||
span,
|
||||
"disambiguate the associated function",
|
||||
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
lint.emit();
|
||||
});
|
||||
}
|
||||
|
||||
fn trait_path_or_bare_name(
|
||||
&self,
|
||||
span: Span,
|
||||
expr_hir_id: HirId,
|
||||
trait_def_id: DefId,
|
||||
) -> String {
|
||||
self.trait_path(span, 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, span: Span, 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;
|
||||
}
|
||||
|
||||
let import_items: Vec<_> = applicable_trait
|
||||
.import_ids
|
||||
.iter()
|
||||
.map(|&import_id| {
|
||||
let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
|
||||
self.tcx.hir().expect_item(hir_id)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Find an identifier with which this trait was imported (note that `_` doesn't count).
|
||||
let any_id = import_items
|
||||
.iter()
|
||||
.filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
|
||||
.next();
|
||||
if let Some(any_id) = any_id {
|
||||
return Some(format!("{}", any_id));
|
||||
}
|
||||
|
||||
// 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, _) => 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a string version of the `expr` that includes explicit adjustments.
|
||||
/// Returns the string and also a bool indicating whther this is a *precise*
|
||||
/// suggestion.
|
||||
fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
|
||||
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 (expr_text, precise) =
|
||||
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
|
||||
(expr_text, true)
|
||||
} else {
|
||||
(format!("(..)"), false)
|
||||
};
|
||||
|
||||
let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
||||
pick.autoref_or_ptr_adjustment
|
||||
{
|
||||
format!("{}{} as *const _", derefs, expr_text)
|
||||
} else {
|
||||
format!("{}{}{}", autoref, derefs, expr_text)
|
||||
};
|
||||
|
||||
(adjusted_text, precise)
|
||||
}
|
||||
}
|
@ -160,7 +160,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ti: TopInfo<'tcx>,
|
||||
) {
|
||||
let path_res = match &pat.kind {
|
||||
PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)),
|
||||
PatKind::Path(qpath) => {
|
||||
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||
@ -904,7 +906,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
// Resolve the path and check the definition for errors.
|
||||
let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span);
|
||||
let (res, opt_ty, segments) =
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
|
||||
if res == Res::Err {
|
||||
self.set_tainted_by_errors();
|
||||
on_error();
|
||||
|
@ -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() {}
|
59
src/test/ui/rust-2021/future-prelude-collision-imported.rs
Normal file
59
src/test/ui/rust-2021/future-prelude-collision-imported.rs
Normal file
@ -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 = 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!
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
//~^ 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 = 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!
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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
|
||||
|
32
src/test/ui/rust-2021/future-prelude-collision-shadow.rs
Normal file
32
src/test/ui/rust-2021/future-prelude-collision-shadow.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// 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() {}
|
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:27: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`.
|
96
src/test/ui/rust-2021/future-prelude-collision.fixed
Normal file
96
src/test/ui/rust-2021/future-prelude-collision.fixed
Normal file
@ -0,0 +1,96 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
// check-pass
|
||||
#![warn(future_prelude_collision)]
|
||||
|
||||
trait TryIntoU32 {
|
||||
fn try_into(self) -> Result<u32, ()>;
|
||||
}
|
||||
|
||||
impl TryIntoU32 for u8 {
|
||||
fn try_into(self) -> Result<u32, ()> {
|
||||
Ok(self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
// needed for autoref test
|
||||
impl TryIntoU32 for &f32 {
|
||||
fn try_into(self) -> Result<u32, ()> {
|
||||
Ok(*self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
trait TryFromU8: Sized {
|
||||
fn try_from(x: u8) -> Result<Self, ()>;
|
||||
}
|
||||
|
||||
impl TryFromU8 for u32 {
|
||||
fn try_from(x: u8) -> Result<Self, ()> {
|
||||
Ok(x as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoU32 for *const u16 {
|
||||
fn try_into(self) -> Result<u32, ()> {
|
||||
Ok(unsafe { *self } as u32)
|
||||
}
|
||||
}
|
||||
|
||||
trait FromByteIterator {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where T: Iterator<Item = u8>;
|
||||
}
|
||||
|
||||
impl FromByteIterator for Vec<u8> {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where T: Iterator<Item = u8>
|
||||
{
|
||||
iter.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// test dot-call that will break in 2021 edition
|
||||
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!
|
||||
|
||||
// test associated function call that will break in 2021 edition
|
||||
let _ = <u32 as TryFromU8>::try_from(3u8).unwrap();
|
||||
//~^ WARNING trait-associated function `try_from` 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!
|
||||
|
||||
// test reverse turbofish too
|
||||
let _ = <Vec<u8> as FromByteIterator>::from_iter(vec![1u8, 2, 3, 4, 5, 6].into_iter());
|
||||
//~^ WARNING trait-associated function `from_iter` 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!
|
||||
|
||||
// negative testing lint (this line should *not* emit a warning)
|
||||
let _: u32 = TryFromU8::try_from(3u8).unwrap();
|
||||
|
||||
// test type omission
|
||||
let _: u32 = <_ as TryFromU8>::try_from(3u8).unwrap();
|
||||
//~^ WARNING trait-associated function `try_from` 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!
|
||||
|
||||
// test autoderef
|
||||
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!
|
||||
|
||||
// test autoref
|
||||
let _: u32 = TryIntoU32::try_into(&3.0).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!
|
||||
|
||||
let mut data = 3u16;
|
||||
let mut_ptr = std::ptr::addr_of_mut!(data);
|
||||
let _: u32 = TryIntoU32::try_into(mut_ptr as *const _).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!
|
||||
|
||||
type U32Alias = u32;
|
||||
let _ = <U32Alias as TryFromU8>::try_from(3u8).unwrap();
|
||||
//~^ WARNING trait-associated function `try_from` 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!
|
||||
}
|
96
src/test/ui/rust-2021/future-prelude-collision.rs
Normal file
96
src/test/ui/rust-2021/future-prelude-collision.rs
Normal file
@ -0,0 +1,96 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
// check-pass
|
||||
#![warn(future_prelude_collision)]
|
||||
|
||||
trait TryIntoU32 {
|
||||
fn try_into(self) -> Result<u32, ()>;
|
||||
}
|
||||
|
||||
impl TryIntoU32 for u8 {
|
||||
fn try_into(self) -> Result<u32, ()> {
|
||||
Ok(self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
// needed for autoref test
|
||||
impl TryIntoU32 for &f32 {
|
||||
fn try_into(self) -> Result<u32, ()> {
|
||||
Ok(*self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
trait TryFromU8: Sized {
|
||||
fn try_from(x: u8) -> Result<Self, ()>;
|
||||
}
|
||||
|
||||
impl TryFromU8 for u32 {
|
||||
fn try_from(x: u8) -> Result<Self, ()> {
|
||||
Ok(x as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoU32 for *const u16 {
|
||||
fn try_into(self) -> Result<u32, ()> {
|
||||
Ok(unsafe { *self } as u32)
|
||||
}
|
||||
}
|
||||
|
||||
trait FromByteIterator {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where T: Iterator<Item = u8>;
|
||||
}
|
||||
|
||||
impl FromByteIterator for Vec<u8> {
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where T: Iterator<Item = u8>
|
||||
{
|
||||
iter.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// test dot-call that will break in 2021 edition
|
||||
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!
|
||||
|
||||
// test associated function call that will break in 2021 edition
|
||||
let _ = u32::try_from(3u8).unwrap();
|
||||
//~^ WARNING trait-associated function `try_from` 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!
|
||||
|
||||
// test reverse turbofish too
|
||||
let _ = <Vec<u8>>::from_iter(vec![1u8, 2, 3, 4, 5, 6].into_iter());
|
||||
//~^ WARNING trait-associated function `from_iter` 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!
|
||||
|
||||
// negative testing lint (this line should *not* emit a warning)
|
||||
let _: u32 = TryFromU8::try_from(3u8).unwrap();
|
||||
|
||||
// test type omission
|
||||
let _: u32 = <_>::try_from(3u8).unwrap();
|
||||
//~^ WARNING trait-associated function `try_from` 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!
|
||||
|
||||
// test autoderef
|
||||
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!
|
||||
|
||||
// test autoref
|
||||
let _: u32 = 3.0.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!
|
||||
|
||||
let mut data = 3u16;
|
||||
let mut_ptr = std::ptr::addr_of_mut!(data);
|
||||
let _: u32 = mut_ptr.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!
|
||||
|
||||
type U32Alias = u32;
|
||||
let _ = U32Alias::try_from(3u8).unwrap();
|
||||
//~^ WARNING trait-associated function `try_from` 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!
|
||||
}
|
79
src/test/ui/rust-2021/future-prelude-collision.stderr
Normal file
79
src/test/ui/rust-2021/future-prelude-collision.stderr
Normal file
@ -0,0 +1,79 @@
|
||||
warning: trait method `try_into` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision.rs:54:18
|
||||
|
|
||||
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.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-associated function `try_from` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision.rs:59:13
|
||||
|
|
||||
LL | let _ = u32::try_from(3u8).unwrap();
|
||||
| ^^^^^^^^^^^^^ help: disambiguate the associated function: `<u32 as TryFromU8>::try_from`
|
||||
|
|
||||
= 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-associated function `from_iter` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision.rs:64:13
|
||||
|
|
||||
LL | let _ = <Vec<u8>>::from_iter(vec![1u8, 2, 3, 4, 5, 6].into_iter());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Vec<u8> as FromByteIterator>::from_iter`
|
||||
|
|
||||
= 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-associated function `try_from` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision.rs:72:18
|
||||
|
|
||||
LL | let _: u32 = <_>::try_from(3u8).unwrap();
|
||||
| ^^^^^^^^^^^^^ help: disambiguate the associated function: `<_ as TryFromU8>::try_from`
|
||||
|
|
||||
= 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.rs:77:18
|
||||
|
|
||||
LL | let _: u32 = (&3u8).try_into().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `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.rs:82:18
|
||||
|
|
||||
LL | let _: u32 = 3.0.try_into().unwrap();
|
||||
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(&3.0)`
|
||||
|
|
||||
= 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.rs:88:18
|
||||
|
|
||||
LL | let _: u32 = mut_ptr.try_into().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(mut_ptr as *const _)`
|
||||
|
|
||||
= 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-associated function `try_from` will become ambiguous in Rust 2021
|
||||
--> $DIR/future-prelude-collision.rs:93:13
|
||||
|
|
||||
LL | let _ = U32Alias::try_from(3u8).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<U32Alias as TryFromU8>::try_from`
|
||||
|
|
||||
= 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: 8 warnings emitted
|
||||
|
18
src/test/ui/rust-2021/generic-type-collision.fixed
Normal file
18
src/test/ui/rust-2021/generic-type-collision.fixed
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
// run-rustfix
|
||||
// edition 2018
|
||||
#![warn(future_prelude_collision)]
|
||||
|
||||
trait MyTrait<A> {
|
||||
fn from_iter(x: Option<A>);
|
||||
}
|
||||
|
||||
impl<T> MyTrait<()> for Vec<T> {
|
||||
fn from_iter(_: Option<()>) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
<Vec<i32> as MyTrait<_>>::from_iter(None);
|
||||
//~^ WARNING trait-associated function `from_iter` 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!
|
||||
}
|
18
src/test/ui/rust-2021/generic-type-collision.rs
Normal file
18
src/test/ui/rust-2021/generic-type-collision.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
// run-rustfix
|
||||
// edition 2018
|
||||
#![warn(future_prelude_collision)]
|
||||
|
||||
trait MyTrait<A> {
|
||||
fn from_iter(x: Option<A>);
|
||||
}
|
||||
|
||||
impl<T> MyTrait<()> for Vec<T> {
|
||||
fn from_iter(_: Option<()>) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
<Vec<i32>>::from_iter(None);
|
||||
//~^ WARNING trait-associated function `from_iter` 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!
|
||||
}
|
16
src/test/ui/rust-2021/generic-type-collision.stderr
Normal file
16
src/test/ui/rust-2021/generic-type-collision.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
warning: trait-associated function `from_iter` will become ambiguous in Rust 2021
|
||||
--> $DIR/generic-type-collision.rs:15:5
|
||||
|
|
||||
LL | <Vec<i32>>::from_iter(None);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Vec<i32> as MyTrait<_>>::from_iter`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/generic-type-collision.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: 1 warning emitted
|
||||
|
53
src/test/ui/rust-2021/inherent-dyn-collision.fixed
Normal file
53
src/test/ui/rust-2021/inherent-dyn-collision.fixed
Normal file
@ -0,0 +1,53 @@
|
||||
// Test case where the method we want is an inherent method on a
|
||||
// dyn Trait. In that case, the fix is to insert `*` on the receiver.
|
||||
//
|
||||
// check-pass
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
|
||||
#![warn(future_prelude_collision)]
|
||||
|
||||
trait TryIntoU32 {
|
||||
fn try_into(&self) -> Result<u32, ()>;
|
||||
}
|
||||
|
||||
impl TryIntoU32 for u8 {
|
||||
// note: &self
|
||||
fn try_into(&self) -> Result<u32, ()> {
|
||||
Ok(22)
|
||||
}
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use super::get_dyn_trait;
|
||||
|
||||
// note: this does nothing, but is copying from ffishim's problem of
|
||||
// having a struct of the same name as the trait in-scope, while *also*
|
||||
// implementing the trait for that struct but **without** importing the
|
||||
// trait itself into scope
|
||||
struct TryIntoU32;
|
||||
|
||||
impl super::TryIntoU32 for TryIntoU32 {
|
||||
fn try_into(&self) -> Result<u32, ()> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
// this is where the gross part happens. since `get_dyn_trait` returns
|
||||
// a Box<dyn Trait>, it can still call the method for `dyn Trait` without
|
||||
// `Trait` being in-scope. it might even be possible to make the trait itself
|
||||
// entirely unreference-able from the callsite?
|
||||
pub fn test() -> u32 {
|
||||
(&*get_dyn_trait()).try_into().unwrap()
|
||||
//~^ WARNING trait method `try_into` will become ambiguous
|
||||
//~| WARNING this was previously accepted
|
||||
}
|
||||
}
|
||||
|
||||
fn get_dyn_trait() -> Box<dyn TryIntoU32> {
|
||||
Box::new(3u8) as Box<dyn TryIntoU32>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
dbg!(inner::test());
|
||||
}
|
53
src/test/ui/rust-2021/inherent-dyn-collision.rs
Normal file
53
src/test/ui/rust-2021/inherent-dyn-collision.rs
Normal file
@ -0,0 +1,53 @@
|
||||
// Test case where the method we want is an inherent method on a
|
||||
// dyn Trait. In that case, the fix is to insert `*` on the receiver.
|
||||
//
|
||||
// check-pass
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
|
||||
#![warn(future_prelude_collision)]
|
||||
|
||||
trait TryIntoU32 {
|
||||
fn try_into(&self) -> Result<u32, ()>;
|
||||
}
|
||||
|
||||
impl TryIntoU32 for u8 {
|
||||
// note: &self
|
||||
fn try_into(&self) -> Result<u32, ()> {
|
||||
Ok(22)
|
||||
}
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use super::get_dyn_trait;
|
||||
|
||||
// note: this does nothing, but is copying from ffishim's problem of
|
||||
// having a struct of the same name as the trait in-scope, while *also*
|
||||
// implementing the trait for that struct but **without** importing the
|
||||
// trait itself into scope
|
||||
struct TryIntoU32;
|
||||
|
||||
impl super::TryIntoU32 for TryIntoU32 {
|
||||
fn try_into(&self) -> Result<u32, ()> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
// this is where the gross part happens. since `get_dyn_trait` returns
|
||||
// a Box<dyn Trait>, it can still call the method for `dyn Trait` without
|
||||
// `Trait` being in-scope. it might even be possible to make the trait itself
|
||||
// entirely unreference-able from the callsite?
|
||||
pub fn test() -> u32 {
|
||||
get_dyn_trait().try_into().unwrap()
|
||||
//~^ WARNING trait method `try_into` will become ambiguous
|
||||
//~| WARNING this was previously accepted
|
||||
}
|
||||
}
|
||||
|
||||
fn get_dyn_trait() -> Box<dyn TryIntoU32> {
|
||||
Box::new(3u8) as Box<dyn TryIntoU32>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
dbg!(inner::test());
|
||||
}
|
16
src/test/ui/rust-2021/inherent-dyn-collision.stderr
Normal file
16
src/test/ui/rust-2021/inherent-dyn-collision.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
warning: trait method `try_into` will become ambiguous in Rust 2021
|
||||
--> $DIR/inherent-dyn-collision.rs:41:9
|
||||
|
|
||||
LL | get_dyn_trait().try_into().unwrap()
|
||||
| ^^^^^^^^^^^^^^^ help: disambiguate the method call: `(&*get_dyn_trait())`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/inherent-dyn-collision.rs:8: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: 1 warning emitted
|
||||
|
15
src/test/ui/rust-2021/inherent-method-collision.rs
Normal file
15
src/test/ui/rust-2021/inherent-method-collision.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Test that we do NOT warn for inherent methods invoked via `T::` form.
|
||||
//
|
||||
// check-pass
|
||||
|
||||
#![deny(future_prelude_collision)]
|
||||
|
||||
pub struct MySeq {}
|
||||
|
||||
impl MySeq {
|
||||
pub fn from_iter(_: impl IntoIterator<Item = u32>) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
MySeq::from_iter(Some(22));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user