aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-04-10 16:53:06 +0100
committerGitHub <[email protected]>2021-04-10 16:53:06 +0100
commit4bf32eea21d1bbf268951f7f30b1356485bd547b (patch)
tree403e5a74843cdc8e2c7af1608093dfa31401f86d
parent0fac165052e7686af1e9cee509e049eb8f2ac5b4 (diff)
parenta15b8136ee3cac8426fa12934f725b161668e9e8 (diff)
Merge #8457
8457: Implement more precise binary op return type heuristic r=flodiebold a=Veykril Should fix #7150 Co-authored-by: Lukas Wirth <[email protected]>
-rw-r--r--crates/hir_ty/src/op.rs58
-rw-r--r--crates/hir_ty/src/tests/traits.rs113
2 files changed, 139 insertions, 32 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 {
9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
10 BinaryOp::Assignment { .. } => TyBuilder::unit(), 10 BinaryOp::Assignment { .. } => TyBuilder::unit(),
11 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { 11 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => {
12 match lhs_ty.kind(&Interner) { 12 // all integer combinations are valid here
13 if matches!(
14 lhs_ty.kind(&Interner),
13 TyKind::Scalar(Scalar::Int(_)) 15 TyKind::Scalar(Scalar::Int(_))
14 | TyKind::Scalar(Scalar::Uint(_)) 16 | TyKind::Scalar(Scalar::Uint(_))
15 | TyKind::Scalar(Scalar::Float(_)) => lhs_ty, 17 | TyKind::InferenceVar(_, TyVariableKind::Integer)
16 TyKind::InferenceVar(_, TyVariableKind::Integer) 18 ) && matches!(
17 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, 19 rhs_ty.kind(&Interner),
18 _ => TyKind::Error.intern(&Interner), 20 TyKind::Scalar(Scalar::Int(_))
21 | TyKind::Scalar(Scalar::Uint(_))
22 | TyKind::InferenceVar(_, TyVariableKind::Integer)
23 ) {
24 lhs_ty
25 } else {
26 TyKind::Error.intern(&Interner)
19 } 27 }
20 } 28 }
21 BinaryOp::ArithOp(_) => match rhs_ty.kind(&Interner) { 29 BinaryOp::ArithOp(_) => match (lhs_ty.kind(&Interner), rhs_ty.kind(&Interner)) {
22 TyKind::Scalar(Scalar::Int(_)) 30 // (int, int) | (uint, uint) | (float, float)
23 | TyKind::Scalar(Scalar::Uint(_)) 31 (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
24 | TyKind::Scalar(Scalar::Float(_)) => rhs_ty, 32 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
25 TyKind::InferenceVar(_, TyVariableKind::Integer) 33 | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty,
26 | TyKind::InferenceVar(_, TyVariableKind::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(_))) => {
37 rhs_ty
38 }
39 // (int, {int}) | (uint, {int})
40 (TyKind::Scalar(Scalar::Int(_)), TyKind::InferenceVar(_, TyVariableKind::Integer))
41 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) => {
42 lhs_ty
43 }
44 // ({float} | float)
45 (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => {
46 rhs_ty
47 }
48 // (float, {float})
49 (TyKind::Scalar(Scalar::Float(_)), TyKind::InferenceVar(_, TyVariableKind::Float)) => {
50 lhs_ty
51 }
52 // ({int}, {int}) | ({float}, {float})
53 (
54 TyKind::InferenceVar(_, TyVariableKind::Integer),
55 TyKind::InferenceVar(_, TyVariableKind::Integer),
56 )
57 | (
58 TyKind::InferenceVar(_, TyVariableKind::Float),
59 TyKind::InferenceVar(_, TyVariableKind::Float),
60 ) => rhs_ty,
27 _ => TyKind::Error.intern(&Interner), 61 _ => TyKind::Error.intern(&Interner),
28 }, 62 },
29 } 63 }
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 1c1aa491d..1879dbc78 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1919,10 +1919,26 @@ fn closure_1() {
1919fn closure_2() { 1919fn closure_2() {
1920 check_infer_with_mismatches( 1920 check_infer_with_mismatches(
1921 r#" 1921 r#"
1922 #[lang = "add"]
1923 pub trait Add<Rhs = Self> {
1924 type Output;
1925 fn add(self, rhs: Rhs) -> Self::Output;
1926 }
1927
1922 trait FnOnce<Args> { 1928 trait FnOnce<Args> {
1923 type Output; 1929 type Output;
1924 } 1930 }
1925 1931
1932 impl Add for u64 {
1933 type Output = Self;
1934 fn add(self, rhs: u64) -> Self::Output {0}
1935 }
1936
1937 impl Add for u128 {
1938 type Output = Self;
1939 fn add(self, rhs: u128) -> Self::Output {0}
1940 }
1941
1926 fn test<F: FnOnce(u32) -> u64>(f: F) { 1942 fn test<F: FnOnce(u32) -> u64>(f: F) {
1927 f(1); 1943 f(1);
1928 let g = |v| v + 1; 1944 let g = |v| v + 1;
@@ -1931,26 +1947,36 @@ fn closure_2() {
1931 } 1947 }
1932 "#, 1948 "#,
1933 expect![[r#" 1949 expect![[r#"
1934 72..73 'f': F 1950 72..76 'self': Self
1935 78..154 '{ ...+ v; }': () 1951 78..81 'rhs': Rhs
1936 84..85 'f': F 1952 203..207 'self': u64
1937 84..88 'f(1)': {unknown} 1953 209..212 'rhs': u64
1938 86..87 '1': i32 1954 235..238 '{0}': u64
1939 98..99 'g': |u64| -> i32 1955 236..237 '0': u64
1940 102..111 '|v| v + 1': |u64| -> i32 1956 297..301 'self': u128
1941 103..104 'v': u64 1957 303..306 'rhs': u128
1942 106..107 'v': u64 1958 330..333 '{0}': u128
1943 106..111 'v + 1': i32 1959 331..332 '0': u128
1944 110..111 '1': i32 1960 368..369 'f': F
1945 117..118 'g': |u64| -> i32 1961 374..450 '{ ...+ v; }': ()
1946 117..124 'g(1u64)': i32 1962 380..381 'f': F
1947 119..123 '1u64': u64 1963 380..384 'f(1)': {unknown}
1948 134..135 'h': |u128| -> u128 1964 382..383 '1': i32
1949 138..151 '|v| 1u128 + v': |u128| -> u128 1965 394..395 'g': |u64| -> u64
1950 139..140 'v': u128 1966 398..407 '|v| v + 1': |u64| -> u64
1951 142..147 '1u128': u128 1967 399..400 'v': u64
1952 142..151 '1u128 + v': u128 1968 402..403 'v': u64
1953 150..151 'v': u128 1969 402..407 'v + 1': u64
1970 406..407 '1': u64
1971 413..414 'g': |u64| -> u64
1972 413..420 'g(1u64)': u64
1973 415..419 '1u64': u64
1974 430..431 'h': |u128| -> u128
1975 434..447 '|v| 1u128 + v': |u128| -> u128
1976 435..436 'v': u128
1977 438..443 '1u128': u128
1978 438..447 '1u128 + v': u128
1979 446..447 'v': u128
1954 "#]], 1980 "#]],
1955 ); 1981 );
1956} 1982}
@@ -3443,3 +3469,50 @@ pub trait Deserialize {
3443 "#, 3469 "#,
3444 ); 3470 );
3445} 3471}
3472
3473#[test]
3474fn bin_op_adt_with_rhs_primitive() {
3475 check_infer_with_mismatches(
3476 r#"
3477#[lang = "add"]
3478pub trait Add<Rhs = Self> {
3479 type Output;
3480 fn add(self, rhs: Rhs) -> Self::Output;
3481}
3482
3483struct Wrapper(u32);
3484impl Add<u32> for Wrapper {
3485 type Output = Self;
3486 fn add(self, rhs: u32) -> Wrapper {
3487 Wrapper(rhs)
3488 }
3489}
3490fn main(){
3491 let wrapped = Wrapper(10);
3492 let num: u32 = 2;
3493 let res = wrapped + num;
3494
3495}"#,
3496 expect![[r#"
3497 72..76 'self': Self
3498 78..81 'rhs': Rhs
3499 192..196 'self': Wrapper
3500 198..201 'rhs': u32
3501 219..247 '{ ... }': Wrapper
3502 229..236 'Wrapper': Wrapper(u32) -> Wrapper
3503 229..241 'Wrapper(rhs)': Wrapper
3504 237..240 'rhs': u32
3505 259..345 '{ ...um; }': ()
3506 269..276 'wrapped': Wrapper
3507 279..286 'Wrapper': Wrapper(u32) -> Wrapper
3508 279..290 'Wrapper(10)': Wrapper
3509 287..289 '10': u32
3510 300..303 'num': u32
3511 311..312 '2': u32
3512 322..325 'res': Wrapper
3513 328..335 'wrapped': Wrapper
3514 328..341 'wrapped + num': Wrapper
3515 338..341 'num': u32
3516 "#]],
3517 )
3518}