1380: [#1083] Try block syntax r=matklad a=andreytkachenko

The `try` block syntax 

Co-authored-by: Andrey Tkachenko <andreytkachenko64@gmail.com>
This commit is contained in:
bors[bot] 2019-06-06 12:58:28 +00:00
commit ba31481599
9 changed files with 121 additions and 2 deletions

View File

@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
use ra_syntax::{ use ra_syntax::{
SyntaxNodePtr, AstPtr, AstNode, SyntaxNodePtr, AstPtr, AstNode,
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner}, ast::{self, TryBlockBodyOwner, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner},
}; };
use crate::{ use crate::{
@ -216,6 +216,9 @@ pub enum Expr {
Try { Try {
expr: ExprId, expr: ExprId,
}, },
TryBlock {
body: ExprId,
},
Cast { Cast {
expr: ExprId, expr: ExprId,
type_ref: TypeRef, type_ref: TypeRef,
@ -299,6 +302,7 @@ impl Expr {
f(*expr); f(*expr);
} }
} }
Expr::TryBlock { body } => f(*body),
Expr::Loop { body } => f(*body), Expr::Loop { body } => f(*body),
Expr::While { condition, body } => { Expr::While { condition, body } => {
f(*condition); f(*condition);
@ -578,6 +582,10 @@ where
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) 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::BlockExpr(e) => self.collect_block_opt(e.block()),
ast::ExprKind::LoopExpr(e) => { ast::ExprKind::LoopExpr(e) => {
let body = self.collect_block_opt(e.loop_body()); let body = self.collect_block_opt(e.loop_body());

View File

@ -946,6 +946,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
then_ty then_ty
} }
Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), 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 } => { Expr::Loop { body } => {
self.infer_expr(*body, &Expectation::has_type(Ty::unit())); self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
// FIXME handle break with value // FIXME handle break with value

View File

@ -52,6 +52,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
CONTINUE_KW, CONTINUE_KW,
LIFETIME, LIFETIME,
ASYNC_KW, ASYNC_KW,
TRY_KW,
]); ]);
const EXPR_RECOVERY_SET: TokenSet = token_set![LET_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![loop] => loop_expr(p, None),
T![for] => for_expr(p, None), T![for] => for_expr(p, None),
T![while] => while_expr(p, None), T![while] => while_expr(p, None),
T![try] => try_block_expr(p, None),
LIFETIME if la == T![:] => { LIFETIME if la == T![:] => {
let m = p.start(); let m = p.start();
label(p); label(p);
@ -116,7 +118,9 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
} }
}; };
let blocklike = match done.kind() { 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, _ => BlockLike::NotBlock,
}; };
Some((done, blocklike)) Some((done, blocklike))
@ -491,3 +495,15 @@ fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
} }
m.complete(p, BREAK_EXPR) 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)
}

View File

@ -103,6 +103,7 @@ pub enum SyntaxKind {
LET_KW, LET_KW,
MOVE_KW, MOVE_KW,
RETURN_KW, RETURN_KW,
TRY_KW,
AUTO_KW, AUTO_KW,
DEFAULT_KW, DEFAULT_KW,
UNION_KW, UNION_KW,
@ -184,6 +185,7 @@ pub enum SyntaxKind {
STRUCT_LIT, STRUCT_LIT,
NAMED_FIELD_LIST, NAMED_FIELD_LIST,
NAMED_FIELD, NAMED_FIELD,
TRY_BLOCK_EXPR,
CALL_EXPR, CALL_EXPR,
INDEX_EXPR, INDEX_EXPR,
METHOD_CALL_EXPR, METHOD_CALL_EXPR,
@ -331,6 +333,7 @@ macro_rules! T {
(let) => { $crate::SyntaxKind::LET_KW }; (let) => { $crate::SyntaxKind::LET_KW };
(move) => { $crate::SyntaxKind::MOVE_KW }; (move) => { $crate::SyntaxKind::MOVE_KW };
(return) => { $crate::SyntaxKind::RETURN_KW }; (return) => { $crate::SyntaxKind::RETURN_KW };
(try) => { $crate::SyntaxKind::TRY_KW };
(auto) => { $crate::SyntaxKind::AUTO_KW }; (auto) => { $crate::SyntaxKind::AUTO_KW };
(default) => { $crate::SyntaxKind::DEFAULT_KW }; (default) => { $crate::SyntaxKind::DEFAULT_KW };
(union) => { $crate::SyntaxKind::UNION_KW }; (union) => { $crate::SyntaxKind::UNION_KW };
@ -388,6 +391,7 @@ impl SyntaxKind {
| LET_KW | LET_KW
| MOVE_KW | MOVE_KW
| RETURN_KW | RETURN_KW
| TRY_KW
| AUTO_KW | AUTO_KW
| DEFAULT_KW | DEFAULT_KW
| UNION_KW | UNION_KW
@ -559,6 +563,7 @@ impl SyntaxKind {
LET_KW => &SyntaxInfo { name: "LET_KW" }, LET_KW => &SyntaxInfo { name: "LET_KW" },
MOVE_KW => &SyntaxInfo { name: "MOVE_KW" }, MOVE_KW => &SyntaxInfo { name: "MOVE_KW" },
RETURN_KW => &SyntaxInfo { name: "RETURN_KW" }, RETURN_KW => &SyntaxInfo { name: "RETURN_KW" },
TRY_KW => &SyntaxInfo { name: "TRY_KW" },
AUTO_KW => &SyntaxInfo { name: "AUTO_KW" }, AUTO_KW => &SyntaxInfo { name: "AUTO_KW" },
DEFAULT_KW => &SyntaxInfo { name: "DEFAULT_KW" }, DEFAULT_KW => &SyntaxInfo { name: "DEFAULT_KW" },
UNION_KW => &SyntaxInfo { name: "UNION_KW" }, UNION_KW => &SyntaxInfo { name: "UNION_KW" },
@ -640,6 +645,7 @@ impl SyntaxKind {
STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" },
NAMED_FIELD_LIST => &SyntaxInfo { name: "NAMED_FIELD_LIST" }, NAMED_FIELD_LIST => &SyntaxInfo { name: "NAMED_FIELD_LIST" },
NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" }, NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" },
TRY_BLOCK_EXPR => &SyntaxInfo { name: "TRY_BLOCK_EXPR" },
CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" }, CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" },
INDEX_EXPR => &SyntaxInfo { name: "INDEX_EXPR" }, INDEX_EXPR => &SyntaxInfo { name: "INDEX_EXPR" },
METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" }, METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" },
@ -734,6 +740,7 @@ impl SyntaxKind {
"let" => LET_KW, "let" => LET_KW,
"move" => MOVE_KW, "move" => MOVE_KW,
"return" => RETURN_KW, "return" => RETURN_KW,
"try" => TRY_KW,
_ => return None, _ => return None,
}; };
Some(kw) Some(kw)

View File

@ -713,6 +713,7 @@ pub enum ExprKind<'a> {
MethodCallExpr(&'a MethodCallExpr), MethodCallExpr(&'a MethodCallExpr),
FieldExpr(&'a FieldExpr), FieldExpr(&'a FieldExpr),
TryExpr(&'a TryExpr), TryExpr(&'a TryExpr),
TryBlockExpr(&'a TryBlockExpr),
CastExpr(&'a CastExpr), CastExpr(&'a CastExpr),
RefExpr(&'a RefExpr), RefExpr(&'a RefExpr),
PrefixExpr(&'a PrefixExpr), PrefixExpr(&'a PrefixExpr),
@ -826,6 +827,11 @@ impl<'a> From<&'a TryExpr> for &'a Expr {
Expr::cast(&n.syntax).unwrap() 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 { impl<'a> From<&'a CastExpr> for &'a Expr {
fn from(n: &'a CastExpr) -> &'a Expr { fn from(n: &'a CastExpr) -> &'a Expr {
Expr::cast(&n.syntax).unwrap() Expr::cast(&n.syntax).unwrap()
@ -887,6 +893,7 @@ impl AstNode for Expr {
| METHOD_CALL_EXPR | METHOD_CALL_EXPR
| FIELD_EXPR | FIELD_EXPR
| TRY_EXPR | TRY_EXPR
| TRY_BLOCK_EXPR
| CAST_EXPR | CAST_EXPR
| REF_EXPR | REF_EXPR
| PREFIX_EXPR | PREFIX_EXPR
@ -929,6 +936,7 @@ impl Expr {
METHOD_CALL_EXPR => ExprKind::MethodCallExpr(MethodCallExpr::cast(&self.syntax).unwrap()), METHOD_CALL_EXPR => ExprKind::MethodCallExpr(MethodCallExpr::cast(&self.syntax).unwrap()),
FIELD_EXPR => ExprKind::FieldExpr(FieldExpr::cast(&self.syntax).unwrap()), FIELD_EXPR => ExprKind::FieldExpr(FieldExpr::cast(&self.syntax).unwrap()),
TRY_EXPR => ExprKind::TryExpr(TryExpr::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()), CAST_EXPR => ExprKind::CastExpr(CastExpr::cast(&self.syntax).unwrap()),
REF_EXPR => ExprKind::RefExpr(RefExpr::cast(&self.syntax).unwrap()), REF_EXPR => ExprKind::RefExpr(RefExpr::cast(&self.syntax).unwrap()),
PREFIX_EXPR => ExprKind::PrefixExpr(PrefixExpr::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 // TryExpr
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
#[repr(transparent)] #[repr(transparent)]

View File

@ -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 { pub trait ArgListOwner: AstNode {
fn arg_list(&self) -> Option<&ast::ArgList> { fn arg_list(&self) -> Option<&ast::ArgList> {
child_opt(self) child_opt(self)

View File

@ -95,6 +95,7 @@ Grammar(
"let", "let",
"move", "move",
"return", "return",
"try",
], ],
contextual_keywords: [ contextual_keywords: [
"auto", "auto",
@ -189,6 +190,7 @@ Grammar(
"STRUCT_LIT", "STRUCT_LIT",
"NAMED_FIELD_LIST", "NAMED_FIELD_LIST",
"NAMED_FIELD", "NAMED_FIELD",
"TRY_BLOCK_EXPR",
// postfix // postfix
"CALL_EXPR", "CALL_EXPR",
@ -417,6 +419,9 @@ Grammar(
"LoopExpr": ( "LoopExpr": (
traits: ["LoopBodyOwner"], traits: ["LoopBodyOwner"],
), ),
"TryBlockExpr": (
traits: ["TryBlockBodyOwner"],
),
"ForExpr": ( "ForExpr": (
traits: ["LoopBodyOwner"], traits: ["LoopBodyOwner"],
options: [ options: [
@ -499,6 +504,7 @@ Grammar(
"MethodCallExpr", "MethodCallExpr",
"FieldExpr", "FieldExpr",
"TryExpr", "TryExpr",
"TryBlockExpr",
"CastExpr", "CastExpr",
"RefExpr", "RefExpr",
"PrefixExpr", "PrefixExpr",

View File

@ -0,0 +1,3 @@
fn foo() {
let _ = try {};
}

View File

@ -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"