Some progress on issue #540.
This commit is contained in:
parent
a14e5e7046
commit
18162d3261
2 changed files with 76 additions and 46 deletions
|
@ -52,7 +52,13 @@ export check_crate;
|
||||||
|
|
||||||
type ty_table = hashmap[ast::def_id, ty::t];
|
type ty_table = hashmap[ast::def_id, ty::t];
|
||||||
|
|
||||||
type obj_info = rec(ast::obj_field[] obj_fields, ast::node_id this_obj);
|
// Used for typechecking the methods of an object.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
type crate_ctxt = rec(mutable obj_info[] obj_infos, ty::ctxt tcx);
|
type crate_ctxt = rec(mutable obj_info[] obj_infos, ty::ctxt tcx);
|
||||||
|
|
||||||
|
@ -622,8 +628,8 @@ mod collect {
|
||||||
ret ty_of_fn_decl(cx, convert, f, fn_info.decl, fn_info.proto,
|
ret ty_of_fn_decl(cx, convert, f, fn_info.decl, fn_info.proto,
|
||||||
tps, some(local_def(it.id)));
|
tps, some(local_def(it.id)));
|
||||||
}
|
}
|
||||||
case (ast::item_obj(?obj_info, ?tps, _)) {
|
case (ast::item_obj(?ob, ?tps, _)) {
|
||||||
auto t_obj = ty_of_obj(cx, it.ident, obj_info, tps);
|
auto t_obj = ty_of_obj(cx, it.ident, ob, tps);
|
||||||
cx.tcx.tcache.insert(local_def(it.id), t_obj);
|
cx.tcx.tcache.insert(local_def(it.id), t_obj);
|
||||||
ret t_obj;
|
ret t_obj;
|
||||||
}
|
}
|
||||||
|
@ -1196,12 +1202,23 @@ fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
|
||||||
// Add object fields, if any.
|
// Add object fields, if any.
|
||||||
alt (get_obj_info(ccx)) {
|
alt (get_obj_info(ccx)) {
|
||||||
case (option::some(?oinfo)) {
|
case (option::some(?oinfo)) {
|
||||||
for (ast::obj_field f in oinfo.obj_fields) {
|
alt (oinfo) {
|
||||||
|
case (regular_obj(?obj_fields, _)) {
|
||||||
|
for (ast::obj_field f in obj_fields) {
|
||||||
auto field_ty = ty::node_id_to_type(ccx.tcx, f.id);
|
auto field_ty = ty::node_id_to_type(ccx.tcx, f.id);
|
||||||
assign(ccx.tcx, vb, locals, local_names, nvi, f.id,
|
assign(ccx.tcx, vb, locals, local_names, nvi, f.id,
|
||||||
f.ident, some(field_ty));
|
f.ident, some(field_ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case (anon_obj(?obj_fields, _)) {
|
||||||
|
for (ast::obj_field f in obj_fields) {
|
||||||
|
auto field_ty = ty::node_id_to_type(ccx.tcx, f.id);
|
||||||
|
assign(ccx.tcx, vb, locals, local_names, nvi, f.id,
|
||||||
|
f.ident, some(field_ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case (option::none) {/* no fields */ }
|
case (option::none) {/* no fields */ }
|
||||||
}
|
}
|
||||||
// Add formal parameters.
|
// Add formal parameters.
|
||||||
|
@ -2095,16 +2112,30 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
|
||||||
let ty::t this_obj_ty = ty::mk_nil(fcx.ccx.tcx);
|
let ty::t this_obj_ty = ty::mk_nil(fcx.ccx.tcx);
|
||||||
let option::t[obj_info] this_obj_info = get_obj_info(fcx.ccx);
|
let option::t[obj_info] this_obj_info = get_obj_info(fcx.ccx);
|
||||||
alt (this_obj_info) {
|
alt (this_obj_info) {
|
||||||
case (
|
case (some(?oinfo)) {
|
||||||
// If we're inside a current object, grab its type.
|
alt (oinfo) {
|
||||||
some(?obj_info)) {
|
case (regular_obj(_, ?obj_id)) {
|
||||||
// FIXME: In the case of anonymous objects with methods
|
auto did = local_def(obj_id);
|
||||||
// containing self-calls, this lookup fails because
|
// Try looking up the current object in the type
|
||||||
// obj_info.this_obj is not in the type cache
|
// cache.
|
||||||
|
alt (fcx.ccx.tcx.tcache.find(did)) {
|
||||||
this_obj_ty =
|
case (some(?tpt)) {
|
||||||
ty::lookup_item_type(fcx.ccx.tcx,
|
// If we're typechecking a self-method on
|
||||||
local_def(obj_info.this_obj))._1;
|
// a regular object, this lookup should
|
||||||
|
// succeed.
|
||||||
|
this_obj_ty = tpt._1;
|
||||||
|
}
|
||||||
|
case (none) {
|
||||||
|
fcx.ccx.tcx.sess.bug(
|
||||||
|
"didn't find " + int::str(did._1) +
|
||||||
|
" in type cache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (anon_obj(_, ?obj_ty)) {
|
||||||
|
this_obj_ty = obj_ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case (none) {
|
case (none) {
|
||||||
// Shouldn't happen.
|
// Shouldn't happen.
|
||||||
|
@ -2353,36 +2384,21 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case (ast::expr_anon_obj(?anon_obj, ?tps)) {
|
case (ast::expr_anon_obj(?ao, ?tps)) {
|
||||||
// TODO: We probably need to do more work here to be able to
|
|
||||||
// handle additional methods that use 'self'
|
|
||||||
|
|
||||||
// We're entering an object, so gather up the info we need.
|
|
||||||
|
|
||||||
let ast::anon_obj_field[] fields = ~[];
|
let ast::anon_obj_field[] fields = ~[];
|
||||||
alt (anon_obj.fields) {
|
alt (ao.fields) {
|
||||||
case (none) { }
|
case (none) { }
|
||||||
case (some(?v)) { fields = v; }
|
case (some(?v)) { fields = v; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is duplicated between here and trans -- it should
|
|
||||||
// appear in one place
|
|
||||||
fn anon_obj_field_to_obj_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 +=
|
|
||||||
~[rec(obj_fields=ivec::map(anon_obj_field_to_obj_field,
|
|
||||||
fields),
|
|
||||||
this_obj=id)];
|
|
||||||
|
|
||||||
// FIXME: These next three functions are largely ripped off from
|
// FIXME: These next three functions are largely ripped off from
|
||||||
// similar ones in collect::. Is there a better way to do this?
|
// similar ones in collect::. Is there a better way to do this?
|
||||||
fn ty_of_arg(@crate_ctxt ccx, &ast::arg a) -> ty::arg {
|
fn ty_of_arg(@crate_ctxt ccx, &ast::arg a) -> ty::arg {
|
||||||
auto ty_mode = ast_mode_to_mode(a.mode);
|
auto ty_mode = ast_mode_to_mode(a.mode);
|
||||||
ret rec(mode=ty_mode, ty=ast_ty_to_ty_crate(ccx, a.ty));
|
ret rec(mode=ty_mode, ty=ast_ty_to_ty_crate(ccx, a.ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_of_method(@crate_ctxt ccx, &@ast::method m) -> ty::method {
|
fn ty_of_method(@crate_ctxt ccx, &@ast::method m) -> ty::method {
|
||||||
auto convert = bind ast_ty_to_ty_crate(ccx, _);
|
auto convert = bind ast_ty_to_ty_crate(ccx, _);
|
||||||
|
|
||||||
|
@ -2402,14 +2418,17 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
|
||||||
inputs=inputs, output=output, cf=m.node.meth.decl.cf,
|
inputs=inputs, output=output, cf=m.node.meth.decl.cf,
|
||||||
constrs=out_constrs);
|
constrs=out_constrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_anon_obj_method_types(@fn_ctxt fcx,
|
fn get_anon_obj_method_types(@fn_ctxt fcx,
|
||||||
&ast::anon_obj anon_obj)
|
&ast::anon_obj ao,
|
||||||
|
&ast::anon_obj_field[] fields,
|
||||||
|
&ast::ty_param[] tps)
|
||||||
-> ty::method[] {
|
-> ty::method[] {
|
||||||
|
|
||||||
let ty::method[] methods = ~[];
|
let ty::method[] methods = ~[];
|
||||||
|
|
||||||
// Outer methods.
|
// Outer methods.
|
||||||
for (@ast::method m in anon_obj.methods) {
|
for (@ast::method m in ao.methods) {
|
||||||
methods += ~[ty_of_method(fcx.ccx, m)];
|
methods += ~[ty_of_method(fcx.ccx, m)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2418,11 +2437,12 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
|
||||||
// Typecheck 'with_obj'. If it exists, it had better have
|
// Typecheck 'with_obj'. If it exists, it had better have
|
||||||
// object type.
|
// object type.
|
||||||
let ty::method[] with_obj_methods = ~[];
|
let ty::method[] with_obj_methods = ~[];
|
||||||
alt (anon_obj.with_obj) {
|
auto with_obj_ty = ty::mk_nil(fcx.ccx.tcx);
|
||||||
|
alt (ao.with_obj) {
|
||||||
case (none) { }
|
case (none) { }
|
||||||
case (some(?e)) {
|
case (some(?e)) {
|
||||||
check_expr(fcx, e);
|
check_expr(fcx, e);
|
||||||
auto with_obj_ty = expr_ty(fcx.ccx.tcx, e);
|
with_obj_ty = expr_ty(fcx.ccx.tcx, e);
|
||||||
|
|
||||||
alt (structure_of(fcx, e.span, with_obj_ty)) {
|
alt (structure_of(fcx, e.span, with_obj_ty)) {
|
||||||
case (ty::ty_obj(?ms)) {
|
case (ty::ty_obj(?ms)) {
|
||||||
|
@ -2438,12 +2458,24 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_err "Pushing an anon obj onto the obj_infos stack...";
|
||||||
|
fn anon_obj_field_to_obj_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)];
|
||||||
|
|
||||||
methods += with_obj_methods;
|
methods += with_obj_methods;
|
||||||
|
|
||||||
ret methods;
|
ret methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto method_types = get_anon_obj_method_types(fcx, anon_obj);
|
auto method_types = get_anon_obj_method_types(fcx, ao,
|
||||||
|
fields, tps);
|
||||||
auto ot = ty::mk_obj(fcx.ccx.tcx, ty::sort_methods(method_types));
|
auto ot = ty::mk_obj(fcx.ccx.tcx, ty::sort_methods(method_types));
|
||||||
|
|
||||||
write::ty_only_fixup(fcx, id, ot);
|
write::ty_only_fixup(fcx, id, ot);
|
||||||
|
@ -2451,15 +2483,15 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
|
||||||
// collect::convert for regular objects.)
|
// collect::convert for regular objects.)
|
||||||
|
|
||||||
auto i = 0u;
|
auto i = 0u;
|
||||||
while (i < ivec::len[@ast::method](anon_obj.methods)) {
|
while (i < ivec::len[@ast::method](ao.methods)) {
|
||||||
write::ty_only(fcx.ccx.tcx, anon_obj.methods.(i).node.id,
|
write::ty_only(fcx.ccx.tcx, ao.methods.(i).node.id,
|
||||||
ty::method_ty_to_fn_ty(fcx.ccx.tcx,
|
ty::method_ty_to_fn_ty(fcx.ccx.tcx,
|
||||||
method_types.(i)));
|
method_types.(i)));
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typecheck the methods.
|
// Typecheck the methods.
|
||||||
for (@ast::method method in anon_obj.methods) {
|
for (@ast::method method in ao.methods) {
|
||||||
check_method(fcx.ccx, method);
|
check_method(fcx.ccx, method);
|
||||||
}
|
}
|
||||||
next_ty_var(fcx);
|
next_ty_var(fcx);
|
||||||
|
@ -2654,8 +2686,8 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
|
||||||
}
|
}
|
||||||
case (ast::item_obj(?ob, _, _)) {
|
case (ast::item_obj(?ob, _, _)) {
|
||||||
// We're entering an object, so gather up the info we need.
|
// We're entering an object, so gather up the info we need.
|
||||||
|
ccx.obj_infos += ~[regular_obj(ob.fields, it.id)];
|
||||||
|
|
||||||
ccx.obj_infos += ~[rec(obj_fields=ob.fields, this_obj=it.id)];
|
|
||||||
// Typecheck the methods.
|
// Typecheck the methods.
|
||||||
for (@ast::method method in ob.methods) {
|
for (@ast::method method in ob.methods) {
|
||||||
check_method(ccx, method);
|
check_method(ccx, method);
|
||||||
|
|
|
@ -19,8 +19,6 @@ fn main() {
|
||||||
// Extending an object with a new method that contains a simple
|
// Extending an object with a new method that contains a simple
|
||||||
// self-call. Adding support for this is issue #540.
|
// self-call. Adding support for this is issue #540.
|
||||||
|
|
||||||
// Right now, this fails with a failed lookup in a hashmap; not
|
|
||||||
// sure where, but I think it might be during typeck.
|
|
||||||
auto my_b = obj {
|
auto my_b = obj {
|
||||||
fn baz() -> int {
|
fn baz() -> int {
|
||||||
ret self.foo();
|
ret self.foo();
|
||||||
|
|
Loading…
Reference in a new issue