mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Infer type of match guard
This commit is contained in:
parent
3f4f50baaa
commit
3daca3eb4d
10 changed files with 152 additions and 59 deletions
|
@ -215,7 +215,7 @@ pub use ra_syntax::ast::BinOp as BinaryOp;
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MatchArm {
|
pub struct MatchArm {
|
||||||
pub pats: Vec<PatId>,
|
pub pats: Vec<PatId>,
|
||||||
// guard: Option<ExprId>, // TODO
|
pub guard: Option<ExprId>,
|
||||||
pub expr: ExprId,
|
pub expr: ExprId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,10 +511,12 @@ impl ExprCollector {
|
||||||
MatchArm {
|
MatchArm {
|
||||||
pats: vec![pat],
|
pats: vec![pat],
|
||||||
expr: then_branch,
|
expr: then_branch,
|
||||||
|
guard: None,
|
||||||
},
|
},
|
||||||
MatchArm {
|
MatchArm {
|
||||||
pats: vec![placeholder_pat],
|
pats: vec![placeholder_pat],
|
||||||
expr: else_branch,
|
expr: else_branch,
|
||||||
|
guard: None,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
self.alloc_expr(
|
self.alloc_expr(
|
||||||
|
@ -613,6 +615,10 @@ impl ExprCollector {
|
||||||
.map(|arm| MatchArm {
|
.map(|arm| MatchArm {
|
||||||
pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
|
pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
|
||||||
expr: self.collect_expr_opt(arm.expr()),
|
expr: self.collect_expr_opt(arm.expr()),
|
||||||
|
guard: arm.guard().map(|guard| {
|
||||||
|
let e = guard.expr().expect("every guard should have an expr");
|
||||||
|
self.collect_expr(e)
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1395,7 +1395,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
for &pat in &arm.pats {
|
for &pat in &arm.pats {
|
||||||
let _pat_ty = self.infer_pat(pat, &input_ty);
|
let _pat_ty = self.infer_pat(pat, &input_ty);
|
||||||
}
|
}
|
||||||
// TODO type the guard
|
if let Some(guard_expr) = arm.guard {
|
||||||
|
self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool));
|
||||||
|
}
|
||||||
self.infer_expr(arm.expr, &expected);
|
self.infer_expr(arm.expr, &expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,9 +1470,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
cast_ty
|
cast_ty
|
||||||
}
|
}
|
||||||
Expr::Ref { expr, mutability } => {
|
Expr::Ref { expr, mutability } => {
|
||||||
// TODO pass the expectation down
|
let expectation = if let Ty::Ref(ref subty, expected_mutability) = expected.ty {
|
||||||
let inner_ty = self.infer_expr(*expr, &Expectation::none());
|
if expected_mutability == Mutability::Mut && *mutability == Mutability::Shared {
|
||||||
|
// TODO: throw type error - expected mut reference but found shared ref,
|
||||||
|
// which cannot be coerced
|
||||||
|
}
|
||||||
|
Expectation::has_type((**subty).clone())
|
||||||
|
} else {
|
||||||
|
Expectation::none()
|
||||||
|
};
|
||||||
// TODO reference coercions etc.
|
// TODO reference coercions etc.
|
||||||
|
let inner_ty = self.infer_expr(*expr, &expectation);
|
||||||
Ty::Ref(Arc::new(inner_ty), *mutability)
|
Ty::Ref(Arc::new(inner_ty), *mutability)
|
||||||
}
|
}
|
||||||
Expr::UnaryOp { expr, op } => {
|
Expr::UnaryOp { expr, op } => {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
created: "2019-01-22T14:44:59.880187500+00:00"
|
created: "2019-01-28T21:58:55.559331849+00:00"
|
||||||
creator: insta@0.4.0
|
creator: insta@0.5.2
|
||||||
expression: "&result"
|
expression: "&result"
|
||||||
source: "crates\\ra_hir\\src\\ty\\tests.rs"
|
source: crates/ra_hir/src/ty/tests.rs
|
||||||
---
|
---
|
||||||
[68; 262) '{ ... d; }': ()
|
[68; 289) '{ ... d; }': ()
|
||||||
[78; 79) 'e': E
|
[78; 79) 'e': E
|
||||||
[82; 95) 'E::A { x: 3 }': E
|
[82; 95) 'E::A { x: 3 }': E
|
||||||
[92; 93) '3': usize
|
[92; 93) '3': usize
|
||||||
|
@ -15,15 +15,18 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs"
|
||||||
[129; 148) 'E::A {..._var }': E
|
[129; 148) 'E::A {..._var }': E
|
||||||
[139; 146) 'new_var': usize
|
[139; 146) 'new_var': usize
|
||||||
[151; 152) 'e': E
|
[151; 152) 'e': E
|
||||||
[159; 218) 'match ... }': usize
|
[159; 245) 'match ... }': usize
|
||||||
[165; 166) 'e': E
|
[165; 166) 'e': E
|
||||||
[177; 187) 'E::A { x }': E
|
[177; 187) 'E::A { x }': E
|
||||||
[184; 185) 'x': usize
|
[184; 185) 'x': usize
|
||||||
[191; 192) 'x': usize
|
[191; 192) 'x': usize
|
||||||
[202; 206) 'E::B': E
|
[202; 206) 'E::B': E
|
||||||
[210; 211) '1': usize
|
[210; 213) 'foo': bool
|
||||||
[229; 248) 'ref d ...{ .. }': &E
|
[217; 218) '1': usize
|
||||||
[237; 248) 'E::A { .. }': E
|
[228; 232) 'E::B': E
|
||||||
[251; 252) 'e': E
|
[236; 238) '10': usize
|
||||||
[258; 259) 'd': &E
|
[256; 275) 'ref d ...{ .. }': &E
|
||||||
|
[264; 275) 'E::A { .. }': E
|
||||||
|
[278; 279) 'e': E
|
||||||
|
[285; 286) 'd': &E
|
||||||
|
|
||||||
|
|
|
@ -421,7 +421,8 @@ fn test() {
|
||||||
|
|
||||||
match e {
|
match e {
|
||||||
E::A { x } => x,
|
E::A { x } => x,
|
||||||
E::B => 1,
|
E::B if foo => 1,
|
||||||
|
E::B => 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ref d @ E::A { .. } = e;
|
let ref d @ E::A { .. } = e;
|
||||||
|
|
|
@ -1981,7 +1981,11 @@ impl ToOwned for MatchGuard {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl MatchGuard {}
|
impl MatchGuard {
|
||||||
|
pub fn expr(&self) -> Option<&Expr> {
|
||||||
|
super::child_opt(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MethodCallExpr
|
// MethodCallExpr
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -418,7 +418,7 @@ Grammar(
|
||||||
],
|
],
|
||||||
collections: [ [ "pats", "Pat" ] ]
|
collections: [ [ "pats", "Pat" ] ]
|
||||||
),
|
),
|
||||||
"MatchGuard": (),
|
"MatchGuard": (options: ["Expr"]),
|
||||||
"StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
|
"StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
|
||||||
"NamedFieldList": (collections: [ ["fields", "NamedField"] ]),
|
"NamedFieldList": (collections: [ ["fields", "NamedField"] ]),
|
||||||
"NamedField": (options: ["NameRef", "Expr"]),
|
"NamedField": (options: ["NameRef", "Expr"]),
|
||||||
|
|
|
@ -360,8 +360,8 @@ fn match_arm(p: &mut Parser) -> BlockLike {
|
||||||
while p.eat(PIPE) {
|
while p.eat(PIPE) {
|
||||||
patterns::pattern(p);
|
patterns::pattern(p);
|
||||||
}
|
}
|
||||||
if p.eat(IF_KW) {
|
if p.at(IF_KW) {
|
||||||
expr(p);
|
match_guard(p);
|
||||||
}
|
}
|
||||||
p.expect(FAT_ARROW);
|
p.expect(FAT_ARROW);
|
||||||
let ret = expr_stmt(p);
|
let ret = expr_stmt(p);
|
||||||
|
@ -369,6 +369,20 @@ fn match_arm(p: &mut Parser) -> BlockLike {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test match_guard
|
||||||
|
// fn foo() {
|
||||||
|
// match () {
|
||||||
|
// _ if foo => (),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
fn match_guard(p: &mut Parser) -> CompletedMarker {
|
||||||
|
assert!(p.at(IF_KW));
|
||||||
|
let m = p.start();
|
||||||
|
p.bump();
|
||||||
|
expr(p);
|
||||||
|
m.complete(p, MATCH_GUARD)
|
||||||
|
}
|
||||||
|
|
||||||
// test block_expr
|
// test block_expr
|
||||||
// fn foo() {
|
// fn foo() {
|
||||||
// {};
|
// {};
|
||||||
|
|
|
@ -37,32 +37,33 @@ SOURCE_FILE@[0; 167)
|
||||||
PLACEHOLDER_PAT@[51; 52)
|
PLACEHOLDER_PAT@[51; 52)
|
||||||
UNDERSCORE@[51; 52)
|
UNDERSCORE@[51; 52)
|
||||||
WHITESPACE@[52; 53)
|
WHITESPACE@[52; 53)
|
||||||
IF_KW@[53; 55)
|
MATCH_GUARD@[53; 77)
|
||||||
WHITESPACE@[55; 56)
|
IF_KW@[53; 55)
|
||||||
BIN_EXPR@[56; 77)
|
WHITESPACE@[55; 56)
|
||||||
PATH_EXPR@[56; 60)
|
BIN_EXPR@[56; 77)
|
||||||
PATH@[56; 60)
|
PATH_EXPR@[56; 60)
|
||||||
PATH_SEGMENT@[56; 60)
|
PATH@[56; 60)
|
||||||
NAME_REF@[56; 60)
|
PATH_SEGMENT@[56; 60)
|
||||||
IDENT@[56; 60) "Test"
|
NAME_REF@[56; 60)
|
||||||
WHITESPACE@[60; 61)
|
IDENT@[56; 60) "Test"
|
||||||
R_ANGLE@[61; 62)
|
WHITESPACE@[60; 61)
|
||||||
WHITESPACE@[62; 63)
|
R_ANGLE@[61; 62)
|
||||||
STRUCT_LIT@[63; 77)
|
WHITESPACE@[62; 63)
|
||||||
PATH@[63; 67)
|
STRUCT_LIT@[63; 77)
|
||||||
PATH_SEGMENT@[63; 67)
|
PATH@[63; 67)
|
||||||
NAME_REF@[63; 67)
|
PATH_SEGMENT@[63; 67)
|
||||||
IDENT@[63; 67) "Test"
|
NAME_REF@[63; 67)
|
||||||
NAMED_FIELD_LIST@[67; 77)
|
IDENT@[63; 67) "Test"
|
||||||
L_CURLY@[67; 68)
|
NAMED_FIELD_LIST@[67; 77)
|
||||||
NAMED_FIELD@[68; 76)
|
L_CURLY@[67; 68)
|
||||||
NAME_REF@[68; 73)
|
NAMED_FIELD@[68; 76)
|
||||||
IDENT@[68; 73) "field"
|
NAME_REF@[68; 73)
|
||||||
COLON@[73; 74)
|
IDENT@[68; 73) "field"
|
||||||
WHITESPACE@[74; 75)
|
COLON@[73; 74)
|
||||||
LITERAL@[75; 76)
|
WHITESPACE@[74; 75)
|
||||||
INT_NUMBER@[75; 76) "0"
|
LITERAL@[75; 76)
|
||||||
R_CURLY@[76; 77)
|
INT_NUMBER@[75; 76) "0"
|
||||||
|
R_CURLY@[76; 77)
|
||||||
WHITESPACE@[77; 78)
|
WHITESPACE@[77; 78)
|
||||||
FAT_ARROW@[78; 80)
|
FAT_ARROW@[78; 80)
|
||||||
WHITESPACE@[80; 81)
|
WHITESPACE@[80; 81)
|
||||||
|
@ -82,13 +83,14 @@ SOURCE_FILE@[0; 167)
|
||||||
NAME@[97; 98)
|
NAME@[97; 98)
|
||||||
IDENT@[97; 98) "Y"
|
IDENT@[97; 98) "Y"
|
||||||
WHITESPACE@[98; 99)
|
WHITESPACE@[98; 99)
|
||||||
IF_KW@[99; 101)
|
MATCH_GUARD@[99; 103)
|
||||||
WHITESPACE@[101; 102)
|
IF_KW@[99; 101)
|
||||||
PATH_EXPR@[102; 103)
|
WHITESPACE@[101; 102)
|
||||||
PATH@[102; 103)
|
PATH_EXPR@[102; 103)
|
||||||
PATH_SEGMENT@[102; 103)
|
PATH@[102; 103)
|
||||||
NAME_REF@[102; 103)
|
PATH_SEGMENT@[102; 103)
|
||||||
IDENT@[102; 103) "Z"
|
NAME_REF@[102; 103)
|
||||||
|
IDENT@[102; 103) "Z"
|
||||||
WHITESPACE@[103; 104)
|
WHITESPACE@[103; 104)
|
||||||
FAT_ARROW@[104; 106)
|
FAT_ARROW@[104; 106)
|
||||||
WHITESPACE@[106; 107)
|
WHITESPACE@[106; 107)
|
||||||
|
@ -110,13 +112,14 @@ SOURCE_FILE@[0; 167)
|
||||||
NAME@[125; 126)
|
NAME@[125; 126)
|
||||||
IDENT@[125; 126) "Y"
|
IDENT@[125; 126) "Y"
|
||||||
WHITESPACE@[126; 127)
|
WHITESPACE@[126; 127)
|
||||||
IF_KW@[127; 129)
|
MATCH_GUARD@[127; 131)
|
||||||
WHITESPACE@[129; 130)
|
IF_KW@[127; 129)
|
||||||
PATH_EXPR@[130; 131)
|
WHITESPACE@[129; 130)
|
||||||
PATH@[130; 131)
|
PATH_EXPR@[130; 131)
|
||||||
PATH_SEGMENT@[130; 131)
|
PATH@[130; 131)
|
||||||
NAME_REF@[130; 131)
|
PATH_SEGMENT@[130; 131)
|
||||||
IDENT@[130; 131) "Z"
|
NAME_REF@[130; 131)
|
||||||
|
IDENT@[130; 131) "Z"
|
||||||
WHITESPACE@[131; 132)
|
WHITESPACE@[131; 132)
|
||||||
FAT_ARROW@[132; 134)
|
FAT_ARROW@[132; 134)
|
||||||
WHITESPACE@[134; 135)
|
WHITESPACE@[134; 135)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn foo() {
|
||||||
|
match () {
|
||||||
|
_ if foo => (),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
SOURCE_FILE@[0; 58)
|
||||||
|
FN_DEF@[0; 57)
|
||||||
|
FN_KW@[0; 2)
|
||||||
|
WHITESPACE@[2; 3)
|
||||||
|
NAME@[3; 6)
|
||||||
|
IDENT@[3; 6) "foo"
|
||||||
|
PARAM_LIST@[6; 8)
|
||||||
|
L_PAREN@[6; 7)
|
||||||
|
R_PAREN@[7; 8)
|
||||||
|
WHITESPACE@[8; 9)
|
||||||
|
BLOCK@[9; 57)
|
||||||
|
L_CURLY@[9; 10)
|
||||||
|
WHITESPACE@[10; 15)
|
||||||
|
MATCH_EXPR@[15; 55)
|
||||||
|
MATCH_KW@[15; 20)
|
||||||
|
WHITESPACE@[20; 21)
|
||||||
|
TUPLE_EXPR@[21; 23)
|
||||||
|
L_PAREN@[21; 22)
|
||||||
|
R_PAREN@[22; 23)
|
||||||
|
WHITESPACE@[23; 24)
|
||||||
|
MATCH_ARM_LIST@[24; 55)
|
||||||
|
L_CURLY@[24; 25)
|
||||||
|
WHITESPACE@[25; 34)
|
||||||
|
MATCH_ARM@[34; 48)
|
||||||
|
PLACEHOLDER_PAT@[34; 35)
|
||||||
|
UNDERSCORE@[34; 35)
|
||||||
|
WHITESPACE@[35; 36)
|
||||||
|
MATCH_GUARD@[36; 42)
|
||||||
|
IF_KW@[36; 38)
|
||||||
|
WHITESPACE@[38; 39)
|
||||||
|
PATH_EXPR@[39; 42)
|
||||||
|
PATH@[39; 42)
|
||||||
|
PATH_SEGMENT@[39; 42)
|
||||||
|
NAME_REF@[39; 42)
|
||||||
|
IDENT@[39; 42) "foo"
|
||||||
|
WHITESPACE@[42; 43)
|
||||||
|
FAT_ARROW@[43; 45)
|
||||||
|
WHITESPACE@[45; 46)
|
||||||
|
TUPLE_EXPR@[46; 48)
|
||||||
|
L_PAREN@[46; 47)
|
||||||
|
R_PAREN@[47; 48)
|
||||||
|
COMMA@[48; 49)
|
||||||
|
WHITESPACE@[49; 54)
|
||||||
|
R_CURLY@[54; 55)
|
||||||
|
WHITESPACE@[55; 56)
|
||||||
|
R_CURLY@[56; 57)
|
||||||
|
WHITESPACE@[57; 58)
|
Loading…
Add table
Add a link
Reference in a new issue