mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +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]]
|
||||
name = "ungrammar"
|
||||
version = "1.14.9"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66be59c2fd880e3d76d1a6cf6d34114008f1d8af2748d4ad9d39ea712f14fda9"
|
||||
checksum = "ed01567101450f7d600508e7680df6005ae4fe97119d79b0364cc5910ff39732"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
|
|
|
@ -28,7 +28,7 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
expr::{
|
||||
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
|
||||
MatchGuard, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
||||
Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
||||
},
|
||||
intern::Interned,
|
||||
item_scope::BuiltinShadowMode,
|
||||
|
@ -155,9 +155,6 @@ impl ExprCollector<'_> {
|
|||
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
|
||||
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 {
|
||||
self.alloc_expr_desugared(Expr::Missing)
|
||||
}
|
||||
|
@ -215,33 +212,15 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
});
|
||||
|
||||
let condition = match 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),
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
let condition = self.collect_expr_opt(e.condition());
|
||||
|
||||
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() {
|
||||
Some(ast::BlockModifier::Try(_)) => {
|
||||
let body = self.collect_block(e);
|
||||
|
@ -282,31 +261,7 @@ impl ExprCollector<'_> {
|
|||
let label = e.label().map(|label| self.collect_label(label));
|
||||
let body = self.collect_block_opt(e.loop_body());
|
||||
|
||||
let condition = match 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),
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
let condition = self.collect_expr_opt(e.condition());
|
||||
|
||||
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
||||
}
|
||||
|
@ -352,15 +307,9 @@ impl ExprCollector<'_> {
|
|||
self.check_cfg(&arm).map(|()| MatchArm {
|
||||
pat: self.collect_pat_opt(arm.pat()),
|
||||
expr: self.collect_expr_opt(arm.expr()),
|
||||
guard: arm.guard().map(|guard| match guard.pat() {
|
||||
Some(pat) => MatchGuard::IfLet {
|
||||
pat: self.collect_pat(pat),
|
||||
expr: self.collect_expr_opt(guard.expr()),
|
||||
},
|
||||
None => {
|
||||
MatchGuard::If { expr: self.collect_expr_opt(guard.expr()) }
|
||||
}
|
||||
}),
|
||||
guard: arm
|
||||
.guard()
|
||||
.map(|guard| self.collect_expr_opt(guard.condition())),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
|
|||
use crate::{
|
||||
body::Body,
|
||||
db::DefDatabase,
|
||||
expr::{Expr, ExprId, LabelId, MatchGuard, Pat, PatId, Statement},
|
||||
expr::{Expr, ExprId, LabelId, Pat, PatId, Statement},
|
||||
BlockId, DefWithBodyId,
|
||||
};
|
||||
|
||||
|
@ -53,9 +53,9 @@ impl ExprScopes {
|
|||
fn new(body: &Body) -> ExprScopes {
|
||||
let mut scopes =
|
||||
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);
|
||||
compute_expr_scopes(body.body_expr, body, &mut scopes, root);
|
||||
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
|
||||
scopes
|
||||
}
|
||||
|
||||
|
@ -151,32 +151,32 @@ fn compute_block_scopes(
|
|||
match stmt {
|
||||
Statement::Let { pat, initializer, else_branch, .. } => {
|
||||
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 {
|
||||
compute_expr_scopes(*expr, body, scopes, scope);
|
||||
compute_expr_scopes(*expr, body, scopes, &mut scope);
|
||||
}
|
||||
scope = scopes.new_scope(scope);
|
||||
scopes.add_bindings(body, scope, *pat);
|
||||
}
|
||||
Statement::Expr { expr, .. } => {
|
||||
compute_expr_scopes(*expr, body, scopes, scope);
|
||||
compute_expr_scopes(*expr, body, scopes, &mut scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 =
|
||||
|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] {
|
||||
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
|
||||
// via the block itself (important for blocks that only contain items, no expressions).
|
||||
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 } => {
|
||||
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);
|
||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||
}
|
||||
Expr::While { condition, body: body_expr, label } => {
|
||||
let scope = scopes.new_labeled_scope(scope, make_label(label));
|
||||
compute_expr_scopes(*condition, body, scopes, scope);
|
||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||
compute_expr_scopes(*condition, body, scopes, &mut scope);
|
||||
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||
}
|
||||
Expr::Loop { body: body_expr, label } => {
|
||||
let scope = scopes.new_labeled_scope(scope, make_label(label));
|
||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||
}
|
||||
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);
|
||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
|
||||
}
|
||||
Expr::Match { expr, arms } => {
|
||||
compute_expr_scopes(*expr, body, scopes, scope);
|
||||
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);
|
||||
match arm.guard {
|
||||
Some(MatchGuard::If { expr: guard }) => {
|
||||
scopes.set_scope(guard, scope);
|
||||
compute_expr_scopes(guard, body, scopes, 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);
|
||||
if let Some(guard) = arm.guard {
|
||||
scope = scopes.new_scope(scope);
|
||||
compute_expr_scopes(guard, body, scopes, &mut scope);
|
||||
}
|
||||
compute_expr_scopes(arm.expr, body, scopes, &mut 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)),
|
||||
};
|
||||
}
|
||||
|
@ -500,8 +503,7 @@ fn foo() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn while_let_desugaring() {
|
||||
cov_mark::check!(infer_resolve_while_let);
|
||||
fn while_let_adds_binding() {
|
||||
do_check_local_name(
|
||||
r#"
|
||||
fn test() {
|
||||
|
@ -513,5 +515,53 @@ fn test() {
|
|||
"#,
|
||||
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,
|
||||
else_branch: Option<ExprId>,
|
||||
},
|
||||
Let {
|
||||
pat: PatId,
|
||||
expr: ExprId,
|
||||
},
|
||||
Block {
|
||||
id: BlockId,
|
||||
statements: Box<[Statement]>,
|
||||
|
@ -189,17 +193,10 @@ pub enum Array {
|
|||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct MatchArm {
|
||||
pub pat: PatId,
|
||||
pub guard: Option<MatchGuard>,
|
||||
pub guard: Option<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)]
|
||||
pub struct RecordLitField {
|
||||
pub name: Name,
|
||||
|
@ -232,6 +229,9 @@ impl Expr {
|
|||
f(else_branch);
|
||||
}
|
||||
}
|
||||
Expr::Let { expr, .. } => {
|
||||
f(*expr);
|
||||
}
|
||||
Expr::Block { statements, tail, .. } => {
|
||||
for stmt in statements.iter() {
|
||||
match stmt {
|
||||
|
|
|
@ -108,18 +108,18 @@ fn expansion_does_not_parse_as_expression() {
|
|||
check(
|
||||
r#"
|
||||
macro_rules! stmts {
|
||||
() => { let _ = 0; }
|
||||
() => { fn foo() {} }
|
||||
}
|
||||
|
||||
fn f() { let _ = stmts!/*+errors*/(); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! stmts {
|
||||
() => { let _ = 0; }
|
||||
() => { fn foo() {} }
|
||||
}
|
||||
|
||||
fn f() { let _ = /* parse error: expected expression */
|
||||
let _ = 0;; }
|
||||
fn foo() {}; }
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -811,10 +811,10 @@ impl ExpandTo {
|
|||
MACRO_TYPE => ExpandTo::Type,
|
||||
|
||||
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
|
||||
| MATCH_GUARD | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR
|
||||
| FIELD_EXPR | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR
|
||||
| BIN_EXPR => ExpandTo::Expr,
|
||||
| CLOSURE_EXPR | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM | MATCH_GUARD
|
||||
| RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR
|
||||
| AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR
|
||||
| LET_EXPR => ExpandTo::Expr,
|
||||
LET_STMT => {
|
||||
// FIXME: Handle LHS Pattern
|
||||
ExpandTo::Expr
|
||||
|
|
|
@ -8,10 +8,7 @@ use std::{
|
|||
|
||||
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
||||
use hir_def::{
|
||||
expr::{
|
||||
ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, MatchGuard, Ordering, Statement,
|
||||
UnaryOp,
|
||||
},
|
||||
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
|
||||
path::{GenericArg, GenericArgs},
|
||||
resolver::resolver_for_expr,
|
||||
FieldId, FunctionId, ItemContainerId, Lookup,
|
||||
|
@ -158,6 +155,11 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
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: _ } => {
|
||||
let old_resolver = mem::replace(
|
||||
&mut self.resolver,
|
||||
|
@ -378,20 +380,11 @@ impl<'a> InferenceContext<'a> {
|
|||
for arm in arms.iter() {
|
||||
self.diverges = Diverges::Maybe;
|
||||
let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
|
||||
match arm.guard {
|
||||
Some(MatchGuard::If { expr: guard_expr }) => {
|
||||
self.infer_expr(
|
||||
guard_expr,
|
||||
&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());
|
||||
}
|
||||
_ => {}
|
||||
if let Some(guard_expr) = arm.guard {
|
||||
self.infer_expr(
|
||||
guard_expr,
|
||||
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
39..442 '{ ...!(); }': ()
|
||||
73..94 'spam!(...am!())': {unknown}
|
||||
100..119 'for _ ...!() {}': ()
|
||||
|
@ -198,6 +197,7 @@ fn expr_macro_def_expanded_in_various_places() {
|
|||
117..119 '{}': ()
|
||||
124..134 '|| spam!()': || -> isize
|
||||
140..156 'while ...!() {}': ()
|
||||
146..153 'spam!()': bool
|
||||
154..156 '{}': ()
|
||||
161..174 'break 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
|
||||
53..456 '{ ...!(); }': ()
|
||||
87..108 'spam!(...am!())': {unknown}
|
||||
114..133 'for _ ...!() {}': ()
|
||||
|
@ -279,6 +278,7 @@ fn expr_macro_rules_expanded_in_various_places() {
|
|||
131..133 '{}': ()
|
||||
138..148 '|| spam!()': || -> isize
|
||||
154..170 'while ...!() {}': ()
|
||||
160..167 'spam!()': bool
|
||||
168..170 '{}': ()
|
||||
175..188 'break spam!()': !
|
||||
194..208 'return spam!()': !
|
||||
|
|
|
@ -55,6 +55,7 @@ fn infer_pattern() {
|
|||
139..140 'g': {unknown}
|
||||
143..144 'e': {unknown}
|
||||
157..204 'if let... }': ()
|
||||
160..175 'let [val] = opt': bool
|
||||
164..169 '[val]': [{unknown}]
|
||||
165..168 'val': {unknown}
|
||||
172..175 'opt': [{unknown}]
|
||||
|
@ -62,6 +63,7 @@ fn infer_pattern() {
|
|||
190..191 'h': {unknown}
|
||||
194..197 'val': {unknown}
|
||||
210..236 'if let...rue {}': ()
|
||||
213..233 'let x ... &true': bool
|
||||
217..225 'x @ true': &bool
|
||||
221..225 'true': bool
|
||||
221..225 'true': bool
|
||||
|
@ -111,36 +113,42 @@ fn infer_literal_pattern() {
|
|||
37..38 'x': &i32
|
||||
46..208 '{ ...) {} }': ()
|
||||
52..75 'if let...y() {}': ()
|
||||
55..72 'let "f... any()': bool
|
||||
59..64 '"foo"': &str
|
||||
59..64 '"foo"': &str
|
||||
67..70 'any': fn any<&str>() -> &str
|
||||
67..72 'any()': &str
|
||||
73..75 '{}': ()
|
||||
80..99 'if let...y() {}': ()
|
||||
83..96 'let 1 = any()': bool
|
||||
87..88 '1': i32
|
||||
87..88 '1': i32
|
||||
91..94 'any': fn any<i32>() -> i32
|
||||
91..96 'any()': i32
|
||||
97..99 '{}': ()
|
||||
104..126 'if let...y() {}': ()
|
||||
107..123 'let 1u... any()': bool
|
||||
111..115 '1u32': u32
|
||||
111..115 '1u32': u32
|
||||
118..121 'any': fn any<u32>() -> u32
|
||||
118..123 'any()': u32
|
||||
124..126 '{}': ()
|
||||
131..153 'if let...y() {}': ()
|
||||
134..150 'let 1f... any()': bool
|
||||
138..142 '1f32': f32
|
||||
138..142 '1f32': f32
|
||||
145..148 'any': fn any<f32>() -> f32
|
||||
145..150 'any()': f32
|
||||
151..153 '{}': ()
|
||||
158..179 'if let...y() {}': ()
|
||||
161..176 'let 1.0 = any()': bool
|
||||
165..168 '1.0': f64
|
||||
165..168 '1.0': f64
|
||||
171..174 'any': fn any<f64>() -> f64
|
||||
171..176 'any()': f64
|
||||
177..179 '{}': ()
|
||||
184..206 'if let...y() {}': ()
|
||||
187..203 'let tr... any()': bool
|
||||
191..195 'true': bool
|
||||
191..195 'true': bool
|
||||
198..201 'any': fn any<bool>() -> bool
|
||||
|
@ -163,10 +171,12 @@ fn infer_range_pattern() {
|
|||
8..9 'x': &i32
|
||||
17..75 '{ ...2 {} }': ()
|
||||
23..45 'if let...u32 {}': ()
|
||||
26..42 'let 1....= 2u32': bool
|
||||
30..35 '1..76': u32
|
||||
38..42 '2u32': u32
|
||||
43..45 '{}': ()
|
||||
50..73 'if let...u32 {}': ()
|
||||
53..70 'let 1....= 2u32': bool
|
||||
57..63 '1..=76': u32
|
||||
66..70 '2u32': u32
|
||||
71..73 '{}': ()
|
||||
|
|
|
@ -2248,6 +2248,7 @@ fn generic_default_in_struct_literal() {
|
|||
176..193 'Thing ...1i32 }': Thing<i32>
|
||||
187..191 '1i32': i32
|
||||
199..240 'if let... }': ()
|
||||
202..221 'let Th... } = z': bool
|
||||
206..217 'Thing { t }': Thing<i32>
|
||||
214..215 't': i32
|
||||
220..221 'z': Thing<i32>
|
||||
|
|
|
@ -18,7 +18,7 @@ use syntax::{
|
|||
algo, ast,
|
||||
display::{fn_as_proc_macro_label, macro_label},
|
||||
match_ast, AstNode, Direction,
|
||||
SyntaxKind::{CONDITION, LET_STMT},
|
||||
SyntaxKind::{LET_EXPR, LET_STMT},
|
||||
SyntaxToken, T,
|
||||
};
|
||||
|
||||
|
@ -484,7 +484,7 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
|
|||
let let_kw = if ident
|
||||
.syntax()
|
||||
.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 "
|
||||
} else {
|
||||
|
|
|
@ -243,7 +243,7 @@ fn is_named_constructor(
|
|||
let expr = match_ast! {
|
||||
match let_node {
|
||||
ast::LetStmt(it) => it.initializer(),
|
||||
ast::Condition(it) => it.expr(),
|
||||
ast::LetExpr(it) => it.expr(),
|
||||
_ => None,
|
||||
}
|
||||
}?;
|
||||
|
@ -372,15 +372,10 @@ fn should_not_display_type_hint(
|
|||
match node {
|
||||
ast::LetStmt(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::IfExpr(it) => {
|
||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
||||
},
|
||||
ast::WhileExpr(it) => {
|
||||
return it.condition().and_then(|condition| condition.pat()).is_some()
|
||||
&& pat_is_enum_variant(db, bind_pat, pat_ty);
|
||||
},
|
||||
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||
ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||
ast::IfExpr(_) => return false,
|
||||
ast::WhileExpr(_) => return false,
|
||||
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).
|
||||
// Type of expr should be iterable.
|
||||
|
|
|
@ -2,7 +2,7 @@ use hir::{known, AsAssocItem, Semantics};
|
|||
use ide_db::{
|
||||
helpers::{
|
||||
for_each_tail_expr,
|
||||
node_ext::{block_as_lone_tail, preorder_expr},
|
||||
node_ext::{block_as_lone_tail, is_pattern_cond, preorder_expr},
|
||||
FamousDefs,
|
||||
},
|
||||
RootDatabase,
|
||||
|
@ -45,8 +45,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext) ->
|
|||
return None;
|
||||
}
|
||||
|
||||
let cond = expr.condition().filter(|cond| !cond.is_pattern_cond())?;
|
||||
let cond = cond.expr()?;
|
||||
let cond = expr.condition().filter(|cond| !is_pattern_cond(cond.clone()))?;
|
||||
let then = expr.then_branch()?;
|
||||
let else_ = match expr.else_branch()? {
|
||||
ast::ElseBranch::Block(b) => b,
|
||||
|
@ -209,7 +208,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext) ->
|
|||
_ => receiver,
|
||||
};
|
||||
let if_expr = make::expr_if(
|
||||
make::condition(cond, None),
|
||||
cond,
|
||||
closure_body.reset_indent(),
|
||||
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
|
||||
)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter::once;
|
||||
|
||||
use ide_db::helpers::node_ext::{is_pattern_cond, single_let};
|
||||
use syntax::{
|
||||
ast::{
|
||||
self,
|
||||
|
@ -48,25 +49,28 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
|||
let cond = if_expr.condition()?;
|
||||
|
||||
// Check if there is an IfLet that we can handle.
|
||||
let if_let_pat = match cond.pat() {
|
||||
None => None, // No IfLet, supported.
|
||||
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
|
||||
let path = pat.path()?;
|
||||
if path.qualifier().is_some() {
|
||||
return None;
|
||||
}
|
||||
let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) {
|
||||
let let_ = single_let(cond)?;
|
||||
match let_.pat() {
|
||||
Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
|
||||
let path = pat.path()?;
|
||||
if path.qualifier().is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bound_ident = pat.fields().next().unwrap();
|
||||
if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
|
||||
return None;
|
||||
}
|
||||
let bound_ident = pat.fields().next().unwrap();
|
||||
if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
|
||||
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 = then_block.stmt_list()?;
|
||||
|
||||
|
@ -119,8 +123,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
|
|||
let then_branch =
|
||||
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
||||
let cond = invert_boolean_expression(cond_expr);
|
||||
make::expr_if(make::condition(cond, None), then_branch, None)
|
||||
.indent(if_indent_level)
|
||||
make::expr_if(cond, then_branch, None).indent(if_indent_level)
|
||||
};
|
||||
new_expr.syntax().clone_for_update()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter::once;
|
||||
|
||||
use ide_db::helpers::node_ext::is_pattern_cond;
|
||||
use syntax::{
|
||||
ast::{
|
||||
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_body = while_expr.loop_body()?;
|
||||
let while_cond = while_expr.condition()?;
|
||||
let while_cond_expr = while_cond.expr()?;
|
||||
|
||||
let target = while_expr.syntax().text_range();
|
||||
acc.add(
|
||||
|
@ -55,19 +55,15 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> O
|
|||
let break_block =
|
||||
make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
|
||||
.indent(while_indent_level);
|
||||
let block_expr = match while_cond.pat() {
|
||||
Some(_) => {
|
||||
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
||||
let stmts = once(make::expr_stmt(if_expr).into());
|
||||
make::block_expr(stmts, None)
|
||||
}
|
||||
None => {
|
||||
let if_cond = make::condition(invert_boolean_expression(while_cond_expr), None);
|
||||
let if_expr = make::expr_if(if_cond, break_block, None);
|
||||
let stmts =
|
||||
once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
|
||||
make::block_expr(stmts, while_body.tail_expr())
|
||||
}
|
||||
let block_expr = if is_pattern_cond(while_cond.clone()) {
|
||||
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
||||
let stmts = once(make::expr_stmt(if_expr).into());
|
||||
make::block_expr(stmts, None)
|
||||
} else {
|
||||
let if_cond = invert_boolean_expression(while_cond);
|
||||
let if_expr = make::expr_if(if_cond, break_block, None);
|
||||
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));
|
||||
|
|
|
@ -1219,28 +1219,26 @@ impl FlowHandler {
|
|||
let stmt = make::expr_stmt(action);
|
||||
let block = make::block_expr(iter::once(stmt.into()), None);
|
||||
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,
|
||||
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 } => {
|
||||
let path = make::ext::ident_path("Some");
|
||||
let value_pat = make::ext::simple_ident_pat(make::name("value"));
|
||||
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 action_expr = action.make_result_handler(Some(value));
|
||||
let action_stmt = make::expr_stmt(action_expr);
|
||||
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 } => {
|
||||
let some_name = "value";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use ide_db::helpers::node_ext::is_pattern_cond;
|
||||
use syntax::{
|
||||
ast::{self, AstNode},
|
||||
T,
|
||||
|
@ -34,12 +35,12 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let cond = expr.condition()?;
|
||||
// This assist should not apply for if-let.
|
||||
if expr.condition()?.is_pattern_cond() {
|
||||
if is_pattern_cond(cond.clone()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let cond = expr.condition()?.expr()?;
|
||||
let then_node = expr.then_branch()?.syntax().clone();
|
||||
let else_block = match expr.else_branch()? {
|
||||
ast::ElseBranch::Block(it) => it,
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
use syntax::{
|
||||
ast::{
|
||||
edit::AstNodeEdit, make, AstNode, BlockExpr, Condition, ElseBranch, Expr, IfExpr, MatchArm,
|
||||
Pat,
|
||||
},
|
||||
ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat},
|
||||
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();
|
||||
|
||||
// FIXME: support `if let` guards too
|
||||
if guard.let_token().is_some() {
|
||||
return None;
|
||||
}
|
||||
let guard_condition = guard.expr()?;
|
||||
let guard_condition = guard.condition()?;
|
||||
let arm_expr = match_arm.expr()?;
|
||||
let if_expr = make::expr_if(
|
||||
make::condition(guard_condition, None),
|
||||
make::block_expr(None, Some(arm_expr.clone())),
|
||||
None,
|
||||
)
|
||||
.indent(arm_expr.indent_level());
|
||||
let if_expr =
|
||||
make::expr_if(guard_condition, make::block_expr(None, Some(arm_expr.clone())), None)
|
||||
.indent(arm_expr.indent_level());
|
||||
|
||||
let target = guard.syntax().text_range();
|
||||
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.
|
||||
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 curr_if = if_expr;
|
||||
let tail = loop {
|
||||
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()?));
|
||||
match curr_if.else_branch() {
|
||||
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]
|
||||
fn move_guard_to_arm_body_works_complex_match() {
|
||||
check_assist(
|
||||
|
@ -440,13 +451,21 @@ fn main() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn move_arm_cond_to_match_guard_if_let_not_works() {
|
||||
check_assist_not_applicable(
|
||||
fn move_arm_cond_to_match_guard_if_let_works() {
|
||||
check_assist(
|
||||
move_arm_cond_to_match_guard,
|
||||
r#"
|
||||
fn main() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -898,7 +917,7 @@ fn main() {
|
|||
|
||||
#[test]
|
||||
fn move_arm_cond_to_match_guard_elseif_iflet() {
|
||||
check_assist_not_applicable(
|
||||
check_assist(
|
||||
move_arm_cond_to_match_guard,
|
||||
r#"
|
||||
fn main() {
|
||||
|
@ -915,9 +934,21 @@ fn main() {
|
|||
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]
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use std::iter::{self, successors};
|
||||
|
||||
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::{
|
||||
ast::{
|
||||
self,
|
||||
|
@ -60,15 +65,22 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
|
|||
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 cond_bodies = Vec::new();
|
||||
for if_expr in if_exprs {
|
||||
let cond = if_expr.condition()?;
|
||||
let expr = cond.expr()?;
|
||||
let cond = match cond.pat() {
|
||||
Some(pat) => {
|
||||
let cond = match single_let(cond.clone()) {
|
||||
Some(let_) => {
|
||||
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() {
|
||||
// Only if all condition expressions are equal we can merge them into a match
|
||||
return None;
|
||||
|
@ -76,7 +88,9 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
|
|||
pat_seen = true;
|
||||
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()?;
|
||||
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 else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
||||
let if_let_expr = make::expr_if(
|
||||
condition,
|
||||
condition.into(),
|
||||
then_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]
|
||||
fn test_if_let_with_match_basic() {
|
||||
check_assist(
|
||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
|
|||
|
||||
let block =
|
||||
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_);
|
||||
|
||||
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
||||
|
|
|
@ -575,6 +575,14 @@ impl<'a> CompletionContext<'a> {
|
|||
|
||||
(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(_) => {
|
||||
cov_mark::hit!(expected_type_fn_param);
|
||||
ActiveParameter::at_token(
|
||||
|
@ -641,9 +649,7 @@ impl<'a> CompletionContext<'a> {
|
|||
(ty, None)
|
||||
},
|
||||
ast::IfExpr(it) => {
|
||||
cov_mark::hit!(expected_type_if_let_without_leading_char);
|
||||
let ty = it.condition()
|
||||
.and_then(|cond| cond.expr())
|
||||
.and_then(|e| self.sema.type_of_expr(&e))
|
||||
.map(TypeInfo::original);
|
||||
(ty, None)
|
||||
|
@ -939,7 +945,7 @@ fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternCont
|
|||
return (PatternRefutability::Irrefutable, has_type_ascription)
|
||||
},
|
||||
ast::MatchArm(_) => PatternRefutability::Refutable,
|
||||
ast::Condition(_) => PatternRefutability::Refutable,
|
||||
ast::LetExpr(_) => PatternRefutability::Refutable,
|
||||
ast::ForExpr(_) => 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::TupleExpr(_)
|
||||
| ast::Expr::WhileExpr(_)
|
||||
| ast::Expr::LetExpr(_)
|
||||
| ast::Expr::YieldExpr(_) => cb(expr),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,3 +216,29 @@ pub fn vis_eq(this: &ast::Visibility, other: &ast::Visibility) -> bool {
|
|||
_ => 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);
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
if p.eat(T![;]) {
|
||||
return;
|
||||
|
@ -185,6 +194,7 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
|
|||
T![%] if p.at(T![%=]) => (1, T![%=]),
|
||||
T![%] => (11, 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![&] => (8, 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)
|
||||
}
|
||||
T![if] => if_expr(p),
|
||||
T![let] => let_expr(p),
|
||||
|
||||
T![loop] => loop_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]));
|
||||
let m = p.start();
|
||||
p.bump(T![if]);
|
||||
condition(p);
|
||||
expr_no_struct(p);
|
||||
block_expr(p);
|
||||
if p.at(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]));
|
||||
let m = m.unwrap_or_else(|| p.start());
|
||||
p.bump(T![while]);
|
||||
condition(p);
|
||||
expr_no_struct(p);
|
||||
block_expr(p);
|
||||
m.complete(p, WHILE_EXPR)
|
||||
}
|
||||
|
@ -355,22 +356,18 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
|||
m.complete(p, FOR_EXPR)
|
||||
}
|
||||
|
||||
// test cond
|
||||
// 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 {}
|
||||
// test let_expr
|
||||
// fn foo() {
|
||||
// if let Some(_) = None && true {}
|
||||
// while 1 == 5 && (let None = None) {}
|
||||
// }
|
||||
fn condition(p: &mut Parser) {
|
||||
fn let_expr(p: &mut Parser) -> CompletedMarker {
|
||||
let m = p.start();
|
||||
if p.eat(T![let]) {
|
||||
patterns::pattern_top(p);
|
||||
p.expect(T![=]);
|
||||
}
|
||||
expr_no_struct(p);
|
||||
m.complete(p, CONDITION);
|
||||
p.bump(T![let]);
|
||||
patterns::pattern_top(p);
|
||||
p.expect(T![=]);
|
||||
expr_let(p);
|
||||
m.complete(p, LET_EXPR)
|
||||
}
|
||||
|
||||
// test match_expr
|
||||
|
@ -482,10 +479,6 @@ fn match_guard(p: &mut Parser) -> CompletedMarker {
|
|||
assert!(p.at(T![if]));
|
||||
let m = p.start();
|
||||
p.bump(T![if]);
|
||||
if p.eat(T![let]) {
|
||||
patterns::pattern_top(p);
|
||||
p.expect(T![=]);
|
||||
}
|
||||
expr(p);
|
||||
m.complete(p, MATCH_GUARD)
|
||||
}
|
||||
|
|
|
@ -178,7 +178,6 @@ pub enum SyntaxKind {
|
|||
CLOSURE_EXPR,
|
||||
IF_EXPR,
|
||||
WHILE_EXPR,
|
||||
CONDITION,
|
||||
LOOP_EXPR,
|
||||
FOR_EXPR,
|
||||
CONTINUE_EXPR,
|
||||
|
@ -188,6 +187,7 @@ pub enum SyntaxKind {
|
|||
STMT_LIST,
|
||||
RETURN_EXPR,
|
||||
YIELD_EXPR,
|
||||
LET_EXPR,
|
||||
MATCH_EXPR,
|
||||
MATCH_ARM_LIST,
|
||||
MATCH_ARM,
|
||||
|
|
|
@ -289,17 +289,19 @@ fn expr() {
|
|||
TopEntryPoint::Expr,
|
||||
"let _ = 0;",
|
||||
expect![[r#"
|
||||
ERROR
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
UNDERSCORE "_"
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
INT_NUMBER "0"
|
||||
SEMICOLON ";"
|
||||
error 0: expected expression
|
||||
"#]],
|
||||
ERROR
|
||||
LET_EXPR
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
WILDCARD_PAT
|
||||
UNDERSCORE "_"
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
INT_NUMBER "0"
|
||||
SEMICOLON ";"
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fn foo() {
|
||||
let foo =
|
||||
let foo = 11
|
||||
let bar = 1;
|
||||
let
|
||||
let baz = 92;
|
||||
|
|
|
@ -20,6 +20,9 @@ SOURCE_FILE
|
|||
IDENT "foo"
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
INT_NUMBER "11"
|
||||
WHITESPACE "\n "
|
||||
LET_STMT
|
||||
LET_KW "let"
|
||||
|
@ -57,9 +60,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -73,9 +75,8 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -95,13 +96,12 @@ SOURCE_FILE
|
|||
WHITESPACE "\n"
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
error 24: expected expression
|
||||
error 24: expected SEMICOLON
|
||||
error 49: expected pattern
|
||||
error 49: expected SEMICOLON
|
||||
error 75: expected pattern
|
||||
error 75: expected SEMICOLON
|
||||
error 98: expected pattern
|
||||
error 98: expected SEMICOLON
|
||||
error 124: expected pattern
|
||||
error 124: expected SEMICOLON
|
||||
error 27: expected SEMICOLON
|
||||
error 52: expected pattern
|
||||
error 52: expected SEMICOLON
|
||||
error 78: expected pattern
|
||||
error 78: expected SEMICOLON
|
||||
error 101: expected pattern
|
||||
error 101: expected SEMICOLON
|
||||
error 127: expected pattern
|
||||
error 127: expected SEMICOLON
|
||||
|
|
|
@ -180,116 +180,118 @@ SOURCE_FILE
|
|||
ERROR
|
||||
PLUS "+"
|
||||
WHITESPACE " "
|
||||
EXPR_STMT
|
||||
TUPLE_EXPR
|
||||
L_PAREN "("
|
||||
FOR_EXPR
|
||||
FOR_KW "for"
|
||||
PATH_PAT
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
L_ANGLE "<"
|
||||
ERROR
|
||||
LIFETIME_IDENT "'a"
|
||||
R_ANGLE ">"
|
||||
WHITESPACE " "
|
||||
TUPLE_EXPR
|
||||
L_PAREN "("
|
||||
FOR_EXPR
|
||||
FOR_KW "for"
|
||||
PATH_PAT
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
L_ANGLE "<"
|
||||
ERROR
|
||||
LIFETIME_IDENT "'a"
|
||||
R_ANGLE ">"
|
||||
WHITESPACE " "
|
||||
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
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Copy"
|
||||
IDENT "Trait"
|
||||
L_ANGLE "<"
|
||||
ERROR
|
||||
LIFETIME_IDENT "'a"
|
||||
R_ANGLE ">"
|
||||
ERROR
|
||||
R_PAREN ")"
|
||||
R_ANGLE ">"
|
||||
ERROR
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n "
|
||||
LET_STMT
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
PLUS "+"
|
||||
WHITESPACE " "
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
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 " "
|
||||
WILDCARD_PAT
|
||||
UNDERSCORE "_"
|
||||
COLON ":"
|
||||
WHITESPACE " "
|
||||
DYN_TRAIT_TYPE
|
||||
TYPE_BOUND_LIST
|
||||
TYPE_BOUND
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Box"
|
||||
GENERIC_ARG_LIST
|
||||
BIN_EXPR
|
||||
BIN_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Box"
|
||||
L_ANGLE "<"
|
||||
TUPLE_EXPR
|
||||
L_PAREN "("
|
||||
FOR_EXPR
|
||||
FOR_KW "for"
|
||||
PATH_PAT
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
L_ANGLE "<"
|
||||
TYPE_ARG
|
||||
PAREN_TYPE
|
||||
L_PAREN "("
|
||||
FOR_TYPE
|
||||
FOR_KW "for"
|
||||
GENERIC_PARAM_LIST
|
||||
L_ANGLE "<"
|
||||
LIFETIME_PARAM
|
||||
LIFETIME
|
||||
LIFETIME_IDENT "'a"
|
||||
R_ANGLE ">"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Trait"
|
||||
GENERIC_ARG_LIST
|
||||
L_ANGLE "<"
|
||||
LIFETIME_ARG
|
||||
LIFETIME
|
||||
LIFETIME_IDENT "'a"
|
||||
R_ANGLE ">"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
PLUS "+"
|
||||
WHITESPACE " "
|
||||
TYPE_BOUND
|
||||
L_PAREN "("
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Copy"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
PLUS "+"
|
||||
WHITESPACE " "
|
||||
TYPE_BOUND
|
||||
L_PAREN "("
|
||||
QUESTION "?"
|
||||
PATH_TYPE
|
||||
ERROR
|
||||
LIFETIME_IDENT "'a"
|
||||
R_ANGLE ">"
|
||||
WHITESPACE " "
|
||||
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
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Copy"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
PLUS "+"
|
||||
WHITESPACE " "
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
ERROR
|
||||
QUESTION "?"
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "Sized"
|
||||
R_PAREN ")"
|
||||
ERROR
|
||||
R_ANGLE ">"
|
||||
SEMICOLON ";"
|
||||
R_ANGLE ">"
|
||||
ERROR
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n"
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
|
@ -312,10 +314,18 @@ error 168: expected expression
|
|||
error 179: expected expression
|
||||
error 180: expected a block
|
||||
error 180: expected COMMA
|
||||
error 180: expected expression
|
||||
error 180: expected R_PAREN
|
||||
error 180: expected SEMICOLON
|
||||
error 215: expected COMMA
|
||||
error 215: expected R_ANGLE
|
||||
error 235: expected SEMICOLON
|
||||
error 235: expected expression
|
||||
error 190: expected EQ
|
||||
error 190: expected expression
|
||||
error 191: expected COMMA
|
||||
error 201: expected type
|
||||
error 204: expected IN_KW
|
||||
error 211: 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_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -30,7 +29,7 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LET_EXPR
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
TUPLE_STRUCT_PAT
|
||||
|
@ -69,15 +68,14 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -16,9 +16,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -30,9 +29,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -51,9 +49,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -65,9 +62,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
FALSE_KW "false"
|
||||
LITERAL
|
||||
FALSE_KW "false"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -86,12 +82,11 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "S"
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "S"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -103,15 +98,14 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -15,9 +15,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BREAK_EXPR
|
||||
BREAK_KW "break"
|
||||
BREAK_EXPR
|
||||
BREAK_KW "break"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -28,9 +27,8 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BREAK_EXPR
|
||||
BREAK_KW "break"
|
||||
BREAK_EXPR
|
||||
BREAK_KW "break"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -16,9 +16,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -50,9 +49,8 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -35,9 +35,8 @@ SOURCE_FILE
|
|||
WHITESPACE " "
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -49,19 +49,20 @@ SOURCE_FILE
|
|||
MATCH_GUARD
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
IDENT_PAT
|
||||
NAME
|
||||
IDENT "foo"
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bar"
|
||||
LET_EXPR
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
IDENT_PAT
|
||||
NAME
|
||||
IDENT "foo"
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bar"
|
||||
WHITESPACE " "
|
||||
FAT_ARROW "=>"
|
||||
WHITESPACE " "
|
||||
|
|
|
@ -51,16 +51,15 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "condition_not_met"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "condition_not_met"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -92,16 +91,15 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "condition_not_met"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "condition_not_met"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -153,16 +151,15 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "foo"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "foo"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -187,16 +184,15 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bar"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "bar"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -280,21 +280,20 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PREFIX_EXPR
|
||||
BANG "!"
|
||||
METHOD_CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "x"
|
||||
DOT "."
|
||||
NAME_REF
|
||||
IDENT "get"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
PREFIX_EXPR
|
||||
BANG "!"
|
||||
METHOD_CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "x"
|
||||
DOT "."
|
||||
NAME_REF
|
||||
IDENT "get"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -443,12 +442,11 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -457,12 +455,11 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -495,12 +492,11 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -549,12 +545,11 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -572,12 +567,11 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
RETURN_EXPR
|
||||
RETURN_KW "return"
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -1037,9 +1031,8 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BREAK_EXPR
|
||||
BREAK_KW "break"
|
||||
BREAK_EXPR
|
||||
BREAK_KW "break"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -1089,18 +1082,17 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BIN_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "i"
|
||||
WHITESPACE " "
|
||||
EQ2 "=="
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
INT_NUMBER "1"
|
||||
BIN_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "i"
|
||||
WHITESPACE " "
|
||||
EQ2 "=="
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
INT_NUMBER "1"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
@ -1344,18 +1336,17 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BIN_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "u8"
|
||||
WHITESPACE " "
|
||||
NEQ "!="
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
INT_NUMBER "0u8"
|
||||
BIN_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "u8"
|
||||
WHITESPACE " "
|
||||
NEQ "!="
|
||||
WHITESPACE " "
|
||||
LITERAL
|
||||
INT_NUMBER "0u8"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -219,7 +219,7 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LET_EXPR
|
||||
LET_KW "let"
|
||||
WHITESPACE " "
|
||||
TUPLE_STRUCT_PAT
|
||||
|
|
|
@ -15,47 +15,46 @@ SOURCE_FILE
|
|||
IF_EXPR
|
||||
IF_KW "if"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
BIN_EXPR
|
||||
CAST_EXPR
|
||||
METHOD_CALL_EXPR
|
||||
LITERAL
|
||||
FLOAT_NUMBER "1.0f32"
|
||||
DOT "."
|
||||
NAME_REF
|
||||
IDENT "floor"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
AS_KW "as"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "i64"
|
||||
BIN_EXPR
|
||||
CAST_EXPR
|
||||
METHOD_CALL_EXPR
|
||||
LITERAL
|
||||
FLOAT_NUMBER "1.0f32"
|
||||
DOT "."
|
||||
NAME_REF
|
||||
IDENT "floor"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
NEQ "!="
|
||||
AS_KW "as"
|
||||
WHITESPACE " "
|
||||
CAST_EXPR
|
||||
METHOD_CALL_EXPR
|
||||
LITERAL
|
||||
FLOAT_NUMBER "1.0f32"
|
||||
DOT "."
|
||||
NAME_REF
|
||||
IDENT "floor"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
AS_KW "as"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "i64"
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "i64"
|
||||
WHITESPACE " "
|
||||
NEQ "!="
|
||||
WHITESPACE " "
|
||||
CAST_EXPR
|
||||
METHOD_CALL_EXPR
|
||||
LITERAL
|
||||
FLOAT_NUMBER "1.0f32"
|
||||
DOT "."
|
||||
NAME_REF
|
||||
IDENT "floor"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
AS_KW "as"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "i64"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -86,9 +86,8 @@ SOURCE_FILE
|
|||
WHILE_EXPR
|
||||
WHILE_KW "while"
|
||||
WHITESPACE " "
|
||||
CONDITION
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
LITERAL
|
||||
TRUE_KW "true"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
|
|
|
@ -30,7 +30,7 @@ rayon = "1"
|
|||
expect-test = "1.2.0-pre.1"
|
||||
proc-macro2 = "1.0.8"
|
||||
quote = "1.0.2"
|
||||
ungrammar = "=1.14.9"
|
||||
ungrammar = "=1.15.0"
|
||||
|
||||
test_utils = { path = "../test_utils" }
|
||||
sourcegen = { path = "../sourcegen" }
|
||||
|
|
|
@ -884,7 +884,7 @@ pub struct IfExpr {
|
|||
impl ast::HasAttrs for IfExpr {}
|
||||
impl IfExpr {
|
||||
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]) }
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1038,7 @@ impl ast::HasAttrs for WhileExpr {}
|
|||
impl ast::HasLoopBody for WhileExpr {}
|
||||
impl WhileExpr {
|
||||
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)]
|
||||
|
@ -1051,6 +1051,18 @@ impl YieldExpr {
|
|||
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)]
|
||||
pub struct StmtList {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
|
@ -1106,17 +1118,6 @@ impl ArgList {
|
|||
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)]
|
||||
pub struct MatchArmList {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
|
@ -1147,10 +1148,7 @@ pub struct MatchGuard {
|
|||
}
|
||||
impl MatchGuard {
|
||||
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 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) }
|
||||
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -1524,6 +1522,7 @@ pub enum Expr {
|
|||
TupleExpr(TupleExpr),
|
||||
WhileExpr(WhileExpr),
|
||||
YieldExpr(YieldExpr),
|
||||
LetExpr(LetExpr),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -2664,6 +2663,17 @@ impl AstNode for YieldExpr {
|
|||
}
|
||||
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 {
|
||||
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
|
@ -2719,17 +2729,6 @@ impl AstNode for ArgList {
|
|||
}
|
||||
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 {
|
||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
|
||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
|
@ -3336,6 +3335,9 @@ impl From<WhileExpr> for Expr {
|
|||
impl From<YieldExpr> for Expr {
|
||||
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 {
|
||||
fn can_cast(kind: SyntaxKind) -> bool {
|
||||
match kind {
|
||||
|
@ -3344,7 +3346,7 @@ impl AstNode for Expr {
|
|||
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
|
||||
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
|
||||
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
|
||||
| YIELD_EXPR => true,
|
||||
| YIELD_EXPR | LET_EXPR => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -3381,6 +3383,7 @@ impl AstNode for Expr {
|
|||
TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
|
||||
WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
|
||||
YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
|
||||
LET_EXPR => Expr::LetExpr(LetExpr { syntax }),
|
||||
_ => return None,
|
||||
};
|
||||
Some(res)
|
||||
|
@ -3418,6 +3421,7 @@ impl AstNode for Expr {
|
|||
Expr::TupleExpr(it) => &it.syntax,
|
||||
Expr::WhileExpr(it) => &it.syntax,
|
||||
Expr::YieldExpr(it) => &it.syntax,
|
||||
Expr::LetExpr(it) => &it.syntax,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3883,6 +3887,7 @@ impl AstNode for AnyHasAttrs {
|
|||
| TUPLE_EXPR
|
||||
| WHILE_EXPR
|
||||
| YIELD_EXPR
|
||||
| LET_EXPR
|
||||
| STMT_LIST
|
||||
| RECORD_EXPR_FIELD_LIST
|
||||
| RECORD_EXPR_FIELD
|
||||
|
@ -4537,6 +4542,11 @@ impl std::fmt::Display for YieldExpr {
|
|||
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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
|
@ -4562,11 +4572,6 @@ impl std::fmt::Display for ArgList {
|
|||
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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
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))
|
||||
}
|
||||
pub fn expr_if(
|
||||
condition: ast::Condition,
|
||||
condition: ast::Expr,
|
||||
then_branch: ast::BlockExpr,
|
||||
else_branch: Option<ast::ElseBranch>,
|
||||
) -> 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 {
|
||||
ast_from_text(&format!("const C: () = {};", text))
|
||||
}
|
||||
|
||||
pub fn condition(expr: ast::Expr, pattern: Option<ast::Pat>) -> ast::Condition {
|
||||
match pattern {
|
||||
None => ast_from_text(&format!("const _: () = while {} {{}};", expr)),
|
||||
Some(pattern) => {
|
||||
ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
|
||||
}
|
||||
}
|
||||
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
|
||||
ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
|
||||
}
|
||||
|
||||
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)]
|
||||
pub enum FieldKind {
|
||||
Name(ast::NameRef),
|
||||
|
|
|
@ -133,7 +133,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
|||
"CLOSURE_EXPR",
|
||||
"IF_EXPR",
|
||||
"WHILE_EXPR",
|
||||
"CONDITION",
|
||||
"LOOP_EXPR",
|
||||
"FOR_EXPR",
|
||||
"CONTINUE_EXPR",
|
||||
|
@ -143,6 +142,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
|||
"STMT_LIST",
|
||||
"RETURN_EXPR",
|
||||
"YIELD_EXPR",
|
||||
"LET_EXPR",
|
||||
"MATCH_EXPR",
|
||||
"MATCH_ARM_LIST",
|
||||
"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::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(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()));
|
||||
}
|
||||
}
|
||||
|
||||
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_KW@134..136 "if"
|
||||
WHITESPACE@136..137 " "
|
||||
CONDITION@137..141
|
||||
LITERAL@137..141
|
||||
TRUE_KW@137..141 "true"
|
||||
LITERAL@137..141
|
||||
TRUE_KW@137..141 "true"
|
||||
WHITESPACE@141..142 " "
|
||||
BLOCK_EXPR@142..257
|
||||
STMT_LIST@142..257
|
||||
|
@ -94,9 +93,8 @@ SOURCE_FILE@0..350
|
|||
WHILE_EXPR@262..347
|
||||
WHILE_KW@262..267 "while"
|
||||
WHITESPACE@267..268 " "
|
||||
CONDITION@268..272
|
||||
LITERAL@268..272
|
||||
TRUE_KW@268..272 "true"
|
||||
LITERAL@268..272
|
||||
TRUE_KW@268..272 "true"
|
||||
WHITESPACE@272..273 " "
|
||||
BLOCK_EXPR@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