Repository: rust-analyzer/rust-analyzer
Pull request #4261 (2020-05-02 12:36:37)

Fix parsing of blocks without `{`


bors r+
🤖


Patch:
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index d9824ff9bd..be0cd5661b 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -54,7 +54,7 @@ pub(crate) mod fragments {
     use super::*;
 
     pub(crate) use super::{
-        expressions::block, paths::type_path as path, patterns::pattern, types::type_,
+        expressions::block_expr, paths::type_path as path, patterns::pattern, types::type_,
     };
 
     pub(crate) fn expr(p: &mut Parser) {
@@ -143,7 +143,7 @@ pub(crate) fn reparser(
     parent: Option<SyntaxKind>,
 ) -> Option<fn(&mut Parser)> {
     let res = match node {
-        BLOCK_EXPR => expressions::block,
+        BLOCK_EXPR => expressions::block_expr,
         RECORD_FIELD_DEF_LIST => items::record_field_def_list,
         RECORD_FIELD_LIST => items::record_field_list,
         ENUM_VARIANT_LIST => items::enum_variant_list,
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index a23dbcacf0..34f0397686 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -2,7 +2,7 @@
 
 mod atom;
 
-pub(crate) use self::atom::match_arm_list;
+pub(crate) use self::atom::{block_expr, match_arm_list};
 pub(super) use self::atom::{literal, LITERAL_FIRST};
 use super::*;
 
@@ -49,19 +49,6 @@ fn expr_no_struct(p: &mut Parser) {
     expr_bp(p, r, 1);
 }
 
-// test block
-// fn a() {}
-// fn b() { let _ = 1; }
-// fn c() { 1; 2; }
-// fn d() { 1; 2 }
-pub(crate) fn block(p: &mut Parser) {
-    if !p.at(T!['{']) {
-        p.error("expected a block");
-        return;
-    }
-    atom::block_expr(p);
-}
-
 fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
     match kind {
         BIN_EXPR | RANGE_EXPR | IF_EXPR => false,
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index efb424dae7..706a2f796b 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -132,7 +132,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
             //        break;
             //    }
             // }
-            block_expr(p)
+            block_expr_unchecked(p)
         }
         T![return] => return_expr(p),
         T![continue] => continue_expr(p),
@@ -240,13 +240,9 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
     p.eat(T![move]);
     params::param_list_closure(p);
     if opt_fn_ret_type(p) {
-        if p.at(T!['{']) {
-            // test lambda_ret_block
-            // fn main() { || -> i32 { 92 }(); }
-            block_expr(p);
-        } else {
-            p.error("expected `{`");
-        }
+        // test lambda_ret_block
+        // fn main() { || -> i32 { 92 }(); }
+        block_expr(p);
     } else {
         if p.at_ts(EXPR_FIRST) {
             expr(p);
@@ -270,13 +266,13 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
     let m = p.start();
     p.bump(T![if]);
     cond(p);
-    block(p);
+    block_expr(p);
     if p.at(T![else]) {
         p.bump(T![else]);
         if p.at(T![if]) {
             if_expr(p);
         } else {
-            block(p);
+            block_expr(p);
         }
     }
     m.complete(p, IF_EXPR)
@@ -304,7 +300,7 @@ fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     assert!(p.at(T![loop]));
     let m = m.unwrap_or_else(|| p.start());
     p.bump(T![loop]);
-    block(p);
+    block_expr(p);
     m.complete(p, LOOP_EXPR)
 }
 
@@ -319,7 +315,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     let m = m.unwrap_or_else(|| p.start());
     p.bump(T![while]);
     cond(p);
-    block(p);
+    block_expr(p);
     m.complete(p, WHILE_EXPR)
 }
 
@@ -334,7 +330,7 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     patterns::pattern(p);
     p.expect(T![in]);
     expr_no_struct(p);
-    block(p);
+    block_expr(p);
     m.complete(p, FOR_EXPR)
 }
 
@@ -467,11 +463,20 @@ fn match_guard(p: &mut Parser) -> CompletedMarker {
     m.complete(p, MATCH_GUARD)
 }
 
-// test block_expr
-// fn foo() {
-//     {};
-// }
-pub(super) fn block_expr(p: &mut Parser) -> CompletedMarker {
+// test block
+// fn a() {}
+// fn b() { let _ = 1; }
+// fn c() { 1; 2; }
+// fn d() { 1; 2 }
+pub(crate) fn block_expr(p: &mut Parser) {
+    if !p.at(T!['{']) {
+        p.error("expected a block");
+        return;
+    }
+    block_expr_unchecked(p);
+}
+
+fn block_expr_unchecked(p: &mut Parser) -> CompletedMarker {
     assert!(p.at(T!['{']));
     let m = p.start();
     p.bump(T!['{']);
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 1503a87300..67a924de53 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -329,7 +329,7 @@ fn fn_def(p: &mut Parser) {
     if p.at(T![;]) {
         p.bump(T![;]);
     } else {
-        expressions::block(p)
+        expressions::block_expr(p)
     }
 }
 
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
index 33d9973e99..2d61f9d808 100644
--- a/crates/ra_parser/src/grammar/type_args.rs
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -48,7 +48,7 @@ fn type_arg(p: &mut Parser) {
             m.complete(p, ASSOC_TYPE_ARG);
         }
         T!['{'] => {
-            expressions::block(p);
+            expressions::block_expr(p);
             m.complete(p, CONST_ARG);
         }
         k if k.is_literal() => {
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index 652492c1ed..e08ad4dae6 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -112,7 +112,7 @@ pub fn parse_fragment(
         FragmentKind::Type => grammar::fragments::type_,
         FragmentKind::Pattern => grammar::fragments::pattern,
         FragmentKind::Item => grammar::fragments::item,
-        FragmentKind::Block => grammar::fragments::block,
+        FragmentKind::Block => grammar::fragments::block_expr,
         FragmentKind::Visibility => grammar::fragments::opt_visibility,
         FragmentKind::MetaItem => grammar::fragments::meta_item,
         FragmentKind::Statement => grammar::fragments::stmt,


Test patch:
diff --git a/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast b/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast
index 06a326d263..3bf57eacc7 100644
--- a/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast
+++ b/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast
@@ -40,5 +40,5 @@ SOURCE_FILE@0..42
       WHITESPACE@39..40 "\n"
       R_CURLY@40..41 "}"
   WHITESPACE@41..42 "\n"
-error 24..24: expected `{`
+error 24..24: expected a block
 error 24..24: expected SEMICOLON
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast b/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast
new file mode 100644
index 0000000000..e464563842
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast
@@ -0,0 +1,71 @@
+SOURCE_FILE@0..83
+  FN_DEF@0..82
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..7
+      IDENT@3..7 "main"
+    PARAM_LIST@7..9
+      L_PAREN@7..8 "("
+      R_PAREN@8..9 ")"
+    WHITESPACE@9..10 " "
+    BLOCK_EXPR@10..82
+      L_CURLY@10..11 "{"
+      WHITESPACE@11..16 "\n    "
+      EXPR_STMT@16..29
+        BLOCK_EXPR@16..29
+          L_CURLY@16..17 "{"
+          WHITESPACE@17..18 " "
+          ERROR@18..24
+            UNSAFE_KW@18..24 "unsafe"
+          WHITESPACE@24..25 " "
+          LITERAL@25..27
+            INT_NUMBER@25..27 "92"
+          WHITESPACE@27..28 " "
+          R_CURLY@28..29 "}"
+      WHITESPACE@29..34 "\n    "
+      EXPR_STMT@34..46
+        BLOCK_EXPR@34..46
+          L_CURLY@34..35 "{"
+          WHITESPACE@35..36 " "
+          ERROR@36..41
+            ASYNC_KW@36..41 "async"
+          WHITESPACE@41..42 " "
+          LITERAL@42..44
+            INT_NUMBER@42..44 "92"
+          WHITESPACE@44..45 " "
+          R_CURLY@45..46 "}"
+      WHITESPACE@46..51 "\n    "
+      EXPR_STMT@51..61
+        BLOCK_EXPR@51..61
+          L_CURLY@51..52 "{"
+          WHITESPACE@52..53 " "
+          EXPR_STMT@53..56
+            EFFECT_EXPR@53..56
+              TRY_KW@53..56 "try"
+          WHITESPACE@56..57 " "
+          LITERAL@57..59
+            INT_NUMBER@57..59 "92"
+          WHITESPACE@59..60 " "
+          R_CURLY@60..61 "}"
+      WHITESPACE@61..66 "\n    "
+      BLOCK_EXPR@66..80
+        L_CURLY@66..67 "{"
+        WHITESPACE@67..68 " "
+        EXPR_STMT@68..75
+          ERROR@68..75
+            LABEL@68..75
+              LIFETIME@68..74 "\'label"
+              COLON@74..75 ":"
+        WHITESPACE@75..76 " "
+        LITERAL@76..78
+          INT_NUMBER@76..78 "92"
+        WHITESPACE@78..79 " "
+        R_CURLY@79..80 "}"
+      WHITESPACE@80..81 "\n"
+      R_CURLY@81..82 "}"
+  WHITESPACE@82..83 "\n"
+error 24..24: expected existential, fn, trait or impl
+error 41..41: expected existential, fn, trait or impl
+error 56..56: expected a block
+error 75..75: expected a loop
+error 75..75: expected SEMICOLON
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs b/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs
new file mode 100644
index 0000000000..8fa324c1a1
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs
@@ -0,0 +1,6 @@
+fn main() {
+    { unsafe 92 }
+    { async 92 }
+    { try 92 }
+    { 'label: 92 }
+}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rast
deleted file mode 100644
index f3a5e30965..0000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rast
+++ /dev/null
@@ -1,21 +0,0 @@
-SOURCE_FILE@0..21
-  FN_DEF@0..20
-    FN_KW@0..2 "fn"
-    WHITESPACE@2..3 " "
-    NAME@3..6
-      IDENT@3..6 "foo"
-    PARAM_LIST@6..8
-      L_PAREN@6..7 "("
-      R_PAREN@7..8 ")"
-    WHITESPACE@8..9 " "
-    BLOCK_EXPR@9..20
-      L_CURLY@9..10 "{"
-      WHITESPACE@10..15 "\n    "
-      EXPR_STMT@15..18
-        BLOCK_EXPR@15..17
-          L_CURLY@15..16 "{"
-          R_CURLY@16..17 "}"
-        SEMICOLON@17..18 ";"
-      WHITESPACE@18..19 "\n"
-      R_CURLY@19..20 "}"
-  WHITESPACE@20..21 "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rs b/crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rs
deleted file mode 100644
index 9c6019fb1a..0000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn foo() {
-    {};
-}