Skip to content

Commit

Permalink
Merge pull request #70 from baszalmstra/binary_op_typecheck
Browse files Browse the repository at this point in the history
feat: add simple binary operation type checking
  • Loading branch information
baszalmstra authored Dec 30, 2019
2 parents 23a4efc + 518f1d1 commit d048a8f
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 8 deletions.
4 changes: 1 addition & 3 deletions crates/mun_hir/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,7 @@ pub enum Pat {
}

impl Pat {
pub fn walk_child_pats(&self, mut _f: impl FnMut(PatId)) {
unreachable!()
}
pub fn walk_child_pats(&self, mut _f: impl FnMut(PatId)) {}
}

// Queries
Expand Down
10 changes: 9 additions & 1 deletion crates/mun_hir/src/ty/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,15 @@ impl<'a, D: HirDatabase> InferenceResultBuilder<'a, D> {
})
}
};
let rhs_expected = op::binary_op_rhs_expectation(*op, lhs_ty);
let rhs_expected = op::binary_op_rhs_expectation(*op, lhs_ty.clone());
if lhs_ty != Ty::Unknown && rhs_expected == Ty::Unknown {
self.diagnostics
.push(InferenceDiagnostic::CannotApplyBinaryOp {
id: tgt_expr,
lhs: lhs_ty,
rhs: rhs_expected.clone(),
})
}
let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expected));
op::binary_op_return_ty(*op, rhs_ty)
}
Expand Down
36 changes: 32 additions & 4 deletions crates/mun_hir/src/ty/op.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
use crate::{BinaryOp, Ty, TypeCtor};
use crate::{ApplicationTy, BinaryOp, CmpOp, Ty, TypeCtor};

pub(super) fn binary_op_rhs_expectation(_op: BinaryOp, lhs_ty: Ty) -> Ty {
lhs_ty
/// Given a binary operation and the type on the left of that operation, returns the expected type
/// for the right hand side of the operation or `Ty::Unknown` if such an operation is invalid.
pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
match op {
BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool),
BinaryOp::Assignment { op: None } | BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int | TypeCtor::Float | TypeCtor::Bool => lhs_ty,
_ => Ty::Unknown,
},
_ => Ty::Unknown,
},
BinaryOp::CmpOp(CmpOp::Ord { .. })
| BinaryOp::Assignment { op: Some(_) }
| BinaryOp::ArithOp(_) => match lhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int | TypeCtor::Float => lhs_ty,
_ => Ty::Unknown,
},
_ => Ty::Unknown,
},
}
}

/// For a binary operation with the specified type on the right hand side of the operation, return
/// the return type of that operation.
pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
match op {
BinaryOp::ArithOp(_) => rhs_ty,
BinaryOp::ArithOp(_) => match rhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int | TypeCtor::Float => rhs_ty,
_ => Ty::Unknown,
},
_ => Ty::Unknown,
},
BinaryOp::CmpOp(_) | BinaryOp::LogicOp(_) => Ty::simple(TypeCtor::Bool),
BinaryOp::Assignment { .. } => Ty::Empty,
}
Expand Down
13 changes: 13 additions & 0 deletions crates/mun_hir/src/ty/snapshots/tests__invalid_binary_ops.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: crates/mun_hir/src/ty/tests.rs
expression: "fn foo() {\n let b = false;\n let n = 1;\n let _ = b + n; // error: invalid binary operation\n}"
---
[57; 62): cannot apply binary operator
[9; 100) '{ ...tion }': nothing
[19; 20) 'b': bool
[23; 28) 'false': bool
[38; 39) 'n': int
[42; 43) '1': int
[57; 58) 'b': bool
[57; 62) 'b + n': int
[61; 62) 'n': int
13 changes: 13 additions & 0 deletions crates/mun_hir/src/ty/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,19 @@ fn infer_while() {
)
}

#[test]
fn invalid_binary_ops() {
infer_snapshot(
r#"
fn foo() {
let b = false;
let n = 1;
let _ = b + n; // error: invalid binary operation
}
"#,
)
}

fn infer_snapshot(text: &str) {
let text = text.trim().replace("\n ", "\n");
insta::assert_snapshot!(insta::_macro_support::AutoName, infer(&text), &text);
Expand Down

0 comments on commit d048a8f

Please sign in to comment.