Skip to content

Commit 6d0a24c

Browse files
committed
Add support for become expr/tail calls
1 parent 085a311 commit 6d0a24c

File tree

16 files changed

+144
-6
lines changed

16 files changed

+144
-6
lines changed

crates/hir-def/src/body/lower.rs

+5
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,11 @@ impl ExprCollector<'_> {
414414
let expr = e.expr().map(|e| self.collect_expr(e));
415415
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
416416
}
417+
ast::Expr::BecomeExpr(e) => {
418+
let expr =
419+
e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
420+
self.alloc_expr(Expr::Become { expr }, syntax_ptr)
421+
}
417422
ast::Expr::YieldExpr(e) => {
418423
self.is_lowering_generator = true;
419424
let expr = e.expr().map(|e| self.collect_expr(e));

crates/hir-def/src/body/pretty.rs

+5
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ impl<'a> Printer<'a> {
258258
self.print_expr(*expr);
259259
}
260260
}
261+
Expr::Become { expr } => {
262+
w!(self, "become");
263+
self.whitespace();
264+
self.print_expr(*expr);
265+
}
261266
Expr::Yield { expr } => {
262267
w!(self, "yield");
263268
if let Some(expr) = expr {

crates/hir-def/src/hir.rs

+4
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ pub enum Expr {
221221
Return {
222222
expr: Option<ExprId>,
223223
},
224+
Become {
225+
expr: ExprId,
226+
},
224227
Yield {
225228
expr: Option<ExprId>,
226229
},
@@ -404,6 +407,7 @@ impl Expr {
404407
f(expr);
405408
}
406409
}
410+
Expr::Become { expr } => f(*expr),
407411
Expr::RecordLit { fields, spread, .. } => {
408412
for field in fields.iter() {
409413
f(field.expr);

crates/hir-ty/src/infer/closure.rs

+3
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ impl InferenceContext<'_> {
532532
self.consume_expr(expr);
533533
}
534534
}
535+
&Expr::Become { expr } => {
536+
self.consume_expr(expr);
537+
}
535538
Expr::RecordLit { fields, spread, .. } => {
536539
if let &Some(expr) = spread {
537540
self.consume_expr(expr);

crates/hir-ty/src/infer/expr.rs

+22
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ impl<'a> InferenceContext<'a> {
507507
self.result.standard_types.never.clone()
508508
}
509509
&Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr),
510+
&Expr::Become { expr } => self.infer_expr_become(expr),
510511
Expr::Yield { expr } => {
511512
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
512513
if let Some(expr) = expr {
@@ -1052,6 +1053,27 @@ impl<'a> InferenceContext<'a> {
10521053
self.result.standard_types.never.clone()
10531054
}
10541055

1056+
fn infer_expr_become(&mut self, expr: ExprId) -> Ty {
1057+
match &self.return_coercion {
1058+
Some(return_coercion) => {
1059+
let ret_ty = return_coercion.expected_ty();
1060+
1061+
let call_expr_ty =
1062+
self.infer_expr_inner(expr, &Expectation::HasType(ret_ty.clone()));
1063+
1064+
// NB: this should *not* coerce.
1065+
// tail calls don't support any coercions except lifetimes ones (like `&'static u8 -> &'a u8`).
1066+
self.unify(&call_expr_ty, &ret_ty);
1067+
}
1068+
None => {
1069+
// FIXME: diagnose `become` outside of functions
1070+
self.infer_expr_no_expect(expr);
1071+
}
1072+
}
1073+
1074+
self.result.standard_types.never.clone()
1075+
}
1076+
10551077
fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
10561078
if let Some(box_id) = self.resolve_boxed_box() {
10571079
let table = &mut self.table;

crates/hir-ty/src/infer/mutability.rs

+3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ impl<'a> InferenceContext<'a> {
9595
self.infer_mut_expr(expr, Mutability::Not);
9696
}
9797
}
98+
Expr::Become { expr } => {
99+
self.infer_mut_expr(*expr, Mutability::Not);
100+
}
98101
Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
99102
self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread))
100103
}

crates/hir-ty/src/mir/lower.rs

+1
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
716716
self.set_terminator(current, TerminatorKind::Return, expr_id.into());
717717
Ok(None)
718718
}
719+
Expr::Become { .. } => not_supported!("tail-calls"),
719720
Expr::Yield { .. } => not_supported!("yield"),
720721
Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => {
721722
let spread_place = match spread {

crates/ide-db/src/syntax_helpers/node_ext.rs

+1
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
330330
| ast::Expr::RecordExpr(_)
331331
| ast::Expr::RefExpr(_)
332332
| ast::Expr::ReturnExpr(_)
333+
| ast::Expr::BecomeExpr(_)
333334
| ast::Expr::TryExpr(_)
334335
| ast::Expr::TupleExpr(_)
335336
| ast::Expr::LetExpr(_)

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

+14
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
5656
T![match],
5757
T![move],
5858
T![return],
59+
T![become],
5960
T![static],
6061
T![try],
6162
T![unsafe],
@@ -98,6 +99,7 @@ pub(super) fn atom_expr(
9899
T![try] => try_block_expr(p, None),
99100
T![match] => match_expr(p),
100101
T![return] => return_expr(p),
102+
T![become] => become_expr(p),
101103
T![yield] => yield_expr(p),
102104
T![do] if p.nth_at_contextual_kw(1, T![yeet]) => yeet_expr(p),
103105
T![continue] => continue_expr(p),
@@ -551,6 +553,18 @@ fn return_expr(p: &mut Parser<'_>) -> CompletedMarker {
551553
m.complete(p, RETURN_EXPR)
552554
}
553555

556+
// test become_expr
557+
// fn foo() {
558+
// become foo();
559+
// }
560+
fn become_expr(p: &mut Parser<'_>) -> CompletedMarker {
561+
assert!(p.at(T![become]));
562+
let m = p.start();
563+
p.bump(T![become]);
564+
expr(p);
565+
m.complete(p, BECOME_EXPR)
566+
}
567+
554568
// test yield_expr
555569
// fn foo() {
556570
// yield;

crates/parser/src/syntax_kind/generated.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub enum SyntaxKind {
9090
PUB_KW,
9191
REF_KW,
9292
RETURN_KW,
93+
BECOME_KW,
9394
SELF_KW,
9495
SELF_TYPE_KW,
9596
STATIC_KW,
@@ -191,6 +192,7 @@ pub enum SyntaxKind {
191192
BLOCK_EXPR,
192193
STMT_LIST,
193194
RETURN_EXPR,
195+
BECOME_EXPR,
194196
YIELD_EXPR,
195197
YEET_EXPR,
196198
LET_EXPR,
@@ -299,6 +301,7 @@ impl SyntaxKind {
299301
| PUB_KW
300302
| REF_KW
301303
| RETURN_KW
304+
| BECOME_KW
302305
| SELF_KW
303306
| SELF_TYPE_KW
304307
| STATIC_KW
@@ -413,6 +416,7 @@ impl SyntaxKind {
413416
"pub" => PUB_KW,
414417
"ref" => REF_KW,
415418
"return" => RETURN_KW,
419+
"become" => BECOME_KW,
416420
"self" => SELF_KW,
417421
"Self" => SELF_TYPE_KW,
418422
"static" => STATIC_KW,
@@ -480,5 +484,5 @@ impl SyntaxKind {
480484
}
481485
}
482486
#[macro_export]
483-
macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
487+
macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
484488
pub use T;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
SOURCE_FILE
2+
FN
3+
FN_KW "fn"
4+
WHITESPACE " "
5+
NAME
6+
IDENT "foo"
7+
PARAM_LIST
8+
L_PAREN "("
9+
R_PAREN ")"
10+
WHITESPACE " "
11+
BLOCK_EXPR
12+
STMT_LIST
13+
L_CURLY "{"
14+
WHITESPACE "\n "
15+
EXPR_STMT
16+
BECOME_EXPR
17+
BECOME_KW "become"
18+
WHITESPACE " "
19+
CALL_EXPR
20+
PATH_EXPR
21+
PATH
22+
PATH_SEGMENT
23+
NAME_REF
24+
IDENT "foo"
25+
ARG_LIST
26+
L_PAREN "("
27+
R_PAREN ")"
28+
SEMICOLON ";"
29+
WHITESPACE "\n"
30+
R_CURLY "}"
31+
WHITESPACE "\n"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn foo() {
2+
become foo();
3+
}

crates/syntax/rust.ungram

+4
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ Expr =
359359
| RecordExpr
360360
| RefExpr
361361
| ReturnExpr
362+
| BecomeExpr
362363
| TryExpr
363364
| TupleExpr
364365
| WhileExpr
@@ -505,6 +506,9 @@ MatchGuard =
505506
ReturnExpr =
506507
Attr* 'return' Expr?
507508

509+
BecomeExpr =
510+
Attr* 'become' Expr
511+
508512
YieldExpr =
509513
Attr* 'yield' Expr?
510514

0 commit comments

Comments
 (0)