aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Klaas de Vries <[email protected]>2019-01-05 20:28:30 +0000
committerMarcus Klaas de Vries <[email protected]>2019-01-05 20:28:30 +0000
commit4fc233a02e8dc07619a969400c445ec47c2b1a9d (patch)
treedae33907a38b7c4ed9d1a63ff38803e99f1ae6df
parent3e42a158787955ff9f2e81be43479dbe8f2b1bb6 (diff)
Implement type inference for boolean operators
-rw-r--r--crates/ra_hir/src/ty.rs13
-rw-r--r--crates/ra_hir/src/ty/tests.rs17
-rw-r--r--crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt10
-rw-r--r--crates/ra_syntax/src/ast.rs39
-rw-r--r--crates/ra_syntax/src/ast/generated.rs10
-rw-r--r--crates/ra_syntax/src/grammar.ron7
6 files changed, 92 insertions, 4 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index e33762e0d..718e193f7 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -26,7 +26,7 @@ use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError};
26 26
27use ra_db::{LocalSyntaxPtr, Cancelable}; 27use ra_db::{LocalSyntaxPtr, Cancelable};
28use ra_syntax::{ 28use ra_syntax::{
29 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp}, 29 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp, BinOp},
30 SyntaxNodeRef 30 SyntaxNodeRef
31}; 31};
32 32
@@ -906,7 +906,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
906 } 906 }
907 } 907 }
908 ast::Expr::RangeExpr(_e) => Ty::Unknown, 908 ast::Expr::RangeExpr(_e) => Ty::Unknown,
909 ast::Expr::BinExpr(_e) => Ty::Unknown, 909 ast::Expr::BinExpr(e) => match e.op() {
910 Some(BinOp::BooleanOr)
911 | Some(BinOp::BooleanAnd)
912 | Some(BinOp::EqualityTest)
913 | Some(BinOp::LesserEqualTest)
914 | Some(BinOp::GreaterEqualTest)
915 | Some(BinOp::LesserTest)
916 | Some(BinOp::GreaterTest) => Ty::Bool,
917 _ => Ty::Unknown,
918 },
910 ast::Expr::Literal(_e) => Ty::Unknown, 919 ast::Expr::Literal(_e) => Ty::Unknown,
911 }; 920 };
912 // use a new type variable if we got Ty::Unknown here 921 // use a new type variable if we got Ty::Unknown here
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index fb53fcf0b..97c466890 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -153,6 +153,23 @@ impl S {
153 ); 153 );
154} 154}
155 155
156#[test]
157fn infer_boolean_op() {
158 check_inference(
159 r#"
160fn test() {
161 let x = a && b;
162 let y = true || false;
163 let z = x == y;
164 let h = CONST_1 <= CONST_2;
165
166 10 < 3
167}
168"#,
169 "0008_boolean_op.txt",
170 );
171}
172
156fn infer(content: &str) -> String { 173fn infer(content: &str) -> String {
157 let (db, _, file_id) = MockDatabase::with_single_file(content); 174 let (db, _, file_id) = MockDatabase::with_single_file(content);
158 let source_file = db.source_file(file_id); 175 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt b/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt
new file mode 100644
index 000000000..cc07cdccb
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt
@@ -0,0 +1,10 @@
1[21; 22) 'x': bool
2[68; 69) 'z': bool
3[72; 78) 'x == y': bool
4[45; 58) 'true || false': bool
5[11; 125) '{ ... < 3 }': bool
6[117; 123) '10 < 3': bool
7[88; 89) 'h': bool
8[41; 42) 'y': bool
9[92; 110) 'CONST_...ONST_2': bool
10[25; 31) 'a && b': bool
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index c10169d90..1bce6fa40 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -489,6 +489,45 @@ impl<'a> PrefixExpr<'a> {
489} 489}
490 490
491#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 491#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
492pub enum BinOp {
493 /// The `||` operator for boolean OR
494 BooleanOr,
495 /// The `&&` operator for boolean AND
496 BooleanAnd,
497 /// The `==` operator for equality testing
498 EqualityTest,
499 /// The `<=` operator for lesser-equal testing
500 LesserEqualTest,
501 /// The `>=` operator for greater-equal testing
502 GreaterEqualTest,
503 /// The `<` operator for comparison
504 LesserTest,
505 /// The `>` operator for comparison
506 GreaterTest,
507 // TODO: lots of others
508}
509
510impl<'a> BinExpr<'a> {
511 pub fn op(&self) -> Option<BinOp> {
512 self.syntax()
513 .children()
514 .filter_map(|c| {
515 match c.kind() {
516 PIPEPIPE => Some(BinOp::BooleanOr),
517 AMPAMP => Some(BinOp::BooleanAnd),
518 EQEQ => Some(BinOp::EqualityTest),
519 LTEQ => Some(BinOp::LesserEqualTest),
520 GTEQ => Some(BinOp::GreaterEqualTest),
521 L_ANGLE => Some(BinOp::LesserTest),
522 R_ANGLE => Some(BinOp::GreaterTest),
523 _ => None,
524 }
525 })
526 .next()
527 }
528}
529
530#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
492pub enum SelfParamFlavor { 531pub enum SelfParamFlavor {
493 /// self 532 /// self
494 Owned, 533 Owned,
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 7df6a9c46..ac320606d 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -217,7 +217,15 @@ impl<R: TreeRoot<RaTypes>> BinExprNode<R> {
217} 217}
218 218
219 219
220impl<'a> BinExpr<'a> {} 220impl<'a> BinExpr<'a> {
221 pub fn lhs(self) -> Option<Expr<'a>> {
222 super::child_opt(self)
223 }
224
225 pub fn rhs(self) -> Option<Expr<'a>> {
226 super::child_opt(self)
227 }
228}
221 229
222// BindPat 230// BindPat
223#[derive(Debug, Clone, Copy,)] 231#[derive(Debug, Clone, Copy,)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index c55e9e07a..e59961da3 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -422,7 +422,12 @@ Grammar(
422 "RefExpr": (options: ["Expr"]), 422 "RefExpr": (options: ["Expr"]),
423 "PrefixExpr": (options: ["Expr"]), 423 "PrefixExpr": (options: ["Expr"]),
424 "RangeExpr": (), 424 "RangeExpr": (),
425 "BinExpr": (), 425 "BinExpr": (
426 options: [
427 ["lhs", "Expr"],
428 ["rhs", "Expr"]
429 ]
430 ),
426 "String": (), 431 "String": (),
427 "Byte": (), 432 "Byte": (),
428 "ByteString": (), 433 "ByteString": (),