diff --git a/Cargo.lock b/Cargo.lock index 9170ec3a66b..9da1f56deaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1760,9 +1760,9 @@ dependencies = [ [[package]] name = "ungrammar" -version = "1.14.4" +version = "1.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6e36d57b143472488b1594fe25c376fa9683bccfd80d858b2180c97806835b" +checksum = "395e988af2480b8a8118ad1d5f1f790197d332e3e2585231f742949b63080ef5" [[package]] name = "unicase" diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 51befc698c0..5cda6cc1e96 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -698,7 +698,7 @@ impl<'db> SemanticsImpl<'db> { ast::ForExpr(it) => it.label(), ast::WhileExpr(it) => it.label(), ast::LoopExpr(it) => it.label(), - ast::EffectExpr(it) => it.label(), + ast::BlockExpr(it) => it.label(), _ => None, } }; diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 70fa249a5b0..04011d91296 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -524,7 +524,8 @@ fn inner_attributes( }, ast::Fn(it) => { let body = it.body()?; - (body.attrs(), ast::CommentIter::from_syntax_node(body.syntax())) + let stmt_list = body.stmt_list()?; + (stmt_list.attrs(), ast::CommentIter::from_syntax_node(body.syntax())) }, ast::Impl(it) => { let assoc_item_list = it.assoc_item_list()?; diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index a34c18d6d0c..6a6d992af34 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -245,43 +245,37 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) } - ast::Expr::EffectExpr(e) => match e.effect() { - ast::Effect::Try(_) => { - let body = self.collect_block_opt(e.block_expr()); + ast::Expr::BlockExpr(e) => match e.modifier() { + Some(ast::BlockModifier::Try(_)) => { + let body = self.collect_block(e); self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) } - ast::Effect::Unsafe(_) => { - let body = self.collect_block_opt(e.block_expr()); + Some(ast::BlockModifier::Unsafe(_)) => { + let body = self.collect_block(e); self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) } // FIXME: we need to record these effects somewhere... - ast::Effect::Label(label) => { + Some(ast::BlockModifier::Label(label)) => { let label = self.collect_label(label); - match e.block_expr() { - Some(block) => { - let res = self.collect_block(block); - match &mut self.body.exprs[res] { - Expr::Block { label: block_label, .. } => { - *block_label = Some(label); - } - _ => unreachable!(), - } - res + let res = self.collect_block(e); + match &mut self.body.exprs[res] { + Expr::Block { label: block_label, .. } => { + *block_label = Some(label); } - None => self.missing_expr(), + _ => unreachable!(), } + res } - // FIXME: we need to record these effects somewhere... - ast::Effect::Async(_) => { - let body = self.collect_block_opt(e.block_expr()); + Some(ast::BlockModifier::Async(_)) => { + let body = self.collect_block(e); self.alloc_expr(Expr::Async { body }, syntax_ptr) } - ast::Effect::Const(_) => { - let body = self.collect_block_opt(e.block_expr()); + Some(ast::BlockModifier::Const(_)) => { + let body = self.collect_block(e); self.alloc_expr(Expr::Const { body }, syntax_ptr) } + None => self.collect_block(e), }, - ast::Expr::BlockExpr(e) => self.collect_block(e), ast::Expr::LoopExpr(e) => { let label = e.label().map(|label| self.collect_label(label)); let body = self.collect_block_opt(e.loop_body()); diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 8bb56e0700d..bdc3023e9c1 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -721,7 +721,7 @@ impl ExpandTo { match parent.kind() { MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items, - MACRO_STMTS | EXPR_STMT | BLOCK_EXPR => ExpandTo::Statements, + MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements, MACRO_PAT => ExpandTo::Pattern, MACRO_TYPE => ExpandTo::Type, diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index 306da6738b0..26078a4b2fa 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs @@ -1083,22 +1083,22 @@ fn dyn_trait_super_trait_not_in_scope() { fn method_resolution_foreign_opaque_type() { check_infer( r#" - extern "C" { - type S; - fn f() -> &'static S; - } +extern "C" { + type S; + fn f() -> &'static S; +} - impl S { - fn foo(&self) -> bool { - true - } - } +impl S { + fn foo(&self) -> bool { + true + } +} - fn test() { - let s = unsafe { f() }; - s.foo(); - } - "#, +fn test() { + let s = unsafe { f() }; + s.foo(); +} +"#, expect![[r#" 75..79 'self': &S 89..109 '{ ... }': bool @@ -1106,7 +1106,7 @@ fn method_resolution_foreign_opaque_type() { 123..167 '{ ...o(); }': () 133..134 's': &S 137..151 'unsafe { f() }': &S - 144..151 '{ f() }': &S + 137..151 'unsafe { f() }': &S 146..147 'f': fn f() -> &S 146..149 'f()': &S 157..158 's': &S diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a409c453b0e..f4d082ea8c6 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs @@ -352,7 +352,7 @@ unsafe fn baz(u: MyUnion) { 71..89 'MyUnio...o: 0 }': MyUnion 86..87 '0': u32 95..113 'unsafe...(u); }': () - 102..113 '{ baz(u); }': () + 95..113 'unsafe...(u); }': () 104..107 'baz': fn baz(MyUnion) 104..110 'baz(u)': () 108..109 'u': MyUnion @@ -360,7 +360,7 @@ unsafe fn baz(u: MyUnion) { 126..146 'MyUnio... 0.0 }': MyUnion 141..144 '0.0': f32 152..170 'unsafe...(u); }': () - 159..170 '{ baz(u); }': () + 152..170 'unsafe...(u); }': () 161..164 'baz': fn baz(MyUnion) 161..167 'baz(u)': () 165..166 'u': MyUnion @@ -1914,41 +1914,41 @@ fn fn_pointer_return() { } #[test] -fn effects_smoke_test() { +fn block_modifiers_smoke_test() { check_infer( r#" - //- minicore: future - async fn main() { - let x = unsafe { 92 }; - let y = async { async { () }.await }; - let z = try { () }; - let w = const { 92 }; - let t = 'a: { 92 }; - } +//- minicore: future +async fn main() { + let x = unsafe { 92 }; + let y = async { async { () }.await }; + let z = try { () }; + let w = const { 92 }; + let t = 'a: { 92 }; +} "#, expect![[r#" 16..162 '{ ...2 }; }': () 26..27 'x': i32 30..43 'unsafe { 92 }': i32 - 37..43 '{ 92 }': i32 + 30..43 'unsafe { 92 }': i32 39..41 '92': i32 53..54 'y': impl Future + 57..85 'async ...wait }': () 57..85 'async ...wait }': impl Future - 63..85 '{ asyn...wait }': () + 65..77 'async { () }': () 65..77 'async { () }': impl Future 65..83 'async ....await': () - 71..77 '{ () }': () 73..75 '()': () 95..96 'z': {unknown} + 99..109 'try { () }': () 99..109 'try { () }': {unknown} - 103..109 '{ () }': () 105..107 '()': () 119..120 'w': i32 123..135 'const { 92 }': i32 - 129..135 '{ 92 }': i32 + 123..135 'const { 92 }': i32 131..133 '92': i32 145..146 't': i32 - 153..159 '{ 92 }': i32 + 149..159 ''a: { 92 }': i32 155..157 '92': i32 "#]], ) @@ -2104,32 +2104,32 @@ fn infer_labelled_break_with_val() { fn infer_labelled_block_break_with_val() { check_infer( r#" - fn default() -> T { loop {} } - fn foo() { - let _x = 'outer: { - let inner = 'inner: { - let i = default(); - if (break 'outer i) { - break 'inner 5i8; - } else if true { - break 'inner 6; - } - break 'inner 'innermost: { 0 }; - 42 - }; - break 'outer inner < 8; - }; - } - "#, +fn default() -> T { loop {} } +fn foo() { + let _x = 'outer: { + let inner = 'inner: { + let i = default(); + if (break 'outer i) { + break 'inner 5i8; + } else if true { + break 'inner 6; + } + break 'inner 'innermost: { 0 }; + 42 + }; + break 'outer inner < 8; + }; +} +"#, expect![[r#" 21..32 '{ loop {} }': T 23..30 'loop {}': ! 28..30 '{}': () 42..381 '{ ... }; }': () 52..54 '_x': bool - 65..378 '{ ... }': bool + 57..378 ''outer... }': bool 79..84 'inner': i8 - 95..339 '{ ... }': i8 + 87..339 ''inner... }': i8 113..114 'i': bool 117..124 'default': fn default() -> bool 117..126 'default()': bool @@ -2145,7 +2145,7 @@ fn infer_labelled_block_break_with_val() { 241..255 'break 'inner 6': ! 254..255 '6': i8 283..313 'break ... { 0 }': ! - 308..313 '{ 0 }': i8 + 296..313 ''inner... { 0 }': i8 310..311 '0': i8 327..329 '42': i8 349..371 'break ...er < 8': ! diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index d305f82fcb0..6aef3a94296 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -164,8 +164,8 @@ fn highlight_exit_points( match anc { ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)), ast::ClosureExpr(closure) => hl(sema, closure.body()), - ast::EffectExpr(effect) => if matches!(effect.effect(), ast::Effect::Async(_) | ast::Effect::Try(_)| ast::Effect::Const(_)) { - hl(sema, effect.block_expr().map(ast::Expr::BlockExpr)) + ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) { + hl(sema, Some(block_expr.into())) } else { continue; }, @@ -180,7 +180,7 @@ fn highlight_break_points(token: SyntaxToken) -> Option> { fn hl( token: Option, label: Option, - body: Option, + body: Option, ) -> Option> { let mut highlights = Vec::new(); let range = cover_range( @@ -204,7 +204,7 @@ fn highlight_break_points(token: SyntaxToken) -> Option> { ast::LoopExpr(l) => l.label().and_then(|it| it.lifetime()), ast::ForExpr(f) => f.label().and_then(|it| it.lifetime()), ast::WhileExpr(w) => w.label().and_then(|it| it.lifetime()), - ast::EffectExpr(b) => Some(b.label().and_then(|it| it.lifetime())?), + ast::BlockExpr(b) => Some(b.label().and_then(|it| it.lifetime())?), _ => return None, } }; @@ -218,16 +218,16 @@ fn highlight_break_points(token: SyntaxToken) -> Option> { for anc in token.ancestors().flat_map(ast::Expr::cast) { return match anc { ast::Expr::LoopExpr(l) if label_matches(l.label()) => { - hl(l.loop_token(), l.label(), l.loop_body()) + hl(l.loop_token(), l.label(), l.loop_body().and_then(|it| it.stmt_list())) } ast::Expr::ForExpr(f) if label_matches(f.label()) => { - hl(f.for_token(), f.label(), f.loop_body()) + hl(f.for_token(), f.label(), f.loop_body().and_then(|it| it.stmt_list())) } ast::Expr::WhileExpr(w) if label_matches(w.label()) => { - hl(w.while_token(), w.label(), w.loop_body()) + hl(w.while_token(), w.label(), w.loop_body().and_then(|it| it.stmt_list())) } - ast::Expr::EffectExpr(e) if e.label().is_some() && label_matches(e.label()) => { - hl(None, e.label(), e.block_expr()) + ast::Expr::BlockExpr(e) if e.label().is_some() && label_matches(e.label()) => { + hl(None, e.label(), e.stmt_list()) } _ => continue, }; @@ -258,7 +258,12 @@ fn highlight_yield_points(token: SyntaxToken) -> Option> { return match_ast! { match anc { ast::Fn(fn_) => hl(fn_.async_token(), fn_.body().map(ast::Expr::BlockExpr)), - ast::EffectExpr(effect) => hl(effect.async_token(), effect.block_expr().map(ast::Expr::BlockExpr)), + ast::BlockExpr(block_expr) => { + if block_expr.async_token().is_none() { + continue; + } + hl(block_expr.async_token(), Some(block_expr.into())) + }, ast::ClosureExpr(closure) => hl(closure.async_token(), closure.body()), _ => continue, } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 5b516de4c64..7f9a91286a4 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -86,8 +86,8 @@ pub(super) fn try_expr( ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db), ast::Item(__) => return None, ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original, - ast::EffectExpr(effect) => if matches!(effect.effect(), ast::Effect::Async(_) | ast::Effect::Try(_)| ast::Effect::Const(_)) { - sema.type_of_expr(&effect.block_expr()?.into())?.original + ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) { + sema.type_of_expr(&block_expr.into())?.original } else { continue; }, diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 8eb2e493590..000d74abacb 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs @@ -212,7 +212,7 @@ fn remove_newline( } fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> { - let block_expr = ast::BlockExpr::cast(token.parent()?)?; + let block_expr = ast::BlockExpr::cast(token.ancestors().nth(1)?)?; if !block_expr.is_standalone() { return None; } diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 633878d1c67..1771b56fe38 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs @@ -133,8 +133,9 @@ mod tests { R_PAREN@7..8 ")" WHITESPACE@8..9 " " BLOCK_EXPR@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" + STMT_LIST@9..11 + L_CURLY@9..10 "{" + R_CURLY@10..11 "}" "#]], ); @@ -158,25 +159,26 @@ fn test() { R_PAREN@8..9 ")" WHITESPACE@9..10 " " BLOCK_EXPR@10..60 - L_CURLY@10..11 "{" - WHITESPACE@11..16 "\n " - EXPR_STMT@16..58 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - WHITESPACE@58..59 "\n" - R_CURLY@59..60 "}" + STMT_LIST@10..60 + L_CURLY@10..11 "{" + WHITESPACE@11..16 "\n " + EXPR_STMT@16..58 + MACRO_CALL@16..57 + PATH@16..22 + PATH_SEGMENT@16..22 + NAME_REF@16..22 + IDENT@16..22 "assert" + BANG@22..23 "!" + TOKEN_TREE@23..57 + L_PAREN@23..24 "(" + STRING@24..52 "\"\n fn foo() {\n ..." + COMMA@52..53 "," + WHITESPACE@53..54 " " + STRING@54..56 "\"\"" + R_PAREN@56..57 ")" + SEMICOLON@57..58 ";" + WHITESPACE@58..59 "\n" + R_CURLY@59..60 "}" "#]], ) } @@ -196,8 +198,9 @@ fn test() { R_PAREN@7..8 ")" WHITESPACE@8..9 " " BLOCK_EXPR@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" + STMT_LIST@9..11 + L_CURLY@9..10 "{" + R_CURLY@10..11 "}" "#]], ); @@ -252,9 +255,10 @@ fn bar() { R_PAREN@7..8 ")" WHITESPACE@8..9 " " BLOCK_EXPR@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" + STMT_LIST@9..12 + L_CURLY@9..10 "{" + WHITESPACE@10..11 "\n" + R_CURLY@11..12 "}" "#]], ); @@ -280,9 +284,10 @@ fn bar() { R_PAREN@7..8 ")" WHITESPACE@8..9 " " BLOCK_EXPR@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" + STMT_LIST@9..12 + L_CURLY@9..10 "{" + WHITESPACE@10..11 "\n" + R_CURLY@11..12 "}" "#]], ); @@ -307,9 +312,10 @@ fn bar() { R_PAREN@7..8 ")" WHITESPACE@8..9 " " BLOCK_EXPR@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" + STMT_LIST@9..12 + L_CURLY@9..10 "{" + WHITESPACE@10..11 "\n" + R_CURLY@11..12 "}" WHITESPACE@12..13 "\n" FN@13..25 FN_KW@13..15 "fn" @@ -321,9 +327,10 @@ fn bar() { R_PAREN@20..21 ")" WHITESPACE@21..22 " " BLOCK_EXPR@22..25 - L_CURLY@22..23 "{" - WHITESPACE@23..24 "\n" - R_CURLY@24..25 "}" + STMT_LIST@22..25 + L_CURLY@22..23 "{" + WHITESPACE@23..24 "\n" + R_CURLY@24..25 "}" "#]], ); } diff --git a/crates/ide_assists/src/handlers/add_return_type.rs b/crates/ide_assists/src/handlers/add_return_type.rs index ce5981b406e..2ecdf33607b 100644 --- a/crates/ide_assists/src/handlers/add_return_type.rs +++ b/crates/ide_assists/src/handlers/add_return_type.rs @@ -100,9 +100,10 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla let action = ret_ty_to_action(func.ret_type(), rparen_pos)?; let body = func.body()?; - let tail_expr = body.tail_expr()?; + let stmt_list = body.stmt_list()?; + let tail_expr = stmt_list.tail_expr()?; - let ret_range_end = body.l_curly_token()?.text_range().start(); + let ret_range_end = stmt_list.l_curly_token()?.text_range().start(); let ret_range = TextRange::new(rparen_pos, ret_range_end); (FnType::Function, tail_expr, ret_range, action) }; diff --git a/crates/ide_assists/src/handlers/convert_to_guarded_return.rs b/crates/ide_assists/src/handlers/convert_to_guarded_return.rs index 1ec0e0a5da3..884905a9188 100644 --- a/crates/ide_assists/src/handlers/convert_to_guarded_return.rs +++ b/crates/ide_assists/src/handlers/convert_to_guarded_return.rs @@ -68,6 +68,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) let cond_expr = cond.expr()?; let then_block = if_expr.then_branch()?; + let then_block = then_block.stmt_list()?; let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; @@ -75,6 +76,9 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) return None; } + // FIXME: This relies on untyped syntax tree and casts to much. It should be + // rewritten to use strongly-typed APIs. + // check for early return and continue let first_in_then_block = then_block.syntax().first_child()?; if ast::ReturnExpr::can_cast(first_in_then_block.kind()) diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index 328d172cb8b..733bb347881 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs @@ -148,24 +148,30 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option None, ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => Some(FunctionBody::from_range( - node.parent().and_then(ast::BlockExpr::cast)?, + node.parent().and_then(ast::StmtList::cast)?, node.text_range(), )), }; } + // Covering element returned the parent block of one or multiple statements that have been selected + if let Some(stmt_list) = ast::StmtList::cast(node.clone()) { + if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) { + if block_expr.syntax().text_range() == selection_range { + return FunctionBody::from_expr(block_expr.into()); + } + } + + // Extract the full statements. + return Some(FunctionBody::from_range(stmt_list, selection_range)); + } + let expr = ast::Expr::cast(node.clone())?; // A node got selected fully if node.text_range() == selection_range { return FunctionBody::from_expr(expr.clone()); } - // Covering element returned the parent block of one or multiple statements that have been selected - if let ast::Expr::BlockExpr(block) = expr { - // Extract the full statements. - return Some(FunctionBody::from_range(block, selection_range)); - } - node.ancestors().find_map(ast::Expr::cast).and_then(FunctionBody::from_expr) } @@ -284,7 +290,7 @@ impl RetType { #[derive(Debug)] enum FunctionBody { Expr(ast::Expr), - Span { parent: ast::BlockExpr, text_range: TextRange }, + Span { parent: ast::StmtList, text_range: TextRange }, } #[derive(Debug)] @@ -441,7 +447,7 @@ impl FunctionBody { } } - fn from_range(parent: ast::BlockExpr, selected: TextRange) -> FunctionBody { + fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody { let mut text_range = parent .statements() .map(|stmt| stmt.syntax().text_range()) @@ -643,14 +649,14 @@ impl FunctionBody { break match_ast! { match anc { ast::ClosureExpr(closure) => (false, closure.body(), infer_expr_opt(closure.body())), - ast::EffectExpr(effect) => { - let (constness, block) = match effect.effect() { - ast::Effect::Const(_) => (true, effect.block_expr()), - ast::Effect::Try(_) => (false, effect.block_expr()), - ast::Effect::Label(label) if label.lifetime().is_some() => (false, effect.block_expr()), + ast::BlockExpr(block_expr) => { + let (constness, block) = match block_expr.modifier() { + Some(ast::BlockModifier::Const(_)) => (true, block_expr), + Some(ast::BlockModifier::Try(_)) => (false, block_expr), + Some(ast::BlockModifier::Label(label)) if label.lifetime().is_some() => (false, block_expr), _ => continue, }; - let expr = block.map(ast::Expr::BlockExpr); + let expr = Some(ast::Expr::BlockExpr(block)); (constness, expr.clone(), infer_expr_opt(expr)) }, ast::Fn(fn_) => { @@ -745,7 +751,7 @@ impl FunctionBody { ast::Expr::LoopExpr(_) | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) => loop_depth -= 1, - ast::Expr::EffectExpr(effect) if effect.unsafe_token().is_some() => { + ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => { unsafe_depth -= 1 } _ => (), @@ -757,7 +763,7 @@ impl FunctionBody { ast::Expr::LoopExpr(_) | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) => { loop_depth += 1; } - ast::Expr::EffectExpr(effect) if effect.unsafe_token().is_some() => { + ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => { unsafe_depth += 1 } ast::Expr::ReturnExpr(it) => { diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index 9398b84b3fc..9b4e1380a46 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs @@ -137,6 +137,7 @@ fn valid_target_expr(node: SyntaxNode) -> Option { } } +#[derive(Debug)] enum Anchor { Before(SyntaxNode), Replace(ast::ExprStmt), @@ -148,7 +149,7 @@ impl Anchor { to_extract.syntax().ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find_map( |node| { if let Some(expr) = - node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) + node.parent().and_then(ast::StmtList::cast).and_then(|it| it.tail_expr()) { if expr.syntax() == &node { cov_mark::hit!(test_extract_var_last_expr); diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs index 9927ceb74ec..bd566ec8208 100644 --- a/crates/ide_assists/src/handlers/inline_call.rs +++ b/crates/ide_assists/src/handlers/inline_call.rs @@ -389,9 +389,13 @@ fn inline( _ => { let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone()); - body.push_front( - make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(), - ) + if let Some(stmt_list) = body.stmt_list() { + stmt_list.push_front( + make::let_stmt(pat.clone(), ty, Some(expr.clone())) + .clone_for_update() + .into(), + ) + } } } } diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs index 7e5c7870584..337cd6cb5a7 100644 --- a/crates/ide_assists/src/handlers/inline_local_variable.rs +++ b/crates/ide_assists/src/handlers/inline_local_variable.rs @@ -93,8 +93,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | ast::Expr::ArrayExpr(_) | ast::Expr::ParenExpr(_) | ast::Expr::PathExpr(_) - | ast::Expr::BlockExpr(_) - | ast::Expr::EffectExpr(_), + | ast::Expr::BlockExpr(_), ); let parent = matches!( usage_parent, diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs index e6aab9e8481..b860a3b6da8 100644 --- a/crates/ide_assists/src/handlers/remove_dbg.rs +++ b/crates/ide_assists/src/handlers/remove_dbg.rs @@ -46,7 +46,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { [] => { match_ast! { match parent { - ast::BlockExpr(__) => { + ast::StmtList(__) => { let range = macro_call.syntax().text_range(); let range = match whitespace_start(macro_call.syntax().prev_sibling_or_token()) { Some(start) => range.cover_offset(start), diff --git a/crates/ide_assists/src/handlers/unwrap_block.rs b/crates/ide_assists/src/handlers/unwrap_block.rs index cd6084f6b30..9171874e9d4 100644 --- a/crates/ide_assists/src/handlers/unwrap_block.rs +++ b/crates/ide_assists/src/handlers/unwrap_block.rs @@ -30,14 +30,14 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let assist_label = "Unwrap block"; let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?; - let mut block = ast::BlockExpr::cast(l_curly_token.parent()?)?; + let mut block = ast::BlockExpr::cast(l_curly_token.ancestors().nth(1)?)?; let target = block.syntax().text_range(); let mut parent = block.syntax().parent()?; if ast::MatchArm::can_cast(parent.kind()) { parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))? } - if matches!(parent.kind(), SyntaxKind::BLOCK_EXPR | SyntaxKind::EXPR_STMT) { + if matches!(parent.kind(), SyntaxKind::STMT_LIST | SyntaxKind::EXPR_STMT) { return acc.add(assist_id, assist_label, target, |builder| { builder.replace(block.syntax().text_range(), update_expr_string(block.to_string())); }); diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 2431f5c4e77..aa0956d0f61 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs @@ -25,30 +25,34 @@ use crate::assist_context::{AssistBuilder, AssistContext}; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; -pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { - extract_trivial_expression(&block) +pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr { + extract_trivial_expression(&block_expr) .filter(|expr| !expr.syntax().text().contains_char('\n')) - .unwrap_or_else(|| block.into()) + .unwrap_or_else(|| block_expr.into()) } -pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option { +pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option { + if block_expr.modifier().is_some() { + return None; + } + let stmt_list = block_expr.stmt_list()?; let has_anything_else = |thing: &SyntaxNode| -> bool { let mut non_trivial_children = - block.syntax().children_with_tokens().filter(|it| match it.kind() { + stmt_list.syntax().children_with_tokens().filter(|it| match it.kind() { WHITESPACE | T!['{'] | T!['}'] => false, _ => it.as_node() != Some(thing), }); non_trivial_children.next().is_some() }; - if let Some(expr) = block.tail_expr() { + if let Some(expr) = stmt_list.tail_expr() { if has_anything_else(expr.syntax()) { return None; } return Some(expr); } // Unwrap `{ continue; }` - let stmt = block.statements().next()?; + let stmt = stmt_list.statements().next()?; if let ast::Stmt::ExprStmt(expr_stmt) = stmt { if has_anything_else(expr_stmt.syntax()) { return None; diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index b9eaccaf55c..7edd2e28765 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs @@ -8,7 +8,7 @@ use ide_db::{ }; use syntax::{ ast::{self, AstNode, AstToken}, - SyntaxKind::{BLOCK_EXPR, EXPR_STMT}, + SyntaxKind::{EXPR_STMT, STMT_LIST}, TextRange, TextSize, }; use text_edit::TextEdit; @@ -256,7 +256,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { .add_to(acc); if let Some(parent) = dot_receiver.syntax().parent().and_then(|p| p.parent()) { - if matches!(parent.kind(), BLOCK_EXPR | EXPR_STMT) { + if matches!(parent.kind(), STMT_LIST | EXPR_STMT) { postfix_snippet( ctx, cap, diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index abc021acf11..7d5c36d01ff 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -326,7 +326,7 @@ impl<'a> CompletionContext<'a> { } pub(crate) fn has_block_expr_parent(&self) -> bool { - matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) + matches!(self.completion_location, Some(ImmediateLocation::StmtList)) } pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool { @@ -818,9 +818,9 @@ impl<'a> CompletionContext<'a> { if let Some(stmt) = ast::ExprStmt::cast(node.clone()) { return Some(stmt.syntax().text_range() == name_ref.syntax().text_range()); } - if let Some(block) = ast::BlockExpr::cast(node) { + if let Some(stmt_list) = ast::StmtList::cast(node) { return Some( - block.tail_expr().map(|e| e.syntax().text_range()) + stmt_list.tail_expr().map(|e| e.syntax().text_range()) == Some(name_ref.syntax().text_range()), ); } diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 6ceef0225a8..05792dd47ef 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -38,7 +38,7 @@ pub(crate) enum ImmediateLocation { TupleField, RefExpr, IdentPat, - BlockExpr, + StmtList, ItemList, TypeBound, // Fake file ast node @@ -201,7 +201,7 @@ pub(crate) fn determine_location( ast::Use(_it) => ImmediateLocation::Use, ast::UseTree(_it) => ImmediateLocation::UseTree, ast::UseTreeList(_it) => ImmediateLocation::UseTree, - ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, + ast::StmtList(_it) => ImmediateLocation::StmtList, ast::SourceFile(_it) => ImmediateLocation::ItemList, ast::ItemList(_it) => ImmediateLocation::ItemList, ast::RefExpr(_it) => ImmediateLocation::RefExpr, @@ -421,8 +421,8 @@ mod tests { #[test] fn test_block_expr_loc() { - check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr); - check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::BlockExpr); + check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::StmtList); + check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::StmtList); } #[test] diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index c92893716fb..a52c4046bfe 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs @@ -139,26 +139,27 @@ impl SnippetCap { pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { match expr { ast::Expr::BlockExpr(b) => { - if let Some(e) = b.tail_expr() { - for_each_tail_expr(&e, cb); - } - } - ast::Expr::EffectExpr(e) => match e.effect() { - ast::Effect::Label(label) => { - for_each_break_expr(Some(label), e.block_expr(), &mut |b| { - cb(&ast::Expr::BreakExpr(b)) - }); - if let Some(b) = e.block_expr() { - for_each_tail_expr(&ast::Expr::BlockExpr(b), cb); + match b.modifier() { + Some( + ast::BlockModifier::Async(_) + | ast::BlockModifier::Try(_) + | ast::BlockModifier::Const(_), + ) => return cb(expr), + + Some(ast::BlockModifier::Label(label)) => { + for_each_break_expr(Some(label), b.stmt_list(), &mut |b| { + cb(&ast::Expr::BreakExpr(b)) + }); } + Some(ast::BlockModifier::Unsafe(_)) => (), + None => (), } - ast::Effect::Unsafe(_) => { - if let Some(e) = e.block_expr().and_then(|b| b.tail_expr()) { + if let Some(stmt_list) = b.stmt_list() { + if let Some(e) = stmt_list.tail_expr() { for_each_tail_expr(&e, cb); } } - ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_) => cb(expr), - }, + } ast::Expr::IfExpr(if_) => { let mut if_ = if_.clone(); loop { @@ -176,7 +177,9 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { } } ast::Expr::LoopExpr(l) => { - for_each_break_expr(l.label(), l.loop_body(), &mut |b| cb(&ast::Expr::BreakExpr(b))) + for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| { + cb(&ast::Expr::BreakExpr(b)) + }) } ast::Expr::MatchExpr(m) => { if let Some(arms) = m.match_arm_list() { @@ -216,7 +219,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { /// Calls `cb` on each break expr inside of `body` that is applicable for the given label. pub fn for_each_break_expr( label: Option, - body: Option, + body: Option, cb: &mut dyn FnMut(ast::BreakExpr), ) { let label = label.and_then(|lbl| lbl.lifetime()); @@ -236,7 +239,7 @@ pub fn for_each_break_expr( ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => { depth += 1 } - ast::Expr::EffectExpr(e) if e.label().is_some() => depth += 1, + ast::Expr::BlockExpr(e) if e.label().is_some() => depth += 1, ast::Expr::BreakExpr(b) if (depth == 0 && b.lifetime().is_none()) || eq_label(b.lifetime()) => { @@ -248,7 +251,7 @@ pub fn for_each_break_expr( ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => { depth -= 1 } - ast::Expr::EffectExpr(e) if e.label().is_some() => depth -= 1, + ast::Expr::BlockExpr(e) if e.label().is_some() => depth -= 1, _ => (), }, } diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 8acad6a8ca4..a8ac0a90062 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs @@ -46,7 +46,7 @@ pub struct InsertUseConfig { pub enum ImportScope { File(ast::SourceFile), Module(ast::ItemList), - Block(ast::BlockExpr), + Block(ast::StmtList), } impl ImportScope { @@ -60,15 +60,15 @@ impl ImportScope { match syntax { ast::Module(module) => module.item_list().map(ImportScope::Module), ast::SourceFile(file) => Some(ImportScope::File(file)), - ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().map(ImportScope::Block)).flatten(), + ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().and_then(|it| it.stmt_list().map(ImportScope::Block))).flatten(), ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? { ast::Expr::BlockExpr(block) => Some(block), _ => None, - }).flatten().map(ImportScope::Block), + }).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)), ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? { ast::Expr::BlockExpr(block) => Some(block), _ => None, - }).flatten().map(ImportScope::Block), + }).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)), _ => None, } diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index c5420f46796..339360ba4a4 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs @@ -1,8 +1,8 @@ -use super::*; - use hir::PrefixKind; use test_utils::{assert_eq_text, extract_range_or_offset, CURSOR_MARKER}; +use super::*; + #[test] fn respects_cfg_attr_fn() { check( diff --git a/crates/ide_db/src/helpers/node_ext.rs b/crates/ide_db/src/helpers/node_ext.rs index 24f853737b8..fe823f74f8b 100644 --- a/crates/ide_db/src/helpers/node_ext.rs +++ b/crates/ide_db/src/helpers/node_ext.rs @@ -32,8 +32,8 @@ pub fn walk_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Expr)) { /// Preorder walk all the expression's child expressions preserving events. /// If the callback returns true on an [`WalkEvent::Enter`], the subtree of the expression will be skipped. /// Note that the subtree may already be skipped due to the context analysis this function does. -pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent) -> bool) { - let mut preorder = expr.syntax().preorder(); +pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent) -> bool) { + let mut preorder = start.syntax().preorder(); while let Some(event) = preorder.next() { let node = match event { WalkEvent::Enter(node) => node, @@ -44,17 +44,17 @@ pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent) continue; } }; - match ast::Stmt::cast(node.clone()) { - // recursively walk the initializer, skipping potential const pat expressions - // let statements aren't usually nested too deeply so this is fine to recurse on - Some(ast::Stmt::LetStmt(l)) => { - if let Some(expr) = l.initializer() { - preorder_expr(&expr, cb); - } + if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) { + if Some(node.clone()) != let_stmt.initializer().map(|it| it.syntax().clone()) { + // skipping potential const pat expressions in let statements preorder.skip_subtree(); + continue; } + } + + match ast::Stmt::cast(node.clone()) { // Don't skip subtree since we want to process the expression child next - Some(ast::Stmt::ExprStmt(_)) => (), + Some(ast::Stmt::ExprStmt(_)) | Some(ast::Stmt::LetStmt(_)) => (), // This might be an expression Some(ast::Stmt::Item(ast::Item::MacroCall(mcall))) => { cb(WalkEvent::Enter(ast::Expr::MacroCall(mcall))); @@ -68,15 +68,19 @@ pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent) preorder.skip_subtree(); } else if let Some(expr) = ast::Expr::cast(node) { let is_different_context = match &expr { - ast::Expr::EffectExpr(effect) => { + ast::Expr::BlockExpr(block_expr) => { matches!( - effect.effect(), - ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_) + block_expr.modifier(), + Some( + ast::BlockModifier::Async(_) + | ast::BlockModifier::Try(_) + | ast::BlockModifier::Const(_) + ) ) } ast::Expr::ClosureExpr(_) => true, _ => false, - }; + } && expr.syntax() != start.syntax(); let skip = cb(WalkEvent::Enter(expr)); if skip || is_different_context { preorder.skip_subtree(); @@ -88,8 +92,8 @@ pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent) } /// Preorder walk all the expression's child patterns. -pub fn walk_patterns_in_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) { - let mut preorder = expr.syntax().preorder(); +pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) { + let mut preorder = start.syntax().preorder(); while let Some(event) = preorder.next() { let node = match event { WalkEvent::Enter(node) => node, @@ -115,15 +119,19 @@ pub fn walk_patterns_in_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) { preorder.skip_subtree(); } else if let Some(expr) = ast::Expr::cast(node.clone()) { let is_different_context = match &expr { - ast::Expr::EffectExpr(effect) => match effect.effect() { - ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_) => { - true - } - ast::Effect::Unsafe(_) | ast::Effect::Label(_) => false, - }, + ast::Expr::BlockExpr(block_expr) => { + matches!( + block_expr.modifier(), + Some( + ast::BlockModifier::Async(_) + | ast::BlockModifier::Try(_) + | ast::BlockModifier::Const(_) + ) + ) + } ast::Expr::ClosureExpr(_) => true, _ => false, - }; + } && expr.syntax() != start.syntax(); if is_different_context { preorder.skip_subtree(); } diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs index eb2e2f6a503..df374aea981 100644 --- a/crates/mbe/src/tests/expand.rs +++ b/crates/mbe/src/tests/expand.rs @@ -217,20 +217,21 @@ fn test_expr_order() { L_PAREN@5..6 "(" R_PAREN@6..7 ")" BLOCK_EXPR@7..15 - L_CURLY@7..8 "{" - EXPR_STMT@8..14 - BIN_EXPR@8..13 - BIN_EXPR@8..11 - LITERAL@8..9 - INT_NUMBER@8..9 "1" - PLUS@9..10 "+" - LITERAL@10..11 - INT_NUMBER@10..11 "1" - STAR@11..12 "*" - LITERAL@12..13 - INT_NUMBER@12..13 "2" - SEMICOLON@13..14 ";" - R_CURLY@14..15 "}""#, + STMT_LIST@7..15 + L_CURLY@7..8 "{" + EXPR_STMT@8..14 + BIN_EXPR@8..13 + BIN_EXPR@8..11 + LITERAL@8..9 + INT_NUMBER@8..9 "1" + PLUS@9..10 "+" + LITERAL@10..11 + INT_NUMBER@10..11 "1" + STAR@11..12 "*" + LITERAL@12..13 + INT_NUMBER@12..13 "2" + SEMICOLON@13..14 ";" + R_CURLY@14..15 "}""#, dump.trim() ); } @@ -1320,70 +1321,72 @@ fn test_vec() { let tree = fixture.expand_expr(r#"vec![1u32,2];"#); - assert_eq!( - format!("{:#?}", tree).trim(), + assert_eq_text!( + &format!("{:#?}", tree), r#"BLOCK_EXPR@0..45 - L_CURLY@0..1 "{" - LET_STMT@1..20 - LET_KW@1..4 "let" - IDENT_PAT@4..8 - MUT_KW@4..7 "mut" - NAME@7..8 - IDENT@7..8 "v" - EQ@8..9 "=" - CALL_EXPR@9..19 - PATH_EXPR@9..17 - PATH@9..17 - PATH@9..12 - PATH_SEGMENT@9..12 - NAME_REF@9..12 - IDENT@9..12 "Vec" - COLON2@12..14 "::" - PATH_SEGMENT@14..17 - NAME_REF@14..17 - IDENT@14..17 "new" - ARG_LIST@17..19 - L_PAREN@17..18 "(" - R_PAREN@18..19 ")" - SEMICOLON@19..20 ";" - EXPR_STMT@20..33 - METHOD_CALL_EXPR@20..32 - PATH_EXPR@20..21 - PATH@20..21 - PATH_SEGMENT@20..21 - NAME_REF@20..21 - IDENT@20..21 "v" - DOT@21..22 "." - NAME_REF@22..26 - IDENT@22..26 "push" - ARG_LIST@26..32 - L_PAREN@26..27 "(" - LITERAL@27..31 - INT_NUMBER@27..31 "1u32" - R_PAREN@31..32 ")" - SEMICOLON@32..33 ";" - EXPR_STMT@33..43 - METHOD_CALL_EXPR@33..42 - PATH_EXPR@33..34 - PATH@33..34 - PATH_SEGMENT@33..34 - NAME_REF@33..34 - IDENT@33..34 "v" - DOT@34..35 "." - NAME_REF@35..39 - IDENT@35..39 "push" - ARG_LIST@39..42 - L_PAREN@39..40 "(" - LITERAL@40..41 - INT_NUMBER@40..41 "2" - R_PAREN@41..42 ")" - SEMICOLON@42..43 ";" - PATH_EXPR@43..44 - PATH@43..44 - PATH_SEGMENT@43..44 - NAME_REF@43..44 - IDENT@43..44 "v" - R_CURLY@44..45 "}""# + STMT_LIST@0..45 + L_CURLY@0..1 "{" + LET_STMT@1..20 + LET_KW@1..4 "let" + IDENT_PAT@4..8 + MUT_KW@4..7 "mut" + NAME@7..8 + IDENT@7..8 "v" + EQ@8..9 "=" + CALL_EXPR@9..19 + PATH_EXPR@9..17 + PATH@9..17 + PATH@9..12 + PATH_SEGMENT@9..12 + NAME_REF@9..12 + IDENT@9..12 "Vec" + COLON2@12..14 "::" + PATH_SEGMENT@14..17 + NAME_REF@14..17 + IDENT@14..17 "new" + ARG_LIST@17..19 + L_PAREN@17..18 "(" + R_PAREN@18..19 ")" + SEMICOLON@19..20 ";" + EXPR_STMT@20..33 + METHOD_CALL_EXPR@20..32 + PATH_EXPR@20..21 + PATH@20..21 + PATH_SEGMENT@20..21 + NAME_REF@20..21 + IDENT@20..21 "v" + DOT@21..22 "." + NAME_REF@22..26 + IDENT@22..26 "push" + ARG_LIST@26..32 + L_PAREN@26..27 "(" + LITERAL@27..31 + INT_NUMBER@27..31 "1u32" + R_PAREN@31..32 ")" + SEMICOLON@32..33 ";" + EXPR_STMT@33..43 + METHOD_CALL_EXPR@33..42 + PATH_EXPR@33..34 + PATH@33..34 + PATH_SEGMENT@33..34 + NAME_REF@33..34 + IDENT@33..34 "v" + DOT@34..35 "." + NAME_REF@35..39 + IDENT@35..39 "push" + ARG_LIST@39..42 + L_PAREN@39..40 "(" + LITERAL@40..41 + INT_NUMBER@40..41 "2" + R_PAREN@41..42 ")" + SEMICOLON@42..43 ";" + PATH_EXPR@43..44 + PATH@43..44 + PATH_SEGMENT@43..44 + NAME_REF@43..44 + IDENT@43..44 "v" + R_CURLY@44..45 "}" +"# ); } diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index f6e9a5f1b34..bb70c0d9322 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs @@ -93,8 +93,8 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar // test labeled_block // fn f() { 'label: {}; } T!['{'] => { - block_expr(p); - m.complete(p, EFFECT_EXPR) + stmt_list(p); + m.complete(p, BLOCK_EXPR) } _ => { // test_err misplaced_label_err @@ -111,8 +111,8 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar let m = p.start(); p.bump(T![async]); p.eat(T![move]); - block_expr(p); - m.complete(p, EFFECT_EXPR) + stmt_list(p); + m.complete(p, BLOCK_EXPR) } T![match] => match_expr(p), // test unsafe_block @@ -120,16 +120,16 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar T![unsafe] if la == T!['{'] => { let m = p.start(); p.bump(T![unsafe]); - block_expr(p); - m.complete(p, EFFECT_EXPR) + stmt_list(p); + m.complete(p, BLOCK_EXPR) } // test const_block // fn f() { const { } } T![const] if la == T!['{'] => { let m = p.start(); p.bump(T![const]); - block_expr(p); - m.complete(p, EFFECT_EXPR) + stmt_list(p); + m.complete(p, BLOCK_EXPR) } T!['{'] => { // test for_range_from @@ -138,7 +138,9 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar // break; // } // } - block_expr_unchecked(p) + let m = p.start(); + stmt_list(p); + m.complete(p, BLOCK_EXPR) } T![return] => return_expr(p), T![yield] => yield_expr(p), @@ -150,9 +152,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar } }; let blocklike = match done.kind() { - IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | EFFECT_EXPR => { - BlockLike::Block - } + IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block, _ => BlockLike::NotBlock, }; Some((done, blocklike)) @@ -486,16 +486,18 @@ pub(crate) fn block_expr(p: &mut Parser) { p.error("expected a block"); return; } - block_expr_unchecked(p); + let m = p.start(); + stmt_list(p); + m.complete(p, BLOCK_EXPR); } -fn block_expr_unchecked(p: &mut Parser) -> CompletedMarker { +fn stmt_list(p: &mut Parser) -> CompletedMarker { assert!(p.at(T!['{'])); let m = p.start(); p.bump(T!['{']); expr_block_contents(p); p.expect(T!['}']); - m.complete(p, BLOCK_EXPR) + m.complete(p, STMT_LIST) } // test return_expr @@ -597,8 +599,12 @@ fn try_block_expr(p: &mut Parser, m: Option) -> CompletedMarker { } p.bump(T![try]); - block_expr(p); - m.complete(p, EFFECT_EXPR) + if p.at(T!['{']) { + stmt_list(p); + } else { + p.error("expected a block") + } + m.complete(p, BLOCK_EXPR) } // test box_expr diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 0986b23bf81..842d66755c6 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -187,6 +187,7 @@ pub enum SyntaxKind { BREAK_EXPR, LABEL, BLOCK_EXPR, + STMT_LIST, RETURN_EXPR, YIELD_EXPR, MATCH_EXPR, @@ -196,7 +197,6 @@ pub enum SyntaxKind { RECORD_EXPR, RECORD_EXPR_FIELD_LIST, RECORD_EXPR_FIELD, - EFFECT_EXPR, BOX_EXPR, CALL_EXPR, INDEX_EXPR, diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 6a48a322a66..f889fa2a2c3 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -29,7 +29,7 @@ rayon = "1" expect-test = "1.1" proc-macro2 = "1.0.8" quote = "1.0.2" -ungrammar = "=1.14" +ungrammar = "=1.14.5" test_utils = { path = "../test_utils" } sourcegen = { path = "../sourcegen" } diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 7c9200f5688..e07b22a550e 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs @@ -18,7 +18,7 @@ use crate::{ }; pub use self::{ - expr_ext::{ArrayExprKind, Effect, ElseBranch, LiteralKind}, + expr_ext::{ArrayExprKind, BlockModifier, ElseBranch, LiteralKind}, generated::{nodes::*, tokens::*}, node_ext::{ AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind, diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 9c5ae9a156d..d6775c89ba7 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -451,7 +451,7 @@ impl ast::RecordExprFieldList { } } -impl ast::BlockExpr { +impl ast::StmtList { pub fn push_front(&self, statement: ast::Stmt) { ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax()); } diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index 9d78cb226fd..4f92cc06716 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs @@ -25,7 +25,6 @@ impl ast::Expr { | ast::Expr::WhileExpr(_) | ast::Expr::BlockExpr(_) | ast::Expr::MatchExpr(_) - | ast::Expr::EffectExpr(_) ) } } @@ -268,38 +267,23 @@ impl ast::Literal { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Effect { +pub enum BlockModifier { Async(SyntaxToken), Unsafe(SyntaxToken), Try(SyntaxToken), Const(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(token) = self.const_token() { - return Effect::Const(token); - } - if let Some(label) = self.label() { - return Effect::Label(label); - } - unreachable!("ast::EffectExpr without Effect") - } -} - impl ast::BlockExpr { + pub fn modifier(&self) -> Option { + self.async_token() + .map(BlockModifier::Async) + .or_else(|| self.unsafe_token().map(BlockModifier::Unsafe)) + .or_else(|| self.try_token().map(BlockModifier::Try)) + .or_else(|| self.const_token().map(BlockModifier::Const)) + .or_else(|| self.label().map(BlockModifier::Label)) + } /// false if the block is an intrinsic part of the syntax and can't be /// replaced with arbitrary expression. /// @@ -312,7 +296,7 @@ impl ast::BlockExpr { Some(it) => it, None => return true, }; - !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR) + !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR) } } diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 547e7546364..066ad91d38a 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -477,10 +477,12 @@ pub struct BlockExpr { } impl ast::AttrsOwner for BlockExpr {} impl BlockExpr { - pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } - pub fn statements(&self) -> AstChildren { support::children(&self.syntax) } - pub fn tail_expr(&self) -> Option { support::child(&self.syntax) } - pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } + pub fn label(&self) -> Option