Skip to content

Commit 3f7ed88

Browse files
authored
Rollup merge of #68129 - varkor:infer-binary-operand-behind-reference, r=nikomatsakis
Correct inference of primitive operand type behind binary operation Fixes #57447. r? @nikomatsakis
2 parents 35071e3 + 0276d7a commit 3f7ed88

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

src/librustc_typeck/check/op.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2525

2626
let ty =
2727
if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
28-
self.enforce_builtin_binop_types(lhs, lhs_ty, rhs, rhs_ty, op);
28+
self.enforce_builtin_binop_types(&lhs.span, lhs_ty, &rhs.span, rhs_ty, op);
2929
self.tcx.mk_unit()
3030
} else {
3131
return_ty
@@ -86,8 +86,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8686
&& !rhs_ty.is_ty_var()
8787
&& is_builtin_binop(lhs_ty, rhs_ty, op)
8888
{
89-
let builtin_return_ty =
90-
self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
89+
let builtin_return_ty = self.enforce_builtin_binop_types(
90+
&lhs_expr.span,
91+
lhs_ty,
92+
&rhs_expr.span,
93+
rhs_ty,
94+
op,
95+
);
9196
self.demand_suptype(expr.span, builtin_return_ty, return_ty);
9297
}
9398

@@ -98,19 +103,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
98103

99104
fn enforce_builtin_binop_types(
100105
&self,
101-
lhs_expr: &'tcx hir::Expr<'tcx>,
106+
lhs_span: &Span,
102107
lhs_ty: Ty<'tcx>,
103-
rhs_expr: &'tcx hir::Expr<'tcx>,
108+
rhs_span: &Span,
104109
rhs_ty: Ty<'tcx>,
105110
op: hir::BinOp,
106111
) -> Ty<'tcx> {
107112
debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
108113

114+
// Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work.
115+
// (See https://github.com/rust-lang/rust/issues/57447.)
116+
let (lhs_ty, rhs_ty) = (deref_ty_if_possible(lhs_ty), deref_ty_if_possible(rhs_ty));
117+
109118
let tcx = self.tcx;
110119
match BinOpCategory::from(op) {
111120
BinOpCategory::Shortcircuit => {
112-
self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
113-
self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty);
121+
self.demand_suptype(*lhs_span, tcx.mk_bool(), lhs_ty);
122+
self.demand_suptype(*rhs_span, tcx.mk_bool(), rhs_ty);
114123
tcx.mk_bool()
115124
}
116125

@@ -121,13 +130,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
121130

122131
BinOpCategory::Math | BinOpCategory::Bitwise => {
123132
// both LHS and RHS and result will have the same type
124-
self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
133+
self.demand_suptype(*rhs_span, lhs_ty, rhs_ty);
125134
lhs_ty
126135
}
127136

128137
BinOpCategory::Comparison => {
129138
// both LHS and RHS and result will have the same type
130-
self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
139+
self.demand_suptype(*rhs_span, lhs_ty, rhs_ty);
131140
tcx.mk_bool()
132141
}
133142
}
@@ -862,6 +871,14 @@ enum Op {
862871
Unary(hir::UnOp, Span),
863872
}
864873

874+
/// Dereferences a single level of immutable referencing.
875+
fn deref_ty_if_possible<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
876+
match ty.kind {
877+
ty::Ref(_, ty, hir::Mutability::Not) => ty,
878+
_ => ty,
879+
}
880+
}
881+
865882
/// Returns `true` if this is a built-in arithmetic operation (e.g., u32
866883
/// + u32, i16x4 == i16x4) and false if these types would have to be
867884
/// overloaded to be legal. There are two reasons that we distinguish
@@ -878,7 +895,11 @@ enum Op {
878895
/// Reason #2 is the killer. I tried for a while to always use
879896
/// overloaded logic and just check the types in constants/codegen after
880897
/// the fact, and it worked fine, except for SIMD types. -nmatsakis
881-
fn is_builtin_binop(lhs: Ty<'_>, rhs: Ty<'_>, op: hir::BinOp) -> bool {
898+
fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool {
899+
// Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work.
900+
// (See https://github.com/rust-lang/rust/issues/57447.)
901+
let (lhs, rhs) = (deref_ty_if_possible(lhs), deref_ty_if_possible(rhs));
902+
882903
match BinOpCategory::from(op) {
883904
BinOpCategory::Shortcircuit => true,
884905

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// check-pass
2+
3+
fn main() {
4+
// Test that we can infer the type of binary operands when
5+
// references are involved, on various types and operators.
6+
let _: u8 = 0 + 0;
7+
let _: u8 = 0 + &0;
8+
let _: u8 = &0 + 0;
9+
let _: u8 = &0 + &0;
10+
11+
let _: f32 = 0.0 + 0.0;
12+
let _: f32 = 0.0 + &0.0;
13+
let _: f32 = &0.0 + 0.0;
14+
let _: f32 = &0.0 + &0.0;
15+
16+
let _: u8 = 0 << 0;
17+
let _: u8 = 0 << &0;
18+
let _: u8 = &0 << 0;
19+
let _: u8 = &0 << &0;
20+
21+
// Test type inference when variable types are indirectly inferred.
22+
let a = 22;
23+
let _: usize = a + &44;
24+
25+
// When we have no expected type, the types of the operands is the default type.
26+
let _ = 0 + 0;
27+
let _ = 0 + &0;
28+
let _ = &0 + 0;
29+
let _ = &0 + &0;
30+
}

0 commit comments

Comments
 (0)