@@ -17,10 +17,8 @@ use super::{
1717 demand,
1818 method,
1919 FnCtxt ,
20- structurally_resolved_type,
2120} ;
2221use middle:: def_id:: DefId ;
23- use middle:: traits;
2422use middle:: ty:: { Ty , HasTypeFlags , PreferMutLvalue } ;
2523use syntax:: ast;
2624use syntax:: parse:: token;
@@ -34,34 +32,24 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
3432 lhs_expr : & ' tcx hir:: Expr ,
3533 rhs_expr : & ' tcx hir:: Expr )
3634{
37- let tcx = fcx. ccx . tcx ;
38-
3935 check_expr_with_lvalue_pref ( fcx, lhs_expr, PreferMutLvalue ) ;
40- check_expr ( fcx, rhs_expr) ;
4136
42- let lhs_ty = structurally_resolved_type ( fcx, lhs_expr. span , fcx. expr_ty ( lhs_expr) ) ;
43- let rhs_ty = structurally_resolved_type ( fcx, rhs_expr. span , fcx. expr_ty ( rhs_expr) ) ;
37+ let lhs_ty = fcx. resolve_type_vars_if_possible ( fcx. expr_ty ( lhs_expr) ) ;
38+ let ( rhs_ty, return_ty) =
39+ check_overloaded_binop ( fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign :: Yes ) ;
40+ let rhs_ty = fcx. resolve_type_vars_if_possible ( rhs_ty) ;
4441
45- if is_builtin_binop ( lhs_ty, rhs_ty, op) {
42+ if !lhs_ty . is_ty_var ( ) && !rhs_ty . is_ty_var ( ) && is_builtin_binop ( lhs_ty, rhs_ty, op) {
4643 enforce_builtin_binop_types ( fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op) ;
4744 fcx. write_nil ( expr. id ) ;
4845 } else {
49- // error types are considered "builtin"
50- assert ! ( !lhs_ty. references_error( ) || !rhs_ty. references_error( ) ) ;
51- span_err ! ( tcx. sess, lhs_expr. span, E0368 ,
52- "binary assignment operation `{}=` cannot be applied to types `{}` and `{}`" ,
53- hir_util:: binop_to_string( op. node) ,
54- lhs_ty,
55- rhs_ty) ;
56- fcx. write_error ( expr. id ) ;
46+ fcx. write_ty ( expr. id , return_ty) ;
5747 }
5848
5949 let tcx = fcx. tcx ( ) ;
6050 if !tcx. expr_is_lval ( lhs_expr) {
6151 span_err ! ( tcx. sess, lhs_expr. span, E0067 , "invalid left-hand side expression" ) ;
6252 }
63-
64- fcx. require_expr_have_sized_type ( lhs_expr, traits:: AssignmentLhsSized ) ;
6553}
6654
6755/// Check a potentially overloaded binary operator.
@@ -95,7 +83,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
9583 // overloaded. This is the way to be most flexible w/r/t
9684 // types that get inferred.
9785 let ( rhs_ty, return_ty) =
98- check_overloaded_binop ( fcx, expr, lhs_expr, lhs_ty, rhs_expr, op) ;
86+ check_overloaded_binop ( fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign :: No ) ;
9987
10088 // Supply type inference hints if relevant. Probably these
10189 // hints should be enforced during select as part of the
@@ -167,14 +155,16 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
167155 lhs_expr : & ' tcx hir:: Expr ,
168156 lhs_ty : Ty < ' tcx > ,
169157 rhs_expr : & ' tcx hir:: Expr ,
170- op : hir:: BinOp )
158+ op : hir:: BinOp ,
159+ is_assign : IsAssign )
171160 -> ( Ty < ' tcx > , Ty < ' tcx > )
172161{
173- debug ! ( "check_overloaded_binop(expr.id={}, lhs_ty={:?})" ,
162+ debug ! ( "check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?} )" ,
174163 expr. id,
175- lhs_ty) ;
164+ lhs_ty,
165+ is_assign) ;
176166
177- let ( name, trait_def_id) = name_and_trait_def_id ( fcx, op) ;
167+ let ( name, trait_def_id) = name_and_trait_def_id ( fcx, op, is_assign ) ;
178168
179169 // NB: As we have not yet type-checked the RHS, we don't have the
180170 // type at hand. Make a variable to represent it. The whole reason
@@ -191,10 +181,17 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
191181 Err ( ( ) ) => {
192182 // error types are considered "builtin"
193183 if !lhs_ty. references_error ( ) {
194- span_err ! ( fcx. tcx( ) . sess, lhs_expr. span, E0369 ,
195- "binary operation `{}` cannot be applied to type `{}`" ,
196- hir_util:: binop_to_string( op. node) ,
197- lhs_ty) ;
184+ if let IsAssign :: Yes = is_assign {
185+ span_err ! ( fcx. tcx( ) . sess, lhs_expr. span, E0368 ,
186+ "binary assignment operation `{}=` cannot be applied to type `{}`" ,
187+ hir_util:: binop_to_string( op. node) ,
188+ lhs_ty) ;
189+ } else {
190+ span_err ! ( fcx. tcx( ) . sess, lhs_expr. span, E0369 ,
191+ "binary operation `{}` cannot be applied to type `{}`" ,
192+ hir_util:: binop_to_string( op. node) ,
193+ lhs_ty) ;
194+ }
198195 }
199196 fcx. tcx ( ) . types . err
200197 }
@@ -231,27 +228,51 @@ pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
231228 }
232229}
233230
234- fn name_and_trait_def_id ( fcx : & FnCtxt , op : hir:: BinOp ) -> ( & ' static str , Option < DefId > ) {
231+ fn name_and_trait_def_id ( fcx : & FnCtxt ,
232+ op : hir:: BinOp ,
233+ is_assign : IsAssign )
234+ -> ( & ' static str , Option < DefId > ) {
235235 let lang = & fcx. tcx ( ) . lang_items ;
236- match op. node {
237- hir:: BiAdd => ( "add" , lang. add_trait ( ) ) ,
238- hir:: BiSub => ( "sub" , lang. sub_trait ( ) ) ,
239- hir:: BiMul => ( "mul" , lang. mul_trait ( ) ) ,
240- hir:: BiDiv => ( "div" , lang. div_trait ( ) ) ,
241- hir:: BiRem => ( "rem" , lang. rem_trait ( ) ) ,
242- hir:: BiBitXor => ( "bitxor" , lang. bitxor_trait ( ) ) ,
243- hir:: BiBitAnd => ( "bitand" , lang. bitand_trait ( ) ) ,
244- hir:: BiBitOr => ( "bitor" , lang. bitor_trait ( ) ) ,
245- hir:: BiShl => ( "shl" , lang. shl_trait ( ) ) ,
246- hir:: BiShr => ( "shr" , lang. shr_trait ( ) ) ,
247- hir:: BiLt => ( "lt" , lang. ord_trait ( ) ) ,
248- hir:: BiLe => ( "le" , lang. ord_trait ( ) ) ,
249- hir:: BiGe => ( "ge" , lang. ord_trait ( ) ) ,
250- hir:: BiGt => ( "gt" , lang. ord_trait ( ) ) ,
251- hir:: BiEq => ( "eq" , lang. eq_trait ( ) ) ,
252- hir:: BiNe => ( "ne" , lang. eq_trait ( ) ) ,
253- hir:: BiAnd | hir:: BiOr => {
254- fcx. tcx ( ) . sess . span_bug ( op. span , "&& and || are not overloadable" )
236+
237+ if let IsAssign :: Yes = is_assign {
238+ match op. node {
239+ hir:: BiAdd => ( "add_assign" , lang. add_assign_trait ( ) ) ,
240+ hir:: BiSub => ( "sub_assign" , lang. sub_assign_trait ( ) ) ,
241+ hir:: BiMul => ( "mul_assign" , lang. mul_assign_trait ( ) ) ,
242+ hir:: BiDiv => ( "div_assign" , lang. div_assign_trait ( ) ) ,
243+ hir:: BiRem => ( "rem_assign" , lang. rem_assign_trait ( ) ) ,
244+ hir:: BiBitXor => ( "bitxor_assign" , lang. bitxor_assign_trait ( ) ) ,
245+ hir:: BiBitAnd => ( "bitand_assign" , lang. bitand_assign_trait ( ) ) ,
246+ hir:: BiBitOr => ( "bitor_assign" , lang. bitor_assign_trait ( ) ) ,
247+ hir:: BiShl => ( "shl_assign" , lang. shl_assign_trait ( ) ) ,
248+ hir:: BiShr => ( "shr_assign" , lang. shr_assign_trait ( ) ) ,
249+ hir:: BiLt | hir:: BiLe | hir:: BiGe | hir:: BiGt | hir:: BiEq | hir:: BiNe | hir:: BiAnd |
250+ hir:: BiOr => {
251+ fcx. tcx ( ) . sess . span_bug ( op. span , & format ! ( "impossible assignment operation: {}=" ,
252+ hir_util:: binop_to_string( op. node) ) )
253+ }
254+ }
255+ } else {
256+ match op. node {
257+ hir:: BiAdd => ( "add" , lang. add_trait ( ) ) ,
258+ hir:: BiSub => ( "sub" , lang. sub_trait ( ) ) ,
259+ hir:: BiMul => ( "mul" , lang. mul_trait ( ) ) ,
260+ hir:: BiDiv => ( "div" , lang. div_trait ( ) ) ,
261+ hir:: BiRem => ( "rem" , lang. rem_trait ( ) ) ,
262+ hir:: BiBitXor => ( "bitxor" , lang. bitxor_trait ( ) ) ,
263+ hir:: BiBitAnd => ( "bitand" , lang. bitand_trait ( ) ) ,
264+ hir:: BiBitOr => ( "bitor" , lang. bitor_trait ( ) ) ,
265+ hir:: BiShl => ( "shl" , lang. shl_trait ( ) ) ,
266+ hir:: BiShr => ( "shr" , lang. shr_trait ( ) ) ,
267+ hir:: BiLt => ( "lt" , lang. ord_trait ( ) ) ,
268+ hir:: BiLe => ( "le" , lang. ord_trait ( ) ) ,
269+ hir:: BiGe => ( "ge" , lang. ord_trait ( ) ) ,
270+ hir:: BiGt => ( "gt" , lang. ord_trait ( ) ) ,
271+ hir:: BiEq => ( "eq" , lang. eq_trait ( ) ) ,
272+ hir:: BiNe => ( "ne" , lang. eq_trait ( ) ) ,
273+ hir:: BiAnd | hir:: BiOr => {
274+ fcx. tcx ( ) . sess . span_bug ( op. span , "&& and || are not overloadable" )
275+ }
255276 }
256277 }
257278}
@@ -362,6 +383,13 @@ impl BinOpCategory {
362383 }
363384}
364385
386+ /// Whether the binary operation is an assignment (`a += b`), or not (`a + b`)
387+ #[ derive( Clone , Copy , Debug ) ]
388+ enum IsAssign {
389+ No ,
390+ Yes ,
391+ }
392+
365393/// Returns true if this is a built-in arithmetic operation (e.g. u32
366394/// + u32, i16x4 == i16x4) and false if these types would have to be
367395/// overloaded to be legal. There are two reasons that we distinguish
0 commit comments