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

Tweak obligation error output #68377

Merged
merged 23 commits into from
Feb 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fca5c64
Point at arguments or output when fn obligations come from them, or i…
estebank Jan 18, 2020
1c9242f
Point at `Sized` bound
estebank Jan 19, 2020
d72bcdb
When object unsafe trait uses itself in associated item suggest using…
estebank Jan 20, 2020
0eb29d1
fix test
estebank Jan 20, 2020
d137b7a
review comments
estebank Jan 25, 2020
4b2f1db
Tweak `Self: Sized` restriction diagnostic output
estebank Jan 29, 2020
972ae5a
Point at the `Sized` obligation in `where` clauses
estebank Jan 29, 2020
8d48597
Point at return type obligations instead of at `fn` ident
estebank Jan 29, 2020
6870f79
Use more accurate failed predicate spans
estebank Jan 30, 2020
144e259
Slight rewording of diagnostic message
estebank Jan 30, 2020
132921b
Remove duplicated code
estebank Jan 30, 2020
06fea92
review comments
estebank Jan 31, 2020
3ca1c5d
Point at `Sized` requirements
estebank Jan 31, 2020
413bfa4
Wording changes to object unsafe trait errors
estebank Feb 1, 2020
a52ec87
Use more appropriate spans on object unsafe traits and provide struct…
estebank Feb 1, 2020
542130b
add tests for structured suggestion
estebank Feb 1, 2020
cb6dfea
Suggest `?Sized` on type parameters
estebank Feb 2, 2020
d216b73
Remove duplicated code
estebank Feb 2, 2020
342db71
Account for `?Sized` type parameter bounds
estebank Feb 2, 2020
16d935e
fix rebase
estebank Feb 2, 2020
865216b
Point at reason in object unsafe trait with `Self` in supertraits or …
estebank Feb 2, 2020
b9c125a
Deal with spans showing `std` lib
estebank Feb 2, 2020
0e58411
Change wording for object unsafe because of assoc const
estebank Feb 3, 2020
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
22 changes: 20 additions & 2 deletions src/librustc/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,10 @@ pub fn report_object_safety_error(
violations: Vec<ObjectSafetyViolation>,
) -> DiagnosticBuilder<'tcx> {
let trait_str = tcx.def_path_str(trait_def_id);
let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
hir::Node::Item(item) => Some(item.ident.span),
_ => None,
});
let span = tcx.sess.source_map().def_span(span);
let mut err = struct_span_err!(
tcx.sess,
Expand All @@ -1045,6 +1049,7 @@ pub fn report_object_safety_error(
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));

let mut reported_violations = FxHashSet::default();
let mut had_span_label = false;
for violation in violations {
if let ObjectSafetyViolation::SizedSelf(sp) = &violation {
if !sp.is_empty() {
Expand All @@ -1055,15 +1060,28 @@ pub fn report_object_safety_error(
}
if reported_violations.insert(violation.clone()) {
let spans = violation.spans();
let msg = if trait_span.is_none() || spans.is_empty() {
format!("the trait cannot be made into an object because {}", violation.error_msg())
} else {
had_span_label = true;
format!("...because {}", violation.error_msg())
};
if spans.is_empty() {
err.note(&violation.error_msg());
err.note(&msg);
} else {
for span in spans {
err.span_label(span, violation.error_msg());
err.span_label(span, &msg);
}
}
if let (Some(_), Some(note)) = (trait_span, violation.solution()) {
// Only provide the help if its a local trait, otherwise it's not actionable.
err.help(&note);
}
}
}
if let (Some(trait_span), true) = (trait_span, had_span_label) {
err.span_label(trait_span, "this trait cannot be made into an object...");
}

if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
Expand Down
53 changes: 45 additions & 8 deletions src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,9 @@ pub enum ObjectSafetyViolation {
impl ObjectSafetyViolation {
pub fn error_msg(&self) -> Cow<'static, str> {
match *self {
ObjectSafetyViolation::SizedSelf(_) => {
"traits that require `Self: Sized` cannot be made into an object".into()
}
ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
ObjectSafetyViolation::SupertraitSelf => {
"the trait cannot use `Self` as a type parameter \
in the supertraits or where-clauses"
"it cannot use `Self` as a type parameter in the supertraits or `where`-clauses"
.into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => {
Expand All @@ -63,19 +60,45 @@ impl ObjectSafetyViolation {
name,
MethodViolationCode::WhereClauseReferencesSelf,
_,
) => format!("method `{}` references the `Self` type in where clauses", name).into(),
) => {
format!("method `{}` references the `Self` type in its `where` clause", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
format!("method `{}` has generic type parameters", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
}
ObjectSafetyViolation::AssocConst(_, DUMMY_SP) => {
"it cannot contain associated consts".into()
}
ObjectSafetyViolation::AssocConst(name, _) => {
format!("the trait cannot contain associated consts like `{}`", name).into()
format!("it cannot contain associated consts like `{}`", name).into()
}
}
}

pub fn solution(&self) -> Option<String> {
Some(match *self {
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf => {
return None;
}
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod, _) => format!(
"consider turning `{}` into a method by giving it a `&self` argument or \
constraining it with `where Self: Sized`",
name
),
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
format!("consider changing method `{}`'s `self` parameter to be `&self`", name)
.into()
}
ObjectSafetyViolation::AssocConst(name, _)
| ObjectSafetyViolation::Method(name, ..) => {
format!("consider moving `{}` to another trait", name)
}
})
}

pub fn spans(&self) -> SmallVec<[Span; 1]> {
// When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
// diagnostics use a `note` instead of a `span_label`.
Expand Down Expand Up @@ -190,7 +213,21 @@ fn object_safety_violations_for_trait(
tcx.def_path_str(trait_def_id)
),
);
err.span_label(*span, violation.error_msg());
let node = tcx.hir().get_if_local(trait_def_id);
let msg = if let Some(hir::Node::Item(item)) = node {
err.span_label(item.ident.span, "this trait cannot be made into an object...");
format!("...because {}", violation.error_msg())
} else {
format!(
"the trait cannot be made into an object because {}",
violation.error_msg()
)
};
err.span_label(*span, &msg);
if let (Some(_), Some(note)) = (node, violation.solution()) {
// Only provide the help if its a local trait, otherwise it's not actionable.
err.help(&note);
}
err.emit();
false
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/associated-const-in-trait.rs:9:6
|
LL | trait Trait {
| ----- this trait cannot be made into an object...
LL | const N: usize;
| - the trait cannot contain associated consts like `N`
| - ...because it cannot contain associated consts like `N`
estebank marked this conversation as resolved.
Show resolved Hide resolved
...
LL | impl dyn Trait {
| ^^^^^^^^^ the trait `Trait` cannot be made into an object
|
= help: consider moving `N` to another trait

error: aborting due to previous error

Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/associated-item/issue-48027.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/issue-48027.rs:6:6
|
LL | trait Bar {
| --- this trait cannot be made into an object...
LL | const X: usize;
| - the trait cannot contain associated consts like `X`
| - ...because it cannot contain associated consts like `X`
...
LL | impl dyn Bar {}
| ^^^^^^^ the trait `Bar` cannot be made into an object
|
= help: consider moving `X` to another trait

error[E0283]: type annotations needed
--> $DIR/issue-48027.rs:3:32
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object
--> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:6
|
LL | trait NotObjectSafe { fn eq(&self, other: Self); }
| -- method `eq` references the `Self` type in its parameters or return type
| ------------- -- ...because method `eq` references the `Self` type in its parameters or return type
| |
| this trait cannot be made into an object...
LL | impl NotObjectSafe for dyn NotObjectSafe { }
| ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
|
= help: consider moving `eq` to another trait

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ error[E0038]: the trait `std::marker::Copy` cannot be made into an object
LL | let _: &Copy + 'static;
| ^^^^^ the trait `std::marker::Copy` cannot be made into an object
|
= note: traits that require `Self: Sized` cannot be made into an object
= note: the trait cannot be made into an object because it requires `Self: Sized`

error: aborting due to 3 previous errors

Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/error-codes/E0033-teach.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ LL | let trait_obj: &dyn SomeTrait = SomeTrait;
error[E0038]: the trait `SomeTrait` cannot be made into an object
--> $DIR/E0033-teach.rs:8:20
|
LL | trait SomeTrait {
| --------- this trait cannot be made into an object...
LL | fn foo();
| --- associated function `foo` has no `self` parameter
| --- ...because associated function `foo` has no `self` parameter
...
LL | let trait_obj: &dyn SomeTrait = SomeTrait;
| ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`

error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
--> $DIR/E0033-teach.rs:12:9
Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/error-codes/E0033.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ LL | let trait_obj: &dyn SomeTrait = SomeTrait;
error[E0038]: the trait `SomeTrait` cannot be made into an object
--> $DIR/E0033.rs:6:20
|
LL | trait SomeTrait {
| --------- this trait cannot be made into an object...
LL | fn foo();
| --- associated function `foo` has no `self` parameter
| --- ...because associated function `foo` has no `self` parameter
...
LL | let trait_obj: &dyn SomeTrait = SomeTrait;
| ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`

error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
--> $DIR/E0033.rs:10:9
Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/error-codes/E0038.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/E0038.rs:5:16
|
LL | trait Trait {
| ----- this trait cannot be made into an object...
LL | fn foo(&self) -> Self;
| --- method `foo` references the `Self` type in its parameters or return type
| --- ...because method `foo` references the `Self` type in its parameters or return type
...
LL | fn call_foo(x: Box<dyn Trait>) {
| ^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object
|
= help: consider moving `foo` to another trait

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,59 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
--> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38
|
LL | trait NonObjectSafe1: Sized {}
| ----- traits that require `Self: Sized` cannot be made into an object
| -------------- ----- ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
...
LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
| ^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object

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

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

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

error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
--> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6
|
LL | trait NonObjectSafe1: Sized {}
| ----- traits that require `Self: Sized` cannot be made into an object
| -------------- ----- ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
...
LL | impl Trait for dyn NonObjectSafe1 {}
| ^^^^^ the trait `NonObjectSafe1` cannot be made into an object
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
error[E0038]: the trait `NotObjectSafe` cannot be made into an object
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:13
|
LL | trait NotObjectSafe {
| ------------- this trait cannot be made into an object...
LL | fn foo() -> Self;
| --- associated function `foo` has no `self` parameter
| --- ...because associated function `foo` has no `self` parameter
...
LL | fn car() -> dyn NotObjectSafe {
| ^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
|
= help: consider turning `foo` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`

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

error: aborting due to 2 previous errors

Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/issues/issue-18959.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/issue-18959.rs:11:11
|
LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
| --- method `foo` has generic type parameters
| --- ...because method `foo` has generic type parameters
LL | pub trait Bar: Foo { }
| --- this trait cannot be made into an object...
...
LL | fn foo(b: &dyn Bar) {
| ^^^^^^^^ the trait `Bar` cannot be made into an object
|
= help: consider moving `foo` to another trait

error: aborting due to previous error

Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/issues/issue-19380.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
error[E0038]: the trait `Qiz` cannot be made into an object
--> $DIR/issue-19380.rs:11:3
|
LL | trait Qiz {
| --- this trait cannot be made into an object...
LL | fn qiz();
| --- associated function `qiz` has no `self` parameter
| --- ...because associated function `qiz` has no `self` parameter
...
LL | foos: &'static [&'static (dyn Qiz + 'static)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
|
= help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it with `where Self: Sized`

error: aborting due to previous error

Expand Down
Loading