Implement static typeclass methods. Closes #3132.

This commit is contained in:
Michael Sullivan 2012-08-02 16:01:38 -07:00
parent a695e074f2
commit 7f7f47620e
20 changed files with 605 additions and 246 deletions

View file

@ -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`

View file

@ -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, _) => {

View file

@ -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 {

View file

@ -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",

View file

@ -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);

View file

@ -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",

View file

@ -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"
}

View file

@ -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))
}

View file

@ -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(_) |

View file

@ -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.

View file

@ -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.

View file

@ -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;

View file

@ -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;}
}

View file

@ -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, _) => {

View file

@ -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
}

View file

@ -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);

View 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!"
}
}

View 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() {}

View 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;
}

View 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>;
}