From 3daca3eb4d843199540edfb1092f57f49938d0f6 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Mon, 28 Jan 2019 23:06:11 +0100 Subject: Infer type of match guard --- crates/ra_hir/src/expr.rs | 8 +++++++- crates/ra_hir/src/ty.rs | 16 ++++++++++++--- .../src/ty/snapshots/tests__infer_adt_pattern.snap | 23 ++++++++++++---------- crates/ra_hir/src/ty/tests.rs | 3 ++- 4 files changed, 35 insertions(+), 15 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 60d997bbe..b01d53e5c 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -215,7 +215,7 @@ pub use ra_syntax::ast::BinOp as BinaryOp; #[derive(Debug, Clone, Eq, PartialEq)] pub struct MatchArm { pub pats: Vec, - // guard: Option, // TODO + pub guard: Option, 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 { diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 31ea45706..e2c7884b5 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -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 } => { diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap index 2719f592e..48c83cbb2 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_adt_pattern.snap @@ -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 diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f74d6f5ea..8aa188059 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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; -- cgit v1.2.3