1
Fork 0

--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
This commit is contained in:
SpanishPear 2022-10-24 00:52:59 +11:00
parent 1c394e1b9a
commit e813132e4f
23 changed files with 292 additions and 2 deletions

View file

@ -284,7 +284,7 @@ impl<'a> Parser<'a> {
self.sess.source_map().span_to_snippet(span)
}
pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let valid_follow = &[
TokenKind::Eq,
TokenKind::Colon,
@ -324,7 +324,60 @@ impl<'a> Parser<'a> {
suggest_raw,
suggest_remove_comma,
};
err.into_diagnostic(&self.sess.span_diagnostic)
let mut err = err.into_diagnostic(&self.sess.span_diagnostic);
// if the token we have is a `<`
// it *might* be a misplaced generic
if self.token == token::Lt {
// all keywords that could have generic applied
let valid_prev_keywords =
[kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait];
// If we've expected an identifier,
// and the current token is a '<'
// if the previous token is a valid keyword
// that might use a generic, then suggest a correct
// generic placement (later on)
let maybe_keyword = self.prev_token.clone();
if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
// if we have a valid keyword, attempt to parse generics
// also obtain the keywords symbol
match self.parse_generics() {
Ok(generic) => {
if let TokenKind::Ident(symbol, _) = maybe_keyword.kind {
let ident_name = symbol.to_string();
// at this point, we've found something like
// `fn <T>id`
// and current token should be Ident with the item name (i.e. the function name)
// if there is a `<` after the fn name, then don't show a suggestion, show help
if !self.look_ahead(1, |t| *t == token::Lt) &&
let Ok(snippet) = self.sess.source_map().span_to_snippet(generic.span) &&
let Ok(ident) = self.sess.source_map().span_to_snippet(self.token.span) {
err.span_suggestion_verbose(
generic.span.to(self.token.span),
format!("place the generic parameter name after the {ident_name} name"),
format!(" {ident}{snippet}"),
Applicability::MachineApplicable,
);
} else {
err.help(format!(
"place the generic parameter name after the {ident_name} name"
));
}
}
}
Err(err) => {
// if there's an error parsing the generics,
// then don't do a misplaced generics suggestion
// and emit the expected ident error instead;
err.cancel();
}
}
}
}
err
}
pub(super) fn expected_one_of_not_found(

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
enum Foo<T> { Variant(T) }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the enum name
//~| SUGGESTION Foo<T>
fn main() {}

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
enum<T> Foo { Variant(T) }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the enum name
//~| SUGGESTION Foo<T>
fn main() {}

View file

@ -0,0 +1,13 @@
error: expected identifier, found `<`
--> $DIR/enum.rs:5:5
|
LL | enum<T> Foo { Variant(T) }
| ^ expected identifier
|
help: place the generic parameter name after the enum name
|
LL | enum Foo<T> { Variant(T) }
| ~~~~~~
error: aborting due to previous error

View file

@ -0,0 +1,9 @@
// Issue: 103366
// there is already an existing generic on f, so don't show a suggestion
#[allow(unused)]
fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the fn name
fn main() {}

View file

@ -0,0 +1,10 @@
error: expected identifier, found `<`
--> $DIR/existing_generics.rs:5:3
|
LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { }
| ^ expected identifier
|
= help: place the generic parameter name after the fn name
error: aborting due to previous error

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the fn name
//~| SUGGESTION f<'a, B: 'a + std::ops::Add<Output = u32>>
fn main() {}

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the fn name
//~| SUGGESTION f<'a, B: 'a + std::ops::Add<Output = u32>>
fn main() {}

View file

@ -0,0 +1,13 @@
error: expected identifier, found `<`
--> $DIR/fn-complex-generics.rs:5:3
|
LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { }
| ^ expected identifier
|
help: place the generic parameter name after the fn name
|
LL | fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { }
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

View file

@ -0,0 +1,8 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// The generics fail to parse here, so don't make any suggestions/help
#[allow(unused)]
fn<~>()> id(x: T) -> T { x }
//~^ ERROR expected identifier, found `<`
fn main() {}

View file

@ -0,0 +1,8 @@
error: expected identifier, found `<`
--> $DIR/fn-invalid-generics.rs:5:3
|
LL | fn<~>()> id(x: T) -> T { x }
| ^ expected identifier
error: aborting due to previous error

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
fn id<T>(x: T) -> T { x }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the fn name
//~| SUGGESTION id<T>
fn main() {}

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
fn<T> id(x: T) -> T { x }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the fn name
//~| SUGGESTION id<T>
fn main() {}

View file

@ -0,0 +1,13 @@
error: expected identifier, found `<`
--> $DIR/fn-simple.rs:5:3
|
LL | fn<T> id(x: T) -> T { x }
| ^ expected identifier
|
help: place the generic parameter name after the fn name
|
LL | fn id<T>(x: T) -> T { x }
| ~~~~~
error: aborting due to previous error

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
struct Foo<T> { x: T }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the struct name
//~| SUGGESTION Foo<T>
fn main() {}

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
struct<T> Foo { x: T }
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the struct name
//~| SUGGESTION Foo<T>
fn main() {}

View file

@ -0,0 +1,13 @@
error: expected identifier, found `<`
--> $DIR/struct.rs:5:7
|
LL | struct<T> Foo { x: T }
| ^ expected identifier
|
help: place the generic parameter name after the struct name
|
LL | struct Foo<T> { x: T }
| ~~~~~~
error: aborting due to previous error

View file

@ -0,0 +1,12 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
trait Foo<T> {
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the trait name
//~| SUGGESTION Foo<T>
}
fn main() {}

View file

@ -0,0 +1,12 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
trait<T> Foo {
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the trait name
//~| SUGGESTION Foo<T>
}
fn main() {}

View file

@ -0,0 +1,13 @@
error: expected identifier, found `<`
--> $DIR/trait.rs:5:6
|
LL | trait<T> Foo {
| ^ expected identifier
|
help: place the generic parameter name after the trait name
|
LL | trait Foo<T> {
| ~~~~~~
error: aborting due to previous error

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
type Foo<T> = T;
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the type name
//~| SUGGESTION Foo<T>
fn main() {}

View file

@ -0,0 +1,10 @@
// Issue: 103366 , Suggest fix for misplaced generic params
// run-rustfix
#[allow(unused)]
type<T> Foo = T;
//~^ ERROR expected identifier, found `<`
//~| HELP place the generic parameter name after the type name
//~| SUGGESTION Foo<T>
fn main() {}

View file

@ -0,0 +1,13 @@
error: expected identifier, found `<`
--> $DIR/type.rs:5:5
|
LL | type<T> Foo = T;
| ^ expected identifier
|
help: place the generic parameter name after the type name
|
LL | type Foo<T> = T;
| ~~~~~~
error: aborting due to previous error