Make most forms of explicit self work. By-value not implemented. Work on #2585.

This commit is contained in:
Michael Sullivan 2012-08-13 12:17:42 -05:00
parent 4c16ff516d
commit e640a66eb4
9 changed files with 86 additions and 83 deletions

View File

@ -600,7 +600,7 @@ enum self_ty_ {
sty_static, // no self: static method
sty_by_ref, // old by-reference self: ``
sty_value, // by-value self: `self`
sty_region(@region, mutability), // by-region self: `&self`
sty_region(mutability), // by-region self: `&self`
sty_box(mutability), // by-managed-pointer self: `@self`
sty_uniq(mutability) // by-unique-pointer self: `~self`
}

View File

@ -2300,29 +2300,7 @@ class parser {
self.bump();
let mutability = self.parse_mutability();
self.expect_self_ident();
// Parse an explicit region, if possible.
let region_name;
match copy self.token {
token::BINOP(token::SLASH) => {
self.bump();
match copy self.token {
token::IDENT(sid, false) => {
self.bump();
region_name = some(self.get_str(sid));
}
_ => {
region_name = none;
}
}
}
_ => {
region_name = none;
}
}
let region = self.region_from_name(region_name);
self_ty = sty_region(region, mutability);
self_ty = sty_region(mutability);
} else {
self_ty = sty_by_ref;
}

View File

@ -598,22 +598,7 @@ fn get_self_ty(item: ebml::doc) -> ast::self_ty_ {
'v' => { return ast::sty_value; }
'@' => { return ast::sty_box(get_mutability(string[1])); }
'~' => { return ast::sty_uniq(get_mutability(string[1])); }
'&' => {
let mutability = get_mutability(string[1]);
let region;
let region_doc =
ebml::get_doc(self_type_doc,
tag_item_trait_method_self_ty_region);
let region_string = str::from_bytes(ebml::doc_data(region_doc));
if region_string == ~"" {
region = ast::re_anon;
} else {
region = ast::re_named(@region_string);
}
return ast::sty_region(@{ id: 0, node: region }, mutability);
}
'&' => { return ast::sty_region(get_mutability(string[1])); }
_ => {
fail fmt!{"unknown self type code: `%c`", self_ty_kind as char};
}

View File

@ -500,7 +500,7 @@ fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) {
sty_static => { ch = 's' as u8; }
sty_by_ref => { ch = 'r' as u8; }
sty_value => { ch = 'v' as u8; }
sty_region(_, _) => { ch = '&' as u8; }
sty_region(_) => { ch = '&' as u8; }
sty_box(_) => { ch = '@' as u8; }
sty_uniq(_) => { ch = '~' as u8; }
}
@ -509,27 +509,17 @@ fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) {
// Encode mutability.
match self_type {
sty_static | sty_by_ref | sty_value => { /* No-op. */ }
sty_region(_, m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => {
sty_region(m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => {
ebml_w.writer.write(&[ 'i' as u8 ]);
}
sty_region(_, m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => {
sty_region(m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => {
ebml_w.writer.write(&[ 'm' as u8 ]);
}
sty_region(_, m_const) | sty_box(m_const) | sty_uniq(m_const) => {
sty_region(m_const) | sty_box(m_const) | sty_uniq(m_const) => {
ebml_w.writer.write(&[ 'c' as u8 ]);
}
}
// Encode the region.
match self_type {
sty_region(region, _) => {
encode_region(ebml_w, *region);
}
sty_static | sty_by_ref | sty_value | sty_box(*) | sty_uniq(*) => {
// Nothing to do.
}
}
ebml_w.end_tag();
}

View File

@ -26,9 +26,23 @@ fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
for vec::each(methods) |m| {
if m.tps.len() == 0u {
let llfn = get_item_val(ccx, m.id);
let self_ty = ty::node_id_to_type(ccx.tcx, m.self_id);
let self_arg = match m.self_ty.node {
ast::sty_static => { no_self }
_ => { impl_self(ty::node_id_to_type(ccx.tcx, m.self_id)) }
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))
}
// XXX: Is this right at all?
ast::sty_region(*) => {
impl_self(ty::mk_imm_ptr(ccx.tcx, self_ty))
}
ast::sty_value => {
ccx.sess.unimpl(~"by value self type not implemented");
}
ast::sty_by_ref => { impl_self(self_ty) }
};
trans_fn(ccx,

View File

@ -80,6 +80,7 @@ import std::map::str_hash;
type self_info = {
self_ty: ty::t,
node_id: ast::node_id,
explicit_self: ast::self_ty_
};
type fn_ctxt_ =
@ -367,14 +368,20 @@ fn check_fn(ccx: @crate_ctxt,
fn check_method(ccx: @crate_ctxt, method: @ast::method,
self_info: self_info) {
check_bare_fn(ccx, method.decl, method.body, method.id, some(self_info));
}
fn check_class_member(ccx: @crate_ctxt, class_t: self_info,
fn check_class_member(ccx: @crate_ctxt, self_ty: ty::t,
node_id: ast::node_id,
cm: @ast::class_member) {
match cm.node {
ast::instance_var(_,t,_,_,_) => (),
ast::class_method(m) => check_method(ccx, m, class_t)
ast::class_method(m) => {
let class_t = {self_ty: self_ty, node_id: node_id,
explicit_self: m.self_ty.node};
check_method(ccx, m, class_t)
}
}
}
@ -404,9 +411,11 @@ fn check_no_duplicate_fields(tcx: ty::ctxt, fields:
fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
id: ast::node_id, span: span) {
let tcx = ccx.tcx;
let class_t = {self_ty: ty::node_id_to_type(tcx, id), node_id: id};
let self_ty = ty::node_id_to_type(tcx, id);
do option::iter(struct_def.ctor) |ctor| {
let class_t = {self_ty: self_ty, node_id: id,
explicit_self: ast::sty_by_ref};
// typecheck the ctor
check_bare_fn(ccx, ctor.node.dec,
ctor.node.body, ctor.node.id,
@ -416,6 +425,8 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
}
do option::iter(struct_def.dtor) |dtor| {
let class_t = {self_ty: self_ty, node_id: id,
explicit_self: ast::sty_by_ref};
// typecheck the dtor
check_bare_fn(ccx, ast_util::dtor_dec(),
dtor.node.body, dtor.node.id,
@ -426,7 +437,7 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
// typecheck the members
for struct_def.members.each |m| {
check_class_member(ccx, class_t, m);
check_class_member(ccx, self_ty, id, m);
}
// Check that there's at least one field
let (fields,_) = split_class_items(struct_def.members);
@ -450,9 +461,12 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
let rp = ccx.tcx.region_paramd_items.contains_key(it.id);
debug!{"item_impl %s with id %d rp %b",
*it.ident, it.id, rp};
let self_info = {self_ty: ccx.to_ty(rscope::type_rscope(rp), ty),
node_id: it.id };
for ms.each |m| { check_method(ccx, m, self_info);}
let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
for ms.each |m| {
let self_info = {self_ty: self_ty, node_id: it.id,
explicit_self: m.self_ty.node };
check_method(ccx, m, self_info)
}
}
ast::item_trait(_, _, trait_methods) => {
for trait_methods.each |trait_method| {
@ -463,7 +477,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
}
provided(m) => {
let self_info = {self_ty: ty::mk_self(ccx.tcx),
node_id: it.id};
node_id: it.id,
explicit_self: m.self_ty.node};
check_method(ccx, m, self_info);
}
}
@ -742,7 +757,8 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
// declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id, require_rp: bool)
-> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
let {n_tps, rp, raw_ty} = if did.crate == ast::local_crate {
@ -778,6 +794,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
raw_ty: ity.ty}
};
let rp = rp || require_rp;
let self_r = if rp {some(fcx.infcx.next_region_var_nb())} else {none};
let tps = fcx.infcx.next_ty_vars(n_tps);
@ -2216,7 +2233,10 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
ast::def_self(_) => {
match fcx.self_info {
some(self_info) => {
return no_params(self_info.self_ty);
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");

View File

@ -20,28 +20,30 @@ type candidate = {
entry: method_map_entry
};
fn transform_self_type_for_method(fcx: @fn_ctxt,
impl_ty: ty::t,
method_info: MethodInfo)
fn transform_self_type_for_method
(tcx: ty::ctxt,
self_region: option<ty::region>,
impl_ty: ty::t,
self_type: ast::self_ty_)
-> ty::t {
match method_info.self_type {
match self_type {
sty_static => {
fcx.tcx().sess.bug(~"calling transform_self_type_for_method on \
static method");
tcx.sess.bug(~"calling transform_self_type_for_method on \
static method");
}
sty_by_ref | sty_value => {
impl_ty
}
sty_region(r, mutability) => {
// XXX: dummy_sp is unfortunate here.
let region = ast_region_to_region(fcx, fcx, dummy_sp(), r);
mk_rptr(fcx.ccx.tcx, region, { ty: impl_ty, mutbl: mutability })
sty_region(mutability) => {
mk_rptr(tcx,
self_region.expect(~"self region missing for &self param"),
{ ty: impl_ty, mutbl: mutability })
}
sty_box(mutability) => {
mk_box(fcx.ccx.tcx, { ty: impl_ty, mutbl: mutability })
mk_box(tcx, { ty: impl_ty, mutbl: mutability })
}
sty_uniq(mutability) => {
mk_uniq(fcx.ccx.tcx, { ty: impl_ty, mutbl: mutability })
mk_uniq(tcx, { ty: impl_ty, mutbl: mutability })
}
}
}
@ -368,14 +370,17 @@ class lookup {
// Check whether this impl has a method with the right name.
for im.methods.find(|m| m.ident == self.m_name).each |m| {
let need_rp = match m.self_type { ast::sty_region(_) => true,
_ => false };
// determine the `self` of the impl with fresh
// variables for each parameter:
let {substs: impl_substs, ty: impl_ty} =
impl_self_ty(self.fcx, im.did);
impl_self_ty(self.fcx, im.did, need_rp);
let impl_ty = transform_self_type_for_method(self.fcx,
impl_ty,
*m);
let impl_ty = transform_self_type_for_method(
self.tcx(), impl_substs.self_r,
impl_ty, m.self_type);
// Depending on our argument, we find potential
// matches either by checking subtypability or

View File

@ -22,6 +22,17 @@ 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), _}) => {
let region = ty::re_bound(ty::br_self);
let ty = ty::mk_rptr(tcx, region,
{ ty: ty::mk_self(tcx), mutbl: m });
vec::push(all_tys, ty);
}
_ => {}
}
for self_ty.each |t| { vec::push(all_tys, t) }
debug!{"replace_bound_regions_in_fn_ty(self_info.self_ty=%?, fn_ty=%s, \
@ -50,7 +61,7 @@ fn replace_bound_regions_in_fn_ty(
// Glue updated self_ty back together with its original node_id.
let new_self_info = match self_info {
some(s) => match check t_self {
some(t) => some({self_ty: t, node_id: s.node_id})
some(t) => some({self_ty: t with s})
// this 'none' case shouldn't happen
},
none => none

View File

@ -146,7 +146,7 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
// check whether the type unifies with the type
// that the impl is for, and continue if not
let {substs: substs, ty: for_ty} =
impl_self_ty(fcx, im.did);
impl_self_ty(fcx, im.did, false);
let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
match fcx.mk_subty(ty, for_ty) {
result::err(_) => again,