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 +- crates/ra_syntax/src/ast/generated.rs | 6 +- crates/ra_syntax/src/grammar.ron | 2 +- crates/ra_syntax/src/grammar/expressions/atom.rs | 18 ++++- .../tests/data/parser/inline/ok/0066_match_arm.txt | 83 +++++++++++----------- .../data/parser/inline/ok/0118_match_guard.rs | 5 ++ .../data/parser/inline/ok/0118_match_guard.txt | 47 ++++++++++++ 10 files changed, 152 insertions(+), 59 deletions(-) create mode 100644 crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs create mode 100644 crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt (limited to 'crates') 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; diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 3ace6533c..4f5a96014 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -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)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 85fc79038..e4cad4eb3 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -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"]), diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs index 6d6d89f70..600774afd 100644 --- a/crates/ra_syntax/src/grammar/expressions/atom.rs +++ b/crates/ra_syntax/src/grammar/expressions/atom.rs @@ -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() { // {}; diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt index 98e7535a3..b44e61879 100644 --- a/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt @@ -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) diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs new file mode 100644 index 000000000..f1bd72fc4 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.rs @@ -0,0 +1,5 @@ +fn foo() { + match () { + _ if foo => (), + } +} diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt new file mode 100644 index 000000000..27553882d --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt @@ -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) -- cgit v1.2.3 From 13cb4a1b370038dee51ae739a42d6b98acaef385 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Wed, 30 Jan 2019 21:14:26 +0100 Subject: Add test for passing on ref expectations --- crates/ra_hir/src/expr.rs | 8 ++++---- crates/ra_hir/src/ty/snapshots/tests__infer_array.snap | 14 ++++++++++---- crates/ra_hir/src/ty/tests.rs | 1 + 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index b01d53e5c..f2d9af2ba 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -615,10 +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) - }), + guard: arm + .guard() + .and_then(|guard| guard.expr()) + .map(|e| self.collect_expr(e)), }) .collect() } else { diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap index 3f2faa598..042248c35 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_array.snap @@ -1,12 +1,12 @@ --- -created: "2019-01-22T14:44:59.880187500+00:00" -creator: insta@0.4.0 +created: "2019-01-30T20:08:05.185312835+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 --- [9; 10) 'x': &str [18; 19) 'y': isize -[28; 293) '{ ... []; }': () +[28; 324) '{ ... 3]; }': () [38; 39) 'a': [&str] [42; 45) '[x]': [&str] [43; 44) 'x': &str @@ -56,4 +56,10 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs" [260; 263) '"b"': &str [275; 276) 'x': [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 diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 8aa188059..812d1238c 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -366,6 +366,7 @@ fn test(x: &str, y: isize) { let b = [a, ["b"]]; let x: [u8; 0] = []; + let z: &[u8] = &[1, 2, 3]; } "#, ); -- cgit v1.2.3