about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-22 07:01:54 +0000
committerbors <bors@rust-lang.org>2021-06-22 07:01:54 +0000
commit44f4a87d7047db0deff5ef033fd2af820722e9a5 (patch)
tree4960627de594af7fc920104a8f40245e480485e9
parentc38111c4fb9c22a36f9a9195d1884052bb670af2 (diff)
parentaa3580baa6f5ef69aba41a63297fb659bcd4b793 (diff)
downloadrust-44f4a87d7047db0deff5ef033fd2af820722e9a5.tar.gz
rust-44f4a87d7047db0deff5ef033fd2af820722e9a5.zip
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.
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs50
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs5
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs49
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs47
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs330
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs7
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-imported.fixed59
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-imported.rs59
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-imported.stderr34
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-shadow.rs32
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-shadow.stderr40
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision.fixed96
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision.rs96
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision.stderr79
-rw-r--r--src/test/ui/rust-2021/generic-type-collision.fixed18
-rw-r--r--src/test/ui/rust-2021/generic-type-collision.rs18
-rw-r--r--src/test/ui/rust-2021/generic-type-collision.stderr16
-rw-r--r--src/test/ui/rust-2021/inherent-dyn-collision.fixed53
-rw-r--r--src/test/ui/rust-2021/inherent-dyn-collision.rs53
-rw-r--r--src/test/ui/rust-2021/inherent-dyn-collision.stderr16
-rw-r--r--src/test/ui/rust-2021/inherent-method-collision.rs15
22 files changed, 1144 insertions, 31 deletions
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index f95d4a6ca54..a2f60142ffc 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -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),
+    };
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b81d29930ee..55b6056209d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -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,
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index d0cbb58fb10..28ab6b15133 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -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.
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 96569ae0e77..8e33f4f9e12 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -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);
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 427102afee1..be6bc625d89 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -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))
     }
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
new file mode 100644
index 00000000000..4c925a6f237
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -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)
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 3ac760e2363..2879614d0c8 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -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();
diff --git a/src/test/ui/rust-2021/future-prelude-collision-imported.fixed b/src/test/ui/rust-2021/future-prelude-collision-imported.fixed
new file mode 100644
index 00000000000..4f8fd9b345b
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-imported.fixed
@@ -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() {}
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..2ce1be6151b
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-imported.rs
@@ -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() {}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-imported.stderr b/src/test/ui/rust-2021/future-prelude-collision-imported.stderr
new file mode 100644
index 00000000000..3903cbfe824
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-imported.stderr
@@ -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
+
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..c9d2529341f
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs
@@ -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() {}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr b/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
new file mode 100644
index 00000000000..ad9b8af00e4
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
@@ -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`.
diff --git a/src/test/ui/rust-2021/future-prelude-collision.fixed b/src/test/ui/rust-2021/future-prelude-collision.fixed
new file mode 100644
index 00000000000..9ede9f3a2fb
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision.fixed
@@ -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!
+}
diff --git a/src/test/ui/rust-2021/future-prelude-collision.rs b/src/test/ui/rust-2021/future-prelude-collision.rs
new file mode 100644
index 00000000000..914e910396a
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision.rs
@@ -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!
+}
diff --git a/src/test/ui/rust-2021/future-prelude-collision.stderr b/src/test/ui/rust-2021/future-prelude-collision.stderr
new file mode 100644
index 00000000000..190145ef4db
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision.stderr
@@ -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
+
diff --git a/src/test/ui/rust-2021/generic-type-collision.fixed b/src/test/ui/rust-2021/generic-type-collision.fixed
new file mode 100644
index 00000000000..00fb128a981
--- /dev/null
+++ b/src/test/ui/rust-2021/generic-type-collision.fixed
@@ -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!
+}
diff --git a/src/test/ui/rust-2021/generic-type-collision.rs b/src/test/ui/rust-2021/generic-type-collision.rs
new file mode 100644
index 00000000000..406fba4d247
--- /dev/null
+++ b/src/test/ui/rust-2021/generic-type-collision.rs
@@ -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!
+}
diff --git a/src/test/ui/rust-2021/generic-type-collision.stderr b/src/test/ui/rust-2021/generic-type-collision.stderr
new file mode 100644
index 00000000000..9374379d247
--- /dev/null
+++ b/src/test/ui/rust-2021/generic-type-collision.stderr
@@ -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
+
diff --git a/src/test/ui/rust-2021/inherent-dyn-collision.fixed b/src/test/ui/rust-2021/inherent-dyn-collision.fixed
new file mode 100644
index 00000000000..cbb6e9659df
--- /dev/null
+++ b/src/test/ui/rust-2021/inherent-dyn-collision.fixed
@@ -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());
+}
diff --git a/src/test/ui/rust-2021/inherent-dyn-collision.rs b/src/test/ui/rust-2021/inherent-dyn-collision.rs
new file mode 100644
index 00000000000..1c9929eff91
--- /dev/null
+++ b/src/test/ui/rust-2021/inherent-dyn-collision.rs
@@ -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());
+}
diff --git a/src/test/ui/rust-2021/inherent-dyn-collision.stderr b/src/test/ui/rust-2021/inherent-dyn-collision.stderr
new file mode 100644
index 00000000000..3d7637100c2
--- /dev/null
+++ b/src/test/ui/rust-2021/inherent-dyn-collision.stderr
@@ -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
+
diff --git a/src/test/ui/rust-2021/inherent-method-collision.rs b/src/test/ui/rust-2021/inherent-method-collision.rs
new file mode 100644
index 00000000000..c638351d5fc
--- /dev/null
+++ b/src/test/ui/rust-2021/inherent-method-collision.rs
@@ -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));
+}