Skip to content

Commit

Permalink
Typechecking self-calls in anon objs. Closes #540.
Browse files Browse the repository at this point in the history
  • Loading branch information
lkuper committed Jul 20, 2011
1 parent 64fb39c commit 2eb4762
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 34 deletions.
80 changes: 50 additions & 30 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ type ty_table = hashmap[ast::def_id, ty::t];
tag obj_info {
// Regular objects have a node_id at compile time.
regular_obj(ast::obj_field[], ast::node_id);
// Anonymous objects only have a type at compile time.
anon_obj(ast::obj_field[], ty::t);
// Anonymous objects only have a type at compile time. It's optional
// because not all anonymous objects have a with_obj to attach to.
anon_obj(ast::obj_field[], option::t[ty::sty]);
}

type crate_ctxt = rec(mutable obj_info[] obj_infos, ty::ctxt tcx);
Expand Down Expand Up @@ -2114,7 +2115,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
}
case (ast::expr_self_method(?ident)) {
auto t = ty::mk_nil(fcx.ccx.tcx);
let ty::t this_obj_ty = ty::mk_nil(fcx.ccx.tcx);
let option::t[ty::sty] this_obj_sty =
some(structure_of(fcx, expr.span, ty::mk_nil(fcx.ccx.tcx)));
let option::t[obj_info] this_obj_info = get_obj_info(fcx.ccx);
alt (this_obj_info) {
case (some(?oinfo)) {
Expand All @@ -2128,7 +2130,10 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
// If we're typechecking a self-method on
// a regular object, this lookup should
// succeed.
this_obj_ty = tpt._1;
this_obj_sty =
some(structure_of(fcx,
expr.span,
tpt._1));
}
case (none) {
fcx.ccx.tcx.sess.bug(
Expand All @@ -2137,8 +2142,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
}
}
}
case (anon_obj(_, ?obj_ty)) {
this_obj_ty = obj_ty;
case (anon_obj(_, ?obj_sty)) {
this_obj_sty = obj_sty;
}
}
}
Expand All @@ -2151,15 +2156,21 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
}

// Grab this method's type out of the current object type.
alt (structure_of(fcx, expr.span, this_obj_ty)) {
case (ty::ty_obj(?methods)) {
for (ty::method method in methods) {
if (method.ident == ident) {
t = ty::method_ty_to_fn_ty(fcx.ccx.tcx, method);
alt (this_obj_sty) {
case (some(?sty)) {
alt (sty) {
case (ty::ty_obj(?methods)) {
for (ty::method method in methods) {
if (method.ident == ident) {
t = ty::method_ty_to_fn_ty(fcx.ccx.tcx,
method);
}
}
}
case (_) { fail; }
}
}
case (_) { fail; }
case (none) { }
}
write::ty_only_fixup(fcx, id, t);
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
Expand Down Expand Up @@ -2442,40 +2453,49 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
// Typecheck 'with_obj'. If it exists, it had better have
// object type.
let ty::method[] with_obj_methods = ~[];
auto with_obj_ty = ty::mk_nil(fcx.ccx.tcx);
let ty::t with_obj_ty = ty::mk_nil(fcx.ccx.tcx);
let option::t[ty::sty] with_obj_sty = none;
alt (ao.with_obj) {
case (none) { }
case (some(?e)) {
// If there's a with_obj, we push it onto the
// obj_infos stack so that self-calls can be checked
// within its context later.
check_expr(fcx, e);
with_obj_ty = expr_ty(fcx.ccx.tcx, e);

alt (structure_of(fcx, e.span, with_obj_ty)) {
case (ty::ty_obj(?ms)) {
with_obj_methods = ms;
}
case (_) {
// The user is trying to extend a non-object.
fcx.ccx.tcx.sess.span_fatal(
e.span,
syntax::print::pprust::expr_to_str(e) +
" does not have object type");
with_obj_sty = some(structure_of(fcx, e.span,
with_obj_ty));

alt (with_obj_sty) {
case (none) { }
case (some(?sty)) {
alt (sty) {
case (ty::ty_obj(?ms)) {
with_obj_methods = ms;
}
case (_) {
// The user is trying to extend a
// non-object.
fcx.ccx.tcx.sess.span_fatal(
e.span,
syntax::print::pprust::expr_to_str(e) +
" does not have object type");
}
}
}
}
}
}

log_err "Pushing an anon obj onto the obj_infos stack...";
fn anon_obj_field_to_obj_field(&ast::anon_obj_field f)
fn ao_field_to_o_field(&ast::anon_obj_field f)
-> ast::obj_field {
ret rec(mut=f.mut, ty=f.ty, ident=f.ident, id=f.id);
}
fcx.ccx.obj_infos +=
~[anon_obj(ivec::map(anon_obj_field_to_obj_field,
fields),
with_obj_ty)];
~[anon_obj(ivec::map(ao_field_to_o_field, fields),
with_obj_sty)];

methods += with_obj_methods;

ret methods;
}

Expand Down
2 changes: 0 additions & 2 deletions src/test/run-pass/anon-obj-with-self-call-2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
//xfail-stage0
//xfail-stage1
//xfail-stage2

// Reduced test case for issue #540.
fn main() {
Expand Down
3 changes: 1 addition & 2 deletions src/test/run-pass/anon-obj-with-self-call.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//xfail-stage0
//xfail-stage1
//xfail-stage2

use std;

fn main() {
Expand Down

0 comments on commit 2eb4762

Please sign in to comment.