Skip to content

Commit 86c1a73

Browse files
ui test: add test of blanklet implementation
Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent 81abfe3 commit 86c1a73

File tree

3 files changed

+187
-31
lines changed

3 files changed

+187
-31
lines changed

compiler/rustc_typeck/src/astconv/mod.rs

+44-31
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,48 +2988,48 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29862988
Some(r)
29872989
}
29882990

2989-
/// make sure that we are in the condition to suggest the blanket implementation, if we are in the
2990-
/// case of suggest it, use the function `err_reporter` to report the error or suggestion.
2991+
/// Make sure that we are in the condition to suggest the blanket implementation.
29912992
fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
29922993
&self,
29932994
self_ty: &hir::Ty<'_>,
2994-
diagnostic: &mut DiagnosticBuilder<'_, T>,
2995+
diag: &mut DiagnosticBuilder<'_, T>,
29952996
) {
29962997
let tcx = self.tcx();
29972998
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
29982999
if let hir::Node::Item(hir::Item {
29993000
kind:
30003001
hir::ItemKind::Impl(hir::Impl {
3001-
self_ty: impl_self_typ, of_trait: Some(trait_ref), generics, ..
3002+
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
30023003
}),
30033004
..
3004-
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_typ.hir_id
3005+
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
30053006
{
3006-
let trait_span = trait_ref.path.span;
3007-
let target_span = if let Some(span) = generics.span_for_param_suggestion() {
3008-
span
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+
let param_name = generics.params.next_type_param_name(Some(&impl_trait_name));
3019+
(span, format!(", {}: {}", param_name, impl_trait_name))
30093020
} else {
3010-
trait_span
3021+
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
30113022
};
3012-
let is_local = trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local());
3013-
if is_local {
3014-
let trait_name = tcx.sess.source_map().span_to_snippet(trait_span).unwrap();
3015-
let self_name = tcx.sess.source_map().span_to_snippet(self_ty.span).unwrap();
3016-
let blanket_msg = format!(
3017-
"use a blanket implementation to implement {} for all types that also implement {}",
3018-
trait_name, self_name
3019-
);
3020-
let blanket_sugg = vec![
3021-
(target_span, "<T: ".to_owned()),
3022-
(trait_span.shrink_to_hi(), format!("{}>", self_name)),
3023-
(self_ty.span, "T".to_owned()),
3024-
];
3025-
diagnostic.multipart_suggestion(
3026-
blanket_msg,
3027-
blanket_sugg,
3028-
Applicability::Unspecified,
3029-
);
3030-
}
3023+
diag.multipart_suggestion(
3024+
format!("alternatively use a blanket \
3025+
implementation to implement `{of_trait_name}` for \
3026+
all types that also implement `{impl_trait_name}`"),
3027+
vec![
3028+
(self_ty.span, param_name),
3029+
add_generic_sugg,
3030+
],
3031+
Applicability::MaybeIncorrect,
3032+
);
30313033
}
30323034
}
30333035

@@ -3045,6 +3047,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
30453047
.map_or(false, |s| s.trim_end().ends_with('<'));
30463048

30473049
let is_global = poly_trait_ref.trait_ref.path.is_global();
3050+
let is_local = if let Some(def_id) = poly_trait_ref.trait_ref.trait_def_id() {
3051+
def_id.is_local()
3052+
} else {
3053+
false
3054+
};
30483055
let sugg = Vec::from_iter([
30493056
(
30503057
self_ty.span.shrink_to_lo(),
@@ -3069,7 +3076,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
30693076
let mut diag =
30703077
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
30713078
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
3072-
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
3079+
// check if the impl trait that we are considering is a impl of a local trait
3080+
if is_local {
3081+
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
3082+
}
30733083
diag.emit();
30743084
} else {
30753085
let msg = "trait objects without an explicit `dyn` are deprecated";
@@ -3084,7 +3094,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
30843094
sugg,
30853095
Applicability::MachineApplicable,
30863096
);
3087-
self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
3097+
// check if the impl trait that we are considering is a impl of a local trait
3098+
if is_local {
3099+
self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
3100+
}
30883101
diag.emit();
30893102
},
30903103
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
16+
impl fmt::Display for LocalTraitOne {
17+
//~^ ERROR trait objects must include the `dyn` keyword
18+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
19+
todo!();
20+
}
21+
}
22+
23+
impl fmt::Display for LocalTraitTwo + Send {
24+
//~^ ERROR trait objects must include the `dyn` keyword
25+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
26+
todo!();
27+
}
28+
}
29+
30+
impl LocalTraitOne for fmt::Display {}
31+
//~^ ERROR trait objects must include the `dyn` keyword
32+
33+
impl LocalTraitOne for fmt::Display + Send {}
34+
//~^ ERROR trait objects must include the `dyn` keyword
35+
36+
impl<E> GenericTrait<E> for LocalTraitOne {}
37+
//~^ ERROR trait objects must include the `dyn` keyword
38+
39+
trait GenericTraitTwo<T> {}
40+
41+
impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
42+
//~^ ERROR trait objects must include the `dyn` keyword
43+
44+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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:16: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:23: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:30: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+
53+
error[E0782]: trait objects must include the `dyn` keyword
54+
--> $DIR/suggest-blanket-impl-local-trait.rs:33:24
55+
|
56+
LL | impl LocalTraitOne for fmt::Display + Send {}
57+
| ^^^^^^^^^^^^^^^^^^^
58+
|
59+
help: add `dyn` keyword before this trait
60+
|
61+
LL - impl LocalTraitOne for fmt::Display + Send {}
62+
LL + impl LocalTraitOne for dyn fmt::Display + Send {}
63+
|
64+
65+
error[E0782]: trait objects must include the `dyn` keyword
66+
--> $DIR/suggest-blanket-impl-local-trait.rs:36:29
67+
|
68+
LL | impl<E> GenericTrait<E> for LocalTraitOne {}
69+
| ^^^^^^^^^^^^^
70+
|
71+
help: add `dyn` keyword before this trait
72+
|
73+
LL - impl<E> GenericTrait<E> for LocalTraitOne {}
74+
LL + impl<E> GenericTrait<E> for dyn LocalTraitOne {}
75+
|
76+
help: alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
77+
|
78+
LL | impl<E, L: LocalTraitOne> GenericTrait<E> for T {}
79+
| ++++++++++++++++++ ~
80+
81+
error[E0782]: trait objects must include the `dyn` keyword
82+
--> $DIR/suggest-blanket-impl-local-trait.rs:41:35
83+
|
84+
LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
85+
| ^^^^^^^^^^^^^^^
86+
|
87+
help: add `dyn` keyword before this trait
88+
|
89+
LL - impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
90+
LL + impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {}
91+
|
92+
help: alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
93+
|
94+
LL | impl<T, E, G: GenericTrait<T>> GenericTraitTwo<E> for U {}
95+
| ++++++++++++++++++++ ~
96+
97+
error: aborting due to 7 previous errors
98+
99+
For more information about this error, try `rustc --explain E0782`.

0 commit comments

Comments
 (0)