Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4f6b5f4

Browse files
committed
Recover better for more delimited sequences
1 parent 244a48d commit 4f6b5f4

20 files changed

+153
-124
lines changed

crates/hir-def/src/macro_expansion_tests/mbe/regression.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,6 @@ macro_rules! rgb_color {
830830
/* parse error: expected COMMA */
831831
/* parse error: expected R_ANGLE */
832832
/* parse error: expected SEMICOLON */
833-
/* parse error: expected SEMICOLON */
834833
/* parse error: expected expression, item or let statement */
835834
pub fn new() {
836835
let _ = 0as u32<<(8+8);
@@ -848,21 +847,21 @@ pub fn new() {
848847
849848
850849
851-
// LET_STMT@11..27
850+
// LET_STMT@11..28
852851
853852
854853
855854
856-
// CAST_EXPR@16..27
855+
// CAST_EXPR@16..28
857856
858857
859858
860-
// PATH_TYPE@19..27
861-
// PATH@19..27
862-
// PATH_SEGMENT@19..27
859+
// PATH_TYPE@19..28
860+
// PATH@19..28
861+
// PATH_SEGMENT@19..28
863862
864863
865-
// GENERIC_ARG_LIST@22..27
864+
// GENERIC_ARG_LIST@22..28
866865
867866
868867
@@ -877,9 +876,9 @@ pub fn new() {
877876
878877
879878
880-
// EXPR_STMT@27..28
881-
882-
879+
// CONST_ARG@27..28
880+
881+
883882
884883
885884

crates/ide/src/syntax_highlighting/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,5 +1126,5 @@ fn benchmark_syntax_highlighting_parser() {
11261126
.filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
11271127
.count()
11281128
};
1129-
assert_eq!(hash, 1609);
1129+
assert_eq!(hash, 1608);
11301130
}

crates/parser/src/grammar.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ impl BlockLike {
200200
}
201201
}
202202

203+
const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]);
204+
203205
fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
204206
match p.current() {
205207
T![pub] => {
@@ -340,3 +342,31 @@ fn error_block(p: &mut Parser<'_>, message: &str) {
340342
p.eat(T!['}']);
341343
m.complete(p, ERROR);
342344
}
345+
346+
/// The `parser` passed this is required to at least consume one token if it returns `true`.
347+
/// If the `parser` returns false, parsing will stop.
348+
fn delimited(
349+
p: &mut Parser<'_>,
350+
bra: SyntaxKind,
351+
ket: SyntaxKind,
352+
delim: SyntaxKind,
353+
first_set: TokenSet,
354+
mut parser: impl FnMut(&mut Parser<'_>) -> bool,
355+
) {
356+
p.bump(bra);
357+
while !p.at(ket) && !p.at(EOF) {
358+
if !parser(p) {
359+
break;
360+
}
361+
if !p.at(delim) {
362+
if p.at_ts(first_set) {
363+
p.error(format!("expected {:?}", delim));
364+
} else {
365+
break;
366+
}
367+
} else {
368+
p.bump(delim);
369+
}
370+
}
371+
p.expect(ket);
372+
}

crates/parser/src/grammar/attributes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::*;
22

3+
pub(super) const ATTRIBUTE_FIRST: TokenSet = TokenSet::new(&[T![#]]);
4+
35
pub(super) fn inner_attrs(p: &mut Parser<'_>) {
46
while p.at(T![#]) && p.nth(1) == T![!] {
57
attr(p, true);

crates/parser/src/grammar/expressions.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
mod atom;
22

3+
use crate::grammar::attributes::ATTRIBUTE_FIRST;
4+
35
use super::*;
46

57
pub(crate) use self::atom::{block_expr, match_arm_list};
@@ -572,27 +574,11 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
572574
fn arg_list(p: &mut Parser<'_>) {
573575
assert!(p.at(T!['(']));
574576
let m = p.start();
575-
p.bump(T!['(']);
576-
while !p.at(T![')']) && !p.at(EOF) {
577-
// test arg_with_attr
578-
// fn main() {
579-
// foo(#[attr] 92)
580-
// }
581-
if !expr(p) {
582-
break;
583-
}
584-
if !p.at(T![,]) {
585-
if p.at_ts(EXPR_FIRST) {
586-
p.error("expected `,`");
587-
continue;
588-
} else {
589-
break;
590-
}
591-
} else {
592-
p.bump(T![,]);
593-
}
594-
}
595-
p.eat(T![')']);
577+
// test arg_with_attr
578+
// fn main() {
579+
// foo(#[attr] 92)
580+
// }
581+
delimited(p, T!['('], T![')'], T![,], EXPR_FIRST.union(ATTRIBUTE_FIRST), expr);
596582
m.complete(p, ARG_LIST);
597583
}
598584

crates/parser/src/grammar/expressions/atom.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ pub(super) fn atom_expr(
118118
// fn main() {
119119
// 'loop: impl
120120
// }
121-
p.error("expected a loop");
121+
p.error("expected a loop or block");
122122
m.complete(p, ERROR);
123123
return None;
124124
}

crates/parser/src/grammar/generic_args.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,35 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo
55
if p.at(T![::]) && p.nth(2) == T![<] {
66
m = p.start();
77
p.bump(T![::]);
8-
p.bump(T![<]);
98
} else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
109
m = p.start();
11-
p.bump(T![<]);
1210
} else {
1311
return;
1412
}
1513

16-
while !p.at(EOF) && !p.at(T![>]) {
17-
generic_arg(p);
18-
if !p.at(T![>]) && !p.expect(T![,]) {
19-
break;
20-
}
21-
}
22-
p.expect(T![>]);
14+
delimited(p, T![<], T![>], T![,], GENERIC_ARG_FIRST, generic_arg);
2315
m.complete(p, GENERIC_ARG_LIST);
2416
}
2517

18+
const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
19+
LIFETIME_IDENT,
20+
IDENT,
21+
T!['{'],
22+
T![true],
23+
T![false],
24+
T![-],
25+
INT_NUMBER,
26+
FLOAT_NUMBER,
27+
CHAR,
28+
BYTE,
29+
STRING,
30+
BYTE_STRING,
31+
])
32+
.union(types::TYPE_FIRST);
33+
2634
// test generic_arg
2735
// type T = S<i32>;
28-
fn generic_arg(p: &mut Parser<'_>) {
36+
fn generic_arg(p: &mut Parser<'_>) -> bool {
2937
match p.current() {
3038
LIFETIME_IDENT => lifetime_arg(p),
3139
T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
@@ -68,8 +76,10 @@ fn generic_arg(p: &mut Parser<'_>) {
6876
}
6977
}
7078
}
71-
_ => type_arg(p),
79+
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
80+
_ => return false,
7281
}
82+
true
7383
}
7484

7585
// test lifetime_arg

crates/parser/src/grammar/generic_params.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::grammar::attributes::ATTRIBUTE_FIRST;
2+
13
use super::*;
24

35
pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
@@ -11,32 +13,31 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
1113
fn generic_param_list(p: &mut Parser<'_>) {
1214
assert!(p.at(T![<]));
1315
let m = p.start();
14-
p.bump(T![<]);
16+
delimited(p, T![<], T![>], T![,], GENERIC_PARAM_FIRST.union(ATTRIBUTE_FIRST), |p| {
17+
// test generic_param_attribute
18+
// fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
19+
let m = p.start();
20+
attributes::outer_attrs(p);
21+
generic_param(p, m)
22+
});
1523

16-
while !p.at(EOF) && !p.at(T![>]) {
17-
generic_param(p);
18-
if !p.at(T![>]) && !p.expect(T![,]) {
19-
break;
20-
}
21-
}
22-
p.expect(T![>]);
2324
m.complete(p, GENERIC_PARAM_LIST);
2425
}
2526

26-
fn generic_param(p: &mut Parser<'_>) {
27-
let m = p.start();
28-
// test generic_param_attribute
29-
// fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
30-
attributes::outer_attrs(p);
27+
const GENERIC_PARAM_FIRST: TokenSet = TokenSet::new(&[IDENT, LIFETIME_IDENT, T![const]]);
28+
29+
fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
3130
match p.current() {
3231
LIFETIME_IDENT => lifetime_param(p, m),
3332
IDENT => type_param(p, m),
3433
T![const] => const_param(p, m),
3534
_ => {
3635
m.abandon(p);
37-
p.err_and_bump("expected type parameter");
36+
p.err_and_bump("expected generic parameter");
37+
return false;
3838
}
3939
}
40+
true
4041
}
4142

4243
// test lifetime_param

crates/parser/src/grammar/items/adt.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::grammar::attributes::ATTRIBUTE_FIRST;
2+
13
use super::*;
24

35
// test struct_item
@@ -141,28 +143,31 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
141143
}
142144
}
143145

146+
const TUPLE_FIELD_FIRST: TokenSet =
147+
types::TYPE_FIRST.union(ATTRIBUTE_FIRST).union(VISIBILITY_FIRST);
148+
144149
fn tuple_field_list(p: &mut Parser<'_>) {
145150
assert!(p.at(T!['(']));
146151
let m = p.start();
147-
p.bump(T!['(']);
148-
while !p.at(T![')']) && !p.at(EOF) {
152+
delimited(p, T!['('], T![')'], T![,], TUPLE_FIELD_FIRST, |p| {
149153
let m = p.start();
150154
// test tuple_field_attrs
151155
// struct S (#[attr] f32);
152156
attributes::outer_attrs(p);
153-
opt_visibility(p, true);
157+
let has_vis = opt_visibility(p, true);
154158
if !p.at_ts(types::TYPE_FIRST) {
155159
p.error("expected a type");
156-
m.complete(p, ERROR);
157-
break;
160+
if has_vis {
161+
m.complete(p, ERROR);
162+
} else {
163+
m.abandon(p);
164+
}
165+
return false;
158166
}
159167
types::type_(p);
160168
m.complete(p, TUPLE_FIELD);
169+
true
170+
});
161171

162-
if !p.at(T![')']) {
163-
p.expect(T![,]);
164-
}
165-
}
166-
p.expect(T![')']);
167172
m.complete(p, TUPLE_FIELD_LIST);
168173
}

crates/parser/src/grammar/params.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::grammar::attributes::ATTRIBUTE_FIRST;
2+
13
use super::*;
24

35
// test param_list
@@ -66,14 +68,20 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) {
6668
}
6769
};
6870

69-
if !p.at_ts(PARAM_FIRST) {
71+
if !p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) {
7072
p.error("expected value parameter");
7173
m.abandon(p);
7274
break;
7375
}
7476
param(p, m, flavor);
75-
if !p.at(ket) {
76-
p.expect(T![,]);
77+
if !p.at(T![,]) {
78+
if p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) {
79+
p.error("expected `,`");
80+
} else {
81+
break;
82+
}
83+
} else {
84+
p.bump(T![,]);
7785
}
7886
}
7987

crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ SOURCE_FILE
4444
IDENT "T"
4545
SEMICOLON ";"
4646
WHITESPACE "\n"
47-
error 9: expected type parameter
48-
error 11: expected COMMA
47+
error 9: expected generic parameter
4948
error 11: expected R_ANGLE
5049
error 11: expected `;`, `{`, or `(`
5150
error 12: expected an item

0 commit comments

Comments
 (0)