about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs195
-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.rs7
-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.fixed33
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-shadow.rs4
-rw-r--r--src/test/ui/rust-2021/future-prelude-collision-shadow.stderr40
7 files changed, 313 insertions, 59 deletions
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index 5f6731b6c52..0750567d3dd 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -4,7 +4,7 @@ use hir::ItemKind;
 use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{Ref, Ty};
 use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
 use rustc_span::symbol::kw::Underscore;
 use rustc_span::symbol::{sym, Ident};
@@ -46,21 +46,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        self.tcx.struct_span_lint_hir(
-            FUTURE_PRELUDE_COLLISION,
-            call_expr.hir_id,
-            call_expr.span,
-            |lint| {
-                let sp = call_expr.span;
-                let trait_name =
-                    self.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container.id());
-
-                let mut lint = lint.build(&format!(
-                    "trait method `{}` will become ambiguous in Rust 2021",
-                    segment.ident.name
-                ));
-
-                if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
+        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 {
@@ -74,46 +84,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }) => "&",
                         Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
                     };
-                    let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
-                        pick.autoref_or_ptr_adjustment
+                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                     {
-                        format!("{}{} as *const _", derefs, self_expr)
+                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                            pick.autoref_or_ptr_adjustment
+                        {
+                            format!("{}{} as *const _", derefs, self_expr)
+                        } else {
+                            format!("{}{}{}", autoref, derefs, self_expr)
+                        };
+
+                        lint.span_suggestion(
+                            sp,
+                            "disambiguate the method call",
+                            format!("({})", self_adjusted),
+                            Applicability::MachineApplicable,
+                        );
                     } else {
-                        format!("{}{}{}", autoref, derefs, self_expr)
-                    };
-                    let args = args
-                        .iter()
-                        .skip(1)
-                        .map(|arg| {
-                            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,
-                        ),
+                        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(),
                     );
-                }
 
-                lint.emit();
-            },
-        );
+                    let mut lint = lint.build(&format!(
+                        "trait method `{}` will become ambiguous in Rust 2021",
+                        segment.ident.name
+                    ));
+
+                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
+                    {
+                        let derefs = "*".repeat(pick.autoderefs);
+
+                        let autoref = match pick.autoref_or_ptr_adjustment {
+                            Some(probe::AutorefOrPtrAdjustment::Autoref {
+                                mutbl: Mutability::Mut,
+                                ..
+                            }) => "&mut ",
+                            Some(probe::AutorefOrPtrAdjustment::Autoref {
+                                mutbl: Mutability::Not,
+                                ..
+                            }) => "&",
+                            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+                        };
+                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                            pick.autoref_or_ptr_adjustment
+                        {
+                            format!("{}{} as *const _", derefs, self_expr)
+                        } else {
+                            format!("{}{}{}", autoref, derefs, self_expr)
+                        };
+                        let args = args
+                            .iter()
+                            .skip(1)
+                            .map(|arg| {
+                                format!(
+                                    ", {}",
+                                    self.sess().source_map().span_to_snippet(arg.span).unwrap()
+                                )
+                            })
+                            .collect::<String>();
+
+                        lint.span_suggestion(
+                            sp,
+                            "disambiguate the associated function",
+                            format!(
+                                "{}::{}({}{})",
+                                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(
@@ -226,11 +305,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
         // so just take the first one.
         match import_items[0].kind {
-            ItemKind::Use(path, _) => {
-                // FIXME: serialize path into something readable like a::b, there must be a fn for this
-                debug!("no name for trait, found import of path: {:?}", path);
-                return None;
-            }
+            ItemKind::Use(path, _) => Some(
+                path.segments
+                    .iter()
+                    .map(|segment| segment.ident.to_string())
+                    .collect::<Vec<_>>()
+                    .join("::"),
+            ),
             _ => {
                 span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
             }
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
index e85a0bd725d..2ce1be6151b 100644
--- a/src/test/ui/rust-2021/future-prelude-collision-imported.rs
+++ b/src/test/ui/rust-2021/future-prelude-collision-imported.rs
@@ -3,6 +3,7 @@
 // check-pass
 #![warn(future_prelude_collision)]
 #![allow(dead_code)]
+#![allow(unused_imports)]
 
 mod m {
     pub trait TryIntoU32 {
@@ -24,6 +25,8 @@ mod a {
     fn main() {
         // In this case, we can just use `TryIntoU32`
         let _: u32 = 3u8.try_into().unwrap();
+        //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+        //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
     }
 }
 
@@ -35,6 +38,8 @@ mod b {
         // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use
         // the path `crate::m::TryIntoU32` (with which it was imported).
         let _: u32 = 3u8.try_into().unwrap();
+        //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+        //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
     }
 }
 
@@ -46,6 +51,8 @@ mod c {
         // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use
         // the path `super::m::TryIntoU32` (with which it was imported).
         let _: u32 = 3u8.try_into().unwrap();
+        //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+        //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
     }
 }
 
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.fixed b/src/test/ui/rust-2021/future-prelude-collision-shadow.fixed
new file mode 100644
index 00000000000..588ab6255fa
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.fixed
@@ -0,0 +1,33 @@
+// run-rustfix
+// edition:2018
+#![warn(future_prelude_collision)]
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+mod m {
+    pub trait TryIntoU32 {
+        fn try_into(self) -> Result<u32, ()>;
+    }
+
+    impl TryIntoU32 for u8 {
+        fn try_into(self) -> Result<u32, ()> {
+            Ok(self as u32)
+        }
+    }
+
+    pub trait AnotherTrick {}
+}
+
+mod d {
+    use crate::m::AnotherTrick as TryIntoU32;
+    use crate::m::*;
+
+    fn main() {
+        // Here, `TryIntoU32` is imported but shadowed, but in that case we don't permit its methods
+        // to be available.
+        let _: u32 = 3u8.try_into().unwrap();
+        //~^ ERROR no method named `try_into` found for type `u8` in the current scope
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-shadow.rs b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs
index ef19cf4d1e6..588ab6255fa 100644
--- a/src/test/ui/rust-2021/future-prelude-collision-shadow.rs
+++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs
@@ -1,8 +1,8 @@
 // run-rustfix
 // edition:2018
-// check-pass
 #![warn(future_prelude_collision)]
 #![allow(dead_code)]
+#![allow(unused_imports)]
 
 mod m {
     pub trait TryIntoU32 {
@@ -26,7 +26,7 @@ mod d {
         // Here, `TryIntoU32` is imported but shadowed, but in that case we don't permit its methods
         // to be available.
         let _: u32 = 3u8.try_into().unwrap();
-        //~^ ERROR no method name `try_into` found
+        //~^ ERROR no method named `try_into` found for type `u8` in the current scope
     }
 }
 
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..3019b2aa5e2
--- /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:28:26
+   |
+LL |         let _: u32 = 3u8.try_into().unwrap();
+   |                          ^^^^^^^^ method not found in `u8`
+   | 
+  ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
+   |
+LL |     fn try_into(self) -> Result<T, Self::Error>;
+   |        --------
+   |        |
+   |        the method is available for `Box<u8>` here
+   |        the method is available for `Pin<u8>` here
+   |        the method is available for `Arc<u8>` here
+   |        the method is available for `Rc<u8>` here
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
+           candidate #1: `use crate::m::TryIntoU32;`
+           candidate #2: `use std::convert::TryInto;`
+help: consider wrapping the receiver expression with the appropriate type
+   |
+LL |         let _: u32 = Box::new(3u8).try_into().unwrap();
+   |                      ^^^^^^^^^   ^
+help: consider wrapping the receiver expression with the appropriate type
+   |
+LL |         let _: u32 = Pin::new(3u8).try_into().unwrap();
+   |                      ^^^^^^^^^   ^
+help: consider wrapping the receiver expression with the appropriate type
+   |
+LL |         let _: u32 = Arc::new(3u8).try_into().unwrap();
+   |                      ^^^^^^^^^   ^
+help: consider wrapping the receiver expression with the appropriate type
+   |
+LL |         let _: u32 = Rc::new(3u8).try_into().unwrap();
+   |                      ^^^^^^^^   ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.