diff --git a/crates/hir-analysis/src/name_resolution/mod.rs b/crates/hir-analysis/src/name_resolution/mod.rs index 545d6c7d4..d9d5af904 100644 --- a/crates/hir-analysis/src/name_resolution/mod.rs +++ b/crates/hir-analysis/src/name_resolution/mod.rs @@ -425,7 +425,7 @@ impl<'db, 'a> Visitor for EarlyPathVisitor<'db, 'a> { expr: ExprId, expr_data: &Expr, ) { - if matches!(expr_data, Expr::Block(_)) { + if matches!(expr_data, Expr::Block { .. }) { walk_expr(self, ctxt, expr) } } diff --git a/crates/hir/src/hir_def/body.rs b/crates/hir/src/hir_def/body.rs index 2ceb9c02f..0acf86ff1 100644 --- a/crates/hir/src/hir_def/body.rs +++ b/crates/hir/src/hir_def/body.rs @@ -164,7 +164,7 @@ impl<'db> Visitor for BlockOrderCalculator<'db> { expr: ExprId, expr_data: &Expr, ) { - if ctxt.body() == self.body && matches!(expr_data, Expr::Block(..)) { + if ctxt.body() == self.body && matches!(expr_data, Expr::Block { .. }) { self.order.insert(expr, self.fresh_number); self.fresh_number += 1; } diff --git a/crates/hir/src/hir_def/expr.rs b/crates/hir/src/hir_def/expr.rs index 18ec5596c..ce7e5896f 100644 --- a/crates/hir/src/hir_def/expr.rs +++ b/crates/hir/src/hir_def/expr.rs @@ -7,7 +7,10 @@ use super::{Body, GenericArgListId, IdentId, IntegerId, LitKind, Partial, PatId, #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Expr { Lit(LitKind), - Block(Vec), + Block { + stmts: Vec, + is_unsafe: bool, + }, /// The first `ExprId` is the lhs, the second is the rhs. /// /// and a `BinOp`. diff --git a/crates/hir/src/lower/expr.rs b/crates/hir/src/lower/expr.rs index 54f192196..da9d8ccff 100644 --- a/crates/hir/src/lower/expr.rs +++ b/crates/hir/src/lower/expr.rs @@ -29,7 +29,13 @@ impl Expr { let stmt = Stmt::push_to_body(ctxt, stmt); stmts.push(stmt); } - let expr_id = ctxt.push_expr(Self::Block(stmts), HirOrigin::raw(&ast)); + let expr_id = ctxt.push_expr( + Self::Block { + stmts, + is_unsafe: block.unsafe_kw().is_some(), + }, + HirOrigin::raw(&ast), + ); for item in block.items() { ItemKind::lower_ast(ctxt.f_ctxt, item); diff --git a/crates/hir/src/span/expr.rs b/crates/hir/src/span/expr.rs index 2e0ab24f8..9dfac9baa 100644 --- a/crates/hir/src/span/expr.rs +++ b/crates/hir/src/span/expr.rs @@ -199,6 +199,14 @@ define_lazy_span_node!( define_lazy_span_node!(LazyMatchArmSpan); +define_lazy_span_node!( + LazyBlockExprSpan, + ast::BlockExpr, + @token { + (unsafe_kw, unsafe_kw), + } +); + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub(crate) struct ExprRoot { expr: ExprId, diff --git a/crates/hir/src/visitor.rs b/crates/hir/src/visitor.rs index 158b0c6d8..b60561212 100644 --- a/crates/hir/src/visitor.rs +++ b/crates/hir/src/visitor.rs @@ -909,7 +909,7 @@ where }, ), - Expr::Block(stmts) => { + Expr::Block { stmts, .. } => { let s_graph = ctxt.top_mod().scope_graph(ctxt.db); let scope = ctxt.scope(); for item in s_graph.child_items(scope) { @@ -1987,7 +1987,7 @@ where /// `scope` is the scope that encloses the expression. pub fn with_expr(db: &'db dyn HirDb, scope: ScopeId, body: Body, expr: ExprId) -> Self { let scope_id = match expr.data(db, body) { - Partial::Present(Expr::Block(_)) => ScopeId::Block(body, expr), + Partial::Present(Expr::Block { .. }) => ScopeId::Block(body, expr), _ => scope, }; diff --git a/crates/parser2/src/ast/expr.rs b/crates/parser2/src/ast/expr.rs index 0fda11b03..2725b7da6 100644 --- a/crates/parser2/src/ast/expr.rs +++ b/crates/parser2/src/ast/expr.rs @@ -74,6 +74,10 @@ impl BlockExpr { pub fn items(&self) -> impl Iterator { support::children(self.syntax()) } + + pub fn unsafe_kw(&self) -> Option { + support::token(self.syntax(), SK::UnsafeKw) + } } ast_node! { diff --git a/crates/parser2/src/parser/expr_atom.rs b/crates/parser2/src/parser/expr_atom.rs index 52fa229b1..bdfaaaedf 100644 --- a/crates/parser2/src/parser/expr_atom.rs +++ b/crates/parser2/src/parser/expr_atom.rs @@ -23,6 +23,7 @@ pub(super) fn parse_expr_atom( match parser.current_kind() { Some(IfKw) => parser.parse(IfExprScope::default(), None), Some(MatchKw) => parser.parse(MatchExprScope::default(), None), + Some(UnsafeKw) => parser.parse(BlockExprScope::default(), None), Some(LBrace) => parser.parse(BlockExprScope::default(), None), Some(LParen) => parser.parse(ParenScope::default(), None), Some(LBracket) => parser.parse(ArrayScope::default(), None), @@ -53,6 +54,10 @@ define_scope! { } impl super::Parse for BlockExprScope { fn parse(&mut self, parser: &mut Parser) { + if parser.current_kind() == Some(SyntaxKind::UnsafeKw) { + parser.bump_expected(SyntaxKind::UnsafeKw); + } + parser.bump_expected(SyntaxKind::LBrace); loop { @@ -67,8 +72,14 @@ impl super::Parse for BlockExprScope { .map(SyntaxKind::is_item_head) .unwrap_or_default() { - parser.parse(ItemScope::default(), None); - continue; + let is_unsafe_block = parser.dry_run(|parser| { + parser.bump_if(SyntaxKind::UnsafeKw) && parser.bump_if(SyntaxKind::LBrace) + }); + + if !is_unsafe_block { + parser.parse(ItemScope::default(), None); + continue; + } } if !parse_stmt(parser, None) { diff --git a/crates/parser2/src/parser/item.rs b/crates/parser2/src/parser/item.rs index 35f545801..a693e8ef4 100644 --- a/crates/parser2/src/parser/item.rs +++ b/crates/parser2/src/parser/item.rs @@ -71,6 +71,13 @@ impl super::Parse for ItemScope { fn parse(&mut self, parser: &mut Parser) { use crate::SyntaxKind::*; + // if parser.peek_two() == (Some(UnsafeKw), Some(LBrace)) { + // parser.parse(BlockExprScope::default(), None); + // return; + // } else { + // println!("{:?}", parser.peek_two(),) + // } + let mut checkpoint = attr::parse_attr_list(parser); let modifier_scope = ItemModifierScope::default(); let modifier = match parser.current_kind() { diff --git a/crates/parser2/test_files/syntax_node/exprs/unsafe.fe b/crates/parser2/test_files/syntax_node/exprs/unsafe.fe new file mode 100644 index 000000000..0c43ca83d --- /dev/null +++ b/crates/parser2/test_files/syntax_node/exprs/unsafe.fe @@ -0,0 +1,7 @@ +unsafe { foo() } + +unsafe { + let a = 42 + std::evm::mstore(offset: 0, value: a) + return +} diff --git a/crates/parser2/test_files/syntax_node/exprs/unsafe.snap b/crates/parser2/test_files/syntax_node/exprs/unsafe.snap new file mode 100644 index 000000000..1c3ed4bff --- /dev/null +++ b/crates/parser2/test_files/syntax_node/exprs/unsafe.snap @@ -0,0 +1,84 @@ +--- +source: crates/parser2/tests/syntax_node.rs +expression: node +input_file: crates/parser2/test_files/syntax_node/exprs/unsafe.fe +--- +Root@0..97 + BlockExpr@0..16 + UnsafeKw@0..6 "unsafe" + WhiteSpace@6..7 " " + LBrace@7..8 "{" + WhiteSpace@8..9 " " + ExprStmt@9..14 + CallExpr@9..14 + PathExpr@9..12 + Path@9..12 + PathSegment@9..12 + Ident@9..12 "foo" + CallArgList@12..14 + LParen@12..13 "(" + RParen@13..14 ")" + WhiteSpace@14..15 " " + RBrace@15..16 "}" + Newline@16..18 "\n\n" + BlockExpr@18..96 + UnsafeKw@18..24 "unsafe" + WhiteSpace@24..25 " " + LBrace@25..26 "{" + Newline@26..27 "\n" + WhiteSpace@27..31 " " + LetStmt@31..41 + LetKw@31..34 "let" + WhiteSpace@34..35 " " + PathPat@35..36 + Path@35..36 + PathSegment@35..36 + Ident@35..36 "a" + WhiteSpace@36..37 " " + Eq@37..38 "=" + WhiteSpace@38..39 " " + LitExpr@39..41 + Lit@39..41 + Int@39..41 "42" + Newline@41..42 "\n" + WhiteSpace@42..46 " " + ExprStmt@46..83 + CallExpr@46..83 + PathExpr@46..62 + Path@46..62 + PathSegment@46..49 + Ident@46..49 "std" + Colon2@49..51 "::" + PathSegment@51..54 + Ident@51..54 "evm" + Colon2@54..56 "::" + PathSegment@56..62 + Ident@56..62 "mstore" + CallArgList@62..83 + LParen@62..63 "(" + CallArg@63..72 + Ident@63..69 "offset" + Colon@69..70 ":" + WhiteSpace@70..71 " " + LitExpr@71..72 + Lit@71..72 + Int@71..72 "0" + Comma@72..73 "," + WhiteSpace@73..74 " " + CallArg@74..82 + Ident@74..79 "value" + Colon@79..80 ":" + WhiteSpace@80..81 " " + PathExpr@81..82 + Path@81..82 + PathSegment@81..82 + Ident@81..82 "a" + RParen@82..83 ")" + Newline@83..84 "\n" + WhiteSpace@84..88 " " + ReturnStmt@88..94 + ReturnKw@88..94 "return" + Newline@94..95 "\n" + RBrace@95..96 "}" + Newline@96..97 "\n" + diff --git a/crates/parser2/test_files/syntax_node/items/func.fe b/crates/parser2/test_files/syntax_node/items/func.fe index c8d6f445f..9bc9b3738 100644 --- a/crates/parser2/test_files/syntax_node/items/func.fe +++ b/crates/parser2/test_files/syntax_node/items/func.fe @@ -18,4 +18,26 @@ fn generics1(t: T, u: Option) -> T t } -fn decl(t: MyStruct) -> Result {} \ No newline at end of file +fn decl(t: MyStruct) -> Result {} + +fn foo() { + unsafe { + bar() + } +} + +fn foo2() { + unsafe { + bar2() + } +} + +pub unsafe fn foo3() { + unsafe + + + { + bar3() + } +} + diff --git a/crates/parser2/test_files/syntax_node/items/func.snap b/crates/parser2/test_files/syntax_node/items/func.snap index 88833e5df..b228d2ce9 100644 --- a/crates/parser2/test_files/syntax_node/items/func.snap +++ b/crates/parser2/test_files/syntax_node/items/func.snap @@ -3,8 +3,8 @@ source: crates/parser2/tests/syntax_node.rs expression: node input_file: crates/parser2/test_files/syntax_node/items/func.fe --- -Root@0..361 - ItemList@0..361 +Root@0..532 + ItemList@0..532 Item@0..32 Func@0..30 ItemModifier@0..3 @@ -282,7 +282,7 @@ Root@0..361 Newline@304..305 "\n" RBrace@305..306 "}" Newline@306..308 "\n\n" - Item@308..361 + Item@308..363 Func@308..361 FnKw@308..310 "fn" WhiteSpace@310..311 " " @@ -348,4 +348,118 @@ Root@0..361 BlockExpr@359..361 LBrace@359..360 "{" RBrace@360..361 "}" + Newline@361..363 "\n\n" + Item@363..410 + Func@363..408 + FnKw@363..365 "fn" + WhiteSpace@365..366 " " + Ident@366..369 "foo" + FuncParamList@369..371 + LParen@369..370 "(" + RParen@370..371 ")" + WhiteSpace@371..372 " " + BlockExpr@372..408 + LBrace@372..373 "{" + Newline@373..374 "\n" + WhiteSpace@374..378 " " + ExprStmt@378..406 + BlockExpr@378..406 + UnsafeKw@378..384 "unsafe" + WhiteSpace@384..385 " " + LBrace@385..386 "{" + Newline@386..387 "\n" + WhiteSpace@387..395 " " + ExprStmt@395..400 + CallExpr@395..400 + PathExpr@395..398 + Path@395..398 + PathSegment@395..398 + Ident@395..398 "bar" + CallArgList@398..400 + LParen@398..399 "(" + RParen@399..400 ")" + Newline@400..401 "\n" + WhiteSpace@401..405 " " + RBrace@405..406 "}" + Newline@406..407 "\n" + RBrace@407..408 "}" + Newline@408..410 "\n\n" + Item@410..462 + Func@410..460 + FnKw@410..412 "fn" + WhiteSpace@412..413 " " + Ident@413..417 "foo2" + FuncParamList@417..419 + LParen@417..418 "(" + RParen@418..419 ")" + WhiteSpace@419..420 " " + BlockExpr@420..460 + LBrace@420..421 "{" + Newline@421..422 "\n" + WhiteSpace@422..426 " " + ExprStmt@426..458 + BlockExpr@426..458 + UnsafeKw@426..432 "unsafe" + WhiteSpace@432..436 " " + LBrace@436..437 "{" + Newline@437..438 "\n" + WhiteSpace@438..446 " " + ExprStmt@446..452 + CallExpr@446..452 + PathExpr@446..450 + Path@446..450 + PathSegment@446..450 + Ident@446..450 "bar2" + CallArgList@450..452 + LParen@450..451 "(" + RParen@451..452 ")" + Newline@452..453 "\n" + WhiteSpace@453..457 " " + RBrace@457..458 "}" + Newline@458..459 "\n" + RBrace@459..460 "}" + Newline@460..462 "\n\n" + Item@462..532 + Func@462..530 + ItemModifier@462..472 + PubKw@462..465 "pub" + WhiteSpace@465..466 " " + UnsafeKw@466..472 "unsafe" + WhiteSpace@472..473 " " + FnKw@473..475 "fn" + WhiteSpace@475..476 " " + Ident@476..480 "foo3" + FuncParamList@480..482 + LParen@480..481 "(" + RParen@481..482 ")" + WhiteSpace@482..483 " " + BlockExpr@483..530 + LBrace@483..484 "{" + Newline@484..485 "\n" + WhiteSpace@485..489 " " + ExprStmt@489..528 + BlockExpr@489..528 + UnsafeKw@489..495 "unsafe" + Newline@495..496 "\n" + WhiteSpace@496..500 " " + Newline@500..502 "\n\n" + WhiteSpace@502..506 " " + LBrace@506..507 "{" + Newline@507..508 "\n" + WhiteSpace@508..516 " " + ExprStmt@516..522 + CallExpr@516..522 + PathExpr@516..520 + Path@516..520 + PathSegment@516..520 + Ident@516..520 "bar3" + CallArgList@520..522 + LParen@520..521 "(" + RParen@521..522 ")" + Newline@522..523 "\n" + WhiteSpace@523..527 " " + RBrace@527..528 "}" + Newline@528..529 "\n" + RBrace@529..530 "}" + Newline@530..532 "\n\n" diff --git a/crates/parser2/test_files/syntax_node/stmts/let.fe b/crates/parser2/test_files/syntax_node/stmts/let.fe index 4582f9b69..7063594da 100644 --- a/crates/parser2/test_files/syntax_node/stmts/let.fe +++ b/crates/parser2/test_files/syntax_node/stmts/let.fe @@ -20,4 +20,8 @@ let x = if b { let x = match b { MyEnum::A(x) | MyEnum::B(x) => x _ => 0 +} + +let z = unsafe { + foo() } \ No newline at end of file diff --git a/crates/parser2/test_files/syntax_node/stmts/let.snap b/crates/parser2/test_files/syntax_node/stmts/let.snap index ffd3cf7c1..0e26ad659 100644 --- a/crates/parser2/test_files/syntax_node/stmts/let.snap +++ b/crates/parser2/test_files/syntax_node/stmts/let.snap @@ -3,7 +3,7 @@ source: crates/parser2/tests/syntax_node.rs expression: node input_file: crates/parser2/test_files/syntax_node/stmts/let.fe --- -Root@0..231 +Root@0..261 LetStmt@0..5 LetKw@0..3 "let" WhiteSpace@3..4 " " @@ -298,4 +298,32 @@ Root@0..231 Int@228..229 "0" Newline@229..230 "\n" RBrace@230..231 "}" + Newline@231..233 "\n\n" + LetStmt@233..261 + LetKw@233..236 "let" + WhiteSpace@236..237 " " + PathPat@237..238 + Path@237..238 + PathSegment@237..238 + Ident@237..238 "z" + WhiteSpace@238..239 " " + Eq@239..240 "=" + WhiteSpace@240..241 " " + BlockExpr@241..261 + UnsafeKw@241..247 "unsafe" + WhiteSpace@247..248 " " + LBrace@248..249 "{" + Newline@249..250 "\n" + WhiteSpace@250..254 " " + ExprStmt@254..259 + CallExpr@254..259 + PathExpr@254..257 + Path@254..257 + PathSegment@254..257 + Ident@254..257 "foo" + CallArgList@257..259 + LParen@257..258 "(" + RParen@258..259 ")" + Newline@259..260 "\n" + RBrace@260..261 "}"