Parse and resolve implementations.

Issue #1227
This commit is contained in:
Marijn Haverbeke 2011-12-13 13:19:56 +01:00
parent d5af61d679
commit 888bc80025
14 changed files with 261 additions and 81 deletions

View File

@ -162,7 +162,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
bind middle::ast_map::map_crate(*crate));
time(time_passes, "external crate/lib resolution",
bind creader::read_crates(sess, *crate));
let {def_map: def_map, ext_map: ext_map, exp_map: exp_map} =
let {def_map, ext_map, exp_map, impl_map} =
time(time_passes, "resolution",
bind resolve::resolve_crate(sess, ast_map, crate));
let freevars =
@ -171,7 +171,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
time(time_passes, "const checking",
bind middle::check_const::check_crate(sess, crate));
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate));
time(time_passes, "typechecking",
bind typeck::check_crate(ty_cx, impl_map, crate));
time(time_passes, "block-use checking",
bind middle::block_use::check_crate(ty_cx, crate));
time(time_passes, "function usage",
@ -267,11 +268,11 @@ fn pretty_print_input(sess: session::session, cfg: ast::crate_cfg, input: str,
ppm_typed. {
crate = syntax::ext::expand::expand_crate(sess, crate);
let amap = middle::ast_map::map_crate(*crate);
let {def_map: def_map, ext_map: ext_map, exp_map: _exp_map} =
let {def_map, ext_map, impl_map, _} =
resolve::resolve_crate(sess, amap, crate);
let freevars = freevars::annotate_freevars(def_map, crate);
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, amap, freevars);
typeck::check_crate(ty_cx, crate);
typeck::check_crate(ty_cx, impl_map, crate);
ann = {pre: ann_paren_for_expr, post: bind ann_typed_post(ty_cx, _)};
}
ppm_identified. {

View File

@ -532,7 +532,7 @@ fn ty_can_unsafely_include(cx: ctx, needle: unsafe_ty, haystack: ty::t,
fn def_is_local(d: ast::def, objfields_count: bool) -> bool {
ret alt d {
ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) |
ast::def_upvar(_, _, _) {
ast::def_upvar(_, _, _) | ast::def_self(_) {
true
}
ast::def_obj_field(_, _) { objfields_count }

View File

@ -264,6 +264,7 @@ fn is_immutable_def(def: def) -> option::t<str> {
def_arg(_, by_ref.) | def_arg(_, by_val.) |
def_arg(_, mode_infer.) { some("argument") }
def_obj_field(_, imm.) { some("immutable object field") }
def_self(_) { some("self argument") }
def_upvar(_, inner, mut) {
if !mut { some("upvar") } else { is_immutable_def(*inner) }
}

View File

@ -19,9 +19,7 @@ import option::{some, none, is_none, is_some};
import syntax::print::pprust::*;
export resolve_crate;
export def_map;
export ext_map;
export exp_map;
export def_map, ext_map, exp_map, impl_map;
// Resolving happens in two passes. The first pass collects defids of all
// (internal) imports and modules, so that they can be looked up when needed,
@ -45,14 +43,23 @@ type scopes = list<scope>;
tag import_state {
todo(ast::node_id, ast::ident, @[ast::ident], codemap::span, scopes);
is_glob(@[ast::ident], scopes, codemap::span);
resolving(span);
resolved(option::t<def>, /* value */
option::t<def>, /* type */
option::t<def>, /* module */
@[def_id],
/* used for reporting unused import warning */
ast::ident, codemap::span);
}
tag glob_import_state {
glob_resolving(span);
glob_resolved(option::t<def>, /* value */
option::t<def>, /* type */
option::t<def>); /* module */
}
type ext_hash = hashmap<{did: def_id, ident: str, ns: namespace}, def>;
fn new_ext_hash() -> ext_hash {
@ -89,7 +96,7 @@ type indexed_mod = {
m: option::t<ast::_mod>,
index: mod_index,
mutable glob_imports: [glob_imp_def],
glob_imported_names: hashmap<str, import_state>,
glob_imported_names: hashmap<str, glob_import_state>,
path: str
};
@ -99,6 +106,7 @@ type indexed_mod = {
type def_map = hashmap<node_id, def>;
type ext_map = hashmap<def_id, [ident]>;
type exp_map = hashmap<str, def>;
type impl_map = hashmap<node_id, iscopes>;
type env =
{cstore: cstore::cstore,
@ -109,6 +117,7 @@ type env =
mod_map: hashmap<ast::node_id, @indexed_mod>,
block_map: hashmap<ast::node_id, [glob_imp_def]>,
ext_map: ext_map,
impl_map: impl_map,
ext_cache: ext_hash,
used_imports: {mutable track: bool,
mutable data: [ast::node_id]},
@ -124,7 +133,8 @@ tag dir { inside; outside; }
tag namespace { ns_value; ns_type; ns_module; }
fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
{def_map: def_map, ext_map: ext_map, exp_map: exp_map} {
{def_map: def_map, ext_map: ext_map,
exp_map: exp_map, impl_map: impl_map} {
let e =
@{cstore: sess.get_cstore(),
def_map: new_int_hash(),
@ -134,6 +144,7 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
mod_map: new_int_hash(),
block_map: new_int_hash(),
ext_map: new_def_hash(),
impl_map: new_int_hash(),
ext_cache: new_ext_hash(),
used_imports: {mutable track: false, mutable data: []},
mutable reported: [],
@ -144,10 +155,12 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
check_for_collisions(e, *crate);
check_exports(e);
resolve_names(e, crate);
resolve_impls(e, crate);
if sess.get_opts().warn_unused_imports {
check_unused_imports(e);
}
ret {def_map: e.def_map, ext_map: e.ext_map, exp_map: e.exp_map};
ret {def_map: e.def_map, ext_map: e.ext_map,
exp_map: e.exp_map, impl_map: e.impl_map};
}
// Locate all modules and imports and index them, so that the next passes can
@ -166,7 +179,7 @@ fn map_crate(e: @env, c: @ast::crate) {
@{m: some(c.node.module),
index: index_mod(c.node.module),
mutable glob_imports: [],
glob_imported_names: new_str_hash::<import_state>(),
glob_imported_names: new_str_hash(),
path: ""});
fn index_vi(e: @env, i: @ast::view_item, sc: scopes, _v: vt<scopes>) {
alt i.node {
@ -181,6 +194,9 @@ fn map_crate(e: @env, c: @ast::crate) {
ident.span, sc));
}
}
ast::view_item_import_glob(pth, id) {
e.imports.insert(id, is_glob(pth, sc, i.span));
}
_ { }
}
}
@ -198,21 +214,19 @@ fn map_crate(e: @env, c: @ast::crate) {
visit_item_with_scope(i, sc, v);
alt i.node {
ast::item_mod(md) {
let s = new_str_hash::<import_state>();
e.mod_map.insert(i.id,
@{m: some(md),
index: index_mod(md),
mutable glob_imports: [],
glob_imported_names: s,
glob_imported_names: new_str_hash(),
path: path_from_scope(sc, i.ident)});
}
ast::item_native_mod(nmd) {
let s = new_str_hash::<import_state>();
e.mod_map.insert(i.id,
@{m: none::<ast::_mod>,
index: index_nmod(nmd),
mutable glob_imports: [],
glob_imported_names: s,
glob_imported_names: new_str_hash(),
path: path_from_scope(sc, i.ident)});
}
_ { }
@ -233,7 +247,7 @@ fn map_crate(e: @env, c: @ast::crate) {
ast::view_item_import_glob(path, _) {
let imp = follow_import(*e, sc, *path, vi.span);
if option::is_some(imp) {
let glob = {def: option::get(imp), item: vi};;
let glob = {def: option::get(imp), item: vi};
alt list::head(sc) {
scope_item(i) {
e.mod_map.get(i.id).glob_imports += [glob];
@ -262,7 +276,7 @@ fn resolve_imports(e: env) {
todo(node_id, name, path, span, scopes) {
resolve_import(e, local_def(node_id), name, *path, span, scopes);
}
resolved(_, _, _, _, _) { }
resolved(_, _, _, _, _, _) | is_glob(_, _, _) { }
}
};
e.used_imports.track = false;
@ -272,7 +286,7 @@ fn resolve_imports(e: env) {
fn check_unused_imports(e: @env) {
e.imports.items {|k, v|
alt v {
resolved(val, ty, md, name, sp) {
resolved(_, _, _, _, name, sp) {
if !vec::member(k, e.used_imports.data) {
e.sess.span_warn(sp, "unused import " + name);
}
@ -472,13 +486,14 @@ fn resolve_constr(e: @env, c: @ast::constr, sc: scopes, _v: vt<scopes>) {
fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
ids: [ast::ident], sp: codemap::span, sc: scopes) {
fn register(e: env, id: node_id, cx: ctxt, sp: codemap::span,
name: ast::ident, lookup: block(namespace) -> option::t<def>){
name: ast::ident, lookup: block(namespace) -> option::t<def>,
impls: [def_id]) {
let val = lookup(ns_value), typ = lookup(ns_type),
md = lookup(ns_module);
if is_none(val) && is_none(typ) && is_none(md) {
unresolved_err(e, cx, sp, name, "import");
} else {
e.imports.insert(id, resolved(val, typ, md, name, sp));
e.imports.insert(id, resolved(val, typ, md, @impls, name, sp));
}
}
// Temporarily disable this import and the imports coming after during
@ -527,7 +542,7 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
let end_id = ids[n_idents - 1u];
if n_idents == 1u {
register(e, defid.node, in_scope(sc), sp, name,
{|ns| lookup_in_scope(e, sc, sp, end_id, ns) });
{|ns| lookup_in_scope(e, sc, sp, end_id, ns) }, []);
} else {
alt lookup_in_scope(e, sc, sp, ids[0], ns_module) {
none. {
@ -537,9 +552,11 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
let dcur = dcur_, i = 1u;
while true {
if i == n_idents - 1u {
let impls = [];
find_impls_in_mod(e, dcur, impls, some(end_id));
register(e, defid.node, in_mod(dcur), sp, name, {|ns|
lookup_in_mod(e, dcur, sp, end_id, ns, outside)
});
}, impls);
break;
} else {
dcur = alt lookup_in_mod(e, dcur, sp, ids[i], ns_module,
@ -563,7 +580,7 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
// import
alt e.imports.find(defid.node) {
some(resolving(sp)) {
e.imports.insert(defid.node, resolved(none, none, none, "", sp));
e.imports.insert(defid.node, resolved(none, none, none, @[], "", sp));
}
_ { }
}
@ -726,6 +743,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
ast::item_obj(ob, ty_params, _) {
ret lookup_in_obj(name, ob, ty_params, ns);
}
ast::item_impl(_, _, _) {
if (name == "self" && ns == ns_value) {
ret some(ast::def_self(local_def(it.id)));
}
}
ast::item_tag(_, ty_params) {
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
}
@ -819,7 +841,6 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
}
}
e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh
}
fn lookup_in_ty_params(name: ident, ty_params: [ast::ty_param]) ->
@ -999,7 +1020,7 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option::t<def> {
}
_ { }
}
ret none::<def>;
ret none;
}
fn lookup_in_mod_strict(e: env, m: def, sp: span, name: ident,
@ -1060,11 +1081,12 @@ fn lookup_import(e: env, defid: def_id, ns: namespace) -> option::t<def> {
e.sess.span_err(sp, "cyclic import");
ret none;
}
resolved(val, typ, md, _, _) {
resolved(val, typ, md, _, _, _) {
if e.used_imports.track {
e.used_imports.data += [defid.node];
}
ret alt ns { ns_value. { val } ns_type. { typ } ns_module. { md } };
ret alt ns { ns_value. { val } ns_type. { typ }
ns_module. { md } };
}
}
}
@ -1136,22 +1158,20 @@ fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
// since we don't know what names we have in advance,
// absence takes the place of todo()
if !info.glob_imported_names.contains_key(id) {
info.glob_imported_names.insert(id, resolving(sp));
info.glob_imported_names.insert(id, glob_resolving(sp));
let val = lookup_in_globs(e, info.glob_imports, sp, id, ns_value, dr);
let typ = lookup_in_globs(e, info.glob_imports, sp, id, ns_type, dr);
let md = lookup_in_globs(e, info.glob_imports, sp, id, ns_module, dr);
info.glob_imported_names.insert(id, resolved(val, typ, md, id, sp));
info.glob_imported_names.insert(id, glob_resolved(val, typ, md));
}
alt info.glob_imported_names.get(id) {
todo(_, _, _, _, _) { e.sess.bug("Shouldn't've put a todo in."); }
//circularity is okay in import globs
resolving(sp) { ret none::<def>; }
resolved(val, typ, md, _, _) {
glob_resolving(sp) { ret none::<def>; }
glob_resolved(val, typ, md) {
ret alt wanted_ns {
ns_value. { val }
ns_type. { typ }
ns_module. { md }
};
ns_value. { val }
ns_type. { typ }
ns_module. { md }
};
}
}
}
@ -1229,7 +1249,8 @@ fn index_mod(md: ast::_mod) -> mod_index {
alt it.node {
ast::item_const(_, _) | ast::item_fn(_, _) | ast::item_mod(_) |
ast::item_native_mod(_) | ast::item_ty(_, _) |
ast::item_res(_, _, _, _) | ast::item_obj(_, _, _) {
ast::item_res(_, _, _, _) | ast::item_obj(_, _, _) |
ast::item_impl(_, _, _) {
add_to_index(index, it.ident, mie_item(it));
}
ast::item_tag(variants, _) {
@ -1289,6 +1310,7 @@ fn ns_for_def(d: def) -> namespace {
ast::def_use(_) { ns_module }
ast::def_native_ty(_) { ns_type }
ast::def_native_fn(_, _) { ns_value }
ast::def_self(_) { ns_value }
};
}
@ -1558,7 +1580,7 @@ fn check_exports(e: @env) {
alt x {
mie_import_ident(id, _) {
alt e.imports.get(id) {
resolved(v, t, m, rid, _) {
resolved(v, t, m, _, rid, _) {
maybe_add_reexport(e, val.path + rid, v);
maybe_add_reexport(e, val.path + rid, t);
maybe_add_reexport(e, val.path + rid, m);
@ -1596,6 +1618,115 @@ fn check_exports(e: @env) {
};
}
// Impl resolution
fn resolve_impls(e: @env, c: @ast::crate) {
visit::visit_crate(*c, nil, visit::mk_vt(@{
visit_block: bind visit_block_with_impl_scope(e, _, _, _),
visit_item: bind visit_item_with_impl_scope(e, _, _, _),
visit_expr: bind resolve_impl_in_expr(e, _, _, _)
with *visit::default_visitor()
}));
}
fn find_impls_in_view_item(e: env, vi: @ast::view_item, &impls: [def_id]) {
alt vi.node {
ast::view_item_import(ident, _, id) {
// FIXME if single name, simply look in our own iscope
alt e.imports.get(id) {
resolved(_, _, _, is, _, _) { impls += *is; }
}
}
ast::view_item_import_from(base, names, _) {
for nm in names {
alt e.imports.get(nm.node.id) {
resolved(_, _, _, is, _, _) { impls += *is; }
}
}
}
ast::view_item_import_glob(ids, id) {
alt e.imports.get(id) {
is_glob(path, sc, sp) {
alt follow_import(e, sc, *path, sp) {
some(def) { find_impls_in_mod(e, def, impls, none); }
_ {}
}
}
}
}
_ {}
}
}
fn find_impls_in_item(i: @ast::item, &impls: [def_id],
name: option::t<ident>, _dir: dir) {
// FIXME check exports
alt i.node {
ast::item_impl(_, _, _) {
if alt name { some(n) { n == i.ident } _ { true } } {
impls += [local_def(i.id)];
}
}
_ {}
}
}
fn find_impls_in_mod(e: env, m: def, &impls: [def_id],
name: option::t<ident>) {
alt m {
ast::def_mod(defid) {
// FIXME external importing of impls
if defid.crate == ast::local_crate {
for i in option::get(e.mod_map.get(defid.node).m).items {
find_impls_in_item(i, impls, name, outside);
}
}
}
_ {}
}
}
type iscopes = list<@[def_id]>;
fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes,
v: vt<iscopes>) {
let impls = [];
for vi in b.node.view_items { find_impls_in_view_item(*e, vi, impls); }
for st in b.node.stmts {
alt st.node {
ast::stmt_decl(@{node: ast::decl_item(i), _}, _) {
find_impls_in_item(i, impls, none, inside);
}
_ {}
}
}
let sc = vec::len(impls) > 0u ? cons(@impls, @sc) : sc;
visit::visit_block(b, sc, v);
}
fn visit_item_with_impl_scope(e: @env, i: @ast::item, sc: iscopes,
v: vt<iscopes>) {
let sc = sc;
alt i.node {
ast::item_mod(m) {
let impls = [];
for vi in m.view_items { find_impls_in_view_item(*e, vi, impls); }
for i in m.items { find_impls_in_item(i, impls, none, inside); }
if vec::len(impls) > 0u { sc = cons(@impls, @sc); }
}
_ {}
}
visit::visit_item(i, sc, v);
}
fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt<iscopes>) {
alt x.node {
ast::expr_field(_, _) { e.impl_map.insert(x.id, sc); }
_ {}
}
visit::visit_expr(x, sc, v);
}
// Local Variables:
// mode: rust
// fill-column: 78;

View File

@ -2678,6 +2678,9 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result {
assert (cx.fcx.llobjfields.contains_key(did.node));
ret { val: cx.fcx.llobjfields.get(did.node), kind: owned };
}
ast::def_self(did) {
ret lval_owned(cx, cx.fcx.llenv);
}
_ {
bcx_ccx(cx).sess.span_unimpl
(cx.sp, "unsupported def type in trans_local_def");
@ -4946,6 +4949,7 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
with *extend_path(cx, item.ident)};
trans_obj(sub_cx, item.span, ob, ctor_id, tps);
}
ast::item_impl(_, _, _) { fail "FIXME[impl]"; }
ast::item_res(dtor, dtor_id, tps, ctor_id) {
trans_res_ctor(cx, item.span, dtor, ctor_id, tps);

View File

@ -26,17 +26,14 @@ fn find_pre_post_native_mod(_m: native_mod) -> native_mod {
fail;
}
fn find_pre_post_obj(ccx: crate_ctxt, o: _obj) {
fn do_a_method(ccx: crate_ctxt, m: @method) {
assert (ccx.fm.contains_key(m.node.id));
let fcx: fn_ctxt =
{enclosing: ccx.fm.get(m.node.id),
id: m.node.id,
name: m.node.ident,
ccx: ccx};
find_pre_post_fn(fcx, m.node.meth);
}
for m: @method in o.methods { do_a_method(ccx, m); }
fn find_pre_post_method(ccx: crate_ctxt, m: @method) {
assert (ccx.fm.contains_key(m.node.id));
let fcx: fn_ctxt =
{enclosing: ccx.fm.get(m.node.id),
id: m.node.id,
name: m.node.ident,
ccx: ccx};
find_pre_post_fn(fcx, m.node.meth);
}
fn find_pre_post_item(ccx: crate_ctxt, i: item) {
@ -77,7 +74,8 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
ccx: ccx};
find_pre_post_fn(fcx, dtor);
}
item_obj(o, _, _) { find_pre_post_obj(ccx, o); }
item_obj(o, _, _) {for m in o.methods { find_pre_post_method(ccx, m); }}
item_impl(_, _, ms) { for m in ms { find_pre_post_method(ccx, m); } }
}
}

View File

@ -2702,20 +2702,12 @@ fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
fn def_has_ty_params(def: ast::def) -> bool {
alt def {
ast::def_fn(_, _) { ret true; }
ast::def_obj_field(_, _) { ret false; }
ast::def_mod(_) { ret false; }
ast::def_const(_) { ret false; }
ast::def_arg(_, _) { ret false; }
ast::def_local(_, _) { ret false; }
ast::def_upvar(_, _, _) { ret false; }
ast::def_variant(_, _) { ret true; }
ast::def_ty(_) { ret false; }
ast::def_ty_param(_, _) { ret false; }
ast::def_binding(_) { ret false; }
ast::def_use(_) { ret false; }
ast::def_native_ty(_) { ret false; }
ast::def_native_fn(_, _) { ret true; }
ast::def_obj_field(_, _) | ast::def_mod(_) | ast::def_const(_) |
ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_upvar(_, _, _) |
ast::def_ty_param(_, _) | ast::def_binding(_) | ast::def_use(_) |
ast::def_native_ty(_) | ast::def_self(_) | ast::def_ty(_) { false }
ast::def_fn(_, _) | ast::def_variant(_, _) |
ast::def_native_fn(_, _) { true }
}
}

View File

@ -33,7 +33,9 @@ tag obj_info {
anon_obj([ast::obj_field], option::t<ty::sty>);
}
type crate_ctxt = {mutable obj_infos: [obj_info], tcx: ty::ctxt};
type crate_ctxt = {mutable obj_infos: [obj_info],
impl_map: resolve::impl_map,
tcx: ty::ctxt};
type fn_ctxt =
// var_bindings, locals and next_var_id are shared
@ -89,6 +91,7 @@ fn ty_param_kinds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
ret {kinds: no_kinds, ty: typ};
}
ast::def_self(id) { fail "FIXME[impl]"; }
ast::def_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_native_fn(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
ast::def_const(id) { ret ty::lookup_item_type(fcx.ccx.tcx, id); }
@ -686,7 +689,7 @@ mod collect {
}
fn convert(cx: @ctxt, it: @ast::item) {
alt it.node {
ast::item_mod(_) {
ast::item_mod(_) | ast::item_impl(_, _, _) {
// ignore item_mod, it has no type.
}
ast::item_native_mod(native_mod) {
@ -2657,12 +2660,15 @@ fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) {
}
}
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
crate: @ast::crate) {
collect::collect_item_types(tcx, crate);
let obj_infos: [obj_info] = [];
let ccx = @{mutable obj_infos: obj_infos, tcx: tcx};
let ccx = @{mutable obj_infos: obj_infos,
impl_map: impl_map,
tcx: tcx};
let visit =
visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _)
with *visit::default_simple_visitor()});

View File

@ -33,9 +33,8 @@ tag def {
def_const(def_id);
def_arg(def_id, mode);
def_local(def_id, let_style);
def_variant(def_id, /* tag */def_id);
/* variant */
def_variant(def_id /* tag */, def_id /* variant */);
def_self(def_id);
def_ty(def_id);
def_ty_param(uint, kind);
def_binding(def_id);
@ -507,6 +506,7 @@ tag item_ {
node_id /* dtor id */,
[ty_param],
node_id /* ctor id */);
item_impl(@path /* iface */, @ty /* self */, [@method]);
}
type native_item =

View File

@ -36,6 +36,7 @@ fn def_id_of_def(d: def) -> def_id {
alt d {
def_fn(id, _) { ret id; }
def_obj_field(id, _) { ret id; }
def_self(id) { ret id; }
def_mod(id) { ret id; }
def_native_mod(id) { ret id; }
def_const(id) { ret id; }

View File

@ -235,6 +235,10 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
methods: vec::map(fld.fold_method, o.methods)},
typms, d)
}
item_impl(iface, ty, methods) {
item_impl(fld.fold_path(iface), fld.fold_ty(ty),
vec::map(fld.fold_method, methods))
}
item_res(dtor, did, typms, cid) {
item_res(fld.fold_fn(dtor), did, typms, cid)
}

View File

@ -155,7 +155,8 @@ fn bad_expr_word_table() -> hashmap<str, ()> {
"cont", "ret", "be", "fail", "type", "resource", "check",
"assert", "claim", "native", "fn", "lambda", "pure",
"unsafe", "block", "import", "export", "let", "const",
"log", "log_err", "tag", "obj", "self", "copy", "sendfn"] {
"log", "log_err", "tag", "obj", "self", "copy", "sendfn",
"impl"] {
words.insert(word, ());
}
words
@ -941,8 +942,8 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
let e = parse_expr(p);
ex = ast::expr_copy(e);
hi = e.span.hi;
} else if eat_word(p, "self") {
expect(p, token::DOT);
} else if is_word(p, "self") && p.look_ahead(1u) == token::DOT {
p.bump(); p.bump();
// The rest is a call expression.
let f: @ast::expr = parse_self_method(p);
let es =
@ -1873,6 +1874,17 @@ fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
attrs);
}
fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.get_last_lo_pos(), ty = parse_ty(p, false);
expect(p, token::COLON);
let path = parse_path(p), meths = [];
expect(p, token::LBRACE);
while !eat(p, token::RBRACE) { meths += [parse_method(p)]; }
ret mk_item(p, lo, p.get_last_hi_pos(),
path.node.idents[vec::len(path.node.idents) - 1u],
ast::item_impl(path, ty, meths), attrs);
}
fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.get_last_lo_pos();
let ident = parse_value_ident(p);
@ -2139,14 +2151,15 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
ret some(parse_item_mod(p, attrs));
} else if eat_word(p, "native") {
ret some(parse_item_native_mod(p, attrs));
}
if eat_word(p, "type") {
} if eat_word(p, "type") {
ret some(parse_item_type(p, attrs));
} else if eat_word(p, "tag") {
ret some(parse_item_tag(p, attrs));
} else if is_word(p, "obj") && p.look_ahead(1u) != token::LPAREN {
p.bump();
ret some(parse_item_obj(p, attrs));
} else if eat_word(p, "impl") {
ret some(parse_item_impl(p, attrs));
} else if eat_word(p, "resource") {
ret some(parse_item_res(p, attrs));
} else { ret none; }

View File

@ -483,6 +483,22 @@ fn print_item(s: ps, &&item: @ast::item) {
}
bclose(s, item.span);
}
ast::item_impl(path, ty, methods) {
head(s, "impl");
print_type(s, ty);
word_space(s, ":");
print_path(s, path, false);
bopen(s);
for meth in methods {
hardbreak_if_not_bol(s);
maybe_print_comment(s, meth.span.lo);
print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
meth.node.ident, [], []);
word(s.s, " ");
print_block(s, meth.node.meth.body);
}
bclose(s, item.span);
}
ast::item_res(dt, dt_id, tps, ct_id) {
head(s, "resource");
word(s.s, item.ident);

View File

@ -105,6 +105,14 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
e, v);
}
}
item_impl(path, ty, methods) {
visit_path(path, e, v);
visit_ty(ty, e, v);
for m in methods {
v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
e, v);
}
}
}
}
@ -133,7 +141,8 @@ fn visit_ty<E>(t: @ty, e: E, v: vt<E>) {
v.visit_ty(m.node.output, e, v);
}
}
ty_path(p, _) { for tp: @ty in p.node.types { v.visit_ty(tp, e, v); } }
ty_path(p, _) { visit_path(p, e, v); }
ty_type. {/* no-op */ }
ty_constr(t, cs) {
v.visit_ty(t, e, v);
for tc: @spanned<constr_general_<@path, node_id>> in cs {
@ -149,10 +158,14 @@ fn visit_constr<E>(_operator: @path, _sp: span, _id: node_id, _e: E,
// default
}
fn visit_path<E>(p: @path, e: E, v: vt<E>) {
for tp: @ty in p.node.types { v.visit_ty(tp, e, v); }
}
fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
alt p.node {
pat_tag(path, children) {
for tp: @ty in path.node.types { v.visit_ty(tp, e, v); }
visit_path(path, e, v);
for child: @pat in children { v.visit_pat(child, e, v); }
}
pat_rec(fields, _) {
@ -286,7 +299,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
}
expr_field(x, _) { v.visit_expr(x, e, v); }
expr_index(a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
expr_path(p) { for tp: @ty in p.node.types { v.visit_ty(tp, e, v); } }
expr_path(p) { visit_path(p, e, v); }
expr_fail(eo) { visit_expr_opt(eo, e, v); }
expr_break. { }
expr_cont. { }