|
1 |
| - |
2 | 1 | import syntax::{ast, ast_util};
|
3 | 2 | import ast::{ident, fn_ident, node_id};
|
4 | 3 | import syntax::codemap::span;
|
@@ -640,11 +639,141 @@ fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat)
|
640 | 639 | ret set;
|
641 | 640 | }
|
642 | 641 |
|
643 |
| -// Wraps the expr_root in mutbl.rs to also handle roots that exist through |
644 |
| -// return-by-reference |
| 642 | +enum deref_t { unbox(bool), field, index, } |
| 643 | + |
| 644 | +type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t}; |
| 645 | + |
645 | 646 | fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
|
646 | 647 | -> {ex: @ast::expr, mutbl: option<unsafe_ty>} {
|
647 |
| - let base_root = mutbl::expr_root_(cx.tcx, none, ex, autoderef); |
| 648 | + |
| 649 | + fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} { |
| 650 | + let mut ds = [], t = t; |
| 651 | + loop { |
| 652 | + alt ty::get(t).struct { |
| 653 | + ty::ty_box(mt) | ty::ty_uniq(mt) | ty::ty_rptr(_, mt) { |
| 654 | + ds += [@{mutbl: mt.mutbl == ast::m_mutbl, |
| 655 | + kind: unbox(false), |
| 656 | + outer_t: t}]; |
| 657 | + t = mt.ty; |
| 658 | + } |
| 659 | + ty::ty_res(_, inner, substs) { |
| 660 | + ds += [@{mutbl: false, kind: unbox(false), outer_t: t}]; |
| 661 | + t = ty::subst(tcx, substs, inner); |
| 662 | + } |
| 663 | + ty::ty_enum(did, substs) { |
| 664 | + let variants = ty::enum_variants(tcx, did); |
| 665 | + if vec::len(*variants) != 1u || |
| 666 | + vec::len(variants[0].args) != 1u { |
| 667 | + break; |
| 668 | + } |
| 669 | + ds += [@{mutbl: false, kind: unbox(false), outer_t: t}]; |
| 670 | + t = ty::subst(tcx, substs, variants[0].args[0]); |
| 671 | + } |
| 672 | + _ { break; } |
| 673 | + } |
| 674 | + } |
| 675 | + ret {t: t, ds: ds}; |
| 676 | + } |
| 677 | + |
| 678 | + fn expr_root_(tcx: ty::ctxt, ctor_self: option<node_id>, |
| 679 | + ex: @ast::expr, autoderef: bool) -> {ex: @ast::expr, |
| 680 | + ds: @[deref]} { |
| 681 | + let mut ds: [deref] = [], ex = ex; |
| 682 | + loop { |
| 683 | + alt copy ex.node { |
| 684 | + ast::expr_field(base, ident, _) { |
| 685 | + let auto_unbox = |
| 686 | + maybe_auto_unbox(tcx, ty::expr_ty(tcx, base)); |
| 687 | + let mut is_mutbl = false; |
| 688 | + alt ty::get(auto_unbox.t).struct { |
| 689 | + ty::ty_rec(fields) { |
| 690 | + for fields.each {|fld| |
| 691 | + if str::eq(ident, fld.ident) { |
| 692 | + is_mutbl = fld.mt.mutbl == ast::m_mutbl; |
| 693 | + break; |
| 694 | + } |
| 695 | + } |
| 696 | + } |
| 697 | + ty::ty_class(did, _) { |
| 698 | + util::common::log_expr(*base); |
| 699 | + let in_self = alt ctor_self { |
| 700 | + some(selfid) { |
| 701 | + alt tcx.def_map.find(base.id) { |
| 702 | + some(ast::def_self(slfid)) { slfid == selfid } |
| 703 | + _ { false } |
| 704 | + } |
| 705 | + } |
| 706 | + none { false } |
| 707 | + }; |
| 708 | + for ty::lookup_class_fields(tcx, did).each {|fld| |
| 709 | + if str::eq(ident, fld.ident) { |
| 710 | + is_mutbl = fld.mutability == ast::class_mutable |
| 711 | + || in_self; // all fields can be mutated |
| 712 | + // in the ctor |
| 713 | + break; |
| 714 | + } |
| 715 | + } |
| 716 | + } |
| 717 | + _ {} |
| 718 | + } |
| 719 | + ds += [@{mutbl:is_mutbl, kind:field, outer_t:auto_unbox.t}]; |
| 720 | + ds += auto_unbox.ds; |
| 721 | + ex = base; |
| 722 | + } |
| 723 | + ast::expr_index(base, _) { |
| 724 | + let auto_unbox = |
| 725 | + maybe_auto_unbox(tcx, ty::expr_ty(tcx, base)); |
| 726 | + alt ty::get(auto_unbox.t).struct { |
| 727 | + ty::ty_evec(mt, _) | |
| 728 | + ty::ty_vec(mt) { |
| 729 | + ds += |
| 730 | + [@{mutbl: mt.mutbl == ast::m_mutbl, |
| 731 | + kind: index, |
| 732 | + outer_t: auto_unbox.t}]; |
| 733 | + } |
| 734 | + ty::ty_estr(_) | |
| 735 | + ty::ty_str { |
| 736 | + ds += [@{mutbl:false, kind:index, outer_t:auto_unbox.t}]; |
| 737 | + } |
| 738 | + _ { break; } |
| 739 | + } |
| 740 | + ds += auto_unbox.ds; |
| 741 | + ex = base; |
| 742 | + } |
| 743 | + ast::expr_unary(op, base) { |
| 744 | + if op == ast::deref { |
| 745 | + let base_t = ty::expr_ty(tcx, base); |
| 746 | + let mut is_mutbl = false, ptr = false; |
| 747 | + alt ty::get(base_t).struct { |
| 748 | + ty::ty_box(mt) { is_mutbl = mt.mutbl==ast::m_mutbl; } |
| 749 | + ty::ty_uniq(mt) { is_mutbl = mt.mutbl==ast::m_mutbl; } |
| 750 | + ty::ty_res(_, _, _) { } |
| 751 | + ty::ty_enum(_, _) { } |
| 752 | + ty::ty_ptr(mt) | ty::ty_rptr(_, mt) { |
| 753 | + is_mutbl = mt.mutbl==ast::m_mutbl; |
| 754 | + ptr = true; |
| 755 | + } |
| 756 | + _ { |
| 757 | + tcx.sess.span_bug( |
| 758 | + base.span, |
| 759 | + "ill-typed base expression in deref"); } |
| 760 | + } |
| 761 | + ds += [@{mutbl: is_mutbl, kind: unbox(ptr && is_mutbl), |
| 762 | + outer_t: base_t}]; |
| 763 | + ex = base; |
| 764 | + } else { break; } |
| 765 | + } |
| 766 | + _ { break; } |
| 767 | + } |
| 768 | + } |
| 769 | + if autoderef { |
| 770 | + let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, ex)); |
| 771 | + ds += auto_unbox.ds; |
| 772 | + } |
| 773 | + ret {ex: ex, ds: @ds}; |
| 774 | + } |
| 775 | + |
| 776 | + let base_root = expr_root_(cx.tcx, none, ex, autoderef); |
648 | 777 | let mut unsafe_ty = none;
|
649 | 778 | for vec::each(*base_root.ds) {|d|
|
650 | 779 | if d.mutbl { unsafe_ty = some(contains(d.outer_t)); break; }
|
|
0 commit comments