mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Recover better for more delimited sequences
This commit is contained in:
parent
244a48d13d
commit
4f6b5f41d4
20 changed files with 153 additions and 124 deletions
|
@ -1,5 +1,7 @@
|
|||
use super::*;
|
||||
|
||||
pub(super) const ATTRIBUTE_FIRST: TokenSet = TokenSet::new(&[T![#]]);
|
||||
|
||||
pub(super) fn inner_attrs(p: &mut Parser<'_>) {
|
||||
while p.at(T![#]) && p.nth(1) == T![!] {
|
||||
attr(p, true);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
mod atom;
|
||||
|
||||
use crate::grammar::attributes::ATTRIBUTE_FIRST;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub(crate) use self::atom::{block_expr, match_arm_list};
|
||||
|
@ -572,27 +574,11 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
|
|||
fn arg_list(p: &mut Parser<'_>) {
|
||||
assert!(p.at(T!['(']));
|
||||
let m = p.start();
|
||||
p.bump(T!['(']);
|
||||
while !p.at(T![')']) && !p.at(EOF) {
|
||||
// test arg_with_attr
|
||||
// fn main() {
|
||||
// foo(#[attr] 92)
|
||||
// }
|
||||
if !expr(p) {
|
||||
break;
|
||||
}
|
||||
if !p.at(T![,]) {
|
||||
if p.at_ts(EXPR_FIRST) {
|
||||
p.error("expected `,`");
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
p.bump(T![,]);
|
||||
}
|
||||
}
|
||||
p.eat(T![')']);
|
||||
// test arg_with_attr
|
||||
// fn main() {
|
||||
// foo(#[attr] 92)
|
||||
// }
|
||||
delimited(p, T!['('], T![')'], T![,], EXPR_FIRST.union(ATTRIBUTE_FIRST), expr);
|
||||
m.complete(p, ARG_LIST);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ pub(super) fn atom_expr(
|
|||
// fn main() {
|
||||
// 'loop: impl
|
||||
// }
|
||||
p.error("expected a loop");
|
||||
p.error("expected a loop or block");
|
||||
m.complete(p, ERROR);
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -5,27 +5,35 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo
|
|||
if p.at(T![::]) && p.nth(2) == T![<] {
|
||||
m = p.start();
|
||||
p.bump(T![::]);
|
||||
p.bump(T![<]);
|
||||
} else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
|
||||
m = p.start();
|
||||
p.bump(T![<]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
while !p.at(EOF) && !p.at(T![>]) {
|
||||
generic_arg(p);
|
||||
if !p.at(T![>]) && !p.expect(T![,]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.expect(T![>]);
|
||||
delimited(p, T![<], T![>], T![,], GENERIC_ARG_FIRST, generic_arg);
|
||||
m.complete(p, GENERIC_ARG_LIST);
|
||||
}
|
||||
|
||||
const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
|
||||
LIFETIME_IDENT,
|
||||
IDENT,
|
||||
T!['{'],
|
||||
T![true],
|
||||
T![false],
|
||||
T![-],
|
||||
INT_NUMBER,
|
||||
FLOAT_NUMBER,
|
||||
CHAR,
|
||||
BYTE,
|
||||
STRING,
|
||||
BYTE_STRING,
|
||||
])
|
||||
.union(types::TYPE_FIRST);
|
||||
|
||||
// test generic_arg
|
||||
// type T = S<i32>;
|
||||
fn generic_arg(p: &mut Parser<'_>) {
|
||||
fn generic_arg(p: &mut Parser<'_>) -> bool {
|
||||
match p.current() {
|
||||
LIFETIME_IDENT => lifetime_arg(p),
|
||||
T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
|
||||
|
@ -68,8 +76,10 @@ fn generic_arg(p: &mut Parser<'_>) {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => type_arg(p),
|
||||
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
// test lifetime_arg
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::grammar::attributes::ATTRIBUTE_FIRST;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
|
||||
|
@ -11,32 +13,31 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
|
|||
fn generic_param_list(p: &mut Parser<'_>) {
|
||||
assert!(p.at(T![<]));
|
||||
let m = p.start();
|
||||
p.bump(T![<]);
|
||||
delimited(p, T![<], T![>], T![,], GENERIC_PARAM_FIRST.union(ATTRIBUTE_FIRST), |p| {
|
||||
// test generic_param_attribute
|
||||
// fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
|
||||
let m = p.start();
|
||||
attributes::outer_attrs(p);
|
||||
generic_param(p, m)
|
||||
});
|
||||
|
||||
while !p.at(EOF) && !p.at(T![>]) {
|
||||
generic_param(p);
|
||||
if !p.at(T![>]) && !p.expect(T![,]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.expect(T![>]);
|
||||
m.complete(p, GENERIC_PARAM_LIST);
|
||||
}
|
||||
|
||||
fn generic_param(p: &mut Parser<'_>) {
|
||||
let m = p.start();
|
||||
// test generic_param_attribute
|
||||
// fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
|
||||
attributes::outer_attrs(p);
|
||||
const GENERIC_PARAM_FIRST: TokenSet = TokenSet::new(&[IDENT, LIFETIME_IDENT, T![const]]);
|
||||
|
||||
fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
|
||||
match p.current() {
|
||||
LIFETIME_IDENT => lifetime_param(p, m),
|
||||
IDENT => type_param(p, m),
|
||||
T![const] => const_param(p, m),
|
||||
_ => {
|
||||
m.abandon(p);
|
||||
p.err_and_bump("expected type parameter");
|
||||
p.err_and_bump("expected generic parameter");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
// test lifetime_param
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::grammar::attributes::ATTRIBUTE_FIRST;
|
||||
|
||||
use super::*;
|
||||
|
||||
// test struct_item
|
||||
|
@ -141,28 +143,31 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
|
|||
}
|
||||
}
|
||||
|
||||
const TUPLE_FIELD_FIRST: TokenSet =
|
||||
types::TYPE_FIRST.union(ATTRIBUTE_FIRST).union(VISIBILITY_FIRST);
|
||||
|
||||
fn tuple_field_list(p: &mut Parser<'_>) {
|
||||
assert!(p.at(T!['(']));
|
||||
let m = p.start();
|
||||
p.bump(T!['(']);
|
||||
while !p.at(T![')']) && !p.at(EOF) {
|
||||
delimited(p, T!['('], T![')'], T![,], TUPLE_FIELD_FIRST, |p| {
|
||||
let m = p.start();
|
||||
// test tuple_field_attrs
|
||||
// struct S (#[attr] f32);
|
||||
attributes::outer_attrs(p);
|
||||
opt_visibility(p, true);
|
||||
let has_vis = opt_visibility(p, true);
|
||||
if !p.at_ts(types::TYPE_FIRST) {
|
||||
p.error("expected a type");
|
||||
m.complete(p, ERROR);
|
||||
break;
|
||||
if has_vis {
|
||||
m.complete(p, ERROR);
|
||||
} else {
|
||||
m.abandon(p);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
types::type_(p);
|
||||
m.complete(p, TUPLE_FIELD);
|
||||
true
|
||||
});
|
||||
|
||||
if !p.at(T![')']) {
|
||||
p.expect(T![,]);
|
||||
}
|
||||
}
|
||||
p.expect(T![')']);
|
||||
m.complete(p, TUPLE_FIELD_LIST);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::grammar::attributes::ATTRIBUTE_FIRST;
|
||||
|
||||
use super::*;
|
||||
|
||||
// test param_list
|
||||
|
@ -66,14 +68,20 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) {
|
|||
}
|
||||
};
|
||||
|
||||
if !p.at_ts(PARAM_FIRST) {
|
||||
if !p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) {
|
||||
p.error("expected value parameter");
|
||||
m.abandon(p);
|
||||
break;
|
||||
}
|
||||
param(p, m, flavor);
|
||||
if !p.at(ket) {
|
||||
p.expect(T![,]);
|
||||
if !p.at(T![,]) {
|
||||
if p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) {
|
||||
p.error("expected `,`");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
p.bump(T![,]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue