Repository: rust-analyzer/rust-analyzer
Pull request #1380 (2019-06-06 11:40:22)

[#1083] Try block syntax
The `try` block syntax 


Patch:
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 51913d37bd..9d9769859c 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
 use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
 use ra_syntax::{
     SyntaxNodePtr, AstPtr, AstNode,
-    ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner},
+    ast::{self, TryBlockBodyOwner, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner},
 };
 
 use crate::{
@@ -216,6 +216,9 @@ pub enum Expr {
     Try {
         expr: ExprId,
     },
+    TryBlock {
+        body: ExprId,
+    },
     Cast {
         expr: ExprId,
         type_ref: TypeRef,
@@ -299,6 +302,7 @@ impl Expr {
                     f(*expr);
                 }
             }
+            Expr::TryBlock { body } => f(*body),
             Expr::Loop { body } => f(*body),
             Expr::While { condition, body } => {
                 f(*condition);
@@ -578,6 +582,10 @@ where
                     self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
                 }
             }
+            ast::ExprKind::TryBlockExpr(e) => {
+                let body = self.collect_block_opt(e.try_body());
+                self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
+            }
             ast::ExprKind::BlockExpr(e) => self.collect_block_opt(e.block()),
             ast::ExprKind::LoopExpr(e) => {
                 let body = self.collect_block_opt(e.loop_body());
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 905fe9f0e3..6cc5dbc6f2 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -946,6 +946,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 then_ty
             }
             Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
+            Expr::TryBlock { body } => {
+                let _inner = self.infer_expr(*body, expected);
+                // FIXME should be std::result::Result<{inner}, _>
+                Ty::Unknown
+            }
             Expr::Loop { body } => {
                 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
                 // FIXME handle break with value
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 8b1a1de495..725fb99f66 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -52,6 +52,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
         CONTINUE_KW,
         LIFETIME,
         ASYNC_KW,
+        TRY_KW,
     ]);
 
 const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
@@ -75,6 +76,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
         T![loop] => loop_expr(p, None),
         T![for] => for_expr(p, None),
         T![while] => while_expr(p, None),
+        T![try] => try_block_expr(p, None),
         LIFETIME if la == T![:] => {
             let m = p.start();
             label(p);
@@ -116,7 +118,9 @@ 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 => BlockLike::Block,
+        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | TRY_BLOCK_EXPR => {
+            BlockLike::Block
+        }
         _ => BlockLike::NotBlock,
     };
     Some((done, blocklike))
@@ -491,3 +495,15 @@ fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
     }
     m.complete(p, BREAK_EXPR)
 }
+
+// test try_block_expr
+// fn foo() {
+//     let _ = try {};
+// }
+fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
+    assert!(p.at(T![try]));
+    let m = m.unwrap_or_else(|| p.start());
+    p.bump();
+    block(p);
+    m.complete(p, TRY_EXPR)
+}
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index d7926bd913..2c021f3e9d 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -103,6 +103,7 @@ pub enum SyntaxKind {
     LET_KW,
     MOVE_KW,
     RETURN_KW,
+    TRY_KW,
     AUTO_KW,
     DEFAULT_KW,
     UNION_KW,
@@ -184,6 +185,7 @@ pub enum SyntaxKind {
     STRUCT_LIT,
     NAMED_FIELD_LIST,
     NAMED_FIELD,
+    TRY_BLOCK_EXPR,
     CALL_EXPR,
     INDEX_EXPR,
     METHOD_CALL_EXPR,
@@ -331,6 +333,7 @@ macro_rules! T {
     (let) => { $crate::SyntaxKind::LET_KW };
     (move) => { $crate::SyntaxKind::MOVE_KW };
     (return) => { $crate::SyntaxKind::RETURN_KW };
+    (try) => { $crate::SyntaxKind::TRY_KW };
     (auto) => { $crate::SyntaxKind::AUTO_KW };
     (default) => { $crate::SyntaxKind::DEFAULT_KW };
     (union) => { $crate::SyntaxKind::UNION_KW };
@@ -388,6 +391,7 @@ impl SyntaxKind {
             | LET_KW
             | MOVE_KW
             | RETURN_KW
+            | TRY_KW
             | AUTO_KW
             | DEFAULT_KW
             | UNION_KW
@@ -559,6 +563,7 @@ impl SyntaxKind {
             LET_KW => &SyntaxInfo { name: "LET_KW" },
             MOVE_KW => &SyntaxInfo { name: "MOVE_KW" },
             RETURN_KW => &SyntaxInfo { name: "RETURN_KW" },
+            TRY_KW => &SyntaxInfo { name: "TRY_KW" },
             AUTO_KW => &SyntaxInfo { name: "AUTO_KW" },
             DEFAULT_KW => &SyntaxInfo { name: "DEFAULT_KW" },
             UNION_KW => &SyntaxInfo { name: "UNION_KW" },
@@ -640,6 +645,7 @@ impl SyntaxKind {
             STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" },
             NAMED_FIELD_LIST => &SyntaxInfo { name: "NAMED_FIELD_LIST" },
             NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" },
+            TRY_BLOCK_EXPR => &SyntaxInfo { name: "TRY_BLOCK_EXPR" },
             CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" },
             INDEX_EXPR => &SyntaxInfo { name: "INDEX_EXPR" },
             METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" },
@@ -734,6 +740,7 @@ impl SyntaxKind {
             "let" => LET_KW,
             "move" => MOVE_KW,
             "return" => RETURN_KW,
+            "try" => TRY_KW,
             _ => return None,
         };
         Some(kw)
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index e73fe22e92..1d888e7094 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -713,6 +713,7 @@ pub enum ExprKind<'a> {
     MethodCallExpr(&'a MethodCallExpr),
     FieldExpr(&'a FieldExpr),
     TryExpr(&'a TryExpr),
+    TryBlockExpr(&'a TryBlockExpr),
     CastExpr(&'a CastExpr),
     RefExpr(&'a RefExpr),
     PrefixExpr(&'a PrefixExpr),
@@ -826,6 +827,11 @@ impl<'a> From<&'a TryExpr> for &'a Expr {
         Expr::cast(&n.syntax).unwrap()
     }
 }
+impl<'a> From<&'a TryBlockExpr> for &'a Expr {
+    fn from(n: &'a TryBlockExpr) -> &'a Expr {
+        Expr::cast(&n.syntax).unwrap()
+    }
+}
 impl<'a> From<&'a CastExpr> for &'a Expr {
     fn from(n: &'a CastExpr) -> &'a Expr {
         Expr::cast(&n.syntax).unwrap()
@@ -887,6 +893,7 @@ impl AstNode for Expr {
             | METHOD_CALL_EXPR
             | FIELD_EXPR
             | TRY_EXPR
+            | TRY_BLOCK_EXPR
             | CAST_EXPR
             | REF_EXPR
             | PREFIX_EXPR
@@ -929,6 +936,7 @@ impl Expr {
             METHOD_CALL_EXPR => ExprKind::MethodCallExpr(MethodCallExpr::cast(&self.syntax).unwrap()),
             FIELD_EXPR => ExprKind::FieldExpr(FieldExpr::cast(&self.syntax).unwrap()),
             TRY_EXPR => ExprKind::TryExpr(TryExpr::cast(&self.syntax).unwrap()),
+            TRY_BLOCK_EXPR => ExprKind::TryBlockExpr(TryBlockExpr::cast(&self.syntax).unwrap()),
             CAST_EXPR => ExprKind::CastExpr(CastExpr::cast(&self.syntax).unwrap()),
             REF_EXPR => ExprKind::RefExpr(RefExpr::cast(&self.syntax).unwrap()),
             PREFIX_EXPR => ExprKind::PrefixExpr(PrefixExpr::cast(&self.syntax).unwrap()),
@@ -3672,6 +3680,35 @@ impl TraitDef {
     }
 }
 
+// TryBlockExpr
+#[derive(Debug, PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct TryBlockExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+unsafe impl TransparentNewType for TryBlockExpr {
+    type Repr = rowan::SyntaxNode;
+}
+
+impl AstNode for TryBlockExpr {
+    fn cast(syntax: &SyntaxNode) -> Option<&Self> {
+        match syntax.kind() {
+            TRY_BLOCK_EXPR => Some(TryBlockExpr::from_repr(syntax.into_repr())),
+            _ => None,
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+
+impl ToOwned for TryBlockExpr {
+    type Owned = TreeArc<TryBlockExpr>;
+    fn to_owned(&self) -> TreeArc<TryBlockExpr> { TreeArc::cast(self.syntax.to_owned()) }
+}
+
+
+impl ast::TryBlockBodyOwner for TryBlockExpr {}
+impl TryBlockExpr {}
+
 // TryExpr
 #[derive(Debug, PartialEq, Eq, Hash)]
 #[repr(transparent)]
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index 1c90cf148b..4334854008 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -33,6 +33,12 @@ pub trait LoopBodyOwner: AstNode {
     }
 }
 
+pub trait TryBlockBodyOwner: AstNode {
+    fn try_body(&self) -> Option<&ast::Block> {
+        child_opt(self)
+    }
+}
+
 pub trait ArgListOwner: AstNode {
     fn arg_list(&self) -> Option<&ast::ArgList> {
         child_opt(self)
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index b8665bbc8c..1c2714307a 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -95,6 +95,7 @@ Grammar(
         "let",
         "move",
         "return",
+        "try",
     ],
     contextual_keywords: [
         "auto",
@@ -189,6 +190,7 @@ Grammar(
         "STRUCT_LIT",
         "NAMED_FIELD_LIST",
         "NAMED_FIELD",
+        "TRY_BLOCK_EXPR",
 
         // postfix
         "CALL_EXPR",
@@ -417,6 +419,9 @@ Grammar(
         "LoopExpr": (
             traits: ["LoopBodyOwner"],
         ),
+        "TryBlockExpr": (
+            traits: ["TryBlockBodyOwner"],
+        ),
         "ForExpr": (
             traits: ["LoopBodyOwner"],
             options: [
@@ -499,6 +504,7 @@ Grammar(
                 "MethodCallExpr",
                 "FieldExpr",
                 "TryExpr",
+                "TryBlockExpr",
                 "CastExpr",
                 "RefExpr",
                 "PrefixExpr",


Test patch:
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0130_try_block_expr.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0130_try_block_expr.rs
new file mode 100644
index 0000000000..0f1b41eb64
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0130_try_block_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+    let _ = try {};
+}
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0130_try_block_expr.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0130_try_block_expr.txt
new file mode 100644
index 0000000000..53f49b9b5d
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0130_try_block_expr.txt
@@ -0,0 +1,31 @@
+SOURCE_FILE@[0; 33)
+  FN_DEF@[0; 32)
+    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@[9; 32)
+      L_CURLY@[9; 10) "{"
+      WHITESPACE@[10; 15) "\n    "
+      LET_STMT@[15; 30)
+        LET_KW@[15; 18) "let"
+        WHITESPACE@[18; 19) " "
+        PLACEHOLDER_PAT@[19; 20)
+          UNDERSCORE@[19; 20) "_"
+        WHITESPACE@[20; 21) " "
+        EQ@[21; 22) "="
+        WHITESPACE@[22; 23) " "
+        TRY_EXPR@[23; 29)
+          TRY_KW@[23; 26) "try"
+          WHITESPACE@[26; 27) " "
+          BLOCK@[27; 29)
+            L_CURLY@[27; 28) "{"
+            R_CURLY@[28; 29) "}"
+        SEMI@[29; 30) ";"
+      WHITESPACE@[30; 31) "\n"
+      R_CURLY@[31; 32) "}"
+  WHITESPACE@[32; 33) "\n"