about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late.rs9
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs21
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs11
-rw-r--r--src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr27
-rw-r--r--src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.rs10
-rw-r--r--src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr29
7 files changed, 107 insertions, 2 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 73d6566e3cd..688ba89c689 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -496,6 +496,9 @@ struct DiagnosticMetadata<'ast> {
 
     /// The current impl items (used to suggest).
     current_impl_items: Option<&'ast [P<AssocItem>]>,
+
+    /// When processing impl trait
+    currently_processing_impl_trait: Option<(TraitRef, Ty)>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -2066,18 +2069,22 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     fn with_optional_trait_ref<T>(
         &mut self,
         opt_trait_ref: Option<&TraitRef>,
+        self_type: &'ast Ty,
         f: impl FnOnce(&mut Self, Option<DefId>) -> T,
     ) -> T {
         let mut new_val = None;
         let mut new_id = None;
         if let Some(trait_ref) = opt_trait_ref {
             let path: Vec<_> = Segment::from_path(&trait_ref.path);
+            self.diagnostic_metadata.currently_processing_impl_trait =
+                Some((trait_ref.clone(), self_type.clone()));
             let res = self.smart_resolve_path_fragment(
                 None,
                 &path,
                 PathSource::Trait(AliasPossibility::No),
                 Finalize::new(trait_ref.ref_id, trait_ref.path.span),
             );
+            self.diagnostic_metadata.currently_processing_impl_trait = None;
             if let Some(def_id) = res.base_res().opt_def_id() {
                 new_id = Some(def_id);
                 new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
@@ -2118,7 +2125,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
                 this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
                     // Resolve the trait reference, if necessary.
-                    this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
+                    this.with_optional_trait_ref(opt_trait_reference.as_ref(), self_type, |this, trait_id| {
                         let item_def_id = this.r.local_def_id(item_id);
 
                         // Register the trait definitions from here.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index a6a04ac9ea6..2266b4a1ecb 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -145,6 +145,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         let is_expected = &|res| source.is_expected(res);
         let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
 
+        debug!(?res, ?source);
+
         // Make the base error.
         struct BaseError<'a> {
             msg: String,
@@ -248,6 +250,25 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         let code = source.error_code(res.is_some());
         let mut err =
             self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
+        if let Some((trait_ref, self_ty)) =
+            self.diagnostic_metadata.currently_processing_impl_trait.clone()
+            && let TyKind::Path(_, self_ty_path) = &self_ty.kind
+            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
+            && let ModuleKind::Def(DefKind::Trait, ..) = module.kind
+            && trait_ref.path.span == span
+            && let PathSource::Trait(_) = source
+            && let Some(Res::Def(DefKind::Struct, _)) = res
+            && let Ok(self_ty_str) =
+                self.r.session.source_map().span_to_snippet(self_ty.span)
+            && let Ok(trait_ref_str) =
+                self.r.session.source_map().span_to_snippet(trait_ref.path.span)
+        {
+                err.multipart_suggestion(
+                    "consider swapping the struct and the trait",
+                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
+                    Applicability::MaybeIncorrect,
+                );
+        }
 
         if let Some(sugg) = base_error.suggestion {
             err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index adf5a744048..456cf6dbe27 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -338,7 +338,7 @@ impl<'a> FileNameDisplay<'a> {
     pub fn to_string_lossy(&self) -> Cow<'a, str> {
         match self.inner {
             FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
-            _ => Cow::from(format!("{}", self)),
+            _ => Cow::from(self.to_string()),
         }
     }
 }
diff --git a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs
new file mode 100644
index 00000000000..a32e943daf8
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.rs
@@ -0,0 +1,11 @@
+// edition:2021
+
+pub trait Trait<'a, T> {}
+
+pub struct Struct<T> {}
+
+impl<'a, T> Struct<T> for Trait<'a, T> {}
+//~^ ERROR expected trait, found struct `Struct`
+//~| ERROR trait objects must include the `dyn` keyword
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr
new file mode 100644
index 00000000000..aa9d09a797b
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait-edition-2021.stderr
@@ -0,0 +1,27 @@
+error[E0404]: expected trait, found struct `Struct`
+  --> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:7:13
+   |
+LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
+   |             ^^^^^^^^^ not a trait
+   |
+help: consider swapping the struct and the trait
+   |
+LL | impl<'a, T> Trait<'a, T> for Struct<T> {}
+   |             ~~~~~~~~~~~~     ~~~~~~~~~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:7:27
+   |
+LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
+   |                           ^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl<'a, T> Struct<T> for Trait<'a, T> {}
+LL + impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
+   | 
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0404, E0782.
+For more information about an error, try `rustc --explain E0404`.
diff --git a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.rs b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.rs
new file mode 100644
index 00000000000..d74cc86f7ea
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.rs
@@ -0,0 +1,10 @@
+pub trait Trait<'a, T> {}
+
+pub struct Struct<T> {}
+
+impl<'a, T> Struct<T> for Trait<'a, T> {}
+//~^ ERROR expected trait, found struct `Struct`
+//~| WARNING trait objects without an explicit `dyn` are deprecated
+//~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
new file mode 100644
index 00000000000..f5f22f03cd9
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
@@ -0,0 +1,29 @@
+error[E0404]: expected trait, found struct `Struct`
+  --> $DIR/suggest-swapping-self-ty-and-trait.rs:5:13
+   |
+LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
+   |             ^^^^^^^^^ not a trait
+   |
+help: consider swapping the struct and the trait
+   |
+LL | impl<'a, T> Trait<'a, T> for Struct<T> {}
+   |             ~~~~~~~~~~~~     ~~~~~~~~~
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/suggest-swapping-self-ty-and-trait.rs:5:27
+   |
+LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
+   |                           ^^^^^^^^^^^^
+   |
+   = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+   |
+LL - impl<'a, T> Struct<T> for Trait<'a, T> {}
+LL + impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
+   | 
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0404`.