Skip to content

Commit 463e623

Browse files
committed
Suggestion moving types before associated types.
This commit extends existing suggestions to move lifetimes before types in generic arguments to also suggest moving types behind associated type bindings.
1 parent 095b44c commit 463e623

File tree

4 files changed

+147
-15
lines changed

4 files changed

+147
-15
lines changed

src/libsyntax/parse/parser.rs

+52-15
Original file line numberDiff line numberDiff line change
@@ -5530,22 +5530,31 @@ impl<'a> Parser<'a> {
55305530
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
55315531
let mut args = Vec::new();
55325532
let mut bindings = Vec::new();
5533+
55335534
let mut seen_type = false;
55345535
let mut seen_binding = false;
5536+
5537+
let mut last_comma_span = None;
55355538
let mut first_type_or_binding_span: Option<Span> = None;
5539+
let mut first_binding_span: Option<Span> = None;
5540+
55365541
let mut bad_lifetime_pos = vec![];
5537-
let mut last_comma_span = None;
5538-
let mut suggestions = vec![];
5542+
let mut bad_type_pos = vec![];
5543+
5544+
let mut lifetime_suggestions = vec![];
5545+
let mut type_suggestions = vec![];
55395546
loop {
55405547
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
55415548
// Parse lifetime argument.
55425549
args.push(GenericArg::Lifetime(self.expect_lifetime()));
5550+
55435551
if seen_type || seen_binding {
55445552
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
55455553
bad_lifetime_pos.push(self.prev_span);
5554+
55465555
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
5547-
suggestions.push((remove_sp, String::new()));
5548-
suggestions.push((
5556+
lifetime_suggestions.push((remove_sp, String::new()));
5557+
lifetime_suggestions.push((
55495558
first_type_or_binding_span.unwrap().shrink_to_lo(),
55505559
format!("{}, ", snippet)));
55515560
}
@@ -5563,24 +5572,29 @@ impl<'a> Parser<'a> {
55635572
ty,
55645573
span,
55655574
});
5575+
55665576
seen_binding = true;
55675577
if first_type_or_binding_span.is_none() {
55685578
first_type_or_binding_span = Some(span);
55695579
}
5580+
if first_binding_span.is_none() {
5581+
first_binding_span = Some(span);
5582+
}
55705583
} else if self.check_type() {
55715584
// Parse type argument.
55725585
let ty_param = self.parse_ty()?;
55735586
if seen_binding {
5574-
self.struct_span_err(
5575-
ty_param.span,
5576-
"type parameters must be declared prior to associated type bindings"
5577-
)
5578-
.span_label(
5579-
ty_param.span,
5580-
"must be declared prior to associated type bindings",
5581-
)
5582-
.emit();
5587+
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
5588+
bad_type_pos.push(self.prev_span);
5589+
5590+
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
5591+
type_suggestions.push((remove_sp, String::new()));
5592+
type_suggestions.push((
5593+
first_binding_span.unwrap().shrink_to_lo(),
5594+
format!("{}, ", snippet)));
5595+
}
55835596
}
5597+
55845598
if first_type_or_binding_span.is_none() {
55855599
first_type_or_binding_span = Some(ty_param.span);
55865600
}
@@ -5596,6 +5610,7 @@ impl<'a> Parser<'a> {
55965610
last_comma_span = Some(self.prev_span);
55975611
}
55985612
}
5613+
55995614
if !bad_lifetime_pos.is_empty() {
56005615
let mut err = self.struct_span_err(
56015616
bad_lifetime_pos.clone(),
@@ -5604,18 +5619,40 @@ impl<'a> Parser<'a> {
56045619
for sp in &bad_lifetime_pos {
56055620
err.span_label(*sp, "must be declared prior to type parameters");
56065621
}
5607-
if !suggestions.is_empty() {
5622+
if !lifetime_suggestions.is_empty() {
56085623
err.multipart_suggestion_with_applicability(
56095624
&format!(
56105625
"move the lifetime parameter{} prior to the first type parameter",
56115626
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
56125627
),
5613-
suggestions,
5628+
lifetime_suggestions,
56145629
Applicability::MachineApplicable,
56155630
);
56165631
}
56175632
err.emit();
56185633
}
5634+
5635+
if !bad_type_pos.is_empty() {
5636+
let mut err = self.struct_span_err(
5637+
bad_type_pos.clone(),
5638+
"type parameters must be declared prior to associated type bindings"
5639+
);
5640+
for sp in &bad_type_pos {
5641+
err.span_label(*sp, "must be declared prior to associated type bindings");
5642+
}
5643+
if !type_suggestions.is_empty() {
5644+
err.multipart_suggestion_with_applicability(
5645+
&format!(
5646+
"move the type parameter{} prior to the first associated type binding",
5647+
if bad_type_pos.len() > 1 { "s" } else { "" },
5648+
),
5649+
type_suggestions,
5650+
Applicability::MachineApplicable,
5651+
);
5652+
}
5653+
err.emit();
5654+
}
5655+
56195656
Ok((args, bindings))
56205657
}
56215658

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,42 @@
1+
#![allow(warnings)]
2+
3+
// This test verifies that the suggestion to move types before associated type bindings
4+
// is correct.
5+
6+
trait One<T> {
7+
type A;
8+
}
9+
10+
trait Three<T, U, V> {
11+
type A;
12+
type B;
13+
type C;
14+
}
15+
16+
struct A<T, M: One<A=(), T>> { //~ ERROR type parameters must be declared
17+
m: M,
18+
t: T,
19+
}
20+
21+
struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR type parameters must be declared
22+
m: M,
23+
t: T,
24+
u: U,
25+
v: V,
26+
}
27+
28+
struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR type parameters must be declared
29+
m: M,
30+
t: T,
31+
u: U,
32+
v: V,
33+
}
34+
35+
struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR type parameters must be declared
36+
m: M,
37+
t: T,
38+
u: U,
39+
v: V,
40+
}
41+
42+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error: type parameters must be declared prior to associated type bindings
2+
--> $DIR/suggest-move-types.rs:16: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: type parameters must be declared prior to associated type bindings
12+
--> $DIR/suggest-move-types.rs:21:46
13+
|
14+
LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> { //~ ERROR type parameters must be declared
15+
| ^ ^ ^ must be declared prior to associated type bindings
16+
| | |
17+
| | must be declared prior to associated type bindings
18+
| must be declared prior to associated type bindings
19+
help: move the type parameters prior to the first associated type binding
20+
|
21+
LL | struct B<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
22+
| ^^ ^^ ^^ --
23+
24+
error: type parameters must be declared prior to associated type bindings
25+
--> $DIR/suggest-move-types.rs:28:49
26+
|
27+
LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> { //~ ERROR type parameters must be declared
28+
| ^ ^ must be declared prior to associated type bindings
29+
| |
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 C<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
34+
| ^^ ^^ --
35+
36+
error: type parameters must be declared prior to associated type bindings
37+
--> $DIR/suggest-move-types.rs:35:43
38+
|
39+
LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> { //~ ERROR type parameters must be declared
40+
| ^ ^ must be declared prior to associated type bindings
41+
| |
42+
| must be declared prior to associated type bindings
43+
help: move the type parameters prior to the first associated type binding
44+
|
45+
LL | struct D<T, U, V, M: Three<T, U, V, A=(), B=(), C=()>> { //~ ERROR type parameters must be declared
46+
| ^^ ^^ -- --
47+
48+
error: aborting due to 4 previous errors
49+

0 commit comments

Comments
 (0)