Skip to content

Commit 7768358

Browse files
authored
Rollup merge of #57886 - davidtwco:issue-57385, r=estebank
Add suggestion for moving type declaration before associated type bindings in generic arguments. Fixes #57385. r? @estebank
2 parents 141fa85 + 7a0abbf commit 7768358

File tree

4 files changed

+303
-27
lines changed

4 files changed

+303
-27
lines changed

src/libsyntax/parse/parser.rs

+107-27
Original file line numberDiff line numberDiff line change
@@ -5543,22 +5543,31 @@ impl<'a> Parser<'a> {
55435543
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
55445544
let mut args = Vec::new();
55455545
let mut bindings = Vec::new();
5546+
55465547
let mut seen_type = false;
55475548
let mut seen_binding = false;
5549+
5550+
let mut last_comma_span = None;
55485551
let mut first_type_or_binding_span: Option<Span> = None;
5552+
let mut first_binding_span: Option<Span> = None;
5553+
55495554
let mut bad_lifetime_pos = vec![];
5550-
let mut last_comma_span = None;
5551-
let mut suggestions = vec![];
5555+
let mut bad_type_pos = vec![];
5556+
5557+
let mut lifetime_suggestions = vec![];
5558+
let mut type_suggestions = vec![];
55525559
loop {
55535560
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
55545561
// Parse lifetime argument.
55555562
args.push(GenericArg::Lifetime(self.expect_lifetime()));
5563+
55565564
if seen_type || seen_binding {
55575565
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
55585566
bad_lifetime_pos.push(self.prev_span);
5567+
55595568
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
5560-
suggestions.push((remove_sp, String::new()));
5561-
suggestions.push((
5569+
lifetime_suggestions.push((remove_sp, String::new()));
5570+
lifetime_suggestions.push((
55625571
first_type_or_binding_span.unwrap().shrink_to_lo(),
55635572
format!("{}, ", snippet)));
55645573
}
@@ -5576,24 +5585,29 @@ impl<'a> Parser<'a> {
55765585
ty,
55775586
span,
55785587
});
5588+
55795589
seen_binding = true;
55805590
if first_type_or_binding_span.is_none() {
55815591
first_type_or_binding_span = Some(span);
55825592
}
5593+
if first_binding_span.is_none() {
5594+
first_binding_span = Some(span);
5595+
}
55835596
} else if self.check_type() {
55845597
// Parse type argument.
55855598
let ty_param = self.parse_ty()?;
55865599
if seen_binding {
5587-
self.struct_span_err(
5588-
ty_param.span,
5589-
"type parameters must be declared prior to associated type bindings"
5590-
)
5591-
.span_label(
5592-
ty_param.span,
5593-
"must be declared prior to associated type bindings",
5594-
)
5595-
.emit();
5600+
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
5601+
bad_type_pos.push(self.prev_span);
5602+
5603+
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
5604+
type_suggestions.push((remove_sp, String::new()));
5605+
type_suggestions.push((
5606+
first_binding_span.unwrap().shrink_to_lo(),
5607+
format!("{}, ", snippet)));
5608+
}
55965609
}
5610+
55975611
if first_type_or_binding_span.is_none() {
55985612
first_type_or_binding_span = Some(ty_param.span);
55995613
}
@@ -5609,27 +5623,93 @@ impl<'a> Parser<'a> {
56095623
last_comma_span = Some(self.prev_span);
56105624
}
56115625
}
5612-
if !bad_lifetime_pos.is_empty() {
5613-
let mut err = self.struct_span_err(
5626+
5627+
self.maybe_report_incorrect_generic_argument_order(
5628+
bad_lifetime_pos, bad_type_pos, lifetime_suggestions, type_suggestions
5629+
);
5630+
5631+
Ok((args, bindings))
5632+
}
5633+
5634+
/// Maybe report an error about incorrect generic argument order - "lifetime parameters
5635+
/// must be declared before type parameters", "type parameters must be declared before
5636+
/// associated type bindings" or both.
5637+
fn maybe_report_incorrect_generic_argument_order(
5638+
&self,
5639+
bad_lifetime_pos: Vec<Span>,
5640+
bad_type_pos: Vec<Span>,
5641+
lifetime_suggestions: Vec<(Span, String)>,
5642+
type_suggestions: Vec<(Span, String)>,
5643+
) {
5644+
let mut err = if !bad_lifetime_pos.is_empty() && !bad_type_pos.is_empty() {
5645+
let mut positions = bad_lifetime_pos.clone();
5646+
positions.extend_from_slice(&bad_type_pos);
5647+
5648+
self.struct_span_err(
5649+
positions,
5650+
"generic arguments must declare lifetimes, types and associated type bindings in \
5651+
that order",
5652+
)
5653+
} else if !bad_lifetime_pos.is_empty() {
5654+
self.struct_span_err(
56145655
bad_lifetime_pos.clone(),
56155656
"lifetime parameters must be declared prior to type parameters"
5616-
);
5657+
)
5658+
} else if !bad_type_pos.is_empty() {
5659+
self.struct_span_err(
5660+
bad_type_pos.clone(),
5661+
"type parameters must be declared prior to associated type bindings"
5662+
)
5663+
} else {
5664+
return;
5665+
};
5666+
5667+
if !bad_lifetime_pos.is_empty() {
56175668
for sp in &bad_lifetime_pos {
56185669
err.span_label(*sp, "must be declared prior to type parameters");
56195670
}
5620-
if !suggestions.is_empty() {
5621-
err.multipart_suggestion_with_applicability(
5622-
&format!(
5623-
"move the lifetime parameter{} prior to the first type parameter",
5624-
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
5625-
),
5626-
suggestions,
5627-
Applicability::MachineApplicable,
5628-
);
5671+
}
5672+
5673+
if !bad_type_pos.is_empty() {
5674+
for sp in &bad_type_pos {
5675+
err.span_label(*sp, "must be declared prior to associated type bindings");
56295676
}
5630-
err.emit();
56315677
}
5632-
Ok((args, bindings))
5678+
5679+
if !lifetime_suggestions.is_empty() && !type_suggestions.is_empty() {
5680+
let mut suggestions = lifetime_suggestions;
5681+
suggestions.extend_from_slice(&type_suggestions);
5682+
5683+
let plural = bad_lifetime_pos.len() + bad_type_pos.len() > 1;
5684+
err.multipart_suggestion_with_applicability(
5685+
&format!(
5686+
"move the parameter{}",
5687+
if plural { "s" } else { "" },
5688+
),
5689+
suggestions,
5690+
Applicability::MachineApplicable,
5691+
);
5692+
} else if !lifetime_suggestions.is_empty() {
5693+
err.multipart_suggestion_with_applicability(
5694+
&format!(
5695+
"move the lifetime parameter{} prior to the first type parameter",
5696+
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
5697+
),
5698+
lifetime_suggestions,
5699+
Applicability::MachineApplicable,
5700+
);
5701+
} else if !type_suggestions.is_empty() {
5702+
err.multipart_suggestion_with_applicability(
5703+
&format!(
5704+
"move the type parameter{} prior to the first associated type binding",
5705+
if bad_type_pos.len() > 1 { "s" } else { "" },
5706+
),
5707+
type_suggestions,
5708+
Applicability::MachineApplicable,
5709+
);
5710+
}
5711+
5712+
err.emit();
56335713
}
56345714

56355715
/// Parses an optional `where` clause and places it in `generics`.

src/test/ui/parser/issue-32214.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ error: type parameters must be declared prior to associated type bindings
33
|
44
LL | pub fn test<W, I: Trait<Item=(), W> >() {}
55
| ^ must be declared prior to associated type bindings
6+
help: move the type parameter prior to the first associated type binding
7+
|
8+
LL | pub fn test<W, I: Trait<W, Item=()> >() {}
9+
| ^^ --
610

711
error: aborting due to previous error
812

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// ignore-tidy-linelength
2+
3+
#![allow(warnings)]
4+
5+
// This test verifies that the suggestion to move types before associated type bindings
6+
// is correct.
7+
8+
trait One<T> {
9+
type A;
10+
}
11+
12+
trait OneWithLifetime<'a, T> {
13+
type A;
14+
}
15+
16+
trait Three<T, U, V> {
17+
type A;
18+
type B;
19+
type C;
20+
}
21+
22+
trait ThreeWithLifetime<'a, 'b, 'c, T, U, V> {
23+
type A;
24+
type B;
25+
type C;
26+
}
27+
28+
struct A<T, M: One<A=(), T>> { //~ ERROR type parameters must be declared
29+
m: M,
30+
t: T,
31+
}
32+
33+
34+
struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
35+
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
36+
m: M,
37+
t: &'a T,
38+
}
39+
40+
struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR type parameters must be declared
41+
m: M,
42+
t: T,
43+
u: U,
44+
v: V,
45+
}
46+
47+
struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
48+
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
49+
m: M,
50+
t: &'a T,
51+
u: &'b U,
52+
v: &'c V,
53+
}
54+
55+
struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR type parameters must be declared
56+
m: M,
57+
t: T,
58+
u: U,
59+
v: V,
60+
}
61+
62+
struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
63+
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
64+
m: M,
65+
t: &'a T,
66+
u: &'b U,
67+
v: &'c V,
68+
}
69+
70+
struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR type parameters must be declared
71+
m: M,
72+
t: T,
73+
u: U,
74+
v: V,
75+
}
76+
77+
struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
78+
//~^ ERROR generic arguments must declare lifetimes, types and associated type bindings in that order
79+
m: M,
80+
t: &'a T,
81+
u: &'b U,
82+
v: &'c V,
83+
}
84+
85+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
error: type parameters must be declared prior to associated type bindings
2+
--> $DIR/suggest-move-types.rs:28:26
3+
|
4+
LL | struct A<T, M: One<A=(), T>> { //~ ERROR type parameters must be declared
5+
| ^ must be declared prior to associated type bindings
6+
help: move the type parameter prior to the first associated type binding
7+
|
8+
LL | struct A<T, M: One<T, A=()>> { //~ ERROR type parameters must be declared
9+
| ^^ --
10+
11+
error: generic arguments must declare lifetimes, types and associated type bindings in that order
12+
--> $DIR/suggest-move-types.rs:34:46
13+
|
14+
LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
15+
| ^ ^^ must be declared prior to type parameters
16+
| |
17+
| must be declared prior to associated type bindings
18+
help: move the parameters
19+
|
20+
LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A=()>> {
21+
| ^^^ ^^ --
22+
23+
error: type parameters must be declared prior to associated type bindings
24+
--> $DIR/suggest-move-types.rs:40:46
25+
|
26+
LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR type parameters must be declared
27+
| ^ ^ ^ must be declared prior to associated type bindings
28+
| | |
29+
| | must be declared prior to associated type bindings
30+
| must be declared prior to associated type bindings
31+
help: move the type parameters prior to the first associated type binding
32+
|
33+
LL | struct B<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
34+
| ^^ ^^ ^^ --
35+
36+
error: generic arguments must declare lifetimes, types and associated type bindings in that order
37+
--> $DIR/suggest-move-types.rs:47:80
38+
|
39+
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
40+
| ^ ^ ^ ^^ ^^ ^^ must be declared prior to type parameters
41+
| | | | | |
42+
| | | | | must be declared prior to type parameters
43+
| | | | must be declared prior to type parameters
44+
| | | must be declared prior to associated type bindings
45+
| | must be declared prior to associated type bindings
46+
| must be declared prior to associated type bindings
47+
help: move the parameters
48+
|
49+
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A=(), B=(), C=()>> {
50+
| ^^^ ^^^ ^^^ ^^ ^^ ^^ --
51+
52+
error: type parameters must be declared prior to associated type bindings
53+
--> $DIR/suggest-move-types.rs:55:49
54+
|
55+
LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR type parameters must be declared
56+
| ^ ^ must be declared prior to associated type bindings
57+
| |
58+
| must be declared prior to associated type bindings
59+
help: move the type parameters prior to the first associated type binding
60+
|
61+
LL | struct C<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
62+
| ^^ ^^ --
63+
64+
error: generic arguments must declare lifetimes, types and associated type bindings in that order
65+
--> $DIR/suggest-move-types.rs:62:56
66+
|
67+
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
68+
| ^^ ^ ^^ ^ ^^ must be declared prior to type parameters
69+
| | | | |
70+
| | | | must be declared prior to associated type bindings
71+
| | | must be declared prior to type parameters
72+
| | must be declared prior to associated type bindings
73+
| must be declared prior to type parameters
74+
help: move the parameters
75+
|
76+
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A=(), B=(), C=()>> {
77+
| ^^^ ^^^ ^^^ -- ^^ ^^ --
78+
79+
error: type parameters must be declared prior to associated type bindings
80+
--> $DIR/suggest-move-types.rs:70:43
81+
|
82+
LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR type parameters must be declared
83+
| ^ ^ must be declared prior to associated type bindings
84+
| |
85+
| must be declared prior to associated type bindings
86+
help: move the type parameters prior to the first associated type binding
87+
|
88+
LL | struct D<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
89+
| ^^ ^^ -- --
90+
91+
error: generic arguments must declare lifetimes, types and associated type bindings in that order
92+
--> $DIR/suggest-move-types.rs:77:56
93+
|
94+
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
95+
| ^^ ^ ^^ ^ ^^ must be declared prior to type parameters
96+
| | | | |
97+
| | | | must be declared prior to associated type bindings
98+
| | | must be declared prior to type parameters
99+
| | must be declared prior to associated type bindings
100+
| must be declared prior to type parameters
101+
help: move the parameters
102+
|
103+
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A=(), B=(), C=()>> {
104+
| ^^^ ^^^ ^^^ -- ^^ ^^ -- --
105+
106+
error: aborting due to 8 previous errors
107+

0 commit comments

Comments
 (0)