Skip to content

Commit 93ffed4

Browse files
committed
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.
1 parent 1348a38 commit 93ffed4

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

src/comp/middle/alias.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -521,20 +521,32 @@ type deref = @rec(bool mut, deref_t kind, ty::t outer_t);
521521
// ds=[field(baz),field(bar)])
522522
fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
523523
rec(@ast::expr ex, @deref[] ds) {
524-
fn maybe_auto_unbox(&ctx cx, &ty::t t) ->
525-
rec(ty::t t, option::t[deref] d) {
526-
alt (ty::struct(cx.tcx, t)) {
527-
case (ty::ty_box(?mt)) {
528-
ret rec(t=mt.ty,
529-
d=some(@rec(mut=mt.mut != ast::imm,
530-
kind=unbox,
531-
outer_t=t)));
524+
fn maybe_auto_unbox(&ctx cx, ty::t t) -> rec(ty::t t, deref[] ds) {
525+
auto ds = ~[];
526+
while (true) {
527+
alt (ty::struct(cx.tcx, t)) {
528+
ty::ty_box(?mt) {
529+
ds += ~[@rec(mut=mt.mut != ast::imm, kind=unbox, outer_t=t)];
530+
t = mt.ty;
531+
}
532+
ty::ty_res(_, ?inner, ?tps) {
533+
ds += ~[@rec(mut=false, kind=unbox, outer_t=t)];
534+
t = ty::substitute_type_params(cx.tcx, tps, inner);
535+
}
536+
ty::ty_tag(?did, ?tps) {
537+
auto variants = ty::tag_variants(cx.tcx, did);
538+
if (ivec::len(variants) != 1u ||
539+
ivec::len(variants.(0).args) != 1u) {
540+
break;
541+
}
542+
ds += ~[@rec(mut=false, kind=unbox, outer_t=t)];
543+
t = ty::substitute_type_params(cx.tcx, tps,
544+
variants.(0).args.(0));
545+
}
546+
_ { break; }
532547
}
533-
case (_) { ret rec(t=t, d=none); }
534548
}
535-
}
536-
fn maybe_push_auto_unbox(&option::t[deref] d, &mutable deref[] ds) {
537-
alt (d) { case (some(?d)) { ds += ~[d]; } case (none) { } }
549+
ret rec(t=t, ds=ds);
538550
}
539551
let deref[] ds = ~[];
540552
while (true) {
@@ -559,7 +571,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
559571
case (ty::ty_obj(_)) { }
560572
}
561573
ds += ~[@rec(mut=mut, kind=field, outer_t=auto_unbox.t)];
562-
maybe_push_auto_unbox(auto_unbox.d, ds);
574+
ds += auto_unbox.ds;
563575
ex = base;
564576
}
565577
case (ast::expr_index(?base, _)) {
@@ -577,7 +589,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
577589
outer_t=auto_unbox.t)];
578590
}
579591
}
580-
maybe_push_auto_unbox(auto_unbox.d, ds);
592+
ds += auto_unbox.ds;
581593
ex = base;
582594
}
583595
case (ast::expr_unary(?op, ?base)) {
@@ -599,7 +611,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
599611
}
600612
if (autoderef) {
601613
auto auto_unbox = maybe_auto_unbox(cx, ty::expr_ty(cx.tcx, ex));
602-
maybe_push_auto_unbox(auto_unbox.d, ds);
614+
ds += auto_unbox.ds;
603615
}
604616
ret rec(ex=ex, ds=@ds);
605617
}

src/test/run-pass/double-unbox.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
type quux = rec(int bar);
2+
3+
fn g(&int i) { }
4+
fn f(@@quux foo) {
5+
g(foo.bar);
6+
}
7+
8+
fn main() {}

0 commit comments

Comments
 (0)