Skip to content

Commit 0618100

Browse files
bors[bot]matklad
andauthored
10354: internal: overhaul expression attribute parsing r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents d401f2a + 56964c9 commit 0618100

21 files changed

+314
-344
lines changed

crates/hir_def/src/body/lower.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,10 @@ impl ExprCollector<'_> {
650650
self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
651651
}
652652
ast::Stmt::ExprStmt(stmt) => {
653-
if self.check_cfg(&stmt).is_none() {
654-
return;
653+
if let Some(expr) = stmt.expr() {
654+
if self.check_cfg(&expr).is_none() {
655+
return;
656+
}
655657
}
656658
let has_semi = stmt.semicolon_token().is_some();
657659
// Note that macro could be expended to multiple statements

crates/parser/src/event.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
9393

9494
for i in 0..events.len() {
9595
match mem::replace(&mut events[i], Event::tombstone()) {
96-
Event::Start { kind: TOMBSTONE, .. } => (),
97-
9896
Event::Start { kind, forward_parent } => {
9997
// For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
10098
// in the normal control flow, the parent-child relation: `A -> B -> C`,
@@ -109,9 +107,7 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
109107
// append `A`'s forward_parent `B`
110108
fp = match mem::replace(&mut events[idx], Event::tombstone()) {
111109
Event::Start { kind, forward_parent } => {
112-
if kind != TOMBSTONE {
113-
forward_parents.push(kind);
114-
}
110+
forward_parents.push(kind);
115111
forward_parent
116112
}
117113
_ => unreachable!(),
@@ -120,7 +116,9 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
120116
}
121117

122118
for kind in forward_parents.drain(..).rev() {
123-
sink.start_node(kind);
119+
if kind != TOMBSTONE {
120+
sink.start_node(kind);
121+
}
124122
}
125123
}
126124
Event::Finish => sink.finish_node(),

crates/parser/src/grammar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub(crate) mod entry_points {
6363
pub(crate) use types::type_;
6464

6565
pub(crate) fn expr(p: &mut Parser) {
66-
let _ = expressions::expr_with_attrs(p);
66+
let _ = expressions::expr(p);
6767
}
6868

6969
pub(crate) fn stmt(p: &mut Parser) {

crates/parser/src/grammar/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub(super) fn meta(p: &mut Parser) {
4141
match p.current() {
4242
T![=] => {
4343
p.bump(T![=]);
44-
if expressions::expr(p).0.is_none() {
44+
if !expressions::expr(p) {
4545
p.error("expected expression");
4646
}
4747
}

crates/parser/src/grammar/expressions.rs

Lines changed: 62 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,19 @@ pub(super) enum StmtWithSemi {
1313

1414
const EXPR_FIRST: TokenSet = LHS_FIRST;
1515

16-
pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
16+
pub(super) fn expr(p: &mut Parser) -> bool {
1717
let r = Restrictions { forbid_structs: false, prefer_stmt: false };
18-
expr_bp(p, r, 1)
18+
expr_bp(p, None, r, 1).is_some()
1919
}
2020

21-
pub(super) fn expr_with_attrs(p: &mut Parser) -> bool {
22-
let m = p.start();
23-
let has_attrs = p.at(T![#]);
24-
attributes::outer_attrs(p);
25-
26-
let (cm, _block_like) = expr(p);
27-
let success = cm.is_some();
28-
29-
match (has_attrs, cm) {
30-
(true, Some(cm)) => cm.extend_to(p, m),
31-
_ => m.abandon(p),
32-
}
33-
34-
success
35-
}
36-
37-
pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
21+
pub(super) fn expr_stmt(p: &mut Parser, m: Option<Marker>) -> Option<(CompletedMarker, BlockLike)> {
3822
let r = Restrictions { forbid_structs: false, prefer_stmt: true };
39-
expr_bp(p, r, 1)
23+
expr_bp(p, m, r, 1)
4024
}
4125

4226
fn expr_no_struct(p: &mut Parser) {
4327
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
44-
expr_bp(p, r, 1);
28+
expr_bp(p, None, r, 1);
4529
}
4630

4731
pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
@@ -53,7 +37,6 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
5337
// #[C] #[D] {}
5438
// #[D] return ();
5539
// }
56-
let has_attrs = p.at(T![#]);
5740
attributes::outer_attrs(p);
5841

5942
if p.at(T![let]) {
@@ -68,61 +51,39 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
6851
Err(m) => m,
6952
};
7053

71-
let (cm, blocklike) = expr_stmt(p);
72-
let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
73-
74-
if has_attrs {
75-
if matches!(kind, BIN_EXPR | RANGE_EXPR) {
76-
// test_err attr_on_expr_not_allowed
54+
if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
55+
if !(p.at(T!['}']) || (prefer_expr && p.at(EOF))) {
56+
// test no_semi_after_block
7757
// fn foo() {
78-
// #[A] 1 + 2;
79-
// #[B] if true {};
58+
// if true {}
59+
// loop {}
60+
// match () {}
61+
// while true {}
62+
// for _ in () {}
63+
// {}
64+
// {}
65+
// macro_rules! test {
66+
// () => {}
67+
// }
68+
// test!{}
8069
// }
81-
p.error(format!("attributes are not allowed on {:?}", kind));
82-
}
83-
}
84-
85-
if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
86-
// test attr_on_last_expr_in_block
87-
// fn foo() {
88-
// { #[A] bar!()? }
89-
// #[B] &()
90-
// }
91-
match cm {
92-
Some(cm) => cm.extend_to(p, m),
93-
None => m.abandon(p),
94-
}
95-
} else {
96-
// test no_semi_after_block
97-
// fn foo() {
98-
// if true {}
99-
// loop {}
100-
// match () {}
101-
// while true {}
102-
// for _ in () {}
103-
// {}
104-
// {}
105-
// macro_rules! test {
106-
// () => {}
107-
// }
108-
// test!{}
109-
// }
110-
111-
match with_semi {
112-
StmtWithSemi::No => (),
113-
StmtWithSemi::Optional => {
114-
p.eat(T![;]);
115-
}
116-
StmtWithSemi::Yes => {
117-
if blocklike.is_block() {
70+
let m = cm.precede(p);
71+
match with_semi {
72+
StmtWithSemi::No => (),
73+
StmtWithSemi::Optional => {
11874
p.eat(T![;]);
119-
} else {
120-
p.expect(T![;]);
75+
}
76+
StmtWithSemi::Yes => {
77+
if blocklike.is_block() {
78+
p.eat(T![;]);
79+
} else {
80+
p.expect(T![;]);
81+
}
12182
}
12283
}
123-
}
12484

125-
m.complete(p, EXPR_STMT);
85+
m.complete(p, EXPR_STMT);
86+
}
12687
}
12788

12889
// test let_stmt
@@ -138,7 +99,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
13899
if p.eat(T![=]) {
139100
// test let_stmt_init
140101
// fn f() { let x = 92; }
141-
expressions::expr_with_attrs(p);
102+
expressions::expr(p);
142103
}
143104

144105
match with_semi {
@@ -234,20 +195,34 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
234195
}
235196

236197
// Parses expression with binding power of at least bp.
237-
fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
198+
fn expr_bp(
199+
p: &mut Parser,
200+
m: Option<Marker>,
201+
mut r: Restrictions,
202+
bp: u8,
203+
) -> Option<(CompletedMarker, BlockLike)> {
204+
let m = m.unwrap_or_else(|| {
205+
let m = p.start();
206+
attributes::outer_attrs(p);
207+
m
208+
});
238209
let mut lhs = match lhs(p, r) {
239210
Some((lhs, blocklike)) => {
211+
let lhs = lhs.extend_to(p, m);
240212
if r.prefer_stmt && blocklike.is_block() {
241213
// test stmt_bin_expr_ambiguity
242214
// fn f() {
243215
// let _ = {1} & 2;
244216
// {1} &2;
245217
// }
246-
return (Some(lhs), BlockLike::Block);
218+
return Some((lhs, BlockLike::Block));
247219
}
248220
lhs
249221
}
250-
None => return (None, BlockLike::NotBlock),
222+
None => {
223+
m.abandon(p);
224+
return None;
225+
}
251226
};
252227

253228
loop {
@@ -285,10 +260,10 @@ fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMark
285260
}
286261
}
287262

288-
expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
263+
expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
289264
lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
290265
}
291-
(Some(lhs), BlockLike::NotBlock)
266+
Some((lhs, BlockLike::NotBlock))
292267
}
293268

294269
const LHS_FIRST: TokenSet =
@@ -341,9 +316,10 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
341316
m = p.start();
342317
p.bump(op);
343318
if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
344-
expr_bp(p, r, 2);
319+
expr_bp(p, None, r, 2);
345320
}
346-
return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
321+
let cm = m.complete(p, RANGE_EXPR);
322+
return Some((cm, BlockLike::NotBlock));
347323
}
348324
}
349325

@@ -353,12 +329,15 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
353329
// {p}.x = 10;
354330
// }
355331
let (lhs, blocklike) = atom::atom_expr(p, r)?;
356-
return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
332+
let (cm, block_like) =
333+
postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
334+
return Some((cm, block_like));
357335
}
358336
};
359337
// parse the interior of the unary expression
360-
expr_bp(p, r, 255);
361-
Some((m.complete(p, kind), BlockLike::NotBlock))
338+
expr_bp(p, None, r, 255);
339+
let cm = m.complete(p, kind);
340+
Some((cm, BlockLike::NotBlock))
362341
}
363342

364343
fn postfix_expr(
@@ -536,7 +515,7 @@ fn arg_list(p: &mut Parser) {
536515
// fn main() {
537516
// foo(#[attr] 92)
538517
// }
539-
if !expr_with_attrs(p) {
518+
if !expr(p) {
540519
break;
541520
}
542521
if !p.at(T![')']) && !p.expect(T![,]) {

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker {
176176

177177
// test tuple_attrs
178178
// const A: (i64, i64) = (1, #[cfg(test)] 2);
179-
if !expr_with_attrs(p) {
179+
if !expr(p) {
180180
break;
181181
}
182182

@@ -209,7 +209,7 @@ fn array_expr(p: &mut Parser) -> CompletedMarker {
209209

210210
// test array_attrs
211211
// const A: &[i64] = &[1, #[cfg(test)] 2];
212-
if !expr_with_attrs(p) {
212+
if !expr(p) {
213213
break;
214214
}
215215

@@ -438,7 +438,10 @@ fn match_arm(p: &mut Parser) {
438438
match_guard(p);
439439
}
440440
p.expect(T![=>]);
441-
let blocklike = expr_stmt(p).1;
441+
let blocklike = match expr_stmt(p, None) {
442+
Some((_, blocklike)) => blocklike,
443+
None => BlockLike::NotBlock,
444+
};
442445

443446
// test match_arms_commas
444447
// fn foo() {
@@ -619,14 +622,14 @@ fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
619622
assert!(p.at(L_DOLLAR));
620623
let m = p.start();
621624
p.bump(L_DOLLAR);
622-
let (completed, _is_block) =
623-
expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
625+
let expr = expr_bp(p, None, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
624626

625-
match (completed, p.current()) {
626-
(Some(it), R_DOLLAR) => {
627+
match (expr, p.current()) {
628+
(Some((cm, _)), R_DOLLAR) => {
627629
p.bump(R_DOLLAR);
630+
// FIXME: this leaves the dollar hanging in the air...
628631
m.abandon(p);
629-
it
632+
cm
630633
}
631634
_ => {
632635
while !p.at(R_DOLLAR) {

crates/parser/src/parser.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,16 @@ impl CompletedMarker {
339339
}
340340

341341
/// Extends this completed marker *to the left* up to `m`.
342-
pub(crate) fn extend_to(self, p: &mut Parser, mut m: Marker) {
343-
assert!(m.pos <= self.pos);
342+
pub(crate) fn extend_to(self, p: &mut Parser, mut m: Marker) -> CompletedMarker {
344343
m.bomb.defuse();
345-
346-
p.events.swap(self.pos as usize, m.pos as usize);
344+
let idx = m.pos as usize;
345+
match &mut p.events[idx] {
346+
Event::Start { forward_parent, .. } => {
347+
*forward_parent = Some(self.pos - m.pos);
348+
}
349+
_ => unreachable!(),
350+
}
351+
self
347352
}
348353

349354
pub(crate) fn kind(&self) -> SyntaxKind {

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ [email protected]
2626
2727
2828
29-
30-
31-
29+
30+
3231
3332
3433
@@ -55,4 +54,3 @@ error 15..15: expected an item
5554
error 17..17: expected an item
5655
error 24..24: expected SEMICOLON
5756
error 24..24: expected expression
58-
error 25..25: expected SEMICOLON

0 commit comments

Comments
 (0)