From 252eb78dc3852707969b27b8a30f8844289aa985 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 10 Apr 2021 16:56:32 +0200 Subject: Implement more precise binary op return type prediction --- crates/hir_ty/src/op.rs | 58 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 12 deletions(-) (limited to 'crates/hir_ty/src/op.rs') diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs index 0491c5cb4..0222de2bc 100644 --- a/crates/hir_ty/src/op.rs +++ b/crates/hir_ty/src/op.rs @@ -9,21 +9,55 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), BinaryOp::Assignment { .. } => TyBuilder::unit(), BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { - match lhs_ty.kind(&Interner) { + // all integer combinations are valid here + if matches!( + lhs_ty.kind(&Interner), TyKind::Scalar(Scalar::Int(_)) - | TyKind::Scalar(Scalar::Uint(_)) - | TyKind::Scalar(Scalar::Float(_)) => lhs_ty, - TyKind::InferenceVar(_, TyVariableKind::Integer) - | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, - _ => TyKind::Error.intern(&Interner), + | TyKind::Scalar(Scalar::Uint(_)) + | TyKind::InferenceVar(_, TyVariableKind::Integer) + ) && matches!( + rhs_ty.kind(&Interner), + TyKind::Scalar(Scalar::Int(_)) + | TyKind::Scalar(Scalar::Uint(_)) + | TyKind::InferenceVar(_, TyVariableKind::Integer) + ) { + lhs_ty + } else { + TyKind::Error.intern(&Interner) } } - BinaryOp::ArithOp(_) => match rhs_ty.kind(&Interner) { - TyKind::Scalar(Scalar::Int(_)) - | TyKind::Scalar(Scalar::Uint(_)) - | TyKind::Scalar(Scalar::Float(_)) => rhs_ty, - TyKind::InferenceVar(_, TyVariableKind::Integer) - | TyKind::InferenceVar(_, TyVariableKind::Float) => rhs_ty, + BinaryOp::ArithOp(_) => match (lhs_ty.kind(&Interner), rhs_ty.kind(&Interner)) { + // (int, int) | (uint, uint) | (float, float) + (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_))) + | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_))) + | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty, + // ({int}, int) | ({int}, uint) + (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Int(_))) + | (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Uint(_))) => { + rhs_ty + } + // (int, {int}) | (uint, {int}) + (TyKind::Scalar(Scalar::Int(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) + | (TyKind::Scalar(Scalar::Uint(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) => { + lhs_ty + } + // ({float} | float) + (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => { + rhs_ty + } + // (float, {float}) + (TyKind::Scalar(Scalar::Float(_)), TyKind::InferenceVar(_, TyVariableKind::Float)) => { + lhs_ty + } + // ({int}, {int}) | ({float}, {float}) + ( + TyKind::InferenceVar(_, TyVariableKind::Integer), + TyKind::InferenceVar(_, TyVariableKind::Integer), + ) + | ( + TyKind::InferenceVar(_, TyVariableKind::Float), + TyKind::InferenceVar(_, TyVariableKind::Float), + ) => rhs_ty, _ => TyKind::Error.intern(&Interner), }, } -- cgit v1.2.3