about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorMichael Sullivan <sully@msully.net>2012-08-22 13:18:29 -0700
committerMichael Sullivan <sully@msully.net>2012-08-22 13:18:29 -0700
commit744fea1a4f1b826def484aa4584e939fa272a8c3 (patch)
tree52e455ddd7906717bcd8319fe5e876592545b35b /src/rustc
parent728496929292c692aaad005bdbf4376bb1d78c4f (diff)
Track the type of self properly. Closes #3247.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/trans/impl.rs38
-rw-r--r--src/rustc/middle/typeck/check.rs115
-rw-r--r--src/rustc/middle/typeck/check/method.rs10
-rw-r--r--src/rustc/middle/typeck/check/regionmanip.rs2
-rw-r--r--src/rustc/middle/typeck/check/writeback.rs8
-rw-r--r--src/rustc/middle/typeck/collect.rs11
6 files changed, 88 insertions, 96 deletions
diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs
index e85cef79358..bc0822bec82 100644
--- a/src/rustc/middle/trans/impl.rs
+++ b/src/rustc/middle/trans/impl.rs
@@ -54,32 +54,28 @@ fn trans_method(ccx: @crate_ctxt,
                 method: &ast::method,
                 param_substs: option<param_substs>,
                 llfn: ValueRef) {
-    // determine the (monomorphized) type that `self` maps to for this method
-    let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
-    let self_ty = match param_substs {
-      none => self_ty,
-      some({tys: ref tys, _}) => ty::subst_tps(ccx.tcx, *tys, self_ty)
-    };
 
-    // apply any transformations from the explicit self declaration
+    // figure out how self is being passed
     let self_arg = match method.self_ty.node {
       ast::sty_static => {
         no_self
       }
-      ast::sty_box(_) => {
-        impl_self(ty::mk_imm_box(ccx.tcx, self_ty))
-      }
-      ast::sty_uniq(_) => {
-        impl_self(ty::mk_imm_uniq(ccx.tcx, self_ty))
-      }
-      ast::sty_region(*) => {
-        impl_self(ty::mk_imm_ptr(ccx.tcx, self_ty))
-      }
-      ast::sty_value => {
-        impl_owned_self(self_ty)
-      }
-      ast::sty_by_ref => {
-        impl_self(self_ty)
+      _ => {
+        // determine the (monomorphized) type that `self` maps to for
+        // this method
+        let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
+        let self_ty = match param_substs {
+          none => self_ty,
+          some({tys: ref tys, _}) => ty::subst_tps(ccx.tcx, *tys, self_ty)
+        };
+        match method.self_ty.node {
+          ast::sty_value => {
+            impl_owned_self(self_ty)
+          }
+          _ => {
+            impl_self(self_ty)
+          }
+        }
       }
     };
 
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 7947bc6ee18..ff9bd009498 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -79,15 +79,16 @@ import std::map::str_hash;
 
 type self_info = {
     self_ty: ty::t,
+    self_id: ast::node_id,
     def_id: ast::def_id,
-    explicit_self: ast::self_ty_
+    explicit_self: ast::self_ty
 };
 
 type fn_ctxt_ =
     // var_bindings, locals and next_var_id are shared
     // with any nested functions that capture the environment
     // (and with any functions whose environment is being captured).
-    {self_info: option<self_info>,
+    {self_impl_def_id: option<ast::def_id>,
      ret_ty: ty::t,
      // Used by loop bodies that return from the outer function
      indirect_ret_ty: option<ty::t>,
@@ -126,7 +127,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
                  region_bnd: ast::node_id) -> @fn_ctxt {
 // It's kind of a kludge to manufacture a fake function context
 // and statement context, but we might as well do write the code only once
-    @fn_ctxt_({self_info: none,
+    @fn_ctxt_({self_impl_def_id: none,
                ret_ty: rty,
                indirect_ret_ty: none,
                purity: ast::pure_fn,
@@ -244,7 +245,7 @@ fn check_fn(ccx: @crate_ctxt,
             }
         } else { none };
 
-        @fn_ctxt_({self_info: self_info,
+        @fn_ctxt_({self_impl_def_id: self_info.map(|info| info.def_id),
                    ret_ty: ret_ty,
                    indirect_ret_ty: indirect_ret_ty,
                    purity: purity,
@@ -257,7 +258,22 @@ fn check_fn(ccx: @crate_ctxt,
                    ccx: ccx})
     };
 
-    gather_locals(fcx, decl, body, arg_tys);
+    // Update the self_info to contain an accurate self type (taking
+    // into account explicit self).
+    let self_info = do self_info.chain |info| {
+        // If the self type is sty_static, we don't have a self ty.
+        if info.explicit_self.node == ast::sty_static {
+            none
+        } else  {
+            let self_region = fcx.in_scope_regions.find(ty::br_self);
+            let ty = method::transform_self_type_for_method(
+                fcx.tcx(), self_region,
+                info.self_ty, info.explicit_self.node);
+            some({self_ty: ty with info})
+        }
+    };
+
+    gather_locals(fcx, decl, body, arg_tys, self_info);
     check_block(fcx, body);
 
     // We unify the tail expr's type with the
@@ -270,10 +286,11 @@ fn check_fn(ccx: @crate_ctxt,
       none => ()
     }
 
-    let mut i = 0u;
-    do vec::iter(arg_tys) |arg| {
-        fcx.write_ty(decl.inputs[i].id, arg);
-        i += 1u;
+    for self_info.each |info| {
+        fcx.write_ty(info.self_id, info.self_ty);
+    }
+    do vec::iter2(decl.inputs, arg_tys) |input, arg| {
+        fcx.write_ty(input.id, arg);
     }
 
     // If we don't have any enclosing function scope, it is time to
@@ -283,13 +300,14 @@ fn check_fn(ccx: @crate_ctxt,
     if option::is_none(old_fcx) {
         vtable::resolve_in_block(fcx, body);
         regionck::regionck_fn(fcx, decl, body);
-        writeback::resolve_type_vars_in_fn(fcx, decl, body);
+        writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
     }
 
     fn gather_locals(fcx: @fn_ctxt,
                      decl: ast::fn_decl,
                      body: ast::blk,
-                     arg_tys: ~[ty::t]) {
+                     arg_tys: ~[ty::t],
+                     self_info: option<self_info>) {
         let tcx = fcx.ccx.tcx;
 
         let assign = fn@(span: span, nid: ast::node_id,
@@ -305,6 +323,14 @@ fn check_fn(ccx: @crate_ctxt,
             }
         };
 
+        // Add the self parameter
+        for self_info.each |info| {
+            assign(info.explicit_self.span,
+                   info.self_id, some(info.self_ty));
+            debug!{"self is assigned to %s",
+                   fcx.locals.get(info.self_id).to_str()};
+        }
+
         // Add formal parameters.
         do vec::iter2(arg_tys, decl.inputs) |arg_ty, input| {
             assign(input.ty.span, input.id, some(arg_ty));
@@ -369,8 +395,11 @@ fn check_fn(ccx: @crate_ctxt,
 }
 
 fn check_method(ccx: @crate_ctxt, method: @ast::method,
-                self_info: self_info) {
-
+                self_ty: ty::t, self_impl_def_id: ast::def_id) {
+    let self_info = {self_ty: self_ty,
+                     self_id: method.self_id,
+                     def_id: self_impl_def_id,
+                     explicit_self: method.self_ty };
     check_bare_fn(ccx, method.decl, method.body, method.id, some(self_info));
 }
 
@@ -404,33 +433,31 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
 
     do option::iter(struct_def.ctor) |ctor| {
         let class_t = {self_ty: self_ty,
+                       self_id: ctor.node.self_id,
                        def_id: local_def(id),
-                       explicit_self: ast::sty_by_ref};
+                       explicit_self: {node: ast::sty_by_ref,
+                                       span: ast_util::dummy_sp()}};
         // typecheck the ctor
         check_bare_fn(ccx, ctor.node.dec,
                       ctor.node.body, ctor.node.id,
                       some(class_t));
-        // Write the ctor's self's type
-        write_ty_to_tcx(tcx, ctor.node.self_id, class_t.self_ty);
     }
 
     do option::iter(struct_def.dtor) |dtor| {
         let class_t = {self_ty: self_ty,
+                       self_id: dtor.node.self_id,
                        def_id: local_def(id),
-                       explicit_self: ast::sty_by_ref};
+                       explicit_self: {node: ast::sty_by_ref,
+                                       span: ast_util::dummy_sp()}};
         // typecheck the dtor
         check_bare_fn(ccx, ast_util::dtor_dec(),
                       dtor.node.body, dtor.node.id,
                       some(class_t));
-        // Write the dtor's self's type
-        write_ty_to_tcx(tcx, dtor.node.self_id, class_t.self_ty);
     };
 
     // typecheck the methods
     for struct_def.methods.each |m| {
-        check_method(ccx, m, {self_ty: self_ty,
-                              def_id: local_def(id),
-                              explicit_self: m.self_ty.node});
+        check_method(ccx, m, self_ty, local_def(id));
     }
     // Check that there's at least one field
     if struct_def.fields.len() < 1u {
@@ -455,10 +482,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
                *it.ident, it.id, rp};
         let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
         for ms.each |m| {
-            let self_info = {self_ty: self_ty,
-                             def_id: local_def(it.id),
-                             explicit_self: m.self_ty.node };
-            check_method(ccx, m, self_info)
+            check_method(ccx, m, self_ty, local_def(it.id));
         }
       }
       ast::item_trait(_, _, trait_methods) => {
@@ -469,10 +493,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
                 // bodies to check.
               }
               provided(m) => {
-                let self_info = {self_ty: ty::mk_self(ccx.tcx),
-                                 def_id: local_def(it.id),
-                                 explicit_self: m.self_ty.node};
-                check_method(ccx, m, self_info);
+                check_method(ccx, m, ty::mk_self(ccx.tcx), local_def(it.id));
               }
             }
         }
@@ -1204,7 +1225,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
 
         fcx.write_ty(expr.id, fty);
 
-        check_fn(fcx.ccx, fcx.self_info, &fn_ty, decl, body,
+        check_fn(fcx.ccx, none, &fn_ty, decl, body,
                  is_loop_body, some(fcx));
     }
 
@@ -2247,29 +2268,12 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
     ty_param_bounds_and_ty {
 
     match defn {
-      ast::def_arg(nid, _) => {
+      ast::def_arg(nid, _) | ast::def_local(nid, _) |
+      ast::def_self(nid) | ast::def_binding(nid, _) => {
         assert (fcx.locals.contains_key(nid));
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
         return no_params(typ);
       }
-      ast::def_local(nid, _) => {
-        assert (fcx.locals.contains_key(nid));
-        let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
-        return no_params(typ);
-      }
-      ast::def_self(_) => {
-        match fcx.self_info {
-          some(self_info) => {
-            let self_region = fcx.in_scope_regions.find(ty::br_self);
-            return no_params(method::transform_self_type_for_method(
-                fcx.tcx(), self_region,
-                self_info.self_ty, self_info.explicit_self));
-          }
-          none => {
-              fcx.ccx.tcx.sess.span_bug(sp, ~"def_self with no self_info");
-          }
-        }
-      }
       ast::def_fn(id, ast::extern_fn) => {
         // extern functions are just u8 pointers
         return {
@@ -2296,20 +2300,15 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
       ast::def_class(id, _) => {
         return ty::lookup_item_type(fcx.ccx.tcx, id);
       }
-      ast::def_binding(nid, _) => {
-        assert (fcx.locals.contains_key(nid));
-        let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
-        return no_params(typ);
-      }
-      ast::def_ty(_) | ast::def_prim_ty(_) => {
-        fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type");
-      }
       ast::def_upvar(_, inner, _, _) => {
         return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
       }
       ast::def_ty_param(did, n) => {
         return no_params(ty::mk_param(fcx.ccx.tcx, n, did));
       }
+      ast::def_ty(_) | ast::def_prim_ty(_) => {
+        fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type");
+      }
       ast::def_mod(*) | ast::def_foreign_mod(*) => {
         fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found module");
       }
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index 26ca4d07c94..a711e2280b4 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -150,14 +150,8 @@ struct lookup {
               ty::ty_self => {
                 // Call is of the form "self.foo()" and appears in one
                 // of a trait's provided methods.
-                let self_def_id = match self.fcx.self_info {
-                  some(self_info) => self_info.def_id,
-                  none => {
-                    // Shouldn't happen; there should always be a
-                    // self_info in this case.
-                    self.tcx().sess.bug(~"unexpected `none` for self_info")
-                  }
-                };
+                let self_def_id = self.fcx.self_impl_def_id.expect(
+                    ~"unexpected `none` for self_impl_def_id");
 
                 let substs = {
                     self_r: none,
diff --git a/src/rustc/middle/typeck/check/regionmanip.rs b/src/rustc/middle/typeck/check/regionmanip.rs
index 888e04d5eef..7eb88a397df 100644
--- a/src/rustc/middle/typeck/check/regionmanip.rs
+++ b/src/rustc/middle/typeck/check/regionmanip.rs
@@ -23,7 +23,7 @@ fn replace_bound_regions_in_fn_ty(
     let mut all_tys = ty::tys_in_fn_ty(fn_ty);
 
     match self_info {
-      some({explicit_self: ast::sty_region(m), _}) => {
+      some({explicit_self: {node: ast::sty_region(m), _}, _}) => {
         let region = ty::re_bound(ty::br_self);
         let ty = ty::mk_rptr(tcx, region,
                              { ty: ty::mk_self(tcx), mutbl: m });
diff --git a/src/rustc/middle/typeck/check/writeback.rs b/src/rustc/middle/typeck/check/writeback.rs
index 9e336ca5ea0..4f9bc928860 100644
--- a/src/rustc/middle/typeck/check/writeback.rs
+++ b/src/rustc/middle/typeck/check/writeback.rs
@@ -171,10 +171,16 @@ fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
 
 fn resolve_type_vars_in_fn(fcx: @fn_ctxt,
                            decl: ast::fn_decl,
-                           blk: ast::blk) -> bool {
+                           blk: ast::blk,
+                           self_info: option<self_info>) -> bool {
     let wbcx = {fcx: fcx, mut success: true};
     let visit = mk_visitor();
     visit.visit_block(blk, wbcx, visit);
+    for self_info.each |self_info| {
+        if self_info.explicit_self.node == ast::sty_static { break; }
+        resolve_type_vars_for_node(wbcx, self_info.explicit_self.span,
+                                   self_info.self_id);
+    }
     for decl.inputs.each |arg| {
         resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id);
     }
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index 18f17c18725..250f431a1c7 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -381,12 +381,10 @@ type converted_method = {mty: ty::method, id: ast::node_id, span: span};
 fn convert_methods(ccx: @crate_ctxt,
                    ms: ~[@ast::method],
                    rp: bool,
-                   rcvr_bounds: @~[ty::param_bounds],
-                   self_ty: ty::t) -> ~[converted_method] {
+                   rcvr_bounds: @~[ty::param_bounds]) -> ~[converted_method] {
 
     let tcx = ccx.tcx;
     do vec::map(ms) |m| {
-        write_ty_to_tcx(tcx, m.self_id, self_ty);
         let bounds = ty_param_bounds(ccx, m.tps);
         let mty = ty_of_method(ccx, m, rp);
         let fty = ty::mk_fn(tcx, mty.fty);
@@ -423,7 +421,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
                            rp: rp,
                            ty: selfty});
 
-        let cms = convert_methods(ccx, ms, rp, i_bounds, selfty);
+        let cms = convert_methods(ccx, ms, rp, i_bounds);
         for trait_ref.each |t| {
             check_methods_against_trait(ccx, tps, rp, selfty, t, cms);
         }
@@ -436,9 +434,8 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
         ensure_trait_methods(ccx, it.id, tpt.ty);
 
         let (_, provided_methods) = split_trait_methods(trait_methods);
-        let selfty = ty::mk_self(tcx);
         let {bounds, _} = mk_substs(ccx, tps, rp);
-        let _cms = convert_methods(ccx, provided_methods, rp, bounds, selfty);
+        let _cms = convert_methods(ccx, provided_methods, rp, bounds);
         // FIXME (#2616): something like this, when we start having
         // trait inheritance?
         // for trait_ref.each |t| {
@@ -510,7 +507,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
     }
     let {bounds, substs} = mk_substs(ccx, tps, rp);
     let selfty = ty::mk_class(tcx, local_def(id), substs);
-    let cms = convert_methods(ccx, struct_def.methods, rp, bounds, selfty);
+    let cms = convert_methods(ccx, struct_def.methods, rp, bounds);
     for struct_def.traits.each |trait_ref| {
         check_methods_against_trait(ccx, tps, rp, selfty, trait_ref, cms);
         // trait_ref.impl_id represents (class, trait) pair