mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Support if let
match guards
This commit is contained in:
parent
4466e07fd7
commit
d568e7686a
10 changed files with 90 additions and 27 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1777,9 +1777,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ungrammar"
|
name = "ungrammar"
|
||||||
version = "1.14.2"
|
version = "1.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5334230a6ae9ca52bc811c968c0ae12f1750c0698ed52ea68dabab7ce5a80972"
|
checksum = "0ef2f5093f958b9aecad9d80a01c49aece7a7bd15ad407e1986258fa36229910"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
|
|
|
@ -28,8 +28,8 @@ use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expr::{
|
expr::{
|
||||||
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
|
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
|
||||||
LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
|
LabelId, Literal, LogicOp, MatchArm, MatchGuard, Ordering, Pat, PatId, RecordFieldPat,
|
||||||
Statement,
|
RecordLitField, Statement,
|
||||||
},
|
},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
item_scope::BuiltinShadowMode,
|
item_scope::BuiltinShadowMode,
|
||||||
|
@ -361,10 +361,15 @@ impl ExprCollector<'_> {
|
||||||
self.check_cfg(&arm).map(|()| MatchArm {
|
self.check_cfg(&arm).map(|()| MatchArm {
|
||||||
pat: self.collect_pat_opt(arm.pat()),
|
pat: self.collect_pat_opt(arm.pat()),
|
||||||
expr: self.collect_expr_opt(arm.expr()),
|
expr: self.collect_expr_opt(arm.expr()),
|
||||||
guard: arm
|
guard: arm.guard().map(|guard| match guard.pat() {
|
||||||
.guard()
|
Some(pat) => MatchGuard::IfLet {
|
||||||
.and_then(|guard| guard.expr())
|
pat: self.collect_pat(pat),
|
||||||
.map(|e| self.collect_expr(e)),
|
expr: self.collect_expr_opt(guard.expr()),
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
MatchGuard::If { expr: self.collect_expr_opt(guard.expr()) }
|
||||||
|
}
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
|
||||||
use crate::{
|
use crate::{
|
||||||
body::Body,
|
body::Body,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expr::{Expr, ExprId, LabelId, Pat, PatId, Statement},
|
expr::{Expr, ExprId, LabelId, MatchGuard, Pat, PatId, Statement},
|
||||||
BlockId, DefWithBodyId,
|
BlockId, DefWithBodyId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -204,12 +204,21 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
|
||||||
Expr::Match { expr, arms } => {
|
Expr::Match { expr, arms } => {
|
||||||
compute_expr_scopes(*expr, body, scopes, scope);
|
compute_expr_scopes(*expr, body, scopes, scope);
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
let scope = scopes.new_scope(scope);
|
let mut scope = scopes.new_scope(scope);
|
||||||
scopes.add_bindings(body, scope, arm.pat);
|
scopes.add_bindings(body, scope, arm.pat);
|
||||||
if let Some(guard) = arm.guard {
|
match arm.guard {
|
||||||
scopes.set_scope(guard, scope);
|
Some(MatchGuard::If { expr: guard }) => {
|
||||||
compute_expr_scopes(guard, body, scopes, scope);
|
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);
|
scopes.set_scope(arm.expr, scope);
|
||||||
compute_expr_scopes(arm.expr, body, scopes, scope);
|
compute_expr_scopes(arm.expr, body, scopes, scope);
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,10 +229,17 @@ pub enum Array {
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MatchArm {
|
pub struct MatchArm {
|
||||||
pub pat: PatId,
|
pub pat: PatId,
|
||||||
pub guard: Option<ExprId>,
|
pub guard: Option<MatchGuard>,
|
||||||
pub expr: ExprId,
|
pub expr: ExprId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum MatchGuard {
|
||||||
|
If { expr: ExprId },
|
||||||
|
|
||||||
|
IfLet { pat: PatId, expr: ExprId },
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct RecordLitField {
|
pub struct RecordLitField {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
|
|
||||||
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
|
expr::{Array, BinaryOp, Expr, ExprId, Literal, MatchGuard, Statement, UnaryOp},
|
||||||
path::{GenericArg, GenericArgs},
|
path::{GenericArg, GenericArgs},
|
||||||
resolver::resolver_for_expr,
|
resolver::resolver_for_expr,
|
||||||
AssocContainerId, FieldId, Lookup,
|
AssocContainerId, FieldId, Lookup,
|
||||||
|
@ -366,12 +366,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
self.diverges = Diverges::Maybe;
|
self.diverges = Diverges::Maybe;
|
||||||
let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
|
let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
|
||||||
if let Some(guard_expr) = arm.guard {
|
if let Some(MatchGuard::If { expr: guard_expr }) = arm.guard {
|
||||||
self.infer_expr(
|
self.infer_expr(
|
||||||
guard_expr,
|
guard_expr,
|
||||||
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
|
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// FIXME: infer `if let` guard
|
||||||
|
|
||||||
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
||||||
all_arms_diverge &= self.diverges;
|
all_arms_diverge &= self.diverges;
|
||||||
|
|
|
@ -37,6 +37,10 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
let guard = match_arm.guard()?;
|
let guard = match_arm.guard()?;
|
||||||
let space_before_guard = guard.syntax().prev_sibling_or_token();
|
let space_before_guard = guard.syntax().prev_sibling_or_token();
|
||||||
|
|
||||||
|
// FIXME: support `if let` guards too
|
||||||
|
if guard.let_token().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let guard_condition = guard.expr()?;
|
let guard_condition = guard.expr()?;
|
||||||
let arm_expr = match_arm.expr()?;
|
let arm_expr = match_arm.expr()?;
|
||||||
let if_expr = make::expr_if(
|
let if_expr = make::expr_if(
|
||||||
|
|
|
@ -458,12 +458,17 @@ fn match_arm(p: &mut Parser) {
|
||||||
// fn foo() {
|
// fn foo() {
|
||||||
// match () {
|
// match () {
|
||||||
// _ if foo => (),
|
// _ if foo => (),
|
||||||
|
// _ if let foo = bar => (),
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
fn match_guard(p: &mut Parser) -> CompletedMarker {
|
fn match_guard(p: &mut Parser) -> CompletedMarker {
|
||||||
assert!(p.at(T![if]));
|
assert!(p.at(T![if]));
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
p.bump(T![if]);
|
p.bump(T![if]);
|
||||||
|
if p.eat(T![let]) {
|
||||||
|
patterns::pattern_top(p);
|
||||||
|
p.expect(T![=]);
|
||||||
|
}
|
||||||
expr(p);
|
expr(p);
|
||||||
m.complete(p, MATCH_GUARD)
|
m.complete(p, MATCH_GUARD)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1021,6 +1021,9 @@ pub struct MatchGuard {
|
||||||
}
|
}
|
||||||
impl MatchGuard {
|
impl MatchGuard {
|
||||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||||
|
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
||||||
|
pub fn 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 expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
SOURCE_FILE@0..58
|
SOURCE_FILE@0..92
|
||||||
FN@0..57
|
FN@0..91
|
||||||
FN_KW@0..2 "fn"
|
FN_KW@0..2 "fn"
|
||||||
WHITESPACE@2..3 " "
|
WHITESPACE@2..3 " "
|
||||||
NAME@3..6
|
NAME@3..6
|
||||||
|
@ -8,17 +8,17 @@ SOURCE_FILE@0..58
|
||||||
L_PAREN@6..7 "("
|
L_PAREN@6..7 "("
|
||||||
R_PAREN@7..8 ")"
|
R_PAREN@7..8 ")"
|
||||||
WHITESPACE@8..9 " "
|
WHITESPACE@8..9 " "
|
||||||
BLOCK_EXPR@9..57
|
BLOCK_EXPR@9..91
|
||||||
L_CURLY@9..10 "{"
|
L_CURLY@9..10 "{"
|
||||||
WHITESPACE@10..15 "\n "
|
WHITESPACE@10..15 "\n "
|
||||||
MATCH_EXPR@15..55
|
MATCH_EXPR@15..89
|
||||||
MATCH_KW@15..20 "match"
|
MATCH_KW@15..20 "match"
|
||||||
WHITESPACE@20..21 " "
|
WHITESPACE@20..21 " "
|
||||||
TUPLE_EXPR@21..23
|
TUPLE_EXPR@21..23
|
||||||
L_PAREN@21..22 "("
|
L_PAREN@21..22 "("
|
||||||
R_PAREN@22..23 ")"
|
R_PAREN@22..23 ")"
|
||||||
WHITESPACE@23..24 " "
|
WHITESPACE@23..24 " "
|
||||||
MATCH_ARM_LIST@24..55
|
MATCH_ARM_LIST@24..89
|
||||||
L_CURLY@24..25 "{"
|
L_CURLY@24..25 "{"
|
||||||
WHITESPACE@25..34 "\n "
|
WHITESPACE@25..34 "\n "
|
||||||
MATCH_ARM@34..49
|
MATCH_ARM@34..49
|
||||||
|
@ -40,8 +40,36 @@ SOURCE_FILE@0..58
|
||||||
L_PAREN@46..47 "("
|
L_PAREN@46..47 "("
|
||||||
R_PAREN@47..48 ")"
|
R_PAREN@47..48 ")"
|
||||||
COMMA@48..49 ","
|
COMMA@48..49 ","
|
||||||
WHITESPACE@49..54 "\n "
|
WHITESPACE@49..58 "\n "
|
||||||
R_CURLY@54..55 "}"
|
MATCH_ARM@58..83
|
||||||
WHITESPACE@55..56 "\n"
|
WILDCARD_PAT@58..59
|
||||||
R_CURLY@56..57 "}"
|
UNDERSCORE@58..59 "_"
|
||||||
WHITESPACE@57..58 "\n"
|
WHITESPACE@59..60 " "
|
||||||
|
MATCH_GUARD@60..76
|
||||||
|
IF_KW@60..62 "if"
|
||||||
|
WHITESPACE@62..63 " "
|
||||||
|
LET_KW@63..66 "let"
|
||||||
|
WHITESPACE@66..67 " "
|
||||||
|
IDENT_PAT@67..70
|
||||||
|
NAME@67..70
|
||||||
|
IDENT@67..70 "foo"
|
||||||
|
WHITESPACE@70..71 " "
|
||||||
|
EQ@71..72 "="
|
||||||
|
WHITESPACE@72..73 " "
|
||||||
|
PATH_EXPR@73..76
|
||||||
|
PATH@73..76
|
||||||
|
PATH_SEGMENT@73..76
|
||||||
|
NAME_REF@73..76
|
||||||
|
IDENT@73..76 "bar"
|
||||||
|
WHITESPACE@76..77 " "
|
||||||
|
FAT_ARROW@77..79 "=>"
|
||||||
|
WHITESPACE@79..80 " "
|
||||||
|
TUPLE_EXPR@80..82
|
||||||
|
L_PAREN@80..81 "("
|
||||||
|
R_PAREN@81..82 ")"
|
||||||
|
COMMA@82..83 ","
|
||||||
|
WHITESPACE@83..88 "\n "
|
||||||
|
R_CURLY@88..89 "}"
|
||||||
|
WHITESPACE@89..90 "\n"
|
||||||
|
R_CURLY@90..91 "}"
|
||||||
|
WHITESPACE@91..92 "\n"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
fn foo() {
|
fn foo() {
|
||||||
match () {
|
match () {
|
||||||
_ if foo => (),
|
_ if foo => (),
|
||||||
|
_ if let foo = bar => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue