rust/src/libsyntax/ast_map.rs
Niko Matsakis ea549e7a71 make borrowck more conservative around rvalues.
this will require more temporaries, but is probably less magical.
also, it means that borrowck matches trans better, so fewer crashes.
bonus.

Finally, stop warning about implicit copies when we are actually borrowing.

Also, one test (vec-res-add) stopped failing due to #2587, and hence I
added an xfail-test.

Fixes #3217, #2977, #3067
2012-08-17 15:14:13 -07:00

355 lines
12 KiB
Rust

import std::map;
import std::map::hashmap;
import ast::*;
import print::pprust;
import ast_util::{path_to_ident, stmt_id};
import diagnostic::span_handler;
enum path_elt { path_mod(ident), path_name(ident) }
type path = ~[path_elt];
/* FIXMEs that say "bad" are as per #2543 */
fn path_to_str_with_sep(p: path, sep: ~str) -> ~str {
let strs = do vec::map(p) |e| {
match e {
path_mod(s) => /* FIXME (#2543) */ copy *s,
path_name(s) => /* FIXME (#2543) */ copy *s
}
};
str::connect(strs, sep)
}
fn path_ident_to_str(p: path, i: ident) -> ~str {
if vec::is_empty(p) {
/* FIXME (#2543) */ copy *i
} else {
fmt!{"%s::%s", path_to_str(p), *i}
}
}
fn path_to_str(p: path) -> ~str {
path_to_str_with_sep(p, ~"::")
}
enum ast_node {
node_item(@item, @path),
node_foreign_item(@foreign_item, foreign_abi, @path),
node_trait_method(@trait_method, def_id /* trait did */,
@path /* path to the trait */),
node_method(@method, def_id /* impl did */, @path /* path to the impl */),
node_variant(variant, @item, @path),
node_expr(@expr),
node_stmt(@stmt),
node_export(@view_path, @path),
// Locals are numbered, because the alias analysis needs to know in which
// order they are introduced.
node_arg(arg, uint),
node_local(uint),
// Constructor for a class
// def_id is parent id
node_ctor(ident, ~[ty_param], @class_ctor, def_id, @path),
// Destructor for a class
node_dtor(~[ty_param], @class_dtor, def_id, @path),
node_block(blk),
}
type map = std::map::hashmap<node_id, ast_node>;
type ctx = {map: map, mut path: path,
mut local_id: uint, diag: span_handler};
type vt = visit::vt<ctx>;
fn extend(cx: ctx, +elt: ident) -> @path {
@(vec::append(cx.path, ~[path_name(elt)]))
}
fn mk_ast_map_visitor() -> vt {
return visit::mk_vt(@{
visit_item: map_item,
visit_expr: map_expr,
visit_stmt: map_stmt,
visit_fn: map_fn,
visit_local: map_local,
visit_arm: map_arm,
visit_view_item: map_view_item,
visit_block: map_block
with *visit::default_visitor()
});
}
fn map_crate(diag: span_handler, c: crate) -> map {
let cx = {map: std::map::int_hash(),
mut path: ~[],
mut local_id: 0u,
diag: diag};
visit::visit_crate(c, cx, mk_ast_map_visitor());
return cx.map;
}
// Used for items loaded from external crate that are being inlined into this
// crate. The `path` should be the path to the item but should not include
// the item itself.
fn map_decoded_item(diag: span_handler,
map: map, +path: path, ii: inlined_item) {
// I believe it is ok for the local IDs of inlined items from other crates
// to overlap with the local ids from this crate, so just generate the ids
// starting from 0. (In particular, I think these ids are only used in
// alias analysis, which we will not be running on the inlined items, and
// even if we did I think it only needs an ordering between local
// variables that are simultaneously in scope).
let cx = {map: map,
mut path: /* FIXME (#2543) */ copy path,
mut local_id: 0u,
diag: diag};
let v = mk_ast_map_visitor();
// methods get added to the AST map when their impl is visited. Since we
// don't decode and instantiate the impl, but just the method, we have to
// add it to the table now:
match ii {
ii_item(*) | ii_ctor(*) | ii_dtor(*) => { /* fallthrough */ }
ii_foreign(i) => {
cx.map.insert(i.id, node_foreign_item(i, foreign_abi_rust_intrinsic,
@path));
}
ii_method(impl_did, m) => {
map_method(impl_did, @path, m, cx);
}
}
// visit the item / method contents and add those to the map:
ii.accept(cx, v);
}
fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
sp: codemap::span, id: node_id, cx: ctx, v: vt) {
for decl.inputs.each |a| {
cx.map.insert(a.id,
node_arg(/* FIXME (#2543) */
copy a, cx.local_id));
cx.local_id += 1u;
}
match fk {
visit::fk_ctor(nm, attrs, tps, self_id, parent_id) => {
let ct = @{node: {id: id,
attrs: attrs,
self_id: self_id,
dec: /* FIXME (#2543) */ copy decl,
body: /* FIXME (#2543) */ copy body},
span: sp};
cx.map.insert(id, node_ctor(/* FIXME (#2543) */ copy nm,
/* FIXME (#2543) */ copy tps,
ct, parent_id,
@/* FIXME (#2543) */ copy cx.path));
}
visit::fk_dtor(tps, attrs, self_id, parent_id) => {
let dt = @{node: {id: id, attrs: attrs, self_id: self_id,
body: /* FIXME (#2543) */ copy body}, span: sp};
cx.map.insert(id, node_dtor(/* FIXME (#2543) */ copy tps, dt,
parent_id,
@/* FIXME (#2543) */ copy cx.path));
}
_ => ()
}
visit::visit_fn(fk, decl, body, sp, id, cx, v);
}
fn map_block(b: blk, cx: ctx, v: vt) {
cx.map.insert(b.node.id, node_block(/* FIXME (#2543) */ copy b));
visit::visit_block(b, cx, v);
}
fn number_pat(cx: ctx, pat: @pat) {
do ast_util::walk_pat(pat) |p| {
match p.node {
pat_ident(*) => {
cx.map.insert(p.id, node_local(cx.local_id));
cx.local_id += 1u;
}
_ => ()
}
};
}
fn map_local(loc: @local, cx: ctx, v: vt) {
number_pat(cx, loc.node.pat);
visit::visit_local(loc, cx, v);
}
fn map_arm(arm: arm, cx: ctx, v: vt) {
number_pat(cx, arm.pats[0]);
visit::visit_arm(arm, cx, v);
}
fn map_method(impl_did: def_id, impl_path: @path,
m: @method, cx: ctx) {
cx.map.insert(m.id, node_method(m, impl_did, impl_path));
cx.map.insert(m.self_id, node_local(cx.local_id));
cx.local_id += 1u;
}
fn map_item(i: @item, cx: ctx, v: vt) {
let item_path = @/* FIXME (#2543) */ copy cx.path;
cx.map.insert(i.id, node_item(i, item_path));
match i.node {
item_impl(_, opt_ir, _, ms) => {
let impl_did = ast_util::local_def(i.id);
for ms.each |m| {
map_method(impl_did, extend(cx, i.ident), m,
cx);
}
}
item_enum(enum_definition, _) => {
for enum_definition.variants.each |v| {
cx.map.insert(v.node.id, node_variant(
/* FIXME (#2543) */ copy v, i,
extend(cx, i.ident)));
}
}
item_foreign_mod(nm) => {
let abi = match attr::foreign_abi(i.attrs) {
either::Left(msg) => cx.diag.span_fatal(i.span, msg),
either::Right(abi) => abi
};
for nm.items.each |nitem| {
cx.map.insert(nitem.id,
node_foreign_item(nitem, abi,
/* FIXME (#2543) */
extend(cx, i.ident)));
}
}
item_class(struct_def, _) => {
map_struct_def(struct_def, node_item(i, item_path), i.ident, i.id, cx,
v);
}
item_trait(tps, traits, methods) => {
// Map trait refs to their parent classes. This is
// so we can find the self_ty
for traits.each |p| {
cx.map.insert(p.ref_id, node_item(i, item_path));
// This is so we can look up the right things when
// encoding/decoding
cx.map.insert(p.impl_id, node_item(i, item_path));
}
for methods.each |tm| {
let id = ast_util::trait_method_to_ty_method(tm).id;
let d_id = ast_util::local_def(i.id);
cx.map.insert(id, node_trait_method(@tm, d_id, item_path));
}
}
_ => ()
}
match i.node {
item_mod(_) | item_foreign_mod(_) => {
vec::push(cx.path, path_mod(i.ident));
}
_ => vec::push(cx.path, path_name(i.ident))
}
visit::visit_item(i, cx, v);
vec::pop(cx.path);
}
fn map_struct_def(struct_def: @ast::struct_def, parent_node: ast_node,
ident: ast::ident, id: ast::node_id, cx: ctx, _v: vt) {
// Map trait refs to their parent classes. This is
// so we can find the self_ty
for struct_def.traits.each |p| {
cx.map.insert(p.ref_id, parent_node);
// This is so we can look up the right things when
// encoding/decoding
cx.map.insert(p.impl_id, parent_node);
}
let d_id = ast_util::local_def(id);
let p = extend(cx, ident);
// only need to handle methods
do vec::iter(struct_def.methods) |m| { map_method(d_id, p, m, cx); }
}
fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
match vi.node {
view_item_export(vps) => for vps.each |vp| {
let (id, name) = match vp.node {
view_path_simple(nm, _, id) => {
(id, /* FIXME (#2543) */ copy nm)
}
view_path_glob(pth, id) | view_path_list(pth, _, id) => {
(id, path_to_ident(pth))
}
};
cx.map.insert(id, node_export(vp, extend(cx, name)));
},
_ => ()
}
}
fn map_expr(ex: @expr, cx: ctx, v: vt) {
cx.map.insert(ex.id, node_expr(ex));
visit::visit_expr(ex, cx, v);
}
fn map_stmt(stmt: @stmt, cx: ctx, v: vt) {
cx.map.insert(stmt_id(*stmt), node_stmt(stmt));
visit::visit_stmt(stmt, cx, v);
}
fn node_id_to_str(map: map, id: node_id) -> ~str {
match map.find(id) {
none => {
fmt!{"unknown node (id=%d)", id}
}
some(node_item(item, path)) => {
fmt!{"item %s (id=%?)", path_ident_to_str(*path, item.ident), id}
}
some(node_foreign_item(item, abi, path)) => {
fmt!{"foreign item %s with abi %? (id=%?)",
path_ident_to_str(*path, item.ident), abi, id}
}
some(node_method(m, impl_did, path)) => {
fmt!{"method %s in %s (id=%?)",
*m.ident, path_to_str(*path), id}
}
some(node_trait_method(tm, impl_did, path)) => {
let m = ast_util::trait_method_to_ty_method(*tm);
fmt!{"method %s in %s (id=%?)",
*m.ident, path_to_str(*path), id}
}
some(node_variant(variant, def_id, path)) => {
fmt!{"variant %s in %s (id=%?)",
*variant.node.name, path_to_str(*path), id}
}
some(node_expr(expr)) => {
fmt!{"expr %s (id=%?)",
pprust::expr_to_str(expr), id}
}
some(node_stmt(stmt)) => {
fmt!{"stmt %s (id=%?)",
pprust::stmt_to_str(*stmt), id}
}
// FIXMEs are as per #2410
some(node_export(_, path)) => {
fmt!{"export %s (id=%?)", // add more info here
path_to_str(*path), id}
}
some(node_arg(_, _)) => { // add more info here
fmt!{"arg (id=%?)", id}
}
some(node_local(_)) => { // add more info here
fmt!{"local (id=%?)", id}
}
some(node_ctor(*)) => { // add more info here
fmt!{"node_ctor (id=%?)", id}
}
some(node_dtor(*)) => { // add more info here
fmt!{"node_dtor (id=%?)", id}
}
some(node_block(_)) => {
fmt!{"block"}
}
}
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: