Introduce separate hir::BinaryOp

Unlike ast::BinOp, it has significantly more structure to it, so it's
easier to, say, handle all assignment-like operations in the same way.
This commit is contained in:
Aleksey Kladov 2019-08-17 17:42:41 +03:00
parent 8919aa8065
commit 7e5a186c1f
4 changed files with 96 additions and 75 deletions

View file

@ -257,7 +257,44 @@ pub enum Expr {
Literal(Literal),
}
pub use ra_syntax::ast::BinOp as BinaryOp;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum BinaryOp {
LogicOp(LogicOp),
ArithOp(ArithOp),
CmpOp(CmpOp),
Assignment { op: Option<ArithOp> },
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum LogicOp {
And,
Or,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum CmpOp {
Equal,
NotEqual,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ArithOp {
Add,
Mul,
Sub,
Div,
Rem,
Shl,
Shr,
BitXor,
BitOr,
BitAnd,
}
pub use ra_syntax::ast::PrefixOp as UnaryOp;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Array {
@ -791,7 +828,7 @@ where
ast::ExprKind::BinExpr(e) => {
let lhs = self.collect_expr_opt(e.lhs());
let rhs = self.collect_expr_opt(e.rhs());
let op = e.op_kind();
let op = e.op_kind().map(BinaryOp::from);
self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
}
ast::ExprKind::TupleExpr(e) => {
@ -1038,6 +1075,42 @@ where
}
}
impl From<ast::BinOp> for BinaryOp {
fn from(ast_op: ast::BinOp) -> Self {
match ast_op {
ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Equal),
ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::NotEqual),
ast::BinOp::LesserEqualTest => BinaryOp::CmpOp(CmpOp::LessOrEqual),
ast::BinOp::GreaterEqualTest => BinaryOp::CmpOp(CmpOp::GreaterOrEqual),
ast::BinOp::LesserTest => BinaryOp::CmpOp(CmpOp::Less),
ast::BinOp::GreaterTest => BinaryOp::CmpOp(CmpOp::Greater),
ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
}
}
}
pub(crate) fn body_with_source_map_query(
db: &impl HirDatabase,
def: DefWithBody,

View file

@ -1265,9 +1265,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Expr::BinaryOp { lhs, rhs, op } => match op {
Some(op) => {
let lhs_expectation = match op {
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => {
Expectation::has_type(Ty::simple(TypeCtor::Bool))
}
BinaryOp::LogicOp(..) => Expectation::has_type(Ty::simple(TypeCtor::Bool)),
_ => Expectation::none(),
};
let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);

View file

@ -1,37 +1,14 @@
use super::{InferTy, Ty, TypeCtor};
use crate::{expr::BinaryOp, ty::ApplicationTy};
use crate::{
expr::{BinaryOp, CmpOp},
ty::ApplicationTy,
};
pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
match op {
BinaryOp::BooleanOr
| BinaryOp::BooleanAnd
| BinaryOp::EqualityTest
| BinaryOp::NegatedEqualityTest
| BinaryOp::LesserEqualTest
| BinaryOp::GreaterEqualTest
| BinaryOp::LesserTest
| BinaryOp::GreaterTest => Ty::simple(TypeCtor::Bool),
BinaryOp::Assignment
| BinaryOp::AddAssign
| BinaryOp::SubAssign
| BinaryOp::DivAssign
| BinaryOp::MulAssign
| BinaryOp::RemAssign
| BinaryOp::ShrAssign
| BinaryOp::ShlAssign
| BinaryOp::BitAndAssign
| BinaryOp::BitOrAssign
| BinaryOp::BitXorAssign => Ty::unit(),
BinaryOp::Addition
| BinaryOp::Subtraction
| BinaryOp::Multiplication
| BinaryOp::Division
| BinaryOp::Remainder
| BinaryOp::LeftShift
| BinaryOp::RightShift
| BinaryOp::BitwiseAnd
| BinaryOp::BitwiseOr
| BinaryOp::BitwiseXor => match rhs_ty {
BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => Ty::simple(TypeCtor::Bool),
BinaryOp::Assignment { .. } => Ty::unit(),
BinaryOp::ArithOp(_) => match rhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int(..) | TypeCtor::Float(..) => rhs_ty,
_ => Ty::Unknown,
@ -39,14 +16,15 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty,
_ => Ty::Unknown,
},
BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown,
}
}
pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
match op {
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::simple(TypeCtor::Bool),
BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty {
BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool),
BinaryOp::Assignment { op: None }
| BinaryOp::CmpOp(CmpOp::Equal)
| BinaryOp::CmpOp(CmpOp::NotEqual) => match lhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int(..)
| TypeCtor::Float(..)
@ -58,37 +36,15 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
_ => Ty::Unknown,
},
BinaryOp::LesserEqualTest
| BinaryOp::GreaterEqualTest
| BinaryOp::LesserTest
| BinaryOp::GreaterTest
| BinaryOp::AddAssign
| BinaryOp::SubAssign
| BinaryOp::DivAssign
| BinaryOp::MulAssign
| BinaryOp::RemAssign
| BinaryOp::ShrAssign
| BinaryOp::ShlAssign
| BinaryOp::BitAndAssign
| BinaryOp::BitOrAssign
| BinaryOp::BitXorAssign
| BinaryOp::Addition
| BinaryOp::Subtraction
| BinaryOp::Multiplication
| BinaryOp::Division
| BinaryOp::Remainder
| BinaryOp::LeftShift
| BinaryOp::RightShift
| BinaryOp::BitwiseAnd
| BinaryOp::BitwiseOr
| BinaryOp::BitwiseXor => match lhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty,
BinaryOp::CmpOp(_) | BinaryOp::Assignment { op: Some(_) } | BinaryOp::ArithOp(_) => {
match lhs_ty {
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty,
_ => Ty::Unknown,
},
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
_ => Ty::Unknown,
},
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
_ => Ty::Unknown,
},
_ => Ty::Unknown,
}
}
}
}

View file

@ -102,10 +102,6 @@ pub enum BinOp {
BitwiseOr,
/// The `&` operator for bitwise AND
BitwiseAnd,
/// The `..` operator for right-open ranges
RangeRightOpen,
/// The `..=` operator for right-closed ranges
RangeRightClosed,
/// The `=` operator for assignment
Assignment,
/// The `+=` operator for assignment after addition
@ -152,8 +148,6 @@ impl ast::BinExpr {
T![^] => BinOp::BitwiseXor,
T![|] => BinOp::BitwiseOr,
T![&] => BinOp::BitwiseAnd,
T![..] => BinOp::RangeRightOpen,
T![..=] => BinOp::RangeRightClosed,
T![=] => BinOp::Assignment,
T![+=] => BinOp::AddAssign,
T![/=] => BinOp::DivAssign,