Skip to content

Commit e813132

Browse files
committed
--wip-- [skip ci]
--wip-- [skip ci] get the generic text and put it int he suggestion, but suggestion not working on derive subdiagnostic refactor away from derives and use span_suggestion() instead. Show's the correct(?) generic contents, but overwrites the fn name :( x fmt drop commented code and s/todo/fixme get the correct diagnostic for functions, at least x fmt remove some debugs remove format remove debugs remove useless change remove useless change remove legacy approach correct lookahead + error message contains the ident name fmt refactor code tests add tests remoev debug remove comment
1 parent 1c394e1 commit e813132

23 files changed

+292
-2
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl<'a> Parser<'a> {
284284
self.sess.source_map().span_to_snippet(span)
285285
}
286286

287-
pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
287+
pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
288288
let valid_follow = &[
289289
TokenKind::Eq,
290290
TokenKind::Colon,
@@ -324,7 +324,60 @@ impl<'a> Parser<'a> {
324324
suggest_raw,
325325
suggest_remove_comma,
326326
};
327-
err.into_diagnostic(&self.sess.span_diagnostic)
327+
let mut err = err.into_diagnostic(&self.sess.span_diagnostic);
328+
329+
// if the token we have is a `<`
330+
// it *might* be a misplaced generic
331+
if self.token == token::Lt {
332+
// all keywords that could have generic applied
333+
let valid_prev_keywords =
334+
[kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait];
335+
336+
// If we've expected an identifier,
337+
// and the current token is a '<'
338+
// if the previous token is a valid keyword
339+
// that might use a generic, then suggest a correct
340+
// generic placement (later on)
341+
let maybe_keyword = self.prev_token.clone();
342+
if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
343+
// if we have a valid keyword, attempt to parse generics
344+
// also obtain the keywords symbol
345+
match self.parse_generics() {
346+
Ok(generic) => {
347+
if let TokenKind::Ident(symbol, _) = maybe_keyword.kind {
348+
let ident_name = symbol.to_string();
349+
// at this point, we've found something like
350+
// `fn <T>id`
351+
// and current token should be Ident with the item name (i.e. the function name)
352+
// if there is a `<` after the fn name, then don't show a suggestion, show help
353+
354+
if !self.look_ahead(1, |t| *t == token::Lt) &&
355+
let Ok(snippet) = self.sess.source_map().span_to_snippet(generic.span) &&
356+
let Ok(ident) = self.sess.source_map().span_to_snippet(self.token.span) {
357+
err.span_suggestion_verbose(
358+
generic.span.to(self.token.span),
359+
format!("place the generic parameter name after the {ident_name} name"),
360+
format!(" {ident}{snippet}"),
361+
Applicability::MachineApplicable,
362+
);
363+
} else {
364+
err.help(format!(
365+
"place the generic parameter name after the {ident_name} name"
366+
));
367+
}
368+
}
369+
}
370+
Err(err) => {
371+
// if there's an error parsing the generics,
372+
// then don't do a misplaced generics suggestion
373+
// and emit the expected ident error instead;
374+
err.cancel();
375+
}
376+
}
377+
}
378+
}
379+
380+
err
328381
}
329382

330383
pub(super) fn expected_one_of_not_found(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
enum Foo<T> { Variant(T) }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the enum name
8+
//~| SUGGESTION Foo<T>
9+
10+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
enum<T> Foo { Variant(T) }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the enum name
8+
//~| SUGGESTION Foo<T>
9+
10+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/enum.rs:5:5
3+
|
4+
LL | enum<T> Foo { Variant(T) }
5+
| ^ expected identifier
6+
|
7+
help: place the generic parameter name after the enum name
8+
|
9+
LL | enum Foo<T> { Variant(T) }
10+
| ~~~~~~
11+
12+
error: aborting due to previous error
13+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Issue: 103366
2+
// there is already an existing generic on f, so don't show a suggestion
3+
4+
#[allow(unused)]
5+
fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the fn name
8+
9+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/existing_generics.rs:5:3
3+
|
4+
LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { }
5+
| ^ expected identifier
6+
|
7+
= help: place the generic parameter name after the fn name
8+
9+
error: aborting due to previous error
10+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the fn name
8+
//~| SUGGESTION f<'a, B: 'a + std::ops::Add<Output = u32>>
9+
10+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the fn name
8+
//~| SUGGESTION f<'a, B: 'a + std::ops::Add<Output = u32>>
9+
10+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/fn-complex-generics.rs:5:3
3+
|
4+
LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
5+
| ^ expected identifier
6+
|
7+
help: place the generic parameter name after the fn name
8+
|
9+
LL | fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { }
10+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11+
12+
error: aborting due to previous error
13+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// The generics fail to parse here, so don't make any suggestions/help
3+
4+
#[allow(unused)]
5+
fn<~>()> id(x: T) -> T { x }
6+
//~^ ERROR expected identifier, found `<`
7+
8+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/fn-invalid-generics.rs:5:3
3+
|
4+
LL | fn<~>()> id(x: T) -> T { x }
5+
| ^ expected identifier
6+
7+
error: aborting due to previous error
8+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
fn id<T>(x: T) -> T { x }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the fn name
8+
//~| SUGGESTION id<T>
9+
10+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
fn<T> id(x: T) -> T { x }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the fn name
8+
//~| SUGGESTION id<T>
9+
10+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/fn-simple.rs:5:3
3+
|
4+
LL | fn<T> id(x: T) -> T { x }
5+
| ^ expected identifier
6+
|
7+
help: place the generic parameter name after the fn name
8+
|
9+
LL | fn id<T>(x: T) -> T { x }
10+
| ~~~~~
11+
12+
error: aborting due to previous error
13+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
struct Foo<T> { x: T }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the struct name
8+
//~| SUGGESTION Foo<T>
9+
10+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
struct<T> Foo { x: T }
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the struct name
8+
//~| SUGGESTION Foo<T>
9+
10+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/struct.rs:5:7
3+
|
4+
LL | struct<T> Foo { x: T }
5+
| ^ expected identifier
6+
|
7+
help: place the generic parameter name after the struct name
8+
|
9+
LL | struct Foo<T> { x: T }
10+
| ~~~~~~
11+
12+
error: aborting due to previous error
13+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
trait Foo<T> {
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the trait name
8+
//~| SUGGESTION Foo<T>
9+
}
10+
11+
12+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
trait<T> Foo {
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the trait name
8+
//~| SUGGESTION Foo<T>
9+
}
10+
11+
12+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/trait.rs:5:6
3+
|
4+
LL | trait<T> Foo {
5+
| ^ expected identifier
6+
|
7+
help: place the generic parameter name after the trait name
8+
|
9+
LL | trait Foo<T> {
10+
| ~~~~~~
11+
12+
error: aborting due to previous error
13+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
type Foo<T> = T;
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the type name
8+
//~| SUGGESTION Foo<T>
9+
10+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Issue: 103366 , Suggest fix for misplaced generic params
2+
// run-rustfix
3+
4+
#[allow(unused)]
5+
type<T> Foo = T;
6+
//~^ ERROR expected identifier, found `<`
7+
//~| HELP place the generic parameter name after the type name
8+
//~| SUGGESTION Foo<T>
9+
10+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `<`
2+
--> $DIR/type.rs:5:5
3+
|
4+
LL | type<T> Foo = T;
5+
| ^ expected identifier
6+
|
7+
help: place the generic parameter name after the type name
8+
|
9+
LL | type Foo<T> = T;
10+
| ~~~~~~
11+
12+
error: aborting due to previous error
13+

0 commit comments

Comments
 (0)