Skip to content

Commit 4bf32ee

Browse files
bors[bot]Veykril
andauthored
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]>
2 parents 0fac165 + a15b813 commit 4bf32ee

File tree

2 files changed

+139
-32
lines changed

2 files changed

+139
-32
lines changed

crates/hir_ty/src/op.rs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,55 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
99
BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
1010
BinaryOp::Assignment { .. } => TyBuilder::unit(),
1111
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),
1315
TyKind::Scalar(Scalar::Int(_))
14-
| TyKind::Scalar(Scalar::Uint(_))
15-
| TyKind::Scalar(Scalar::Float(_)) => lhs_ty,
16-
TyKind::InferenceVar(_, TyVariableKind::Integer)
17-
| TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
18-
_ => TyKind::Error.intern(&Interner),
16+
| TyKind::Scalar(Scalar::Uint(_))
17+
| TyKind::InferenceVar(_, TyVariableKind::Integer)
18+
) && matches!(
19+
rhs_ty.kind(&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)
1927
}
2028
}
21-
BinaryOp::ArithOp(_) => match rhs_ty.kind(&Interner) {
22-
TyKind::Scalar(Scalar::Int(_))
23-
| TyKind::Scalar(Scalar::Uint(_))
24-
| TyKind::Scalar(Scalar::Float(_)) => rhs_ty,
25-
TyKind::InferenceVar(_, TyVariableKind::Integer)
26-
| TyKind::InferenceVar(_, TyVariableKind::Float) => rhs_ty,
29+
BinaryOp::ArithOp(_) => match (lhs_ty.kind(&Interner), rhs_ty.kind(&Interner)) {
30+
// (int, int) | (uint, uint) | (float, float)
31+
(TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
32+
| (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
33+
| (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::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,
2761
_ => TyKind::Error.intern(&Interner),
2862
},
2963
}

crates/hir_ty/src/tests/traits.rs

Lines changed: 93 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,10 +1919,26 @@ fn closure_1() {
19191919
fn closure_2() {
19201920
check_infer_with_mismatches(
19211921
r#"
1922+
#[lang = "add"]
1923+
pub trait Add<Rhs = Self> {
1924+
type Output;
1925+
fn add(self, rhs: Rhs) -> Self::Output;
1926+
}
1927+
19221928
trait FnOnce<Args> {
19231929
type Output;
19241930
}
19251931
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+
19261942
fn test<F: FnOnce(u32) -> u64>(f: F) {
19271943
f(1);
19281944
let g = |v| v + 1;
@@ -1931,26 +1947,36 @@ fn closure_2() {
19311947
}
19321948
"#,
19331949
expect![[r#"
1934-
72..73 'f': F
1935-
78..154 '{ ...+ v; }': ()
1936-
84..85 'f': F
1937-
84..88 'f(1)': {unknown}
1938-
86..87 '1': i32
1939-
98..99 'g': |u64| -> i32
1940-
102..111 '|v| v + 1': |u64| -> i32
1941-
103..104 'v': u64
1942-
106..107 'v': u64
1943-
106..111 'v + 1': i32
1944-
110..111 '1': i32
1945-
117..118 'g': |u64| -> i32
1946-
117..124 'g(1u64)': i32
1947-
119..123 '1u64': u64
1948-
134..135 'h': |u128| -> u128
1949-
138..151 '|v| 1u128 + v': |u128| -> u128
1950-
139..140 'v': u128
1951-
142..147 '1u128': u128
1952-
142..151 '1u128 + v': u128
1953-
150..151 'v': u128
1950+
72..76 'self': Self
1951+
78..81 'rhs': Rhs
1952+
203..207 'self': u64
1953+
209..212 'rhs': u64
1954+
235..238 '{0}': u64
1955+
236..237 '0': u64
1956+
297..301 'self': u128
1957+
303..306 'rhs': u128
1958+
330..333 '{0}': u128
1959+
331..332 '0': u128
1960+
368..369 'f': F
1961+
374..450 '{ ...+ v; }': ()
1962+
380..381 'f': F
1963+
380..384 'f(1)': {unknown}
1964+
382..383 '1': i32
1965+
394..395 'g': |u64| -> u64
1966+
398..407 '|v| v + 1': |u64| -> u64
1967+
399..400 'v': u64
1968+
402..403 'v': u64
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
19541980
"#]],
19551981
);
19561982
}
@@ -3443,3 +3469,50 @@ pub trait Deserialize {
34433469
"#,
34443470
);
34453471
}
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+
}

0 commit comments

Comments
 (0)