701: Minor type inference tweaks r=flodiebold a=marcusklaas

Pass down expectation for reference expressions and type the guard in match expressions.

I wasn't able to add a test for the former addition because the type variable previously introduced would always resolve to the right type in the things I tried!

Co-authored-by: Marcus Klaas de Vries <mail@marcusklaas.nl>
This commit is contained in:
bors[bot] 2019-01-30 20:51:47 +00:00
commit 28fdb8d03c
11 changed files with 163 additions and 63 deletions

View file

@ -219,7 +219,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,
} }
@ -515,10 +515,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(
@ -617,6 +619,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()
.and_then(|guard| guard.expr())
.map(|e| self.collect_expr(e)),
}) })
.collect() .collect()
} else { } else {

View file

@ -1488,7 +1488,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);
} }
@ -1561,9 +1563,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 } => {

View file

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

View file

@ -1,12 +1,12 @@
--- ---
created: "2019-01-22T14:44:59.880187500+00:00" created: "2019-01-30T20:08:05.185312835+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
--- ---
[9; 10) 'x': &str [9; 10) 'x': &str
[18; 19) 'y': isize [18; 19) 'y': isize
[28; 293) '{ ... []; }': () [28; 324) '{ ... 3]; }': ()
[38; 39) 'a': [&str] [38; 39) 'a': [&str]
[42; 45) '[x]': [&str] [42; 45) '[x]': [&str]
[43; 44) 'x': &str [43; 44) 'x': &str
@ -56,4 +56,10 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs"
[260; 263) '"b"': &str [260; 263) '"b"': &str
[275; 276) 'x': [u8] [275; 276) 'x': [u8]
[288; 290) '[]': [u8] [288; 290) '[]': [u8]
[300; 301) 'z': &[u8]
[311; 321) '&[1, 2, 3]': &[u8]
[312; 321) '[1, 2, 3]': [u8]
[313; 314) '1': u8
[316; 317) '2': u8
[319; 320) '3': u8

View file

@ -371,6 +371,7 @@ fn test(x: &str, y: isize) {
let b = [a, ["b"]]; let b = [a, ["b"]];
let x: [u8; 0] = []; let x: [u8; 0] = [];
let z: &[u8] = &[1, 2, 3];
} }
"#, "#,
); );
@ -426,7 +427,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;

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 // MethodCallExpr
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]

View file

@ -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"]),

View file

@ -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() {
// {}; // {};

View file

@ -37,6 +37,7 @@ SOURCE_FILE@[0; 167)
PLACEHOLDER_PAT@[51; 52) PLACEHOLDER_PAT@[51; 52)
UNDERSCORE@[51; 52) UNDERSCORE@[51; 52)
WHITESPACE@[52; 53) WHITESPACE@[52; 53)
MATCH_GUARD@[53; 77)
IF_KW@[53; 55) IF_KW@[53; 55)
WHITESPACE@[55; 56) WHITESPACE@[55; 56)
BIN_EXPR@[56; 77) BIN_EXPR@[56; 77)
@ -82,6 +83,7 @@ SOURCE_FILE@[0; 167)
NAME@[97; 98) NAME@[97; 98)
IDENT@[97; 98) "Y" IDENT@[97; 98) "Y"
WHITESPACE@[98; 99) WHITESPACE@[98; 99)
MATCH_GUARD@[99; 103)
IF_KW@[99; 101) IF_KW@[99; 101)
WHITESPACE@[101; 102) WHITESPACE@[101; 102)
PATH_EXPR@[102; 103) PATH_EXPR@[102; 103)
@ -110,6 +112,7 @@ SOURCE_FILE@[0; 167)
NAME@[125; 126) NAME@[125; 126)
IDENT@[125; 126) "Y" IDENT@[125; 126) "Y"
WHITESPACE@[126; 127) WHITESPACE@[126; 127)
MATCH_GUARD@[127; 131)
IF_KW@[127; 129) IF_KW@[127; 129)
WHITESPACE@[129; 130) WHITESPACE@[129; 130)
PATH_EXPR@[130; 131) PATH_EXPR@[130; 131)

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)