about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-07-01 20:19:16 +0530
committerGitHub <noreply@github.com>2022-07-01 20:19:16 +0530
commite2ed8d7ed167d7b7026cc9ea990e8fec2a1d5d46 (patch)
tree872c8b5b0b317b219daf968b60e0649886ad2c85
parentca1e68b3229e710c3948a361ee770d846a88e6da (diff)
parent835b7a523a41cc89f0839f40652477af097db390 (diff)
downloadrust-e2ed8d7ed167d7b7026cc9ea990e8fec2a1d5d46.tar.gz
rust-e2ed8d7ed167d7b7026cc9ea990e8fec2a1d5d46.zip
Rollup merge of #97488 - vincenzopalazzo:macros/blanket_sugg, r=compiler-errors
Suggest blanket impl to the local traits

This PR will add additional suggestion regarding the blanket implementation when it is possible, by generation a new help message + suggestion.

Closes https://github.com/rust-lang/rust/issues/96076

Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs72
-rw-r--r--src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs58
-rw-r--r--src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr107
-rwxr-xr-xsuggest-blanket-impl-local-traitbin0 -> 479160 bytes
4 files changed, 226 insertions, 11 deletions
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index eec3b24aec2..37958cc0f40 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -38,7 +38,9 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::astconv_object_safety_violations;
-use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
+use rustc_trait_selection::traits::error_reporting::{
+    report_object_safety_error, suggestions::NextTypeParamName,
+};
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
 use smallvec::SmallVec;
@@ -2986,6 +2988,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         Some(r)
     }
 
+    /// Make sure that we are in the condition to suggest the blanket implementation.
+    fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
+        &self,
+        self_ty: &hir::Ty<'_>,
+        diag: &mut DiagnosticBuilder<'_, T>,
+    ) {
+        let tcx = self.tcx();
+        let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
+        if let hir::Node::Item(hir::Item {
+            kind:
+                hir::ItemKind::Impl(hir::Impl {
+                    self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
+                }),
+            ..
+        }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
+        {
+            if !of_trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local()) {
+                return;
+            }
+            let of_trait_span = of_trait_ref.path.span;
+            // make sure that we are not calling unwrap to abort during the compilation
+            let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
+            let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
+            // check if the trait has generics, to make a correct suggestion
+            let param_name = generics.params.next_type_param_name(None);
+
+            let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
+                (span, format!(", {}: {}", param_name, impl_trait_name))
+            } else {
+                (generics.span, format!("<{}: {}>", param_name, impl_trait_name))
+            };
+            diag.multipart_suggestion(
+            format!("alternatively use a blanket \
+                     implementation to implement `{of_trait_name}` for \
+                     all types that also implement `{impl_trait_name}`"),
+                vec![
+                    (self_ty.span, param_name),
+                    add_generic_sugg,
+                ],
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
         let tcx = self.tcx();
         if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
@@ -3021,9 +3067,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             if self_ty.span.edition() >= Edition::Edition2021 {
                 let msg = "trait objects must include the `dyn` keyword";
                 let label = "add `dyn` keyword before this trait";
-                rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
-                    .multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
-                    .emit();
+                let mut diag =
+                    rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
+                diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+                // check if the impl trait that we are considering is a impl of a local trait
+                self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
+                diag.emit();
             } else {
                 let msg = "trait objects without an explicit `dyn` are deprecated";
                 tcx.struct_span_lint_hir(
@@ -3031,13 +3080,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     self_ty.hir_id,
                     self_ty.span,
                     |lint| {
-                        lint.build(msg)
-                            .multipart_suggestion_verbose(
-                                "use `dyn`",
-                                sugg,
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
+                        let mut diag = lint.build(msg);
+                        diag.multipart_suggestion_verbose(
+                            "use `dyn`",
+                            sugg,
+                            Applicability::MachineApplicable,
+                        );
+                        self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
+                        diag.emit();
                     },
                 );
             }
diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs
new file mode 100644
index 00000000000..7cf536f7966
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs
@@ -0,0 +1,58 @@
+// Ensure that the compiler include the blanklet implementation suggestion
+// when inside a `impl` statment are used two local traits.
+//
+// edition:2021
+use std::fmt;
+
+trait LocalTraitOne { }
+
+trait LocalTraitTwo { }
+
+trait GenericTrait<T> {}
+
+impl LocalTraitTwo for LocalTraitOne {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
+
+impl fmt::Display for LocalTraitOne {
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        todo!();
+    }
+}
+
+impl fmt::Display for LocalTraitTwo + Send {
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        todo!();
+    }
+}
+
+impl LocalTraitOne for fmt::Display {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
+
+
+impl LocalTraitOne for fmt::Display + Send {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
+
+
+impl<E> GenericTrait<E> for LocalTraitOne {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
+
+trait GenericTraitTwo<T> {}
+
+impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr
new file mode 100644
index 00000000000..d739a8272f1
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr
@@ -0,0 +1,107 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:13:24
+   |
+LL | impl LocalTraitTwo for LocalTraitOne {}
+   |                        ^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl LocalTraitTwo for LocalTraitOne {}
+LL + impl LocalTraitTwo for dyn LocalTraitOne {}
+   |
+help: alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
+   |
+LL | impl<T: LocalTraitOne> LocalTraitTwo for T {}
+   |     ++++++++++++++++++                   ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:18:23
+   |
+LL | impl fmt::Display for LocalTraitOne {
+   |                       ^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl fmt::Display for LocalTraitOne {
+LL + impl fmt::Display for dyn LocalTraitOne {
+   |
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:26:23
+   |
+LL | impl fmt::Display for LocalTraitTwo + Send {
+   |                       ^^^^^^^^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl fmt::Display for LocalTraitTwo + Send {
+LL + impl fmt::Display for dyn LocalTraitTwo + Send {
+   |
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:34:24
+   |
+LL | impl LocalTraitOne for fmt::Display {}
+   |                        ^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl LocalTraitOne for fmt::Display {}
+LL + impl LocalTraitOne for dyn fmt::Display {}
+   |
+help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
+   |
+LL | impl<T: fmt::Display> LocalTraitOne for T {}
+   |     +++++++++++++++++                   ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:40:24
+   |
+LL | impl LocalTraitOne for fmt::Display + Send {}
+   |                        ^^^^^^^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl LocalTraitOne for fmt::Display + Send {}
+LL + impl LocalTraitOne for dyn fmt::Display + Send {}
+   |
+help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
+   |
+LL | impl<T: fmt::Display + Send> LocalTraitOne for T {}
+   |     ++++++++++++++++++++++++                   ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:46:29
+   |
+LL | impl<E> GenericTrait<E> for LocalTraitOne {}
+   |                             ^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl<E> GenericTrait<E> for LocalTraitOne {}
+LL + impl<E> GenericTrait<E> for dyn LocalTraitOne {}
+   |
+help: alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
+   |
+LL | impl<E, T: LocalTraitOne> GenericTrait<E> for T {}
+   |       ++++++++++++++++++                      ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:53:35
+   |
+LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
+   |                                   ^^^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
+LL + impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {}
+   |
+help: alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
+   |
+LL | impl<T, E, U: GenericTrait<T>> GenericTraitTwo<E> for U {}
+   |          ++++++++++++++++++++                         ~
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
diff --git a/suggest-blanket-impl-local-trait b/suggest-blanket-impl-local-trait
new file mode 100755
index 00000000000..0a357e006c3
--- /dev/null
+++ b/suggest-blanket-impl-local-trait
Binary files differ