From a2b6d3da30020421c97100d7c8699a3b4f8cd6fb Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Mon, 14 Jan 2019 23:15:16 +0100 Subject: Implement rudimentary type inference for unary operators --- crates/ra_hir/src/expr.rs | 9 ++++++--- crates/ra_hir/src/ty.rs | 17 +++++++++++++++-- crates/ra_hir/src/ty/tests.rs | 23 +++++++++++++++++++++++ crates/ra_hir/src/ty/tests/data/unary_op.txt | 28 ++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 crates/ra_hir/src/ty/tests/data/unary_op.txt (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 4e8dc0c54..663338844 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -182,7 +182,7 @@ pub enum Expr { }, UnaryOp { expr: ExprId, - op: Option, + op: UnaryOp, }, BinaryOp { lhs: ExprId, @@ -612,8 +612,11 @@ impl ExprCollector { } ast::ExprKind::PrefixExpr(e) => { let expr = self.collect_expr_opt(e.expr()); - let op = e.op(); - self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) + if let Some(op) = e.op() { + self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) + } else { + self.alloc_expr(Expr::Missing, syntax_ptr) + } } ast::ExprKind::LambdaExpr(e) => { let mut args = Vec::new(); diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index dbbbce795..85d4dc05c 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -1051,7 +1051,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr(*expr, &Expectation::none()); match op { - Some(UnaryOp::Deref) => { + UnaryOp::Deref => { if let Some(derefed_ty) = inner_ty.builtin_deref() { derefed_ty } else { @@ -1059,7 +1059,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Ty::Unknown } } - _ => Ty::Unknown, + UnaryOp::Neg => { + match inner_ty { + Ty::Int(primitive::UncertainIntTy::Unknown) + | Ty::Int(primitive::UncertainIntTy::Signed(..)) + | Ty::Infer(InferTy::IntVar(..)) + | Ty::Infer(InferTy::FloatVar(..)) + | Ty::Float(..) => inner_ty, + // TODO: resolve ops::Neg trait + _ => Ty::Unknown, + } + } + UnaryOp::Not if inner_ty == Ty::Bool => Ty::Bool, + // TODO: resolve ops::Not trait for inner_ty + UnaryOp::Not => Ty::Unknown, } } Expr::BinaryOp { lhs, rhs, op } => match op { diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 929fee04c..5d7bc25cc 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -158,6 +158,29 @@ fn test() { ); } +#[test] +fn infer_unary_op() { + check_inference( + r#" +enum SomeType {} + +fn test(x: SomeType) { + let b = false; + let c = !b; + let a = 100; + let d: i128 = -a; + let e = -100; + let f = !!!true; + -3.14; + -x; + !x; + -"hello"; +} +"#, + "unary_op.txt", + ); +} + #[test] fn infer_backwards() { check_inference( diff --git a/crates/ra_hir/src/ty/tests/data/unary_op.txt b/crates/ra_hir/src/ty/tests/data/unary_op.txt new file mode 100644 index 000000000..203022e82 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/unary_op.txt @@ -0,0 +1,28 @@ +[27; 28) 'x': SomeType +[40; 197) '{ ...lo"; }': () +[50; 51) 'b': bool +[54; 59) 'false': bool +[69; 70) 'c': bool +[73; 75) '!b': bool +[74; 75) 'b': bool +[85; 86) 'a': i128 +[89; 92) '100': i128 +[102; 103) 'd': i128 +[112; 114) '-a': i128 +[113; 114) 'a': i128 +[124; 125) 'e': i32 +[128; 132) '-100': i32 +[129; 132) '100': i32 +[142; 143) 'f': bool +[146; 153) '!!!true': bool +[147; 153) '!!true': bool +[148; 153) '!true': bool +[149; 153) 'true': bool +[159; 164) '-3.14': f64 +[160; 164) '3.14': f64 +[170; 172) '-x': [unknown] +[171; 172) 'x': SomeType +[178; 180) '!x': [unknown] +[179; 180) 'x': SomeType +[186; 194) '-"hello"': [unknown] +[187; 194) '"hello"': &str -- cgit v1.2.3