diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2012-07-31 16:32:37 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2012-07-31 16:35:11 -0700 |
| commit | 2cfe8fb357f8ad7e99dc03b09e0ec5fa1c2c9029 (patch) | |
| tree | 56af8b2f6feb43d3393caf47bcebaa8399712257 /src/rustc | |
| parent | 567f881fdf4053d4890929eb4cd46c67c4a011ee (diff) | |
| download | rust-2cfe8fb357f8ad7e99dc03b09e0ec5fa1c2c9029.tar.gz rust-2cfe8fb357f8ad7e99dc03b09e0ec5fa1c2c9029.zip | |
rustc: Check self types in method lookup; allow required trait methods to have self types; write self types into metadata
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/metadata/common.rs | 2 | ||||
| -rw-r--r-- | src/rustc/metadata/decoder.rs | 57 | ||||
| -rw-r--r-- | src/rustc/metadata/encoder.rs | 57 | ||||
| -rw-r--r-- | src/rustc/middle/resolve3.rs | 31 | ||||
| -rw-r--r-- | src/rustc/middle/ty.rs | 1 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check/method.rs | 34 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/coherence.rs | 6 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/collect.rs | 2 |
8 files changed, 172 insertions, 18 deletions
diff --git a/src/rustc/metadata/common.rs b/src/rustc/metadata/common.rs index e7ef25a04d5..946f3c764fa 100644 --- a/src/rustc/metadata/common.rs +++ b/src/rustc/metadata/common.rs @@ -97,6 +97,8 @@ const tag_mod_impl_trait: uint = 0x47u; const tag_item_impl_method: uint = 0x48u; const tag_item_dtor: uint = 0x49u; const tag_paths_foreign_path: uint = 0x4a; +const tag_item_trait_method_self_ty: uint = 0x4b; +const tag_item_trait_method_self_ty_region: uint = 0x4c; // used to encode crate_ctxt side tables enum astencode_tag { // Reserves 0x50 -- 0x6f diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index ba5ff3a6a9d..37da481a82d 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -565,19 +565,70 @@ fn get_enum_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) } // NB: These types are duplicated in resolve.rs -type method_info = {did: ast::def_id, n_tps: uint, ident: ast::ident}; +type method_info = { + did: ast::def_id, + n_tps: uint, + ident: ast::ident, + self_type: ast::self_ty_ +}; + type _impl = {did: ast::def_id, ident: ast::ident, methods: ~[@method_info]}; +fn get_self_ty(item: ebml::doc) -> ast::self_ty_ { + fn get_mutability(ch: u8) -> ast::mutability { + alt ch as char { + 'i' => { ast::m_imm } + 'm' => { ast::m_mutbl } + 'c' => { ast::m_const } + _ => { + fail fmt!{"unknown mutability character: `%c`", ch as char} + } + } + } + + let self_type_doc = ebml::get_doc(item, tag_item_trait_method_self_ty); + let string = ebml::doc_as_str(self_type_doc); + + let self_ty_kind = string[0]; + alt self_ty_kind as char { + 'r' => { ret ast::sty_by_ref; } + 'v' => { ret ast::sty_value; } + '@' => { ret ast::sty_box(get_mutability(string[1])); } + '~' => { ret 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 str::eq(region_string, ~"") { + region = ast::re_anon; + } else { + region = ast::re_named(@region_string); + } + + ret ast::sty_region(@{ id: 0, node: region }, mutability); + } + _ => { + fail fmt!{"unknown self type code: `%c`", self_ty_kind as char}; + } + } +} + fn item_impl_methods(cdata: cmd, item: ebml::doc, base_tps: uint) -> ~[@method_info] { let mut rslt = ~[]; for ebml::tagged_docs(item, tag_item_impl_method) |doc| { let m_did = ebml::with_doc_data(doc, |d| parse_def_id(d)); let mth_item = lookup_item(m_did.node, cdata.data); + let self_ty = get_self_ty(mth_item); vec::push(rslt, @{did: translate_def_id(cdata, m_did), /* FIXME (maybe #2323) tjc: take a look at this. */ n_tps: item_ty_param_count(mth_item) - base_tps, - ident: item_name(mth_item)}); + ident: item_name(mth_item), + self_type: self_ty}); } rslt } @@ -628,7 +679,9 @@ fn get_trait_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) tcx.diag.handler().bug( ~"get_trait_methods: id has non-function type"); } }; + let self_ty = get_self_ty(mth); vec::push(result, {ident: name, tps: bounds, fty: fty, + self_ty: self_ty, purity: alt check item_family(mth) { 'u' { ast::unsafe_fn } 'f' { ast::impure_fn } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index ee4a8bdd63f..49096e1fdf8 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -438,6 +438,58 @@ fn encode_visibility(ebml_w: ebml::writer, visibility: visibility) { }); } +fn encode_region(ebml_w: ebml::writer, region: region) { + alt region.node { + re_anon => { + ebml_w.wr_tagged_str(tag_item_trait_method_self_ty, ~""); + } + re_named(ident) => { + ebml_w.wr_tagged_str(tag_item_trait_method_self_ty, *ident); + } + } +} + +fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) { + ebml_w.start_tag(tag_item_trait_method_self_ty); + + // Encode the base self type. + let ch; + alt self_type { + sty_by_ref => { ch = 'r' as u8; } + sty_value => { ch = 'v' as u8; } + sty_region(_, _) => { ch = '&' as u8; } + sty_box(_) => { ch = '@' as u8; } + sty_uniq(_) => { ch = '~' as u8; } + } + ebml_w.writer.write(&[ ch ]); + + // Encode mutability. + alt self_type { + sty_by_ref | sty_value => { /* No-op. */ } + 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) => { + ebml_w.writer.write(&[ 'm' as u8 ]); + } + sty_region(_, m_const) | sty_box(m_const) | sty_uniq(m_const) => { + ebml_w.writer.write(&[ 'c' as u8 ]); + } + } + + // Encode the region. + alt self_type { + sty_region(region, _) => { + encode_region(ebml_w, *region); + } + sty_by_ref | sty_value | sty_box(*) | sty_uniq(*) => { + // Nothing to do. + } + } + + ebml_w.end_tag(); +} + /* Returns an index of items in this class */ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer, id: node_id, path: ast_map::path, @@ -523,6 +575,7 @@ fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::writer, encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); encode_name(ebml_w, m.ident); encode_path(ebml_w, impl_path, ast_map::path_name(m.ident)); + encode_self_type(ebml_w, m.self_ty.node); if all_tps.len() > 0u || should_inline { ecx.encode_inlined_item( ecx, ebml_w, impl_path, @@ -712,9 +765,10 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_type_param_bounds(ebml_w, ecx, m.tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id)); encode_def_id(ebml_w, local_def(m.id)); + encode_self_type(ebml_w, m.self_ty.node); ebml_w.end_tag(); /* Write the info that's needed when viewing this class - as an impl (just the method def_id) */ + as an impl (just the method def_id and self type) */ ebml_w.start_tag(tag_item_impl_method); ebml_w.writer.write(str::bytes(def_to_str(local_def(m.id)))); ebml_w.end_tag(); @@ -778,6 +832,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_type_param_bounds(ebml_w, ecx, ty_m.tps); encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty)); encode_family(ebml_w, purity_fn_family(mty.purity)); + encode_self_type(ebml_w, mty.self_ty); ebml_w.end_tag(); } provided(m) { diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index 13019f19a8a..7a7f80bf9dc 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -28,13 +28,13 @@ import syntax::ast::{item_mod, item_trait, item_ty, le, local, local_crate}; import syntax::ast::{lt, method, mul, ne, neg, node_id, pat, pat_enum}; import syntax::ast::{pat_ident, path, prim_ty, pat_box, pat_uniq, pat_lit}; import syntax::ast::{pat_range, pat_rec, pat_tup, pat_wild, provided}; -import syntax::ast::{required, rem, shl, stmt_decl, subtract, ty, ty_bool}; -import syntax::ast::{ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16}; -import syntax::ast::{ty_i32, ty_i64, ty_i8, ty_int, ty_param, ty_path}; -import syntax::ast::{ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint}; -import syntax::ast::{variant, view_item, view_item_export, view_item_import}; -import syntax::ast::{view_item_use, view_path_glob, view_path_list}; -import syntax::ast::{view_path_simple}; +import syntax::ast::{required, rem, self_ty_, shl, stmt_decl, subtract, ty}; +import syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i}; +import syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, ty_param}; +import syntax::ast::{ty_path, ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8}; +import syntax::ast::{ty_uint, variant, view_item, view_item_export}; +import syntax::ast::{view_item_import, view_item_use, view_path_glob}; +import syntax::ast::{view_path_list, view_path_simple}; import syntax::ast_util::{def_id_of_def, dummy_sp, local_def, new_def_hash}; import syntax::ast_util::{walk_pat}; import syntax::attr::{attr_metas, contains_name}; @@ -59,7 +59,16 @@ import str_eq = str::eq; type DefMap = hashmap<node_id,def>; // Implementation resolution -type MethodInfo = { did: def_id, n_tps: uint, ident: ident }; + +// XXX: This kind of duplicates information kept in ty::method. Maybe it +// should go away. +type MethodInfo = { + did: def_id, + n_tps: uint, + ident: ident, + self_type: self_ty_ +}; + type Impl = { did: def_id, ident: ident, methods: ~[@MethodInfo] }; type ImplScope = @~[@Impl]; type ImplScopes = @list<ImplScope>; @@ -925,7 +934,8 @@ class Resolver { @{ did: local_def(method.id), n_tps: method.tps.len(), - ident: method.ident + ident: method.ident, + self_type: method.self_ty.node } ]; } @@ -962,7 +972,8 @@ class Resolver { @{ did: local_def(method.id), n_tps: method.tps.len(), - ident: method.ident + ident: method.ident, + self_type: method.self_ty.node } ]; } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index f2903232400..71e0fedef61 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -183,6 +183,7 @@ type param_bounds = @~[param_bound]; type method = {ident: ast::ident, tps: @~[param_bounds], fty: fn_ty, + self_ty: ast::self_ty_, purity: ast::purity, vis: ast::visibility}; diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index ac18b8ccad6..08f36bdb256 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -1,12 +1,14 @@ /* Code to handle method lookups (which can be quite complex) */ import coherence::get_base_type_def_id; -import middle::resolve3::Impl; +import middle::resolve3::{Impl, MethodInfo}; +import middle::ty::{mk_box, mk_rptr, mk_uniq}; import middle::typeck::infer::methods; // next_ty_vars -import syntax::ast::def_id; +import syntax::ast::{def_id, sty_box, sty_by_ref, sty_region, sty_uniq}; +import syntax::ast::{sty_value}; import syntax::ast_map; import syntax::ast_map::node_id_to_str; -import syntax::ast_util::new_def_hash; +import syntax::ast_util::{dummy_sp, new_def_hash}; import dvec::{dvec, extensions}; type candidate = { @@ -18,6 +20,28 @@ type candidate = { entry: method_map_entry }; +fn transform_self_type_for_method(fcx: @fn_ctxt, + impl_ty: ty::t, + method_info: MethodInfo) + -> ty::t { + alt method_info.self_type { + 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_box(mutability) => { + mk_box(fcx.ccx.tcx, { ty: impl_ty, mutbl: mutability }) + } + sty_uniq(mutability) => { + mk_uniq(fcx.ccx.tcx, { ty: impl_ty, mutbl: mutability }) + } + } +} + class lookup { let fcx: @fn_ctxt; let expr: @ast::expr; @@ -370,6 +394,10 @@ class lookup { let {substs: impl_substs, ty: impl_ty} = impl_self_ty(self.fcx, im.did); + let impl_ty = transform_self_type_for_method(self.fcx, + impl_ty, + *m); + // Depending on our argument, we find potential // matches either by checking subtypability or // type assignability. Collect the matches. diff --git a/src/rustc/middle/typeck/coherence.rs b/src/rustc/middle/typeck/coherence.rs index e3fdd0424b7..091980ceb39 100644 --- a/src/rustc/middle/typeck/coherence.rs +++ b/src/rustc/middle/typeck/coherence.rs @@ -492,7 +492,8 @@ class CoherenceChecker { push(methods, @{ did: local_def(ast_method.id), n_tps: ast_method.tps.len(), - ident: ast_method.ident + ident: ast_method.ident, + self_type: ast_method.self_ty.node }); } @@ -513,7 +514,8 @@ class CoherenceChecker { push(methods, @{ did: local_def(ast_method.id), n_tps: ast_method.tps.len(), - ident: ast_method.ident + ident: ast_method.ident, + self_type: ast_method.self_ty.node }); } } diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index 22063051dce..0c16fc16933 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -432,6 +432,7 @@ fn ty_of_method(ccx: @crate_ctxt, tps: ty_param_bounds(ccx, m.tps), fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl, none), + self_ty: m.self_ty.node, purity: m.decl.purity, vis: m.vis} } @@ -444,6 +445,7 @@ fn ty_of_ty_method(self: @crate_ctxt, fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl, none), // assume public, because this is only invoked on trait methods + self_ty: m.self_ty.node, purity: m.decl.purity, vis: ast::public} } |
