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 +++++++++++++++++++++++++++++++-------- crates/hir_ty/src/tests/traits.rs | 10 +++---- 2 files changed, 51 insertions(+), 17 deletions(-) (limited to 'crates/hir_ty') 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), }, } diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 1c1aa491d..89b65fb5f 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -1936,14 +1936,14 @@ fn closure_2() { 84..85 'f': F 84..88 'f(1)': {unknown} 86..87 '1': i32 - 98..99 'g': |u64| -> i32 - 102..111 '|v| v + 1': |u64| -> i32 + 98..99 'g': |u64| -> {unknown} + 102..111 '|v| v + 1': |u64| -> {unknown} 103..104 'v': u64 106..107 'v': u64 - 106..111 'v + 1': i32 + 106..111 'v + 1': {unknown} 110..111 '1': i32 - 117..118 'g': |u64| -> i32 - 117..124 'g(1u64)': i32 + 117..118 'g': |u64| -> {unknown} + 117..124 'g(1u64)': {unknown} 119..123 '1u64': u64 134..135 'h': |u128| -> u128 138..151 '|v| 1u128 + v': |u128| -> u128 -- cgit v1.2.3