]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/op.rs
minor: use minicore
[rust.git] / crates / hir_ty / src / op.rs
1 //! Helper functions for binary operator type inference.
2 use chalk_ir::TyVariableKind;
3 use hir_def::expr::{ArithOp, BinaryOp, CmpOp};
4
5 use crate::{Interner, Scalar, Ty, TyBuilder, TyKind};
6
7 pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
8     match op {
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
13             if matches!(
14                 lhs_ty.kind(&Interner),
15                 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
16                     | TyKind::InferenceVar(_, TyVariableKind::Integer)
17             ) && matches!(
18                 rhs_ty.kind(&Interner),
19                 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
20                     | TyKind::InferenceVar(_, TyVariableKind::Integer)
21             ) {
22                 lhs_ty
23             } else {
24                 TyKind::Error.intern(&Interner)
25             }
26         }
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)
33             (
34                 TyKind::InferenceVar(_, TyVariableKind::Integer),
35                 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
36             ) => rhs_ty,
37             // (int, {int}) | (uint, {int})
38             (
39                 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
40                 TyKind::InferenceVar(_, TyVariableKind::Integer),
41             ) => lhs_ty,
42             // ({float} | float)
43             (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => {
44                 rhs_ty
45             }
46             // (float, {float})
47             (TyKind::Scalar(Scalar::Float(_)), TyKind::InferenceVar(_, TyVariableKind::Float)) => {
48                 lhs_ty
49             }
50             // ({int}, {int}) | ({float}, {float})
51             (
52                 TyKind::InferenceVar(_, TyVariableKind::Integer),
53                 TyKind::InferenceVar(_, TyVariableKind::Integer),
54             )
55             | (
56                 TyKind::InferenceVar(_, TyVariableKind::Float),
57                 TyKind::InferenceVar(_, TyVariableKind::Float),
58             ) => rhs_ty,
59             _ => TyKind::Error.intern(&Interner),
60         },
61     }
62 }
63
64 pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
65     match op {
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),
72         },
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),
80         },
81     }
82 }