@@ -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
0 commit comments