Suggest appropriate place for lifetime when declared after type arguments
This commit is contained in:
parent
e9bca7a993
commit
79ee8f329d
8 changed files with 102 additions and 8 deletions
|
@ -5178,8 +5178,10 @@ impl<'a> Parser<'a> {
|
||||||
/// Parses (possibly empty) list of lifetime and type parameters, possibly including
|
/// Parses (possibly empty) list of lifetime and type parameters, possibly including
|
||||||
/// trailing comma and erroneous trailing attributes.
|
/// trailing comma and erroneous trailing attributes.
|
||||||
crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
|
crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
|
||||||
|
let mut lifetimes = Vec::new();
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
let mut seen_ty_param = false;
|
let mut seen_ty_param: Option<Span> = None;
|
||||||
|
let mut last_comma_span = None;
|
||||||
loop {
|
loop {
|
||||||
let attrs = self.parse_outer_attributes()?;
|
let attrs = self.parse_outer_attributes()?;
|
||||||
if self.check_lifetime() {
|
if self.check_lifetime() {
|
||||||
|
@ -5190,25 +5192,48 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
params.push(ast::GenericParam {
|
lifetimes.push(ast::GenericParam {
|
||||||
ident: lifetime.ident,
|
ident: lifetime.ident,
|
||||||
id: lifetime.id,
|
id: lifetime.id,
|
||||||
attrs: attrs.into(),
|
attrs: attrs.into(),
|
||||||
bounds,
|
bounds,
|
||||||
kind: ast::GenericParamKind::Lifetime,
|
kind: ast::GenericParamKind::Lifetime,
|
||||||
});
|
});
|
||||||
if seen_ty_param {
|
if let Some(sp) = seen_ty_param {
|
||||||
self.span_err(self.prev_span,
|
let param_span = self.prev_span;
|
||||||
"lifetime parameters must be declared prior to type parameters");
|
let ate_comma = self.eat(&token::Comma);
|
||||||
|
let remove_sp = if ate_comma {
|
||||||
|
param_span.until(self.span)
|
||||||
|
} else {
|
||||||
|
last_comma_span.unwrap_or(param_span).to(param_span)
|
||||||
|
};
|
||||||
|
let mut err = self.struct_span_err(
|
||||||
|
self.prev_span,
|
||||||
|
"lifetime parameters must be declared prior to type parameters",
|
||||||
|
);
|
||||||
|
if let Ok(snippet) = self.sess.source_map().span_to_snippet(param_span) {
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"move the lifetime parameter prior to the first type parameter",
|
||||||
|
vec![
|
||||||
|
(remove_sp, String::new()),
|
||||||
|
(sp.shrink_to_lo(), format!("{}, ", snippet)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
if ate_comma {
|
||||||
|
last_comma_span = Some(self.prev_span);
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if self.check_ident() {
|
} else if self.check_ident() {
|
||||||
// Parse type parameter.
|
// Parse type parameter.
|
||||||
params.push(self.parse_ty_param(attrs)?);
|
params.push(self.parse_ty_param(attrs)?);
|
||||||
seen_ty_param = true;
|
seen_ty_param = Some(self.prev_span);
|
||||||
} else {
|
} else {
|
||||||
// Check for trailing attributes and stop parsing.
|
// Check for trailing attributes and stop parsing.
|
||||||
if !attrs.is_empty() {
|
if !attrs.is_empty() {
|
||||||
let param_kind = if seen_ty_param { "type" } else { "lifetime" };
|
let param_kind = if seen_ty_param.is_some() { "type" } else { "lifetime" };
|
||||||
self.span_err(attrs[0].span,
|
self.span_err(attrs[0].span,
|
||||||
&format!("trailing attribute after {} parameters", param_kind));
|
&format!("trailing attribute after {} parameters", param_kind));
|
||||||
}
|
}
|
||||||
|
@ -5218,8 +5243,10 @@ impl<'a> Parser<'a> {
|
||||||
if !self.eat(&token::Comma) {
|
if !self.eat(&token::Comma) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
last_comma_span = Some(self.prev_span);
|
||||||
}
|
}
|
||||||
Ok(params)
|
lifetimes.extend(params); // ensure the correct order of lifetimes and type params
|
||||||
|
Ok(lifetimes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a set of optional generic type parameter declarations. Where
|
/// Parse a set of optional generic type parameter declarations. Where
|
||||||
|
|
|
@ -3,6 +3,10 @@ error: lifetime parameters must be declared prior to type parameters
|
||||||
|
|
|
|
||||||
LL | enum X<'a, T, 'b> {
|
LL | enum X<'a, T, 'b> {
|
||||||
| ^^
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | enum X<'a, 'b, T> {
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ error: lifetime parameters must be declared prior to type parameters
|
||||||
|
|
|
|
||||||
LL | fn foo<'a, T, 'b>(x: &'a T) {}
|
LL | fn foo<'a, T, 'b>(x: &'a T) {}
|
||||||
| ^^
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | fn foo<'a, 'b, T>(x: &'a T) {}
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ error: lifetime parameters must be declared prior to type parameters
|
||||||
|
|
|
|
||||||
LL | impl<'a, T, 'b> X {}
|
LL | impl<'a, T, 'b> X {}
|
||||||
| ^^
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | impl<'a, 'b, T> X {}
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ error: lifetime parameters must be declared prior to type parameters
|
||||||
|
|
|
|
||||||
LL | struct X<'a, T, 'b> {
|
LL | struct X<'a, T, 'b> {
|
||||||
| ^^
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | struct X<'a, 'b, T> {
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ error: lifetime parameters must be declared prior to type parameters
|
||||||
|
|
|
|
||||||
LL | trait Foo<'a, T, 'b> {}
|
LL | trait Foo<'a, T, 'b> {}
|
||||||
| ^^
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | trait Foo<'a, 'b, T> {}
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
15
src/test/ui/suggestions/suggest-move-lifetimes.rs
Normal file
15
src/test/ui/suggestions/suggest-move-lifetimes.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
struct A<T, 'a> {
|
||||||
|
t: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct B<T, 'a, U> {
|
||||||
|
t: &'a T,
|
||||||
|
u: U,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C<T, U, 'a> {
|
||||||
|
t: &'a T,
|
||||||
|
u: U,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
32
src/test/ui/suggestions/suggest-move-lifetimes.stderr
Normal file
32
src/test/ui/suggestions/suggest-move-lifetimes.stderr
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
error: lifetime parameters must be declared prior to type parameters
|
||||||
|
--> $DIR/suggest-move-lifetimes.rs:1:13
|
||||||
|
|
|
||||||
|
LL | struct A<T, 'a> {
|
||||||
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | struct A<'a, T> {
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
|
error: lifetime parameters must be declared prior to type parameters
|
||||||
|
--> $DIR/suggest-move-lifetimes.rs:5:15
|
||||||
|
|
|
||||||
|
LL | struct B<T, 'a, U> {
|
||||||
|
| ^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | struct B<'a, T, U> {
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
|
error: lifetime parameters must be declared prior to type parameters
|
||||||
|
--> $DIR/suggest-move-lifetimes.rs:10:16
|
||||||
|
|
|
||||||
|
LL | struct C<T, U, 'a> {
|
||||||
|
| ^^
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | struct C<T, 'a, U> {
|
||||||
|
| ^^^ --
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue