From 93ffed4c1636f257e68f07c6cd6c5f2bb38c74e5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 22 Jul 2011 09:29:01 +0200 Subject: [PATCH] Fix unboxing in alias pass The alias checker would only deref once for autoderef, and only deref boxes. It should now do the right thing. Closes #725. --- src/comp/middle/alias.rs | 42 ++++++++++++++++++++----------- src/test/run-pass/double-unbox.rs | 8 ++++++ 2 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 src/test/run-pass/double-unbox.rs diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index fd03e264d49..fac5db76e58 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -521,20 +521,32 @@ type deref = @rec(bool mut, deref_t kind, ty::t outer_t); // ds=[field(baz),field(bar)]) fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) -> rec(@ast::expr ex, @deref[] ds) { - fn maybe_auto_unbox(&ctx cx, &ty::t t) -> - rec(ty::t t, option::t[deref] d) { - alt (ty::struct(cx.tcx, t)) { - case (ty::ty_box(?mt)) { - ret rec(t=mt.ty, - d=some(@rec(mut=mt.mut != ast::imm, - kind=unbox, - outer_t=t))); + fn maybe_auto_unbox(&ctx cx, ty::t t) -> rec(ty::t t, deref[] ds) { + auto ds = ~[]; + while (true) { + alt (ty::struct(cx.tcx, t)) { + ty::ty_box(?mt) { + ds += ~[@rec(mut=mt.mut != ast::imm, kind=unbox, outer_t=t)]; + t = mt.ty; + } + ty::ty_res(_, ?inner, ?tps) { + ds += ~[@rec(mut=false, kind=unbox, outer_t=t)]; + t = ty::substitute_type_params(cx.tcx, tps, inner); + } + ty::ty_tag(?did, ?tps) { + auto variants = ty::tag_variants(cx.tcx, did); + if (ivec::len(variants) != 1u || + ivec::len(variants.(0).args) != 1u) { + break; + } + ds += ~[@rec(mut=false, kind=unbox, outer_t=t)]; + t = ty::substitute_type_params(cx.tcx, tps, + variants.(0).args.(0)); + } + _ { break; } } - case (_) { ret rec(t=t, d=none); } } - } - fn maybe_push_auto_unbox(&option::t[deref] d, &mutable deref[] ds) { - alt (d) { case (some(?d)) { ds += ~[d]; } case (none) { } } + ret rec(t=t, ds=ds); } let deref[] ds = ~[]; while (true) { @@ -559,7 +571,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) -> case (ty::ty_obj(_)) { } } ds += ~[@rec(mut=mut, kind=field, outer_t=auto_unbox.t)]; - maybe_push_auto_unbox(auto_unbox.d, ds); + ds += auto_unbox.ds; ex = base; } case (ast::expr_index(?base, _)) { @@ -577,7 +589,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) -> outer_t=auto_unbox.t)]; } } - maybe_push_auto_unbox(auto_unbox.d, ds); + ds += auto_unbox.ds; ex = base; } case (ast::expr_unary(?op, ?base)) { @@ -599,7 +611,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) -> } if (autoderef) { auto auto_unbox = maybe_auto_unbox(cx, ty::expr_ty(cx.tcx, ex)); - maybe_push_auto_unbox(auto_unbox.d, ds); + ds += auto_unbox.ds; } ret rec(ex=ex, ds=@ds); } diff --git a/src/test/run-pass/double-unbox.rs b/src/test/run-pass/double-unbox.rs new file mode 100644 index 00000000000..19f3ed32da6 --- /dev/null +++ b/src/test/run-pass/double-unbox.rs @@ -0,0 +1,8 @@ +type quux = rec(int bar); + +fn g(&int i) { } +fn f(@@quux foo) { + g(foo.bar); +} + +fn main() {}