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) | BinaryOp::ArithOp(ArithOp::Shr) => {
12 // all integer combinations are valid here
14 lhs_ty.kind(&Interner),
15 TyKind::Scalar(Scalar::Int(_))
16 | TyKind::Scalar(Scalar::Uint(_))
17 | TyKind::InferenceVar(_, TyVariableKind::Integer)
19 rhs_ty.kind(&Interner),
20 TyKind::Scalar(Scalar::Int(_))
21 | TyKind::Scalar(Scalar::Uint(_))
22 | TyKind::InferenceVar(_, TyVariableKind::Integer)
26 TyKind::Error.intern(&Interner)
29 BinaryOp::ArithOp(_) => match (lhs_ty.kind(&Interner), rhs_ty.kind(&Interner)) {
30 // (int, int) | (uint, uint) | (float, float)
31 (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
32 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
33 | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty,
34 // ({int}, int) | ({int}, uint)
35 (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Int(_)))
36 | (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Uint(_))) => {
39 // (int, {int}) | (uint, {int})
40 (TyKind::Scalar(Scalar::Int(_)), TyKind::InferenceVar(_, TyVariableKind::Integer))
41 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) => {
45 (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => {
49 (TyKind::Scalar(Scalar::Float(_)), TyKind::InferenceVar(_, TyVariableKind::Float)) => {
52 // ({int}, {int}) | ({float}, {float})
54 TyKind::InferenceVar(_, TyVariableKind::Integer),
55 TyKind::InferenceVar(_, TyVariableKind::Integer),
58 TyKind::InferenceVar(_, TyVariableKind::Float),
59 TyKind::InferenceVar(_, TyVariableKind::Float),
61 _ => TyKind::Error.intern(&Interner),
66 pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
68 BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
69 BinaryOp::Assignment { op: None } => lhs_ty,
70 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) {
71 TyKind::Scalar(_) | TyKind::Str => lhs_ty,
72 TyKind::InferenceVar(_, TyVariableKind::Integer)
73 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
74 _ => TyKind::Error.intern(&Interner),
76 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => {
77 TyKind::Error.intern(&Interner)
79 BinaryOp::CmpOp(CmpOp::Ord { .. })
80 | BinaryOp::Assignment { op: Some(_) }
81 | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) {
82 TyKind::Scalar(Scalar::Int(_))
83 | TyKind::Scalar(Scalar::Uint(_))
84 | TyKind::Scalar(Scalar::Float(_)) => lhs_ty,
85 TyKind::InferenceVar(_, TyVariableKind::Integer)
86 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
87 _ => TyKind::Error.intern(&Interner),