about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/parser/src/grammar.rs4
-rw-r--r--crates/parser/src/grammar/attributes.rs2
-rw-r--r--crates/parser/src/grammar/expressions.rs28
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs10
-rw-r--r--crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rast58
-rw-r--r--crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rs6
-rw-r--r--crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rast46
-rw-r--r--crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rs6
-rw-r--r--crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rast85
-rw-r--r--crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rs8
-rw-r--r--crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rast49
-rw-r--r--crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rs6
-rw-r--r--crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rast57
-rw-r--r--crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rs7
-rw-r--r--crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rast69
-rw-r--r--crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rs1
16 files changed, 430 insertions, 12 deletions
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 15ec9e167e0..15435a26cea 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -198,6 +198,10 @@ impl BlockLike {
     fn is_block(self) -> bool {
         self == BlockLike::Block
     }
+
+    fn is_blocklike(kind: SyntaxKind) -> bool {
+        matches!(kind, BLOCK_EXPR | IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR)
+    }
 }
 
 const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]);
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs
index 4ecaa6e6a85..c13a1943792 100644
--- a/crates/parser/src/grammar/attributes.rs
+++ b/crates/parser/src/grammar/attributes.rs
@@ -43,7 +43,7 @@ pub(super) fn meta(p: &mut Parser<'_>) {
     match p.current() {
         T![=] => {
             p.bump(T![=]);
-            if !expressions::expr(p) {
+            if expressions::expr(p).is_none() {
                 p.error("expected expression");
             }
         }
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 4b080102a2c..a884d8b6ec8 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -16,9 +16,9 @@ pub(super) enum Semicolon {
 
 const EXPR_FIRST: TokenSet = LHS_FIRST;
 
-pub(super) fn expr(p: &mut Parser<'_>) -> bool {
+pub(super) fn expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
     let r = Restrictions { forbid_structs: false, prefer_stmt: false };
-    expr_bp(p, None, r, 1).is_some()
+    expr_bp(p, None, r, 1).map(|(m, _)| m)
 }
 
 pub(super) fn expr_stmt(
@@ -120,16 +120,27 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
             // fn f() { let x: i32; }
             types::ascription(p);
         }
+
+        let mut expr_after_eq: Option<CompletedMarker> = None;
         if p.eat(T![=]) {
             // test let_stmt_init
             // fn f() { let x = 92; }
-            expressions::expr(p);
+            expr_after_eq = expressions::expr(p);
         }
 
         if p.at(T![else]) {
+            // test_err let_else_right_curly_brace
+            // fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
+            if let Some(expr) = expr_after_eq {
+                if BlockLike::is_blocklike(expr.kind()) {
+                    p.error(
+                        "right curly brace `}` before `else` in a `let...else` statement not allowed",
+                    )
+                }
+            }
+
             // test let_else
             // fn f() { let Some(x) = opt else { return }; }
-
             let m = p.start();
             p.bump(T![else]);
             block_expr(p);
@@ -578,7 +589,14 @@ fn arg_list(p: &mut Parser<'_>) {
     // fn main() {
     //     foo(#[attr] 92)
     // }
-    delimited(p, T!['('], T![')'], T![,], EXPR_FIRST.union(ATTRIBUTE_FIRST), expr);
+    delimited(
+        p,
+        T!['('],
+        T![')'],
+        T![,],
+        EXPR_FIRST.union(ATTRIBUTE_FIRST),
+        |p: &mut Parser<'_>| expr(p).is_some(),
+    );
     m.complete(p, ARG_LIST);
 }
 
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index efc2603835e..d051dd2682f 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -163,10 +163,8 @@ pub(super) fn atom_expr(
             return None;
         }
     };
-    let blocklike = match done.kind() {
-        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
-        _ => BlockLike::NotBlock,
-    };
+    let blocklike =
+        if BlockLike::is_blocklike(done.kind()) { BlockLike::Block } else { BlockLike::NotBlock };
     Some((done, blocklike))
 }
 
@@ -188,7 +186,7 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
 
         // test tuple_attrs
         // const A: (i64, i64) = (1, #[cfg(test)] 2);
-        if !expr(p) {
+        if expr(p).is_none() {
             break;
         }
 
@@ -221,7 +219,7 @@ fn array_expr(p: &mut Parser<'_>) -> CompletedMarker {
 
         // test array_attrs
         // const A: &[i64] = &[1, #[cfg(test)] 2];
-        if !expr(p) {
+        if expr(p).is_none() {
             break;
         }
 
diff --git a/crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rast b/crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rast
new file mode 100644
index 00000000000..026fecf4c9d
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rast
@@ -0,0 +1,58 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          WILDCARD_PAT
+            UNDERSCORE "_"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          FOR_EXPR
+            FOR_KW "for"
+            WHITESPACE " "
+            WILDCARD_PAT
+              UNDERSCORE "_"
+            WHITESPACE " "
+            IN_KW "in"
+            WHITESPACE " "
+            RANGE_EXPR
+              LITERAL
+                INT_NUMBER "0"
+              DOT2 ".."
+              LITERAL
+                INT_NUMBER "10"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                RETURN_EXPR
+                  RETURN_KW "return"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 43: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rs b/crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rs
new file mode 100644
index 00000000000..d410274198d
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0049_let_else_right_curly_brace_for.rs
@@ -0,0 +1,6 @@
+fn f() {
+    let _ = for _ in 0..10 {
+    } else {
+        return
+    };
+}
\ No newline at end of file
diff --git a/crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rast b/crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rast
new file mode 100644
index 00000000000..10232195413
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rast
@@ -0,0 +1,46 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          WILDCARD_PAT
+            UNDERSCORE "_"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          LOOP_EXPR
+            LOOP_KW "loop"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                RETURN_EXPR
+                  RETURN_KW "return"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 33: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rs b/crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rs
new file mode 100644
index 00000000000..28b892869a1
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0050_let_else_right_curly_brace_loop.rs
@@ -0,0 +1,6 @@
+fn f() {
+    let _ = loop {
+    } else {
+        return
+    };
+}
\ No newline at end of file
diff --git a/crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rast b/crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rast
new file mode 100644
index 00000000000..6e1181246c0
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rast
@@ -0,0 +1,85 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          WILDCARD_PAT
+            UNDERSCORE "_"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          MATCH_EXPR
+            MATCH_KW "match"
+            WHITESPACE " "
+            CALL_EXPR
+              PATH_EXPR
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "Some"
+              ARG_LIST
+                L_PAREN "("
+                LITERAL
+                  INT_NUMBER "1"
+                R_PAREN ")"
+            WHITESPACE " "
+            MATCH_ARM_LIST
+              L_CURLY "{"
+              WHITESPACE "\n        "
+              MATCH_ARM
+                TUPLE_STRUCT_PAT
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Some"
+                  L_PAREN "("
+                  WILDCARD_PAT
+                    UNDERSCORE "_"
+                  R_PAREN ")"
+                WHITESPACE " "
+                FAT_ARROW "=>"
+                WHITESPACE " "
+                LITERAL
+                  INT_NUMBER "1"
+                COMMA ","
+              WHITESPACE "\n        "
+              MATCH_ARM
+                IDENT_PAT
+                  NAME
+                    IDENT "None"
+                WHITESPACE " "
+                FAT_ARROW "=>"
+                WHITESPACE " "
+                LITERAL
+                  INT_NUMBER "2"
+                COMMA ","
+              WHITESPACE "\n    "
+              R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                RETURN_EXPR
+                  RETURN_KW "return"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 83: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rs b/crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rs
new file mode 100644
index 00000000000..902d70daed5
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0051_let_else_right_curly_brace_match.rs
@@ -0,0 +1,8 @@
+fn f() {
+    let _ = match Some(1) {
+        Some(_) => 1,
+        None => 2,
+    } else {
+        return
+    };
+}
\ No newline at end of file
diff --git a/crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rast b/crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rast
new file mode 100644
index 00000000000..298d47d5394
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rast
@@ -0,0 +1,49 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          WILDCARD_PAT
+            UNDERSCORE "_"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          WHILE_EXPR
+            WHILE_KW "while"
+            WHITESPACE " "
+            LITERAL
+              TRUE_KW "true"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                RETURN_EXPR
+                  RETURN_KW "return"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 39: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rs b/crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rs
new file mode 100644
index 00000000000..a52343d8e6f
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0052_let_else_right_curly_brace_while.rs
@@ -0,0 +1,6 @@
+fn f() {
+    let _ = while true {
+    } else {
+        return
+    };
+}
\ No newline at end of file
diff --git a/crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rast b/crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rast
new file mode 100644
index 00000000000..c0a4b0400d8
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rast
@@ -0,0 +1,57 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          WILDCARD_PAT
+            UNDERSCORE "_"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          IF_EXPR
+            IF_KW "if"
+            WHITESPACE " "
+            LITERAL
+              TRUE_KW "true"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+            WHITESPACE " "
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE "\n        "
+                RETURN_EXPR
+                  RETURN_KW "return"
+                WHITESPACE "\n    "
+                R_CURLY "}"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+error 49: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rs b/crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rs
new file mode 100644
index 00000000000..9a87aecbd41
--- /dev/null
+++ b/crates/parser/test_data/parser/err/0053_let_else_right_curly_brace_if.rs
@@ -0,0 +1,7 @@
+fn f() {
+    let _ = if true {
+    } else {
+    } else {
+        return
+    };
+}
\ No newline at end of file
diff --git a/crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rast b/crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rast
new file mode 100644
index 00000000000..6ec580212b4
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rast
@@ -0,0 +1,69 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "func"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          TUPLE_STRUCT_PAT
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "Some"
+            L_PAREN "("
+            WILDCARD_PAT
+              UNDERSCORE "_"
+            R_PAREN ")"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          BLOCK_EXPR
+            STMT_LIST
+              L_CURLY "{"
+              CALL_EXPR
+                PATH_EXPR
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Some"
+                ARG_LIST
+                  L_PAREN "("
+                  LITERAL
+                    INT_NUMBER "1"
+                  R_PAREN ")"
+              R_CURLY "}"
+          WHITESPACE " "
+          LET_ELSE
+            ELSE_KW "else"
+            WHITESPACE " "
+            BLOCK_EXPR
+              STMT_LIST
+                L_CURLY "{"
+                WHITESPACE " "
+                MACRO_EXPR
+                  MACRO_CALL
+                    PATH
+                      PATH_SEGMENT
+                        NAME_REF
+                          IDENT "panic"
+                    BANG "!"
+                    TOKEN_TREE
+                      L_PAREN "("
+                      STRING "\"h\""
+                      R_PAREN ")"
+                WHITESPACE " "
+                R_CURLY "}"
+          SEMICOLON ";"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 35: right curly brace `}` before `else` in a `let...else` statement not allowed
diff --git a/crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rs b/crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rs
new file mode 100644
index 00000000000..30d52fea3b2
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0017_let_else_right_curly_brace.rs
@@ -0,0 +1 @@
+fn func() { let Some(_) = {Some(1)} else { panic!("h") };}