rust/src/libsyntax/ast_util.rs
Tim Chevalier a0d05844ed Correctly forbid upvars in nested impls, traits and classes
Previously, resolve was allowing impls, traits or classes that were
nested within a fn to refer to upvars, as well as referring to type
parameters bound by the fn. Fixing this required adding a new kind of
def: def_typaram_binder, which can refer to any of an impl, trait or
class that has bound ty params. resolve uses this to enforce that
methods can refer to their parent item's type parameters, but not to
outer items' type parameters; other stages ignore it. I also made
sure that impl, trait and class methods get checked inside a
MethodRibKind thing so as to forbid upvars, and changed the definition
of MethodRibKind so that its second argument is an optional node_id
(so that required trait method signatures can be checked with a
MethodRibKind as well).
2012-07-27 17:31:42 -07:00

578 lines
15 KiB
Rust

import codemap::span;
import ast::*;
pure fn spanned<T>(lo: uint, hi: uint, +t: T) -> spanned<T> {
respan(mk_sp(lo, hi), t)
}
pure fn respan<T>(sp: span, +t: T) -> spanned<T> {
{node: t, span: sp}
}
pure fn dummy_spanned<T>(+t: T) -> spanned<T> {
respan(dummy_sp(), t)
}
/* assuming that we're not in macro expansion */
pure fn mk_sp(lo: uint, hi: uint) -> span {
{lo: lo, hi: hi, expn_info: none}
}
// make this a const, once the compiler supports it
pure fn dummy_sp() -> span { ret mk_sp(0u, 0u); }
pure fn path_name(p: @path) -> ~str { path_name_i(p.idents) }
pure fn path_name_i(idents: ~[ident]) -> ~str {
// FIXME: Bad copies (#2543 -- same for everything else that says "bad")
str::connect(idents.map(|i|*i), ~"::")
}
pure fn path_to_ident(p: @path) -> ident { vec::last(p.idents) }
pure fn local_def(id: node_id) -> def_id { {crate: local_crate, node: id} }
pure fn is_local(did: ast::def_id) -> bool { did.crate == local_crate }
pure fn stmt_id(s: stmt) -> node_id {
alt s.node {
stmt_decl(_, id) { id }
stmt_expr(_, id) { id }
stmt_semi(_, id) { id }
}
}
fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} {
alt d { def_variant(enum_id, var_id) {
ret {enm: enum_id, var: var_id}; }
_ { fail ~"non-variant in variant_def_ids"; } }
}
pure fn def_id_of_def(d: def) -> def_id {
alt d {
def_fn(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, _) { id }
def_arg(id, _) | def_local(id, _) | def_self(id) |
def_upvar(id, _, _) | def_binding(id) | def_region(id)
| def_typaram_binder(id) {
local_def(id)
}
def_prim_ty(_) { fail; }
}
}
pure fn binop_to_str(op: binop) -> ~str {
alt op {
add { ret ~"+"; }
subtract { ret ~"-"; }
mul { ret ~"*"; }
div { ret ~"/"; }
rem { ret ~"%"; }
and { ret ~"&&"; }
or { ret ~"||"; }
bitxor { ret ~"^"; }
bitand { ret ~"&"; }
bitor { ret ~"|"; }
shl { ret ~"<<"; }
shr { ret ~">>"; }
eq { ret ~"=="; }
lt { ret ~"<"; }
le { ret ~"<="; }
ne { ret ~"!="; }
ge { ret ~">="; }
gt { ret ~">"; }
}
}
pure fn lazy_binop(b: binop) -> bool {
alt b { and { true } or { true } _ { false } }
}
pure fn is_shift_binop(b: binop) -> bool {
alt b {
shl { true }
shr { true }
_ { false }
}
}
pure fn unop_to_str(op: unop) -> ~str {
alt op {
box(mt) { if mt == m_mutbl { ret ~"@mut "; } ret ~"@"; }
uniq(mt) { if mt == m_mutbl { ret ~"~mut "; } ret ~"~"; }
deref { ret ~"*"; }
not { ret ~"!"; }
neg { ret ~"-"; }
}
}
pure fn is_path(e: @expr) -> bool {
ret alt e.node { expr_path(_) { true } _ { false } };
}
pure fn int_ty_to_str(t: int_ty) -> ~str {
alt t {
ty_char { ~"u8" } // ???
ty_i { ~"" } ty_i8 { ~"i8" } ty_i16 { ~"i16" }
ty_i32 { ~"i32" } ty_i64 { ~"i64" }
}
}
pure fn int_ty_max(t: int_ty) -> u64 {
alt t {
ty_i8 { 0x80u64 }
ty_i16 { 0x8000u64 }
ty_i | ty_char | ty_i32 { 0x80000000u64 } // actually ni about ty_i
ty_i64 { 0x8000000000000000u64 }
}
}
pure fn uint_ty_to_str(t: uint_ty) -> ~str {
alt t {
ty_u { ~"u" } ty_u8 { ~"u8" } ty_u16 { ~"u16" }
ty_u32 { ~"u32" } ty_u64 { ~"u64" }
}
}
pure fn uint_ty_max(t: uint_ty) -> u64 {
alt t {
ty_u8 { 0xffu64 }
ty_u16 { 0xffffu64 }
ty_u | ty_u32 { 0xffffffffu64 } // actually ni about ty_u
ty_u64 { 0xffffffffffffffffu64 }
}
}
pure fn float_ty_to_str(t: float_ty) -> ~str {
alt t { ty_f { ~"" } ty_f32 { ~"f32" } ty_f64 { ~"f64" } }
}
fn is_exported(i: ident, m: _mod) -> bool {
let mut local = false;
let mut parent_enum : option<ident> = none;
for m.items.each |it| {
if it.ident == i { local = true; }
alt it.node {
item_enum(variants, _) {
for variants.each |v| {
if v.node.name == i {
local = true;
parent_enum = some(/* FIXME (#2543) */ copy it.ident);
}
}
}
_ { }
}
if local { break; }
}
let mut has_explicit_exports = false;
for m.view_items.each |vi| {
alt vi.node {
view_item_export(vps) {
has_explicit_exports = true;
for vps.each |vp| {
alt vp.node {
ast::view_path_simple(id, _, _) {
if id == i { ret true; }
alt parent_enum {
some(parent_enum_id) {
if id == parent_enum_id { ret true; }
}
_ {}
}
}
ast::view_path_list(path, ids, _) {
if vec::len(path.idents) == 1u {
if i == path.idents[0] { ret true; }
for ids.each |id| {
if id.node.name == i { ret true; }
}
} else {
fail ~"export of path-qualified list";
}
}
// FIXME: glob-exports aren't supported yet. (#2006)
_ {}
}
}
}
_ {}
}
}
// If there are no declared exports then
// everything not imported is exported
// even if it's local (since it's explicit)
ret !has_explicit_exports && local;
}
pure fn is_call_expr(e: @expr) -> bool {
alt e.node { expr_call(_, _, _) { true } _ { false } }
}
fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret box::ptr_eq(a, b); }
fn hash_ty(&&t: @ty) -> uint {
let res = (t.span.lo << 16u) + t.span.hi;
ret res;
}
fn def_eq(a: ast::def_id, b: ast::def_id) -> bool {
ret a.crate == b.crate && a.node == b.node;
}
fn hash_def(d: ast::def_id) -> uint {
let mut h = 5381u;
h = (h << 5u) + h ^ (d.crate as uint);
h = (h << 5u) + h ^ (d.node as uint);
ret h;
}
fn new_def_hash<V: copy>() -> std::map::hashmap<ast::def_id, V> {
let hasher: std::map::hashfn<ast::def_id> = hash_def;
let eqer: std::map::eqfn<ast::def_id> = def_eq;
ret std::map::hashmap::<ast::def_id, V>(hasher, eqer);
}
fn block_from_expr(e: @expr) -> blk {
let blk_ = default_block(~[], option::some::<@expr>(e), e.id);
ret {node: blk_, span: e.span};
}
fn default_block(+stmts1: ~[@stmt], expr1: option<@expr>, id1: node_id) ->
blk_ {
{view_items: ~[], stmts: stmts1,
expr: expr1, id: id1, rules: default_blk}
}
fn ident_to_path(s: span, +i: ident) -> @path {
@{span: s, global: false, idents: ~[i],
rp: none, types: ~[]}
}
pure fn is_unguarded(&&a: arm) -> bool {
alt a.guard {
none { true }
_ { false }
}
}
pure fn unguarded_pat(a: arm) -> option<~[@pat]> {
if is_unguarded(a) { some(/* FIXME (#2543) */ copy a.pats) } else { none }
}
pure fn class_item_ident(ci: @class_member) -> ident {
alt ci.node {
instance_var(i,_,_,_,_) { /* FIXME (#2543) */ copy i }
class_method(it) { /* FIXME (#2543) */ copy it.ident }
}
}
type ivar = {ident: ident, ty: @ty, cm: class_mutability,
id: node_id, vis: visibility};
fn public_methods(ms: ~[@method]) -> ~[@method] {
vec::filter(ms,
|m| alt m.vis {
public { true }
_ { false }
})
}
fn split_class_items(cs: ~[@class_member]) -> (~[ivar], ~[@method]) {
let mut vs = ~[], ms = ~[];
for cs.each |c| {
alt c.node {
instance_var(i, t, cm, id, vis) {
vec::push(vs, {ident: /* FIXME (#2543) */ copy i,
ty: t,
cm: cm,
id: id,
vis: vis});
}
class_method(m) { vec::push(ms, m); }
}
};
(vs, ms)
}
pure fn class_member_visibility(ci: @class_member) -> visibility {
alt ci.node {
instance_var(_, _, _, _, vis) { vis }
class_method(m) { m.vis }
}
}
trait inlined_item_utils {
fn ident() -> ident;
fn id() -> ast::node_id;
fn accept<E>(e: E, v: visit::vt<E>);
}
impl inlined_item_methods of inlined_item_utils for inlined_item {
fn ident() -> ident {
alt self {
ii_item(i) { /* FIXME (#2543) */ copy i.ident }
ii_foreign(i) { /* FIXME (#2543) */ copy i.ident }
ii_method(_, m) { /* FIXME (#2543) */ copy m.ident }
ii_ctor(_, nm, _, _) { /* FIXME (#2543) */ copy nm }
ii_dtor(_, nm, _, _) { /* FIXME (#2543) */ copy nm }
}
}
fn id() -> ast::node_id {
alt self {
ii_item(i) { i.id }
ii_foreign(i) { i.id }
ii_method(_, m) { m.id }
ii_ctor(ctor, _, _, _) { ctor.node.id }
ii_dtor(dtor, _, _, _) { dtor.node.id }
}
}
fn accept<E>(e: E, v: visit::vt<E>) {
alt self {
ii_item(i) { v.visit_item(i, e, v) }
ii_foreign(i) { v.visit_foreign_item(i, e, v) }
ii_method(_, m) { visit::visit_method_helper(m, e, v) }
ii_ctor(ctor, nm, tps, parent_id) {
visit::visit_class_ctor_helper(ctor, nm, tps, parent_id, e, v);
}
ii_dtor(dtor, nm, tps, parent_id) {
visit::visit_class_dtor_helper(dtor, tps, parent_id, e, v);
}
}
}
}
/* True if d is either a def_self, or a chain of def_upvars
referring to a def_self */
fn is_self(d: ast::def) -> bool {
alt d {
def_self(_) { true }
def_upvar(_, d, _) { is_self(*d) }
_ { false }
}
}
/// Maps a binary operator to its precedence
fn operator_prec(op: ast::binop) -> uint {
alt op {
mul | div | rem { 12u }
// 'as' sits between here with 11
add | subtract { 10u }
shl | shr { 9u }
bitand { 8u }
bitxor { 7u }
bitor { 6u }
lt | le | ge | gt { 4u }
eq | ne { 3u }
and { 2u }
or { 1u }
}
}
fn dtor_dec() -> fn_decl {
let nil_t = @{id: 0, node: ty_nil, span: dummy_sp()};
// dtor has one argument, of type ()
{inputs: ~[{mode: ast::expl(ast::by_ref),
ty: nil_t, ident: @~"_", id: 0}],
output: nil_t, purity: impure_fn, cf: return_val}
}
// ______________________________________________________________________
// Enumerating the IDs which appear in an AST
#[auto_serialize]
type id_range = {min: node_id, max: node_id};
fn empty(range: id_range) -> bool {
range.min >= range.max
}
fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
visit::mk_simple_visitor(@{
visit_mod: fn@(_m: _mod, _sp: span, id: node_id) {
vfn(id)
},
visit_view_item: fn@(vi: @view_item) {
alt vi.node {
view_item_use(_, _, id) { vfn(id) }
view_item_import(vps) | view_item_export(vps) {
do vec::iter(vps) |vp| {
alt vp.node {
view_path_simple(_, _, id) { vfn(id) }
view_path_glob(_, id) { vfn(id) }
view_path_list(_, _, id) { vfn(id) }
}
}
}
}
},
visit_foreign_item: fn@(ni: @foreign_item) {
vfn(ni.id)
},
visit_item: fn@(i: @item) {
vfn(i.id);
alt i.node {
item_enum(vs, _) { for vs.each |v| { vfn(v.node.id); } }
_ {}
}
},
visit_local: fn@(l: @local) {
vfn(l.node.id);
},
visit_block: fn@(b: blk) {
vfn(b.node.id);
},
visit_stmt: fn@(s: @stmt) {
vfn(ast_util::stmt_id(*s));
},
visit_arm: fn@(_a: arm) { },
visit_pat: fn@(p: @pat) {
vfn(p.id)
},
visit_decl: fn@(_d: @decl) {
},
visit_expr: fn@(e: @expr) {
vfn(e.callee_id);
vfn(e.id);
},
visit_ty: fn@(t: @ty) {
alt t.node {
ty_path(_, id) {
vfn(id)
}
_ { /* fall through */ }
}
},
visit_ty_params: fn@(ps: ~[ty_param]) {
vec::iter(ps, |p| vfn(p.id))
},
visit_fn: fn@(fk: visit::fn_kind, d: ast::fn_decl,
_b: ast::blk, _sp: span, id: ast::node_id) {
vfn(id);
alt fk {
visit::fk_ctor(nm, _, tps, self_id, parent_id) {
vec::iter(tps, |tp| vfn(tp.id));
vfn(id);
vfn(self_id);
vfn(parent_id.node);
}
visit::fk_dtor(tps, _, self_id, parent_id) {
vec::iter(tps, |tp| vfn(tp.id));
vfn(id);
vfn(self_id);
vfn(parent_id.node);
}
visit::fk_item_fn(_, tps) {
vec::iter(tps, |tp| vfn(tp.id));
}
visit::fk_method(_, tps, m) {
vfn(m.self_id);
vec::iter(tps, |tp| vfn(tp.id));
}
visit::fk_anon(_, capture_clause)
| visit::fk_fn_block(capture_clause) {
for vec::each(*capture_clause) |clause| {
vfn(clause.id);
}
}
}
do vec::iter(d.inputs) |arg| {
vfn(arg.id)
}
},
visit_ty_method: fn@(_ty_m: ty_method) {
},
visit_trait_method: fn@(_ty_m: trait_method) {
},
visit_class_item: fn@(c: @class_member) {
alt c.node {
instance_var(_, _, _, id,_) {
vfn(id)
}
class_method(_) {
}
}
}
})
}
fn visit_ids_for_inlined_item(item: inlined_item, vfn: fn@(node_id)) {
item.accept((), id_visitor(vfn));
}
fn compute_id_range(visit_ids_fn: fn(fn@(node_id))) -> id_range {
let min = @mut int::max_value;
let max = @mut int::min_value;
do visit_ids_fn |id| {
*min = int::min(*min, id);
*max = int::max(*max, id + 1);
}
ret {min:*min, max:*max};
}
fn compute_id_range_for_inlined_item(item: inlined_item) -> id_range {
compute_id_range(|f| visit_ids_for_inlined_item(item, f))
}
pure fn is_item_impl(item: @ast::item) -> bool {
alt item.node {
item_impl(*) { true }
_ { false }
}
}
fn walk_pat(pat: @pat, it: fn(@pat)) {
it(pat);
alt pat.node {
pat_ident(pth, some(p)) { walk_pat(p, it); }
pat_rec(fields, _) {
for fields.each |f| { walk_pat(f.pat, it); }
}
pat_enum(_, some(s)) | pat_tup(s) {
for s.each |p| { walk_pat(p, it); }
}
pat_box(s) | pat_uniq(s) { walk_pat(s, it); }
pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _)
| pat_enum(_, _) {}
}
}
fn view_path_id(p: @view_path) -> node_id {
alt p.node {
view_path_simple(_, _, id) | view_path_glob(_, id) |
view_path_list(_, _, id) { id }
}
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: