Skip to content

Commit c9e8029

Browse files
committed
Tweak wording and only suggest dyn Trait if Trait is object safe
1 parent e55ab93 commit c9e8029

File tree

40 files changed

+268
-535
lines changed

40 files changed

+268
-535
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
2020
) -> Option<ErrorGuaranteed> {
2121
let tcx = self.tcx();
2222

23-
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
24-
self_ty.kind
25-
else {
23+
let hir::TyKind::TraitObject(traits, _, TraitObjectSyntax::None) = self_ty.kind else {
24+
return None;
25+
};
26+
let [poly_trait_ref, ..] = traits else {
2627
return None;
2728
};
2829

@@ -36,6 +37,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
3637

3738
let is_global = poly_trait_ref.trait_ref.path.is_global();
3839

40+
let object_safe = traits.iter().all(|ptr| match ptr.trait_ref.path.res {
41+
Res::Def(DefKind::Trait, def_id) => tcx.object_safety_violations(def_id).is_empty(),
42+
_ => false,
43+
});
44+
3945
let mut sugg = vec![(
4046
self_ty.span.shrink_to_lo(),
4147
format!(
@@ -63,10 +69,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
6369
rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
6470
let mut downgrade = false;
6571
if self_ty.span.can_be_used_for_suggestions() {
66-
let (non_object_safe, should_downgrade) =
67-
self.maybe_suggest_impl_trait(self_ty, &mut diag);
72+
let should_downgrade = self.maybe_suggest_impl_trait(self_ty, &mut diag);
6873
downgrade = should_downgrade;
69-
if !non_object_safe {
74+
if object_safe {
7075
// Only emit this suggestion if the trait is object safe.
7176
diag.multipart_suggestion_verbose(
7277
label,
@@ -89,12 +94,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
8994
} else {
9095
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| {
9196
lint.primary_message("trait objects without an explicit `dyn` are deprecated");
92-
if self_ty.span.can_be_used_for_suggestions() {
93-
lint.multipart_suggestion_verbose(
94-
"if this is an object-safe trait, use `dyn`",
95-
sugg,
96-
Applicability::MachineApplicable,
97-
);
97+
match (object_safe, self_ty.span.can_be_used_for_suggestions()) {
98+
(true, true) => {
99+
lint.multipart_suggestion_verbose(
100+
"as this is an \"object safe\" trait, write `dyn` in front of the \
101+
trait",
102+
sugg,
103+
Applicability::MachineApplicable,
104+
);
105+
}
106+
(true, false) => {
107+
lint.note(
108+
"as this is an \"object safe\" trait, you can write `dyn` in front of \
109+
the trait",
110+
);
111+
}
112+
(false, _) => {
113+
lint.note(
114+
"you can't use write a trait object here because the trait isn't \
115+
\"object safe\"",
116+
);
117+
}
98118
}
99119
self.maybe_suggest_blanket_trait_impl(self_ty, lint);
100120
});
@@ -170,7 +190,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
170190
/// Make sure that we are in the condition to suggest `impl Trait`.
171191
///
172192
/// Returns whether a suggestion was provided and whether the error itself should not be emitted
173-
fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> (bool, bool) {
193+
fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
174194
let tcx = self.tcx();
175195
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
176196
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
@@ -185,10 +205,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
185205
owner_id,
186206
..
187207
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
188-
_ => return (false, false),
208+
_ => return false,
189209
};
190210
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
191-
return (false, false);
211+
return false;
192212
};
193213
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
194214
let mut is_downgradable = true;
@@ -201,7 +221,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
201221
// For recursive traits, don't downgrade the error. (#119652)
202222
is_downgradable = false;
203223
}
204-
tcx.is_object_safe(id)
224+
tcx.object_safety_violations(id).is_empty()
205225
}
206226
_ => false,
207227
})
@@ -234,7 +254,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
234254
// We'll emit the object safety error already, with a structured suggestion.
235255
downgrade = true;
236256
}
237-
return (true, downgrade);
257+
return downgrade;
238258
}
239259
for ty in sig.decl.inputs {
240260
if ty.hir_id != self_ty.hir_id {
@@ -279,9 +299,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
279299
Applicability::MachineApplicable,
280300
);
281301
}
282-
return (true, downgrade);
302+
return downgrade;
283303
}
284-
(false, downgrade)
304+
downgrade
285305
}
286306

287307
fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {

tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33

44
fn f(_: impl Trait<T = Copy>) {}
55
//~^ ERROR trait objects must include the `dyn` keyword
6-
//~| HELP add `dyn` keyword before this trait
76
//~| HELP you might have meant to write a bound here
87

98
fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
109
//~^ ERROR trait objects must include the `dyn` keyword
11-
//~| HELP add `dyn` keyword before this trait
1210
//~| HELP you might have meant to write a bound here
1311

1412
fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
@@ -19,7 +17,6 @@ fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
1917
// Don't suggest assoc ty bound in trait object types, that's not valid:
2018
type Obj = dyn Trait<T = Clone>;
2119
//~^ ERROR trait objects must include the `dyn` keyword
22-
//~| HELP add `dyn` keyword before this trait
2320

2421
trait Trait { type T; }
2522

tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,24 @@ error[E0782]: trait objects must include the `dyn` keyword
44
LL | fn f(_: impl Trait<T = Copy>) {}
55
| ^^^^
66
|
7-
help: add `dyn` keyword before this trait
8-
|
9-
LL | fn f(_: impl Trait<T = dyn Copy>) {}
10-
| +++
117
help: you might have meant to write a bound here
128
|
139
LL | fn f(_: impl Trait<T: Copy>) {}
1410
| ~
1511

1612
error[E0782]: trait objects must include the `dyn` keyword
17-
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:9:24
13+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:8:24
1814
|
1915
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
2016
| ^^^^^^^^^^^^^^^^^^^^
2117
|
22-
help: add `dyn` keyword before this trait
23-
|
24-
LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {}
25-
| +++
2618
help: you might have meant to write a bound here
2719
|
2820
LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {}
2921
| ~
3022

3123
error[E0782]: trait objects must include the `dyn` keyword
32-
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:14:26
24+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:12:26
3325
|
3426
LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
3527
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,15 +36,10 @@ LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {}
4436
| ~
4537

4638
error[E0782]: trait objects must include the `dyn` keyword
47-
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:20:26
39+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26
4840
|
4941
LL | type Obj = dyn Trait<T = Clone>;
5042
| ^^^^^
51-
|
52-
help: add `dyn` keyword before this trait
53-
|
54-
LL | type Obj = dyn Trait<T = dyn Clone>;
55-
| +++
5643

5744
error: aborting due to 4 previous errors
5845

tests/ui/const-generics/not_wf_param_in_rpitit.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22

33
trait Trait<const N: Trait = bar> {
44
//~^ ERROR: cannot find value `bar` in this scope
5-
//~| ERROR: cycle detected when computing type of `Trait::N`
6-
//~| ERROR: the trait `Trait` cannot be made into an object
7-
//~| ERROR: the trait `Trait` cannot be made into an object
8-
//~| ERROR: the trait `Trait` cannot be made into an object
9-
//~| ERROR: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
10-
//~| ERROR: trait objects must include the `dyn` keyword
5+
//~| ERROR: cycle detected when computing predicates of `Trait`
116
async fn a() {}
127
}
138

tests/ui/const-generics/not_wf_param_in_rpitit.stderr

Lines changed: 26 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,110 +4,51 @@ error[E0425]: cannot find value `bar` in this scope
44
LL | trait Trait<const N: Trait = bar> {
55
| ^^^ not found in this scope
66

7-
error[E0391]: cycle detected when computing type of `Trait::N`
8-
--> $DIR/not_wf_param_in_rpitit.rs:3:22
7+
error[E0391]: cycle detected when computing predicates of `Trait`
8+
--> $DIR/not_wf_param_in_rpitit.rs:3:1
99
|
1010
LL | trait Trait<const N: Trait = bar> {
11-
| ^^^^^
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212
|
13-
= note: ...which immediately requires computing type of `Trait::N` again
14-
note: cycle used when computing explicit predicates of trait `Trait`
13+
note: ...which requires computing predicates of `Trait`...
1514
--> $DIR/not_wf_param_in_rpitit.rs:3:1
1615
|
1716
LL | trait Trait<const N: Trait = bar> {
1817
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19-
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
20-
21-
error[E0038]: the trait `Trait` cannot be made into an object
22-
--> $DIR/not_wf_param_in_rpitit.rs:3:22
18+
note: ...which requires computing explicit predicates of `Trait`...
19+
--> $DIR/not_wf_param_in_rpitit.rs:3:1
2320
|
2421
LL | trait Trait<const N: Trait = bar> {
25-
| ^^^^^ `Trait` cannot be made into an object
26-
|
27-
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
28-
--> $DIR/not_wf_param_in_rpitit.rs:11:14
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
note: ...which requires computing explicit predicates of trait `Trait`...
24+
--> $DIR/not_wf_param_in_rpitit.rs:3:1
2925
|
3026
LL | trait Trait<const N: Trait = bar> {
31-
| ----- this trait cannot be made into an object...
32-
...
33-
LL | async fn a() {}
34-
| ^ ...because associated function `a` has no `self` parameter
35-
help: consider turning `a` into a method by giving it a `&self` argument
36-
|
37-
LL | async fn a(&self) {}
38-
| +++++
39-
help: alternatively, consider constraining `a` so it does not apply to trait objects
40-
|
41-
LL | async fn a() where Self: Sized {}
42-
| +++++++++++++++++
43-
44-
error[E0038]: the trait `Trait` cannot be made into an object
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
note: ...which requires computing type of `Trait::N`...
4529
--> $DIR/not_wf_param_in_rpitit.rs:3:13
4630
|
4731
LL | trait Trait<const N: Trait = bar> {
48-
| ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
49-
|
50-
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
51-
--> $DIR/not_wf_param_in_rpitit.rs:11:14
52-
|
53-
LL | trait Trait<const N: Trait = bar> {
54-
| ----- this trait cannot be made into an object...
55-
...
56-
LL | async fn a() {}
57-
| ^ ...because associated function `a` has no `self` parameter
58-
help: consider turning `a` into a method by giving it a `&self` argument
59-
|
60-
LL | async fn a(&self) {}
61-
| +++++
62-
help: alternatively, consider constraining `a` so it does not apply to trait objects
63-
|
64-
LL | async fn a() where Self: Sized {}
65-
| +++++++++++++++++
66-
67-
error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
68-
--> $DIR/not_wf_param_in_rpitit.rs:3:22
69-
|
70-
LL | trait Trait<const N: Trait = bar> {
71-
| ^^^^^
72-
|
73-
= note: the only supported types are integers, `bool` and `char`
74-
75-
error[E0038]: the trait `Trait` cannot be made into an object
76-
--> $DIR/not_wf_param_in_rpitit.rs:3:13
32+
| ^^^^^^^^^^^^^^^^^^^^
33+
note: ...which requires determining object safety of trait `Trait`...
34+
--> $DIR/not_wf_param_in_rpitit.rs:3:1
7735
|
7836
LL | trait Trait<const N: Trait = bar> {
79-
| ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
80-
|
81-
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
82-
--> $DIR/not_wf_param_in_rpitit.rs:11:14
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
note: ...which requires check whether the item has a `where Self: Sized` bound...
39+
--> $DIR/not_wf_param_in_rpitit.rs:6:5
8340
|
84-
LL | trait Trait<const N: Trait = bar> {
85-
| ----- this trait cannot be made into an object...
86-
...
8741
LL | async fn a() {}
88-
| ^ ...because associated function `a` has no `self` parameter
89-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
90-
help: consider turning `a` into a method by giving it a `&self` argument
91-
|
92-
LL | async fn a(&self) {}
93-
| +++++
94-
help: alternatively, consider constraining `a` so it does not apply to trait objects
95-
|
96-
LL | async fn a() where Self: Sized {}
97-
| +++++++++++++++++
98-
99-
error[E0782]: trait objects must include the `dyn` keyword
100-
--> $DIR/not_wf_param_in_rpitit.rs:3:22
42+
| ^^^^^^^^^^^^
43+
= note: ...which again requires computing predicates of `Trait`, completing the cycle
44+
note: cycle used when checking that `Trait` is well-formed
45+
--> $DIR/not_wf_param_in_rpitit.rs:3:1
10146
|
10247
LL | trait Trait<const N: Trait = bar> {
103-
| ^^^^^
104-
|
105-
help: add `dyn` keyword before this trait
106-
|
107-
LL | trait Trait<const N: dyn Trait = bar> {
108-
| +++
48+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
10950

110-
error: aborting due to 7 previous errors
51+
error: aborting due to 2 previous errors
11152

112-
Some errors have detailed explanations: E0038, E0391, E0425, E0782.
113-
For more information about an error, try `rustc --explain E0038`.
53+
Some errors have detailed explanations: E0391, E0425.
54+
For more information about an error, try `rustc --explain E0391`.

tests/ui/consts/const_refs_to_static-ice-121413.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | static FOO: Sync = AtomicUsize::new(0);
1818
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
1919
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
2020
= note: `#[warn(bare_trait_objects)]` on by default
21-
help: if this is an object-safe trait, use `dyn`
21+
help: as this is an "object safe" trait, write `dyn` in front of the trait
2222
|
2323
LL | static FOO: dyn Sync = AtomicUsize::new(0);
2424
| +++
@@ -32,7 +32,7 @@ LL | static FOO: Sync = AtomicUsize::new(0);
3232
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
3333
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
3434
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
35-
help: if this is an object-safe trait, use `dyn`
35+
help: as this is an "object safe" trait, write `dyn` in front of the trait
3636
|
3737
LL | static FOO: dyn Sync = AtomicUsize::new(0);
3838
| +++

tests/ui/did_you_mean/bad-assoc-ty.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ LL | type H = Fn(u8) -> (u8)::Output;
182182
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
183183
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
184184
= note: `#[warn(bare_trait_objects)]` on by default
185-
help: if this is an object-safe trait, use `dyn`
185+
help: as this is an "object safe" trait, write `dyn` in front of the trait
186186
|
187187
LL | type H = <dyn Fn(u8) -> (u8)>::Output;
188188
| ++++ +

0 commit comments

Comments
 (0)