Introduce EffectExpr

This commit is contained in:
Aleksey Kladov 2020-05-02 01:18:19 +02:00
parent 3c96de5380
commit 4f2134cc33
25 changed files with 242 additions and 261 deletions

View file

@ -2,7 +2,7 @@ use std::{iter::once, ops::RangeInclusive};
use ra_syntax::{ use ra_syntax::{
algo::replace_children, algo::replace_children,
ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat}, ast::{self, edit::IndentLevel, make},
AstNode, AstNode,
SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
SyntaxNode, SyntaxNode,
@ -47,7 +47,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
// Check if there is an IfLet that we can handle. // Check if there is an IfLet that we can handle.
let if_let_pat = match cond.pat() { let if_let_pat = match cond.pat() {
None => None, // No IfLet, supported. None => None, // No IfLet, supported.
Some(TupleStructPat(pat)) if pat.args().count() == 1 => { Some(ast::Pat::TupleStructPat(pat)) if pat.args().count() == 1 => {
let path = pat.path()?; let path = pat.path()?;
match path.qualifier() { match path.qualifier() {
None => { None => {
@ -61,9 +61,9 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
}; };
let cond_expr = cond.expr()?; let cond_expr = cond.expr()?;
let then_block = if_expr.then_branch()?.block()?; let then_block = if_expr.then_branch()?;
let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
if parent_block.expr()? != if_expr.clone().into() { if parent_block.expr()? != if_expr.clone().into() {
return None; return None;
@ -80,7 +80,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
return None; return None;
} }
let parent_container = parent_block.syntax().parent()?.parent()?; let parent_container = parent_block.syntax().parent()?;
let early_expression: ast::Expr = match parent_container.kind() { let early_expression: ast::Expr = match parent_container.kind() {
WHILE_EXPR | LOOP_EXPR => make::expr_continue(), WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
@ -144,13 +144,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
} }
}; };
edit.target(if_expr.syntax().text_range()); edit.target(if_expr.syntax().text_range());
edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
edit.set_cursor(cursor_position); edit.set_cursor(cursor_position);
fn replace( fn replace(
new_expr: &SyntaxNode, new_expr: &SyntaxNode,
then_block: &Block, then_block: &ast::BlockExpr,
parent_block: &Block, parent_block: &ast::BlockExpr,
if_expr: &ast::IfExpr, if_expr: &ast::IfExpr,
) -> SyntaxNode { ) -> SyntaxNode {
let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());

View file

@ -89,6 +89,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
| (ast::Expr::ParenExpr(_), _) | (ast::Expr::ParenExpr(_), _)
| (ast::Expr::PathExpr(_), _) | (ast::Expr::PathExpr(_), _)
| (ast::Expr::BlockExpr(_), _) | (ast::Expr::BlockExpr(_), _)
| (ast::Expr::EffectExpr(_), _)
| (_, ast::Expr::CallExpr(_)) | (_, ast::Expr::CallExpr(_))
| (_, ast::Expr::TupleExpr(_)) | (_, ast::Expr::TupleExpr(_))
| (_, ast::Expr::ArrayExpr(_)) | (_, ast::Expr::ArrayExpr(_))

View file

@ -111,7 +111,7 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
/// expression like a lambda or match arm. /// expression like a lambda or match arm.
fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
expr.syntax().ancestors().find_map(|node| { expr.syntax().ancestors().find_map(|node| {
if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) { if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) {
if expr.syntax() == &node { if expr.syntax() == &node {
tested_by!(test_introduce_var_last_expr); tested_by!(test_introduce_var_last_expr);
return Some((node, false)); return Some((node, false));

View file

@ -113,9 +113,9 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
"Move condition to match guard", "Move condition to match guard",
|edit| { |edit| {
edit.target(if_expr.syntax().text_range()); edit.target(if_expr.syntax().text_range());
let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none(); let then_only_expr = then_block.statements().next().is_none();
match &then_block.block().and_then(|it| it.expr()) { match &then_block.expr() {
Some(then_expr) if then_only_expr => { Some(then_expr) if then_only_expr => {
edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text())
} }

View file

@ -42,7 +42,6 @@ pub fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
} }
pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
let block = block.block()?;
let has_anything_else = |thing: &SyntaxNode| -> bool { let has_anything_else = |thing: &SyntaxNode| -> bool {
let mut non_trivial_children = let mut non_trivial_children =
block.syntax().children_with_tokens().filter(|it| match it.kind() { block.syntax().children_with_tokens().filter(|it| match it.kind() {

View file

@ -203,10 +203,16 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
} }
ast::Expr::TryBlockExpr(e) => { ast::Expr::EffectExpr(e) => match e.effect() {
let body = self.collect_block_opt(e.body()); ast::Effect::Try(_) => {
let body = self.collect_block_opt(e.block_expr());
self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
} }
// FIXME: we need to record these effects somewhere...
ast::Effect::Async(_) | ast::Effect::Label(_) | ast::Effect::Unsafe(_) => {
self.collect_block_opt(e.block_expr())
}
},
ast::Expr::BlockExpr(e) => self.collect_block(e), ast::Expr::BlockExpr(e) => self.collect_block(e),
ast::Expr::LoopExpr(e) => { ast::Expr::LoopExpr(e) => {
let body = self.collect_block_opt(e.loop_body()); let body = self.collect_block_opt(e.loop_body());
@ -494,12 +500,8 @@ impl ExprCollector<'_> {
} }
} }
fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId { fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
let syntax_node_ptr = AstPtr::new(&expr.clone().into()); let syntax_node_ptr = AstPtr::new(&block.clone().into());
let block = match expr.block() {
Some(block) => block,
None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
};
self.collect_block_items(&block); self.collect_block_items(&block);
let statements = block let statements = block
.statements() .statements()
@ -517,7 +519,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
} }
fn collect_block_items(&mut self, block: &ast::Block) { fn collect_block_items(&mut self, block: &ast::BlockExpr) {
let container = ContainerId::DefWithBodyId(self.def); let container = ContainerId::DefWithBodyId(self.def);
for item in block.items() { for item in block.items() {
let (def, name): (ModuleDefId, Option<ast::Name>) = match item { let (def, name): (ModuleDefId, Option<ast::Name>) = match item {

View file

@ -330,7 +330,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
FragmentKind::Expr FragmentKind::Expr
} }
// FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
EXPR_STMT | BLOCK => FragmentKind::Expr, EXPR_STMT | BLOCK_EXPR => FragmentKind::Expr,
ARG_LIST => FragmentKind::Expr, ARG_LIST => FragmentKind::Expr,
TRY_EXPR => FragmentKind::Expr, TRY_EXPR => FragmentKind::Expr,
TUPLE_EXPR => FragmentKind::Expr, TUPLE_EXPR => FragmentKind::Expr,
@ -342,7 +342,6 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
CONDITION => FragmentKind::Expr, CONDITION => FragmentKind::Expr,
BREAK_EXPR => FragmentKind::Expr, BREAK_EXPR => FragmentKind::Expr,
RETURN_EXPR => FragmentKind::Expr, RETURN_EXPR => FragmentKind::Expr,
BLOCK_EXPR => FragmentKind::Expr,
MATCH_EXPR => FragmentKind::Expr, MATCH_EXPR => FragmentKind::Expr,
MATCH_ARM => FragmentKind::Expr, MATCH_ARM => FragmentKind::Expr,
MATCH_GUARD => FragmentKind::Expr, MATCH_GUARD => FragmentKind::Expr,

View file

@ -344,7 +344,7 @@ impl<'a> CompletionContext<'a> {
stmt.syntax().text_range() == name_ref.syntax().text_range(), stmt.syntax().text_range() == name_ref.syntax().text_range(),
); );
} }
if let Some(block) = ast::Block::cast(node) { if let Some(block) = ast::BlockExpr::cast(node) {
return Some( return Some(
block.expr().map(|e| e.syntax().text_range()) block.expr().map(|e| e.syntax().text_range())
== Some(name_ref.syntax().text_range()), == Some(name_ref.syntax().text_range()),

View file

@ -88,7 +88,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
| ITEM_LIST | ITEM_LIST
| EXTERN_ITEM_LIST | EXTERN_ITEM_LIST
| USE_TREE_LIST | USE_TREE_LIST
| BLOCK | BLOCK_EXPR
| MATCH_ARM_LIST | MATCH_ARM_LIST
| ENUM_VARIANT_LIST | ENUM_VARIANT_LIST
| TOKEN_TREE => Some(FoldKind::Block), | TOKEN_TREE => Some(FoldKind::Block),

View file

@ -129,8 +129,7 @@ fn has_comma_after(node: &SyntaxNode) -> bool {
} }
fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> {
let block = ast::Block::cast(token.parent())?; let block_expr = ast::BlockExpr::cast(token.parent())?;
let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
if !block_expr.is_standalone() { if !block_expr.is_standalone() {
return None; return None;
} }

View file

@ -120,7 +120,6 @@ SOURCE_FILE@0..11
R_PAREN@7..8 ")" R_PAREN@7..8 ")"
WHITESPACE@8..9 " " WHITESPACE@8..9 " "
BLOCK_EXPR@9..11 BLOCK_EXPR@9..11
BLOCK@9..11
L_CURLY@9..10 "{" L_CURLY@9..10 "{"
R_CURLY@10..11 "}" R_CURLY@10..11 "}"
"# "#
@ -153,7 +152,6 @@ SOURCE_FILE@0..60
R_PAREN@8..9 ")" R_PAREN@8..9 ")"
WHITESPACE@9..10 " " WHITESPACE@9..10 " "
BLOCK_EXPR@10..60 BLOCK_EXPR@10..60
BLOCK@10..60
L_CURLY@10..11 "{" L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n " WHITESPACE@11..16 "\n "
EXPR_STMT@16..58 EXPR_STMT@16..58
@ -196,7 +194,6 @@ FN_DEF@0..11
R_PAREN@7..8 ")" R_PAREN@7..8 ")"
WHITESPACE@8..9 " " WHITESPACE@8..9 " "
BLOCK_EXPR@9..11 BLOCK_EXPR@9..11
BLOCK@9..11
L_CURLY@9..10 "{" L_CURLY@9..10 "{"
R_CURLY@10..11 "}" R_CURLY@10..11 "}"
"# "#
@ -265,7 +262,6 @@ SOURCE_FILE@0..12
R_PAREN@7..8 ")" R_PAREN@7..8 ")"
WHITESPACE@8..9 " " WHITESPACE@8..9 " "
BLOCK_EXPR@9..12 BLOCK_EXPR@9..12
BLOCK@9..12
L_CURLY@9..10 "{" L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n" WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}" R_CURLY@11..12 "}"
@ -300,7 +296,6 @@ SOURCE_FILE@0..12
R_PAREN@7..8 ")" R_PAREN@7..8 ")"
WHITESPACE@8..9 " " WHITESPACE@8..9 " "
BLOCK_EXPR@9..12 BLOCK_EXPR@9..12
BLOCK@9..12
L_CURLY@9..10 "{" L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n" WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}" R_CURLY@11..12 "}"
@ -334,7 +329,6 @@ SOURCE_FILE@0..25
R_PAREN@7..8 ")" R_PAREN@7..8 ")"
WHITESPACE@8..9 " " WHITESPACE@8..9 " "
BLOCK_EXPR@9..12 BLOCK_EXPR@9..12
BLOCK@9..12
L_CURLY@9..10 "{" L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n" WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}" R_CURLY@11..12 "}"
@ -349,7 +343,6 @@ SOURCE_FILE@0..25
R_PAREN@20..21 ")" R_PAREN@20..21 ")"
WHITESPACE@21..22 " " WHITESPACE@21..22 " "
BLOCK_EXPR@22..25 BLOCK_EXPR@22..25
BLOCK@22..25
L_CURLY@22..23 "{" L_CURLY@22..23 "{"
WHITESPACE@23..24 "\n" WHITESPACE@23..24 "\n"
R_CURLY@24..25 "}" R_CURLY@24..25 "}"

View file

@ -266,7 +266,6 @@ fn test_expr_order() {
L_PAREN@5..6 "(" L_PAREN@5..6 "("
R_PAREN@6..7 ")" R_PAREN@6..7 ")"
BLOCK_EXPR@7..15 BLOCK_EXPR@7..15
BLOCK@7..15
L_CURLY@7..8 "{" L_CURLY@7..8 "{"
EXPR_STMT@8..14 EXPR_STMT@8..14
BIN_EXPR@8..13 BIN_EXPR@8..13
@ -1114,7 +1113,6 @@ fn test_vec() {
assert_eq!( assert_eq!(
format!("{:#?}", tree).trim(), format!("{:#?}", tree).trim(),
r#"BLOCK_EXPR@0..45 r#"BLOCK_EXPR@0..45
BLOCK@0..45
L_CURLY@0..1 "{" L_CURLY@0..1 "{"
LET_STMT@1..20 LET_STMT@1..20
LET_KW@1..4 "let" LET_KW@1..4 "let"

View file

@ -143,7 +143,7 @@ pub(crate) fn reparser(
parent: Option<SyntaxKind>, parent: Option<SyntaxKind>,
) -> Option<fn(&mut Parser)> { ) -> Option<fn(&mut Parser)> {
let res = match node { let res = match node {
BLOCK => expressions::naked_block, BLOCK_EXPR => expressions::block,
RECORD_FIELD_DEF_LIST => items::record_field_def_list, RECORD_FIELD_DEF_LIST => items::record_field_def_list,
RECORD_FIELD_LIST => items::record_field_list, RECORD_FIELD_LIST => items::record_field_list,
ENUM_VARIANT_LIST => items::enum_variant_list, ENUM_VARIANT_LIST => items::enum_variant_list,

View file

@ -59,16 +59,7 @@ pub(crate) fn block(p: &mut Parser) {
p.error("expected a block"); p.error("expected a block");
return; return;
} }
atom::block_expr(p, None); atom::block_expr(p);
}
pub(crate) fn naked_block(p: &mut Parser) {
assert!(p.at(T!['{']));
let m = p.start();
p.bump(T!['{']);
expr_block_contents(p);
p.expect(T!['}']);
m.complete(p, BLOCK);
} }
fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
@ -197,7 +188,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
} }
} }
pub(crate) fn expr_block_contents(p: &mut Parser) { pub(super) fn expr_block_contents(p: &mut Parser) {
// This is checked by a validator // This is checked by a validator
attributes::inner_attributes(p); attributes::inner_attributes(p);

View file

@ -92,7 +92,10 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
T![loop] => loop_expr(p, Some(m)), T![loop] => loop_expr(p, Some(m)),
T![for] => for_expr(p, Some(m)), T![for] => for_expr(p, Some(m)),
T![while] => while_expr(p, Some(m)), T![while] => while_expr(p, Some(m)),
T!['{'] => block_expr(p, Some(m)), T!['{'] => {
block_expr(p);
m.complete(p, EFFECT_EXPR)
}
_ => { _ => {
// test_err misplaced_label_err // test_err misplaced_label_err
// fn main() { // fn main() {
@ -108,13 +111,15 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
let m = p.start(); let m = p.start();
p.bump(T![async]); p.bump(T![async]);
p.eat(T![move]); p.eat(T![move]);
block_expr(p, Some(m)) block_expr(p);
m.complete(p, EFFECT_EXPR)
} }
T![match] => match_expr(p), T![match] => match_expr(p),
T![unsafe] if la == T!['{'] => { T![unsafe] if la == T!['{'] => {
let m = p.start(); let m = p.start();
p.bump(T![unsafe]); p.bump(T![unsafe]);
block_expr(p, Some(m)) block_expr(p);
m.complete(p, EFFECT_EXPR)
} }
T!['{'] => { T!['{'] => {
// test for_range_from // test for_range_from
@ -123,7 +128,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
// break; // break;
// } // }
// } // }
block_expr(p, None) block_expr(p)
} }
T![return] => return_expr(p), T![return] => return_expr(p),
T![continue] => continue_expr(p), T![continue] => continue_expr(p),
@ -134,7 +139,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
} }
}; };
let blocklike = match done.kind() { let blocklike = match done.kind() {
IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | TRY_BLOCK_EXPR => { IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | EFFECT_EXPR => {
BlockLike::Block BlockLike::Block
} }
_ => BlockLike::NotBlock, _ => BlockLike::NotBlock,
@ -234,7 +239,7 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
if p.at(T!['{']) { if p.at(T!['{']) {
// test lambda_ret_block // test lambda_ret_block
// fn main() { || -> i32 { 92 }(); } // fn main() { || -> i32 { 92 }(); }
block_expr(p, None); block_expr(p);
} else { } else {
p.error("expected `{`"); p.error("expected `{`");
} }
@ -464,10 +469,12 @@ fn match_guard(p: &mut Parser) -> CompletedMarker {
// unsafe {}; // unsafe {};
// 'label: {}; // 'label: {};
// } // }
pub(super) fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { pub(super) fn block_expr(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T!['{'])); assert!(p.at(T!['{']));
let m = m.unwrap_or_else(|| p.start()); let m = p.start();
naked_block(p); p.bump(T!['{']);
expr_block_contents(p);
p.expect(T!['}']);
m.complete(p, BLOCK_EXPR) m.complete(p, BLOCK_EXPR)
} }
@ -552,8 +559,8 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
} }
p.bump(T![try]); p.bump(T![try]);
block(p); block_expr(p);
m.complete(p, TRY_EXPR) m.complete(p, EFFECT_EXPR)
} }
// test box_expr // test box_expr

View file

@ -191,7 +191,7 @@ pub enum SyntaxKind {
RECORD_LIT, RECORD_LIT,
RECORD_FIELD_LIST, RECORD_FIELD_LIST,
RECORD_FIELD, RECORD_FIELD,
TRY_BLOCK_EXPR, EFFECT_EXPR,
BOX_EXPR, BOX_EXPR,
CALL_EXPR, CALL_EXPR,
INDEX_EXPR, INDEX_EXPR,
@ -204,7 +204,6 @@ pub enum SyntaxKind {
PREFIX_EXPR, PREFIX_EXPR,
RANGE_EXPR, RANGE_EXPR,
BIN_EXPR, BIN_EXPR,
BLOCK,
EXTERN_BLOCK, EXTERN_BLOCK,
EXTERN_ITEM_LIST, EXTERN_ITEM_LIST,
ENUM_VARIANT, ENUM_VARIANT,

View file

@ -16,7 +16,7 @@ use crate::{
}; };
pub use self::{ pub use self::{
expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, expr_extensions::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
extensions::{ extensions::{
AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
StructKind, TypeBoundKind, VisibilityKind, StructKind, TypeBoundKind, VisibilityKind,

View file

@ -28,7 +28,7 @@ impl ast::BinExpr {
impl ast::FnDef { impl ast::FnDef {
#[must_use] #[must_use]
pub fn with_body(&self, body: ast::Block) -> ast::FnDef { pub fn with_body(&self, body: ast::BlockExpr) -> ast::FnDef {
let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() { let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() {
old_body.syntax().clone().into() old_body.syntax().clone().into()

View file

@ -16,7 +16,7 @@ impl ast::Expr {
| ast::Expr::WhileExpr(_) | ast::Expr::WhileExpr(_)
| ast::Expr::BlockExpr(_) | ast::Expr::BlockExpr(_)
| ast::Expr::MatchExpr(_) | ast::Expr::MatchExpr(_)
| ast::Expr::TryBlockExpr(_) => true, | ast::Expr::EffectExpr(_) => true,
_ => false, _ => false,
} }
} }
@ -359,6 +359,33 @@ impl ast::Literal {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Effect {
Async(SyntaxToken),
Unsafe(SyntaxToken),
Try(SyntaxToken),
// Very much not an effect, but we stuff it into this node anyway
Label(ast::Label),
}
impl ast::EffectExpr {
pub fn effect(&self) -> Effect {
if let Some(token) = self.async_token() {
return Effect::Async(token);
}
if let Some(token) = self.unsafe_token() {
return Effect::Unsafe(token);
}
if let Some(token) = self.try_token() {
return Effect::Try(token);
}
if let Some(label) = self.label() {
return Effect::Label(label);
}
unreachable!("ast::EffectExpr without Effect")
}
}
impl ast::BlockExpr { impl ast::BlockExpr {
/// false if the block is an intrinsic part of the syntax and can't be /// false if the block is an intrinsic part of the syntax and can't be
/// replaced with arbitrary expression. /// replaced with arbitrary expression.
@ -368,15 +395,12 @@ impl ast::BlockExpr {
/// const FOO: () = { stand_alone }; /// const FOO: () = { stand_alone };
/// ``` /// ```
pub fn is_standalone(&self) -> bool { pub fn is_standalone(&self) -> bool {
if self.unsafe_token().is_some() || self.async_token().is_some() { let parent = match self.syntax().parent() {
return false; Some(it) => it,
}
let kind = match self.syntax().parent() {
None => return true, None => return true,
Some(it) => it.kind(),
}; };
match kind { match parent.kind() {
FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | TRY_BLOCK_EXPR => false, FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR => false,
_ => true, _ => true,
} }
} }

View file

@ -476,13 +476,16 @@ impl LoopExpr {
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TryBlockExpr { pub struct EffectExpr {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
impl ast::AttrsOwner for TryBlockExpr {} impl ast::AttrsOwner for EffectExpr {}
impl TryBlockExpr { impl EffectExpr {
pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) } pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -551,11 +554,12 @@ pub struct BlockExpr {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
impl ast::AttrsOwner for BlockExpr {} impl ast::AttrsOwner for BlockExpr {}
impl ast::ModuleItemOwner for BlockExpr {}
impl BlockExpr { impl BlockExpr {
pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn block(&self) -> Option<Block> { support::child(&self.syntax) } pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -627,8 +631,8 @@ pub struct TryExpr {
} }
impl ast::AttrsOwner for TryExpr {} impl ast::AttrsOwner for TryExpr {}
impl TryExpr { impl TryExpr {
pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -1121,19 +1125,6 @@ impl Condition {
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Block {
pub(crate) syntax: SyntaxNode,
}
impl ast::AttrsOwner for Block {}
impl ast::ModuleItemOwner for Block {}
impl Block {
pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ParamList { pub struct ParamList {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
@ -1477,7 +1468,7 @@ pub enum Expr {
FieldExpr(FieldExpr), FieldExpr(FieldExpr),
AwaitExpr(AwaitExpr), AwaitExpr(AwaitExpr),
TryExpr(TryExpr), TryExpr(TryExpr),
TryBlockExpr(TryBlockExpr), EffectExpr(EffectExpr),
CastExpr(CastExpr), CastExpr(CastExpr),
RefExpr(RefExpr), RefExpr(RefExpr),
PrefixExpr(PrefixExpr), PrefixExpr(PrefixExpr),
@ -1960,8 +1951,8 @@ impl AstNode for LoopExpr {
} }
fn syntax(&self) -> &SyntaxNode { &self.syntax } fn syntax(&self) -> &SyntaxNode { &self.syntax }
} }
impl AstNode for TryBlockExpr { impl AstNode for EffectExpr {
fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_BLOCK_EXPR } fn can_cast(kind: SyntaxKind) -> bool { kind == EFFECT_EXPR }
fn cast(syntax: SyntaxNode) -> Option<Self> { fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) { if Self::can_cast(syntax.kind()) {
Some(Self { syntax }) Some(Self { syntax })
@ -2653,17 +2644,6 @@ impl AstNode for Condition {
} }
fn syntax(&self) -> &SyntaxNode { &self.syntax } fn syntax(&self) -> &SyntaxNode { &self.syntax }
} }
impl AstNode for Block {
fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK }
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Self { syntax })
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl AstNode for ParamList { impl AstNode for ParamList {
fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST } fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
fn cast(syntax: SyntaxNode) -> Option<Self> { fn cast(syntax: SyntaxNode) -> Option<Self> {
@ -3312,8 +3292,8 @@ impl From<AwaitExpr> for Expr {
impl From<TryExpr> for Expr { impl From<TryExpr> for Expr {
fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) } fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
} }
impl From<TryBlockExpr> for Expr { impl From<EffectExpr> for Expr {
fn from(node: TryBlockExpr) -> Expr { Expr::TryBlockExpr(node) } fn from(node: EffectExpr) -> Expr { Expr::EffectExpr(node) }
} }
impl From<CastExpr> for Expr { impl From<CastExpr> for Expr {
fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) } fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) }
@ -3345,9 +3325,10 @@ impl AstNode for Expr {
TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR
| LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL
| BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR
| METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | TRY_BLOCK_EXPR | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | EFFECT_EXPR | CAST_EXPR
| CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | BOX_EXPR => {
| BOX_EXPR => true, true
}
_ => false, _ => false,
} }
} }
@ -3375,7 +3356,7 @@ impl AstNode for Expr {
FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }), FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }),
AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }), AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }),
TRY_EXPR => Expr::TryExpr(TryExpr { syntax }), TRY_EXPR => Expr::TryExpr(TryExpr { syntax }),
TRY_BLOCK_EXPR => Expr::TryBlockExpr(TryBlockExpr { syntax }), EFFECT_EXPR => Expr::EffectExpr(EffectExpr { syntax }),
CAST_EXPR => Expr::CastExpr(CastExpr { syntax }), CAST_EXPR => Expr::CastExpr(CastExpr { syntax }),
REF_EXPR => Expr::RefExpr(RefExpr { syntax }), REF_EXPR => Expr::RefExpr(RefExpr { syntax }),
PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }), PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }),
@ -3412,7 +3393,7 @@ impl AstNode for Expr {
Expr::FieldExpr(it) => &it.syntax, Expr::FieldExpr(it) => &it.syntax,
Expr::AwaitExpr(it) => &it.syntax, Expr::AwaitExpr(it) => &it.syntax,
Expr::TryExpr(it) => &it.syntax, Expr::TryExpr(it) => &it.syntax,
Expr::TryBlockExpr(it) => &it.syntax, Expr::EffectExpr(it) => &it.syntax,
Expr::CastExpr(it) => &it.syntax, Expr::CastExpr(it) => &it.syntax,
Expr::RefExpr(it) => &it.syntax, Expr::RefExpr(it) => &it.syntax,
Expr::PrefixExpr(it) => &it.syntax, Expr::PrefixExpr(it) => &it.syntax,
@ -3893,7 +3874,7 @@ impl std::fmt::Display for LoopExpr {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)
} }
} }
impl std::fmt::Display for TryBlockExpr { impl std::fmt::Display for EffectExpr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)
} }
@ -4208,11 +4189,6 @@ impl std::fmt::Display for Condition {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)
} }
} }
impl std::fmt::Display for Block {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for ParamList { impl std::fmt::Display for ParamList {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)

View file

@ -82,10 +82,10 @@ pub fn block_expr(
ast_from_text(&format!("fn f() {}", buf)) ast_from_text(&format!("fn f() {}", buf))
} }
pub fn block_from_expr(e: ast::Expr) -> ast::Block { pub fn block_from_expr(e: ast::Expr) -> ast::BlockExpr {
return from_text(&format!("{{ {} }}", e)); return from_text(&format!("{{ {} }}", e));
fn from_text(text: &str) -> ast::Block { fn from_text(text: &str) -> ast::BlockExpr {
ast_from_text(&format!("fn f() {}", text)) ast_from_text(&format!("fn f() {}", text))
} }
} }

View file

@ -237,8 +237,7 @@ fn api_walkthrough() {
// Let's get the `1 + 1` expression! // Let's get the `1 + 1` expression!
let body: ast::BlockExpr = func.body().unwrap(); let body: ast::BlockExpr = func.body().unwrap();
let block = body.block().unwrap(); let expr: ast::Expr = body.expr().unwrap();
let expr: ast::Expr = block.expr().unwrap();
// Enums are used to group related ast nodes together, and can be used for // Enums are used to group related ast nodes together, and can be used for
// matching. However, because there are no public fields, it's possible to // matching. However, because there are no public fields, it's possible to
@ -274,8 +273,8 @@ fn api_walkthrough() {
assert_eq!(text.to_string(), "1 + 1"); assert_eq!(text.to_string(), "1 + 1");
// There's a bunch of traversal methods on `SyntaxNode`: // There's a bunch of traversal methods on `SyntaxNode`:
assert_eq!(expr_syntax.parent().as_ref(), Some(block.syntax())); assert_eq!(expr_syntax.parent().as_ref(), Some(body.syntax()));
assert_eq!(block.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{'])); assert_eq!(body.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
assert_eq!( assert_eq!(
expr_syntax.next_sibling_or_token().map(|it| it.kind()), expr_syntax.next_sibling_or_token().map(|it| it.kind()),
Some(SyntaxKind::WHITESPACE) Some(SyntaxKind::WHITESPACE)

View file

@ -6,19 +6,17 @@ use crate::{
SyntaxKind::*, SyntaxKind::*,
}; };
pub(crate) fn validate_block_expr(expr: ast::BlockExpr, errors: &mut Vec<SyntaxError>) { pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) {
if let Some(parent) = expr.syntax().parent() { if let Some(parent) = block.syntax().parent() {
match parent.kind() { match parent.kind() {
FN_DEF | EXPR_STMT | BLOCK => return, FN_DEF | EXPR_STMT | BLOCK_EXPR => return,
_ => {} _ => {}
} }
} }
if let Some(block) = expr.block() {
errors.extend(block.attrs().map(|attr| { errors.extend(block.attrs().map(|attr| {
SyntaxError::new( SyntaxError::new(
"A block in this position cannot accept inner attributes", "A block in this position cannot accept inner attributes",
attr.syntax().text_range(), attr.syntax().text_range(),
) )
})) }))
}
} }

View file

@ -162,7 +162,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
"RECORD_LIT", "RECORD_LIT",
"RECORD_FIELD_LIST", "RECORD_FIELD_LIST",
"RECORD_FIELD", "RECORD_FIELD",
"TRY_BLOCK_EXPR", "EFFECT_EXPR",
"BOX_EXPR", "BOX_EXPR",
// postfix // postfix
"CALL_EXPR", "CALL_EXPR",
@ -177,7 +177,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
"PREFIX_EXPR", "PREFIX_EXPR",
"RANGE_EXPR", // just weird "RANGE_EXPR", // just weird
"BIN_EXPR", "BIN_EXPR",
"BLOCK",
"EXTERN_BLOCK", "EXTERN_BLOCK",
"EXTERN_ITEM_LIST", "EXTERN_ITEM_LIST",
"ENUM_VARIANT", "ENUM_VARIANT",
@ -440,7 +439,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
} }
struct IfExpr: AttrsOwner { T![if], Condition } struct IfExpr: AttrsOwner { T![if], Condition }
struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] } struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] }
struct TryBlockExpr: AttrsOwner { T![try], body: BlockExpr } struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr }
struct ForExpr: AttrsOwner, LoopBodyOwner { struct ForExpr: AttrsOwner, LoopBodyOwner {
T![for], T![for],
Pat, Pat,
@ -451,7 +450,9 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] } struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] }
struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr } struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr }
struct Label { T![lifetime] } struct Label { T![lifetime] }
struct BlockExpr: AttrsOwner { Label, T![unsafe], T![async], Block } struct BlockExpr: AttrsOwner, ModuleItemOwner {
T!['{'], statements: [Stmt], Expr, T!['}'],
}
struct ReturnExpr: AttrsOwner { Expr } struct ReturnExpr: AttrsOwner { Expr }
struct CallExpr: ArgListOwner { Expr } struct CallExpr: ArgListOwner { Expr }
struct MethodCallExpr: AttrsOwner, ArgListOwner { struct MethodCallExpr: AttrsOwner, ArgListOwner {
@ -460,7 +461,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
struct IndexExpr: AttrsOwner { T!['['], T![']'] } struct IndexExpr: AttrsOwner { T!['['], T![']'] }
struct FieldExpr: AttrsOwner { Expr, T![.], NameRef } struct FieldExpr: AttrsOwner { Expr, T![.], NameRef }
struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] } struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] }
struct TryExpr: AttrsOwner { T![try], Expr } struct TryExpr: AttrsOwner { Expr, T![?] }
struct CastExpr: AttrsOwner { Expr, T![as], TypeRef } struct CastExpr: AttrsOwner { Expr, T![as], TypeRef }
struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], Expr } struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], Expr }
struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr } struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr }
@ -556,12 +557,6 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
T![;], T![;],
} }
struct Condition { T![let], Pat, T![=], Expr } struct Condition { T![let], Pat, T![=], Expr }
struct Block: AttrsOwner, ModuleItemOwner {
T!['{'],
statements: [Stmt],
Expr,
T!['}'],
}
struct ParamList { struct ParamList {
T!['('], T!['('],
SelfParam, SelfParam,
@ -722,7 +717,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
FieldExpr, FieldExpr,
AwaitExpr, AwaitExpr,
TryExpr, TryExpr,
TryBlockExpr, EffectExpr,
CastExpr, CastExpr,
RefExpr, RefExpr,
PrefixExpr, PrefixExpr,

View file

@ -432,6 +432,7 @@ impl Field<'_> {
":" => "colon", ":" => "colon",
"::" => "coloncolon", "::" => "coloncolon",
"#" => "pound", "#" => "pound",
"?" => "question_mark",
_ => name, _ => name,
}; };
format_ident!("{}_token", name) format_ident!("{}_token", name)