Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dba5997

Browse files
committedFeb 14, 2024
Auto merge of #15003 - WaffleLapkin:become_unuwuable, r=Veykril
feature: Add basic support for `become` expr/tail calls This follows rust-lang/rfcs#3407 and my WIP implementation in the compiler. Notice that I haven't even *opened* a compiler PR (although I plan to soon), so this feature doesn't really exist outside of my WIP branches. I've used this to help me test my implementation; opening a PR before I forget. (feel free to ignore this for now, given all of the above)
2 parents 3bb8d3a + e146139 commit dba5997

File tree

16 files changed

+144
-6
lines changed

16 files changed

+144
-6
lines changed
 

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,11 @@ impl ExprCollector<'_> {
416416
let expr = e.expr().map(|e| self.collect_expr(e));
417417
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
418418
}
419+
ast::Expr::BecomeExpr(e) => {
420+
let expr =
421+
e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
422+
self.alloc_expr(Expr::Become { expr }, syntax_ptr)
423+
}
419424
ast::Expr::YieldExpr(e) => {
420425
self.is_lowering_coroutine = true;
421426
let expr = e.expr().map(|e| self.collect_expr(e));

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ impl Printer<'_> {
261261
self.print_expr(*expr);
262262
}
263263
}
264+
Expr::Become { expr } => {
265+
w!(self, "become");
266+
self.whitespace();
267+
self.print_expr(*expr);
268+
}
264269
Expr::Yield { expr } => {
265270
w!(self, "yield");
266271
if let Some(expr) = expr {

‎crates/hir-def/src/hir.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ pub enum Expr {
216216
Return {
217217
expr: Option<ExprId>,
218218
},
219+
Become {
220+
expr: ExprId,
221+
},
219222
Yield {
220223
expr: Option<ExprId>,
221224
},
@@ -410,6 +413,7 @@ impl Expr {
410413
f(expr);
411414
}
412415
}
416+
Expr::Become { expr } => f(*expr),
413417
Expr::RecordLit { fields, spread, .. } => {
414418
for field in fields.iter() {
415419
f(field.expr);

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ impl InferenceContext<'_> {
531531
self.consume_expr(expr);
532532
}
533533
}
534+
&Expr::Become { expr } => {
535+
self.consume_expr(expr);
536+
}
534537
Expr::RecordLit { fields, spread, .. } => {
535538
if let &Some(expr) = spread {
536539
self.consume_expr(expr);

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ impl InferenceContext<'_> {
502502
self.result.standard_types.never.clone()
503503
}
504504
&Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr),
505+
&Expr::Become { expr } => self.infer_expr_become(expr),
505506
Expr::Yield { expr } => {
506507
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
507508
if let Some(expr) = expr {
@@ -1084,6 +1085,27 @@ impl InferenceContext<'_> {
10841085
self.result.standard_types.never.clone()
10851086
}
10861087

1088+
fn infer_expr_become(&mut self, expr: ExprId) -> Ty {
1089+
match &self.return_coercion {
1090+
Some(return_coercion) => {
1091+
let ret_ty = return_coercion.expected_ty();
1092+
1093+
let call_expr_ty =
1094+
self.infer_expr_inner(expr, &Expectation::HasType(ret_ty.clone()));
1095+
1096+
// NB: this should *not* coerce.
1097+
// tail calls don't support any coercions except lifetimes ones (like `&'static u8 -> &'a u8`).
1098+
self.unify(&call_expr_ty, &ret_ty);
1099+
}
1100+
None => {
1101+
// FIXME: diagnose `become` outside of functions
1102+
self.infer_expr_no_expect(expr);
1103+
}
1104+
}
1105+
1106+
self.result.standard_types.never.clone()
1107+
}
1108+
10871109
fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
10881110
if let Some(box_id) = self.resolve_boxed_box() {
10891111
let table = &mut self.table;

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ impl InferenceContext<'_> {
9393
self.infer_mut_expr(expr, Mutability::Not);
9494
}
9595
}
96+
Expr::Become { expr } => {
97+
self.infer_mut_expr(*expr, Mutability::Not);
98+
}
9699
Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
97100
self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
98101
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
775775
self.set_terminator(current, TerminatorKind::Return, expr_id.into());
776776
Ok(None)
777777
}
778+
Expr::Become { .. } => not_supported!("tail-calls"),
778779
Expr::Yield { .. } => not_supported!("yield"),
779780
Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => {
780781
let spread_place = match spread {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
329329
| ast::Expr::RecordExpr(_)
330330
| ast::Expr::RefExpr(_)
331331
| ast::Expr::ReturnExpr(_)
332+
| ast::Expr::BecomeExpr(_)
332333
| ast::Expr::TryExpr(_)
333334
| ast::Expr::TupleExpr(_)
334335
| ast::Expr::LetExpr(_)

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
5858
T![match],
5959
T![move],
6060
T![return],
61+
T![become],
6162
T![static],
6263
T![try],
6364
T![unsafe],
@@ -102,6 +103,7 @@ pub(super) fn atom_expr(
102103
T![try] => try_block_expr(p, None),
103104
T![match] => match_expr(p),
104105
T![return] => return_expr(p),
106+
T![become] => become_expr(p),
105107
T![yield] => yield_expr(p),
106108
T![do] if p.nth_at_contextual_kw(1, T![yeet]) => yeet_expr(p),
107109
T![continue] => continue_expr(p),
@@ -621,6 +623,18 @@ fn return_expr(p: &mut Parser<'_>) -> CompletedMarker {
621623
m.complete(p, RETURN_EXPR)
622624
}
623625

626+
// test become_expr
627+
// fn foo() {
628+
// become foo();
629+
// }
630+
fn become_expr(p: &mut Parser<'_>) -> CompletedMarker {
631+
assert!(p.at(T![become]));
632+
let m = p.start();
633+
p.bump(T![become]);
634+
expr(p);
635+
m.complete(p, BECOME_EXPR)
636+
}
637+
624638
// test yield_expr
625639
// fn foo() {
626640
// yield;

‎crates/parser/src/syntax_kind/generated.rs

Lines changed: 5 additions & 1 deletion
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,
@@ -195,6 +196,7 @@ pub enum SyntaxKind {
195196
BLOCK_EXPR,
196197
STMT_LIST,
197198
RETURN_EXPR,
199+
BECOME_EXPR,
198200
YIELD_EXPR,
199201
YEET_EXPR,
200202
LET_EXPR,
@@ -307,6 +309,7 @@ impl SyntaxKind {
307309
| PUB_KW
308310
| REF_KW
309311
| RETURN_KW
312+
| BECOME_KW
310313
| SELF_KW
311314
| SELF_TYPE_KW
312315
| STATIC_KW
@@ -425,6 +428,7 @@ impl SyntaxKind {
425428
"pub" => PUB_KW,
426429
"ref" => REF_KW,
427430
"return" => RETURN_KW,
431+
"become" => BECOME_KW,
428432
"self" => SELF_KW,
429433
"Self" => SELF_TYPE_KW,
430434
"static" => STATIC_KW,
@@ -496,4 +500,4 @@ impl SyntaxKind {
496500
}
497501
}
498502
#[macro_export]
499-
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 } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_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 } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
503+
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 } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_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 } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
Lines changed: 31 additions & 0 deletions
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"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn foo() {
2+
become foo();
3+
}

‎crates/syntax/rust.ungram

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ Expr =
367367
| RecordExpr
368368
| RefExpr
369369
| ReturnExpr
370+
| BecomeExpr
370371
| TryExpr
371372
| TupleExpr
372373
| WhileExpr
@@ -528,6 +529,9 @@ MatchGuard =
528529
ReturnExpr =
529530
Attr* 'return' Expr?
530531

532+
BecomeExpr =
533+
Attr* 'become' Expr
534+
531535
YieldExpr =
532536
Attr* 'yield' Expr?
533537

‎crates/syntax/src/ast/generated/nodes.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,16 @@ impl ReturnExpr {
10951095
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
10961096
}
10971097

1098+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1099+
pub struct BecomeExpr {
1100+
pub(crate) syntax: SyntaxNode,
1101+
}
1102+
impl ast::HasAttrs for BecomeExpr {}
1103+
impl BecomeExpr {
1104+
pub fn become_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![become]) }
1105+
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1106+
}
1107+
10981108
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10991109
pub struct TryExpr {
11001110
pub(crate) syntax: SyntaxNode,
@@ -1633,6 +1643,7 @@ pub enum Expr {
16331643
RecordExpr(RecordExpr),
16341644
RefExpr(RefExpr),
16351645
ReturnExpr(ReturnExpr),
1646+
BecomeExpr(BecomeExpr),
16361647
TryExpr(TryExpr),
16371648
TupleExpr(TupleExpr),
16381649
WhileExpr(WhileExpr),
@@ -2792,6 +2803,17 @@ impl AstNode for ReturnExpr {
27922803
}
27932804
fn syntax(&self) -> &SyntaxNode { &self.syntax }
27942805
}
2806+
impl AstNode for BecomeExpr {
2807+
fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
2808+
fn cast(syntax: SyntaxNode) -> Option<Self> {
2809+
if Self::can_cast(syntax.kind()) {
2810+
Some(Self { syntax })
2811+
} else {
2812+
None
2813+
}
2814+
}
2815+
fn syntax(&self) -> &SyntaxNode { &self.syntax }
2816+
}
27952817
impl AstNode for TryExpr {
27962818
fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
27972819
fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3540,6 +3562,9 @@ impl From<RefExpr> for Expr {
35403562
impl From<ReturnExpr> for Expr {
35413563
fn from(node: ReturnExpr) -> Expr { Expr::ReturnExpr(node) }
35423564
}
3565+
impl From<BecomeExpr> for Expr {
3566+
fn from(node: BecomeExpr) -> Expr { Expr::BecomeExpr(node) }
3567+
}
35433568
impl From<TryExpr> for Expr {
35443569
fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
35453570
}
@@ -3593,6 +3618,7 @@ impl AstNode for Expr {
35933618
| RECORD_EXPR
35943619
| REF_EXPR
35953620
| RETURN_EXPR
3621+
| BECOME_EXPR
35963622
| TRY_EXPR
35973623
| TUPLE_EXPR
35983624
| WHILE_EXPR
@@ -3632,6 +3658,7 @@ impl AstNode for Expr {
36323658
RECORD_EXPR => Expr::RecordExpr(RecordExpr { syntax }),
36333659
REF_EXPR => Expr::RefExpr(RefExpr { syntax }),
36343660
RETURN_EXPR => Expr::ReturnExpr(ReturnExpr { syntax }),
3661+
BECOME_EXPR => Expr::BecomeExpr(BecomeExpr { syntax }),
36353662
TRY_EXPR => Expr::TryExpr(TryExpr { syntax }),
36363663
TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
36373664
WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
@@ -3673,6 +3700,7 @@ impl AstNode for Expr {
36733700
Expr::RecordExpr(it) => &it.syntax,
36743701
Expr::RefExpr(it) => &it.syntax,
36753702
Expr::ReturnExpr(it) => &it.syntax,
3703+
Expr::BecomeExpr(it) => &it.syntax,
36763704
Expr::TryExpr(it) => &it.syntax,
36773705
Expr::TupleExpr(it) => &it.syntax,
36783706
Expr::WhileExpr(it) => &it.syntax,
@@ -4150,6 +4178,7 @@ impl AstNode for AnyHasAttrs {
41504178
| RANGE_EXPR
41514179
| REF_EXPR
41524180
| RETURN_EXPR
4181+
| BECOME_EXPR
41534182
| TRY_EXPR
41544183
| TUPLE_EXPR
41554184
| WHILE_EXPR
@@ -4851,6 +4880,11 @@ impl std::fmt::Display for ReturnExpr {
48514880
std::fmt::Display::fmt(self.syntax(), f)
48524881
}
48534882
}
4883+
impl std::fmt::Display for BecomeExpr {
4884+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4885+
std::fmt::Display::fmt(self.syntax(), f)
4886+
}
4887+
}
48544888
impl std::fmt::Display for TryExpr {
48554889
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48564890
std::fmt::Display::fmt(self.syntax(), f)

‎crates/syntax/src/ast/prec.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ impl Expr {
130130
//
131131
ContinueExpr(_) => (0, 0),
132132

133-
ClosureExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | BreakExpr(_)
134-
| OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
133+
ClosureExpr(_) | ReturnExpr(_) | BecomeExpr(_) | YieldExpr(_) | YeetExpr(_)
134+
| BreakExpr(_) | OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
135135

136136
RangeExpr(_) => (5, 5),
137137

@@ -288,6 +288,7 @@ impl Expr {
288288
PrefixExpr(e) => e.op_token(),
289289
RefExpr(e) => e.amp_token(),
290290
ReturnExpr(e) => e.return_token(),
291+
BecomeExpr(e) => e.become_token(),
291292
TryExpr(e) => e.question_mark_token(),
292293
YieldExpr(e) => e.yield_token(),
293294
YeetExpr(e) => e.do_token(),
@@ -316,7 +317,8 @@ impl Expr {
316317

317318
// For BinExpr and RangeExpr this is technically wrong -- the child can be on the left...
318319
BinExpr(_) | RangeExpr(_) | BreakExpr(_) | ContinueExpr(_) | PrefixExpr(_)
319-
| RefExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | LetExpr(_) => self
320+
| RefExpr(_) | ReturnExpr(_) | BecomeExpr(_) | YieldExpr(_) | YeetExpr(_)
321+
| LetExpr(_) => self
320322
.syntax()
321323
.parent()
322324
.and_then(Expr::cast)

‎crates/syntax/src/tests/ast_src.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
6767
keywords: &[
6868
"as", "async", "await", "box", "break", "const", "continue", "crate", "do", "dyn", "else",
6969
"enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "macro",
70-
"match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct",
71-
"super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield",
70+
"match", "mod", "move", "mut", "pub", "ref", "return", "become", "self", "Self", "static",
71+
"struct", "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while",
72+
"yield",
7273
],
7374
contextual_keywords: &[
7475
"auto",
@@ -154,6 +155,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
154155
"BLOCK_EXPR",
155156
"STMT_LIST",
156157
"RETURN_EXPR",
158+
"BECOME_EXPR",
157159
"YIELD_EXPR",
158160
"YEET_EXPR",
159161
"LET_EXPR",

0 commit comments

Comments
 (0)
Please sign in to comment.