mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
Merge #11375
11375: feat: Support if- and while- let chains r=Veykril a=ChayimFriedman2 Closes #11320. Co-authored-by: Chayim Refael Friedman <chayimfr@gmail.com>
This commit is contained in:
commit
c67660fc22
57 changed files with 1177 additions and 1094 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1832,9 +1832,9 @@ checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ungrammar"
|
name = "ungrammar"
|
||||||
version = "1.14.9"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "66be59c2fd880e3d76d1a6cf6d34114008f1d8af2748d4ad9d39ea712f14fda9"
|
checksum = "ed01567101450f7d600508e7680df6005ae4fe97119d79b0364cc5910ff39732"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expr::{
|
expr::{
|
||||||
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
|
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
|
||||||
MatchGuard, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
||||||
},
|
},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
item_scope::BuiltinShadowMode,
|
item_scope::BuiltinShadowMode,
|
||||||
|
@ -155,9 +155,6 @@ impl ExprCollector<'_> {
|
||||||
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
|
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
|
||||||
self.make_expr(expr, Err(SyntheticSyntax))
|
self.make_expr(expr, Err(SyntheticSyntax))
|
||||||
}
|
}
|
||||||
fn unit(&mut self) -> ExprId {
|
|
||||||
self.alloc_expr_desugared(Expr::Tuple { exprs: Box::default() })
|
|
||||||
}
|
|
||||||
fn missing_expr(&mut self) -> ExprId {
|
fn missing_expr(&mut self) -> ExprId {
|
||||||
self.alloc_expr_desugared(Expr::Missing)
|
self.alloc_expr_desugared(Expr::Missing)
|
||||||
}
|
}
|
||||||
|
@ -215,33 +212,15 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let condition = match e.condition() {
|
let condition = self.collect_expr_opt(e.condition());
|
||||||
None => self.missing_expr(),
|
|
||||||
Some(condition) => match condition.pat() {
|
|
||||||
None => self.collect_expr_opt(condition.expr()),
|
|
||||||
// if let -- desugar to match
|
|
||||||
Some(pat) => {
|
|
||||||
let pat = self.collect_pat(pat);
|
|
||||||
let match_expr = self.collect_expr_opt(condition.expr());
|
|
||||||
let placeholder_pat = self.missing_pat();
|
|
||||||
let arms = vec![
|
|
||||||
MatchArm { pat, expr: then_branch, guard: None },
|
|
||||||
MatchArm {
|
|
||||||
pat: placeholder_pat,
|
|
||||||
expr: else_branch.unwrap_or_else(|| self.unit()),
|
|
||||||
guard: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.into();
|
|
||||||
return Some(
|
|
||||||
self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
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::Expr::LetExpr(e) => {
|
||||||
|
let pat = self.collect_pat_opt(e.pat());
|
||||||
|
let expr = self.collect_expr_opt(e.expr());
|
||||||
|
self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
|
||||||
|
}
|
||||||
ast::Expr::BlockExpr(e) => match e.modifier() {
|
ast::Expr::BlockExpr(e) => match e.modifier() {
|
||||||
Some(ast::BlockModifier::Try(_)) => {
|
Some(ast::BlockModifier::Try(_)) => {
|
||||||
let body = self.collect_block(e);
|
let body = self.collect_block(e);
|
||||||
|
@ -282,31 +261,7 @@ impl ExprCollector<'_> {
|
||||||
let label = e.label().map(|label| self.collect_label(label));
|
let label = e.label().map(|label| self.collect_label(label));
|
||||||
let body = self.collect_block_opt(e.loop_body());
|
let body = self.collect_block_opt(e.loop_body());
|
||||||
|
|
||||||
let condition = match e.condition() {
|
let condition = self.collect_expr_opt(e.condition());
|
||||||
None => self.missing_expr(),
|
|
||||||
Some(condition) => match condition.pat() {
|
|
||||||
None => self.collect_expr_opt(condition.expr()),
|
|
||||||
// if let -- desugar to match
|
|
||||||
Some(pat) => {
|
|
||||||
cov_mark::hit!(infer_resolve_while_let);
|
|
||||||
let pat = self.collect_pat(pat);
|
|
||||||
let match_expr = self.collect_expr_opt(condition.expr());
|
|
||||||
let placeholder_pat = self.missing_pat();
|
|
||||||
let break_ =
|
|
||||||
self.alloc_expr_desugared(Expr::Break { expr: None, label: None });
|
|
||||||
let arms = vec![
|
|
||||||
MatchArm { pat, expr: body, guard: None },
|
|
||||||
MatchArm { pat: placeholder_pat, expr: break_, guard: None },
|
|
||||||
]
|
|
||||||
.into();
|
|
||||||
let match_expr =
|
|
||||||
self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
|
|
||||||
return Some(
|
|
||||||
self.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
||||||
}
|
}
|
||||||
|
@ -352,15 +307,9 @@ impl ExprCollector<'_> {
|
||||||
self.check_cfg(&arm).map(|()| MatchArm {
|
self.check_cfg(&arm).map(|()| MatchArm {
|
||||||
pat: self.collect_pat_opt(arm.pat()),
|
pat: self.collect_pat_opt(arm.pat()),
|
||||||
expr: self.collect_expr_opt(arm.expr()),
|
expr: self.collect_expr_opt(arm.expr()),
|
||||||
guard: arm.guard().map(|guard| match guard.pat() {
|
guard: arm
|
||||||
Some(pat) => MatchGuard::IfLet {
|
.guard()
|
||||||
pat: self.collect_pat(pat),
|
.map(|guard| self.collect_expr_opt(guard.condition())),
|
||||||
expr: self.collect_expr_opt(guard.expr()),
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
MatchGuard::If { expr: self.collect_expr_opt(guard.expr()) }
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
|
||||||
use crate::{
|
use crate::{
|
||||||
body::Body,
|
body::Body,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expr::{Expr, ExprId, LabelId, MatchGuard, Pat, PatId, Statement},
|
expr::{Expr, ExprId, LabelId, Pat, PatId, Statement},
|
||||||
BlockId, DefWithBodyId,
|
BlockId, DefWithBodyId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ impl ExprScopes {
|
||||||
fn new(body: &Body) -> ExprScopes {
|
fn new(body: &Body) -> ExprScopes {
|
||||||
let mut scopes =
|
let mut scopes =
|
||||||
ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
|
ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
|
||||||
let root = scopes.root_scope();
|
let mut root = scopes.root_scope();
|
||||||
scopes.add_params_bindings(body, root, &body.params);
|
scopes.add_params_bindings(body, root, &body.params);
|
||||||
compute_expr_scopes(body.body_expr, body, &mut scopes, root);
|
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
|
||||||
scopes
|
scopes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,32 +151,32 @@ fn compute_block_scopes(
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Let { pat, initializer, else_branch, .. } => {
|
Statement::Let { pat, initializer, else_branch, .. } => {
|
||||||
if let Some(expr) = initializer {
|
if let Some(expr) = initializer {
|
||||||
compute_expr_scopes(*expr, body, scopes, scope);
|
compute_expr_scopes(*expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
if let Some(expr) = else_branch {
|
if let Some(expr) = else_branch {
|
||||||
compute_expr_scopes(*expr, body, scopes, scope);
|
compute_expr_scopes(*expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
scope = scopes.new_scope(scope);
|
scope = scopes.new_scope(scope);
|
||||||
scopes.add_bindings(body, scope, *pat);
|
scopes.add_bindings(body, scope, *pat);
|
||||||
}
|
}
|
||||||
Statement::Expr { expr, .. } => {
|
Statement::Expr { expr, .. } => {
|
||||||
compute_expr_scopes(*expr, body, scopes, scope);
|
compute_expr_scopes(*expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(expr) = tail {
|
if let Some(expr) = tail {
|
||||||
compute_expr_scopes(expr, body, scopes, scope);
|
compute_expr_scopes(expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) {
|
fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) {
|
||||||
let make_label =
|
let make_label =
|
||||||
|label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
|
|label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
|
||||||
|
|
||||||
scopes.set_scope(expr, scope);
|
scopes.set_scope(expr, *scope);
|
||||||
match &body[expr] {
|
match &body[expr] {
|
||||||
Expr::Block { statements, tail, id, label } => {
|
Expr::Block { statements, tail, id, label } => {
|
||||||
let scope = scopes.new_block_scope(scope, *id, make_label(label));
|
let scope = scopes.new_block_scope(*scope, *id, make_label(label));
|
||||||
// Overwrite the old scope for the block expr, so that every block scope can be found
|
// Overwrite the old scope for the block expr, so that every block scope can be found
|
||||||
// via the block itself (important for blocks that only contain items, no expressions).
|
// via the block itself (important for blocks that only contain items, no expressions).
|
||||||
scopes.set_scope(expr, scope);
|
scopes.set_scope(expr, scope);
|
||||||
|
@ -184,46 +184,49 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
|
||||||
}
|
}
|
||||||
Expr::For { iterable, pat, body: body_expr, label } => {
|
Expr::For { iterable, pat, body: body_expr, label } => {
|
||||||
compute_expr_scopes(*iterable, body, scopes, scope);
|
compute_expr_scopes(*iterable, body, scopes, scope);
|
||||||
let scope = scopes.new_labeled_scope(scope, make_label(label));
|
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||||
scopes.add_bindings(body, scope, *pat);
|
scopes.add_bindings(body, scope, *pat);
|
||||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
Expr::While { condition, body: body_expr, label } => {
|
Expr::While { condition, body: body_expr, label } => {
|
||||||
let scope = scopes.new_labeled_scope(scope, make_label(label));
|
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||||
compute_expr_scopes(*condition, body, scopes, scope);
|
compute_expr_scopes(*condition, body, scopes, &mut scope);
|
||||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
Expr::Loop { body: body_expr, label } => {
|
Expr::Loop { body: body_expr, label } => {
|
||||||
let scope = scopes.new_labeled_scope(scope, make_label(label));
|
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
Expr::Lambda { args, body: body_expr, .. } => {
|
Expr::Lambda { args, body: body_expr, .. } => {
|
||||||
let scope = scopes.new_scope(scope);
|
let mut scope = scopes.new_scope(*scope);
|
||||||
scopes.add_params_bindings(body, scope, args);
|
scopes.add_params_bindings(body, scope, args);
|
||||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||||
}
|
}
|
||||||
Expr::Match { expr, arms } => {
|
Expr::Match { expr, arms } => {
|
||||||
compute_expr_scopes(*expr, body, scopes, scope);
|
compute_expr_scopes(*expr, body, scopes, scope);
|
||||||
for arm in arms.iter() {
|
for arm in arms.iter() {
|
||||||
let mut scope = scopes.new_scope(scope);
|
let mut scope = scopes.new_scope(*scope);
|
||||||
scopes.add_bindings(body, scope, arm.pat);
|
scopes.add_bindings(body, scope, arm.pat);
|
||||||
match arm.guard {
|
if let Some(guard) = arm.guard {
|
||||||
Some(MatchGuard::If { expr: guard }) => {
|
scope = scopes.new_scope(scope);
|
||||||
scopes.set_scope(guard, scope);
|
compute_expr_scopes(guard, body, scopes, &mut scope);
|
||||||
compute_expr_scopes(guard, body, scopes, scope);
|
}
|
||||||
}
|
compute_expr_scopes(arm.expr, body, scopes, &mut scope);
|
||||||
Some(MatchGuard::IfLet { pat, expr: guard }) => {
|
|
||||||
scopes.set_scope(guard, scope);
|
|
||||||
compute_expr_scopes(guard, body, scopes, scope);
|
|
||||||
scope = scopes.new_scope(scope);
|
|
||||||
scopes.add_bindings(body, scope, pat);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
scopes.set_scope(arm.expr, scope);
|
|
||||||
compute_expr_scopes(arm.expr, body, scopes, scope);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&Expr::If { condition, then_branch, else_branch } => {
|
||||||
|
let mut then_branch_scope = scopes.new_scope(*scope);
|
||||||
|
compute_expr_scopes(condition, body, scopes, &mut then_branch_scope);
|
||||||
|
compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope);
|
||||||
|
if let Some(else_branch) = else_branch {
|
||||||
|
compute_expr_scopes(else_branch, body, scopes, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Expr::Let { pat, expr } => {
|
||||||
|
compute_expr_scopes(expr, body, scopes, scope);
|
||||||
|
*scope = scopes.new_scope(*scope);
|
||||||
|
scopes.add_bindings(body, *scope, pat);
|
||||||
|
}
|
||||||
e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
|
e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -500,8 +503,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn while_let_desugaring() {
|
fn while_let_adds_binding() {
|
||||||
cov_mark::check!(infer_resolve_while_let);
|
|
||||||
do_check_local_name(
|
do_check_local_name(
|
||||||
r#"
|
r#"
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -513,5 +515,53 @@ fn test() {
|
||||||
"#,
|
"#,
|
||||||
75,
|
75,
|
||||||
);
|
);
|
||||||
|
do_check_local_name(
|
||||||
|
r#"
|
||||||
|
fn test() {
|
||||||
|
let foo: Option<f32> = None;
|
||||||
|
while (((let Option::Some(_) = foo))) && let Option::Some(spam) = foo {
|
||||||
|
spam$0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
107,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn match_guard_if_let() {
|
||||||
|
do_check_local_name(
|
||||||
|
r#"
|
||||||
|
fn test() {
|
||||||
|
let foo: Option<f32> = None;
|
||||||
|
match foo {
|
||||||
|
_ if let Option::Some(spam) = foo => spam$0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
93,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn let_chains_can_reference_previous_lets() {
|
||||||
|
do_check_local_name(
|
||||||
|
r#"
|
||||||
|
fn test() {
|
||||||
|
let foo: Option<i32> = None;
|
||||||
|
if let Some(spam) = foo && spa$0m > 1 && let Some(spam) = foo && spam > 1 {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
61,
|
||||||
|
);
|
||||||
|
do_check_local_name(
|
||||||
|
r#"
|
||||||
|
fn test() {
|
||||||
|
let foo: Option<i32> = None;
|
||||||
|
if let Some(spam) = foo && spam > 1 && let Some(spam) = foo && sp$0am > 1 {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
100,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,10 @@ pub enum Expr {
|
||||||
then_branch: ExprId,
|
then_branch: ExprId,
|
||||||
else_branch: Option<ExprId>,
|
else_branch: Option<ExprId>,
|
||||||
},
|
},
|
||||||
|
Let {
|
||||||
|
pat: PatId,
|
||||||
|
expr: ExprId,
|
||||||
|
},
|
||||||
Block {
|
Block {
|
||||||
id: BlockId,
|
id: BlockId,
|
||||||
statements: Box<[Statement]>,
|
statements: Box<[Statement]>,
|
||||||
|
@ -189,17 +193,10 @@ pub enum Array {
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MatchArm {
|
pub struct MatchArm {
|
||||||
pub pat: PatId,
|
pub pat: PatId,
|
||||||
pub guard: Option<MatchGuard>,
|
pub guard: Option<ExprId>,
|
||||||
pub expr: ExprId,
|
pub expr: ExprId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub enum MatchGuard {
|
|
||||||
If { expr: ExprId },
|
|
||||||
|
|
||||||
IfLet { pat: PatId, expr: ExprId },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct RecordLitField {
|
pub struct RecordLitField {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
|
@ -232,6 +229,9 @@ impl Expr {
|
||||||
f(else_branch);
|
f(else_branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::Let { expr, .. } => {
|
||||||
|
f(*expr);
|
||||||
|
}
|
||||||
Expr::Block { statements, tail, .. } => {
|
Expr::Block { statements, tail, .. } => {
|
||||||
for stmt in statements.iter() {
|
for stmt in statements.iter() {
|
||||||
match stmt {
|
match stmt {
|
||||||
|
|
|
@ -108,18 +108,18 @@ fn expansion_does_not_parse_as_expression() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
macro_rules! stmts {
|
macro_rules! stmts {
|
||||||
() => { let _ = 0; }
|
() => { fn foo() {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f() { let _ = stmts!/*+errors*/(); }
|
fn f() { let _ = stmts!/*+errors*/(); }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
macro_rules! stmts {
|
macro_rules! stmts {
|
||||||
() => { let _ = 0; }
|
() => { fn foo() {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f() { let _ = /* parse error: expected expression */
|
fn f() { let _ = /* parse error: expected expression */
|
||||||
let _ = 0;; }
|
fn foo() {}; }
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -811,10 +811,10 @@ impl ExpandTo {
|
||||||
MACRO_TYPE => ExpandTo::Type,
|
MACRO_TYPE => ExpandTo::Type,
|
||||||
|
|
||||||
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
|
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
|
||||||
| CLOSURE_EXPR | CONDITION | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM
|
| CLOSURE_EXPR | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM | MATCH_GUARD
|
||||||
| MATCH_GUARD | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR
|
| RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR
|
||||||
| FIELD_EXPR | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR
|
| AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR
|
||||||
| BIN_EXPR => ExpandTo::Expr,
|
| LET_EXPR => ExpandTo::Expr,
|
||||||
LET_STMT => {
|
LET_STMT => {
|
||||||
// FIXME: Handle LHS Pattern
|
// FIXME: Handle LHS Pattern
|
||||||
ExpandTo::Expr
|
ExpandTo::Expr
|
||||||
|
|
|
@ -8,10 +8,7 @@ use std::{
|
||||||
|
|
||||||
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
expr::{
|
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
|
||||||
ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, MatchGuard, Ordering, Statement,
|
|
||||||
UnaryOp,
|
|
||||||
},
|
|
||||||
path::{GenericArg, GenericArgs},
|
path::{GenericArg, GenericArgs},
|
||||||
resolver::resolver_for_expr,
|
resolver::resolver_for_expr,
|
||||||
FieldId, FunctionId, ItemContainerId, Lookup,
|
FieldId, FunctionId, ItemContainerId, Lookup,
|
||||||
|
@ -158,6 +155,11 @@ impl<'a> InferenceContext<'a> {
|
||||||
|
|
||||||
coerce.complete()
|
coerce.complete()
|
||||||
}
|
}
|
||||||
|
&Expr::Let { pat, expr } => {
|
||||||
|
let input_ty = self.infer_expr(expr, &Expectation::none());
|
||||||
|
self.infer_pat(pat, &input_ty, BindingMode::default());
|
||||||
|
TyKind::Scalar(Scalar::Bool).intern(Interner)
|
||||||
|
}
|
||||||
Expr::Block { statements, tail, label, id: _ } => {
|
Expr::Block { statements, tail, label, id: _ } => {
|
||||||
let old_resolver = mem::replace(
|
let old_resolver = mem::replace(
|
||||||
&mut self.resolver,
|
&mut self.resolver,
|
||||||
|
@ -378,20 +380,11 @@ impl<'a> InferenceContext<'a> {
|
||||||
for arm in arms.iter() {
|
for arm in arms.iter() {
|
||||||
self.diverges = Diverges::Maybe;
|
self.diverges = Diverges::Maybe;
|
||||||
let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
|
let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
|
||||||
match arm.guard {
|
if let Some(guard_expr) = arm.guard {
|
||||||
Some(MatchGuard::If { expr: guard_expr }) => {
|
self.infer_expr(
|
||||||
self.infer_expr(
|
guard_expr,
|
||||||
guard_expr,
|
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
|
||||||
&Expectation::has_type(
|
);
|
||||||
TyKind::Scalar(Scalar::Bool).intern(Interner),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(MatchGuard::IfLet { expr, pat }) => {
|
|
||||||
let input_ty = self.infer_expr(expr, &Expectation::none());
|
|
||||||
let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
||||||
|
|
|
@ -190,7 +190,6 @@ fn expr_macro_def_expanded_in_various_places() {
|
||||||
!0..6 '1isize': isize
|
!0..6 '1isize': isize
|
||||||
!0..6 '1isize': isize
|
!0..6 '1isize': isize
|
||||||
!0..6 '1isize': isize
|
!0..6 '1isize': isize
|
||||||
!0..6 '1isize': isize
|
|
||||||
39..442 '{ ...!(); }': ()
|
39..442 '{ ...!(); }': ()
|
||||||
73..94 'spam!(...am!())': {unknown}
|
73..94 'spam!(...am!())': {unknown}
|
||||||
100..119 'for _ ...!() {}': ()
|
100..119 'for _ ...!() {}': ()
|
||||||
|
@ -198,6 +197,7 @@ fn expr_macro_def_expanded_in_various_places() {
|
||||||
117..119 '{}': ()
|
117..119 '{}': ()
|
||||||
124..134 '|| spam!()': || -> isize
|
124..134 '|| spam!()': || -> isize
|
||||||
140..156 'while ...!() {}': ()
|
140..156 'while ...!() {}': ()
|
||||||
|
146..153 'spam!()': bool
|
||||||
154..156 '{}': ()
|
154..156 '{}': ()
|
||||||
161..174 'break spam!()': !
|
161..174 'break spam!()': !
|
||||||
180..194 'return spam!()': !
|
180..194 'return spam!()': !
|
||||||
|
@ -271,7 +271,6 @@ fn expr_macro_rules_expanded_in_various_places() {
|
||||||
!0..6 '1isize': isize
|
!0..6 '1isize': isize
|
||||||
!0..6 '1isize': isize
|
!0..6 '1isize': isize
|
||||||
!0..6 '1isize': isize
|
!0..6 '1isize': isize
|
||||||
!0..6 '1isize': isize
|
|
||||||
53..456 '{ ...!(); }': ()
|
53..456 '{ ...!(); }': ()
|
||||||
87..108 'spam!(...am!())': {unknown}
|
87..108 'spam!(...am!())': {unknown}
|
||||||
114..133 'for _ ...!() {}': ()
|
114..133 'for _ ...!() {}': ()
|
||||||
|
@ -279,6 +278,7 @@ fn expr_macro_rules_expanded_in_various_places() {
|
||||||
131..133 '{}': ()
|
131..133 '{}': ()
|
||||||
138..148 '|| spam!()': || -> isize
|
138..148 '|| spam!()': || -> isize
|
||||||
154..170 'while ...!() {}': ()
|
154..170 'while ...!() {}': ()
|
||||||
|
160..167 'spam!()': bool
|
||||||
168..170 '{}': ()
|
168..170 '{}': ()
|
||||||
175..188 'break spam!()': !
|
175..188 'break spam!()': !
|
||||||
194..208 'return spam!()': !
|
194..208 'return spam!()': !
|
||||||
|
|
|
@ -55,6 +55,7 @@ fn infer_pattern() {
|
||||||
139..140 'g': {unknown}
|
139..140 'g': {unknown}
|
||||||
143..144 'e': {unknown}
|
143..144 'e': {unknown}
|
||||||
157..204 'if let... }': ()
|
157..204 'if let... }': ()
|
||||||
|
160..175 'let [val] = opt': bool
|
||||||
164..169 '[val]': [{unknown}]
|
164..169 '[val]': [{unknown}]
|
||||||
165..168 'val': {unknown}
|
165..168 'val': {unknown}
|
||||||
172..175 'opt': [{unknown}]
|
172..175 'opt': [{unknown}]
|
||||||
|
@ -62,6 +63,7 @@ fn infer_pattern() {
|
||||||
190..191 'h': {unknown}
|
190..191 'h': {unknown}
|
||||||
194..197 'val': {unknown}
|
194..197 'val': {unknown}
|
||||||
210..236 'if let...rue {}': ()
|
210..236 'if let...rue {}': ()
|
||||||
|
213..233 'let x ... &true': bool
|
||||||
217..225 'x @ true': &bool
|
217..225 'x @ true': &bool
|
||||||
221..225 'true': bool
|
221..225 'true': bool
|
||||||
221..225 'true': bool
|
221..225 'true': bool
|
||||||
|
@ -111,36 +113,42 @@ fn infer_literal_pattern() {
|
||||||
37..38 'x': &i32
|
37..38 'x': &i32
|
||||||
46..208 '{ ...) {} }': ()
|
46..208 '{ ...) {} }': ()
|
||||||
52..75 'if let...y() {}': ()
|
52..75 'if let...y() {}': ()
|
||||||
|
55..72 'let "f... any()': bool
|
||||||
59..64 '"foo"': &str
|
59..64 '"foo"': &str
|
||||||
59..64 '"foo"': &str
|
59..64 '"foo"': &str
|
||||||
67..70 'any': fn any<&str>() -> &str
|
67..70 'any': fn any<&str>() -> &str
|
||||||
67..72 'any()': &str
|
67..72 'any()': &str
|
||||||
73..75 '{}': ()
|
73..75 '{}': ()
|
||||||
80..99 'if let...y() {}': ()
|
80..99 'if let...y() {}': ()
|
||||||
|
83..96 'let 1 = any()': bool
|
||||||
87..88 '1': i32
|
87..88 '1': i32
|
||||||
87..88 '1': i32
|
87..88 '1': i32
|
||||||
91..94 'any': fn any<i32>() -> i32
|
91..94 'any': fn any<i32>() -> i32
|
||||||
91..96 'any()': i32
|
91..96 'any()': i32
|
||||||
97..99 '{}': ()
|
97..99 '{}': ()
|
||||||
104..126 'if let...y() {}': ()
|
104..126 'if let...y() {}': ()
|
||||||
|
107..123 'let 1u... any()': bool
|
||||||
111..115 '1u32': u32
|
111..115 '1u32': u32
|
||||||
111..115 '1u32': u32
|
111..115 '1u32': u32
|
||||||
118..121 'any': fn any<u32>() -> u32
|
118..121 'any': fn any<u32>() -> u32
|
||||||
118..123 'any()': u32
|
118..123 'any()': u32
|
||||||
124..126 '{}': ()
|
124..126 '{}': ()
|
||||||
131..153 'if let...y() {}': ()
|
131..153 'if let...y() {}': ()
|
||||||
|
134..150 'let 1f... any()': bool
|
||||||
138..142 '1f32': f32
|
138..142 '1f32': f32
|
||||||
138..142 '1f32': f32
|
138..142 '1f32': f32
|
||||||
145..148 'any': fn any<f32>() -> f32
|
145..148 'any': fn any<f32>() -> f32
|
||||||
145..150 'any()': f32
|
145..150 'any()': f32
|
||||||
151..153 '{}': ()
|
151..153 '{}': ()
|
||||||
158..179 'if let...y() {}': ()
|
158..179 'if let...y() {}': ()
|
||||||
|
161..176 'let 1.0 = any()': bool
|
||||||
165..168 '1.0': f64
|
165..168 '1.0': f64
|
||||||
165..168 '1.0': f64
|
165..168 '1.0': f64
|
||||||
171..174 'any': fn any<f64>() -> f64
|
171..174 'any': fn any<f64>() -> f64
|
||||||
171..176 'any()': f64
|
171..176 'any()': f64
|
||||||
177..179 '{}': ()
|
177..179 '{}': ()
|
||||||
184..206 'if let...y() {}': ()
|
184..206 'if let...y() {}': ()
|
||||||
|
187..203 'let tr... any()': bool
|
||||||
191..195 'true': bool
|
191..195 'true': bool
|
||||||
191..195 'true': bool
|
191..195 'true': bool
|
||||||
198..201 'any': fn any<bool>() -> bool
|
198..201 'any': fn any<bool>() -> bool
|
||||||
|
@ -163,10 +171,12 @@ fn infer_range_pattern() {
|
||||||
8..9 'x': &i32
|
8..9 'x': &i32
|
||||||
17..75 '{ ...2 {} }': ()
|
17..75 '{ ...2 {} }': ()
|
||||||
23..45 'if let...u32 {}': ()
|
23..45 'if let...u32 {}': ()
|
||||||
|
26..42 'let 1....= 2u32': bool
|
||||||
30..35 '1..76': u32
|
30..35 '1..76': u32
|
||||||
38..42 '2u32': u32
|
38..42 '2u32': u32
|
||||||
43..45 '{}': ()
|
43..45 '{}': ()
|
||||||
50..73 'if let...u32 {}': ()
|
50..73 'if let...u32 {}': ()
|
||||||
|
53..70 'let 1....= 2u32': bool
|
||||||
57..63 '1..=76': u32
|
57..63 '1..=76': u32
|
||||||
66..70 '2u32': u32
|
66..70 '2u32': u32
|
||||||
71..73 '{}': ()
|
71..73 '{}': ()
|
||||||
|
|
|
@ -2248,6 +2248,7 @@ fn generic_default_in_struct_literal() {
|
||||||
176..193 'Thing ...1i32 }': Thing<i32>
|
176..193 'Thing ...1i32 }': Thing<i32>
|
||||||
187..191 '1i32': i32
|
187..191 '1i32': i32
|
||||||
199..240 'if let... }': ()
|
199..240 'if let... }': ()
|
||||||
|
202..221 'let Th... } = z': bool
|
||||||
206..217 'Thing { t }': Thing<i32>
|
206..217 'Thing { t }': Thing<i32>
|
||||||
214..215 't': i32
|
214..215 't': i32
|
||||||
220..221 'z': Thing<i32>
|
220..221 'z': Thing<i32>
|
||||||
|
|
|
@ -18,7 +18,7 @@ use syntax::{
|
||||||
algo, ast,
|
algo, ast,
|
||||||
display::{fn_as_proc_macro_label, macro_label},
|
display::{fn_as_proc_macro_label, macro_label},
|
||||||
match_ast, AstNode, Direction,
|
match_ast, AstNode, Direction,
|
||||||
SyntaxKind::{CONDITION, LET_STMT},
|
SyntaxKind::{LET_EXPR, LET_STMT},
|
||||||
SyntaxToken, T,
|
SyntaxToken, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
|
||||||
let let_kw = if ident
|
let let_kw = if ident
|
||||||
.syntax()
|
.syntax()
|
||||||
.parent()
|
.parent()
|
||||||
.map_or(false, |p| p.kind() == LET_STMT || p.kind() == CONDITION)
|
.map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR)
|
||||||
{
|
{
|
||||||
"let "
|
"let "
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -243,7 +243,7 @@ fn is_named_constructor(
|
||||||
let expr = match_ast! {
|
let expr = match_ast! {
|
||||||
match let_node {
|
match let_node {
|
||||||
ast::LetStmt(it) => it.initializer(),
|
ast::LetStmt(it) => it.initializer(),
|
||||||
ast::Condition(it) => it.expr(),
|
ast::LetExpr(it) => it.expr(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
|
@ -372,15 +372,10 @@ fn should_not_display_type_hint(
|
||||||
match node {
|
match node {
|
||||||
ast::LetStmt(it) => return it.ty().is_some(),
|
ast::LetStmt(it) => return it.ty().is_some(),
|
||||||
ast::Param(it) => return it.ty().is_some(),
|
ast::Param(it) => return it.ty().is_some(),
|
||||||
ast::MatchArm(_it) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||||
ast::IfExpr(it) => {
|
ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
ast::IfExpr(_) => return false,
|
||||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
ast::WhileExpr(_) => return false,
|
||||||
},
|
|
||||||
ast::WhileExpr(it) => {
|
|
||||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
|
||||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
|
||||||
},
|
|
||||||
ast::ForExpr(it) => {
|
ast::ForExpr(it) => {
|
||||||
// We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
|
// We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
|
||||||
// Type of expr should be iterable.
|
// Type of expr should be iterable.
|
||||||
|
|
|
@ -2,7 +2,7 @@ use hir::{known, AsAssocItem, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
helpers::{
|
helpers::{
|
||||||
for_each_tail_expr,
|
for_each_tail_expr,
|
||||||
node_ext::{block_as_lone_tail, preorder_expr},
|
node_ext::{block_as_lone_tail, is_pattern_cond, preorder_expr},
|
||||||
FamousDefs,
|
FamousDefs,
|
||||||
},
|
},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
|
@ -45,8 +45,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cond = expr.condition().filter(|cond| !cond.is_pattern_cond())?;
|
let cond = expr.condition().filter(|cond| !is_pattern_cond(cond.clone()))?;
|
||||||
let cond = cond.expr()?;
|
|
||||||
let then = expr.then_branch()?;
|
let then = expr.then_branch()?;
|
||||||
let else_ = match expr.else_branch()? {
|
let else_ = match expr.else_branch()? {
|
||||||
ast::ElseBranch::Block(b) => b,
|
ast::ElseBranch::Block(b) => b,
|
||||||
|
@ -209,7 +208,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
_ => receiver,
|
_ => receiver,
|
||||||
};
|
};
|
||||||
let if_expr = make::expr_if(
|
let if_expr = make::expr_if(
|
||||||
make::condition(cond, None),
|
cond,
|
||||||
closure_body.reset_indent(),
|
closure_body.reset_indent(),
|
||||||
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
|
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
|
use ide_db::helpers::node_ext::{is_pattern_cond, single_let};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self,
|
self,
|
||||||
|
@ -48,25 +49,28 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
||||||
let cond = if_expr.condition()?;
|
let cond = if_expr.condition()?;
|
||||||
|
|
||||||
// Check if there is an IfLet that we can handle.
|
// Check if there is an IfLet that we can handle.
|
||||||
let if_let_pat = match cond.pat() {
|
let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) {
|
||||||
None => None, // No IfLet, supported.
|
let let_ = single_let(cond)?;
|
||||||
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
|
match let_.pat() {
|
||||||
let path = pat.path()?;
|
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
|
||||||
if path.qualifier().is_some() {
|
let path = pat.path()?;
|
||||||
return None;
|
if path.qualifier().is_some() {
|
||||||
}
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let bound_ident = pat.fields().next().unwrap();
|
let bound_ident = pat.fields().next().unwrap();
|
||||||
if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
|
if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some((path, bound_ident))
|
(Some((path, bound_ident)), let_.expr()?)
|
||||||
|
}
|
||||||
|
_ => return None, // Unsupported IfLet.
|
||||||
}
|
}
|
||||||
Some(_) => return None, // Unsupported IfLet.
|
} else {
|
||||||
|
(None, cond)
|
||||||
};
|
};
|
||||||
|
|
||||||
let cond_expr = cond.expr()?;
|
|
||||||
let then_block = if_expr.then_branch()?;
|
let then_block = if_expr.then_branch()?;
|
||||||
let then_block = then_block.stmt_list()?;
|
let then_block = then_block.stmt_list()?;
|
||||||
|
|
||||||
|
@ -119,8 +123,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
||||||
let then_branch =
|
let then_branch =
|
||||||
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
||||||
let cond = invert_boolean_expression(cond_expr);
|
let cond = invert_boolean_expression(cond_expr);
|
||||||
make::expr_if(make::condition(cond, None), then_branch, None)
|
make::expr_if(cond, then_branch, None).indent(if_indent_level)
|
||||||
.indent(if_indent_level)
|
|
||||||
};
|
};
|
||||||
new_expr.syntax().clone_for_update()
|
new_expr.syntax().clone_for_update()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
|
use ide_db::helpers::node_ext::is_pattern_cond;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self,
|
self,
|
||||||
|
@ -42,7 +43,6 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> O
|
||||||
let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
|
let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
|
||||||
let while_body = while_expr.loop_body()?;
|
let while_body = while_expr.loop_body()?;
|
||||||
let while_cond = while_expr.condition()?;
|
let while_cond = while_expr.condition()?;
|
||||||
let while_cond_expr = while_cond.expr()?;
|
|
||||||
|
|
||||||
let target = while_expr.syntax().text_range();
|
let target = while_expr.syntax().text_range();
|
||||||
acc.add(
|
acc.add(
|
||||||
|
@ -55,19 +55,15 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> O
|
||||||
let break_block =
|
let break_block =
|
||||||
make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
|
make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
|
||||||
.indent(while_indent_level);
|
.indent(while_indent_level);
|
||||||
let block_expr = match while_cond.pat() {
|
let block_expr = if is_pattern_cond(while_cond.clone()) {
|
||||||
Some(_) => {
|
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
||||||
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
let stmts = once(make::expr_stmt(if_expr).into());
|
||||||
let stmts = once(make::expr_stmt(if_expr).into());
|
make::block_expr(stmts, None)
|
||||||
make::block_expr(stmts, None)
|
} else {
|
||||||
}
|
let if_cond = invert_boolean_expression(while_cond);
|
||||||
None => {
|
let if_expr = make::expr_if(if_cond, break_block, None);
|
||||||
let if_cond = make::condition(invert_boolean_expression(while_cond_expr), None);
|
let stmts = once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
|
||||||
let if_expr = make::expr_if(if_cond, break_block, None);
|
make::block_expr(stmts, while_body.tail_expr())
|
||||||
let stmts =
|
|
||||||
once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
|
|
||||||
make::block_expr(stmts, while_body.tail_expr())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let replacement = make::expr_loop(block_expr.indent(while_indent_level));
|
let replacement = make::expr_loop(block_expr.indent(while_indent_level));
|
||||||
|
|
|
@ -1219,28 +1219,26 @@ impl FlowHandler {
|
||||||
let stmt = make::expr_stmt(action);
|
let stmt = make::expr_stmt(action);
|
||||||
let block = make::block_expr(iter::once(stmt.into()), None);
|
let block = make::block_expr(iter::once(stmt.into()), None);
|
||||||
let controlflow_break_path = make::path_from_text("ControlFlow::Break");
|
let controlflow_break_path = make::path_from_text("ControlFlow::Break");
|
||||||
let condition = make::condition(
|
let condition = make::expr_let(
|
||||||
|
make::tuple_struct_pat(
|
||||||
|
controlflow_break_path,
|
||||||
|
iter::once(make::wildcard_pat().into()),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
call_expr,
|
call_expr,
|
||||||
Some(
|
|
||||||
make::tuple_struct_pat(
|
|
||||||
controlflow_break_path,
|
|
||||||
iter::once(make::wildcard_pat().into()),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
make::expr_if(condition, block, None)
|
make::expr_if(condition.into(), block, None)
|
||||||
}
|
}
|
||||||
FlowHandler::IfOption { action } => {
|
FlowHandler::IfOption { action } => {
|
||||||
let path = make::ext::ident_path("Some");
|
let path = make::ext::ident_path("Some");
|
||||||
let value_pat = make::ext::simple_ident_pat(make::name("value"));
|
let value_pat = make::ext::simple_ident_pat(make::name("value"));
|
||||||
let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
||||||
let cond = make::condition(call_expr, Some(pattern.into()));
|
let cond = make::expr_let(pattern.into(), call_expr);
|
||||||
let value = make::expr_path(make::ext::ident_path("value"));
|
let value = make::expr_path(make::ext::ident_path("value"));
|
||||||
let action_expr = action.make_result_handler(Some(value));
|
let action_expr = action.make_result_handler(Some(value));
|
||||||
let action_stmt = make::expr_stmt(action_expr);
|
let action_stmt = make::expr_stmt(action_expr);
|
||||||
let then = make::block_expr(iter::once(action_stmt.into()), None);
|
let then = make::block_expr(iter::once(action_stmt.into()), None);
|
||||||
make::expr_if(cond, then, None)
|
make::expr_if(cond.into(), then, None)
|
||||||
}
|
}
|
||||||
FlowHandler::MatchOption { none } => {
|
FlowHandler::MatchOption { none } => {
|
||||||
let some_name = "value";
|
let some_name = "value";
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use ide_db::helpers::node_ext::is_pattern_cond;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
T,
|
T,
|
||||||
|
@ -34,12 +35,12 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cond = expr.condition()?;
|
||||||
// This assist should not apply for if-let.
|
// This assist should not apply for if-let.
|
||||||
if expr.condition()?.is_pattern_cond() {
|
if is_pattern_cond(cond.clone()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cond = expr.condition()?.expr()?;
|
|
||||||
let then_node = expr.then_branch()?.syntax().clone();
|
let then_node = expr.then_branch()?.syntax().clone();
|
||||||
let else_block = match expr.else_branch()? {
|
let else_block = match expr.else_branch()? {
|
||||||
ast::ElseBranch::Block(it) => it,
|
ast::ElseBranch::Block(it) => it,
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat},
|
||||||
edit::AstNodeEdit, make, AstNode, BlockExpr, Condition, ElseBranch, Expr, IfExpr, MatchArm,
|
|
||||||
Pat,
|
|
||||||
},
|
|
||||||
SyntaxKind::WHITESPACE,
|
SyntaxKind::WHITESPACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,18 +41,11 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
}
|
}
|
||||||
let space_before_guard = guard.syntax().prev_sibling_or_token();
|
let space_before_guard = guard.syntax().prev_sibling_or_token();
|
||||||
|
|
||||||
// FIXME: support `if let` guards too
|
let guard_condition = guard.condition()?;
|
||||||
if guard.let_token().is_some() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let guard_condition = guard.expr()?;
|
|
||||||
let arm_expr = match_arm.expr()?;
|
let arm_expr = match_arm.expr()?;
|
||||||
let if_expr = make::expr_if(
|
let if_expr =
|
||||||
make::condition(guard_condition, None),
|
make::expr_if(guard_condition, make::block_expr(None, Some(arm_expr.clone())), None)
|
||||||
make::block_expr(None, Some(arm_expr.clone())),
|
.indent(arm_expr.indent_level());
|
||||||
None,
|
|
||||||
)
|
|
||||||
.indent(arm_expr.indent_level());
|
|
||||||
|
|
||||||
let target = guard.syntax().text_range();
|
let target = guard.syntax().text_range();
|
||||||
acc.add(
|
acc.add(
|
||||||
|
@ -193,17 +183,13 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses an if-else-if chain to get the conditons and the then branches until we encounter an else
|
// Parses an if-else-if chain to get the conditions and the then branches until we encounter an else
|
||||||
// branch or the end.
|
// branch or the end.
|
||||||
fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Condition, BlockExpr)>, Option<BlockExpr>)> {
|
fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Expr, BlockExpr)>, Option<BlockExpr>)> {
|
||||||
let mut conds_blocks = Vec::new();
|
let mut conds_blocks = Vec::new();
|
||||||
let mut curr_if = if_expr;
|
let mut curr_if = if_expr;
|
||||||
let tail = loop {
|
let tail = loop {
|
||||||
let cond = curr_if.condition()?;
|
let cond = curr_if.condition()?;
|
||||||
// Not support moving if let to arm guard
|
|
||||||
if cond.is_pattern_cond() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
conds_blocks.push((cond, curr_if.then_branch()?));
|
conds_blocks.push((cond, curr_if.then_branch()?));
|
||||||
match curr_if.else_branch() {
|
match curr_if.else_branch() {
|
||||||
Some(ElseBranch::IfExpr(e)) => {
|
Some(ElseBranch::IfExpr(e)) => {
|
||||||
|
@ -280,6 +266,31 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn move_let_guard_to_arm_body_works() {
|
||||||
|
check_assist(
|
||||||
|
move_guard_to_arm_body,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
match 92 {
|
||||||
|
x $0if (let 1 = x) => false,
|
||||||
|
_ => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
match 92 {
|
||||||
|
x => if (let 1 = x) {
|
||||||
|
false
|
||||||
|
},
|
||||||
|
_ => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn move_guard_to_arm_body_works_complex_match() {
|
fn move_guard_to_arm_body_works_complex_match() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
@ -440,13 +451,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn move_arm_cond_to_match_guard_if_let_not_works() {
|
fn move_arm_cond_to_match_guard_if_let_works() {
|
||||||
check_assist_not_applicable(
|
check_assist(
|
||||||
move_arm_cond_to_match_guard,
|
move_arm_cond_to_match_guard,
|
||||||
r#"
|
r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
match 92 {
|
match 92 {
|
||||||
x => if let 62 = x { $0false },
|
x => if let 62 = x && true { $0false },
|
||||||
|
_ => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
match 92 {
|
||||||
|
x if let 62 = x && true => false,
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -898,7 +917,7 @@ fn main() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn move_arm_cond_to_match_guard_elseif_iflet() {
|
fn move_arm_cond_to_match_guard_elseif_iflet() {
|
||||||
check_assist_not_applicable(
|
check_assist(
|
||||||
move_arm_cond_to_match_guard,
|
move_arm_cond_to_match_guard,
|
||||||
r#"
|
r#"
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -915,9 +934,21 @@ fn main() {
|
||||||
4
|
4
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}"#,
|
||||||
"#,
|
r#"
|
||||||
)
|
fn main() {
|
||||||
|
match 92 {
|
||||||
|
3 => 0,
|
||||||
|
x if x > 10 => 1,
|
||||||
|
x if x > 5 => 2,
|
||||||
|
x if let 4 = 4 => {
|
||||||
|
42;
|
||||||
|
3
|
||||||
|
}
|
||||||
|
x => 4,
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
use std::iter::{self, successors};
|
use std::iter::{self, successors};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use ide_db::{defs::NameClass, ty_filter::TryEnum, RootDatabase};
|
use ide_db::{
|
||||||
|
defs::NameClass,
|
||||||
|
helpers::node_ext::{is_pattern_cond, single_let},
|
||||||
|
ty_filter::TryEnum,
|
||||||
|
RootDatabase,
|
||||||
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self,
|
self,
|
||||||
|
@ -60,15 +65,22 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let scrutinee_to_be_expr = if_expr.condition()?.expr()?;
|
let scrutinee_to_be_expr = if_expr.condition()?;
|
||||||
|
let scrutinee_to_be_expr = match single_let(scrutinee_to_be_expr.clone()) {
|
||||||
|
Some(cond) => cond.expr()?,
|
||||||
|
None => scrutinee_to_be_expr,
|
||||||
|
};
|
||||||
|
|
||||||
let mut pat_seen = false;
|
let mut pat_seen = false;
|
||||||
let mut cond_bodies = Vec::new();
|
let mut cond_bodies = Vec::new();
|
||||||
for if_expr in if_exprs {
|
for if_expr in if_exprs {
|
||||||
let cond = if_expr.condition()?;
|
let cond = if_expr.condition()?;
|
||||||
let expr = cond.expr()?;
|
let cond = match single_let(cond.clone()) {
|
||||||
let cond = match cond.pat() {
|
Some(let_) => {
|
||||||
Some(pat) => {
|
let pat = let_.pat()?;
|
||||||
|
let expr = let_.expr()?;
|
||||||
|
// FIXME: If one `let` is wrapped in parentheses and the second is not,
|
||||||
|
// we'll exit here.
|
||||||
if scrutinee_to_be_expr.syntax().text() != expr.syntax().text() {
|
if scrutinee_to_be_expr.syntax().text() != expr.syntax().text() {
|
||||||
// Only if all condition expressions are equal we can merge them into a match
|
// Only if all condition expressions are equal we can merge them into a match
|
||||||
return None;
|
return None;
|
||||||
|
@ -76,7 +88,9 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
|
||||||
pat_seen = true;
|
pat_seen = true;
|
||||||
Either::Left(pat)
|
Either::Left(pat)
|
||||||
}
|
}
|
||||||
None => Either::Right(expr),
|
// Multiple `let`, unsupported.
|
||||||
|
None if is_pattern_cond(cond.clone()) => return None,
|
||||||
|
None => Either::Right(cond),
|
||||||
};
|
};
|
||||||
let body = if_expr.then_branch()?;
|
let body = if_expr.then_branch()?;
|
||||||
cond_bodies.push((cond, body));
|
cond_bodies.push((cond, body));
|
||||||
|
@ -217,11 +231,11 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let condition = make::condition(scrutinee, Some(if_let_pat));
|
let condition = make::expr_let(if_let_pat, scrutinee);
|
||||||
let then_block = make_block_expr(then_expr.reset_indent());
|
let then_block = make_block_expr(then_expr.reset_indent());
|
||||||
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
||||||
let if_let_expr = make::expr_if(
|
let if_let_expr = make::expr_if(
|
||||||
condition,
|
condition.into(),
|
||||||
then_block,
|
then_block,
|
||||||
else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
|
else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
|
||||||
)
|
)
|
||||||
|
@ -372,6 +386,18 @@ impl VariantData {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_if_let_with_match_let_chain() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
replace_if_let_with_match,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
if $0let true = true && let Some(1) = None {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_if_let_with_match_basic() {
|
fn test_if_let_with_match_basic() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
|
|
||||||
let block =
|
let block =
|
||||||
make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax()));
|
make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax()));
|
||||||
let if_ = make::expr_if(make::condition(init, Some(pat)), block, None);
|
let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None);
|
||||||
let stmt = make::expr_stmt(if_);
|
let stmt = make::expr_stmt(if_);
|
||||||
|
|
||||||
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
||||||
|
|
|
@ -575,6 +575,14 @@ impl<'a> CompletionContext<'a> {
|
||||||
|
|
||||||
(ty, name)
|
(ty, name)
|
||||||
},
|
},
|
||||||
|
ast::LetExpr(it) => {
|
||||||
|
cov_mark::hit!(expected_type_if_let_without_leading_char);
|
||||||
|
let ty = it.pat()
|
||||||
|
.and_then(|pat| self.sema.type_of_pat(&pat))
|
||||||
|
.or_else(|| it.expr().and_then(|it| self.sema.type_of_expr(&it)))
|
||||||
|
.map(TypeInfo::original);
|
||||||
|
(ty, None)
|
||||||
|
},
|
||||||
ast::ArgList(_) => {
|
ast::ArgList(_) => {
|
||||||
cov_mark::hit!(expected_type_fn_param);
|
cov_mark::hit!(expected_type_fn_param);
|
||||||
ActiveParameter::at_token(
|
ActiveParameter::at_token(
|
||||||
|
@ -641,9 +649,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
(ty, None)
|
(ty, None)
|
||||||
},
|
},
|
||||||
ast::IfExpr(it) => {
|
ast::IfExpr(it) => {
|
||||||
cov_mark::hit!(expected_type_if_let_without_leading_char);
|
|
||||||
let ty = it.condition()
|
let ty = it.condition()
|
||||||
.and_then(|cond| cond.expr())
|
|
||||||
.and_then(|e| self.sema.type_of_expr(&e))
|
.and_then(|e| self.sema.type_of_expr(&e))
|
||||||
.map(TypeInfo::original);
|
.map(TypeInfo::original);
|
||||||
(ty, None)
|
(ty, None)
|
||||||
|
@ -939,7 +945,7 @@ fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternCont
|
||||||
return (PatternRefutability::Irrefutable, has_type_ascription)
|
return (PatternRefutability::Irrefutable, has_type_ascription)
|
||||||
},
|
},
|
||||||
ast::MatchArm(_) => PatternRefutability::Refutable,
|
ast::MatchArm(_) => PatternRefutability::Refutable,
|
||||||
ast::Condition(_) => PatternRefutability::Refutable,
|
ast::LetExpr(_) => PatternRefutability::Refutable,
|
||||||
ast::ForExpr(_) => PatternRefutability::Irrefutable,
|
ast::ForExpr(_) => PatternRefutability::Irrefutable,
|
||||||
_ => PatternRefutability::Irrefutable,
|
_ => PatternRefutability::Irrefutable,
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,6 +226,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
|
||||||
| ast::Expr::TryExpr(_)
|
| ast::Expr::TryExpr(_)
|
||||||
| ast::Expr::TupleExpr(_)
|
| ast::Expr::TupleExpr(_)
|
||||||
| ast::Expr::WhileExpr(_)
|
| ast::Expr::WhileExpr(_)
|
||||||
|
| ast::Expr::LetExpr(_)
|
||||||
| ast::Expr::YieldExpr(_) => cb(expr),
|
| ast::Expr::YieldExpr(_) => cb(expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,3 +216,29 @@ pub fn vis_eq(this: &ast::Visibility, other: &ast::Visibility) -> bool {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `let` only if there is exactly one (that is, `let pat = expr`
|
||||||
|
/// or `((let pat = expr))`, but not `let pat = expr && expr` or `non_let_expr`).
|
||||||
|
pub fn single_let(expr: ast::Expr) -> Option<ast::LetExpr> {
|
||||||
|
match expr {
|
||||||
|
ast::Expr::ParenExpr(expr) => expr.expr().and_then(single_let),
|
||||||
|
ast::Expr::LetExpr(expr) => Some(expr),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_pattern_cond(expr: ast::Expr) -> bool {
|
||||||
|
match expr {
|
||||||
|
ast::Expr::BinExpr(expr)
|
||||||
|
if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) =>
|
||||||
|
{
|
||||||
|
expr.lhs()
|
||||||
|
.map(is_pattern_cond)
|
||||||
|
.or_else(|| expr.rhs().map(is_pattern_cond))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
ast::Expr::ParenExpr(expr) => expr.expr().map_or(false, is_pattern_cond),
|
||||||
|
ast::Expr::LetExpr(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,15 @@ fn expr_no_struct(p: &mut Parser) {
|
||||||
expr_bp(p, None, r, 1);
|
expr_bp(p, None, r, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses the expression in `let pattern = expression`.
|
||||||
|
/// It needs to be parsed with lower precedence than `&&`, so that
|
||||||
|
/// `if let true = true && false` is parsed as `if (let true = true) && (true)`
|
||||||
|
/// and not `if let true = (true && true)`.
|
||||||
|
fn expr_let(p: &mut Parser) {
|
||||||
|
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
|
||||||
|
expr_bp(p, None, r, 5);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn stmt(p: &mut Parser, semicolon: Semicolon) {
|
pub(super) fn stmt(p: &mut Parser, semicolon: Semicolon) {
|
||||||
if p.eat(T![;]) {
|
if p.eat(T![;]) {
|
||||||
return;
|
return;
|
||||||
|
@ -185,6 +194,7 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
|
||||||
T![%] if p.at(T![%=]) => (1, T![%=]),
|
T![%] if p.at(T![%=]) => (1, T![%=]),
|
||||||
T![%] => (11, T![%]),
|
T![%] => (11, T![%]),
|
||||||
T![&] if p.at(T![&=]) => (1, T![&=]),
|
T![&] if p.at(T![&=]) => (1, T![&=]),
|
||||||
|
// If you update this, remember to update `expr_let()` too.
|
||||||
T![&] if p.at(T![&&]) => (4, T![&&]),
|
T![&] if p.at(T![&&]) => (4, T![&&]),
|
||||||
T![&] => (8, T![&]),
|
T![&] => (8, T![&]),
|
||||||
T![/] if p.at(T![/=]) => (1, T![/=]),
|
T![/] if p.at(T![/=]) => (1, T![/=]),
|
||||||
|
|
|
@ -79,6 +79,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
|
||||||
closure_expr(p)
|
closure_expr(p)
|
||||||
}
|
}
|
||||||
T![if] => if_expr(p),
|
T![if] => if_expr(p),
|
||||||
|
T![let] => let_expr(p),
|
||||||
|
|
||||||
T![loop] => loop_expr(p, None),
|
T![loop] => loop_expr(p, None),
|
||||||
T![box] => box_expr(p, None),
|
T![box] => box_expr(p, None),
|
||||||
|
@ -286,7 +287,7 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
|
||||||
assert!(p.at(T![if]));
|
assert!(p.at(T![if]));
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
p.bump(T![if]);
|
p.bump(T![if]);
|
||||||
condition(p);
|
expr_no_struct(p);
|
||||||
block_expr(p);
|
block_expr(p);
|
||||||
if p.at(T![else]) {
|
if p.at(T![else]) {
|
||||||
p.bump(T![else]);
|
p.bump(T![else]);
|
||||||
|
@ -335,7 +336,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
||||||
assert!(p.at(T![while]));
|
assert!(p.at(T![while]));
|
||||||
let m = m.unwrap_or_else(|| p.start());
|
let m = m.unwrap_or_else(|| p.start());
|
||||||
p.bump(T![while]);
|
p.bump(T![while]);
|
||||||
condition(p);
|
expr_no_struct(p);
|
||||||
block_expr(p);
|
block_expr(p);
|
||||||
m.complete(p, WHILE_EXPR)
|
m.complete(p, WHILE_EXPR)
|
||||||
}
|
}
|
||||||
|
@ -355,22 +356,18 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
||||||
m.complete(p, FOR_EXPR)
|
m.complete(p, FOR_EXPR)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test cond
|
// test let_expr
|
||||||
// fn foo() { if let Some(_) = None {} }
|
// fn foo() {
|
||||||
// fn bar() {
|
// if let Some(_) = None && true {}
|
||||||
// if let Some(_) | Some(_) = None {}
|
// while 1 == 5 && (let None = None) {}
|
||||||
// if let | Some(_) = None {}
|
|
||||||
// while let Some(_) | Some(_) = None {}
|
|
||||||
// while let | Some(_) = None {}
|
|
||||||
// }
|
// }
|
||||||
fn condition(p: &mut Parser) {
|
fn let_expr(p: &mut Parser) -> CompletedMarker {
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
if p.eat(T![let]) {
|
p.bump(T![let]);
|
||||||
patterns::pattern_top(p);
|
patterns::pattern_top(p);
|
||||||
p.expect(T![=]);
|
p.expect(T![=]);
|
||||||
}
|
expr_let(p);
|
||||||
expr_no_struct(p);
|
m.complete(p, LET_EXPR)
|
||||||
m.complete(p, CONDITION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test match_expr
|
// test match_expr
|
||||||
|
@ -482,10 +479,6 @@ fn match_guard(p: &mut Parser) -> CompletedMarker {
|
||||||
assert!(p.at(T![if]));
|
assert!(p.at(T![if]));
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
p.bump(T![if]);
|
p.bump(T![if]);
|
||||||
if p.eat(T![let]) {
|
|
||||||
patterns::pattern_top(p);
|
|
||||||
p.expect(T![=]);
|
|
||||||
}
|
|
||||||
expr(p);
|
expr(p);
|
||||||
m.complete(p, MATCH_GUARD)
|
m.complete(p, MATCH_GUARD)
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,6 @@ pub enum SyntaxKind {
|
||||||
CLOSURE_EXPR,
|
CLOSURE_EXPR,
|
||||||
IF_EXPR,
|
IF_EXPR,
|
||||||
WHILE_EXPR,
|
WHILE_EXPR,
|
||||||
CONDITION,
|
|
||||||
LOOP_EXPR,
|
LOOP_EXPR,
|
||||||
FOR_EXPR,
|
FOR_EXPR,
|
||||||
CONTINUE_EXPR,
|
CONTINUE_EXPR,
|
||||||
|
@ -188,6 +187,7 @@ pub enum SyntaxKind {
|
||||||
STMT_LIST,
|
STMT_LIST,
|
||||||
RETURN_EXPR,
|
RETURN_EXPR,
|
||||||
YIELD_EXPR,
|
YIELD_EXPR,
|
||||||
|
LET_EXPR,
|
||||||
MATCH_EXPR,
|
MATCH_EXPR,
|
||||||
MATCH_ARM_LIST,
|
MATCH_ARM_LIST,
|
||||||
MATCH_ARM,
|
MATCH_ARM,
|
||||||
|
|
|
@ -289,17 +289,19 @@ fn expr() {
|
||||||
TopEntryPoint::Expr,
|
TopEntryPoint::Expr,
|
||||||
"let _ = 0;",
|
"let _ = 0;",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ERROR
|
ERROR
|
||||||
LET_KW "let"
|
LET_EXPR
|
||||||
WHITESPACE " "
|
LET_KW "let"
|
||||||
UNDERSCORE "_"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
WILDCARD_PAT
|
||||||
EQ "="
|
UNDERSCORE "_"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
INT_NUMBER "0"
|
EQ "="
|
||||||
SEMICOLON ";"
|
WHITESPACE " "
|
||||||
error 0: expected expression
|
LITERAL
|
||||||
"#]],
|
INT_NUMBER "0"
|
||||||
|
SEMICOLON ";"
|
||||||
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let foo =
|
let foo = 11
|
||||||
let bar = 1;
|
let bar = 1;
|
||||||
let
|
let
|
||||||
let baz = 92;
|
let baz = 92;
|
||||||
|
|
|
@ -20,6 +20,9 @@ SOURCE_FILE
|
||||||
IDENT "foo"
|
IDENT "foo"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
EQ "="
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "11"
|
||||||
WHITESPACE "\n "
|
WHITESPACE "\n "
|
||||||
LET_STMT
|
LET_STMT
|
||||||
LET_KW "let"
|
LET_KW "let"
|
||||||
|
@ -57,9 +60,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -73,9 +75,8 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -95,13 +96,12 @@ SOURCE_FILE
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
R_CURLY "}"
|
R_CURLY "}"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
error 24: expected expression
|
error 27: expected SEMICOLON
|
||||||
error 24: expected SEMICOLON
|
error 52: expected pattern
|
||||||
error 49: expected pattern
|
error 52: expected SEMICOLON
|
||||||
error 49: expected SEMICOLON
|
error 78: expected pattern
|
||||||
error 75: expected pattern
|
error 78: expected SEMICOLON
|
||||||
error 75: expected SEMICOLON
|
error 101: expected pattern
|
||||||
error 98: expected pattern
|
error 101: expected SEMICOLON
|
||||||
error 98: expected SEMICOLON
|
error 127: expected pattern
|
||||||
error 124: expected pattern
|
error 127: expected SEMICOLON
|
||||||
error 124: expected SEMICOLON
|
|
||||||
|
|
|
@ -180,116 +180,118 @@ SOURCE_FILE
|
||||||
ERROR
|
ERROR
|
||||||
PLUS "+"
|
PLUS "+"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
EXPR_STMT
|
TUPLE_EXPR
|
||||||
TUPLE_EXPR
|
L_PAREN "("
|
||||||
L_PAREN "("
|
FOR_EXPR
|
||||||
FOR_EXPR
|
FOR_KW "for"
|
||||||
FOR_KW "for"
|
PATH_PAT
|
||||||
PATH_PAT
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
L_ANGLE "<"
|
||||||
L_ANGLE "<"
|
ERROR
|
||||||
ERROR
|
LIFETIME_IDENT "'a"
|
||||||
LIFETIME_IDENT "'a"
|
R_ANGLE ">"
|
||||||
R_ANGLE ">"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
BIN_EXPR
|
||||||
BIN_EXPR
|
BIN_EXPR
|
||||||
BIN_EXPR
|
BIN_EXPR
|
||||||
BIN_EXPR
|
BIN_EXPR
|
||||||
BIN_EXPR
|
|
||||||
PATH_EXPR
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Trait"
|
|
||||||
L_ANGLE "<"
|
|
||||||
ERROR
|
|
||||||
LIFETIME_IDENT "'a"
|
|
||||||
R_ANGLE ">"
|
|
||||||
ERROR
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
PLUS "+"
|
|
||||||
WHITESPACE " "
|
|
||||||
PAREN_EXPR
|
|
||||||
L_PAREN "("
|
|
||||||
PATH_EXPR
|
PATH_EXPR
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "Copy"
|
IDENT "Trait"
|
||||||
|
L_ANGLE "<"
|
||||||
|
ERROR
|
||||||
|
LIFETIME_IDENT "'a"
|
||||||
|
R_ANGLE ">"
|
||||||
|
ERROR
|
||||||
R_PAREN ")"
|
R_PAREN ")"
|
||||||
R_ANGLE ">"
|
WHITESPACE " "
|
||||||
ERROR
|
PLUS "+"
|
||||||
SEMICOLON ";"
|
WHITESPACE " "
|
||||||
WHITESPACE "\n "
|
PAREN_EXPR
|
||||||
LET_STMT
|
L_PAREN "("
|
||||||
LET_KW "let"
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "Copy"
|
||||||
|
R_PAREN ")"
|
||||||
|
R_ANGLE ">"
|
||||||
|
ERROR
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
LET_EXPR
|
||||||
|
LET_KW "let"
|
||||||
|
WHITESPACE " "
|
||||||
|
WILDCARD_PAT
|
||||||
|
UNDERSCORE "_"
|
||||||
|
ERROR
|
||||||
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
WILDCARD_PAT
|
BIN_EXPR
|
||||||
UNDERSCORE "_"
|
BIN_EXPR
|
||||||
COLON ":"
|
PATH_EXPR
|
||||||
WHITESPACE " "
|
PATH
|
||||||
DYN_TRAIT_TYPE
|
PATH_SEGMENT
|
||||||
TYPE_BOUND_LIST
|
NAME_REF
|
||||||
TYPE_BOUND
|
IDENT "Box"
|
||||||
PATH_TYPE
|
L_ANGLE "<"
|
||||||
PATH
|
TUPLE_EXPR
|
||||||
PATH_SEGMENT
|
L_PAREN "("
|
||||||
NAME_REF
|
FOR_EXPR
|
||||||
IDENT "Box"
|
FOR_KW "for"
|
||||||
GENERIC_ARG_LIST
|
PATH_PAT
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
L_ANGLE "<"
|
L_ANGLE "<"
|
||||||
TYPE_ARG
|
ERROR
|
||||||
PAREN_TYPE
|
LIFETIME_IDENT "'a"
|
||||||
L_PAREN "("
|
R_ANGLE ">"
|
||||||
FOR_TYPE
|
WHITESPACE " "
|
||||||
FOR_KW "for"
|
BIN_EXPR
|
||||||
GENERIC_PARAM_LIST
|
BIN_EXPR
|
||||||
L_ANGLE "<"
|
BIN_EXPR
|
||||||
LIFETIME_PARAM
|
BIN_EXPR
|
||||||
LIFETIME
|
PATH_EXPR
|
||||||
LIFETIME_IDENT "'a"
|
PATH
|
||||||
R_ANGLE ">"
|
PATH_SEGMENT
|
||||||
WHITESPACE " "
|
NAME_REF
|
||||||
PATH_TYPE
|
IDENT "Trait"
|
||||||
PATH
|
L_ANGLE "<"
|
||||||
PATH_SEGMENT
|
ERROR
|
||||||
NAME_REF
|
LIFETIME_IDENT "'a"
|
||||||
IDENT "Trait"
|
R_ANGLE ">"
|
||||||
GENERIC_ARG_LIST
|
ERROR
|
||||||
L_ANGLE "<"
|
R_PAREN ")"
|
||||||
LIFETIME_ARG
|
WHITESPACE " "
|
||||||
LIFETIME
|
PLUS "+"
|
||||||
LIFETIME_IDENT "'a"
|
WHITESPACE " "
|
||||||
R_ANGLE ">"
|
PAREN_EXPR
|
||||||
R_PAREN ")"
|
L_PAREN "("
|
||||||
WHITESPACE " "
|
PATH_EXPR
|
||||||
PLUS "+"
|
PATH
|
||||||
WHITESPACE " "
|
PATH_SEGMENT
|
||||||
TYPE_BOUND
|
NAME_REF
|
||||||
L_PAREN "("
|
IDENT "Copy"
|
||||||
PATH_TYPE
|
R_PAREN ")"
|
||||||
PATH
|
WHITESPACE " "
|
||||||
PATH_SEGMENT
|
PLUS "+"
|
||||||
NAME_REF
|
WHITESPACE " "
|
||||||
IDENT "Copy"
|
PAREN_EXPR
|
||||||
R_PAREN ")"
|
L_PAREN "("
|
||||||
WHITESPACE " "
|
ERROR
|
||||||
PLUS "+"
|
QUESTION "?"
|
||||||
WHITESPACE " "
|
PATH_EXPR
|
||||||
TYPE_BOUND
|
|
||||||
L_PAREN "("
|
|
||||||
QUESTION "?"
|
|
||||||
PATH_TYPE
|
|
||||||
PATH
|
PATH
|
||||||
PATH_SEGMENT
|
PATH_SEGMENT
|
||||||
NAME_REF
|
NAME_REF
|
||||||
IDENT "Sized"
|
IDENT "Sized"
|
||||||
R_PAREN ")"
|
R_PAREN ")"
|
||||||
ERROR
|
R_ANGLE ">"
|
||||||
R_ANGLE ">"
|
ERROR
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
R_CURLY "}"
|
R_CURLY "}"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
|
@ -312,10 +314,18 @@ error 168: expected expression
|
||||||
error 179: expected expression
|
error 179: expected expression
|
||||||
error 180: expected a block
|
error 180: expected a block
|
||||||
error 180: expected COMMA
|
error 180: expected COMMA
|
||||||
error 180: expected expression
|
error 190: expected EQ
|
||||||
error 180: expected R_PAREN
|
error 190: expected expression
|
||||||
error 180: expected SEMICOLON
|
error 191: expected COMMA
|
||||||
error 215: expected COMMA
|
error 201: expected type
|
||||||
error 215: expected R_ANGLE
|
error 204: expected IN_KW
|
||||||
error 235: expected SEMICOLON
|
error 211: expected expression
|
||||||
error 235: expected expression
|
error 214: expected expression
|
||||||
|
error 228: expected expression
|
||||||
|
error 229: expected R_PAREN
|
||||||
|
error 229: expected a block
|
||||||
|
error 229: expected COMMA
|
||||||
|
error 236: expected expression
|
||||||
|
error 237: expected COMMA
|
||||||
|
error 237: expected expression
|
||||||
|
error 237: expected R_PAREN
|
||||||
|
|
|
@ -1,209 +0,0 @@
|
||||||
SOURCE_FILE@0..197
|
|
||||||
FN@0..37
|
|
||||||
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..37
|
|
||||||
STMT_LIST@9..37
|
|
||||||
L_CURLY@9..10 "{"
|
|
||||||
WHITESPACE@10..11 " "
|
|
||||||
IF_EXPR@11..35
|
|
||||||
IF_KW@11..13 "if"
|
|
||||||
WHITESPACE@13..14 " "
|
|
||||||
CONDITION@14..32
|
|
||||||
LET_KW@14..17 "let"
|
|
||||||
WHITESPACE@17..18 " "
|
|
||||||
TUPLE_STRUCT_PAT@18..25
|
|
||||||
PATH@18..22
|
|
||||||
PATH_SEGMENT@18..22
|
|
||||||
NAME_REF@18..22
|
|
||||||
IDENT@18..22 "Some"
|
|
||||||
L_PAREN@22..23 "("
|
|
||||||
WILDCARD_PAT@23..24
|
|
||||||
UNDERSCORE@23..24 "_"
|
|
||||||
R_PAREN@24..25 ")"
|
|
||||||
WHITESPACE@25..26 " "
|
|
||||||
EQ@26..27 "="
|
|
||||||
WHITESPACE@27..28 " "
|
|
||||||
PATH_EXPR@28..32
|
|
||||||
PATH@28..32
|
|
||||||
PATH_SEGMENT@28..32
|
|
||||||
NAME_REF@28..32
|
|
||||||
IDENT@28..32 "None"
|
|
||||||
WHITESPACE@32..33 " "
|
|
||||||
BLOCK_EXPR@33..35
|
|
||||||
STMT_LIST@33..35
|
|
||||||
L_CURLY@33..34 "{"
|
|
||||||
R_CURLY@34..35 "}"
|
|
||||||
WHITESPACE@35..36 " "
|
|
||||||
R_CURLY@36..37 "}"
|
|
||||||
WHITESPACE@37..38 "\n"
|
|
||||||
FN@38..196
|
|
||||||
FN_KW@38..40 "fn"
|
|
||||||
WHITESPACE@40..41 " "
|
|
||||||
NAME@41..44
|
|
||||||
IDENT@41..44 "bar"
|
|
||||||
PARAM_LIST@44..46
|
|
||||||
L_PAREN@44..45 "("
|
|
||||||
R_PAREN@45..46 ")"
|
|
||||||
WHITESPACE@46..47 " "
|
|
||||||
BLOCK_EXPR@47..196
|
|
||||||
STMT_LIST@47..196
|
|
||||||
L_CURLY@47..48 "{"
|
|
||||||
WHITESPACE@48..53 "\n "
|
|
||||||
EXPR_STMT@53..87
|
|
||||||
IF_EXPR@53..87
|
|
||||||
IF_KW@53..55 "if"
|
|
||||||
WHITESPACE@55..56 " "
|
|
||||||
CONDITION@56..84
|
|
||||||
LET_KW@56..59 "let"
|
|
||||||
WHITESPACE@59..60 " "
|
|
||||||
OR_PAT@60..77
|
|
||||||
TUPLE_STRUCT_PAT@60..67
|
|
||||||
PATH@60..64
|
|
||||||
PATH_SEGMENT@60..64
|
|
||||||
NAME_REF@60..64
|
|
||||||
IDENT@60..64 "Some"
|
|
||||||
L_PAREN@64..65 "("
|
|
||||||
WILDCARD_PAT@65..66
|
|
||||||
UNDERSCORE@65..66 "_"
|
|
||||||
R_PAREN@66..67 ")"
|
|
||||||
WHITESPACE@67..68 " "
|
|
||||||
PIPE@68..69 "|"
|
|
||||||
WHITESPACE@69..70 " "
|
|
||||||
TUPLE_STRUCT_PAT@70..77
|
|
||||||
PATH@70..74
|
|
||||||
PATH_SEGMENT@70..74
|
|
||||||
NAME_REF@70..74
|
|
||||||
IDENT@70..74 "Some"
|
|
||||||
L_PAREN@74..75 "("
|
|
||||||
WILDCARD_PAT@75..76
|
|
||||||
UNDERSCORE@75..76 "_"
|
|
||||||
R_PAREN@76..77 ")"
|
|
||||||
WHITESPACE@77..78 " "
|
|
||||||
EQ@78..79 "="
|
|
||||||
WHITESPACE@79..80 " "
|
|
||||||
PATH_EXPR@80..84
|
|
||||||
PATH@80..84
|
|
||||||
PATH_SEGMENT@80..84
|
|
||||||
NAME_REF@80..84
|
|
||||||
IDENT@80..84 "None"
|
|
||||||
WHITESPACE@84..85 " "
|
|
||||||
BLOCK_EXPR@85..87
|
|
||||||
STMT_LIST@85..87
|
|
||||||
L_CURLY@85..86 "{"
|
|
||||||
R_CURLY@86..87 "}"
|
|
||||||
WHITESPACE@87..92 "\n "
|
|
||||||
EXPR_STMT@92..118
|
|
||||||
IF_EXPR@92..118
|
|
||||||
IF_KW@92..94 "if"
|
|
||||||
WHITESPACE@94..95 " "
|
|
||||||
CONDITION@95..115
|
|
||||||
LET_KW@95..98 "let"
|
|
||||||
WHITESPACE@98..99 " "
|
|
||||||
PIPE@99..100 "|"
|
|
||||||
WHITESPACE@100..101 " "
|
|
||||||
TUPLE_STRUCT_PAT@101..108
|
|
||||||
PATH@101..105
|
|
||||||
PATH_SEGMENT@101..105
|
|
||||||
NAME_REF@101..105
|
|
||||||
IDENT@101..105 "Some"
|
|
||||||
L_PAREN@105..106 "("
|
|
||||||
WILDCARD_PAT@106..107
|
|
||||||
UNDERSCORE@106..107 "_"
|
|
||||||
R_PAREN@107..108 ")"
|
|
||||||
WHITESPACE@108..109 " "
|
|
||||||
EQ@109..110 "="
|
|
||||||
WHITESPACE@110..111 " "
|
|
||||||
PATH_EXPR@111..115
|
|
||||||
PATH@111..115
|
|
||||||
PATH_SEGMENT@111..115
|
|
||||||
NAME_REF@111..115
|
|
||||||
IDENT@111..115 "None"
|
|
||||||
WHITESPACE@115..116 " "
|
|
||||||
BLOCK_EXPR@116..118
|
|
||||||
STMT_LIST@116..118
|
|
||||||
L_CURLY@116..117 "{"
|
|
||||||
R_CURLY@117..118 "}"
|
|
||||||
WHITESPACE@118..123 "\n "
|
|
||||||
EXPR_STMT@123..160
|
|
||||||
WHILE_EXPR@123..160
|
|
||||||
WHILE_KW@123..128 "while"
|
|
||||||
WHITESPACE@128..129 " "
|
|
||||||
CONDITION@129..157
|
|
||||||
LET_KW@129..132 "let"
|
|
||||||
WHITESPACE@132..133 " "
|
|
||||||
OR_PAT@133..150
|
|
||||||
TUPLE_STRUCT_PAT@133..140
|
|
||||||
PATH@133..137
|
|
||||||
PATH_SEGMENT@133..137
|
|
||||||
NAME_REF@133..137
|
|
||||||
IDENT@133..137 "Some"
|
|
||||||
L_PAREN@137..138 "("
|
|
||||||
WILDCARD_PAT@138..139
|
|
||||||
UNDERSCORE@138..139 "_"
|
|
||||||
R_PAREN@139..140 ")"
|
|
||||||
WHITESPACE@140..141 " "
|
|
||||||
PIPE@141..142 "|"
|
|
||||||
WHITESPACE@142..143 " "
|
|
||||||
TUPLE_STRUCT_PAT@143..150
|
|
||||||
PATH@143..147
|
|
||||||
PATH_SEGMENT@143..147
|
|
||||||
NAME_REF@143..147
|
|
||||||
IDENT@143..147 "Some"
|
|
||||||
L_PAREN@147..148 "("
|
|
||||||
WILDCARD_PAT@148..149
|
|
||||||
UNDERSCORE@148..149 "_"
|
|
||||||
R_PAREN@149..150 ")"
|
|
||||||
WHITESPACE@150..151 " "
|
|
||||||
EQ@151..152 "="
|
|
||||||
WHITESPACE@152..153 " "
|
|
||||||
PATH_EXPR@153..157
|
|
||||||
PATH@153..157
|
|
||||||
PATH_SEGMENT@153..157
|
|
||||||
NAME_REF@153..157
|
|
||||||
IDENT@153..157 "None"
|
|
||||||
WHITESPACE@157..158 " "
|
|
||||||
BLOCK_EXPR@158..160
|
|
||||||
STMT_LIST@158..160
|
|
||||||
L_CURLY@158..159 "{"
|
|
||||||
R_CURLY@159..160 "}"
|
|
||||||
WHITESPACE@160..165 "\n "
|
|
||||||
WHILE_EXPR@165..194
|
|
||||||
WHILE_KW@165..170 "while"
|
|
||||||
WHITESPACE@170..171 " "
|
|
||||||
CONDITION@171..191
|
|
||||||
LET_KW@171..174 "let"
|
|
||||||
WHITESPACE@174..175 " "
|
|
||||||
PIPE@175..176 "|"
|
|
||||||
WHITESPACE@176..177 " "
|
|
||||||
TUPLE_STRUCT_PAT@177..184
|
|
||||||
PATH@177..181
|
|
||||||
PATH_SEGMENT@177..181
|
|
||||||
NAME_REF@177..181
|
|
||||||
IDENT@177..181 "Some"
|
|
||||||
L_PAREN@181..182 "("
|
|
||||||
WILDCARD_PAT@182..183
|
|
||||||
UNDERSCORE@182..183 "_"
|
|
||||||
R_PAREN@183..184 ")"
|
|
||||||
WHITESPACE@184..185 " "
|
|
||||||
EQ@185..186 "="
|
|
||||||
WHITESPACE@186..187 " "
|
|
||||||
PATH_EXPR@187..191
|
|
||||||
PATH@187..191
|
|
||||||
PATH_SEGMENT@187..191
|
|
||||||
NAME_REF@187..191
|
|
||||||
IDENT@187..191 "None"
|
|
||||||
WHITESPACE@191..192 " "
|
|
||||||
BLOCK_EXPR@192..194
|
|
||||||
STMT_LIST@192..194
|
|
||||||
L_CURLY@192..193 "{"
|
|
||||||
R_CURLY@193..194 "}"
|
|
||||||
WHITESPACE@194..195 "\n"
|
|
||||||
R_CURLY@195..196 "}"
|
|
||||||
WHITESPACE@196..197 "\n"
|
|
|
@ -1,7 +0,0 @@
|
||||||
fn foo() { if let Some(_) = None {} }
|
|
||||||
fn bar() {
|
|
||||||
if let Some(_) | Some(_) = None {}
|
|
||||||
if let | Some(_) = None {}
|
|
||||||
while let Some(_) | Some(_) = None {}
|
|
||||||
while let | Some(_) = None {}
|
|
||||||
}
|
|
|
@ -1,209 +0,0 @@
|
||||||
SOURCE_FILE
|
|
||||||
FN
|
|
||||||
FN_KW "fn"
|
|
||||||
WHITESPACE " "
|
|
||||||
NAME
|
|
||||||
IDENT "foo"
|
|
||||||
PARAM_LIST
|
|
||||||
L_PAREN "("
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
WHITESPACE " "
|
|
||||||
IF_EXPR
|
|
||||||
IF_KW "if"
|
|
||||||
WHITESPACE " "
|
|
||||||
CONDITION
|
|
||||||
LET_KW "let"
|
|
||||||
WHITESPACE " "
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
EQ "="
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_EXPR
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "None"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE " "
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE "\n"
|
|
||||||
FN
|
|
||||||
FN_KW "fn"
|
|
||||||
WHITESPACE " "
|
|
||||||
NAME
|
|
||||||
IDENT "bar"
|
|
||||||
PARAM_LIST
|
|
||||||
L_PAREN "("
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
WHITESPACE "\n "
|
|
||||||
EXPR_STMT
|
|
||||||
IF_EXPR
|
|
||||||
IF_KW "if"
|
|
||||||
WHITESPACE " "
|
|
||||||
CONDITION
|
|
||||||
LET_KW "let"
|
|
||||||
WHITESPACE " "
|
|
||||||
OR_PAT
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
PIPE "|"
|
|
||||||
WHITESPACE " "
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
EQ "="
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_EXPR
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "None"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE "\n "
|
|
||||||
EXPR_STMT
|
|
||||||
IF_EXPR
|
|
||||||
IF_KW "if"
|
|
||||||
WHITESPACE " "
|
|
||||||
CONDITION
|
|
||||||
LET_KW "let"
|
|
||||||
WHITESPACE " "
|
|
||||||
PIPE "|"
|
|
||||||
WHITESPACE " "
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
EQ "="
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_EXPR
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "None"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE "\n "
|
|
||||||
EXPR_STMT
|
|
||||||
WHILE_EXPR
|
|
||||||
WHILE_KW "while"
|
|
||||||
WHITESPACE " "
|
|
||||||
CONDITION
|
|
||||||
LET_KW "let"
|
|
||||||
WHITESPACE " "
|
|
||||||
OR_PAT
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
PIPE "|"
|
|
||||||
WHITESPACE " "
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
EQ "="
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_EXPR
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "None"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE "\n "
|
|
||||||
WHILE_EXPR
|
|
||||||
WHILE_KW "while"
|
|
||||||
WHITESPACE " "
|
|
||||||
CONDITION
|
|
||||||
LET_KW "let"
|
|
||||||
WHITESPACE " "
|
|
||||||
PIPE "|"
|
|
||||||
WHITESPACE " "
|
|
||||||
TUPLE_STRUCT_PAT
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "Some"
|
|
||||||
L_PAREN "("
|
|
||||||
WILDCARD_PAT
|
|
||||||
UNDERSCORE "_"
|
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
EQ "="
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_EXPR
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "None"
|
|
||||||
WHITESPACE " "
|
|
||||||
BLOCK_EXPR
|
|
||||||
STMT_LIST
|
|
||||||
L_CURLY "{"
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE "\n"
|
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE "\n"
|
|
90
crates/parser/test_data/parser/inline/ok/0030_let_expr.rast
Normal file
90
crates/parser/test_data/parser/inline/ok/0030_let_expr.rast
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
SOURCE_FILE
|
||||||
|
FN
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "foo"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
EXPR_STMT
|
||||||
|
IF_EXPR
|
||||||
|
IF_KW "if"
|
||||||
|
WHITESPACE " "
|
||||||
|
BIN_EXPR
|
||||||
|
LET_EXPR
|
||||||
|
LET_KW "let"
|
||||||
|
WHITESPACE " "
|
||||||
|
TUPLE_STRUCT_PAT
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "Some"
|
||||||
|
L_PAREN "("
|
||||||
|
WILDCARD_PAT
|
||||||
|
UNDERSCORE "_"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "None"
|
||||||
|
WHITESPACE " "
|
||||||
|
AMP2 "&&"
|
||||||
|
WHITESPACE " "
|
||||||
|
LITERAL
|
||||||
|
TRUE_KW "true"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
WHILE_EXPR
|
||||||
|
WHILE_KW "while"
|
||||||
|
WHITESPACE " "
|
||||||
|
BIN_EXPR
|
||||||
|
BIN_EXPR
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "1"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ2 "=="
|
||||||
|
WHITESPACE " "
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "5"
|
||||||
|
WHITESPACE " "
|
||||||
|
AMP2 "&&"
|
||||||
|
WHITESPACE " "
|
||||||
|
PAREN_EXPR
|
||||||
|
L_PAREN "("
|
||||||
|
LET_EXPR
|
||||||
|
LET_KW "let"
|
||||||
|
WHITESPACE " "
|
||||||
|
IDENT_PAT
|
||||||
|
NAME
|
||||||
|
IDENT "None"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "None"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn foo() {
|
||||||
|
if let Some(_) = None && true {}
|
||||||
|
while 1 == 5 && (let None = None) {}
|
||||||
|
}
|
90
crates/parser/test_data/parser/inline/ok/0030_let_expr.txt
Normal file
90
crates/parser/test_data/parser/inline/ok/0030_let_expr.txt
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
SOURCE_FILE
|
||||||
|
FN
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "foo"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
EXPR_STMT
|
||||||
|
IF_EXPR
|
||||||
|
IF_KW "if"
|
||||||
|
WHITESPACE " "
|
||||||
|
BIN_EXPR
|
||||||
|
LET_EXPR
|
||||||
|
LET_KW "let"
|
||||||
|
WHITESPACE " "
|
||||||
|
TUPLE_STRUCT_PAT
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "Some"
|
||||||
|
L_PAREN "("
|
||||||
|
WILDCARD_PAT
|
||||||
|
UNDERSCORE "_"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "None"
|
||||||
|
WHITESPACE " "
|
||||||
|
AMP2 "&&"
|
||||||
|
WHITESPACE " "
|
||||||
|
LITERAL
|
||||||
|
TRUE_KW "true"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
WHILE_EXPR
|
||||||
|
WHILE_KW "while"
|
||||||
|
WHITESPACE " "
|
||||||
|
BIN_EXPR
|
||||||
|
BIN_EXPR
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "1"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ2 "=="
|
||||||
|
WHITESPACE " "
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "5"
|
||||||
|
WHITESPACE " "
|
||||||
|
AMP2 "&&"
|
||||||
|
WHITESPACE " "
|
||||||
|
PAREN_EXPR
|
||||||
|
L_PAREN "("
|
||||||
|
LET_EXPR
|
||||||
|
LET_KW "let"
|
||||||
|
WHITESPACE " "
|
||||||
|
IDENT_PAT
|
||||||
|
NAME
|
||||||
|
IDENT "None"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "None"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
|
@ -16,9 +16,8 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -30,7 +29,7 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LET_EXPR
|
||||||
LET_KW "let"
|
LET_KW "let"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
TUPLE_STRUCT_PAT
|
TUPLE_STRUCT_PAT
|
||||||
|
@ -69,15 +68,14 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BLOCK_EXPR
|
||||||
BLOCK_EXPR
|
STMT_LIST
|
||||||
STMT_LIST
|
L_CURLY "{"
|
||||||
L_CURLY "{"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
R_CURLY "}"
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -16,9 +16,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -30,9 +29,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -51,9 +49,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -65,9 +62,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
FALSE_KW "false"
|
||||||
FALSE_KW "false"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -86,12 +82,11 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "S"
|
||||||
IDENT "S"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -103,15 +98,14 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BLOCK_EXPR
|
||||||
BLOCK_EXPR
|
STMT_LIST
|
||||||
STMT_LIST
|
L_CURLY "{"
|
||||||
L_CURLY "{"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
R_CURLY "}"
|
||||||
R_CURLY "}"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -15,9 +15,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BREAK_EXPR
|
||||||
BREAK_EXPR
|
BREAK_KW "break"
|
||||||
BREAK_KW "break"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -28,9 +27,8 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BREAK_EXPR
|
||||||
BREAK_EXPR
|
BREAK_KW "break"
|
||||||
BREAK_KW "break"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -16,9 +16,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -50,9 +49,8 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -35,9 +35,8 @@ SOURCE_FILE
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -49,19 +49,20 @@ SOURCE_FILE
|
||||||
MATCH_GUARD
|
MATCH_GUARD
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
LET_KW "let"
|
LET_EXPR
|
||||||
WHITESPACE " "
|
LET_KW "let"
|
||||||
IDENT_PAT
|
WHITESPACE " "
|
||||||
NAME
|
IDENT_PAT
|
||||||
IDENT "foo"
|
NAME
|
||||||
WHITESPACE " "
|
IDENT "foo"
|
||||||
EQ "="
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
EQ "="
|
||||||
PATH_EXPR
|
WHITESPACE " "
|
||||||
PATH
|
PATH_EXPR
|
||||||
PATH_SEGMENT
|
PATH
|
||||||
NAME_REF
|
PATH_SEGMENT
|
||||||
IDENT "bar"
|
NAME_REF
|
||||||
|
IDENT "bar"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
FAT_ARROW "=>"
|
FAT_ARROW "=>"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
|
|
@ -51,16 +51,15 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
CALL_EXPR
|
||||||
CALL_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "condition_not_met"
|
||||||
IDENT "condition_not_met"
|
ARG_LIST
|
||||||
ARG_LIST
|
L_PAREN "("
|
||||||
L_PAREN "("
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -92,16 +91,15 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
CALL_EXPR
|
||||||
CALL_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "condition_not_met"
|
||||||
IDENT "condition_not_met"
|
ARG_LIST
|
||||||
ARG_LIST
|
L_PAREN "("
|
||||||
L_PAREN "("
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -153,16 +151,15 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
CALL_EXPR
|
||||||
CALL_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "foo"
|
||||||
IDENT "foo"
|
ARG_LIST
|
||||||
ARG_LIST
|
L_PAREN "("
|
||||||
L_PAREN "("
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -187,16 +184,15 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
CALL_EXPR
|
||||||
CALL_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "bar"
|
||||||
IDENT "bar"
|
ARG_LIST
|
||||||
ARG_LIST
|
L_PAREN "("
|
||||||
L_PAREN "("
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -280,21 +280,20 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PREFIX_EXPR
|
||||||
PREFIX_EXPR
|
BANG "!"
|
||||||
BANG "!"
|
METHOD_CALL_EXPR
|
||||||
METHOD_CALL_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "x"
|
||||||
IDENT "x"
|
DOT "."
|
||||||
DOT "."
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "get"
|
||||||
IDENT "get"
|
ARG_LIST
|
||||||
ARG_LIST
|
L_PAREN "("
|
||||||
L_PAREN "("
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -443,12 +442,11 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PAREN_EXPR
|
||||||
PAREN_EXPR
|
L_PAREN "("
|
||||||
L_PAREN "("
|
RETURN_EXPR
|
||||||
RETURN_EXPR
|
RETURN_KW "return"
|
||||||
RETURN_KW "return"
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -457,12 +455,11 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PAREN_EXPR
|
||||||
PAREN_EXPR
|
L_PAREN "("
|
||||||
L_PAREN "("
|
RETURN_EXPR
|
||||||
RETURN_EXPR
|
RETURN_KW "return"
|
||||||
RETURN_KW "return"
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -495,12 +492,11 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PAREN_EXPR
|
||||||
PAREN_EXPR
|
L_PAREN "("
|
||||||
L_PAREN "("
|
RETURN_EXPR
|
||||||
RETURN_EXPR
|
RETURN_KW "return"
|
||||||
RETURN_KW "return"
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -549,12 +545,11 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PAREN_EXPR
|
||||||
PAREN_EXPR
|
L_PAREN "("
|
||||||
L_PAREN "("
|
RETURN_EXPR
|
||||||
RETURN_EXPR
|
RETURN_KW "return"
|
||||||
RETURN_KW "return"
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -572,12 +567,11 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
PAREN_EXPR
|
||||||
PAREN_EXPR
|
L_PAREN "("
|
||||||
L_PAREN "("
|
RETURN_EXPR
|
||||||
RETURN_EXPR
|
RETURN_KW "return"
|
||||||
RETURN_KW "return"
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -1037,9 +1031,8 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BREAK_EXPR
|
||||||
BREAK_EXPR
|
BREAK_KW "break"
|
||||||
BREAK_KW "break"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -1089,18 +1082,17 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BIN_EXPR
|
||||||
BIN_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "i"
|
||||||
IDENT "i"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
EQ2 "=="
|
||||||
EQ2 "=="
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
LITERAL
|
||||||
LITERAL
|
INT_NUMBER "1"
|
||||||
INT_NUMBER "1"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
@ -1344,18 +1336,17 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BIN_EXPR
|
||||||
BIN_EXPR
|
PATH_EXPR
|
||||||
PATH_EXPR
|
PATH
|
||||||
PATH
|
PATH_SEGMENT
|
||||||
PATH_SEGMENT
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "u8"
|
||||||
IDENT "u8"
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
NEQ "!="
|
||||||
NEQ "!="
|
WHITESPACE " "
|
||||||
WHITESPACE " "
|
LITERAL
|
||||||
LITERAL
|
INT_NUMBER "0u8"
|
||||||
INT_NUMBER "0u8"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -219,7 +219,7 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LET_EXPR
|
||||||
LET_KW "let"
|
LET_KW "let"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
TUPLE_STRUCT_PAT
|
TUPLE_STRUCT_PAT
|
||||||
|
|
|
@ -15,47 +15,46 @@ SOURCE_FILE
|
||||||
IF_EXPR
|
IF_EXPR
|
||||||
IF_KW "if"
|
IF_KW "if"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
BIN_EXPR
|
||||||
BIN_EXPR
|
CAST_EXPR
|
||||||
CAST_EXPR
|
METHOD_CALL_EXPR
|
||||||
METHOD_CALL_EXPR
|
LITERAL
|
||||||
LITERAL
|
FLOAT_NUMBER "1.0f32"
|
||||||
FLOAT_NUMBER "1.0f32"
|
DOT "."
|
||||||
DOT "."
|
NAME_REF
|
||||||
NAME_REF
|
IDENT "floor"
|
||||||
IDENT "floor"
|
ARG_LIST
|
||||||
ARG_LIST
|
L_PAREN "("
|
||||||
L_PAREN "("
|
R_PAREN ")"
|
||||||
R_PAREN ")"
|
|
||||||
WHITESPACE " "
|
|
||||||
AS_KW "as"
|
|
||||||
WHITESPACE " "
|
|
||||||
PATH_TYPE
|
|
||||||
PATH
|
|
||||||
PATH_SEGMENT
|
|
||||||
NAME_REF
|
|
||||||
IDENT "i64"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
NEQ "!="
|
AS_KW "as"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CAST_EXPR
|
PATH_TYPE
|
||||||
METHOD_CALL_EXPR
|
PATH
|
||||||
LITERAL
|
PATH_SEGMENT
|
||||||
FLOAT_NUMBER "1.0f32"
|
NAME_REF
|
||||||
DOT "."
|
IDENT "i64"
|
||||||
NAME_REF
|
WHITESPACE " "
|
||||||
IDENT "floor"
|
NEQ "!="
|
||||||
ARG_LIST
|
WHITESPACE " "
|
||||||
L_PAREN "("
|
CAST_EXPR
|
||||||
R_PAREN ")"
|
METHOD_CALL_EXPR
|
||||||
WHITESPACE " "
|
LITERAL
|
||||||
AS_KW "as"
|
FLOAT_NUMBER "1.0f32"
|
||||||
WHITESPACE " "
|
DOT "."
|
||||||
PATH_TYPE
|
NAME_REF
|
||||||
PATH
|
IDENT "floor"
|
||||||
PATH_SEGMENT
|
ARG_LIST
|
||||||
NAME_REF
|
L_PAREN "("
|
||||||
IDENT "i64"
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
AS_KW "as"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "i64"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -86,9 +86,8 @@ SOURCE_FILE
|
||||||
WHILE_EXPR
|
WHILE_EXPR
|
||||||
WHILE_KW "while"
|
WHILE_KW "while"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
CONDITION
|
LITERAL
|
||||||
LITERAL
|
TRUE_KW "true"
|
||||||
TRUE_KW "true"
|
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
BLOCK_EXPR
|
BLOCK_EXPR
|
||||||
STMT_LIST
|
STMT_LIST
|
||||||
|
|
|
@ -30,7 +30,7 @@ rayon = "1"
|
||||||
expect-test = "1.2.0-pre.1"
|
expect-test = "1.2.0-pre.1"
|
||||||
proc-macro2 = "1.0.8"
|
proc-macro2 = "1.0.8"
|
||||||
quote = "1.0.2"
|
quote = "1.0.2"
|
||||||
ungrammar = "=1.14.9"
|
ungrammar = "=1.15.0"
|
||||||
|
|
||||||
test_utils = { path = "../test_utils" }
|
test_utils = { path = "../test_utils" }
|
||||||
sourcegen = { path = "../sourcegen" }
|
sourcegen = { path = "../sourcegen" }
|
||||||
|
|
|
@ -884,7 +884,7 @@ pub struct IfExpr {
|
||||||
impl ast::HasAttrs for IfExpr {}
|
impl ast::HasAttrs for IfExpr {}
|
||||||
impl IfExpr {
|
impl IfExpr {
|
||||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||||
pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
|
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
|
pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,7 +1038,7 @@ impl ast::HasAttrs for WhileExpr {}
|
||||||
impl ast::HasLoopBody for WhileExpr {}
|
impl ast::HasLoopBody for WhileExpr {}
|
||||||
impl WhileExpr {
|
impl WhileExpr {
|
||||||
pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
|
pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
|
||||||
pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
|
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -1051,6 +1051,18 @@ impl YieldExpr {
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct LetExpr {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl ast::HasAttrs for LetExpr {}
|
||||||
|
impl LetExpr {
|
||||||
|
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
||||||
|
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
||||||
|
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
||||||
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtList {
|
pub struct StmtList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -1106,17 +1118,6 @@ impl ArgList {
|
||||||
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Condition {
|
|
||||||
pub(crate) syntax: SyntaxNode,
|
|
||||||
}
|
|
||||||
impl Condition {
|
|
||||||
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
|
||||||
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
|
||||||
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct MatchArmList {
|
pub struct MatchArmList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -1147,10 +1148,7 @@ pub struct MatchGuard {
|
||||||
}
|
}
|
||||||
impl MatchGuard {
|
impl MatchGuard {
|
||||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||||
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
|
||||||
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -1524,6 +1522,7 @@ pub enum Expr {
|
||||||
TupleExpr(TupleExpr),
|
TupleExpr(TupleExpr),
|
||||||
WhileExpr(WhileExpr),
|
WhileExpr(WhileExpr),
|
||||||
YieldExpr(YieldExpr),
|
YieldExpr(YieldExpr),
|
||||||
|
LetExpr(LetExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -2664,6 +2663,17 @@ impl AstNode for YieldExpr {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for LetExpr {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for StmtList {
|
impl AstNode for StmtList {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -2719,17 +2729,6 @@ impl AstNode for ArgList {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
impl AstNode for Condition {
|
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == CONDITION }
|
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
|
||||||
if Self::can_cast(syntax.kind()) {
|
|
||||||
Some(Self { syntax })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
|
||||||
}
|
|
||||||
impl AstNode for MatchArmList {
|
impl AstNode for MatchArmList {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -3336,6 +3335,9 @@ impl From<WhileExpr> for Expr {
|
||||||
impl From<YieldExpr> for Expr {
|
impl From<YieldExpr> for Expr {
|
||||||
fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
|
fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
|
||||||
}
|
}
|
||||||
|
impl From<LetExpr> for Expr {
|
||||||
|
fn from(node: LetExpr) -> Expr { Expr::LetExpr(node) }
|
||||||
|
}
|
||||||
impl AstNode for Expr {
|
impl AstNode for Expr {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool {
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -3344,7 +3346,7 @@ impl AstNode for Expr {
|
||||||
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
|
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
|
||||||
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
|
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
|
||||||
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
|
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
|
||||||
| YIELD_EXPR => true,
|
| YIELD_EXPR | LET_EXPR => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3381,6 +3383,7 @@ impl AstNode for Expr {
|
||||||
TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
|
TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
|
||||||
WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
|
WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
|
||||||
YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
|
YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
|
||||||
|
LET_EXPR => Expr::LetExpr(LetExpr { syntax }),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
|
@ -3418,6 +3421,7 @@ impl AstNode for Expr {
|
||||||
Expr::TupleExpr(it) => &it.syntax,
|
Expr::TupleExpr(it) => &it.syntax,
|
||||||
Expr::WhileExpr(it) => &it.syntax,
|
Expr::WhileExpr(it) => &it.syntax,
|
||||||
Expr::YieldExpr(it) => &it.syntax,
|
Expr::YieldExpr(it) => &it.syntax,
|
||||||
|
Expr::LetExpr(it) => &it.syntax,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3883,6 +3887,7 @@ impl AstNode for AnyHasAttrs {
|
||||||
| TUPLE_EXPR
|
| TUPLE_EXPR
|
||||||
| WHILE_EXPR
|
| WHILE_EXPR
|
||||||
| YIELD_EXPR
|
| YIELD_EXPR
|
||||||
|
| LET_EXPR
|
||||||
| STMT_LIST
|
| STMT_LIST
|
||||||
| RECORD_EXPR_FIELD_LIST
|
| RECORD_EXPR_FIELD_LIST
|
||||||
| RECORD_EXPR_FIELD
|
| RECORD_EXPR_FIELD
|
||||||
|
@ -4537,6 +4542,11 @@ impl std::fmt::Display for YieldExpr {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for LetExpr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for StmtList {
|
impl std::fmt::Display for StmtList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
@ -4562,11 +4572,6 @@ impl std::fmt::Display for ArgList {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for Condition {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::fmt::Display for MatchArmList {
|
impl std::fmt::Display for MatchArmList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
|
|
@ -397,7 +397,7 @@ pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Ex
|
||||||
expr_from_text(&format!("match {} {}", expr, match_arm_list))
|
expr_from_text(&format!("match {} {}", expr, match_arm_list))
|
||||||
}
|
}
|
||||||
pub fn expr_if(
|
pub fn expr_if(
|
||||||
condition: ast::Condition,
|
condition: ast::Expr,
|
||||||
then_branch: ast::BlockExpr,
|
then_branch: ast::BlockExpr,
|
||||||
else_branch: Option<ast::ElseBranch>,
|
else_branch: Option<ast::ElseBranch>,
|
||||||
) -> ast::Expr {
|
) -> ast::Expr {
|
||||||
|
@ -456,14 +456,8 @@ pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
|
||||||
fn expr_from_text(text: &str) -> ast::Expr {
|
fn expr_from_text(text: &str) -> ast::Expr {
|
||||||
ast_from_text(&format!("const C: () = {};", text))
|
ast_from_text(&format!("const C: () = {};", text))
|
||||||
}
|
}
|
||||||
|
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
|
||||||
pub fn condition(expr: ast::Expr, pattern: Option<ast::Pat>) -> ast::Condition {
|
ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
|
||||||
match pattern {
|
|
||||||
None => ast_from_text(&format!("const _: () = while {} {{}};", expr)),
|
|
||||||
Some(pattern) => {
|
|
||||||
ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
|
pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
|
||||||
|
|
|
@ -528,12 +528,6 @@ impl ast::Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::Condition {
|
|
||||||
pub fn is_pattern_cond(&self) -> bool {
|
|
||||||
self.let_token().is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum FieldKind {
|
pub enum FieldKind {
|
||||||
Name(ast::NameRef),
|
Name(ast::NameRef),
|
||||||
|
|
|
@ -133,7 +133,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"CLOSURE_EXPR",
|
"CLOSURE_EXPR",
|
||||||
"IF_EXPR",
|
"IF_EXPR",
|
||||||
"WHILE_EXPR",
|
"WHILE_EXPR",
|
||||||
"CONDITION",
|
|
||||||
"LOOP_EXPR",
|
"LOOP_EXPR",
|
||||||
"FOR_EXPR",
|
"FOR_EXPR",
|
||||||
"CONTINUE_EXPR",
|
"CONTINUE_EXPR",
|
||||||
|
@ -143,6 +142,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"STMT_LIST",
|
"STMT_LIST",
|
||||||
"RETURN_EXPR",
|
"RETURN_EXPR",
|
||||||
"YIELD_EXPR",
|
"YIELD_EXPR",
|
||||||
|
"LET_EXPR",
|
||||||
"MATCH_EXPR",
|
"MATCH_EXPR",
|
||||||
"MATCH_ARM_LIST",
|
"MATCH_ARM_LIST",
|
||||||
"MATCH_ARM",
|
"MATCH_ARM",
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
|
||||||
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
|
ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
|
||||||
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
|
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
|
||||||
ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
|
ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
|
||||||
|
ast::LetExpr(it) => validate_let_expr(it, &mut errors),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,3 +344,33 @@ fn validate_const(const_: ast::Const, errors: &mut Vec<SyntaxError>) {
|
||||||
errors.push(SyntaxError::new("const globals cannot be mutable", mut_token.text_range()));
|
errors.push(SyntaxError::new("const globals cannot be mutable", mut_token.text_range()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_let_expr(let_: ast::LetExpr, errors: &mut Vec<SyntaxError>) {
|
||||||
|
let mut token = let_.syntax().clone();
|
||||||
|
loop {
|
||||||
|
token = match token.parent() {
|
||||||
|
Some(it) => it,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ast::ParenExpr::can_cast(token.kind()) {
|
||||||
|
continue;
|
||||||
|
} else if let Some(it) = ast::BinExpr::cast(token.clone()) {
|
||||||
|
if it.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if ast::IfExpr::can_cast(token.kind())
|
||||||
|
|| ast::WhileExpr::can_cast(token.kind())
|
||||||
|
|| ast::MatchGuard::can_cast(token.kind())
|
||||||
|
{
|
||||||
|
// It must be part of the condition since the expressions are inside a block.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errors.push(SyntaxError::new(
|
||||||
|
"`let` expressions are not supported here",
|
||||||
|
let_.syntax().text_range(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
|
@ -49,9 +49,8 @@ SOURCE_FILE@0..350
|
||||||
IF_EXPR@134..257
|
IF_EXPR@134..257
|
||||||
IF_KW@134..136 "if"
|
IF_KW@134..136 "if"
|
||||||
WHITESPACE@136..137 " "
|
WHITESPACE@136..137 " "
|
||||||
CONDITION@137..141
|
LITERAL@137..141
|
||||||
LITERAL@137..141
|
TRUE_KW@137..141 "true"
|
||||||
TRUE_KW@137..141 "true"
|
|
||||||
WHITESPACE@141..142 " "
|
WHITESPACE@141..142 " "
|
||||||
BLOCK_EXPR@142..257
|
BLOCK_EXPR@142..257
|
||||||
STMT_LIST@142..257
|
STMT_LIST@142..257
|
||||||
|
@ -94,9 +93,8 @@ SOURCE_FILE@0..350
|
||||||
WHILE_EXPR@262..347
|
WHILE_EXPR@262..347
|
||||||
WHILE_KW@262..267 "while"
|
WHILE_KW@262..267 "while"
|
||||||
WHITESPACE@267..268 " "
|
WHITESPACE@267..268 " "
|
||||||
CONDITION@268..272
|
LITERAL@268..272
|
||||||
LITERAL@268..272
|
TRUE_KW@268..272 "true"
|
||||||
TRUE_KW@268..272 "true"
|
|
||||||
WHITESPACE@272..273 " "
|
WHITESPACE@272..273 " "
|
||||||
BLOCK_EXPR@273..347
|
BLOCK_EXPR@273..347
|
||||||
STMT_LIST@273..347
|
STMT_LIST@273..347
|
||||||
|
|
216
crates/syntax/test_data/parser/validation/invalid_let_expr.rast
Normal file
216
crates/syntax/test_data/parser/validation/invalid_let_expr.rast
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
SOURCE_FILE@0..282
|
||||||
|
FN@0..281
|
||||||
|
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..281
|
||||||
|
STMT_LIST@9..281
|
||||||
|
L_CURLY@9..10 "{"
|
||||||
|
WHITESPACE@10..15 "\n "
|
||||||
|
CONST@15..42
|
||||||
|
CONST_KW@15..20 "const"
|
||||||
|
WHITESPACE@20..21 " "
|
||||||
|
UNDERSCORE@21..22 "_"
|
||||||
|
COLON@22..23 ":"
|
||||||
|
WHITESPACE@23..24 " "
|
||||||
|
TUPLE_TYPE@24..26
|
||||||
|
L_PAREN@24..25 "("
|
||||||
|
R_PAREN@25..26 ")"
|
||||||
|
WHITESPACE@26..27 " "
|
||||||
|
EQ@27..28 "="
|
||||||
|
WHITESPACE@28..29 " "
|
||||||
|
LET_EXPR@29..41
|
||||||
|
LET_KW@29..32 "let"
|
||||||
|
WHITESPACE@32..33 " "
|
||||||
|
WILDCARD_PAT@33..34
|
||||||
|
UNDERSCORE@33..34 "_"
|
||||||
|
WHITESPACE@34..35 " "
|
||||||
|
EQ@35..36 "="
|
||||||
|
WHITESPACE@36..37 " "
|
||||||
|
PATH_EXPR@37..41
|
||||||
|
PATH@37..41
|
||||||
|
PATH_SEGMENT@37..41
|
||||||
|
NAME_REF@37..41
|
||||||
|
IDENT@37..41 "None"
|
||||||
|
SEMICOLON@41..42 ";"
|
||||||
|
WHITESPACE@42..48 "\n\n "
|
||||||
|
LET_STMT@48..83
|
||||||
|
LET_KW@48..51 "let"
|
||||||
|
WHITESPACE@51..52 " "
|
||||||
|
WILDCARD_PAT@52..53
|
||||||
|
UNDERSCORE@52..53 "_"
|
||||||
|
WHITESPACE@53..54 " "
|
||||||
|
EQ@54..55 "="
|
||||||
|
WHITESPACE@55..56 " "
|
||||||
|
IF_EXPR@56..82
|
||||||
|
IF_KW@56..58 "if"
|
||||||
|
WHITESPACE@58..59 " "
|
||||||
|
LITERAL@59..63
|
||||||
|
TRUE_KW@59..63 "true"
|
||||||
|
WHITESPACE@63..64 " "
|
||||||
|
BLOCK_EXPR@64..82
|
||||||
|
STMT_LIST@64..82
|
||||||
|
L_CURLY@64..65 "{"
|
||||||
|
WHITESPACE@65..66 " "
|
||||||
|
PAREN_EXPR@66..80
|
||||||
|
L_PAREN@66..67 "("
|
||||||
|
LET_EXPR@67..79
|
||||||
|
LET_KW@67..70 "let"
|
||||||
|
WHITESPACE@70..71 " "
|
||||||
|
WILDCARD_PAT@71..72
|
||||||
|
UNDERSCORE@71..72 "_"
|
||||||
|
WHITESPACE@72..73 " "
|
||||||
|
EQ@73..74 "="
|
||||||
|
WHITESPACE@74..75 " "
|
||||||
|
PATH_EXPR@75..79
|
||||||
|
PATH@75..79
|
||||||
|
PATH_SEGMENT@75..79
|
||||||
|
NAME_REF@75..79
|
||||||
|
IDENT@75..79 "None"
|
||||||
|
R_PAREN@79..80 ")"
|
||||||
|
WHITESPACE@80..81 " "
|
||||||
|
R_CURLY@81..82 "}"
|
||||||
|
SEMICOLON@82..83 ";"
|
||||||
|
WHITESPACE@83..89 "\n\n "
|
||||||
|
IF_EXPR@89..279
|
||||||
|
IF_KW@89..91 "if"
|
||||||
|
WHITESPACE@91..92 " "
|
||||||
|
BIN_EXPR@92..114
|
||||||
|
LITERAL@92..96
|
||||||
|
TRUE_KW@92..96 "true"
|
||||||
|
WHITESPACE@96..97 " "
|
||||||
|
AMP2@97..99 "&&"
|
||||||
|
WHITESPACE@99..100 " "
|
||||||
|
PAREN_EXPR@100..114
|
||||||
|
L_PAREN@100..101 "("
|
||||||
|
LET_EXPR@101..113
|
||||||
|
LET_KW@101..104 "let"
|
||||||
|
WHITESPACE@104..105 " "
|
||||||
|
WILDCARD_PAT@105..106
|
||||||
|
UNDERSCORE@105..106 "_"
|
||||||
|
WHITESPACE@106..107 " "
|
||||||
|
EQ@107..108 "="
|
||||||
|
WHITESPACE@108..109 " "
|
||||||
|
PATH_EXPR@109..113
|
||||||
|
PATH@109..113
|
||||||
|
PATH_SEGMENT@109..113
|
||||||
|
NAME_REF@109..113
|
||||||
|
IDENT@109..113 "None"
|
||||||
|
R_PAREN@113..114 ")"
|
||||||
|
WHITESPACE@114..115 " "
|
||||||
|
BLOCK_EXPR@115..279
|
||||||
|
STMT_LIST@115..279
|
||||||
|
L_CURLY@115..116 "{"
|
||||||
|
WHITESPACE@116..125 "\n "
|
||||||
|
EXPR_STMT@125..140
|
||||||
|
PAREN_EXPR@125..139
|
||||||
|
L_PAREN@125..126 "("
|
||||||
|
LET_EXPR@126..138
|
||||||
|
LET_KW@126..129 "let"
|
||||||
|
WHITESPACE@129..130 " "
|
||||||
|
WILDCARD_PAT@130..131
|
||||||
|
UNDERSCORE@130..131 "_"
|
||||||
|
WHITESPACE@131..132 " "
|
||||||
|
EQ@132..133 "="
|
||||||
|
WHITESPACE@133..134 " "
|
||||||
|
PATH_EXPR@134..138
|
||||||
|
PATH@134..138
|
||||||
|
PATH_SEGMENT@134..138
|
||||||
|
NAME_REF@134..138
|
||||||
|
IDENT@134..138 "None"
|
||||||
|
R_PAREN@138..139 ")"
|
||||||
|
SEMICOLON@139..140 ";"
|
||||||
|
WHITESPACE@140..149 "\n "
|
||||||
|
WHILE_EXPR@149..273
|
||||||
|
WHILE_KW@149..154 "while"
|
||||||
|
WHITESPACE@154..155 " "
|
||||||
|
LET_EXPR@155..167
|
||||||
|
LET_KW@155..158 "let"
|
||||||
|
WHITESPACE@158..159 " "
|
||||||
|
WILDCARD_PAT@159..160
|
||||||
|
UNDERSCORE@159..160 "_"
|
||||||
|
WHITESPACE@160..161 " "
|
||||||
|
EQ@161..162 "="
|
||||||
|
WHITESPACE@162..163 " "
|
||||||
|
PATH_EXPR@163..167
|
||||||
|
PATH@163..167
|
||||||
|
PATH_SEGMENT@163..167
|
||||||
|
NAME_REF@163..167
|
||||||
|
IDENT@163..167 "None"
|
||||||
|
WHITESPACE@167..168 " "
|
||||||
|
BLOCK_EXPR@168..273
|
||||||
|
STMT_LIST@168..273
|
||||||
|
L_CURLY@168..169 "{"
|
||||||
|
WHITESPACE@169..182 "\n "
|
||||||
|
MATCH_EXPR@182..263
|
||||||
|
MATCH_KW@182..187 "match"
|
||||||
|
WHITESPACE@187..188 " "
|
||||||
|
PATH_EXPR@188..192
|
||||||
|
PATH@188..192
|
||||||
|
PATH_SEGMENT@188..192
|
||||||
|
NAME_REF@188..192
|
||||||
|
IDENT@188..192 "None"
|
||||||
|
WHITESPACE@192..193 " "
|
||||||
|
MATCH_ARM_LIST@193..263
|
||||||
|
L_CURLY@193..194 "{"
|
||||||
|
WHITESPACE@194..211 "\n "
|
||||||
|
MATCH_ARM@211..249
|
||||||
|
WILDCARD_PAT@211..212
|
||||||
|
UNDERSCORE@211..212 "_"
|
||||||
|
WHITESPACE@212..213 " "
|
||||||
|
MATCH_GUARD@213..228
|
||||||
|
IF_KW@213..215 "if"
|
||||||
|
WHITESPACE@215..216 " "
|
||||||
|
LET_EXPR@216..228
|
||||||
|
LET_KW@216..219 "let"
|
||||||
|
WHITESPACE@219..220 " "
|
||||||
|
WILDCARD_PAT@220..221
|
||||||
|
UNDERSCORE@220..221 "_"
|
||||||
|
WHITESPACE@221..222 " "
|
||||||
|
EQ@222..223 "="
|
||||||
|
WHITESPACE@223..224 " "
|
||||||
|
PATH_EXPR@224..228
|
||||||
|
PATH@224..228
|
||||||
|
PATH_SEGMENT@224..228
|
||||||
|
NAME_REF@224..228
|
||||||
|
IDENT@224..228 "None"
|
||||||
|
WHITESPACE@228..229 " "
|
||||||
|
FAT_ARROW@229..231 "=>"
|
||||||
|
WHITESPACE@231..232 " "
|
||||||
|
BLOCK_EXPR@232..249
|
||||||
|
STMT_LIST@232..249
|
||||||
|
L_CURLY@232..233 "{"
|
||||||
|
WHITESPACE@233..234 " "
|
||||||
|
LET_STMT@234..247
|
||||||
|
LET_KW@234..237 "let"
|
||||||
|
WHITESPACE@237..238 " "
|
||||||
|
WILDCARD_PAT@238..239
|
||||||
|
UNDERSCORE@238..239 "_"
|
||||||
|
WHITESPACE@239..240 " "
|
||||||
|
EQ@240..241 "="
|
||||||
|
WHITESPACE@241..242 " "
|
||||||
|
PATH_EXPR@242..246
|
||||||
|
PATH@242..246
|
||||||
|
PATH_SEGMENT@242..246
|
||||||
|
NAME_REF@242..246
|
||||||
|
IDENT@242..246 "None"
|
||||||
|
SEMICOLON@246..247 ";"
|
||||||
|
WHITESPACE@247..248 " "
|
||||||
|
R_CURLY@248..249 "}"
|
||||||
|
WHITESPACE@249..262 "\n "
|
||||||
|
R_CURLY@262..263 "}"
|
||||||
|
WHITESPACE@263..272 "\n "
|
||||||
|
R_CURLY@272..273 "}"
|
||||||
|
WHITESPACE@273..278 "\n "
|
||||||
|
R_CURLY@278..279 "}"
|
||||||
|
WHITESPACE@279..280 "\n"
|
||||||
|
R_CURLY@280..281 "}"
|
||||||
|
WHITESPACE@281..282 "\n"
|
||||||
|
error 29..41: `let` expressions are not supported here
|
||||||
|
error 67..79: `let` expressions are not supported here
|
||||||
|
error 126..138: `let` expressions are not supported here
|
|
@ -0,0 +1,14 @@
|
||||||
|
fn foo() {
|
||||||
|
const _: () = let _ = None;
|
||||||
|
|
||||||
|
let _ = if true { (let _ = None) };
|
||||||
|
|
||||||
|
if true && (let _ = None) {
|
||||||
|
(let _ = None);
|
||||||
|
while let _ = None {
|
||||||
|
match None {
|
||||||
|
_ if let _ = None => { let _ = None; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue