1 //! Helper functions for binary operator type inference.
2 use chalk_ir::TyVariableKind;
3 use hir_def::expr::{ArithOp, BinaryOp, CmpOp};
5 use crate::{Interner, Scalar, Ty, TyBuilder, TyKind};
7 pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
10 BinaryOp::Assignment { .. } => TyBuilder::unit(),
11 BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
12 // all integer combinations are valid here
14 lhs_ty.kind(&Interner),
15 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
16 | TyKind::InferenceVar(_, TyVariableKind::Integer)
18 rhs_ty.kind(&Interner),
19 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
20 | TyKind::InferenceVar(_, TyVariableKind::Integer)
24 TyKind::Error.intern(&Interner)
27 BinaryOp::ArithOp(_) => match (lhs_ty.kind(&Interner), rhs_ty.kind(&Interner)) {
28 // (int, int) | (uint, uint) | (float, float)
29 (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
30 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
31 | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty,
32 // ({int}, int) | ({int}, uint)
34 TyKind::InferenceVar(_, TyVariableKind::Integer),
35 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
37 // (int, {int}) | (uint, {int})
39 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
40 TyKind::InferenceVar(_, TyVariableKind::Integer),
43 (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => {
47 (TyKind::Scalar(Scalar::Float(_)), TyKind::InferenceVar(_, TyVariableKind::Float)) => {
50 // ({int}, {int}) | ({float}, {float})
52 TyKind::InferenceVar(_, TyVariableKind::Integer),
53 TyKind::InferenceVar(_, TyVariableKind::Integer),
56 TyKind::InferenceVar(_, TyVariableKind::Float),
57 TyKind::InferenceVar(_, TyVariableKind::Float),
59 _ => TyKind::Error.intern(&Interner),
64 pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
66 BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
67 BinaryOp::Assignment { op: None } => lhs_ty,
68 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) {
69 TyKind::Scalar(_) | TyKind::Str => lhs_ty,
70 TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
71 _ => TyKind::Error.intern(&Interner),
73 BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => TyKind::Error.intern(&Interner),
74 BinaryOp::CmpOp(CmpOp::Ord { .. })
75 | BinaryOp::Assignment { op: Some(_) }
76 | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) {
77 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
78 TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
79 _ => TyKind::Error.intern(&Interner),