|
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