@@ -17,10 +17,8 @@ use super::{
17
17
demand,
18
18
method,
19
19
FnCtxt ,
20
- structurally_resolved_type,
21
20
} ;
22
21
use middle:: def_id:: DefId ;
23
- use middle:: traits;
24
22
use middle:: ty:: { Ty , HasTypeFlags , PreferMutLvalue } ;
25
23
use syntax:: ast;
26
24
use syntax:: parse:: token;
@@ -34,34 +32,24 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
34
32
lhs_expr : & ' tcx hir:: Expr ,
35
33
rhs_expr : & ' tcx hir:: Expr )
36
34
{
37
- let tcx = fcx. ccx . tcx ;
38
-
39
35
check_expr_with_lvalue_pref ( fcx, lhs_expr, PreferMutLvalue ) ;
40
- check_expr ( fcx, rhs_expr) ;
41
36
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) ;
44
41
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) {
46
43
enforce_builtin_binop_types ( fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op) ;
47
44
fcx. write_nil ( expr. id ) ;
48
45
} 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) ;
57
47
}
58
48
59
49
let tcx = fcx. tcx ( ) ;
60
50
if !tcx. expr_is_lval ( lhs_expr) {
61
51
span_err ! ( tcx. sess, lhs_expr. span, E0067 , "invalid left-hand side expression" ) ;
62
52
}
63
-
64
- fcx. require_expr_have_sized_type ( lhs_expr, traits:: AssignmentLhsSized ) ;
65
53
}
66
54
67
55
/// Check a potentially overloaded binary operator.
@@ -95,7 +83,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
95
83
// overloaded. This is the way to be most flexible w/r/t
96
84
// types that get inferred.
97
85
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 ) ;
99
87
100
88
// Supply type inference hints if relevant. Probably these
101
89
// hints should be enforced during select as part of the
@@ -167,14 +155,16 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
167
155
lhs_expr : & ' tcx hir:: Expr ,
168
156
lhs_ty : Ty < ' tcx > ,
169
157
rhs_expr : & ' tcx hir:: Expr ,
170
- op : hir:: BinOp )
158
+ op : hir:: BinOp ,
159
+ is_assign : IsAssign )
171
160
-> ( Ty < ' tcx > , Ty < ' tcx > )
172
161
{
173
- debug ! ( "check_overloaded_binop(expr.id={}, lhs_ty={:?})" ,
162
+ debug ! ( "check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?} )" ,
174
163
expr. id,
175
- lhs_ty) ;
164
+ lhs_ty,
165
+ is_assign) ;
176
166
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 ) ;
178
168
179
169
// NB: As we have not yet type-checked the RHS, we don't have the
180
170
// 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>,
191
181
Err ( ( ) ) => {
192
182
// error types are considered "builtin"
193
183
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
+ }
198
195
}
199
196
fcx. tcx ( ) . types . err
200
197
}
@@ -231,27 +228,51 @@ pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
231
228
}
232
229
}
233
230
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 > ) {
235
235
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
+ }
255
276
}
256
277
}
257
278
}
@@ -362,6 +383,13 @@ impl BinOpCategory {
362
383
}
363
384
}
364
385
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
+
365
393
/// Returns true if this is a built-in arithmetic operation (e.g. u32
366
394
/// + u32, i16x4 == i16x4) and false if these types would have to be
367
395
/// overloaded to be legal. There are two reasons that we distinguish
0 commit comments