diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-04-10 16:53:06 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-04-10 16:53:06 +0100 |
commit | 4bf32eea21d1bbf268951f7f30b1356485bd547b (patch) | |
tree | 403e5a74843cdc8e2c7af1608093dfa31401f86d /crates/hir_ty | |
parent | 0fac165052e7686af1e9cee509e049eb8f2ac5b4 (diff) | |
parent | a15b8136ee3cac8426fa12934f725b161668e9e8 (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]>
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/op.rs | 58 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/traits.rs | 113 |
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() { | |||
1919 | fn closure_2() { | 1919 | fn 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] | ||
3474 | fn bin_op_adt_with_rhs_primitive() { | ||
3475 | check_infer_with_mismatches( | ||
3476 | r#" | ||
3477 | #[lang = "add"] | ||
3478 | pub trait Add<Rhs = Self> { | ||
3479 | type Output; | ||
3480 | fn add(self, rhs: Rhs) -> Self::Output; | ||
3481 | } | ||
3482 | |||
3483 | struct Wrapper(u32); | ||
3484 | impl Add<u32> for Wrapper { | ||
3485 | type Output = Self; | ||
3486 | fn add(self, rhs: u32) -> Wrapper { | ||
3487 | Wrapper(rhs) | ||
3488 | } | ||
3489 | } | ||
3490 | fn 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 | } | ||