Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest blanket impl to the local traits #97488

Merged
merged 3 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 61 additions & 11 deletions compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) =
Expand Down Expand Up @@ -3021,23 +3067,27 @@ 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(
BARE_TRAIT_OBJECTS,
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();
},
);
}
Expand Down
58 changes: 58 additions & 0 deletions src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs
Original file line number Diff line number Diff line change
@@ -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() {}
107 changes: 107 additions & 0 deletions src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Binary file added suggest-blanket-impl-local-trait
Binary file not shown.