Suggest correct location for lifetime parameters in use
This commit is contained in:
parent
db740313e0
commit
28ea03e114
@ -5330,23 +5330,28 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
|
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
|
||||||
/// possibly including trailing comma.
|
/// possibly including trailing comma.
|
||||||
fn parse_generic_args(&mut self)
|
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
||||||
-> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
let mut bindings = Vec::new();
|
let mut bindings = Vec::new();
|
||||||
let mut seen_type = false;
|
let mut seen_type = false;
|
||||||
let mut seen_binding = false;
|
let mut seen_binding = false;
|
||||||
|
let mut first_type_or_binding_span: Option<Span> = None;
|
||||||
|
let mut bad_lifetime_pos = vec![];
|
||||||
|
let mut last_comma_span = None;
|
||||||
|
let mut suggestions = vec![];
|
||||||
loop {
|
loop {
|
||||||
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
||||||
// Parse lifetime argument.
|
// Parse lifetime argument.
|
||||||
args.push(GenericArg::Lifetime(self.expect_lifetime()));
|
args.push(GenericArg::Lifetime(self.expect_lifetime()));
|
||||||
if seen_type || seen_binding {
|
if seen_type || seen_binding {
|
||||||
self.struct_span_err(
|
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
|
||||||
self.prev_span,
|
bad_lifetime_pos.push(self.prev_span);
|
||||||
"lifetime parameters must be declared prior to type parameters"
|
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
|
||||||
)
|
suggestions.push((remove_sp, String::new()));
|
||||||
.span_label(self.prev_span, "must be declared prior to type parameters")
|
suggestions.push((
|
||||||
.emit();
|
first_type_or_binding_span.unwrap().shrink_to_lo(),
|
||||||
|
format!("{}, ", snippet)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
|
} else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
|
||||||
// Parse associated type binding.
|
// Parse associated type binding.
|
||||||
@ -5354,13 +5359,17 @@ impl<'a> Parser<'a> {
|
|||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
self.bump();
|
self.bump();
|
||||||
let ty = self.parse_ty()?;
|
let ty = self.parse_ty()?;
|
||||||
|
let span = lo.to(self.prev_span);
|
||||||
bindings.push(TypeBinding {
|
bindings.push(TypeBinding {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
ident,
|
ident,
|
||||||
ty,
|
ty,
|
||||||
span: lo.to(self.prev_span),
|
span,
|
||||||
});
|
});
|
||||||
seen_binding = true;
|
seen_binding = true;
|
||||||
|
if first_type_or_binding_span.is_none() {
|
||||||
|
first_type_or_binding_span = Some(span);
|
||||||
|
}
|
||||||
} else if self.check_type() {
|
} else if self.check_type() {
|
||||||
// Parse type argument.
|
// Parse type argument.
|
||||||
let ty_param = self.parse_ty()?;
|
let ty_param = self.parse_ty()?;
|
||||||
@ -5375,6 +5384,9 @@ impl<'a> Parser<'a> {
|
|||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
if first_type_or_binding_span.is_none() {
|
||||||
|
first_type_or_binding_span = Some(ty_param.span);
|
||||||
|
}
|
||||||
args.push(GenericArg::Type(ty_param));
|
args.push(GenericArg::Type(ty_param));
|
||||||
seen_type = true;
|
seen_type = true;
|
||||||
} else {
|
} else {
|
||||||
@ -5383,8 +5395,30 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
if !self.eat(&token::Comma) {
|
if !self.eat(&token::Comma) {
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
last_comma_span = Some(self.prev_span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !bad_lifetime_pos.is_empty() {
|
||||||
|
let mut err = self.struct_span_err(
|
||||||
|
bad_lifetime_pos.clone(),
|
||||||
|
"lifetime parameters must be declared prior to type parameters"
|
||||||
|
);
|
||||||
|
for sp in &bad_lifetime_pos {
|
||||||
|
err.span_label(*sp, "must be declared prior to type parameters");
|
||||||
|
}
|
||||||
|
if !suggestions.is_empty() {
|
||||||
|
err.multipart_suggestion_with_applicability(
|
||||||
|
&format!(
|
||||||
|
"move the lifetime parameter{} prior to the first type parameter",
|
||||||
|
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
|
||||||
|
),
|
||||||
|
suggestions,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
Ok((args, bindings))
|
Ok((args, bindings))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
fn main() {
|
// can't run rustfix because it doesn't handle multipart suggestions correctly
|
||||||
(0..4)
|
// compile-flags: -Zborrowck=mir
|
||||||
.map(|x| x * 2)
|
// we need the above to avoid ast borrowck failure in recovered code
|
||||||
.collect::<Vec<'a, usize, 'b>>()
|
|
||||||
//~^ ERROR lifetime parameters must be declared prior to type parameters
|
struct S<'a, T> {
|
||||||
//~| ERROR use of undeclared lifetime name
|
a: &'a T,
|
||||||
//~| ERROR use of undeclared lifetime name
|
b: &'a T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn foo<'a, 'b>(start: &'a usize, end: &'a usize) {
|
||||||
|
let _x = (*start..*end)
|
||||||
|
.map(|x| S { a: start, b: end })
|
||||||
|
.collect::<Vec<S<_, 'a>>>();
|
||||||
|
//~^ ERROR lifetime parameters must be declared prior to type parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
@ -1,21 +1,12 @@
|
|||||||
error: lifetime parameters must be declared prior to type parameters
|
error: lifetime parameters must be declared prior to type parameters
|
||||||
--> $DIR/issue-14303-fncall.rs:4:31
|
--> $DIR/issue-14303-fncall.rs:13:29
|
||||||
|
|
|
|
||||||
LL | .collect::<Vec<'a, usize, 'b>>()
|
LL | .collect::<Vec<S<_, 'a>>>();
|
||||||
| ^^ must be declared prior to type parameters
|
| ^^ must be declared prior to type parameters
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
error[E0261]: use of undeclared lifetime name `'a`
|
|
||||||
--> $DIR/issue-14303-fncall.rs:4:20
|
|
||||||
|
|
|
|
||||||
LL | .collect::<Vec<'a, usize, 'b>>()
|
LL | .collect::<Vec<S<'a, _>>>();
|
||||||
| ^^ undeclared lifetime
|
| ^^^ --
|
||||||
|
|
||||||
error[E0261]: use of undeclared lifetime name `'b`
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-14303-fncall.rs:4:31
|
|
||||||
|
|
|
||||||
LL | .collect::<Vec<'a, usize, 'b>>()
|
|
||||||
| ^^ undeclared lifetime
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0261`.
|
|
||||||
|
@ -9,6 +9,5 @@ mod foo {
|
|||||||
|
|
||||||
fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
|
fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
|
||||||
//~^ ERROR lifetime parameters must be declared prior to type parameters
|
//~^ ERROR lifetime parameters must be declared prior to type parameters
|
||||||
//~| ERROR lifetime parameters must be declared prior to type parameters
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -2,13 +2,13 @@ error: lifetime parameters must be declared prior to type parameters
|
|||||||
--> $DIR/issue-14303-path.rs:10:40
|
--> $DIR/issue-14303-path.rs:10:40
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
|
LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
|
||||||
| ^^ must be declared prior to type parameters
|
| ^^ ^^ must be declared prior to type parameters
|
||||||
|
| |
|
||||||
error: lifetime parameters must be declared prior to type parameters
|
| must be declared prior to type parameters
|
||||||
--> $DIR/issue-14303-path.rs:10:44
|
help: move the lifetime parameters prior to the first type parameter
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
|
LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, 'b, 'c, T>) {}
|
||||||
| ^^ must be declared prior to type parameters
|
| ^^^ ^^^ --
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// A few contrived examples where lifetime should (or should not) be parsed as an object type.
|
// A few contrived examples where lifetime should (or should not) be parsed as an object type.
|
||||||
// Lifetimes parsed as types are still rejected later by semantic checks.
|
// Lifetimes parsed as types are still rejected later by semantic checks.
|
||||||
|
|
||||||
// compile-flags: -Z continue-parse-after-error
|
|
||||||
|
|
||||||
struct S<'a, T>(&'a u8, T);
|
struct S<'a, T>(&'a u8, T);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -1,29 +1,33 @@
|
|||||||
error: lifetime parameters must be declared prior to type parameters
|
error: lifetime parameters must be declared prior to type parameters
|
||||||
--> $DIR/trait-object-vs-lifetime.rs:16:25
|
--> $DIR/trait-object-vs-lifetime.rs:14:25
|
||||||
|
|
|
|
||||||
LL | let _: S<'static +, 'static>;
|
LL | let _: S<'static +, 'static>;
|
||||||
| ^^^^^^^ must be declared prior to type parameters
|
| ^^^^^^^ must be declared prior to type parameters
|
||||||
|
help: move the lifetime parameter prior to the first type parameter
|
||||||
|
|
|
||||||
|
LL | let _: S<'static, 'static +>;
|
||||||
|
| ^^^^^^^^ --
|
||||||
|
|
||||||
error[E0224]: at least one non-builtin trait is required for an object type
|
error[E0224]: at least one non-builtin trait is required for an object type
|
||||||
--> $DIR/trait-object-vs-lifetime.rs:11:23
|
--> $DIR/trait-object-vs-lifetime.rs:9:23
|
||||||
|
|
|
|
||||||
LL | let _: S<'static, 'static +>;
|
LL | let _: S<'static, 'static +>;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error[E0107]: wrong number of lifetime arguments: expected 1, found 2
|
error[E0107]: wrong number of lifetime arguments: expected 1, found 2
|
||||||
--> $DIR/trait-object-vs-lifetime.rs:13:23
|
--> $DIR/trait-object-vs-lifetime.rs:11:23
|
||||||
|
|
|
|
||||||
LL | let _: S<'static, 'static>;
|
LL | let _: S<'static, 'static>;
|
||||||
| ^^^^^^^ unexpected lifetime argument
|
| ^^^^^^^ unexpected lifetime argument
|
||||||
|
|
||||||
error[E0107]: wrong number of type arguments: expected 1, found 0
|
error[E0107]: wrong number of type arguments: expected 1, found 0
|
||||||
--> $DIR/trait-object-vs-lifetime.rs:13:12
|
--> $DIR/trait-object-vs-lifetime.rs:11:12
|
||||||
|
|
|
|
||||||
LL | let _: S<'static, 'static>;
|
LL | let _: S<'static, 'static>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^ expected 1 type argument
|
| ^^^^^^^^^^^^^^^^^^^ expected 1 type argument
|
||||||
|
|
||||||
error[E0224]: at least one non-builtin trait is required for an object type
|
error[E0224]: at least one non-builtin trait is required for an object type
|
||||||
--> $DIR/trait-object-vs-lifetime.rs:16:14
|
--> $DIR/trait-object-vs-lifetime.rs:14:14
|
||||||
|
|
|
|
||||||
LL | let _: S<'static +, 'static>;
|
LL | let _: S<'static +, 'static>;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
Loading…
x
Reference in New Issue
Block a user