rust/src/comp/middle/visit.rs
Tim Chevalier 698c6406ba Reject programs with unsatisfied predicate constraints
Generate appropriate constraints for calls to functions with
preconditions, and reject calls where those constraints don't
hold true in the prestate.

...by which I mean that it works for one test case :-)
2011-06-10 19:17:15 -07:00

431 lines
14 KiB
Rust

import front::ast::*;
import std::option;
import std::option::some;
import std::option::none;
import util::common::span;
// Context-passing AST walker. Each overridden visit method has full control
// over what happens with its node, it can do its own traversal of the node's
// children (potentially passing in different contexts to each), call
// visit::visit_* to apply the default traversal algorithm (again, it can
// override the context), or prevent deeper traversal by doing nothing.
// Lots of redundant indirection and refcounting. Our typesystem doesn't do
// circular types, so the visitor record can not hold functions that take
// visitors. A vt tag is used to break the cycle.
tag vt[E] { vtor(visitor[E]); }
fn vt[E](&vt[E] x) -> visitor[E] {
alt (x) { case (vtor(?v)) { ret v; } }
}
type visitor[E] =
@rec(fn(&_mod m, &span sp, &E e, &vt[E] v) visit_mod,
fn(&@view_item v, &E e, &vt[E] v) visit_view_item,
fn(&@native_item i, &E e, &vt[E] v) visit_native_item,
fn(&@item i, &E e, &vt[E] v) visit_item,
fn(&block b, &E e, &vt[E] v) visit_block,
fn(&@stmt s, &E e, &vt[E] v) visit_stmt,
fn(&arm a, &E e, &vt[E] v) visit_arm,
fn(&@pat p, &E e, &vt[E] v) visit_pat,
fn(&@decl d, &E e, &vt[E] v) visit_decl,
fn(&@expr ex, &E e, &vt[E] v) visit_expr,
fn(&@ty t, &E e, &vt[E] v) visit_ty,
fn(&@constr c, &E e, &vt[E] v) visit_constr,
fn(&_fn f, &vec[ty_param] tp, &span sp, &ident name, &def_id d_id,
&ann a, &E e, &vt[E] v) visit_fn);
fn default_visitor[E]() -> visitor[E] {
ret @rec(visit_mod = bind visit_mod[E](_, _, _, _),
visit_view_item = bind visit_view_item[E](_, _, _),
visit_native_item = bind visit_native_item[E](_, _, _),
visit_item = bind visit_item[E](_, _, _),
visit_block = bind visit_block[E](_, _, _),
visit_stmt = bind visit_stmt[E](_, _, _),
visit_arm = bind visit_arm[E](_, _, _),
visit_pat = bind visit_pat[E](_, _, _),
visit_decl = bind visit_decl[E](_, _, _),
visit_expr = bind visit_expr[E](_, _, _),
visit_ty = bind visit_ty[E](_, _, _),
visit_constr = bind visit_constr[E](_, _, _),
visit_fn = bind visit_fn[E](_, _, _, _, _, _, _, _));
}
fn visit_crate[E](&crate c, &E e, &vt[E] v) {
vt(v).visit_mod(c.node.module, c.span, e, v);
}
fn visit_crate_directive[E](&@crate_directive cd, &E e, &vt[E] v) {
alt (cd.node) {
case (cdir_let(_, ?ex, ?cdirs)) {
vt(v).visit_expr(ex, e, v);
for (@crate_directive cdir in cdirs) {
visit_crate_directive(cdir, e, v);
}
}
case (cdir_src_mod(_, _)) {}
case (cdir_dir_mod(_, _, ?cdirs)) {
for (@crate_directive cdir in cdirs) {
visit_crate_directive(cdir, e, v);
}
}
case (cdir_view_item(?vi)) {
vt(v).visit_view_item(vi, e, v);
}
case (cdir_meta(_,_)) {}
case (cdir_syntax(_)) {}
case (cdir_auth(_, _)) {}
}
}
fn visit_mod[E](&_mod m, &span sp, &E e, &vt[E] v) {
for (@view_item vi in m.view_items) {
vt(v).visit_view_item(vi, e, v);
}
for (@item i in m.items) {
vt(v).visit_item(i, e, v);
}
}
fn visit_view_item[E](&@view_item vi, &E e, &vt[E] v) {}
fn visit_item[E](&@item i, &E e, &vt[E] v) {
alt (i.node) {
case (item_const(_, ?t, ?ex, _, _)) {
vt(v).visit_ty(t, e, v);
vt(v).visit_expr(ex, e, v);
}
case (item_fn(?nm, ?f, ?tp, ?d, ?a)) {
vt(v).visit_fn(f, tp, i.span, nm, d, a, e, v);
}
case (item_mod(_, ?m, _)) {
vt(v).visit_mod(m, i.span, e, v);
}
case (item_native_mod(_, ?nm, _)) {
for (@view_item vi in nm.view_items) {
vt(v).visit_view_item(vi, e, v);
}
for (@native_item ni in nm.items) {
vt(v).visit_native_item(ni, e, v);
}
}
case (item_ty(_, ?t, _, _, _)) {
vt(v).visit_ty(t, e, v);
}
case (item_tag(_, ?variants, _, _, _)) {
for (variant vr in variants) {
for (variant_arg va in vr.node.args) {
vt(v).visit_ty(va.ty, e, v);
}
}
}
case (item_obj(_, ?ob, _, _, _)) {
for (obj_field f in ob.fields) {
vt(v).visit_ty(f.ty, e, v);
}
for (@method m in ob.methods) {
vt(v).visit_fn(m.node.meth, [], m.span, m.node.ident,
m.node.id, m.node.ann, e, v);
}
alt (ob.dtor) {
case (none) {}
case (some(?m)) {
vt(v).visit_fn(m.node.meth, [], m.span, m.node.ident,
m.node.id, m.node.ann, e, v);
}
}
}
}
}
fn visit_ty[E](&@ty t, &E e, &vt[E] v) {
alt (t.node) {
case (ty_box(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
case (ty_vec(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
case (ty_ptr(?mt)) { vt(v).visit_ty(mt.ty, e, v); }
case (ty_port(?t)) { vt(v).visit_ty(t, e, v); }
case (ty_chan(?t)) { vt(v).visit_ty(t, e, v); }
case (ty_tup(?mts)) {
for (mt mt in mts) {
vt(v).visit_ty(mt.ty, e, v);
}
}
case (ty_rec(?flds)) {
for (ty_field f in flds) {
vt(v).visit_ty(f.node.mt.ty, e, v);
}
}
case (ty_fn(_, ?args, ?out, _, ?constrs)) {
for (ty_arg a in args) {
vt(v).visit_ty(a.node.ty, e, v);
}
for (@constr c in constrs) {
vt(v).visit_constr(c, e, v);
}
vt(v).visit_ty(out, e, v);
}
case (ty_obj(?tmeths)) {
for (ty_method m in tmeths) {
for (ty_arg a in m.node.inputs) {
vt(v).visit_ty(a.node.ty, e, v);
}
vt(v).visit_ty(m.node.output, e, v);
}
}
case (ty_path(?p, _)) {
for (@ty tp in p.node.types) {
vt(v).visit_ty(tp, e, v);
}
}
case (ty_constr(?t, _)) { vt(v).visit_ty(t, e, v); }
case (_) {}
}
}
fn visit_constr[E](&@constr c, &E e, &vt[E] v) {
// default
}
fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
alt (p.node) {
case (pat_tag(?path, ?children, _)) {
for (@ty tp in path.node.types) { vt(v).visit_ty(tp, e, v); }
for (@pat child in children) { vt(v).visit_pat(child, e, v); }
}
case (_) {}
}
}
fn visit_native_item[E](&@native_item ni, &E e, &vt[E] v) {
alt (ni.node) {
case (native_item_fn(_, _, ?fd, _, _, _)) {
visit_fn_decl(fd, e, v);
}
case (native_item_ty(_, _)) {}
}
}
fn visit_fn_decl[E](&fn_decl fd, &E e, &vt[E] v) {
for (arg a in fd.inputs) {
vt(v).visit_ty(a.ty, e, v);
}
for (@constr c in fd.constraints) {
vt(v).visit_constr(c, e, v);
}
vt(v).visit_ty(fd.output, e, v);
}
fn visit_fn[E](&_fn f, &vec[ty_param] tp, &span sp, &ident i, &def_id d,
&ann a, &E e, &vt[E] v) {
visit_fn_decl(f.decl, e, v);
vt(v).visit_block(f.body, e, v);
}
fn visit_block[E](&block b, &E e, &vt[E] v) {
for (@stmt s in b.node.stmts) { vt(v).visit_stmt(s, e, v); }
visit_expr_opt(b.node.expr, e, v);
}
fn visit_stmt[E](&@stmt s, &E e, &vt[E] v) {
alt (s.node) {
case (stmt_decl(?d, _)) { vt(v).visit_decl(d, e, v); }
case (stmt_expr(?ex, _)) { vt(v).visit_expr(ex, e, v); }
case (stmt_crate_directive(?cd)) { visit_crate_directive(cd, e, v); }
}
}
fn visit_decl[E](&@decl d, &E e, &vt[E] v) {
alt (d.node) {
case (decl_local(?loc)) {
alt (loc.ty) {
case (none) {}
case (some(?t)) { vt(v).visit_ty(t, e, v); }
}
alt (loc.init) {
case (none) {}
case (some(?i)) { vt(v).visit_expr(i.expr, e, v); }
}
}
case (decl_item(?it)) { vt(v).visit_item(it, e, v); }
}
}
fn visit_expr_opt[E](option::t[@expr] eo, &E e, &vt[E] v) {
alt (eo) {
case (none) {}
case (some(?ex)) { vt(v).visit_expr(ex, e, v);
}
}
}
fn visit_exprs[E](vec[@expr] exprs, &E e, &vt[E] v) {
for (@expr ex in exprs) { vt(v).visit_expr(ex, e, v); }
}
fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
alt (ex.node) {
case (expr_vec(?es, _, _, _)) {
visit_exprs(es, e, v);
}
case (expr_tup(?elts, _)) {
for (elt el in elts) { vt(v).visit_expr(el.expr, e, v); }
}
case (expr_rec(?flds, ?base, _)) {
for (field f in flds) { vt(v).visit_expr(f.node.expr, e, v); }
visit_expr_opt(base, e, v);
}
case (expr_call(?callee, ?args, _)) {
vt(v).visit_expr(callee, e, v);
visit_exprs(args, e, v);
}
case (expr_self_method(_, _)) { }
case (expr_bind(?callee, ?args, _)) {
vt(v).visit_expr(callee, e, v);
for (option::t[@expr] eo in args) { visit_expr_opt(eo, e, v); }
}
case (expr_spawn(_, _, ?callee, ?args, _)) {
vt(v).visit_expr(callee, e, v);
visit_exprs(args, e, v);
}
case (expr_binary(_, ?a, ?b, _)) {
vt(v).visit_expr(a, e, v);
vt(v).visit_expr(b, e, v);
}
case (expr_unary(_, ?a, _)) {
vt(v).visit_expr(a, e, v);
}
case (expr_lit(_, _)) { }
case (expr_cast(?x, ?t, _)) {
vt(v).visit_expr(x, e, v);
vt(v).visit_ty(t, e, v);
}
case (expr_if(?x, ?b, ?eo, _)) {
vt(v).visit_expr(x, e, v);
vt(v).visit_block(b, e, v);
visit_expr_opt(eo, e, v);
}
case (expr_while(?x, ?b, _)) {
vt(v).visit_expr(x, e, v);
vt(v).visit_block(b, e, v);
}
case (expr_for(?dcl, ?x, ?b, _)) {
vt(v).visit_decl(dcl, e, v);
vt(v).visit_expr(x, e, v);
vt(v).visit_block(b, e, v);
}
case (expr_for_each(?dcl, ?x, ?b, _)) {
vt(v).visit_decl(dcl, e, v);
vt(v).visit_expr(x, e, v);
vt(v).visit_block(b, e, v);
}
case (expr_do_while(?b, ?x, _)) {
vt(v).visit_block(b, e, v);
vt(v).visit_expr(x, e, v);
}
case (expr_alt(?x, ?arms, _)) {
vt(v).visit_expr(x, e, v);
for (arm a in arms) {
vt(v).visit_arm(a, e, v);
}
}
case (expr_block(?b, _)) {
vt(v).visit_block(b, e, v);
}
case (expr_assign(?a, ?b, _)) {
vt(v).visit_expr(b, e, v);
vt(v).visit_expr(a, e, v);
}
case (expr_move(?a, ?b, _)) {
vt(v).visit_expr(b, e, v);
vt(v).visit_expr(a, e, v);
}
case (expr_assign_op(_, ?a, ?b, _)) {
vt(v).visit_expr(b, e, v);
vt(v).visit_expr(a, e, v);
}
case (expr_send(?a, ?b, _)) {
vt(v).visit_expr(a, e, v);
vt(v).visit_expr(b, e, v);
}
case (expr_recv(?a, ?b, _)) {
vt(v).visit_expr(a, e, v);
vt(v).visit_expr(b, e, v);
}
case (expr_field(?x, _, _)) {
vt(v).visit_expr(x, e, v);
}
case (expr_index(?a, ?b, _)) {
vt(v).visit_expr(a, e, v);
vt(v).visit_expr(b, e, v);
}
case (expr_path(?p, _)) {
for (@ty tp in p.node.types) {
vt(v).visit_ty(tp, e, v);
}
}
case (expr_ext(_, _, _, ?expansion, _)) {
vt(v).visit_expr(expansion, e, v);
}
case (expr_fail(_, _)) { }
case (expr_break(_)) { }
case (expr_cont(_)) { }
case (expr_ret(?eo, _)) {
visit_expr_opt(eo, e, v);
}
case (expr_put(?eo, _)) {
visit_expr_opt(eo, e, v);
}
case (expr_be(?x, _)) {
vt(v).visit_expr(x, e, v);
}
case (expr_log(_,?x, _)) {
vt(v).visit_expr(x, e, v);
}
case (expr_check(?x, _)) {
vt(v).visit_expr(x, e, v);
}
case (expr_assert(?x, _)) {
vt(v).visit_expr(x, e, v);
}
case (expr_port(_)) { }
case (expr_chan(?x, _)) {
vt(v).visit_expr(x, e, v);
}
case (expr_anon_obj(?anon_obj,_,_,_)) {
alt (anon_obj.fields) {
case (none) { }
case (some(?fields)) {
for (obj_field f in fields) {
vt(v).visit_ty(f.ty, e, v);
}
}
}
alt (anon_obj.with_obj) {
case (none) { }
case (some(?ex)) {
vt(v).visit_expr(ex, e, v);
}
}
for (@method m in anon_obj.methods) {
vt(v).visit_fn(m.node.meth, [], m.span, m.node.ident,
m.node.id, m.node.ann, e, v);
}
}
}
}
fn visit_arm[E](&arm a, &E e, &vt[E] v) {
vt(v).visit_pat(a.pat, e, v);
vt(v).visit_block(a.block, e, v);
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End: