Skip to content

Commit 5217007

Browse files
committed
Tweak output and add test cases
1 parent 711760c commit 5217007

File tree

3 files changed

+222
-16
lines changed

3 files changed

+222
-16
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_session::config::nightly_options;
1919
use rustc_session::parse::feature_err;
2020
use rustc_span::hygiene::MacroKind;
2121
use rustc_span::symbol::{kw, sym, Ident, Symbol};
22-
use rustc_span::{BytePos, Span, DUMMY_SP};
22+
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
2323

2424
use tracing::debug;
2525

@@ -446,12 +446,58 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
446446
err.span_label(base_span, fallback_label);
447447

448448
if let PathSource::Trait(AliasPossibility::Maybe) = source {
449-
if let Some([start, .., end]) = self.diagnostic_metadata.current_trait_object {
449+
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
450+
let spans: Vec<Span> = bounds
451+
.iter()
452+
.map(|bound| bound.span())
453+
.filter(|&sp| sp != base_span)
454+
.collect();
455+
456+
let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap();
457+
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
458+
let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap();
459+
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
460+
let last_bound_span = spans.last().cloned().unwrap();
461+
let mut multi_span: MultiSpan = spans.clone().into();
462+
for sp in spans {
463+
let msg = if sp == last_bound_span {
464+
format!(
465+
"...because of {} bound{}",
466+
if bounds.len() <= 2 { "this" } else { "these" },
467+
if bounds.len() <= 2 { "" } else { "s" },
468+
)
469+
} else {
470+
String::new()
471+
};
472+
multi_span.push_span_label(sp, msg);
473+
}
474+
multi_span.push_span_label(
475+
base_span,
476+
"expected this type to be a trait...".to_string(),
477+
);
450478
err.span_help(
451-
start.span().to(end.span()),
452-
"`+` can be used to constrain a \"trait object\" type with lifetimes or \
453-
auto-traits, structs and enums can't be bound in that way",
479+
multi_span,
480+
"`+` is used to constrain a \"trait object\" type with lifetimes or \
481+
auto-traits; structs and enums can't be bound in that way",
454482
);
483+
if bounds.iter().all(|bound| match bound {
484+
ast::GenericBound::Outlives(_) => true,
485+
ast::GenericBound::Trait(tr, _) => tr.span == base_span,
486+
}) {
487+
let mut sugg = vec![];
488+
if base_span != start_span {
489+
sugg.push((start_span.until(base_span), String::new()));
490+
}
491+
if base_span != end_span {
492+
sugg.push((base_span.shrink_to_hi().to(end_span), String::new()));
493+
}
494+
495+
err.multipart_suggestion(
496+
"if you meant to use a type and not a trait here, remove the bounds",
497+
sugg,
498+
Applicability::MaybeIncorrect,
499+
);
500+
}
455501
}
456502
}
457503
match self.diagnostic_metadata.current_let_binding {
Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,38 @@
1+
// We don't need those errors. Ideally we would silence them, but to do so we need to move the
2+
// lint from being an early-lint during parsing to a late-lint, because it needs to be aware of
3+
// the types involved.
14
#![allow(bare_trait_objects)]
25

36
struct Foo;
47

58
fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
69

7-
type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
10+
type TypeAlias<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
811

9-
fn main() { }
12+
struct A;
13+
fn a() -> A + 'static { //~ ERROR expected trait, found
14+
A
15+
}
16+
fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { //~ ERROR expected trait, found
17+
panic!()
18+
}
19+
fn c() -> 'static + A { //~ ERROR expected trait, found
20+
A
21+
}
22+
fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { //~ ERROR expected trait, found
23+
panic!()
24+
}
25+
fn e() -> 'static + A + 'static { //~ ERROR expected trait, found
26+
//~^ ERROR only a single explicit lifetime bound is permitted
27+
A
28+
}
29+
fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { //~ ERROR expected trait, found
30+
//~^ ERROR only a single explicit lifetime bound is permitted
31+
panic!()
32+
}
33+
struct Traitor;
34+
trait Trait {}
35+
fn g() -> Traitor + 'static { //~ ERROR expected trait, found struct `Traitor`
36+
A
37+
}
38+
fn main() {}
Lines changed: 140 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,152 @@
1+
error[E0226]: only a single explicit lifetime bound is permitted
2+
--> $DIR/trait-bounds-not-on-struct.rs:25:25
3+
|
4+
LL | fn e() -> 'static + A + 'static {
5+
| ^^^^^^^
6+
7+
error[E0226]: only a single explicit lifetime bound is permitted
8+
--> $DIR/trait-bounds-not-on-struct.rs:29:53
9+
|
10+
LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
11+
| ^^
12+
113
error[E0404]: expected trait, found struct `Foo`
2-
--> $DIR/trait-bounds-not-on-struct.rs:5:16
14+
--> $DIR/trait-bounds-not-on-struct.rs:8:16
315
|
416
LL | fn foo(_x: Box<Foo + Send>) { }
517
| ^^^ not a trait
618
|
7-
help: `+` can be used to constrain a "trait object" type with lifetimes or auto-traits, structs and enums can't be bound in that way
8-
--> $DIR/trait-bounds-not-on-struct.rs:5:16
19+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
20+
--> $DIR/trait-bounds-not-on-struct.rs:8:22
921
|
1022
LL | fn foo(_x: Box<Foo + Send>) { }
11-
| ^^^^^^^^^^
23+
| --- ^^^^ ...because of this bound
24+
| |
25+
| expected this type to be a trait...
1226

1327
error[E0404]: expected trait, found struct `Vec`
14-
--> $DIR/trait-bounds-not-on-struct.rs:7:21
28+
--> $DIR/trait-bounds-not-on-struct.rs:10:29
29+
|
30+
LL | type TypeAlias<T> = Box<dyn Vec<T>>;
31+
| ^^^^^^ not a trait
32+
33+
error[E0404]: expected trait, found struct `A`
34+
--> $DIR/trait-bounds-not-on-struct.rs:13:11
35+
|
36+
LL | fn a() -> A + 'static {
37+
| ^ not a trait
38+
|
39+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
40+
--> $DIR/trait-bounds-not-on-struct.rs:13:15
41+
|
42+
LL | fn a() -> A + 'static {
43+
| - ^^^^^^^ ...because of this bound
44+
| |
45+
| expected this type to be a trait...
46+
help: if you meant to use a type and not a trait here, remove the bounds
47+
|
48+
LL | fn a() -> A {
49+
| --
50+
51+
error[E0404]: expected trait, found enum `Result`
52+
--> $DIR/trait-bounds-not-on-struct.rs:16:34
53+
|
54+
LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
55+
| ^^^^^^^^^^^ not a trait
56+
|
57+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
58+
--> $DIR/trait-bounds-not-on-struct.rs:16:48
59+
|
60+
LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
61+
| ----------- ^^ ...because of this bound
62+
| |
63+
| expected this type to be a trait...
64+
help: if you meant to use a type and not a trait here, remove the bounds
65+
|
66+
LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
67+
| --
68+
69+
error[E0404]: expected trait, found struct `A`
70+
--> $DIR/trait-bounds-not-on-struct.rs:19:21
71+
|
72+
LL | fn c() -> 'static + A {
73+
| ^ not a trait
74+
|
75+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
76+
--> $DIR/trait-bounds-not-on-struct.rs:19:11
77+
|
78+
LL | fn c() -> 'static + A {
79+
| ^^^^^^^ - expected this type to be a trait...
80+
| |
81+
| ...because of this bound
82+
help: if you meant to use a type and not a trait here, remove the bounds
83+
|
84+
LL | fn c() -> A {
85+
| --
86+
87+
error[E0404]: expected trait, found enum `Result`
88+
--> $DIR/trait-bounds-not-on-struct.rs:22:39
89+
|
90+
LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
91+
| ^^^^^^^^^^^ not a trait
92+
|
93+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
94+
--> $DIR/trait-bounds-not-on-struct.rs:22:34
95+
|
96+
LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
97+
| ^^ ----------- expected this type to be a trait...
98+
| |
99+
| ...because of this bound
100+
help: if you meant to use a type and not a trait here, remove the bounds
101+
|
102+
LL | fn d<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
103+
| --
104+
105+
error[E0404]: expected trait, found struct `A`
106+
--> $DIR/trait-bounds-not-on-struct.rs:25:21
107+
|
108+
LL | fn e() -> 'static + A + 'static {
109+
| ^ not a trait
110+
|
111+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
112+
--> $DIR/trait-bounds-not-on-struct.rs:25:11
113+
|
114+
LL | fn e() -> 'static + A + 'static {
115+
| ^^^^^^^ - ^^^^^^^ ...because of these bounds
116+
| |
117+
| expected this type to be a trait...
118+
help: if you meant to use a type and not a trait here, remove the bounds
119+
|
120+
LL | fn e() -> A {
121+
| ---
122+
123+
error[E0404]: expected trait, found enum `Result`
124+
--> $DIR/trait-bounds-not-on-struct.rs:29:39
125+
|
126+
LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
127+
| ^^^^^^^^^^^ not a trait
128+
|
129+
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
130+
--> $DIR/trait-bounds-not-on-struct.rs:29:34
131+
|
132+
LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
133+
| ^^ ----------- ^^ ...because of these bounds
134+
| |
135+
| expected this type to be a trait...
136+
help: if you meant to use a type and not a trait here, remove the bounds
137+
|
138+
LL | fn f<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
139+
| -- --
140+
141+
error[E0404]: expected trait, found struct `Traitor`
142+
--> $DIR/trait-bounds-not-on-struct.rs:35:11
15143
|
16-
LL | type A<T> = Box<dyn Vec<T>>;
17-
| ^^^^^^ not a trait
144+
LL | trait Trait {}
145+
| ----------- similarly named trait `Trait` defined here
146+
LL | fn g() -> Traitor + 'static {
147+
| ^^^^^^^ help: a trait with a similar name exists: `Trait`
18148

19-
error: aborting due to 2 previous errors
149+
error: aborting due to 11 previous errors
20150

21-
For more information about this error, try `rustc --explain E0404`.
151+
Some errors have detailed explanations: E0226, E0404.
152+
For more information about an error, try `rustc --explain E0226`.

0 commit comments

Comments
 (0)