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(-) 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 From d9554c258b9c1cc2a328572e5671bc2a87729b18 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 10 Apr 2021 17:16:35 +0200 Subject: Add manual ops::Add impls to test::traits::closure_2 --- crates/hir_ty/src/tests/traits.rs | 66 +++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 89b65fb5f..c93ff91ee 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -1919,10 +1919,26 @@ fn closure_1() { fn closure_2() { check_infer_with_mismatches( r#" + #[lang = "add"] + pub trait Add { + type Output; + fn add(self, rhs: Rhs) -> Self::Output; + } + trait FnOnce { type Output; } + impl Add for u64 { + type Output = Self; + fn add(self, rhs: u64) -> Self::Output {0} + } + + impl Add for u128 { + type Output = Self; + fn add(self, rhs: u128) -> Self::Output {0} + } + fn test u64>(f: F) { f(1); let g = |v| v + 1; @@ -1931,26 +1947,36 @@ fn closure_2() { } "#, expect![[r#" - 72..73 'f': F - 78..154 '{ ...+ v; }': () - 84..85 'f': F - 84..88 'f(1)': {unknown} - 86..87 '1': 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': {unknown} - 110..111 '1': 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 - 139..140 'v': u128 - 142..147 '1u128': u128 - 142..151 '1u128 + v': u128 - 150..151 'v': u128 + 72..76 'self': Self + 78..81 'rhs': Rhs + 203..207 'self': u64 + 209..212 'rhs': u64 + 235..238 '{0}': u64 + 236..237 '0': u64 + 297..301 'self': u128 + 303..306 'rhs': u128 + 330..333 '{0}': u128 + 331..332 '0': u128 + 368..369 'f': F + 374..450 '{ ...+ v; }': () + 380..381 'f': F + 380..384 'f(1)': {unknown} + 382..383 '1': i32 + 394..395 'g': |u64| -> u64 + 398..407 '|v| v + 1': |u64| -> u64 + 399..400 'v': u64 + 402..403 'v': u64 + 402..407 'v + 1': u64 + 406..407 '1': u64 + 413..414 'g': |u64| -> u64 + 413..420 'g(1u64)': u64 + 415..419 '1u64': u64 + 430..431 'h': |u128| -> u128 + 434..447 '|v| 1u128 + v': |u128| -> u128 + 435..436 'v': u128 + 438..443 '1u128': u128 + 438..447 '1u128 + v': u128 + 446..447 'v': u128 "#]], ); } -- cgit v1.2.3 From a15b8136ee3cac8426fa12934f725b161668e9e8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 10 Apr 2021 17:52:24 +0200 Subject: Add test for binary op return ty with adt --- crates/hir_ty/src/tests/traits.rs | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index c93ff91ee..1879dbc78 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -3469,3 +3469,50 @@ pub trait Deserialize { "#, ); } + +#[test] +fn bin_op_adt_with_rhs_primitive() { + check_infer_with_mismatches( + r#" +#[lang = "add"] +pub trait Add { + type Output; + fn add(self, rhs: Rhs) -> Self::Output; +} + +struct Wrapper(u32); +impl Add for Wrapper { + type Output = Self; + fn add(self, rhs: u32) -> Wrapper { + Wrapper(rhs) + } +} +fn main(){ + let wrapped = Wrapper(10); + let num: u32 = 2; + let res = wrapped + num; + +}"#, + expect![[r#" + 72..76 'self': Self + 78..81 'rhs': Rhs + 192..196 'self': Wrapper + 198..201 'rhs': u32 + 219..247 '{ ... }': Wrapper + 229..236 'Wrapper': Wrapper(u32) -> Wrapper + 229..241 'Wrapper(rhs)': Wrapper + 237..240 'rhs': u32 + 259..345 '{ ...um; }': () + 269..276 'wrapped': Wrapper + 279..286 'Wrapper': Wrapper(u32) -> Wrapper + 279..290 'Wrapper(10)': Wrapper + 287..289 '10': u32 + 300..303 'num': u32 + 311..312 '2': u32 + 322..325 'res': Wrapper + 328..335 'wrapped': Wrapper + 328..341 'wrapped + num': Wrapper + 338..341 'num': u32 + "#]], + ) +} -- cgit v1.2.3