Merge remote-tracking branch 'graydon/master' into typestate_4
This commit is contained in:
commit
467b938ea8
11 changed files with 281 additions and 28 deletions
|
@ -55,6 +55,8 @@ const int obj_field_box = 1;
|
||||||
const int obj_body_elt_tydesc = 0;
|
const int obj_body_elt_tydesc = 0;
|
||||||
const int obj_body_elt_typarams = 1;
|
const int obj_body_elt_typarams = 1;
|
||||||
const int obj_body_elt_fields = 2;
|
const int obj_body_elt_fields = 2;
|
||||||
|
const int obj_body_elt_with_obj = 3; /* The base object to which an anonymous
|
||||||
|
* object is attached */
|
||||||
|
|
||||||
const int fn_field_code = 0;
|
const int fn_field_code = 0;
|
||||||
const int fn_field_box = 1;
|
const int fn_field_box = 1;
|
||||||
|
|
|
@ -379,7 +379,7 @@ type anon_obj = rec(
|
||||||
option::t[vec[obj_field]] fields,
|
option::t[vec[obj_field]] fields,
|
||||||
vec[@method] methods,
|
vec[@method] methods,
|
||||||
// with_obj: the original object being extended, if it exists.
|
// with_obj: the original object being extended, if it exists.
|
||||||
option::t[ident] with_obj);
|
option::t[@expr] with_obj);
|
||||||
|
|
||||||
type _mod = rec(vec[@view_item] view_items,
|
type _mod = rec(vec[@view_item] view_items,
|
||||||
vec[@item] items);
|
vec[@item] items);
|
||||||
|
|
|
@ -820,13 +820,13 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
let vec[@ast::method] meths = [];
|
let vec[@ast::method] meths = [];
|
||||||
let option::t[ast::ident] with_obj = none[ast::ident];
|
let option::t[@ast::expr] with_obj = none[@ast::expr];
|
||||||
|
|
||||||
expect(p, token::LBRACE);
|
expect(p, token::LBRACE);
|
||||||
|
|
||||||
while (p.peek() != token::RBRACE) {
|
while (p.peek() != token::RBRACE) {
|
||||||
if (eat_word(p, "with")) {
|
if (eat_word(p, "with")) {
|
||||||
with_obj = some[ast::ident](parse_ident(p));
|
with_obj = some[@ast::expr](parse_expr(p));
|
||||||
} else {
|
} else {
|
||||||
vec::push[@ast::method](meths,
|
vec::push[@ast::method](meths,
|
||||||
parse_method(p));
|
parse_method(p));
|
||||||
|
|
|
@ -336,7 +336,7 @@ type ast_fold[ENV] =
|
||||||
(fn(&ENV e,
|
(fn(&ENV e,
|
||||||
&option::t[vec[ast::obj_field]] fields,
|
&option::t[vec[ast::obj_field]] fields,
|
||||||
&vec[@ast::method] methods,
|
&vec[@ast::method] methods,
|
||||||
&option::t[ident] with_obj)
|
&option::t[@ast::expr] with_obj)
|
||||||
-> ast::anon_obj) fold_anon_obj,
|
-> ast::anon_obj) fold_anon_obj,
|
||||||
|
|
||||||
// Env updates.
|
// Env updates.
|
||||||
|
@ -1001,11 +1001,11 @@ fn fold_anon_obj[ENV](&ENV env, &ast_fold[ENV] fld, &ast::anon_obj ob)
|
||||||
}
|
}
|
||||||
|
|
||||||
// with_obj
|
// with_obj
|
||||||
let option::t[ast::ident] with_obj = none[ast::ident];
|
let option::t[@ast::expr] with_obj = none[@ast::expr];
|
||||||
alt (ob.with_obj) {
|
alt (ob.with_obj) {
|
||||||
case (none[ast::ident]) { }
|
case (none[@ast::expr]) { }
|
||||||
case (some[ast::ident](?i)) {
|
case (some[@ast::expr](?e)) {
|
||||||
with_obj = some[ast::ident](i);
|
with_obj = some[@ast::expr](fold_expr(env, fld, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,7 +1665,8 @@ fn identity_fold_obj[ENV](&ENV e,
|
||||||
fn identity_fold_anon_obj[ENV](&ENV e,
|
fn identity_fold_anon_obj[ENV](&ENV e,
|
||||||
&option::t[vec[ast::obj_field]] fields,
|
&option::t[vec[ast::obj_field]] fields,
|
||||||
&vec[@ast::method] methods,
|
&vec[@ast::method] methods,
|
||||||
&option::t[ident] with_obj) -> ast::anon_obj {
|
&option::t[@ast::expr] with_obj)
|
||||||
|
-> ast::anon_obj {
|
||||||
ret rec(fields=fields, methods=methods, with_obj=with_obj);
|
ret rec(fields=fields, methods=methods, with_obj=with_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4576,7 +4576,8 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
|
||||||
}
|
}
|
||||||
case (_) {
|
case (_) {
|
||||||
cx.fcx.lcx.ccx.sess.span_unimpl(e.span,
|
cx.fcx.lcx.ccx.sess.span_unimpl(e.span,
|
||||||
"expr variant in trans_lval");
|
"expr variant in trans_lval: "
|
||||||
|
+ util::common::expr_to_str(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fail;
|
fail;
|
||||||
|
@ -5547,6 +5548,10 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
|
||||||
ret trans_spawn(cx, dom, name, func, args, ann);
|
ret trans_spawn(cx, dom, name, func, args, ann);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
|
||||||
|
ret trans_anon_obj(cx, e.span, anon_obj, tps, odid, ann);
|
||||||
|
}
|
||||||
|
|
||||||
case (_) {
|
case (_) {
|
||||||
// The expression is an lvalue. Fall through.
|
// The expression is an lvalue. Fall through.
|
||||||
}
|
}
|
||||||
|
@ -6111,6 +6116,77 @@ fn recv_val(&@block_ctxt cx, ValueRef lhs, &@ast::expr rhs,
|
||||||
ret res(bcx, lhs);
|
ret res(bcx, lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Suppose we create an anonymous object my_b from a regular object a:
|
||||||
|
|
||||||
|
obj a() {
|
||||||
|
fn foo() -> int {
|
||||||
|
ret 2;
|
||||||
|
}
|
||||||
|
fn bar() -> int {
|
||||||
|
ret self.foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto my_a = a();
|
||||||
|
auto my_b = obj { fn baz() -> int { ret self.foo() } with my_a };
|
||||||
|
|
||||||
|
Here we're extending the my_a object with an additional method baz, creating
|
||||||
|
an object my_b. Since it's an object, my_b is a pair of a vtable pointer and
|
||||||
|
a body pointer:
|
||||||
|
|
||||||
|
my_b: [vtbl* | body*]
|
||||||
|
|
||||||
|
my_b's vtable has entries for foo, bar, and baz, whereas my_a's vtable has
|
||||||
|
only foo and bar. my_b's 3-entry vtable consists of two forwarding functions
|
||||||
|
and one real method.
|
||||||
|
|
||||||
|
my_b's body just contains the pair a: [ a_vtable | a_body ], wrapped up with
|
||||||
|
any additional fields that my_b added. None were added, so my_b is just the
|
||||||
|
wrapped inner object.
|
||||||
|
|
||||||
|
*/
|
||||||
|
fn trans_anon_obj(&@block_ctxt cx, &ast::span sp,
|
||||||
|
&ast::anon_obj anon_obj,
|
||||||
|
&vec[ast::ty_param] ty_params,
|
||||||
|
&ast::obj_def_ids oid,
|
||||||
|
&ast::ann ann) -> result {
|
||||||
|
|
||||||
|
let option::t[result] with_obj_val = none[result];
|
||||||
|
alt (anon_obj.with_obj) {
|
||||||
|
case (none[@ast::expr]) { }
|
||||||
|
case (some[@ast::expr](?e)) {
|
||||||
|
// Translating with_obj returns a pointer to a 2-word value. We
|
||||||
|
// want to allocate space for this value in our outer object, then
|
||||||
|
// copy it into the outer object.
|
||||||
|
with_obj_val = some[result](trans_expr(cx, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the anon obj's additional fields, if any exist, translate object
|
||||||
|
// constructor arguments to function arguments.
|
||||||
|
let option::t[vec[ast::obj_field]] addtl_fields
|
||||||
|
= none[vec[ast::obj_field]];
|
||||||
|
let vec[ast::arg] addtl_fn_args = [];
|
||||||
|
|
||||||
|
alt (anon_obj.fields) {
|
||||||
|
case (none[vec[ast::obj_field]]) { }
|
||||||
|
case (some[vec[ast::obj_field]](?fields)) {
|
||||||
|
for (ast::obj_field f in fields) {
|
||||||
|
addtl_fn_args += [rec(mode=ast::alias, ty=f.ty,
|
||||||
|
ident=f.ident, id=f.id)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: everything else.
|
||||||
|
|
||||||
|
cx.fcx.lcx.ccx.sess.unimpl("support for anonymous objects");
|
||||||
|
fail;
|
||||||
|
}
|
||||||
|
|
||||||
fn init_local(&@block_ctxt cx, &@ast::local local) -> result {
|
fn init_local(&@block_ctxt cx, &@ast::local local) -> result {
|
||||||
|
|
||||||
// Make a note to drop this slot on the way out.
|
// Make a note to drop this slot on the way out.
|
||||||
|
|
|
@ -132,6 +132,7 @@ import front::ast::expr_assert;
|
||||||
import front::ast::expr_cast;
|
import front::ast::expr_cast;
|
||||||
import front::ast::expr_for;
|
import front::ast::expr_for;
|
||||||
import front::ast::expr_for_each;
|
import front::ast::expr_for_each;
|
||||||
|
import front::ast::expr_anon_obj;
|
||||||
import front::ast::stmt_decl;
|
import front::ast::stmt_decl;
|
||||||
import front::ast::stmt_expr;
|
import front::ast::stmt_expr;
|
||||||
import front::ast::block;
|
import front::ast::block;
|
||||||
|
@ -556,6 +557,17 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
|
||||||
find_pre_post_expr(fcx, expanded);
|
find_pre_post_expr(fcx, expanded);
|
||||||
copy_pre_post(fcx.ccx, a, expanded);
|
copy_pre_post(fcx.ccx, a, expanded);
|
||||||
}
|
}
|
||||||
|
case (expr_anon_obj(?anon_obj, _, _, ?a)) {
|
||||||
|
alt (anon_obj.with_obj) {
|
||||||
|
case (some[@expr](?ex)) {
|
||||||
|
find_pre_post_expr(fcx, ex);
|
||||||
|
copy_pre_post(fcx.ccx, a, ex);
|
||||||
|
}
|
||||||
|
case (none[@expr]) {
|
||||||
|
clear_pp(expr_pp(fcx.ccx, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,7 @@ import front::ast::expr_assert;
|
||||||
import front::ast::expr_cast;
|
import front::ast::expr_cast;
|
||||||
import front::ast::expr_for;
|
import front::ast::expr_for;
|
||||||
import front::ast::expr_for_each;
|
import front::ast::expr_for_each;
|
||||||
|
import front::ast::expr_anon_obj;
|
||||||
import front::ast::stmt_decl;
|
import front::ast::stmt_decl;
|
||||||
import front::ast::stmt_expr;
|
import front::ast::stmt_expr;
|
||||||
import front::ast::block;
|
import front::ast::block;
|
||||||
|
@ -578,6 +579,20 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
case (expr_self_method(_, ?a)) {
|
case (expr_self_method(_, ?a)) {
|
||||||
ret pure_exp(fcx.ccx, a, pres);
|
ret pure_exp(fcx.ccx, a, pres);
|
||||||
}
|
}
|
||||||
|
case (expr_anon_obj(?anon_obj, _, _,?a)) {
|
||||||
|
alt (anon_obj.with_obj) {
|
||||||
|
case (some[@expr](?e)) {
|
||||||
|
changed = find_pre_post_state_expr(fcx, pres, e);
|
||||||
|
changed = extend_prestate_ann(fcx.ccx, a, pres) || changed;
|
||||||
|
changed = extend_poststate_ann(fcx.ccx, a,
|
||||||
|
expr_poststate(fcx.ccx, e)) || changed;
|
||||||
|
ret changed;
|
||||||
|
}
|
||||||
|
case (none[@expr]) {
|
||||||
|
ret pure_exp(fcx.ccx, a, pres);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -502,13 +502,13 @@ mod collect {
|
||||||
ret tpt;
|
ret tpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_of_arg(@ctxt cx, &ast::arg a) -> arg {
|
fn ty_of_arg(@ctxt cx, &ast::arg a) -> ty::arg {
|
||||||
auto ty_mode = ast_mode_to_mode(a.mode);
|
auto ty_mode = ast_mode_to_mode(a.mode);
|
||||||
auto f = bind getter(cx, _);
|
auto f = bind getter(cx, _);
|
||||||
ret rec(mode=ty_mode, ty=ast_ty_to_ty(cx.tcx, f, a.ty));
|
ret rec(mode=ty_mode, ty=ast_ty_to_ty(cx.tcx, f, a.ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_of_method(@ctxt cx, &@ast::method m) -> method {
|
fn ty_of_method(@ctxt cx, &@ast::method m) -> ty::method {
|
||||||
auto get = bind getter(cx, _);
|
auto get = bind getter(cx, _);
|
||||||
auto convert = bind ast_ty_to_ty(cx.tcx, get, _);
|
auto convert = bind ast_ty_to_ty(cx.tcx, get, _);
|
||||||
auto f = bind ty_of_arg(cx, _);
|
auto f = bind ty_of_arg(cx, _);
|
||||||
|
@ -694,10 +694,10 @@ mod collect {
|
||||||
|
|
||||||
ret result;
|
ret result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_obj_method_types(&@ctxt cx, &ast::_obj object) -> vec[method] {
|
fn get_obj_method_types(&@ctxt cx, &ast::_obj object) -> vec[ty::method] {
|
||||||
ret vec::map[@ast::method,method](bind ty_of_method(cx, _),
|
ret vec::map[@ast::method,method](bind ty_of_method(cx, _),
|
||||||
object.methods);
|
object.methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect(ty::item_table id_to_ty_item, &@ast::item i) {
|
fn collect(ty::item_table id_to_ty_item, &@ast::item i) {
|
||||||
|
@ -1485,6 +1485,14 @@ mod Pushdown {
|
||||||
write::ty_only_fixup(scx, ann.id, t);
|
write::ty_only_fixup(scx, ann.id, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) {
|
||||||
|
// NB: Not sure if this is correct, but not worrying too much
|
||||||
|
// about it since pushdown is going away anyway.
|
||||||
|
auto t = Demand::autoderef(scx, e.span, expected,
|
||||||
|
ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk);
|
||||||
|
write::ty_only_fixup(scx, ann.id, t);
|
||||||
|
}
|
||||||
|
|
||||||
case (_) {
|
case (_) {
|
||||||
scx.fcx.ccx.tcx.sess.span_unimpl(e.span,
|
scx.fcx.ccx.tcx.sess.span_unimpl(e.span,
|
||||||
#fmt("type unification for expression variant: %s",
|
#fmt("type unification for expression variant: %s",
|
||||||
|
@ -1771,14 +1779,13 @@ fn require_pure_function(@crate_ctxt ccx, &ast::def_id d_id, &span sp) -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
//fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
|
// scx.fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
|
||||||
// util::common::expr_to_str(expr));
|
// util::common::expr_to_str(expr));
|
||||||
|
|
||||||
// A generic function to factor out common logic from call and bind
|
// A generic function to factor out common logic from call and bind
|
||||||
// expressions.
|
// expressions.
|
||||||
fn check_call_or_bind(&@stmt_ctxt scx, &@ast::expr f,
|
fn check_call_or_bind(&@stmt_ctxt scx, &@ast::expr f,
|
||||||
&vec[option::t[@ast::expr]] args) {
|
&vec[option::t[@ast::expr]] args) {
|
||||||
|
|
||||||
// Check the function.
|
// Check the function.
|
||||||
check_expr(scx, f);
|
check_expr(scx, f);
|
||||||
|
|
||||||
|
@ -2297,10 +2304,20 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
auto t = ty::mk_nil(scx.fcx.ccx.tcx);
|
auto t = ty::mk_nil(scx.fcx.ccx.tcx);
|
||||||
let ty::t this_obj_ty;
|
let ty::t this_obj_ty;
|
||||||
|
|
||||||
auto oinfo_opt = get_obj_info(scx.fcx.ccx);
|
let option::t[obj_info] this_obj_info = get_obj_info(scx.fcx.ccx);
|
||||||
auto this_obj_id = option::get[obj_info](oinfo_opt).this_obj;
|
|
||||||
this_obj_ty = ty::lookup_item_type(scx.fcx.ccx.tcx,
|
alt (this_obj_info) {
|
||||||
this_obj_id)._1;
|
// If we're inside a current object, grab its type.
|
||||||
|
case (some[obj_info](?obj_info)) {
|
||||||
|
// FIXME: In the case of anonymous objects with methods
|
||||||
|
// containing self-calls, this lookup fails because
|
||||||
|
// obj_info.this_obj is not in the type cache
|
||||||
|
this_obj_ty = ty::lookup_item_type(scx.fcx.ccx.tcx,
|
||||||
|
obj_info.this_obj)._1;
|
||||||
|
}
|
||||||
|
|
||||||
|
case (none[obj_info]) { fail; }
|
||||||
|
}
|
||||||
|
|
||||||
// Grab this method's type out of the current object type.
|
// Grab this method's type out of the current object type.
|
||||||
alt (struct(scx.fcx.ccx.tcx, this_obj_ty)) {
|
alt (struct(scx.fcx.ccx.tcx, this_obj_ty)) {
|
||||||
|
@ -2474,7 +2491,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
case (ty::ty_rec(?fields)) {
|
case (ty::ty_rec(?fields)) {
|
||||||
let uint ix = ty::field_idx(scx.fcx.ccx.tcx.sess,
|
let uint ix = ty::field_idx(scx.fcx.ccx.tcx.sess,
|
||||||
expr.span, field, fields);
|
expr.span, field, fields);
|
||||||
if (ix >= vec::len[typeck::field](fields)) {
|
if (ix >= vec::len[ty::field](fields)) {
|
||||||
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
||||||
"bad index on record");
|
"bad index on record");
|
||||||
}
|
}
|
||||||
|
@ -2484,7 +2501,8 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
case (ty::ty_obj(?methods)) {
|
case (ty::ty_obj(?methods)) {
|
||||||
let uint ix = ty::method_idx(scx.fcx.ccx.tcx.sess,
|
let uint ix = ty::method_idx(scx.fcx.ccx.tcx.sess,
|
||||||
expr.span, field, methods);
|
expr.span, field, methods);
|
||||||
if (ix >= vec::len[typeck::method](methods)) {
|
|
||||||
|
if (ix >= vec::len[ty::method](methods)) {
|
||||||
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
||||||
"bad index on obj");
|
"bad index on obj");
|
||||||
}
|
}
|
||||||
|
@ -2560,6 +2578,75 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case (ast::expr_anon_obj(?anon_obj, ?tps, ?obj_def_ids, ?a)) {
|
||||||
|
// 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 vec[ast::obj_field] fields = [];
|
||||||
|
alt (anon_obj.fields) {
|
||||||
|
case (none[vec[ast::obj_field]]) { }
|
||||||
|
case (some[vec[ast::obj_field]](?v)) { fields = v; }
|
||||||
|
}
|
||||||
|
let ast::def_id di = obj_def_ids.ty;
|
||||||
|
|
||||||
|
vec::push[obj_info](scx.fcx.ccx.obj_infos,
|
||||||
|
rec(obj_fields=fields, this_obj=di));
|
||||||
|
|
||||||
|
// Typecheck 'with_obj', if it exists.
|
||||||
|
let option::t[@ast::expr] with_obj = none[@ast::expr];
|
||||||
|
alt (anon_obj.with_obj) {
|
||||||
|
case (none[@ast::expr]) { }
|
||||||
|
case (some[@ast::expr](?e)) {
|
||||||
|
// This had better have object type. TOOD: report an
|
||||||
|
// error if the user is trying to extend a non-object
|
||||||
|
// with_obj.
|
||||||
|
check_expr(scx, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typecheck the methods.
|
||||||
|
for (@ast::method method in anon_obj.methods) {
|
||||||
|
check_method(scx.fcx.ccx, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto t = next_ty_var(scx);
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: These next three functions are largely ripped off from
|
||||||
|
// similar ones in collect::. Is there a better way to do this?
|
||||||
|
|
||||||
|
fn ty_of_arg(@crate_ctxt ccx, &ast::arg a) -> ty::arg {
|
||||||
|
auto ty_mode = ast_mode_to_mode(a.mode);
|
||||||
|
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 {
|
||||||
|
auto convert = bind ast_ty_to_ty_crate(ccx, _);
|
||||||
|
auto f = bind ty_of_arg(ccx, _);
|
||||||
|
auto inputs = vec::map[ast::arg,arg](f,
|
||||||
|
m.node.meth.decl.inputs);
|
||||||
|
auto output = convert(m.node.meth.decl.output);
|
||||||
|
ret rec(proto=m.node.meth.proto, ident=m.node.ident,
|
||||||
|
inputs=inputs, output=output, cf=m.node.meth.decl.cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_anon_obj_method_types(@crate_ctxt ccx,
|
||||||
|
&ast::anon_obj anon_obj)
|
||||||
|
-> vec[ty::method] {
|
||||||
|
ret vec::map[@ast::method,method](bind ty_of_method(ccx, _),
|
||||||
|
anon_obj.methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto methods = get_anon_obj_method_types(scx.fcx.ccx, anon_obj);
|
||||||
|
auto ot = ty::mk_obj(scx.fcx.ccx.tcx,
|
||||||
|
ty::sort_methods(methods));
|
||||||
|
write::ty_only_fixup(scx, a.id, ot);
|
||||||
|
|
||||||
|
// Now remove the info from the stack.
|
||||||
|
vec::pop[obj_info](scx.fcx.ccx.obj_infos);
|
||||||
|
}
|
||||||
|
|
||||||
case (_) {
|
case (_) {
|
||||||
scx.fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr");
|
scx.fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr");
|
||||||
}
|
}
|
||||||
|
@ -2757,7 +2844,6 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Utilities for the unification cache
|
// Utilities for the unification cache
|
||||||
|
|
||||||
fn hash_unify_cache_entry(&unify_cache_entry uce) -> uint {
|
fn hash_unify_cache_entry(&unify_cache_entry uce) -> uint {
|
||||||
|
|
|
@ -444,7 +444,39 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
|
||||||
walk_expr(v, x);
|
walk_expr(v, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast::expr_anon_obj(_,_,_,_)) { }
|
case (ast::expr_anon_obj(?anon_obj,_,_,_)) {
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
let option::t[vec[ast::obj_field]] fields
|
||||||
|
= none[vec[ast::obj_field]];
|
||||||
|
|
||||||
|
alt (anon_obj.fields) {
|
||||||
|
case (none[vec[ast::obj_field]]) { }
|
||||||
|
case (some[vec[ast::obj_field]](?fields)) {
|
||||||
|
for (ast::obj_field f in fields) {
|
||||||
|
walk_ty(v, f.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// with_obj
|
||||||
|
let option::t[@ast::expr] with_obj = none[@ast::expr];
|
||||||
|
alt (anon_obj.with_obj) {
|
||||||
|
case (none[@ast::expr]) { }
|
||||||
|
case (some[@ast::expr](?e)) {
|
||||||
|
walk_expr(v, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
for (@ast::method m in anon_obj.methods) {
|
||||||
|
v.visit_method_pre(m);
|
||||||
|
walk_fn(v, m.node.meth, m.node.ident,
|
||||||
|
m.node.id, m.node.ann);
|
||||||
|
v.visit_method_post(m);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
v.visit_expr_post(e);
|
v.visit_expr_post(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -712,8 +712,8 @@ fn print_expr(ps s, &@ast::expr expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast::expr_anon_obj(_,_,_,_)) {
|
case (ast::expr_anon_obj(_,_,_,_)) {
|
||||||
wrd(s.s, "obj");
|
wrd(s.s, "anon obj");
|
||||||
// TODO
|
// TODO: nicer pretty-printing of anon objs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
src/test/run-pass/simple-anon-objs.rs
Normal file
29
src/test/run-pass/simple-anon-objs.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// xfail-stage0
|
||||||
|
// xfail-stage1
|
||||||
|
use std;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
obj a() {
|
||||||
|
fn foo() -> int {
|
||||||
|
ret 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto my_a = a();
|
||||||
|
|
||||||
|
// Extending an object with a new method
|
||||||
|
auto my_b = obj {
|
||||||
|
fn bar() -> int {
|
||||||
|
ret 3;
|
||||||
|
}
|
||||||
|
with my_a
|
||||||
|
};
|
||||||
|
|
||||||
|
assert my_a.foo() == 2;
|
||||||
|
|
||||||
|
// FIXME: these raise a runtime error
|
||||||
|
//assert my_b.foo() == 2;
|
||||||
|
assert my_b.bar() == 3;
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue