about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2011-05-20 18:23:03 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2011-05-20 18:23:03 -0700
commit467b938ea84e1d4f19b26c86c9220176bbbb704c (patch)
tree7d0acc267194ef7517c6370e01ea33e22f395918 /src/comp
parent5de9d27fccb7ccfe0b22ea88633d65c3f019fe28 (diff)
parentc3410bf927c863cd33057184e97e6a6169475059 (diff)
downloadrust-467b938ea84e1d4f19b26c86c9220176bbbb704c.tar.gz
rust-467b938ea84e1d4f19b26c86c9220176bbbb704c.zip
Merge remote-tracking branch 'graydon/master' into typestate_4
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/back/abi.rs2
-rw-r--r--src/comp/front/ast.rs2
-rw-r--r--src/comp/front/parser.rs4
-rw-r--r--src/comp/middle/fold.rs13
-rw-r--r--src/comp/middle/trans.rs78
-rw-r--r--src/comp/middle/tstate/pre_post_conditions.rs12
-rw-r--r--src/comp/middle/tstate/states.rs15
-rw-r--r--src/comp/middle/typeck.rs116
-rw-r--r--src/comp/middle/walk.rs34
-rw-r--r--src/comp/pretty/pprust.rs4
10 files changed, 252 insertions, 28 deletions
diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs
index 54dc5e0d01d..54f800c1667 100644
--- a/src/comp/back/abi.rs
+++ b/src/comp/back/abi.rs
@@ -55,6 +55,8 @@ const int obj_field_box = 1;
 const int obj_body_elt_tydesc = 0;
 const int obj_body_elt_typarams = 1;
 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_box = 1;
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index db625124be4..0653e45d268 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -379,7 +379,7 @@ type anon_obj = rec(
     option::t[vec[obj_field]] fields,
     vec[@method] methods,
     // 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,
                 vec[@item] items);
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index a2f877f2c23..a39f57e5216 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -820,13 +820,13 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
         }
 
         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);
 
         while (p.peek() != token::RBRACE) {
             if (eat_word(p, "with")) {
-                with_obj = some[ast::ident](parse_ident(p));
+                with_obj = some[@ast::expr](parse_expr(p));
             } else {
                 vec::push[@ast::method](meths,
                                          parse_method(p));
diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs
index 9d48d50b4e6..1173c11729e 100644
--- a/src/comp/middle/fold.rs
+++ b/src/comp/middle/fold.rs
@@ -336,7 +336,7 @@ type ast_fold[ENV] =
      (fn(&ENV e,
          &option::t[vec[ast::obj_field]] fields,
          &vec[@ast::method] methods,
-         &option::t[ident] with_obj) 
+         &option::t[@ast::expr] with_obj) 
       -> ast::anon_obj)                           fold_anon_obj,
 
      // Env updates.
@@ -1001,11 +1001,11 @@ fn fold_anon_obj[ENV](&ENV env, &ast_fold[ENV] fld, &ast::anon_obj ob)
     }
 
     // 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) {
-        case (none[ast::ident]) { }
-        case (some[ast::ident](?i)) {
-            with_obj = some[ast::ident](i);
+        case (none[@ast::expr]) { }
+        case (some[@ast::expr](?e)) {
+            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,
                                &option::t[vec[ast::obj_field]] fields,
                                &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);
 }
 
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 9bcfd77d251..4f9dd2f9a34 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -4576,7 +4576,8 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
         }
         case (_) {
             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;
@@ -5547,6 +5548,10 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
             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 (_) {
             // 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);
 }
 
+
+/*
+
+  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 {
 
     // Make a note to drop this slot on the way out.
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index a837bd9f9a2..308c99ac620 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -132,6 +132,7 @@ import front::ast::expr_assert;
 import front::ast::expr_cast;
 import front::ast::expr_for;
 import front::ast::expr_for_each;
+import front::ast::expr_anon_obj;
 import front::ast::stmt_decl;
 import front::ast::stmt_expr;
 import front::ast::block;
@@ -556,6 +557,17 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
             find_pre_post_expr(fcx, 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));
+                }
+            }
+        }
     }
 }
 
diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs
index c04ad500574..ef1e86275ce 100644
--- a/src/comp/middle/tstate/states.rs
+++ b/src/comp/middle/tstate/states.rs
@@ -143,6 +143,7 @@ import front::ast::expr_assert;
 import front::ast::expr_cast;
 import front::ast::expr_for;
 import front::ast::expr_for_each;
+import front::ast::expr_anon_obj;
 import front::ast::stmt_decl;
 import front::ast::stmt_expr;
 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)) {
         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);
+            }
+        }
+    }
   }
 }
 
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index de47fce619d..cb95a5e6f01 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -502,13 +502,13 @@ mod collect {
         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 f = bind getter(cx, _);
         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 convert = bind ast_ty_to_ty(cx.tcx, get, _);
         auto f = bind ty_of_arg(cx, _);
@@ -694,10 +694,10 @@ mod collect {
 
         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, _),
-                                           object.methods);
+                                          object.methods);
     }
 
     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);
             }
 
+            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 (_) {
                 scx.fcx.ccx.tcx.sess.span_unimpl(e.span,
                     #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) {
-    //fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
-    //                       util::common::expr_to_str(expr));
+    // scx.fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
+    //                                util::common::expr_to_str(expr));
 
     // A generic function to factor out common logic from call and bind
     // expressions.
     fn check_call_or_bind(&@stmt_ctxt scx, &@ast::expr f,
                           &vec[option::t[@ast::expr]] args) {
-
         // Check the function.
         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);
             let ty::t this_obj_ty;
 
-            auto oinfo_opt = 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,
-                                               this_obj_id)._1;
+            let option::t[obj_info] this_obj_info = get_obj_info(scx.fcx.ccx);
+
+            alt (this_obj_info) {
+                // 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.
             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)) {
                     let uint ix = ty::field_idx(scx.fcx.ccx.tcx.sess,
                                                 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,
                                               "bad index on record");
                     }
@@ -2484,7 +2501,8 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
                 case (ty::ty_obj(?methods)) {
                     let uint ix = ty::method_idx(scx.fcx.ccx.tcx.sess,
                                                  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,
                                                   "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 (_) {
             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
 
 fn hash_unify_cache_entry(&unify_cache_entry uce) -> uint {
diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs
index cac5fd0ea35..3580df7e3f9 100644
--- a/src/comp/middle/walk.rs
+++ b/src/comp/middle/walk.rs
@@ -444,7 +444,39 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
             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);
 }
diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs
index d104e862dc8..0f825c33934 100644
--- a/src/comp/pretty/pprust.rs
+++ b/src/comp/pretty/pprust.rs
@@ -712,8 +712,8 @@ fn print_expr(ps s, &@ast::expr expr) {
         }
 
         case (ast::expr_anon_obj(_,_,_,_)) {
-            wrd(s.s, "obj");
-            // TODO
+            wrd(s.s, "anon obj");
+            // TODO: nicer pretty-printing of anon objs
         }
     }