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 | |
| parent | a695e074f23e1c5353947c1d0e0c2b418750b80d (diff) | |
| download | rust-7f7f47620eaeaab8e4993e568d2f5c23e1cb6416.tar.gz rust-7f7f47620eaeaab8e4993e568d2f5c23e1cb6416.zip | |
Implement static typeclass methods. Closes #3132.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libsyntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ast_util.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 54 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 50 | ||||
| -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 | ||||
| -rw-r--r-- | src/test/auxiliary/static-methods-crate.rs | 33 | ||||
| -rw-r--r-- | src/test/compile-fail/staticness-mismatch.rs | 10 | ||||
| -rw-r--r-- | src/test/run-pass/static-method-test.rs | 79 | ||||
| -rw-r--r-- | src/test/run-pass/static-method-xcrate.rs | 12 |
20 files changed, 605 insertions, 246 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 78b1fa0a469..0cc433fdeba 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -71,6 +71,7 @@ type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]}; #[auto_serialize] enum def { def_fn(def_id, purity), + def_static_method(def_id, purity), def_self(node_id), def_mod(def_id), def_foreign_mod(def_id), @@ -596,6 +597,7 @@ enum ret_style { #[auto_serialize] 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` diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index caaf6cca5b1..7bbdac4db3c 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -53,7 +53,7 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} { pure fn def_id_of_def(d: def) -> def_id { match d { - def_fn(id, _) | def_mod(id) | + def_fn(id, _) | def_static_method(id, _) | def_mod(id) | def_foreign_mod(id) | def_const(id) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | def_use(id) | def_class(id, _) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 52a93a60361..780eff1f757 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,20 +43,24 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute, match_nonterminal, match_seq, match_tok, method, mode, mt, mul, mutability, neg, noreturn, not, pat, pat_box, pat_enum, pat_ident, pat_lit, pat_range, pat_rec, pat_struct, pat_tup, - pat_uniq, pat_wild, path, private, proto, proto_bare, - proto_block, proto_box, proto_uniq, provided, public, pure_fn, - purity, re_anon, re_named, region, rem, required, ret_style, - return_val, self_ty, shl, shr, stmt, stmt_decl, stmt_expr, - stmt_semi, subtract, sty_box, sty_by_ref, sty_region, sty_uniq, - sty_value, token_tree, trait_method, trait_ref, tt_delim, tt_seq, - tt_tok, tt_nonterminal, tuple_variant_kind, ty, ty_, ty_bot, - ty_box, ty_field, ty_fn, ty_infer, ty_mac, ty_method, ty_nil, - ty_param, ty_param_bound, ty_path, ty_ptr, ty_rec, ty_rptr, - ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length, unchecked_blk, - uniq, unsafe_blk, unsafe_fn, variant, view_item, view_item_, - view_item_export, view_item_import, view_item_use, view_path, - view_path_glob, view_path_list, view_path_simple, visibility, - vstore, vstore_box, vstore_fixed, vstore_slice, vstore_uniq}; + pat_uniq, + pat_wild, path, private, proto, proto_bare, proto_block, + proto_box, proto_uniq, provided, public, pure_fn, purity, + re_anon, re_named, region, rem, required, ret_style, return_val, + self_ty, shl, shr, stmt, stmt_decl, stmt_expr, stmt_semi, + subtract, sty_box, sty_by_ref, sty_region, sty_static, + sty_uniq, sty_value, + token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok, + tt_nonterminal, ty, ty_, ty_bot, ty_box, ty_field, ty_fn, + ty_infer, ty_mac, ty_method, ty_nil, ty_param, ty_param_bound, + ty_path, ty_ptr, + ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq, ty_vec, + ty_fixed_length, tuple_variant_kind, + unchecked_blk, uniq, unsafe_blk, unsafe_fn, + variant, view_item, view_item_, view_item_export, + view_item_import, view_item_use, view_path, view_path_glob, + view_path_list, view_path_simple, visibility, vstore, vstore_box, + vstore_fixed, vstore_slice, vstore_uniq}; export file_type; export parser; @@ -279,6 +283,9 @@ class parser { seq_sep_none()) |p| { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; + let is_static = p.parse_staticness(); + let static_sty = spanned(lo, p.span.hi, sty_static); + let pur = p.parse_fn_purity(); // NB: at the moment, trait methods are public by default; this // could change. @@ -287,7 +294,8 @@ class parser { let tps = p.parse_ty_params(); let d = p.parse_ty_fn_decl(pur); let hi = p.last_span.hi; - let self_ty = spanned(lo, hi, sty_by_ref); // XXX: Wrong. + let self_ty = if is_static { static_sty } else + { spanned(lo, hi, sty_by_ref) }; // XXX: Wrong. debug!{"parse_trait_methods(): trait method signature ends in \ `%s`", token_to_str(p.reader, p.token)}; @@ -2379,15 +2387,24 @@ class parser { fn parse_method(pr: visibility) -> @method { let attrs = self.parse_outer_attributes(); - let lo = self.span.lo, pur = self.parse_fn_purity(); + let lo = self.span.lo; + + let is_static = self.parse_staticness(); + let static_sty = spanned(lo, self.span.hi, sty_static); + + let pur = self.parse_fn_purity(); let ident = self.parse_method_name(); let tps = self.parse_ty_params(); let (self_ty, decl, _) = do self.parse_fn_decl_with_self(pur) |p| { p.parse_arg() }; + // XXX: interaction between staticness, self_ty is broken now + let self_ty = if is_static { static_sty} else { self_ty }; + let (inner_attrs, body) = self.parse_inner_attrs_and_block(true); let attrs = vec::append(attrs, inner_attrs); - @{ident: ident, attrs: attrs, tps: tps, self_ty: self_ty, decl: decl, + @{ident: ident, attrs: attrs, + tps: tps, self_ty: self_ty, decl: decl, body: body, id: self.get_id(), span: mk_sp(lo, body.span.hi), self_id: self.get_id(), vis: pr} } @@ -2689,6 +2706,9 @@ class parser { else if self.eat_keyword(~"priv") { private } else { inherited } } + fn parse_staticness() -> bool { + self.eat_keyword(~"static") + } fn parse_mod_items(term: token::token, +first_item_attrs: ~[attribute]) -> _mod { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index db62637a673..1965ea73186 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -144,7 +144,7 @@ fn fun_to_str(decl: ast::fn_decl, name: ast::ident, params: ~[ast::ty_param]) -> ~str { let buffer = io::mem_buffer(); let s = rust_printer(io::mem_buffer_writer(buffer)); - print_fn(s, decl, name, params); + print_fn(s, decl, name, params, none); end(s); // Close the head box end(s); // Close the outer box eof(s.s); @@ -400,7 +400,7 @@ fn print_type_ex(s: ps, &&ty: @ast::ty, print_colons: bool) { pclose(s); } ast::ty_fn(proto, bounds, d) => { - print_ty_fn(s, some(proto), bounds, d, none, none); + print_ty_fn(s, some(proto), bounds, d, none, none, none); } ast::ty_path(path, _) => print_path(s, path, print_colons), ast::ty_fixed_length(t, v) => { @@ -425,7 +425,7 @@ fn print_foreign_item(s: ps, item: @ast::foreign_item) { print_outer_attributes(s, item.attrs); match item.node { ast::foreign_item_fn(decl, typarams) => { - print_fn(s, decl, item.ident, typarams); + print_fn(s, decl, item.ident, typarams, none); end(s); // end head-ibox word(s.s, ~";"); end(s); // end the outer fn box @@ -454,7 +454,7 @@ fn print_item(s: ps, &&item: @ast::item) { } ast::item_fn(decl, typarams, body) => { - print_fn(s, decl, item.ident, typarams); + print_fn(s, decl, item.ident, typarams, none); word(s.s, ~" "); print_block_with_attrs(s, body, item.attrs); } @@ -722,7 +722,8 @@ fn print_ty_method(s: ps, m: ast::ty_method) { hardbreak_if_not_bol(s); maybe_print_comment(s, m.span.lo); print_outer_attributes(s, m.attrs); - print_ty_fn(s, none, @~[], m.decl, some(m.ident), some(m.tps)); + print_ty_fn(s, none, @~[], m.decl, some(m.ident), some(m.tps), + some(m.self_ty.node)); word(s.s, ~";"); } @@ -737,7 +738,7 @@ fn print_method(s: ps, meth: @ast::method) { hardbreak_if_not_bol(s); maybe_print_comment(s, meth.span.lo); print_outer_attributes(s, meth.attrs); - print_fn(s, meth.decl, meth.ident, meth.tps); + print_fn(s, meth.decl, meth.ident, meth.tps, some(meth.self_ty.node)); word(s.s, ~" "); print_block_with_attrs(s, meth.body, meth.attrs); } @@ -1150,8 +1151,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) { cbox(s, indent_unit); // head-box, will be closed by print-block at start ibox(s, 0u); - print_purity(s, decl.purity); - word(s.s, proto_to_str(proto)); + word(s.s, fn_header_info_to_str(none, decl.purity, some(proto))); print_fn_args_and_ret(s, decl, *cap_clause); space(s.s); print_block(s, body); @@ -1455,11 +1455,9 @@ fn print_pat(s: ps, &&pat: @ast::pat) { } fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident, - typarams: ~[ast::ty_param]) { - match decl.purity { - ast::impure_fn => head(s, ~"fn"), - _ => head(s, purity_to_str(decl.purity) + ~" fn") - } + typarams: ~[ast::ty_param], + opt_self_ty: option<ast::self_ty_>) { + head(s, fn_header_info_to_str(opt_self_ty, decl.purity, none)); word(s.s, *name); print_type_params(s, typarams); print_fn_args_and_ret(s, decl, ~[]); @@ -1667,9 +1665,10 @@ fn print_arg(s: ps, input: ast::arg) { fn print_ty_fn(s: ps, opt_proto: option<ast::proto>, bounds: @~[ast::ty_param_bound], decl: ast::fn_decl, id: option<ast::ident>, - tps: option<~[ast::ty_param]>) { + tps: option<~[ast::ty_param]>, + opt_self_ty: option<ast::self_ty_>) { ibox(s, indent_unit); - word(s.s, opt_proto_to_str(opt_proto)); + word(s.s, fn_header_info_to_str(opt_self_ty, decl.purity, opt_proto)); print_bounds(s, bounds); match id { some(id) => { word(s.s, ~" "); word(s.s, *id); } _ => () } match tps { some(tps) => print_type_params(s, tps), _ => () } @@ -1869,6 +1868,27 @@ fn next_comment(s: ps) -> option<comments::cmnt> { } } +fn fn_header_info_to_str(opt_sty: option<ast::self_ty_>, + purity: ast::purity, + opt_p: option<ast::proto>) -> ~str { + let mut s = match opt_sty { + some(ast::sty_static) => ~"static ", + _ => ~ "" + }; + + match purity { + ast::impure_fn => { } + _ => { + str::push_str(s, purity_to_str(purity)); + str::push_char(s, ' '); + } + } + + str::push_str(s, opt_proto_to_str(opt_p)); + + return s; +} + fn opt_proto_to_str(opt_p: option<ast::proto>) -> ~str { match opt_p { none => ~"fn", 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); diff --git a/src/test/auxiliary/static-methods-crate.rs b/src/test/auxiliary/static-methods-crate.rs new file mode 100644 index 00000000000..56cc7f9aca3 --- /dev/null +++ b/src/test/auxiliary/static-methods-crate.rs @@ -0,0 +1,33 @@ +#[link(name = "static_methods_crate", + vers = "0.1")]; + +#[crate_type = "lib"]; + +export read, readMaybe; + +trait read { + static fn readMaybe(s: ~str) -> option<self>; +} + +impl of read for int { + static fn readMaybe(s: ~str) -> option<int> { + int::from_str(s) + } +} + +impl of read for bool { + static fn readMaybe(s: ~str) -> option<bool> { + match s { + ~"true" => some(true), + ~"false" => some(false), + _ => none + } + } +} + +fn read<T: read copy>(s: ~str) -> T { + match readMaybe(s) { + some(x) => x, + _ => fail ~"read failed!" + } +} diff --git a/src/test/compile-fail/staticness-mismatch.rs b/src/test/compile-fail/staticness-mismatch.rs new file mode 100644 index 00000000000..1e23f588843 --- /dev/null +++ b/src/test/compile-fail/staticness-mismatch.rs @@ -0,0 +1,10 @@ + +trait foo { + static fn bar(); +} + +impl of foo for int { + fn bar() {} //~ ERROR self type does not match the trait method's +} + +fn main() {} diff --git a/src/test/run-pass/static-method-test.rs b/src/test/run-pass/static-method-test.rs new file mode 100644 index 00000000000..5cfa34ed59b --- /dev/null +++ b/src/test/run-pass/static-method-test.rs @@ -0,0 +1,79 @@ + +// A trait for objects that can be used to do an if-then-else +// (No actual need for this to be static, but it is a simple test.) +trait bool_like { + static fn select<A>(b: self, +x1: A, +x2: A) -> A; +} + +fn andand<T: bool_like copy>(x1: T, x2: T) -> T { + select(x1, x2, x1) +} + +impl of bool_like for bool { + static fn select<A>(&&b: bool, +x1: A, +x2: A) -> A { + if b { x1 } else { x2 } + } +} + +impl of bool_like for int { + static fn select<A>(&&b: int, +x1: A, +x2: A) -> A { + if b != 0 { x1 } else { x2 } + } +} + +// A trait for sequences that can be constructed imperatively. +trait buildable<A> { + static pure fn build_sized(size: uint, + builder: fn(push: pure fn(+A))) -> self; +} + + +impl extensions<A> of buildable<A> for @[A] { + #[inline(always)] + static pure fn build_sized(size: uint, + builder: fn(push: pure fn(+A))) -> @[A] { + at_vec::build_sized(size, builder) + } +} +impl extensions<A> of buildable<A> for ~[A] { + #[inline(always)] + static pure fn build_sized(size: uint, + builder: fn(push: pure fn(+A))) -> ~[A] { + vec::build_sized(size, builder) + } +} + +#[inline(always)] +pure fn build<A, B: buildable<A>>(builder: fn(push: pure fn(+A))) -> B { + build_sized(4, builder) +} + +/// Apply a function to each element of an iterable and return the results +fn map<T, IT: base_iter<T>, U, BU: buildable<U>> + (v: IT, f: fn(T) -> U) -> BU { + do build |push| { + for v.each() |elem| { + push(f(elem)); + } + } +} + +fn seq_range<BT: buildable<int>>(lo: uint, hi: uint) -> BT { + do build_sized(hi-lo) |push| { + for uint::range(lo, hi) |i| { + push(i as int); + } + } +} + +fn main() { + assert seq_range(0, 10) == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + assert map(&[1,2,3], |x| 1+x) == @[2, 3, 4]; + assert map(&[1,2,3], |x| 1+x) == ~[2, 3, 4]; + + assert select(true, 9, 14) == 9; + assert !andand(true, false); + assert andand(7, 12) == 12; + assert andand(0, 12) == 0; +} diff --git a/src/test/run-pass/static-method-xcrate.rs b/src/test/run-pass/static-method-xcrate.rs new file mode 100644 index 00000000000..a502e4ac2d5 --- /dev/null +++ b/src/test/run-pass/static-method-xcrate.rs @@ -0,0 +1,12 @@ +// xfail-fast +// aux-build:static-methods-crate.rs + +use static_methods_crate; +import static_methods_crate::read; +import readMaybeRenamed = static_methods_crate::readMaybe; + +fn main() { + assert read(~"5") == 5; + assert readMaybeRenamed(~"false") == some(false); + assert readMaybeRenamed(~"foo") == none::<bool>; +} |
