mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +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]]
|
||||
name = "ungrammar"
|
||||
version = "1.14.2"
|
||||
version = "1.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5334230a6ae9ca52bc811c968c0ae12f1750c0698ed52ea68dabab7ce5a80972"
|
||||
checksum = "0ef2f5093f958b9aecad9d80a01c49aece7a7bd15ad407e1986258fa36229910"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
|
|
|
@ -28,8 +28,8 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
expr::{
|
||||
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
|
||||
LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
|
||||
Statement,
|
||||
LabelId, Literal, LogicOp, MatchArm, MatchGuard, Ordering, Pat, PatId, RecordFieldPat,
|
||||
RecordLitField, Statement,
|
||||
},
|
||||
intern::Interned,
|
||||
item_scope::BuiltinShadowMode,
|
||||
|
@ -361,10 +361,15 @@ 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()
|
||||
.and_then(|guard| guard.expr())
|
||||
.map(|e| self.collect_expr(e)),
|
||||
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()) }
|
||||
}
|
||||
}),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
|
|||
use crate::{
|
||||
body::Body,
|
||||
db::DefDatabase,
|
||||
expr::{Expr, ExprId, LabelId, Pat, PatId, Statement},
|
||||
expr::{Expr, ExprId, LabelId, MatchGuard, Pat, PatId, Statement},
|
||||
BlockId, DefWithBodyId,
|
||||
};
|
||||
|
||||
|
@ -204,12 +204,21 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
|
|||
Expr::Match { expr, arms } => {
|
||||
compute_expr_scopes(*expr, body, scopes, scope);
|
||||
for arm in arms {
|
||||
let scope = scopes.new_scope(scope);
|
||||
let mut scope = scopes.new_scope(scope);
|
||||
scopes.add_bindings(body, scope, arm.pat);
|
||||
if let Some(guard) = arm.guard {
|
||||
scopes.set_scope(guard, scope);
|
||||
compute_expr_scopes(guard, body, scopes, scope);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -229,10 +229,17 @@ pub enum Array {
|
|||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct MatchArm {
|
||||
pub pat: PatId,
|
||||
pub guard: Option<ExprId>,
|
||||
pub guard: Option<MatchGuard>,
|
||||
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,
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
|
||||
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
||||
use hir_def::{
|
||||
expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
|
||||
expr::{Array, BinaryOp, Expr, ExprId, Literal, MatchGuard, Statement, UnaryOp},
|
||||
path::{GenericArg, GenericArgs},
|
||||
resolver::resolver_for_expr,
|
||||
AssocContainerId, FieldId, Lookup,
|
||||
|
@ -366,12 +366,13 @@ impl<'a> InferenceContext<'a> {
|
|||
for arm in arms {
|
||||
self.diverges = Diverges::Maybe;
|
||||
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(
|
||||
guard_expr,
|
||||
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
|
||||
);
|
||||
}
|
||||
// FIXME: infer `if let` guard
|
||||
|
||||
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
||||
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 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 arm_expr = match_arm.expr()?;
|
||||
let if_expr = make::expr_if(
|
||||
|
|
|
@ -458,12 +458,17 @@ fn match_arm(p: &mut Parser) {
|
|||
// fn foo() {
|
||||
// match () {
|
||||
// _ if foo => (),
|
||||
// _ if let foo = bar => (),
|
||||
// }
|
||||
// }
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -1021,6 +1021,9 @@ 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) }
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SOURCE_FILE@0..58
|
||||
FN@0..57
|
||||
SOURCE_FILE@0..92
|
||||
FN@0..91
|
||||
FN_KW@0..2 "fn"
|
||||
WHITESPACE@2..3 " "
|
||||
NAME@3..6
|
||||
|
@ -8,17 +8,17 @@ SOURCE_FILE@0..58
|
|||
L_PAREN@6..7 "("
|
||||
R_PAREN@7..8 ")"
|
||||
WHITESPACE@8..9 " "
|
||||
BLOCK_EXPR@9..57
|
||||
BLOCK_EXPR@9..91
|
||||
L_CURLY@9..10 "{"
|
||||
WHITESPACE@10..15 "\n "
|
||||
MATCH_EXPR@15..55
|
||||
MATCH_EXPR@15..89
|
||||
MATCH_KW@15..20 "match"
|
||||
WHITESPACE@20..21 " "
|
||||
TUPLE_EXPR@21..23
|
||||
L_PAREN@21..22 "("
|
||||
R_PAREN@22..23 ")"
|
||||
WHITESPACE@23..24 " "
|
||||
MATCH_ARM_LIST@24..55
|
||||
MATCH_ARM_LIST@24..89
|
||||
L_CURLY@24..25 "{"
|
||||
WHITESPACE@25..34 "\n "
|
||||
MATCH_ARM@34..49
|
||||
|
@ -40,8 +40,36 @@ SOURCE_FILE@0..58
|
|||
L_PAREN@46..47 "("
|
||||
R_PAREN@47..48 ")"
|
||||
COMMA@48..49 ","
|
||||
WHITESPACE@49..54 "\n "
|
||||
R_CURLY@54..55 "}"
|
||||
WHITESPACE@55..56 "\n"
|
||||
R_CURLY@56..57 "}"
|
||||
WHITESPACE@57..58 "\n"
|
||||
WHITESPACE@49..58 "\n "
|
||||
MATCH_ARM@58..83
|
||||
WILDCARD_PAT@58..59
|
||||
UNDERSCORE@58..59 "_"
|
||||
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() {
|
||||
match () {
|
||||
_ if foo => (),
|
||||
_ if let foo = bar => (),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue