@@ -2247,7 +2247,8 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
2247
2247
base_expr : & ' tcx hir:: Expr ,
2248
2248
base_ty : Ty < ' tcx > ,
2249
2249
idx_ty : Ty < ' tcx > ,
2250
- lvalue_pref : LvaluePreference )
2250
+ lvalue_pref : LvaluePreference ,
2251
+ is_assignment : bool )
2251
2252
-> Option < ( /*index type*/ Ty < ' tcx > , /*element type*/ Ty < ' tcx > ) >
2252
2253
{
2253
2254
// FIXME(#18741) -- this is almost but not quite the same as the
@@ -2262,7 +2263,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
2262
2263
lvalue_pref,
2263
2264
|adj_ty, idx| {
2264
2265
try_index_step ( fcx, MethodCall :: expr ( expr. id ) , expr, base_expr,
2265
- adj_ty, idx, false , lvalue_pref, idx_ty)
2266
+ adj_ty, idx, false , lvalue_pref, idx_ty, is_assignment )
2266
2267
} ) ;
2267
2268
2268
2269
if final_mt. is_some ( ) {
@@ -2274,7 +2275,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
2274
2275
if let ty:: TyArray ( element_ty, _) = ty. sty {
2275
2276
let adjusted_ty = fcx. tcx ( ) . mk_slice ( element_ty) ;
2276
2277
try_index_step ( fcx, MethodCall :: expr ( expr. id ) , expr, base_expr,
2277
- adjusted_ty, autoderefs, true , lvalue_pref, idx_ty)
2278
+ adjusted_ty, autoderefs, true , lvalue_pref, idx_ty, is_assignment )
2278
2279
} else {
2279
2280
None
2280
2281
}
@@ -2292,21 +2293,45 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
2292
2293
autoderefs : usize ,
2293
2294
unsize : bool ,
2294
2295
lvalue_pref : LvaluePreference ,
2295
- index_ty : Ty < ' tcx > )
2296
+ index_ty : Ty < ' tcx > ,
2297
+ is_assignment : bool )
2296
2298
-> Option < ( /*index type*/ Ty < ' tcx > , /*element type*/ Ty < ' tcx > ) >
2297
2299
{
2298
2300
let tcx = fcx. tcx ( ) ;
2299
2301
debug ! ( "try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
2300
- autoderefs={}, unsize={}, index_ty={:?})",
2302
+ autoderefs={}, unsize={}, index_ty={:?}, is_assignment={} )",
2301
2303
expr,
2302
2304
base_expr,
2303
2305
adjusted_ty,
2304
2306
autoderefs,
2305
2307
unsize,
2306
- index_ty) ;
2308
+ index_ty,
2309
+ is_assignment) ;
2307
2310
2308
2311
let input_ty = fcx. infcx ( ) . next_ty_var ( ) ;
2309
2312
2313
+ // Try `IndexAssign` if this is an assignment operation
2314
+ if is_assignment {
2315
+ return tcx. lang_items . index_assign_trait ( ) . and_then ( |trait_did| {
2316
+ let rhs_ty = fcx. infcx ( ) . next_ty_var ( ) ;
2317
+
2318
+ method:: lookup_in_trait_adjusted ( fcx,
2319
+ expr. span ,
2320
+ Some ( & * base_expr) ,
2321
+ token:: intern ( "index_assign" ) ,
2322
+ trait_did,
2323
+ autoderefs,
2324
+ unsize,
2325
+ adjusted_ty,
2326
+ Some ( vec ! [ input_ty, rhs_ty] ) )
2327
+ . map ( |method| {
2328
+ fcx. inh . tables . borrow_mut ( ) . method_map . insert ( method_call, method) ;
2329
+
2330
+ ( input_ty, rhs_ty)
2331
+ } )
2332
+ } )
2333
+ }
2334
+
2310
2335
// First, try built-in indexing.
2311
2336
match ( adjusted_ty. builtin_index ( ) , & index_ty. sty ) {
2312
2337
( Some ( ty) , & ty:: TyUint ( ast:: TyUs ) ) | ( Some ( ty) , & ty:: TyInfer ( ty:: IntVar ( _) ) ) => {
@@ -3445,25 +3470,56 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
3445
3470
fcx. write_ty ( id, fcx. infcx ( ) . next_diverging_ty_var ( ) ) ;
3446
3471
}
3447
3472
hir:: ExprAssign ( ref lhs, ref rhs) => {
3448
- check_expr_with_lvalue_pref ( fcx, & * * lhs, PreferMutLvalue ) ;
3473
+ if let hir:: ExprIndex ( ref base, ref idx) = lhs. node {
3474
+ let lvalue_pref = PreferMutLvalue ;
3475
+
3476
+ check_expr_with_lvalue_pref ( fcx, & * * base, lvalue_pref) ;
3477
+ check_expr ( fcx, & * * idx) ;
3478
+
3479
+ let base_t = structurally_resolved_type ( fcx, lhs. span , fcx. expr_ty ( & * * base) ) ;
3480
+ let idx_t = fcx. expr_ty ( & * * idx) ;
3481
+
3482
+ lookup_indexing ( fcx, expr, base, base_t, idx_t, lvalue_pref, true )
3483
+ . map ( |( index_ty, rhs_ty) | {
3484
+ demand:: eqtype ( fcx, idx. span , index_ty, idx_t) ;
3485
+ check_expr_coercable_to_type ( fcx, & * * rhs, rhs_ty) ;
3486
+ fcx. write_nil ( lhs. id ) ;
3487
+ fcx. write_nil ( id) ;
3488
+
3489
+ if !tcx. sess . features . borrow ( ) . indexed_assignments {
3490
+ tcx. sess . span_err (
3491
+ expr. span ,
3492
+ "overloaded indexed assignments are not stable" ) ;
3493
+ fileline_help ! (
3494
+ tcx. sess,
3495
+ expr. span,
3496
+ "add `#![feature(indexed_assignments)]` to the crate features to \
3497
+ enable") ;
3498
+ }
3499
+ } )
3500
+ } else {
3501
+ None
3502
+ } . unwrap_or_else ( || {
3503
+ check_expr_with_lvalue_pref ( fcx, & * * lhs, PreferMutLvalue ) ;
3449
3504
3450
- let tcx = fcx. tcx ( ) ;
3451
- if !tcx. expr_is_lval ( & * * lhs) {
3452
- span_err ! ( tcx. sess, expr. span, E0070 ,
3453
- "invalid left-hand side expression" ) ;
3454
- }
3505
+ let tcx = fcx. tcx ( ) ;
3506
+ if !tcx. expr_is_lval ( & * * lhs) {
3507
+ span_err ! ( tcx. sess, expr. span, E0070 ,
3508
+ "invalid left-hand side expression" ) ;
3509
+ }
3455
3510
3456
- let lhs_ty = fcx. expr_ty ( & * * lhs) ;
3457
- check_expr_coercable_to_type ( fcx, & * * rhs, lhs_ty) ;
3458
- let rhs_ty = fcx. expr_ty ( & * * rhs) ;
3511
+ let lhs_ty = fcx. expr_ty ( & * * lhs) ;
3512
+ check_expr_coercable_to_type ( fcx, & * * rhs, lhs_ty) ;
3513
+ let rhs_ty = fcx. expr_ty ( & * * rhs) ;
3459
3514
3460
- fcx. require_expr_have_sized_type ( & * * lhs, traits:: AssignmentLhsSized ) ;
3515
+ fcx. require_expr_have_sized_type ( & * * lhs, traits:: AssignmentLhsSized ) ;
3461
3516
3462
- if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
3463
- fcx. write_error ( id) ;
3464
- } else {
3465
- fcx. write_nil ( id) ;
3466
- }
3517
+ if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
3518
+ fcx. write_error ( id) ;
3519
+ } else {
3520
+ fcx. write_nil ( id) ;
3521
+ }
3522
+ } )
3467
3523
}
3468
3524
hir:: ExprIf ( ref cond, ref then_blk, ref opt_else_expr) => {
3469
3525
check_then_else ( fcx, & * * cond, & * * then_blk, opt_else_expr. as_ref ( ) . map ( |e| & * * e) ,
@@ -3666,7 +3722,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
3666
3722
fcx. write_ty ( id, idx_t) ;
3667
3723
} else {
3668
3724
let base_t = structurally_resolved_type ( fcx, expr. span , base_t) ;
3669
- match lookup_indexing ( fcx, expr, base, base_t, idx_t, lvalue_pref) {
3725
+ match lookup_indexing ( fcx, expr, base, base_t, idx_t, lvalue_pref, false ) {
3670
3726
Some ( ( index_ty, element_ty) ) => {
3671
3727
let idx_expr_ty = fcx. expr_ty ( idx) ;
3672
3728
demand:: eqtype ( fcx, expr. span , index_ty, idx_expr_ty) ;
0 commit comments