Skip to content

Commit 413bfa4

Browse files
committed
Wording changes to object unsafe trait errors
Stemming from the thread at https://twitter.com/indygreg/status/1223279056398929920
1 parent 3ca1c5d commit 413bfa4

File tree

51 files changed

+332
-91
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+332
-91
lines changed

src/librustc/traits/error_reporting/mod.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,10 @@ pub fn report_object_safety_error(
10341034
violations: Vec<ObjectSafetyViolation>,
10351035
) -> DiagnosticBuilder<'tcx> {
10361036
let trait_str = tcx.def_path_str(trait_def_id);
1037+
let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
1038+
hir::Node::Item(item) => Some(item.ident.span),
1039+
_ => None,
1040+
});
10371041
let span = tcx.sess.source_map().def_span(span);
10381042
let mut err = struct_span_err!(
10391043
tcx.sess,
@@ -1045,6 +1049,7 @@ pub fn report_object_safety_error(
10451049
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
10461050

10471051
let mut reported_violations = FxHashSet::default();
1052+
let mut had_span_label = false;
10481053
for violation in violations {
10491054
if let ObjectSafetyViolation::SizedSelf(sp) = &violation {
10501055
if !sp.is_empty() {
@@ -1055,15 +1060,28 @@ pub fn report_object_safety_error(
10551060
}
10561061
if reported_violations.insert(violation.clone()) {
10571062
let spans = violation.spans();
1063+
let msg = if trait_span.is_none() || spans.is_empty() {
1064+
format!("the trait cannot be made into an object because {}", violation.error_msg())
1065+
} else {
1066+
had_span_label = true;
1067+
format!("...because {}", violation.error_msg())
1068+
};
10581069
if spans.is_empty() {
1059-
err.note(&violation.error_msg());
1070+
err.note(&msg);
10601071
} else {
10611072
for span in spans {
1062-
err.span_label(span, violation.error_msg());
1073+
err.span_label(span, &msg);
10631074
}
10641075
}
1076+
if let (Some(_), Some(note)) = (trait_span, violation.solution()) {
1077+
// Only provide the help if its a local trait, otherwise it's not actionable.
1078+
err.help(&note);
1079+
}
10651080
}
10661081
}
1082+
if let (Some(trait_span), true) = (trait_span, had_span_label) {
1083+
err.span_label(trait_span, "this trait cannot be made into an object...");
1084+
}
10671085

10681086
if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
10691087
// Avoid emitting error caused by non-existing method (#58734)

src/librustc/traits/object_safety.rs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,9 @@ pub enum ObjectSafetyViolation {
4343
impl ObjectSafetyViolation {
4444
pub fn error_msg(&self) -> Cow<'static, str> {
4545
match *self {
46-
ObjectSafetyViolation::SizedSelf(_) => {
47-
"traits that require `Self: Sized` cannot be made into an object".into()
48-
}
46+
ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
4947
ObjectSafetyViolation::SupertraitSelf => {
50-
"the trait cannot use `Self` as a type parameter \
51-
in the supertraits or where-clauses"
48+
"it cannot use `Self` as a type parameter in the supertraits or `where`-clauses"
5249
.into()
5350
}
5451
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => {
@@ -63,19 +60,45 @@ impl ObjectSafetyViolation {
6360
name,
6461
MethodViolationCode::WhereClauseReferencesSelf,
6562
_,
66-
) => format!("method `{}` references the `Self` type in where clauses", name).into(),
63+
) => {
64+
format!("method `{}` references the `Self` type in its `where` clause", name).into()
65+
}
6766
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
6867
format!("method `{}` has generic type parameters", name).into()
6968
}
7069
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
7170
format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
7271
}
72+
ObjectSafetyViolation::AssocConst(_, DUMMY_SP) => {
73+
"it cannot contain associated consts".into()
74+
}
7375
ObjectSafetyViolation::AssocConst(name, _) => {
74-
format!("the trait cannot contain associated consts like `{}`", name).into()
76+
format!("it cannot contain associated consts like `{}`", name).into()
7577
}
7678
}
7779
}
7880

81+
pub fn solution(&self) -> Option<String> {
82+
Some(match *self {
83+
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf => {
84+
return None;
85+
}
86+
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => format!(
87+
"consider turning `{}` into a method by giving it a `&self` argument or \
88+
constraining it with `where Self: Sized`",
89+
name
90+
),
91+
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
92+
format!("consider changing method `{}`'s `self` parameter to be `&self`", name)
93+
.into()
94+
}
95+
ObjectSafetyViolation::AssocConst(name, _)
96+
| ObjectSafetyViolation::Method(name, ..) => {
97+
format!("consider moving `{}` to another trait", name)
98+
}
99+
})
100+
}
101+
79102
pub fn spans(&self) -> SmallVec<[Span; 1]> {
80103
// When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
81104
// diagnostics use a `note` instead of a `span_label`.
@@ -190,7 +213,21 @@ fn object_safety_violations_for_trait(
190213
tcx.def_path_str(trait_def_id)
191214
),
192215
);
193-
err.span_label(*span, violation.error_msg());
216+
let node = tcx.hir().get_if_local(trait_def_id);
217+
let msg = if let Some(hir::Node::Item(item)) = node {
218+
err.span_label(item.ident.span, "this trait cannot be made into an object...");
219+
format!("...because {}", violation.error_msg())
220+
} else {
221+
format!(
222+
"the trait cannot be made into an object because {}",
223+
violation.error_msg()
224+
)
225+
};
226+
err.span_label(*span, &msg);
227+
if let (Some(_), Some(note)) = (node, violation.solution()) {
228+
// Only provide the help if its a local trait, otherwise it's not actionable.
229+
err.help(&note);
230+
}
194231
err.emit();
195232
false
196233
} else {

src/test/ui/associated-const/associated-const-in-trait.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
error[E0038]: the trait `Trait` cannot be made into an object
22
--> $DIR/associated-const-in-trait.rs:9:6
33
|
4+
LL | trait Trait {
5+
| ----- this trait cannot be made into an object...
46
LL | const N: usize;
5-
| - the trait cannot contain associated consts like `N`
7+
| - ...because it cannot contain associated consts like `N`
68
...
79
LL | impl dyn Trait {
810
| ^^^^^^^^^ the trait `Trait` cannot be made into an object
11+
|
12+
= help: consider moving `N` to another trait
913

1014
error: aborting due to previous error
1115

src/test/ui/associated-item/issue-48027.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
error[E0038]: the trait `Bar` cannot be made into an object
22
--> $DIR/issue-48027.rs:6:6
33
|
4+
LL | trait Bar {
5+
| --- this trait cannot be made into an object...
46
LL | const X: usize;
5-
| - the trait cannot contain associated consts like `X`
7+
| - ...because it cannot contain associated consts like `X`
68
...
79
LL | impl dyn Bar {}
810
| ^^^^^^^ the trait `Bar` cannot be made into an object
11+
|
12+
= help: consider moving `X` to another trait
913

1014
error[E0283]: type annotations needed
1115
--> $DIR/issue-48027.rs:3:32

src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object
22
--> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:6
33
|
44
LL | trait NotObjectSafe { fn eq(&self, other: Self); }
5-
| -- method `eq` references the `Self` type in its parameters or return type
5+
| ------------- -- ...because method `eq` references the `Self` type in its parameters or return type
6+
| |
7+
| this trait cannot be made into an object...
68
LL | impl NotObjectSafe for dyn NotObjectSafe { }
79
| ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
10+
|
11+
= help: consider moving `eq` to another trait
812

913
error: aborting due to previous error
1014

src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ error[E0038]: the trait `std::marker::Copy` cannot be made into an object
1616
LL | let _: &Copy + 'static;
1717
| ^^^^^ the trait `std::marker::Copy` cannot be made into an object
1818
|
19-
= note: traits that require `Self: Sized` cannot be made into an object
19+
= note: the trait cannot be made into an object because it requires `Self: Sized`
2020

2121
error: aborting due to 3 previous errors
2222

src/test/ui/error-codes/E0033-teach.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@ LL | let trait_obj: &dyn SomeTrait = SomeTrait;
77
error[E0038]: the trait `SomeTrait` cannot be made into an object
88
--> $DIR/E0033-teach.rs:8:20
99
|
10+
LL | trait SomeTrait {
11+
| --------- this trait cannot be made into an object...
1012
LL | fn foo();
11-
| --- associated function `foo` has no `self` parameter
13+
| --- ...because associated function `foo` has no `self` parameter
1214
...
1315
LL | let trait_obj: &dyn SomeTrait = SomeTrait;
1416
| ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
17+
|
18+
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
1519

1620
error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
1721
--> $DIR/E0033-teach.rs:12:9

src/test/ui/error-codes/E0033.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@ LL | let trait_obj: &dyn SomeTrait = SomeTrait;
77
error[E0038]: the trait `SomeTrait` cannot be made into an object
88
--> $DIR/E0033.rs:6:20
99
|
10+
LL | trait SomeTrait {
11+
| --------- this trait cannot be made into an object...
1012
LL | fn foo();
11-
| --- associated function `foo` has no `self` parameter
13+
| --- ...because associated function `foo` has no `self` parameter
1214
...
1315
LL | let trait_obj: &dyn SomeTrait = SomeTrait;
1416
| ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
17+
|
18+
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
1519

1620
error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
1721
--> $DIR/E0033.rs:10:9

src/test/ui/error-codes/E0038.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
error[E0038]: the trait `Trait` cannot be made into an object
22
--> $DIR/E0038.rs:5:16
33
|
4+
LL | trait Trait {
5+
| ----- this trait cannot be made into an object...
46
LL | fn foo(&self) -> Self;
5-
| --- method `foo` references the `Self` type in its parameters or return type
7+
| --- ...because method `foo` references the `Self` type in its parameters or return type
68
...
79
LL | fn call_foo(x: Box<dyn Trait>) {
810
| ^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object
11+
|
12+
= help: consider moving `foo` to another trait
913

1014
error: aborting due to previous error
1115

src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,59 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
22
--> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38
33
|
44
LL | trait NonObjectSafe1: Sized {}
5-
| ----- traits that require `Self: Sized` cannot be made into an object
5+
| -------------- ----- ...because it requires `Self: Sized`
6+
| |
7+
| this trait cannot be made into an object...
68
...
79
LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
810
| ^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object
911

1012
error[E0038]: the trait `NonObjectSafe2` cannot be made into an object
1113
--> $DIR/feature-gate-object_safe_for_dispatch.rs:22:36
1214
|
15+
LL | trait NonObjectSafe2 {
16+
| -------------- this trait cannot be made into an object...
1317
LL | fn static_fn() {}
14-
| --------- associated function `static_fn` has no `self` parameter
18+
| --------- ...because associated function `static_fn` has no `self` parameter
1519
...
1620
LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
1721
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object
22+
|
23+
= help: consider turning `static_fn` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
1824

1925
error[E0038]: the trait `NonObjectSafe3` cannot be made into an object
2026
--> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35
2127
|
28+
LL | trait NonObjectSafe3 {
29+
| -------------- this trait cannot be made into an object...
2230
LL | fn foo<T>(&self);
23-
| --- method `foo` has generic type parameters
31+
| --- ...because method `foo` has generic type parameters
2432
...
2533
LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
2634
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe3` cannot be made into an object
35+
|
36+
= help: consider moving `foo` to another trait
2737

2838
error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
2939
--> $DIR/feature-gate-object_safe_for_dispatch.rs:31:35
3040
|
41+
LL | trait NonObjectSafe4 {
42+
| -------------- this trait cannot be made into an object...
3143
LL | fn foo(&self, &Self);
32-
| --- method `foo` references the `Self` type in its parameters or return type
44+
| --- ...because method `foo` references the `Self` type in its parameters or return type
3345
...
3446
LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
3547
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object
48+
|
49+
= help: consider moving `foo` to another trait
3650

3751
error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
3852
--> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6
3953
|
4054
LL | trait NonObjectSafe1: Sized {}
41-
| ----- traits that require `Self: Sized` cannot be made into an object
55+
| -------------- ----- ...because it requires `Self: Sized`
56+
| |
57+
| this trait cannot be made into an object...
4258
...
4359
LL | impl Trait for dyn NonObjectSafe1 {}
4460
| ^^^^^ the trait `NonObjectSafe1` cannot be made into an object

src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
error[E0038]: the trait `NotObjectSafe` cannot be made into an object
22
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:13
33
|
4+
LL | trait NotObjectSafe {
5+
| ------------- this trait cannot be made into an object...
46
LL | fn foo() -> Self;
5-
| --- associated function `foo` has no `self` parameter
7+
| --- ...because associated function `foo` has no `self` parameter
68
...
79
LL | fn car() -> dyn NotObjectSafe {
810
| ^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
11+
|
12+
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
913

1014
error[E0038]: the trait `NotObjectSafe` cannot be made into an object
1115
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:13
1216
|
17+
LL | trait NotObjectSafe {
18+
| ------------- this trait cannot be made into an object...
1319
LL | fn foo() -> Self;
14-
| --- associated function `foo` has no `self` parameter
20+
| --- ...because associated function `foo` has no `self` parameter
1521
...
1622
LL | fn cat() -> Box<dyn NotObjectSafe> {
1723
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
24+
|
25+
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
1826

1927
error: aborting due to 2 previous errors
2028

src/test/ui/issues/issue-18959.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ error[E0038]: the trait `Bar` cannot be made into an object
22
--> $DIR/issue-18959.rs:11:11
33
|
44
LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
5-
| --- method `foo` has generic type parameters
5+
| --- ...because method `foo` has generic type parameters
6+
LL | pub trait Bar: Foo { }
7+
| --- this trait cannot be made into an object...
68
...
79
LL | fn foo(b: &dyn Bar) {
810
| ^^^^^^^^ the trait `Bar` cannot be made into an object
11+
|
12+
= help: consider moving `foo` to another trait
913

1014
error: aborting due to previous error
1115

src/test/ui/issues/issue-19380.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
error[E0038]: the trait `Qiz` cannot be made into an object
22
--> $DIR/issue-19380.rs:11:3
33
|
4+
LL | trait Qiz {
5+
| --- this trait cannot be made into an object...
46
LL | fn qiz();
5-
| --- associated function `qiz` has no `self` parameter
7+
| --- ...because associated function `qiz` has no `self` parameter
68
...
79
LL | foos: &'static [&'static (dyn Qiz + 'static)]
810
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
11+
|
12+
= help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`
913

1014
error: aborting due to previous error
1115

0 commit comments

Comments
 (0)