Implement static typeclass methods. Closes #3132.
This commit is contained in:
parent
a695e074f2
commit
7f7f47620e
20 changed files with 605 additions and 246 deletions
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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, _) => {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_) |
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, _) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
33
src/test/auxiliary/static-methods-crate.rs
Normal file
33
src/test/auxiliary/static-methods-crate.rs
Normal file
|
|
@ -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!"
|
||||
}
|
||||
}
|
||||
10
src/test/compile-fail/staticness-mismatch.rs
Normal file
10
src/test/compile-fail/staticness-mismatch.rs
Normal file
|
|
@ -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() {}
|
||||
79
src/test/run-pass/static-method-test.rs
Normal file
79
src/test/run-pass/static-method-test.rs
Normal file
|
|
@ -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;
|
||||
}
|
||||
12
src/test/run-pass/static-method-xcrate.rs
Normal file
12
src/test/run-pass/static-method-xcrate.rs
Normal file
|
|
@ -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>;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue