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, 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_impl_def_id: option, ret_ty: ty::t, // Used by loop bodies that return from the outer function indirect_ret_ty: option, @@ -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) { 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) -> 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 diff --git a/src/test/run-pass/explicit-self-closures.rs b/src/test/run-pass/explicit-self-closures.rs new file mode 100644 index 00000000000..b1f447d6648 --- /dev/null +++ b/src/test/run-pass/explicit-self-closures.rs @@ -0,0 +1,19 @@ +// Test to make sure that explicit self params work inside closures + +struct Box { + x: uint; +} + +impl Box { + fn set_many(&mut self, xs: &[uint]) { + for xs.each |x| { self.x = x; } + } + fn set_many2(@mut self, xs: &[uint]) { + for xs.each |x| { self.x = x; } + } + fn set_many3(~mut self, xs: &[uint]) { + for xs.each |x| { self.x = x; } + } +} + +fn main() {}