diff options
| author | Michael Sullivan <sully@msully.net> | 2012-08-02 16:01:38 -0700 |
|---|---|---|
| committer | Michael Sullivan <sully@msully.net> | 2012-08-07 17:18:14 -0700 |
| commit | 7f7f47620eaeaab8e4993e568d2f5c23e1cb6416 (patch) | |
| tree | 3e93c8b6772ae3d87b090766661e429215b2cbad /src/rustc | |
| parent | a695e074f23e1c5353947c1d0e0c2b418750b80d (diff) | |
| download | rust-7f7f47620eaeaab8e4993e568d2f5c23e1cb6416.tar.gz rust-7f7f47620eaeaab8e4993e568d2f5c23e1cb6416.zip | |
Implement static typeclass methods. Closes #3132.
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/metadata/csearch.rs | 2 | ||||
| -rw-r--r-- | src/rustc/metadata/decoder.rs | 29 | ||||
| -rw-r--r-- | src/rustc/metadata/encoder.rs | 77 | ||||
| -rw-r--r-- | src/rustc/middle/astencode.rs | 17 | ||||
| -rw-r--r-- | src/rustc/middle/borrowck/categorization.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/resolve3.rs | 321 | ||||
| -rw-r--r-- | src/rustc/middle/trans/base.rs | 3 | ||||
| -rw-r--r-- | src/rustc/middle/trans/impl.rs | 64 | ||||
| -rw-r--r-- | src/rustc/middle/trans/type_use.rs | 6 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check.rs | 8 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check/method.rs | 7 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/collect.rs | 73 |
12 files changed, 396 insertions, 213 deletions
diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs index 627d7a326d0..203b527b21f 100644 --- a/src/rustc/metadata/csearch.rs +++ b/src/rustc/metadata/csearch.rs @@ -144,7 +144,7 @@ fn get_trait_methods(tcx: ty::ctxt, def: ast::def_id) -> @~[ty::method] { } fn get_method_names_if_trait(cstore: cstore::cstore, def: ast::def_id) - -> option<@dvec<@~str>> { + -> option<@dvec<(@~str, ast::self_ty_)>> { let cdata = cstore::get_crate_data(cstore, def.crate); return decoder::get_method_names_if_trait(cdata, def.node); diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 2fae50785af..fdb4be4c6e0 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -282,7 +282,10 @@ fn item_to_def_like(item: ebml::doc, did: ast::def_id, cnum: ast::crate_num) 'u' => dl_def(ast::def_fn(did, ast::unsafe_fn)), 'f' => dl_def(ast::def_fn(did, ast::impure_fn)), 'p' => dl_def(ast::def_fn(did, ast::pure_fn)), - 'F' => dl_def(ast::def_fn(did, ast::extern_fn)), + 'e' => dl_def(ast::def_fn(did, ast::extern_fn)), + 'U' => dl_def(ast::def_static_method(did, ast::unsafe_fn)), + 'F' => dl_def(ast::def_static_method(did, ast::impure_fn)), + 'P' => dl_def(ast::def_static_method(did, ast::pure_fn)), 'y' => dl_def(ast::def_ty(did)), 't' => dl_def(ast::def_ty(did)), 'm' => dl_def(ast::def_mod(did)), @@ -592,6 +595,7 @@ fn get_self_ty(item: ebml::doc) -> ast::self_ty_ { let self_ty_kind = string[0]; match self_ty_kind as char { + 's' => { return ast::sty_static; } 'r' => { return ast::sty_by_ref; } 'v' => { return ast::sty_value; } '@' => { return ast::sty_box(get_mutability(string[1])); } @@ -693,21 +697,23 @@ fn get_trait_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) @result } -// If the item in question is a trait, returns its set of methods. Otherwise, -// returns none. +// If the item in question is a trait, returns its set of methods and +// their self types. Otherwise, returns none. This overlaps in an +// annoying way with get_trait_methods. fn get_method_names_if_trait(cdata: cmd, node_id: ast::node_id) - -> option<@dvec<@~str>> { + -> option<@dvec<(@~str, ast::self_ty_)>> { let item = lookup_item(node_id, cdata.data); if item_family(item) != 'I' { return none; } - let resulting_method_names = @dvec(); + let resulting_methods = @dvec(); for ebml::tagged_docs(item, tag_item_trait_method) |method| { - (*resulting_method_names).push(item_name(method)); + resulting_methods.push( + (item_name(method), get_self_ty(method))); } - return some(resulting_method_names); + return some(resulting_methods); } fn get_item_attrs(cdata: cmd, @@ -757,7 +763,7 @@ fn get_class_fields(cdata: cmd, id: ast::node_id) -> ~[ty::field_ty] { fn family_has_type_params(fam_ch: char) -> bool { match check fam_ch { - 'c' | 'T' | 'm' | 'n' | 'g' | 'h' | 'j' => false, + 'c' | 'T' | 'm' | 'n' | 'g' | 'h' | 'j' | 'e' => false, 'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' | 'C' | 'a' | 'S' => true @@ -791,9 +797,10 @@ fn item_family_to_str(fam: char) -> ~str { 'f' => return ~"fn", 'u' => return ~"unsafe fn", 'p' => return ~"pure fn", - 'F' => return ~"foreign fn", - 'U' => return ~"unsafe foreign fn", - 'P' => return ~"pure foreign fn", + 'F' => return ~"static method", + 'U' => return ~"unsafe static method", + 'P' => return ~"pure static method", + 'e' => return ~"foreign fn", 'y' => return ~"type", 'T' => return ~"foreign type", 't' => return ~"type", diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index 545d3821f02..4c535f8af09 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -122,6 +122,21 @@ fn encode_enum_variant_paths(ebml_w: ebml::writer, variants: ~[variant], } } +fn encode_trait_static_method_paths(ebml_w: ebml::writer, + methods: ~[trait_method], + path: ~[ident], + &index: ~[entry<~str>]) { + for methods.each |method| { + let ty_m = trait_method_to_ty_method(method); + if ty_m.self_ty.node != sty_static { again; } + add_to_index(ebml_w, path, index, ty_m.ident); + do ebml_w.wr_tag(tag_paths_data_item) { + encode_name(ebml_w, ty_m.ident); + encode_def_id(ebml_w, local_def(ty_m.id)); + } + } +} + fn add_to_index(ebml_w: ebml::writer, path: &[ident], &index: ~[entry<~str>], name: ident) { let mut full_path = ~[]; @@ -214,10 +229,11 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, } encode_enum_variant_paths(ebml_w, variants, path, index); } - item_trait(*) => { + item_trait(_, _, methods) => { do ebml_w.wr_tag(tag_paths_data_item) { - encode_name_and_def_id(ebml_w, it.ident, it.id); - } + encode_name_and_def_id(ebml_w, it.ident, it.id); + } + encode_trait_static_method_paths(ebml_w, methods, path, index); } item_impl(*) => {} item_mac(*) => fail ~"item macros unimplemented" @@ -286,8 +302,8 @@ fn encode_family(ebml_w: ebml::writer, c: char) { fn def_to_str(did: def_id) -> ~str { fmt!{"%d:%d", did.crate, did.node} } -fn encode_type_param_bounds(ebml_w: ebml::writer, ecx: @encode_ctxt, - params: ~[ty_param]) { +fn encode_ty_type_param_bounds(ebml_w: ebml::writer, ecx: @encode_ctxt, + params: @~[ty::param_bounds]) { let ty_str_ctxt = @{diag: ecx.diag, ds: def_to_str, tcx: ecx.tcx, @@ -295,12 +311,19 @@ fn encode_type_param_bounds(ebml_w: ebml::writer, ecx: @encode_ctxt, abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; for params.each |param| { ebml_w.start_tag(tag_items_data_item_ty_param_bounds); - let bs = ecx.tcx.ty_param_bounds.get(param.id); - tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, bs); + tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, param); ebml_w.end_tag(); } } +fn encode_type_param_bounds(ebml_w: ebml::writer, ecx: @encode_ctxt, + params: ~[ty_param]) { + let ty_param_bounds = + @params.map(|param| ecx.tcx.ty_param_bounds.get(param.id)); + encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds); +} + + fn encode_variant_id(ebml_w: ebml::writer, vid: def_id) { ebml_w.start_tag(tag_items_data_item_variant); ebml_w.writer.write(str::bytes(def_to_str(vid))); @@ -472,6 +495,7 @@ fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) { // Encode the base self type. let ch; match self_type { + sty_static => { ch = 's' as u8; } sty_by_ref => { ch = 'r' as u8; } sty_value => { ch = 'v' as u8; } sty_region(_, _) => { ch = '&' as u8; } @@ -482,7 +506,7 @@ fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) { // Encode mutability. match self_type { - sty_by_ref | sty_value => { /* No-op. */ } + sty_static | 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 ]); } @@ -499,7 +523,7 @@ fn encode_self_type(ebml_w: ebml::writer, self_type: ast::self_ty_) { sty_region(region, _) => { encode_region(ebml_w, *region); } - sty_by_ref | sty_value | sty_box(*) | sty_uniq(*) => { + sty_static | sty_by_ref | sty_value | sty_box(*) | sty_uniq(*) => { // Nothing to do. } } @@ -608,7 +632,15 @@ fn purity_fn_family(p: purity) -> char { unsafe_fn => 'u', pure_fn => 'p', impure_fn => 'f', - extern_fn => 'F' + extern_fn => 'e' + } +} +fn purity_static_method_family(p: purity) -> char { + match p { + unsafe_fn => 'U', + pure_fn => 'P', + impure_fn => 'F', + extern_fn => 'E' } } @@ -853,6 +885,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, match ms[i] { required(ty_m) => { ebml_w.start_tag(tag_item_trait_method); + encode_def_id(ebml_w, local_def(ty_m.id)); encode_name(ebml_w, mty.ident); encode_type_param_bounds(ebml_w, ecx, ty_m.tps); encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty)); @@ -873,6 +906,30 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_trait_ref(ebml_w, ecx, associated_trait) } ebml_w.end_tag(); + + // Now, output all of the static methods as items. Note that for the + // method info, we output static methods with type signatures as + // written. Here, we output the *real* type signatures. I feel like + // maybe we should only ever handle the real type signatures. + for vec::each(ms) |m| { + let ty_m = ast_util::trait_method_to_ty_method(m); + if ty_m.self_ty.node != ast::sty_static { again; } + + vec::push(*index, {val: ty_m.id, pos: ebml_w.writer.tell()}); + + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(ty_m.id)); + encode_name(ebml_w, ty_m.ident); + encode_family(ebml_w, + purity_static_method_family(ty_m.decl.purity)); + let polyty = ecx.tcx.tcache.get(local_def(ty_m.id)); + encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds); + encode_type(ecx, ebml_w, polyty.ty); + encode_path(ebml_w, path, ast_map::path_name(ty_m.ident)); + ebml_w.end_tag(); + } + + } item_mac(*) => fail ~"item macros unimplemented" } diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index b1b54816998..cf0b586e51e 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -353,13 +353,16 @@ fn decode_def(xcx: extended_decode_ctxt, doc: ebml::doc) -> ast::def { impl of tr for ast::def { fn tr(xcx: extended_decode_ctxt) -> ast::def { match self { - ast::def_fn(did, p) => ast::def_fn(did.tr(xcx), p), - ast::def_self(nid) => ast::def_self(xcx.tr_id(nid)), - ast::def_mod(did) => ast::def_mod(did.tr(xcx)), - ast::def_foreign_mod(did) => ast::def_foreign_mod(did.tr(xcx)), - ast::def_const(did) => ast::def_const(did.tr(xcx)), - ast::def_arg(nid, m) => ast::def_arg(xcx.tr_id(nid), m), - ast::def_local(nid, b) => ast::def_local(xcx.tr_id(nid), b), + ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) } + ast::def_static_method(did, p) => { + ast::def_static_method(did.tr(xcx), p) + } + ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) } + ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) } + ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) } + ast::def_const(did) => { ast::def_const(did.tr(xcx)) } + ast::def_arg(nid, m) => { ast::def_arg(xcx.tr_id(nid), m) } + ast::def_local(nid, b) => { ast::def_local(xcx.tr_id(nid), b) } ast::def_variant(e_did, v_did) => { ast::def_variant(e_did.tr(xcx), v_did.tr(xcx)) } diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs index 2d76607e8fa..41204f117a5 100644 --- a/src/rustc/middle/borrowck/categorization.rs +++ b/src/rustc/middle/borrowck/categorization.rs @@ -191,7 +191,7 @@ impl public_methods for borrowck_ctxt { expr_ty: ty::t, def: ast::def) -> cmt { match def { - ast::def_fn(*) | ast::def_mod(_) | + ast::def_fn(*) | ast::def_static_method(*) | ast::def_mod(_) | ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(*) | ast::def_ty(_) | ast::def_prim_ty(_) | diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index a2bd1280021..7efd7442380 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -16,7 +16,7 @@ import syntax::ast::{class_member, class_method, crate, crate_num, decl_item}; import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn}; import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod}; import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; -import syntax::ast::{def_typaram_binder}; +import syntax::ast::{def_typaram_binder, def_static_method}; import syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; import syntax::ast::{expr_binary, expr_cast, expr_field, expr_fn}; import syntax::ast::{expr_fn_block, expr_index, expr_path}; @@ -30,17 +30,18 @@ import syntax::ast::{instance_var, item, item_class, item_const, item_enum}; import syntax::ast::{item_fn, item_mac, item_foreign_mod, item_impl}; 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, pat_struct, path, prim_ty, pat_box, pat_uniq}; -import syntax::ast::{pat_lit, pat_range, pat_rec, pat_tup, pat_wild}; +import syntax::ast::{pat_ident, path, prim_ty, pat_box, pat_uniq, pat_lit}; +import syntax::ast::{pat_range, pat_rec, pat_struct, pat_tup, pat_wild}; import syntax::ast::{provided, required, rem, self_ty_, shl, stmt_decl}; -import syntax::ast::{subtract, ty, ty_bool, ty_char, ty_f, ty_f32, ty_f64}; -import syntax::ast::{ty_float, ty_i, ty_i16, ty_i32, ty_i64, ty_i8, ty_int}; -import syntax::ast::{ty_param, ty_path, ty_str, ty_u, ty_u16, ty_u32, ty_u64}; -import syntax::ast::{ty_u8, ty_uint, variant, view_item, view_item_export}; +import syntax::ast::{sty_static, 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, path_to_ident}; +import syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; import syntax::attr::{attr_metas, contains_name}; import syntax::print::pprust::{pat_to_str, path_to_str}; import syntax::codemap::span; @@ -1079,18 +1080,25 @@ class Resolver { // Add the names of all the methods to the trait info. let method_names = @atom_hashmap(); for methods.each |method| { - let atom; - match method { - required(required_method) => { - atom = (*self.atom_table).intern - (required_method.ident); - } - provided(provided_method) => { - atom = (*self.atom_table).intern - (provided_method.ident); - } + let ty_m = trait_method_to_ty_method(method); + + let atom = (*self.atom_table).intern(ty_m.ident); + // Add it to the trait info if not static, + // add it as a name in the enclosing module otherwise. + match ty_m.self_ty.node { + sty_static => { + // which parent to use?? + let (method_name_bindings, _) = + self.add_child(atom, new_parent, ~[ValueNS], + ty_m.span); + let def = def_static_method(local_def(ty_m.id), + ty_m.decl.purity); + (*method_name_bindings).define_value(def, ty_m.span); + } + _ => { + (*method_names).insert(atom, ()); + } } - (*method_names).insert(atom, ()); } let def_id = local_def(item.id); @@ -1338,6 +1346,124 @@ class Resolver { visit_block(block, new_parent, visitor); } + fn handle_external_def(def: def, modules: hashmap<def_id, @Module>, + child_name_bindings: @NameBindings, + final_ident: ~str, + atom: Atom, new_parent: ReducedGraphParent) { + match def { + def_mod(def_id) | def_foreign_mod(def_id) => { + match copy child_name_bindings.module_def { + NoModuleDef => { + debug!("(building reduced graph for \ + external crate) building module \ + %s", final_ident); + let parent_link = self.get_parent_link(new_parent, atom); + + match modules.find(def_id) { + none => { + child_name_bindings.define_module(parent_link, + some(def_id), + dummy_sp()); + modules.insert(def_id, + child_name_bindings.get_module()); + } + some(existing_module) => { + // Create an import resolution to + // avoid creating cycles in the + // module graph. + + let resolution = @ImportResolution(dummy_sp()); + resolution.outstanding_references = 0; + + match existing_module.parent_link { + NoParentLink | + BlockParentLink(*) => { + fail ~"can't happen"; + } + ModuleParentLink(parent_module, atom) => { + + let name_bindings = parent_module.children.get(atom); + + resolution.module_target = + some(Target(parent_module, name_bindings)); + } + } + + debug!("(building reduced graph for external crate) \ + ... creating import resolution"); + + new_parent.import_resolutions.insert(atom, resolution); + } + } + } + ModuleDef(module_) => { + debug!("(building reduced graph for \ + external crate) already created \ + module"); + module_.def_id = some(def_id); + modules.insert(def_id, module_); + } + } + } + def_fn(def_id, _) | def_static_method(def_id, _) | + def_const(def_id) | def_variant(_, def_id) => { + debug!("(building reduced graph for external \ + crate) building value %s", final_ident); + (*child_name_bindings).define_value(def, dummy_sp()); + } + def_ty(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + // If this is a trait, add all the method names + // to the trait info. + + match get_method_names_if_trait(self.session.cstore, + def_id) { + none => { + // Nothing to do. + } + some(method_names) => { + let interned_method_names = @atom_hashmap(); + for method_names.each |method_data| { + let (method_name, self_ty) = method_data; + debug!("(building reduced graph for \ + external crate) ... adding \ + trait method '%?'", method_name); + + let m_atom = self.atom_table.intern(method_name); + + // Add it to the trait info if not static. + if self_ty != sty_static { + interned_method_names.insert(m_atom, ()); + } + } + self.trait_info.insert(def_id, interned_method_names); + } + } + + child_name_bindings.define_type(def, dummy_sp()); + } + def_class(def_id, has_constructor) => { + debug!("(building reduced graph for external \ + crate) building type %s (value? %d)", + final_ident, + if has_constructor { 1 } else { 0 }); + child_name_bindings.define_type(def, dummy_sp()); + + if has_constructor { + child_name_bindings.define_value(def, dummy_sp()); + } + } + def_self(*) | def_arg(*) | def_local(*) | + def_prim_ty(*) | def_ty_param(*) | def_binding(*) | + def_use(*) | def_upvar(*) | def_region(*) | + def_typaram_binder(*) => { + fail fmt!("didn't expect `%?`", def); + } + } + } + /** * Builds the reduced graph rooted at the 'use' directive for an external * crate. @@ -1395,145 +1521,9 @@ class Resolver { match path_entry.def_like { dl_def(def) => { - match def { - def_mod(def_id) | def_foreign_mod(def_id) => { - match copy child_name_bindings.module_def { - NoModuleDef => { - debug!{"(building reduced graph for \ - external crate) building module \ - %s", final_ident}; - let parent_link = - self.get_parent_link(new_parent, - atom); - - match modules.find(def_id) { - none => { - (*child_name_bindings). - define_module(parent_link, - some(def_id), - dummy_sp()); - modules.insert(def_id, - (*child_name_bindings). - get_module()); - } - some(existing_module) => { - // Create an import resolution to - // avoid creating cycles in the - // module graph. - - let resolution = - @ImportResolution(dummy_sp()); - resolution. - outstanding_references = 0; - - match existing_module - .parent_link { - - NoParentLink | - BlockParentLink(*) => { - fail ~"can't happen"; - } - ModuleParentLink - (parent_module, - atom) => { - - let name_bindings = - parent_module. - children.get - (atom); - - resolution.module_target = - some(Target - (parent_module, - name_bindings)); - } - } - - debug!{"(building reduced graph \ - for external crate) \ - ... creating import \ - resolution"}; - - new_parent.import_resolutions. - insert(atom, resolution); - } - } - } - ModuleDef(module_) => { - debug!{"(building reduced graph for \ - external crate) already created \ - module"}; - module_.def_id = some(def_id); - modules.insert(def_id, module_); - } - } - } - def_fn(def_id, _) | def_const(def_id) | - def_variant(_, def_id) => { - debug!{"(building reduced graph for external \ - crate) building value %s", final_ident}; - // Might want a better span - (*child_name_bindings).define_value(def, - dummy_sp()); - } - def_ty(def_id) => { - debug!{"(building reduced graph for external \ - crate) building type %s", final_ident}; - - // If this is a trait, add all the method names - // to the trait info. - - match get_method_names_if_trait( - self.session.cstore, def_id) { - - none => { - // Nothing to do. - } - some(method_names) => { - let interned_method_names = - @atom_hashmap(); - for method_names.each |method_name| { - debug!{"(building reduced graph for \ - external crate) ... adding \ - trait method '%?'", - method_name}; - let atom = - (*self.atom_table).intern - (method_name); - (*interned_method_names).insert(atom, - ()); - } - self.trait_info.insert - (def_id, interned_method_names); - } - } - - // Might want a better span - (*child_name_bindings).define_type(def, - dummy_sp()); - } - def_class(def_id, has_constructor) => { - debug!{"(building reduced graph for external \ - crate) building type %s (value? %d)", - final_ident, - if has_constructor { 1 } else { 0 }}; - // Might want a better span - (*child_name_bindings).define_type(def, - dummy_sp()); - - // Might want a better span - if has_constructor { - (*child_name_bindings).define_value(def, - dummy_sp()); - } - } - def_self(*) | def_arg(*) | def_local(*) | - def_prim_ty(*) | def_ty_param(*) | def_binding(*) | - def_use(*) | def_upvar(*) | def_region(*) | - def_typaram_binder(*) => { - fail fmt!{"didn't expect `%?`", def}; - } - } + self.handle_external_def(def, modules, + child_name_bindings, + final_ident, atom, new_parent); } dl_impl(_) => { // Because of the infelicitous way the metadata is @@ -3589,11 +3579,17 @@ class Resolver { method.id, outer_type_parameter_count, rib_kind); + // we only have self ty if it is a non static method + let self_binding = match method.self_ty.node { + sty_static => { NoSelfBinding } + _ => { HasSelfBinding(method.self_id) } + }; + self.resolve_function(rib_kind, some(@method.decl), type_parameters, method.body, - HasSelfBinding(method.self_id), + self_binding, NoCaptureClause, visitor); } @@ -3647,7 +3643,11 @@ class Resolver { for methods.each |method| { // We also need a new scope for the method-specific // type parameters. - + self.resolve_method(MethodRibKind(id, Provided(method.id)), + method, + outer_type_parameter_count, + visitor); +/* let borrowed_type_parameters = &method.tps; self.resolve_function(MethodRibKind(id, Provided(method.id)), some(@method.decl), @@ -3660,6 +3660,7 @@ class Resolver { HasSelfBinding(method.self_id), NoCaptureClause, visitor); +*/ } // Restore the original trait references. diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 36397250f1a..11643f8a5ee 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2454,6 +2454,9 @@ fn trans_var(cx: block, def: ast::def, id: ast::node_id)-> lval_maybe_callee { ast::def_fn(did, _) => { return lval_static_fn(cx, did, id); } + ast::def_static_method(did, _) => { + return impl::trans_static_method_callee(cx, did, id); + } ast::def_variant(tid, vid) => { if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u { // N-ary variant. diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index 7bac09e3706..5d821dbd86d 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -26,10 +26,15 @@ 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_arg = match m.self_ty.node { + ast::sty_static => { no_self } + _ => { impl_self(ty::node_id_to_type(ccx.tcx, m.self_id)) } + }; + trans_fn(ccx, vec::append_one(sub_path, path_name(m.ident)), m.decl, m.body, - llfn, impl_self(ty::node_id_to_type(ccx.tcx, m.self_id)), + llfn, self_arg, none, m.id); } } @@ -65,8 +70,9 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id, param_num:p, bound_num:b}) => { match check bcx.fcx.param_substs { some(substs) => { + let vtbl = find_vtable_in_fn_ctxt(substs, p, b); trans_monomorphized_callee(bcx, callee_id, self, mentry.derefs, - iid, off, p, b, substs) + iid, off, vtbl) } } } @@ -81,6 +87,54 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id, } } +fn trans_static_method_callee(bcx: block, method_id: ast::def_id, + callee_id: ast::node_id) -> lval_maybe_callee { + let _icx = bcx.insn_ctxt(~"impl::trans_static_method_callee"); + let ccx = bcx.ccx(); + + let mname = if method_id.crate == ast::local_crate { + match check bcx.tcx().items.get(method_id.node) { + ast_map::node_trait_method(trait_method, _, _) => { + ast_util::trait_method_to_ty_method(*trait_method).ident + } + } + } else { + let path = csearch::get_item_path(bcx.tcx(), method_id); + match path[path.len()-1] { + path_name(s) => { s } + path_mod(_) => { fail ~"path doesn't have a name?" } + } + }; + debug!("trans_static_method_callee: method_id=%?, callee_id=%?, \ + name=%s", method_id, callee_id, *mname); + + let vtbls = resolve_vtables_in_fn_ctxt( + bcx.fcx, ccx.maps.vtable_map.get(callee_id)); + + match vtbls[0] { // is index 0 always the one we want? + typeck::vtable_static(impl_did, impl_substs, sub_origins) => { + + let mth_id = method_with_name(bcx.ccx(), impl_did, mname); + let n_m_tps = method_ty_param_count(ccx, mth_id, impl_did); + let node_substs = node_id_type_params(bcx, callee_id); + let ty_substs + = vec::append(impl_substs, + vec::tailn(node_substs, + node_substs.len() - n_m_tps)); + + let lval = lval_static_fn_inner(bcx, mth_id, callee_id, ty_substs, + some(sub_origins)); + {env: null_env, + val: PointerCast(bcx, lval.val, T_ptr(type_of_fn_from_ty( + ccx, node_id_type(bcx, callee_id)))) + with lval} + } + _ => { + fail ~"vtable_param left in monomorphized function's vtable substs"; + } + } +} + fn method_from_methods(ms: ~[@ast::method], name: ast::ident) -> ast::def_id { local_def(option::get(vec::find(ms, |m| m.ident == name)).id) @@ -119,10 +173,10 @@ fn method_ty_param_count(ccx: @crate_ctxt, m_id: ast::def_id, fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id, base: @ast::expr, derefs: uint, trait_id: ast::def_id, n_method: uint, - n_param: uint, n_bound: uint, - substs: param_substs) -> lval_maybe_callee { + vtbl: typeck::vtable_origin) + -> lval_maybe_callee { let _icx = bcx.insn_ctxt(~"impl::trans_monomorphized_callee"); - match find_vtable_in_fn_ctxt(substs, n_param, n_bound) { + match vtbl { typeck::vtable_static(impl_did, impl_substs, sub_origins) => { let ccx = bcx.ccx(); let mname = ty::trait_methods(ccx.tcx, trait_id)[n_method].ident; diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index a48e594818f..fda5902e594 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -69,6 +69,12 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint) ast_map::node_method(@{body, _}, _, _) => { handle_body(cx, body); } + ast_map::node_trait_method(*) => { + // This will be a static trait method. For now, we just assume + // it fully depends on all of the type information. (Doing + // otherwise would require finding the actual implementation). + for uint::range(0u, n_tps) |n| { cx.uses[n] |= use_repr|use_tydesc;} + } ast_map::node_variant(_, _, _) => { for uint::range(0u, n_tps) |n| { cx.uses[n] |= use_repr;} } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index d5165e26a2b..cb723bca83d 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -2179,14 +2179,16 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> }; } - ast::def_fn(id, ast::unsafe_fn) => { + ast::def_fn(id, ast::unsafe_fn) | + ast::def_static_method(id, ast::unsafe_fn) => { // Unsafe functions can only be touched in an unsafe context fcx.require_unsafe(sp, ~"access to unsafe function"); return ty::lookup_item_type(fcx.ccx.tcx, id); } - ast::def_fn(id, _) | ast::def_const(id) | - ast::def_variant(_, id) | ast::def_class(id, _) => { + ast::def_fn(id, _) | ast::def_static_method(id, _) | + ast::def_const(id) | ast::def_variant(_, id) | + ast::def_class(id, _) => { return ty::lookup_item_type(fcx.ccx.tcx, id); } ast::def_binding(nid, _) => { diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index 905f1f10137..2f2da5b65bc 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -4,7 +4,8 @@ import coherence::get_base_type_def_id; 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, sty_box, sty_by_ref, sty_region, sty_uniq}; +import syntax::ast::{def_id, + sty_static, 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; @@ -25,6 +26,10 @@ fn transform_self_type_for_method(fcx: @fn_ctxt, method_info: MethodInfo) -> ty::t { match method_info.self_type { + sty_static => { + fcx.tcx().sess.bug(~"calling transform_self_type_for_method on \ + static method"); + } sty_by_ref | sty_value => { impl_ty } diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index 2abc201d132..eb2f31d1c16 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -21,6 +21,7 @@ are represented as `ty_param()` instances. */ import astconv::{ast_conv, ty_of_fn_decl, ty_of_arg, ast_ty_to_ty}; +import ast_util::trait_method_to_ty_method; import rscope::*; fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) { @@ -147,19 +148,54 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id) { ty::store_trait_methods(ccx.tcx, id, @vec::map(stuff, f)); } + fn make_static_method_ty(ccx: @crate_ctxt, id: ast::node_id, + am: ast::ty_method, + rp: bool, m: ty::method, + trait_bounds: @~[ty::param_bounds]) { + // We need to create a typaram that replaces self. This param goes + // *in between* the typarams from the trait and those from the + // method (since its bound can depend on the trait? or + // something like that). + + // build up a subst that shifts all of the parameters over + // by one and substitute in a new type param for self + + let dummy_defid = {crate: 0, node: 0}; + + let non_shifted_trait_tps = do vec::from_fn(trait_bounds.len()) |i| { + ty::mk_param(ccx.tcx, i, dummy_defid) + }; + let self_param = ty::mk_param(ccx.tcx, trait_bounds.len(), + dummy_defid); + let shifted_method_tps = do vec::from_fn(m.tps.len()) |i| { + ty::mk_param(ccx.tcx, i + 1, dummy_defid) + }; + + let substs = { self_r: none, self_ty: some(self_param), + tps: non_shifted_trait_tps + shifted_method_tps }; + + let ty = ty::subst(ccx.tcx, substs, ty::mk_fn(ccx.tcx, m.fty)); + let trait_ty = ty::node_id_to_type(ccx.tcx, id); + let bounds = @(*trait_bounds + ~[@~[ty::bound_trait(trait_ty)]] + + *m.tps); + ccx.tcx.tcache.insert(local_def(am.id), + {bounds: bounds, rp: rp, ty: ty}); + } + + let tcx = ccx.tcx; let rp = tcx.region_paramd_items.contains_key(id); match check tcx.items.get(id) { - ast_map::node_item(@{node: ast::item_trait(_, _, ms), _}, _) => { + ast_map::node_item(@{node: ast::item_trait(params, _, ms), _}, _) => { store_methods::<ast::trait_method>(ccx, id, ms, |m| { - match m { - required(ty_m) => { - ty_of_ty_method(ccx, ty_m, rp) - } - provided(m) => { - ty_of_method(ccx, m, rp) - } + let trait_bounds = ty_param_bounds(ccx, params); + let ty_m = trait_method_to_ty_method(m); + let method_ty = ty_of_ty_method(ccx, ty_m, rp); + if ty_m.self_ty.node == ast::sty_static { + make_static_method_ty(ccx, id, ty_m, rp, + method_ty, trait_bounds); } + method_ty }); } ast_map::node_item(@{node: ast::item_class(struct_def, _), _}, _) => { @@ -190,6 +226,21 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, trait_m: ty::method, trait_substs: ty::substs, self_ty: ty::t) { + if impl_m.purity != trait_m.purity { + tcx.sess.span_err( + sp, fmt!{"method `%s`'s purity does \ + not match the trait method's \ + purity", *impl_m.ident}); + } + + // is this check right? + if impl_m.self_ty != trait_m.self_ty { + tcx.sess.span_err( + sp, fmt!{"method `%s`'s self type does \ + not match the trait method's \ + self type", *impl_m.ident}); + } + if impl_m.tps != trait_m.tps { tcx.sess.span_err(sp, ~"method `" + *trait_m.ident + ~"` has an incompatible set of type parameters"); @@ -259,12 +310,6 @@ fn check_methods_against_trait(ccx: @crate_ctxt, for vec::each(*ty::trait_methods(tcx, did)) |trait_m| { match vec::find(impl_ms, |impl_m| trait_m.ident == impl_m.mty.ident) { some({mty: impl_m, id, span}) => { - if impl_m.purity != trait_m.purity { - ccx.tcx.sess.span_err( - span, fmt!{"method `%s`'s purity does \ - not match the trait method's \ - purity", *impl_m.ident}); - } compare_impl_method( ccx.tcx, span, impl_m, vec::len(tps), trait_m, tpt.substs, selfty); |
