Infer type of match guard

This commit is contained in:
Marcus Klaas de Vries 2019-01-28 23:06:11 +01:00
parent 3f4f50baaa
commit 3daca3eb4d
10 changed files with 152 additions and 59 deletions

View File

@ -215,7 +215,7 @@ pub use ra_syntax::ast::BinOp as BinaryOp;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MatchArm {
pub pats: Vec<PatId>,
// guard: Option<ExprId>, // TODO
pub guard: Option<ExprId>,
pub expr: ExprId,
}
@ -511,10 +511,12 @@ impl ExprCollector {
MatchArm {
pats: vec![pat],
expr: then_branch,
guard: None,
},
MatchArm {
pats: vec![placeholder_pat],
expr: else_branch,
guard: None,
},
];
self.alloc_expr(
@ -613,6 +615,10 @@ impl ExprCollector {
.map(|arm| MatchArm {
pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
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()
} else {

View File

@ -1395,7 +1395,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
for &pat in &arm.pats {
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);
}
@ -1468,9 +1470,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
cast_ty
}
Expr::Ref { expr, mutability } => {
// TODO pass the expectation down
let inner_ty = self.infer_expr(*expr, &Expectation::none());
let expectation = if let Ty::Ref(ref subty, expected_mutability) = expected.ty {
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.
let inner_ty = self.infer_expr(*expr, &expectation);
Ty::Ref(Arc::new(inner_ty), *mutability)
}
Expr::UnaryOp { expr, op } => {

View File

@ -1,10 +1,10 @@
---
created: "2019-01-22T14:44:59.880187500+00:00"
creator: insta@0.4.0
created: "2019-01-28T21:58:55.559331849+00:00"
creator: insta@0.5.2
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
[82; 95) 'E::A { x: 3 }': E
[92; 93) '3': usize
@ -15,15 +15,18 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs"
[129; 148) 'E::A {..._var }': E
[139; 146) 'new_var': usize
[151; 152) 'e': E
[159; 218) 'match ... }': usize
[159; 245) 'match ... }': usize
[165; 166) 'e': E
[177; 187) 'E::A { x }': E
[184; 185) 'x': usize
[191; 192) 'x': usize
[202; 206) 'E::B': E
[210; 211) '1': usize
[229; 248) 'ref d ...{ .. }': &E
[237; 248) 'E::A { .. }': E
[251; 252) 'e': E
[258; 259) 'd': &E
[210; 213) 'foo': bool
[217; 218) '1': usize
[228; 232) 'E::B': E
[236; 238) '10': usize
[256; 275) 'ref d ...{ .. }': &E
[264; 275) 'E::A { .. }': E
[278; 279) 'e': E
[285; 286) 'd': &E

View File

@ -421,7 +421,8 @@ fn test() {
match e {
E::A { x } => x,
E::B => 1,
E::B if foo => 1,
E::B => 10,
};
let ref d @ E::A { .. } = e;

View File

@ -1981,7 +1981,11 @@ impl ToOwned for MatchGuard {
}
impl MatchGuard {}
impl MatchGuard {
pub fn expr(&self) -> Option<&Expr> {
super::child_opt(self)
}
}
// MethodCallExpr
#[derive(Debug, PartialEq, Eq, Hash)]

View File

@ -418,7 +418,7 @@ Grammar(
],
collections: [ [ "pats", "Pat" ] ]
),
"MatchGuard": (),
"MatchGuard": (options: ["Expr"]),
"StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
"NamedFieldList": (collections: [ ["fields", "NamedField"] ]),
"NamedField": (options: ["NameRef", "Expr"]),

View File

@ -360,8 +360,8 @@ fn match_arm(p: &mut Parser) -> BlockLike {
while p.eat(PIPE) {
patterns::pattern(p);
}
if p.eat(IF_KW) {
expr(p);
if p.at(IF_KW) {
match_guard(p);
}
p.expect(FAT_ARROW);
let ret = expr_stmt(p);
@ -369,6 +369,20 @@ fn match_arm(p: &mut Parser) -> BlockLike {
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
// fn foo() {
// {};

View File

@ -37,32 +37,33 @@ SOURCE_FILE@[0; 167)
PLACEHOLDER_PAT@[51; 52)
UNDERSCORE@[51; 52)
WHITESPACE@[52; 53)
IF_KW@[53; 55)
WHITESPACE@[55; 56)
BIN_EXPR@[56; 77)
PATH_EXPR@[56; 60)
PATH@[56; 60)
PATH_SEGMENT@[56; 60)
NAME_REF@[56; 60)
IDENT@[56; 60) "Test"
WHITESPACE@[60; 61)
R_ANGLE@[61; 62)
WHITESPACE@[62; 63)
STRUCT_LIT@[63; 77)
PATH@[63; 67)
PATH_SEGMENT@[63; 67)
NAME_REF@[63; 67)
IDENT@[63; 67) "Test"
NAMED_FIELD_LIST@[67; 77)
L_CURLY@[67; 68)
NAMED_FIELD@[68; 76)
NAME_REF@[68; 73)
IDENT@[68; 73) "field"
COLON@[73; 74)
WHITESPACE@[74; 75)
LITERAL@[75; 76)
INT_NUMBER@[75; 76) "0"
R_CURLY@[76; 77)
MATCH_GUARD@[53; 77)
IF_KW@[53; 55)
WHITESPACE@[55; 56)
BIN_EXPR@[56; 77)
PATH_EXPR@[56; 60)
PATH@[56; 60)
PATH_SEGMENT@[56; 60)
NAME_REF@[56; 60)
IDENT@[56; 60) "Test"
WHITESPACE@[60; 61)
R_ANGLE@[61; 62)
WHITESPACE@[62; 63)
STRUCT_LIT@[63; 77)
PATH@[63; 67)
PATH_SEGMENT@[63; 67)
NAME_REF@[63; 67)
IDENT@[63; 67) "Test"
NAMED_FIELD_LIST@[67; 77)
L_CURLY@[67; 68)
NAMED_FIELD@[68; 76)
NAME_REF@[68; 73)
IDENT@[68; 73) "field"
COLON@[73; 74)
WHITESPACE@[74; 75)
LITERAL@[75; 76)
INT_NUMBER@[75; 76) "0"
R_CURLY@[76; 77)
WHITESPACE@[77; 78)
FAT_ARROW@[78; 80)
WHITESPACE@[80; 81)
@ -82,13 +83,14 @@ SOURCE_FILE@[0; 167)
NAME@[97; 98)
IDENT@[97; 98) "Y"
WHITESPACE@[98; 99)
IF_KW@[99; 101)
WHITESPACE@[101; 102)
PATH_EXPR@[102; 103)
PATH@[102; 103)
PATH_SEGMENT@[102; 103)
NAME_REF@[102; 103)
IDENT@[102; 103) "Z"
MATCH_GUARD@[99; 103)
IF_KW@[99; 101)
WHITESPACE@[101; 102)
PATH_EXPR@[102; 103)
PATH@[102; 103)
PATH_SEGMENT@[102; 103)
NAME_REF@[102; 103)
IDENT@[102; 103) "Z"
WHITESPACE@[103; 104)
FAT_ARROW@[104; 106)
WHITESPACE@[106; 107)
@ -110,13 +112,14 @@ SOURCE_FILE@[0; 167)
NAME@[125; 126)
IDENT@[125; 126) "Y"
WHITESPACE@[126; 127)
IF_KW@[127; 129)
WHITESPACE@[129; 130)
PATH_EXPR@[130; 131)
PATH@[130; 131)
PATH_SEGMENT@[130; 131)
NAME_REF@[130; 131)
IDENT@[130; 131) "Z"
MATCH_GUARD@[127; 131)
IF_KW@[127; 129)
WHITESPACE@[129; 130)
PATH_EXPR@[130; 131)
PATH@[130; 131)
PATH_SEGMENT@[130; 131)
NAME_REF@[130; 131)
IDENT@[130; 131) "Z"
WHITESPACE@[131; 132)
FAT_ARROW@[132; 134)
WHITESPACE@[134; 135)

View File

@ -0,0 +1,5 @@
fn foo() {
match () {
_ if foo => (),
}
}

View File

@ -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)