Skip to content

Commit e2ed8d7

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#96076 Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
2 parents ca1e68b + 835b7a5 commit e2ed8d7

File tree

4 files changed

+226
-11
lines changed

4 files changed

+226
-11
lines changed

compiler/rustc_typeck/src/astconv/mod.rs

+61-11
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ use rustc_span::{Span, DUMMY_SP};
3838
use rustc_target::spec::abi;
3939
use rustc_trait_selection::traits;
4040
use rustc_trait_selection::traits::astconv_object_safety_violations;
41-
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
41+
use rustc_trait_selection::traits::error_reporting::{
42+
report_object_safety_error, suggestions::NextTypeParamName,
43+
};
4244
use rustc_trait_selection::traits::wf::object_region_bounds;
4345

4446
use smallvec::SmallVec;
@@ -2986,6 +2988,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29862988
Some(r)
29872989
}
29882990

2991+
/// Make sure that we are in the condition to suggest the blanket implementation.
2992+
fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
2993+
&self,
2994+
self_ty: &hir::Ty<'_>,
2995+
diag: &mut DiagnosticBuilder<'_, T>,
2996+
) {
2997+
let tcx = self.tcx();
2998+
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
2999+
if let hir::Node::Item(hir::Item {
3000+
kind:
3001+
hir::ItemKind::Impl(hir::Impl {
3002+
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
3003+
}),
3004+
..
3005+
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
3006+
{
3007+
if !of_trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local()) {
3008+
return;
3009+
}
3010+
let of_trait_span = of_trait_ref.path.span;
3011+
// make sure that we are not calling unwrap to abort during the compilation
3012+
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
3013+
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
3014+
// check if the trait has generics, to make a correct suggestion
3015+
let param_name = generics.params.next_type_param_name(None);
3016+
3017+
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
3018+
(span, format!(", {}: {}", param_name, impl_trait_name))
3019+
} else {
3020+
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
3021+
};
3022+
diag.multipart_suggestion(
3023+
format!("alternatively use a blanket \
3024+
implementation to implement `{of_trait_name}` for \
3025+
all types that also implement `{impl_trait_name}`"),
3026+
vec![
3027+
(self_ty.span, param_name),
3028+
add_generic_sugg,
3029+
],
3030+
Applicability::MaybeIncorrect,
3031+
);
3032+
}
3033+
}
3034+
29893035
fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
29903036
let tcx = self.tcx();
29913037
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
@@ -3021,23 +3067,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
30213067
if self_ty.span.edition() >= Edition::Edition2021 {
30223068
let msg = "trait objects must include the `dyn` keyword";
30233069
let label = "add `dyn` keyword before this trait";
3024-
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
3025-
.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
3026-
.emit();
3070+
let mut diag =
3071+
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
3072+
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
3073+
// check if the impl trait that we are considering is a impl of a local trait
3074+
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
3075+
diag.emit();
30273076
} else {
30283077
let msg = "trait objects without an explicit `dyn` are deprecated";
30293078
tcx.struct_span_lint_hir(
30303079
BARE_TRAIT_OBJECTS,
30313080
self_ty.hir_id,
30323081
self_ty.span,
30333082
|lint| {
3034-
lint.build(msg)
3035-
.multipart_suggestion_verbose(
3036-
"use `dyn`",
3037-
sugg,
3038-
Applicability::MachineApplicable,
3039-
)
3040-
.emit();
3083+
let mut diag = lint.build(msg);
3084+
diag.multipart_suggestion_verbose(
3085+
"use `dyn`",
3086+
sugg,
3087+
Applicability::MachineApplicable,
3088+
);
3089+
self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
3090+
diag.emit();
30413091
},
30423092
);
30433093
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Ensure that the compiler include the blanklet implementation suggestion
2+
// when inside a `impl` statment are used two local traits.
3+
//
4+
// edition:2021
5+
use std::fmt;
6+
7+
trait LocalTraitOne { }
8+
9+
trait LocalTraitTwo { }
10+
11+
trait GenericTrait<T> {}
12+
13+
impl LocalTraitTwo for LocalTraitOne {}
14+
//~^ ERROR trait objects must include the `dyn` keyword
15+
//~| HELP add `dyn` keyword before this trait
16+
//~| HELP alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
17+
18+
impl fmt::Display for LocalTraitOne {
19+
//~^ ERROR trait objects must include the `dyn` keyword
20+
//~| HELP add `dyn` keyword before this trait
21+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
22+
todo!();
23+
}
24+
}
25+
26+
impl fmt::Display for LocalTraitTwo + Send {
27+
//~^ ERROR trait objects must include the `dyn` keyword
28+
//~| HELP add `dyn` keyword before this trait
29+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
30+
todo!();
31+
}
32+
}
33+
34+
impl LocalTraitOne for fmt::Display {}
35+
//~^ ERROR trait objects must include the `dyn` keyword
36+
//~| HELP add `dyn` keyword before this trait
37+
//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
38+
39+
40+
impl LocalTraitOne for fmt::Display + Send {}
41+
//~^ ERROR trait objects must include the `dyn` keyword
42+
//~| HELP add `dyn` keyword before this trait
43+
//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
44+
45+
46+
impl<E> GenericTrait<E> for LocalTraitOne {}
47+
//~^ ERROR trait objects must include the `dyn` keyword
48+
//~| HELP add `dyn` keyword before this trait
49+
//~| HELP alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
50+
51+
trait GenericTraitTwo<T> {}
52+
53+
impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
54+
//~^ ERROR trait objects must include the `dyn` keyword
55+
//~| HELP add `dyn` keyword before this trait
56+
//~| HELP alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
57+
58+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
error[E0782]: trait objects must include the `dyn` keyword
2+
--> $DIR/suggest-blanket-impl-local-trait.rs:13:24
3+
|
4+
LL | impl LocalTraitTwo for LocalTraitOne {}
5+
| ^^^^^^^^^^^^^
6+
|
7+
help: add `dyn` keyword before this trait
8+
|
9+
LL - impl LocalTraitTwo for LocalTraitOne {}
10+
LL + impl LocalTraitTwo for dyn LocalTraitOne {}
11+
|
12+
help: alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
13+
|
14+
LL | impl<T: LocalTraitOne> LocalTraitTwo for T {}
15+
| ++++++++++++++++++ ~
16+
17+
error[E0782]: trait objects must include the `dyn` keyword
18+
--> $DIR/suggest-blanket-impl-local-trait.rs:18:23
19+
|
20+
LL | impl fmt::Display for LocalTraitOne {
21+
| ^^^^^^^^^^^^^
22+
|
23+
help: add `dyn` keyword before this trait
24+
|
25+
LL - impl fmt::Display for LocalTraitOne {
26+
LL + impl fmt::Display for dyn LocalTraitOne {
27+
|
28+
29+
error[E0782]: trait objects must include the `dyn` keyword
30+
--> $DIR/suggest-blanket-impl-local-trait.rs:26:23
31+
|
32+
LL | impl fmt::Display for LocalTraitTwo + Send {
33+
| ^^^^^^^^^^^^^^^^^^^^
34+
|
35+
help: add `dyn` keyword before this trait
36+
|
37+
LL - impl fmt::Display for LocalTraitTwo + Send {
38+
LL + impl fmt::Display for dyn LocalTraitTwo + Send {
39+
|
40+
41+
error[E0782]: trait objects must include the `dyn` keyword
42+
--> $DIR/suggest-blanket-impl-local-trait.rs:34:24
43+
|
44+
LL | impl LocalTraitOne for fmt::Display {}
45+
| ^^^^^^^^^^^^
46+
|
47+
help: add `dyn` keyword before this trait
48+
|
49+
LL - impl LocalTraitOne for fmt::Display {}
50+
LL + impl LocalTraitOne for dyn fmt::Display {}
51+
|
52+
help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
53+
|
54+
LL | impl<T: fmt::Display> LocalTraitOne for T {}
55+
| +++++++++++++++++ ~
56+
57+
error[E0782]: trait objects must include the `dyn` keyword
58+
--> $DIR/suggest-blanket-impl-local-trait.rs:40:24
59+
|
60+
LL | impl LocalTraitOne for fmt::Display + Send {}
61+
| ^^^^^^^^^^^^^^^^^^^
62+
|
63+
help: add `dyn` keyword before this trait
64+
|
65+
LL - impl LocalTraitOne for fmt::Display + Send {}
66+
LL + impl LocalTraitOne for dyn fmt::Display + Send {}
67+
|
68+
help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
69+
|
70+
LL | impl<T: fmt::Display + Send> LocalTraitOne for T {}
71+
| ++++++++++++++++++++++++ ~
72+
73+
error[E0782]: trait objects must include the `dyn` keyword
74+
--> $DIR/suggest-blanket-impl-local-trait.rs:46:29
75+
|
76+
LL | impl<E> GenericTrait<E> for LocalTraitOne {}
77+
| ^^^^^^^^^^^^^
78+
|
79+
help: add `dyn` keyword before this trait
80+
|
81+
LL - impl<E> GenericTrait<E> for LocalTraitOne {}
82+
LL + impl<E> GenericTrait<E> for dyn LocalTraitOne {}
83+
|
84+
help: alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
85+
|
86+
LL | impl<E, T: LocalTraitOne> GenericTrait<E> for T {}
87+
| ++++++++++++++++++ ~
88+
89+
error[E0782]: trait objects must include the `dyn` keyword
90+
--> $DIR/suggest-blanket-impl-local-trait.rs:53:35
91+
|
92+
LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
93+
| ^^^^^^^^^^^^^^^
94+
|
95+
help: add `dyn` keyword before this trait
96+
|
97+
LL - impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
98+
LL + impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {}
99+
|
100+
help: alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
101+
|
102+
LL | impl<T, E, U: GenericTrait<T>> GenericTraitTwo<E> for U {}
103+
| ++++++++++++++++++++ ~
104+
105+
error: aborting due to 7 previous errors
106+
107+
For more information about this error, try `rustc --explain E0782`.

suggest-blanket-impl-local-trait

468 KB
Binary file not shown.

0 commit comments

Comments
 (0)