|
10 | 10 |
|
11 | 11 | use super::probe; |
12 | 12 |
|
13 | | -use check::{FnCtxt, callee}; |
| 13 | +use check::{FnCtxt, LvalueOp, callee}; |
14 | 14 | use hir::def_id::DefId; |
15 | 15 | use rustc::ty::subst::Substs; |
16 | 16 | use rustc::traits; |
@@ -433,137 +433,81 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { |
433 | 433 | for (i, &expr) in exprs.iter().rev().enumerate() { |
434 | 434 | debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr); |
435 | 435 |
|
436 | | - // Count autoderefs. We don't need to fix up the autoref - the parent |
437 | | - // expression will fix them up for us. |
438 | | - let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned(); |
439 | | - match adjustment { |
440 | | - Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => { |
441 | | - if autoderefs > 0 { |
442 | | - let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); |
443 | | - autoderef.nth(autoderefs).unwrap_or_else(|| { |
444 | | - span_bug!(expr.span, |
445 | | - "expr was deref-able {} times but now isn't?", |
446 | | - autoderefs); |
447 | | - }); |
448 | | - autoderef.finalize(PreferMutLvalue, expr); |
| 436 | + // Fix up the adjustment. |
| 437 | + let autoderefs = match self.tables.borrow_mut().adjustments.get_mut(&expr.id) { |
| 438 | + Some(&mut Adjustment { |
| 439 | + kind: Adjust::DerefRef { autoderefs, ref mut autoref, .. }, ref mut target |
| 440 | + }) => { |
| 441 | + if let &mut Some(AutoBorrow::Ref(_, ref mut mutbl)) = autoref { |
| 442 | + *mutbl = hir::Mutability::MutMutable; |
| 443 | + *target = match target.sty { |
| 444 | + ty::TyRef(r, ty::TypeAndMut { ty, .. }) => |
| 445 | + self.tcx.mk_ref(r, ty::TypeAndMut { ty, mutbl: *mutbl }), |
| 446 | + _ => span_bug!(expr.span, "AutoBorrow::Ref resulted in non-ref {:?}", |
| 447 | + target) |
| 448 | + }; |
449 | 449 | } |
| 450 | + autoderefs |
450 | 451 | } |
451 | | - Some(_) | None => {} |
| 452 | + Some(_) | None => 0 |
| 453 | + }; |
| 454 | + |
| 455 | + if autoderefs > 0 { |
| 456 | + let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); |
| 457 | + autoderef.nth(autoderefs).unwrap_or_else(|| { |
| 458 | + span_bug!(expr.span, |
| 459 | + "expr was deref-able {} times but now isn't?", |
| 460 | + autoderefs); |
| 461 | + }); |
| 462 | + autoderef.finalize(PreferMutLvalue, expr); |
452 | 463 | } |
453 | 464 |
|
454 | | - // Don't retry the first one or we might infinite loop! |
455 | | - if i == 0 { |
456 | | - continue; |
457 | | - } |
458 | 465 | match expr.node { |
459 | 466 | hir::ExprIndex(ref base_expr, ref index_expr) => { |
460 | | - // If this is an overloaded index, the |
461 | | - // adjustment will include an extra layer of |
462 | | - // autoref because the method is an &self/&mut |
463 | | - // self method. We have to peel it off to get |
464 | | - // the raw adjustment that `try_index_step` |
465 | | - // expects. This is annoying and horrible. We |
466 | | - // ought to recode this routine so it doesn't |
467 | | - // (ab)use the normal type checking paths. |
468 | | - let adj = self.tables.borrow_mut().adjustments.remove(&base_expr.id); |
469 | | - let (autoderefs, unsize, adjusted_base_ty) = match adj { |
470 | | - Some(Adjustment { |
471 | | - kind: Adjust::DerefRef { autoderefs, autoref, unsize }, |
472 | | - target |
473 | | - }) => { |
474 | | - match autoref { |
475 | | - None => { |
476 | | - assert!(!unsize); |
477 | | - } |
478 | | - Some(AutoBorrow::Ref(..)) => {} |
479 | | - Some(_) => { |
480 | | - span_bug!(base_expr.span, |
481 | | - "unexpected adjustment autoref {:?}", |
482 | | - adj); |
483 | | - } |
484 | | - } |
485 | | - |
486 | | - (autoderefs, unsize, if unsize { |
487 | | - target.builtin_deref(false, NoPreference) |
488 | | - .expect("fixup: AutoBorrow::Ref is not &T") |
489 | | - .ty |
490 | | - } else { |
491 | | - let ty = self.node_ty(base_expr.id); |
492 | | - let mut ty = self.shallow_resolve(ty); |
493 | | - let mut method_type = |method_call: ty::MethodCall| { |
494 | | - self.tables.borrow().method_map.get(&method_call).map(|m| { |
495 | | - self.resolve_type_vars_if_possible(&m.ty) |
496 | | - }) |
497 | | - }; |
498 | | - |
499 | | - if !ty.references_error() { |
500 | | - for i in 0..autoderefs { |
501 | | - ty = ty.adjust_for_autoderef(self.tcx, |
502 | | - base_expr.id, |
503 | | - base_expr.span, |
504 | | - i as u32, |
505 | | - &mut method_type); |
506 | | - } |
507 | | - } |
508 | | - |
509 | | - ty |
510 | | - }) |
511 | | - } |
512 | | - None => (0, false, self.node_ty(base_expr.id)), |
513 | | - Some(_) => { |
514 | | - span_bug!(base_expr.span, "unexpected adjustment type"); |
515 | | - } |
516 | | - }; |
517 | | - |
518 | 467 | let index_expr_ty = self.node_ty(index_expr.id); |
519 | | - let adjusted_base_ty = self.resolve_type_vars_if_possible(&adjusted_base_ty); |
520 | | - let index_expr_ty = self.resolve_type_vars_if_possible(&index_expr_ty); |
521 | | - |
522 | | - let result = self.try_index_step(ty::MethodCall::expr(expr.id), |
523 | | - expr, |
524 | | - &base_expr, |
525 | | - adjusted_base_ty, |
526 | | - autoderefs, |
527 | | - unsize, |
528 | | - PreferMutLvalue, |
529 | | - index_expr_ty); |
530 | | - |
531 | | - if let Some((input_ty, return_ty)) = result { |
532 | | - self.demand_suptype(index_expr.span, input_ty, index_expr_ty); |
533 | | - |
534 | | - let expr_ty = self.node_ty(expr.id); |
535 | | - self.demand_suptype(expr.span, expr_ty, return_ty); |
536 | | - } else { |
537 | | - // We could not perform a mutable index. Re-apply the |
538 | | - // immutable index adjustments - borrowck will detect |
539 | | - // this as an error. |
540 | | - if let Some(adjustment) = adjustment { |
541 | | - self.apply_adjustment(expr.id, adjustment); |
542 | | - } |
543 | | - self.tcx.sess.delay_span_bug( |
544 | | - expr.span, "convert_lvalue_derefs_to_mutable failed"); |
545 | | - } |
| 468 | + self.convert_lvalue_op_to_mutable( |
| 469 | + LvalueOp::Index, expr, base_expr, &[index_expr_ty]); |
546 | 470 | } |
547 | 471 | hir::ExprUnary(hir::UnDeref, ref base_expr) => { |
548 | | - // if this is an overloaded deref, then re-evaluate with |
549 | | - // a preference for mut |
550 | | - let method_call = ty::MethodCall::expr(expr.id); |
551 | | - if self.tables.borrow().method_map.contains_key(&method_call) { |
552 | | - self.tables.borrow_mut().adjustments.remove(&base_expr.id); |
553 | | - let method = self.try_overloaded_deref(expr.span, |
554 | | - Some(&base_expr), |
555 | | - self.node_ty(base_expr.id), |
556 | | - PreferMutLvalue); |
557 | | - let ok = method.expect("re-trying deref failed"); |
558 | | - let method = self.register_infer_ok_obligations(ok); |
559 | | - self.tables.borrow_mut().method_map.insert(method_call, method); |
560 | | - } |
| 472 | + self.convert_lvalue_op_to_mutable( |
| 473 | + LvalueOp::Deref, expr, base_expr, &[]); |
561 | 474 | } |
562 | 475 | _ => {} |
563 | 476 | } |
564 | 477 | } |
565 | 478 | } |
566 | 479 |
|
| 480 | + fn convert_lvalue_op_to_mutable(&self, |
| 481 | + op: LvalueOp, |
| 482 | + expr: &hir::Expr, |
| 483 | + base_expr: &hir::Expr, |
| 484 | + arg_tys: &[Ty<'tcx>]) |
| 485 | + { |
| 486 | + debug!("convert_lvalue_op_to_mutable({:?}, {:?}, {:?}, {:?})", |
| 487 | + op, expr, base_expr, arg_tys); |
| 488 | + let method_call = ty::MethodCall::expr(expr.id); |
| 489 | + if !self.tables.borrow().method_map.contains_key(&method_call) { |
| 490 | + debug!("convert_lvalue_op_to_mutable - builtin, nothing to do"); |
| 491 | + return |
| 492 | + } |
| 493 | + |
| 494 | + let base_ty = self.tables.borrow().adjustments.get(&base_expr.id) |
| 495 | + .map_or_else(|| self.node_ty(expr.id), |adj| adj.target); |
| 496 | + let base_ty = self.resolve_type_vars_if_possible(&base_ty); |
| 497 | + |
| 498 | + // Need to deref because overloaded lvalue ops take self by-reference. |
| 499 | + let base_ty = base_ty.builtin_deref(false, NoPreference) |
| 500 | + .expect("lvalue op takes something that is not a ref") |
| 501 | + .ty; |
| 502 | + |
| 503 | + let method = self.try_overloaded_lvalue_op( |
| 504 | + expr.span, None, base_ty, arg_tys, PreferMutLvalue, op); |
| 505 | + let ok = method.expect("re-trying op failed"); |
| 506 | + let method = self.register_infer_ok_obligations(ok); |
| 507 | + debug!("convert_lvalue_op_to_mutable: method={:?}", method); |
| 508 | + self.tables.borrow_mut().method_map.insert(method_call, method); |
| 509 | + } |
| 510 | + |
567 | 511 | /////////////////////////////////////////////////////////////////////////// |
568 | 512 | // MISCELLANY |
569 | 513 |
|
|
0 commit comments