Make { || ... } sugar for any type of closure, inferred
This commit is contained in:
parent
1e4de33374
commit
6a90140941
21 changed files with 392 additions and 242 deletions
|
@ -61,7 +61,7 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) {
|
||||||
copy_map: std::map::new_int_hash(),
|
copy_map: std::map::new_int_hash(),
|
||||||
ref_map: std::map::new_int_hash(),
|
ref_map: std::map::new_int_hash(),
|
||||||
mutable silent: false};
|
mutable silent: false};
|
||||||
let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
|
let v = @{visit_fn_body: bind visit_fn_body(cx, _, _, _, _, _, _, _),
|
||||||
visit_expr: bind visit_expr(cx, _, _, _),
|
visit_expr: bind visit_expr(cx, _, _, _),
|
||||||
visit_block: bind visit_block(cx, _, _, _)
|
visit_block: bind visit_block(cx, _, _, _)
|
||||||
with *visit::default_visitor::<scope>()};
|
with *visit::default_visitor::<scope>()};
|
||||||
|
@ -71,10 +71,12 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) {
|
||||||
ret (cx.copy_map, cx.ref_map);
|
ret (cx.copy_map, cx.ref_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span,
|
fn visit_fn_body(cx: @ctx, decl: ast::fn_decl, body: ast::blk,
|
||||||
_name: fn_ident, id: ast::node_id, sc: scope, v: vt<scope>) {
|
sp: span, _name: ast::fn_ident,
|
||||||
visit::visit_fn_decl(f.decl, sc, v);
|
id: ast::node_id, sc: scope, v: vt<scope>) {
|
||||||
let args = ty::ty_fn_args(cx.tcx, ty::node_id_to_type(cx.tcx, id));
|
visit::visit_fn_decl(decl, sc, v);
|
||||||
|
let fty = ty::node_id_to_type(cx.tcx, id);
|
||||||
|
let args = ty::ty_fn_args(cx.tcx, fty);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg.mode == ast::by_val &&
|
if arg.mode == ast::by_val &&
|
||||||
ty::type_has_dynamic_size(cx.tcx, arg.ty) {
|
ty::type_has_dynamic_size(cx.tcx, arg.ty) {
|
||||||
|
@ -84,11 +86,12 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span,
|
||||||
|
|
||||||
// Blocks need to obey any restrictions from the enclosing scope, and may
|
// Blocks need to obey any restrictions from the enclosing scope, and may
|
||||||
// be called multiple times.
|
// be called multiple times.
|
||||||
if f.proto == ast::proto_block {
|
let proto = ty::ty_fn_proto(cx.tcx, fty);
|
||||||
check_loop(*cx, sc) {|| v.visit_block(f.body, sc, v);}
|
if proto == ast::proto_block {
|
||||||
|
check_loop(*cx, sc) {|| v.visit_block(body, sc, v);}
|
||||||
} else {
|
} else {
|
||||||
let sc = {bs: [], invalid: @mutable list::nil};
|
let sc = {bs: [], invalid: @mutable list::nil};
|
||||||
v.visit_block(f.body, sc, v);
|
v.visit_block(body, sc, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ fn map_crate(c: crate) -> map {
|
||||||
(@{visit_item: bind map_item(cx, _),
|
(@{visit_item: bind map_item(cx, _),
|
||||||
visit_native_item: bind map_native_item(cx, _),
|
visit_native_item: bind map_native_item(cx, _),
|
||||||
visit_expr: bind map_expr(cx, _),
|
visit_expr: bind map_expr(cx, _),
|
||||||
visit_fn: bind map_fn(cx, _, _, _, _, _),
|
visit_fn_body: bind map_fn_body(cx, _, _, _, _, _),
|
||||||
visit_local: bind map_local(cx, _),
|
visit_local: bind map_local(cx, _),
|
||||||
visit_arm: bind map_arm(cx, _)
|
visit_arm: bind map_arm(cx, _)
|
||||||
with *visit::default_simple_visitor()});
|
with *visit::default_simple_visitor()});
|
||||||
|
@ -40,9 +40,9 @@ fn map_crate(c: crate) -> map {
|
||||||
ret cx.map;
|
ret cx.map;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_fn(cx: ctx, f: _fn, _tp: [ty_param], _sp: codemap::span,
|
fn map_fn_body(cx: ctx, decl: fn_decl, _body: blk,
|
||||||
_name: fn_ident, _id: node_id) {
|
_sp: codemap::span, _n: fn_ident, _id: node_id) {
|
||||||
for a in f.decl.inputs {
|
for a in decl.inputs {
|
||||||
cx.map.insert(a.id, node_arg(a, cx.local_id));
|
cx.map.insert(a.id, node_arg(a, cx.local_id));
|
||||||
cx.local_id += 1u;
|
cx.local_id += 1u;
|
||||||
}
|
}
|
||||||
|
|
|
@ -740,6 +740,9 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> {
|
||||||
ast::expr_fn(f, _) {
|
ast::expr_fn(f, _) {
|
||||||
(dbg_cx.names.next("fn"), f.decl.output, expr.id)
|
(dbg_cx.names.next("fn"), f.decl.output, expr.id)
|
||||||
}
|
}
|
||||||
|
ast::expr_fn_block(decl, _) {
|
||||||
|
(dbg_cx.names.next("fn"), decl.output, expr.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,8 +28,8 @@ type freevar_map = hashmap<ast::node_id, freevar_info>;
|
||||||
// Since we want to be able to collect upvars in some arbitrary piece
|
// Since we want to be able to collect upvars in some arbitrary piece
|
||||||
// of the AST, we take a walker function that we invoke with a visitor
|
// of the AST, we take a walker function that we invoke with a visitor
|
||||||
// in order to start the search.
|
// in order to start the search.
|
||||||
fn collect_freevars(def_map: resolve::def_map, walker: fn@(visit::vt<int>)) ->
|
fn collect_freevars(def_map: resolve::def_map, blk: ast::blk)
|
||||||
freevar_info {
|
-> freevar_info {
|
||||||
let seen = new_int_hash();
|
let seen = new_int_hash();
|
||||||
let refs = @mutable [];
|
let refs = @mutable [];
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@ fn collect_freevars(def_map: resolve::def_map, walker: fn@(visit::vt<int>)) ->
|
||||||
visit::visit_expr(expr, depth + 1, v);
|
visit::visit_expr(expr, depth + 1, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::expr_fn_block(_, _) {
|
||||||
|
visit::visit_expr(expr, depth + 1, v);
|
||||||
|
}
|
||||||
ast::expr_path(path) {
|
ast::expr_path(path) {
|
||||||
let def = def_map.get(expr.id), i = 0;
|
let def = def_map.get(expr.id), i = 0;
|
||||||
while i < depth {
|
while i < depth {
|
||||||
|
@ -64,8 +67,9 @@ fn collect_freevars(def_map: resolve::def_map, walker: fn@(visit::vt<int>)) ->
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
walker(visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr
|
let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr
|
||||||
with *visit::default_visitor()}));
|
with *visit::default_visitor()});
|
||||||
|
v.visit_block(blk, 1, v);
|
||||||
ret @*refs;
|
ret @*refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,20 +82,16 @@ fn annotate_freevars(def_map: resolve::def_map, crate: @ast::crate) ->
|
||||||
freevar_map {
|
freevar_map {
|
||||||
let freevars = new_int_hash();
|
let freevars = new_int_hash();
|
||||||
|
|
||||||
let walk_fn =
|
let walk_fn_body = lambda (_decl: ast::fn_decl, blk: ast::blk,
|
||||||
lambda (f: ast::_fn, tps: [ast::ty_param], sp: span, i: ast::fn_ident,
|
_sp: span, _nm: ast::fn_ident,
|
||||||
nid: ast::node_id) {
|
nid: ast::node_id) {
|
||||||
let start_walk =
|
let vars = collect_freevars(def_map, blk);
|
||||||
lambda (v: visit::vt<int>) {
|
freevars.insert(nid, vars);
|
||||||
v.visit_fn(f, tps, sp, i, nid, 1, v);
|
};
|
||||||
};
|
|
||||||
let vars = collect_freevars(def_map, start_walk);
|
|
||||||
freevars.insert(nid, vars);
|
|
||||||
};
|
|
||||||
|
|
||||||
let visitor =
|
let visitor =
|
||||||
visit::mk_simple_visitor(@{visit_fn: walk_fn
|
visit::mk_simple_visitor(@{visit_fn_body: walk_fn_body
|
||||||
with *visit::default_simple_visitor()});
|
with *visit::default_simple_visitor()});
|
||||||
visit::visit_crate(*crate, (), visitor);
|
visit::visit_crate(*crate, (), visitor);
|
||||||
|
|
||||||
ret freevars;
|
ret freevars;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import syntax::{visit, ast_util};
|
import syntax::{visit, ast_util};
|
||||||
import syntax::ast::*;
|
import syntax::ast::*;
|
||||||
|
import syntax::codemap::span;
|
||||||
import std::list::{list, nil, cons, tail};
|
import std::list::{list, nil, cons, tail};
|
||||||
import core::{vec, option};
|
import core::{vec, option};
|
||||||
import std::list;
|
import std::list;
|
||||||
|
@ -42,7 +43,7 @@ type ctx = {last_uses: std::map::hashmap<node_id, bool>,
|
||||||
fn find_last_uses(c: @crate, def_map: resolve::def_map,
|
fn find_last_uses(c: @crate, def_map: resolve::def_map,
|
||||||
ref_map: alias::ref_map, tcx: ty::ctxt) -> last_uses {
|
ref_map: alias::ref_map, tcx: ty::ctxt) -> last_uses {
|
||||||
let v = visit::mk_vt(@{visit_expr: visit_expr,
|
let v = visit::mk_vt(@{visit_expr: visit_expr,
|
||||||
visit_fn: visit_fn
|
visit_fn_body: visit_fn_body
|
||||||
with *visit::default_visitor()});
|
with *visit::default_visitor()});
|
||||||
let cx = {last_uses: std::map::new_int_hash(),
|
let cx = {last_uses: std::map::new_int_hash(),
|
||||||
def_map: def_map,
|
def_map: def_map,
|
||||||
|
@ -136,6 +137,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||||
alt arg.node {
|
alt arg.node {
|
||||||
//NDM--register captured as uses
|
//NDM--register captured as uses
|
||||||
expr_fn(_, captured) { fns += [arg]; }
|
expr_fn(_, captured) { fns += [arg]; }
|
||||||
|
expr_fn_block(_, _) { fns += [arg]; }
|
||||||
_ {
|
_ {
|
||||||
alt arg_ts[i].mode {
|
alt arg_ts[i].mode {
|
||||||
by_mut_ref. { clear_if_path(cx, arg, v, false); }
|
by_mut_ref. { clear_if_path(cx, arg, v, false); }
|
||||||
|
@ -151,16 +153,19 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn(f: _fn, tps: [ty_param], sp: syntax::codemap::span,
|
fn visit_fn_body(decl: fn_decl, body: blk,
|
||||||
ident: fn_ident, id: node_id, cx: ctx, v: visit::vt<ctx>) {
|
sp: span, nm: fn_ident, id: node_id,
|
||||||
if f.proto == proto_block {
|
cx: ctx, v: visit::vt<ctx>) {
|
||||||
|
let fty = ty::node_id_to_type(cx.tcx, id);
|
||||||
|
let proto = ty::ty_fn_proto(cx.tcx, fty);
|
||||||
|
if proto == proto_block {
|
||||||
visit_block(func, cx, {||
|
visit_block(func, cx, {||
|
||||||
visit::visit_fn(f, tps, sp, ident, id, cx, v);
|
visit::visit_fn_body(decl, body, sp, nm, id, cx, v);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let old = nil;
|
let old = nil;
|
||||||
cx.blocks <-> old;
|
cx.blocks <-> old;
|
||||||
visit::visit_fn(f, tps, sp, ident, id, cx, v);
|
visit::visit_fn_body(decl, body, sp, nm, id, cx, v);
|
||||||
cx.blocks <-> old;
|
cx.blocks <-> old;
|
||||||
leave_fn(cx);
|
leave_fn(cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,7 @@ fn check_lval(cx: @ctx, dest: @expr, msg: msg) {
|
||||||
alt dest.node {
|
alt dest.node {
|
||||||
expr_path(p) {
|
expr_path(p) {
|
||||||
let def = cx.tcx.def_map.get(dest.id);
|
let def = cx.tcx.def_map.get(dest.id);
|
||||||
alt is_immutable_def(def) {
|
alt is_immutable_def(cx, def) {
|
||||||
some(name) { mk_err(cx, dest.span, msg, name); }
|
some(name) { mk_err(cx, dest.span, msg, name); }
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ fn check_bind(cx: @ctx, f: @expr, args: [option::t<@expr>]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_immutable_def(def: def) -> option::t<str> {
|
fn is_immutable_def(cx: @ctx, def: def) -> option::t<str> {
|
||||||
alt def {
|
alt def {
|
||||||
def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
|
def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
|
||||||
def_use(_) {
|
def_use(_) {
|
||||||
|
@ -268,8 +268,13 @@ fn is_immutable_def(def: def) -> option::t<str> {
|
||||||
def_arg(_, mode_infer.) { some("argument") }
|
def_arg(_, mode_infer.) { some("argument") }
|
||||||
def_obj_field(_, imm.) { some("immutable object field") }
|
def_obj_field(_, imm.) { some("immutable object field") }
|
||||||
def_self(_) { some("self argument") }
|
def_self(_) { some("self argument") }
|
||||||
def_upvar(_, inner, mut) {
|
def_upvar(_, inner, node_id) {
|
||||||
if !mut { some("upvar") } else { is_immutable_def(*inner) }
|
let ty = ty::node_id_to_monotype(cx.tcx, node_id);
|
||||||
|
let proto = ty::ty_fn_proto(cx.tcx, ty);
|
||||||
|
ret alt proto {
|
||||||
|
proto_block. { is_immutable_def(cx, *inner) }
|
||||||
|
_ { some("upvar") }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
def_binding(_) { some("binding") }
|
def_binding(_) { some("binding") }
|
||||||
def_local(_, let_ref.) { some("by-reference binding") }
|
def_local(_, let_ref.) { some("by-reference binding") }
|
||||||
|
|
|
@ -31,7 +31,8 @@ export _impl, iscopes, method_info;
|
||||||
tag scope {
|
tag scope {
|
||||||
scope_crate;
|
scope_crate;
|
||||||
scope_item(@ast::item);
|
scope_item(@ast::item);
|
||||||
scope_fn(ast::fn_decl, ast::proto, [ast::ty_param]);
|
scope_bare_fn(ast::fn_decl, node_id, [ast::ty_param]);
|
||||||
|
scope_fn_expr(ast::fn_decl, node_id, [ast::ty_param]);
|
||||||
scope_native_item(@ast::native_item);
|
scope_native_item(@ast::native_item);
|
||||||
scope_loop(@ast::local); // there's only 1 decl per loop.
|
scope_loop(@ast::local); // there's only 1 decl per loop.
|
||||||
scope_block(ast::blk, @mutable uint, @mutable uint);
|
scope_block(ast::blk, @mutable uint, @mutable uint);
|
||||||
|
@ -335,8 +336,11 @@ fn resolve_names(e: @env, c: @ast::crate) {
|
||||||
visit_expr: bind walk_expr(e, _, _, _),
|
visit_expr: bind walk_expr(e, _, _, _),
|
||||||
visit_ty: bind walk_ty(e, _, _, _),
|
visit_ty: bind walk_ty(e, _, _, _),
|
||||||
visit_constr: bind walk_constr(e, _, _, _, _, _),
|
visit_constr: bind walk_constr(e, _, _, _, _, _),
|
||||||
visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
|
visit_fn_proto:
|
||||||
with *visit::default_visitor()};
|
bind visit_fn_proto_with_scope(e, _, _, _, _, _, _, _),
|
||||||
|
visit_fn_block:
|
||||||
|
bind visit_fn_block_with_scope(e, _, _, _, _, _, _)
|
||||||
|
with *visit::default_visitor()};
|
||||||
visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v));
|
visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v));
|
||||||
e.used_imports.track = false;
|
e.used_imports.track = false;
|
||||||
e.sess.abort_if_errors();
|
e.sess.abort_if_errors();
|
||||||
|
@ -400,8 +404,8 @@ fn visit_item_with_scope(i: @ast::item, sc: scopes, v: vt<scopes>) {
|
||||||
ast::item_impl(tps, sty, methods) {
|
ast::item_impl(tps, sty, methods) {
|
||||||
visit::visit_ty(sty, sc, v);
|
visit::visit_ty(sty, sc, v);
|
||||||
for m in methods {
|
for m in methods {
|
||||||
v.visit_fn(m.node.meth, tps + m.node.tps, m.span,
|
v.visit_fn_proto(m.node.meth, tps + m.node.tps, m.span,
|
||||||
some(m.node.ident), m.node.id, sc, v);
|
some(m.node.ident), m.node.id, sc, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ { visit::visit_item(i, sc, v); }
|
_ { visit::visit_item(i, sc, v); }
|
||||||
|
@ -413,9 +417,9 @@ fn visit_native_item_with_scope(ni: @ast::native_item, sc: scopes,
|
||||||
visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v);
|
visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param], sp: span,
|
fn visit_fn_proto_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param],
|
||||||
name: fn_ident, id: node_id, sc: scopes,
|
sp: span, name: fn_ident, id: node_id,
|
||||||
v: vt<scopes>) {
|
sc: scopes, v: vt<scopes>) {
|
||||||
// is this a main fn declaration?
|
// is this a main fn declaration?
|
||||||
alt name {
|
alt name {
|
||||||
some(nm) {
|
some(nm) {
|
||||||
|
@ -431,8 +435,21 @@ fn visit_fn_with_scope(e: @env, f: ast::_fn, tp: [ast::ty_param], sp: span,
|
||||||
// here's where we need to set up the mapping
|
// here's where we need to set up the mapping
|
||||||
// for f's constrs in the table.
|
// for f's constrs in the table.
|
||||||
for c: @ast::constr in f.decl.constraints { resolve_constr(e, c, sc, v); }
|
for c: @ast::constr in f.decl.constraints { resolve_constr(e, c, sc, v); }
|
||||||
visit::visit_fn(f, tp, sp, name, id,
|
let scope = alt f.proto {
|
||||||
cons(scope_fn(f.decl, f.proto, tp), @sc), v);
|
ast::proto_bare. { scope_bare_fn(f.decl, id, tp) }
|
||||||
|
_ { scope_fn_expr(f.decl, id, tp) }
|
||||||
|
};
|
||||||
|
|
||||||
|
visit::visit_fn_proto(f, tp, sp, name, id, cons(scope, @sc), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_fn_block_with_scope(_e: @env, decl: fn_decl, blk: ast::blk,
|
||||||
|
span: span, id: node_id,
|
||||||
|
sc: scopes, v: vt<scopes>) {
|
||||||
|
let scope = scope_fn_expr(decl, id, []);
|
||||||
|
log ("scope=", scope);
|
||||||
|
visit::visit_fn_block(decl, blk, span, id, cons(scope, @sc), v);
|
||||||
|
log ("unscope");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
|
fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
|
||||||
|
@ -648,7 +665,8 @@ fn unresolved_err(e: env, cx: ctxt, sp: span, name: ident, kind: str) {
|
||||||
alt sc {
|
alt sc {
|
||||||
cons(cur, rest) {
|
cons(cur, rest) {
|
||||||
alt cur {
|
alt cur {
|
||||||
scope_crate. | scope_fn(_, _, _) |
|
scope_crate. | scope_bare_fn(_, _, _) |
|
||||||
|
scope_fn_expr(_, _, _) |
|
||||||
scope_item(@{node: ast::item_mod(_), _}) {
|
scope_item(@{node: ast::item_mod(_), _}) {
|
||||||
ret some(cur);
|
ret some(cur);
|
||||||
}
|
}
|
||||||
|
@ -734,23 +752,17 @@ fn lookup_in_scope_strict(e: env, sc: scopes, sp: span, name: ident,
|
||||||
|
|
||||||
fn scope_is_fn(sc: scope) -> bool {
|
fn scope_is_fn(sc: scope) -> bool {
|
||||||
ret alt sc {
|
ret alt sc {
|
||||||
scope_fn(_, ast::proto_bare., _) |
|
scope_bare_fn(_, _, _) | scope_native_item(_) { true }
|
||||||
scope_native_item(_) {
|
_ { false }
|
||||||
true
|
};
|
||||||
}
|
|
||||||
_ { false }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns:
|
// Returns:
|
||||||
// none - does not close
|
// none - does not close
|
||||||
// some(true) - closes and permits mutation
|
// some(node_id) - closes via the expr w/ node_id
|
||||||
// some(false) - closes but no mutation
|
fn scope_closes(sc: scope) -> option::t<node_id> {
|
||||||
fn scope_closes(sc: scope) -> option::t<bool> {
|
|
||||||
alt sc {
|
alt sc {
|
||||||
scope_fn(_, ast::proto_block., _) { some(true) }
|
scope_fn_expr(_, node_id, _) { some(node_id) }
|
||||||
scope_fn(_, ast::proto_send., _) { some(false) }
|
|
||||||
scope_fn(_, ast::proto_shared(_), _) { some(false) }
|
|
||||||
_ { none }
|
_ { none }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -823,7 +835,8 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope_fn(decl, _, ty_params) {
|
scope_bare_fn(decl, _, ty_params) |
|
||||||
|
scope_fn_expr(decl, _, ty_params) {
|
||||||
ret lookup_in_fn(name, decl, ty_params, ns);
|
ret lookup_in_fn(name, decl, ty_params, ns);
|
||||||
}
|
}
|
||||||
scope_loop(local) {
|
scope_loop(local) {
|
||||||
|
@ -887,7 +900,10 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
|
||||||
left_fn_level2 = true;
|
left_fn_level2 = true;
|
||||||
} else if ns == ns_value || ns == ns_type {
|
} else if ns == ns_value || ns == ns_type {
|
||||||
left_fn = scope_is_fn(hd);
|
left_fn = scope_is_fn(hd);
|
||||||
alt scope_closes(hd) { some(mut) { closing += [mut]; } _ { } }
|
alt scope_closes(hd) {
|
||||||
|
some(node_id) { closing += [node_id]; }
|
||||||
|
_ { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sc = *tl;
|
sc = *tl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3558,6 +3558,19 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
|
||||||
ret trans_closure::trans_expr_fn(
|
ret trans_closure::trans_expr_fn(
|
||||||
bcx, f, e.span, e.id, *cap_clause, dest);
|
bcx, f, e.span, e.id, *cap_clause, dest);
|
||||||
}
|
}
|
||||||
|
ast::expr_fn_block(decl, body) {
|
||||||
|
alt ty::struct(tcx, ty::expr_ty(tcx, e)) {
|
||||||
|
ty::ty_fn(proto, _, _, _, _) {
|
||||||
|
let f: ast::_fn = { decl: decl, proto: proto, body: body };
|
||||||
|
let cap_clause = { copies: [], moves: [] };
|
||||||
|
ret trans_closure::trans_expr_fn(
|
||||||
|
bcx, f, e.span, e.id, cap_clause, dest);
|
||||||
|
}
|
||||||
|
_ {
|
||||||
|
fail "Type of fn block is not a function!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::expr_bind(f, args) {
|
ast::expr_bind(f, args) {
|
||||||
ret trans_closure::trans_bind(
|
ret trans_closure::trans_bind(
|
||||||
bcx, f, args, e.id, dest);
|
bcx, f, args, e.id, dest);
|
||||||
|
|
|
@ -32,15 +32,14 @@ fn collect_ids_local(l: @local, rs: @mutable [node_id]) {
|
||||||
*rs += pat_binding_ids(l.node.pat);
|
*rs += pat_binding_ids(l.node.pat);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_ids_in_fn(f: _fn, tps: [ty_param], sp: span, i: fn_ident, id: node_id,
|
fn node_ids_in_fn(body: blk, rs: @mutable [node_id]) {
|
||||||
rs: @mutable [node_id]) {
|
|
||||||
let collect_ids =
|
let collect_ids =
|
||||||
visit::mk_simple_visitor(@{visit_expr: bind collect_ids_expr(_, rs),
|
visit::mk_simple_visitor(@{visit_expr: bind collect_ids_expr(_, rs),
|
||||||
visit_block: bind collect_ids_block(_, rs),
|
visit_block: bind collect_ids_block(_, rs),
|
||||||
visit_stmt: bind collect_ids_stmt(_, rs),
|
visit_stmt: bind collect_ids_stmt(_, rs),
|
||||||
visit_local: bind collect_ids_local(_, rs)
|
visit_local: bind collect_ids_local(_, rs)
|
||||||
with *visit::default_simple_visitor()});
|
with *visit::default_simple_visitor()});
|
||||||
visit::visit_fn(f, tps, sp, i, id, (), collect_ids);
|
collect_ids.visit_block(body, (), collect_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) {
|
fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) {
|
||||||
|
@ -50,25 +49,24 @@ fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn(ccx: crate_ctxt, num_constraints: uint, f: _fn, tps: [ty_param],
|
fn visit_fn(ccx: crate_ctxt, num_constraints: uint, body: blk) {
|
||||||
sp: span, i: fn_ident, id: node_id) {
|
|
||||||
let node_ids: @mutable [node_id] = @mutable [];
|
let node_ids: @mutable [node_id] = @mutable [];
|
||||||
node_ids_in_fn(f, tps, sp, i, id, node_ids);
|
node_ids_in_fn(body, node_ids);
|
||||||
let node_id_vec = *node_ids;
|
let node_id_vec = *node_ids;
|
||||||
init_vecs(ccx, node_id_vec, num_constraints);
|
init_vecs(ccx, node_id_vec, num_constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn annotate_in_fn(ccx: crate_ctxt, f: _fn, tps: [ty_param], sp: span,
|
fn annotate_in_fn_body(ccx: crate_ctxt, _decl: fn_decl, body: blk,
|
||||||
i: fn_ident, id: node_id) {
|
_sp: span, _n: fn_ident, id: node_id) {
|
||||||
let f_info = get_fn_info(ccx, id);
|
let f_info = get_fn_info(ccx, id);
|
||||||
visit_fn(ccx, num_constraints(f_info), f, tps, sp, i, id);
|
visit_fn(ccx, num_constraints(f_info), body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn annotate_crate(ccx: crate_ctxt, crate: crate) {
|
fn annotate_crate(ccx: crate_ctxt, crate: crate) {
|
||||||
let do_ann =
|
let do_ann =
|
||||||
visit::mk_simple_visitor(@{visit_fn:
|
visit::mk_simple_visitor(
|
||||||
bind annotate_in_fn(ccx, _, _, _, _, _)
|
@{visit_fn_body: bind annotate_in_fn_body(ccx, _, _, _, _, _)
|
||||||
with *visit::default_simple_visitor()});
|
with *visit::default_simple_visitor()});
|
||||||
visit::visit_crate(crate, (), do_ann);
|
visit::visit_crate(crate, (), do_ann);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
|
@ -1003,8 +1003,9 @@ fn op_to_oper_ty(io: init_op) -> oper_type {
|
||||||
}
|
}
|
||||||
|
|
||||||
// default function visitor
|
// default function visitor
|
||||||
fn do_nothing<T>(_f: _fn, _tp: [ty_param], _sp: span, _i: fn_ident,
|
fn do_nothing<T>(_decl: fn_decl, _body: blk,
|
||||||
_iid: node_id, _cx: T, _v: visit::vt<T>) {
|
_sp: span, _i: fn_ident, _id: node_id,
|
||||||
|
_t: T, _v: visit::vt<T>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ fn relax_precond_block(fcx: fn_ctxt, i: node_id, b: blk) {
|
||||||
visit_stmt: relax_precond_stmt,
|
visit_stmt: relax_precond_stmt,
|
||||||
visit_item:
|
visit_item:
|
||||||
fn (_i: @item, _cx: relax_ctxt, _vt: visit::vt<relax_ctxt>) { },
|
fn (_i: @item, _cx: relax_ctxt, _vt: visit::vt<relax_ctxt>) { },
|
||||||
visit_fn: bind do_nothing(_, _, _, _, _, _, _)
|
visit_fn_body: bind do_nothing(_, _, _, _, _, _, _)
|
||||||
with *visitor};
|
with *visitor};
|
||||||
let v1 = visit::mk_vt(visitor);
|
let v1 = visit::mk_vt(visitor);
|
||||||
v1.visit_block(b, cx, v1);
|
v1.visit_block(b, cx, v1);
|
||||||
|
|
|
@ -95,45 +95,47 @@ fn check_states_stmt(s: @stmt, fcx: fn_ctxt, v: visit::vt<fn_ctxt>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_states_against_conditions(fcx: fn_ctxt, f: _fn, tps: [ast::ty_param],
|
fn check_states_against_conditions(fcx: fn_ctxt,
|
||||||
id: node_id, sp: span, i: fn_ident) {
|
f_decl: ast::fn_decl,
|
||||||
|
f_body: ast::blk,
|
||||||
|
sp: span,
|
||||||
|
nm: fn_ident,
|
||||||
|
id: node_id) {
|
||||||
/* Postorder traversal instead of pre is important
|
/* Postorder traversal instead of pre is important
|
||||||
because we want the smallest possible erroneous statement
|
because we want the smallest possible erroneous statement
|
||||||
or expression. */
|
or expression. */
|
||||||
|
|
||||||
let visitor = visit::default_visitor::<fn_ctxt>();
|
let visitor = visit::mk_vt(
|
||||||
|
|
||||||
visitor =
|
|
||||||
@{visit_stmt: check_states_stmt,
|
@{visit_stmt: check_states_stmt,
|
||||||
visit_expr: check_states_expr,
|
visit_expr: check_states_expr,
|
||||||
visit_fn: bind do_nothing(_, _, _, _, _, _, _)
|
visit_fn_body: bind do_nothing::<fn_ctxt>(_, _, _, _, _, _, _)
|
||||||
with *visitor};
|
with *visit::default_visitor::<fn_ctxt>()});
|
||||||
visit::visit_fn(f, tps, sp, i, id, fcx, visit::mk_vt(visitor));
|
visit::visit_fn_body(f_decl, f_body, sp, nm, id, fcx, visitor);
|
||||||
|
|
||||||
/* Check that the return value is initialized */
|
/* Check that the return value is initialized */
|
||||||
let post = aux::block_poststate(fcx.ccx, f.body);
|
let post = aux::block_poststate(fcx.ccx, f_body);
|
||||||
if !promises(fcx, post, fcx.enclosing.i_return) &&
|
if !promises(fcx, post, fcx.enclosing.i_return) &&
|
||||||
!type_is_nil(fcx.ccx.tcx, ret_ty_of_fn(fcx.ccx.tcx, id)) &&
|
!type_is_nil(fcx.ccx.tcx, ret_ty_of_fn(fcx.ccx.tcx, id)) &&
|
||||||
f.decl.cf == return_val {
|
f_decl.cf == return_val {
|
||||||
fcx.ccx.tcx.sess.span_err(f.body.span,
|
fcx.ccx.tcx.sess.span_err(f_body.span,
|
||||||
"In function " + fcx.name +
|
"In function " + fcx.name +
|
||||||
", not all control paths \
|
", not all control paths \
|
||||||
return a value");
|
return a value");
|
||||||
fcx.ccx.tcx.sess.span_fatal(f.decl.output.span,
|
fcx.ccx.tcx.sess.span_fatal(f_decl.output.span,
|
||||||
"see declared return type of '" +
|
"see declared return type of '" +
|
||||||
ty_to_str(f.decl.output) + "'");
|
ty_to_str(f_decl.output) + "'");
|
||||||
} else if f.decl.cf == noreturn {
|
} else if f_decl.cf == noreturn {
|
||||||
|
|
||||||
// check that this really always fails
|
// check that this really always fails
|
||||||
// Note that it's ok for i_diverge and i_return to both be true.
|
// Note that it's ok for i_diverge and i_return to both be true.
|
||||||
// In fact, i_diverge implies i_return. (But not vice versa!)
|
// In fact, i_diverge implies i_return. (But not vice versa!)
|
||||||
|
|
||||||
if !promises(fcx, post, fcx.enclosing.i_diverge) {
|
if !promises(fcx, post, fcx.enclosing.i_diverge) {
|
||||||
fcx.ccx.tcx.sess.span_fatal(f.body.span,
|
fcx.ccx.tcx.sess.span_fatal(f_body.span,
|
||||||
"In non-returning function " +
|
"In non-returning function " +
|
||||||
fcx.name +
|
fcx.name +
|
||||||
", some control paths may \
|
", some control paths may \
|
||||||
return to the caller");
|
return to the caller");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,29 +143,34 @@ fn check_states_against_conditions(fcx: fn_ctxt, f: _fn, tps: [ast::ty_param],
|
||||||
check_unused_vars(fcx);
|
check_unused_vars(fcx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fn_states(fcx: fn_ctxt, f: _fn, tps: [ast::ty_param], id: node_id,
|
fn check_fn_states(fcx: fn_ctxt,
|
||||||
sp: span, i: fn_ident) {
|
f_decl: ast::fn_decl,
|
||||||
|
f_body: ast::blk,
|
||||||
|
sp: span,
|
||||||
|
nm: fn_ident,
|
||||||
|
id: node_id) {
|
||||||
/* Compute the pre- and post-states for this function */
|
/* Compute the pre- and post-states for this function */
|
||||||
|
|
||||||
// Fixpoint iteration
|
// Fixpoint iteration
|
||||||
while find_pre_post_state_fn(fcx, f) { }
|
while find_pre_post_state_fn(fcx, f_decl, f_body) { }
|
||||||
|
|
||||||
/* Now compare each expr's pre-state to its precondition
|
/* Now compare each expr's pre-state to its precondition
|
||||||
and post-state to its postcondition */
|
and post-state to its postcondition */
|
||||||
|
|
||||||
check_states_against_conditions(fcx, f, tps, id, sp, i);
|
check_states_against_conditions(fcx, f_decl, f_body, sp, nm, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_states(f: _fn, tps: [ast::ty_param], sp: span, i: fn_ident, id: node_id,
|
fn fn_states(f_decl: ast::fn_decl, f_body: ast::blk,
|
||||||
|
sp: span, i: ast::fn_ident, id: node_id,
|
||||||
ccx: crate_ctxt, v: visit::vt<crate_ctxt>) {
|
ccx: crate_ctxt, v: visit::vt<crate_ctxt>) {
|
||||||
visit::visit_fn(f, tps, sp, i, id, ccx, v);
|
visit::visit_fn_body(f_decl, f_body, sp, i, id, ccx, v);
|
||||||
/* Look up the var-to-bit-num map for this function */
|
/* Look up the var-to-bit-num map for this function */
|
||||||
|
|
||||||
assert (ccx.fm.contains_key(id));
|
assert (ccx.fm.contains_key(id));
|
||||||
let f_info = ccx.fm.get(id);
|
let f_info = ccx.fm.get(id);
|
||||||
let name = option::from_maybe("anon", i);
|
let name = option::from_maybe("anon", i); // XXXX
|
||||||
let fcx = {enclosing: f_info, id: id, name: name, ccx: ccx};
|
let fcx = {enclosing: f_info, id: id, name: name, ccx: ccx};
|
||||||
check_fn_states(fcx, f, tps, id, sp, i);
|
check_fn_states(fcx, f_decl, f_body, sp, i, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_crate(cx: ty::ctxt, crate: @crate) {
|
fn check_crate(cx: ty::ctxt, crate: @crate) {
|
||||||
|
@ -177,12 +184,13 @@ fn check_crate(cx: ty::ctxt, crate: @crate) {
|
||||||
/* Compute the pre and postcondition for every subexpression */
|
/* Compute the pre and postcondition for every subexpression */
|
||||||
|
|
||||||
let vtor = visit::default_visitor::<crate_ctxt>();
|
let vtor = visit::default_visitor::<crate_ctxt>();
|
||||||
vtor = @{visit_fn: fn_pre_post with *vtor};
|
vtor = @{visit_fn_body: fn_pre_post with *vtor};
|
||||||
visit::visit_crate(*crate, ccx, visit::mk_vt(vtor));
|
visit::visit_crate(*crate, ccx, visit::mk_vt(vtor));
|
||||||
|
|
||||||
/* Check the pre- and postcondition against the pre- and poststate
|
/* Check the pre- and postcondition against the pre- and poststate
|
||||||
for every expression */
|
for every expression */
|
||||||
vtor = @{visit_fn: fn_states with *vtor};
|
let vtor = visit::default_visitor::<crate_ctxt>();
|
||||||
|
vtor = @{visit_fn_body: fn_states with *vtor};
|
||||||
visit::visit_crate(*crate, ccx, visit::mk_vt(vtor));
|
visit::visit_crate(*crate, ccx, visit::mk_vt(vtor));
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
|
@ -44,7 +44,11 @@ fn collect_pred(e: @expr, cx: ctxt, v: visit::vt<ctxt>) {
|
||||||
visit::visit_expr(e, cx, v);
|
visit::visit_expr(e, cx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_locals(tcx: ty::ctxt, f: _fn, tps: [ty_param], sp: span, i: fn_ident,
|
fn find_locals(tcx: ty::ctxt,
|
||||||
|
f_decl: fn_decl,
|
||||||
|
f_body: blk,
|
||||||
|
sp: span,
|
||||||
|
n: fn_ident,
|
||||||
id: node_id) -> ctxt {
|
id: node_id) -> ctxt {
|
||||||
let cx: ctxt = {cs: @mutable [], tcx: tcx};
|
let cx: ctxt = {cs: @mutable [], tcx: tcx};
|
||||||
let visitor = visit::default_visitor::<ctxt>();
|
let visitor = visit::default_visitor::<ctxt>();
|
||||||
|
@ -52,9 +56,10 @@ fn find_locals(tcx: ty::ctxt, f: _fn, tps: [ty_param], sp: span, i: fn_ident,
|
||||||
visitor =
|
visitor =
|
||||||
@{visit_local: collect_local,
|
@{visit_local: collect_local,
|
||||||
visit_expr: collect_pred,
|
visit_expr: collect_pred,
|
||||||
visit_fn: bind do_nothing(_, _, _, _, _, _, _)
|
visit_fn_body: bind do_nothing(_, _, _, _, _, _, _)
|
||||||
with *visitor};
|
with *visitor};
|
||||||
visit::visit_fn(f, tps, sp, i, id, cx, visit::mk_vt(visitor));
|
visit::visit_fn_body(f_decl, f_body, sp,
|
||||||
|
n, id, cx, visit::mk_vt(visitor));
|
||||||
ret cx;
|
ret cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,13 +95,17 @@ fn add_constraint(tcx: ty::ctxt, c: sp_constr, next: uint, tbl: constr_map) ->
|
||||||
|
|
||||||
/* builds a table mapping each local var defined in f
|
/* builds a table mapping each local var defined in f
|
||||||
to a bit number in the precondition/postcondition vectors */
|
to a bit number in the precondition/postcondition vectors */
|
||||||
fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span,
|
fn mk_fn_info(ccx: crate_ctxt,
|
||||||
f_name: fn_ident, id: node_id) {
|
f_decl: fn_decl,
|
||||||
|
f_body: blk,
|
||||||
|
f_sp: span,
|
||||||
|
f_name: fn_ident,
|
||||||
|
id: node_id) {
|
||||||
let name = fn_ident_to_string(id, f_name);
|
let name = fn_ident_to_string(id, f_name);
|
||||||
let res_map = @new_def_hash::<constraint>();
|
let res_map = @new_def_hash::<constraint>();
|
||||||
let next: uint = 0u;
|
let next: uint = 0u;
|
||||||
|
|
||||||
let cx: ctxt = find_locals(ccx.tcx, f, tp, f_sp, f_name, id);
|
let cx: ctxt = find_locals(ccx.tcx, f_decl, f_body, f_sp, f_name, id);
|
||||||
/* now we have to add bit nums for both the constraints
|
/* now we have to add bit nums for both the constraints
|
||||||
and the variables... */
|
and the variables... */
|
||||||
|
|
||||||
|
@ -106,17 +115,19 @@ fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span,
|
||||||
/* if this function has any constraints, instantiate them to the
|
/* if this function has any constraints, instantiate them to the
|
||||||
argument names and add them */
|
argument names and add them */
|
||||||
let sc;
|
let sc;
|
||||||
for c: @constr in f.decl.constraints {
|
for c: @constr in f_decl.constraints {
|
||||||
sc = ast_constr_to_sp_constr(cx.tcx, f.decl.inputs, c);
|
sc = ast_constr_to_sp_constr(cx.tcx, f_decl.inputs, c);
|
||||||
next = add_constraint(cx.tcx, sc, next, res_map);
|
next = add_constraint(cx.tcx, sc, next, res_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to add constraints for args too, b/c they
|
/* Need to add constraints for args too, b/c they
|
||||||
can be deinitialized */
|
can be deinitialized */
|
||||||
for a: arg in f.decl.inputs {
|
for a: arg in f_decl.inputs {
|
||||||
next =
|
next = add_constraint(
|
||||||
add_constraint(cx.tcx, respan(f_sp, ninit(a.id, a.ident)), next,
|
cx.tcx,
|
||||||
res_map);
|
respan(f_sp, ninit(a.id, a.ident)),
|
||||||
|
next,
|
||||||
|
res_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add the special i_diverge and i_return constraints
|
/* add the special i_diverge and i_return constraints
|
||||||
|
@ -137,7 +148,7 @@ fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span,
|
||||||
let rslt =
|
let rslt =
|
||||||
{constrs: res_map,
|
{constrs: res_map,
|
||||||
num_constraints: next,
|
num_constraints: next,
|
||||||
cf: f.decl.cf,
|
cf: f_decl.cf,
|
||||||
i_return: ninit(id, name),
|
i_return: ninit(id, name),
|
||||||
i_diverge: ninit(diverges_id, diverges_name),
|
i_diverge: ninit(diverges_id, diverges_name),
|
||||||
used_vars: v};
|
used_vars: v};
|
||||||
|
@ -152,9 +163,9 @@ fn mk_fn_info(ccx: crate_ctxt, f: _fn, tp: [ty_param], f_sp: span,
|
||||||
to bit number) */
|
to bit number) */
|
||||||
fn mk_f_to_fn_info(ccx: crate_ctxt, c: @crate) {
|
fn mk_f_to_fn_info(ccx: crate_ctxt, c: @crate) {
|
||||||
let visitor =
|
let visitor =
|
||||||
visit::mk_simple_visitor(@{visit_fn:
|
visit::mk_simple_visitor(@{visit_fn_body:
|
||||||
bind mk_fn_info(ccx, _, _, _, _, _)
|
bind mk_fn_info(ccx, _, _, _, _, _)
|
||||||
with *visit::default_simple_visitor()});
|
with *visit::default_simple_visitor()});
|
||||||
visit::visit_crate(*c, (), visitor);
|
visit::visit_crate(*c, (), visitor);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
|
@ -33,7 +33,7 @@ fn find_pre_post_method(ccx: crate_ctxt, m: @method) {
|
||||||
id: m.node.id,
|
id: m.node.id,
|
||||||
name: m.node.ident,
|
name: m.node.ident,
|
||||||
ccx: ccx};
|
ccx: ccx};
|
||||||
find_pre_post_fn(fcx, m.node.meth);
|
find_pre_post_fn(fcx, m.node.meth.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_pre_post_item(ccx: crate_ctxt, i: item) {
|
fn find_pre_post_item(ccx: crate_ctxt, i: item) {
|
||||||
|
@ -60,7 +60,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
|
||||||
assert (ccx.fm.contains_key(i.id));
|
assert (ccx.fm.contains_key(i.id));
|
||||||
let fcx =
|
let fcx =
|
||||||
{enclosing: ccx.fm.get(i.id), id: i.id, name: i.ident, ccx: ccx};
|
{enclosing: ccx.fm.get(i.id), id: i.id, name: i.ident, ccx: ccx};
|
||||||
find_pre_post_fn(fcx, f);
|
find_pre_post_fn(fcx, f.body);
|
||||||
}
|
}
|
||||||
item_mod(m) { find_pre_post_mod(m); }
|
item_mod(m) { find_pre_post_mod(m); }
|
||||||
item_native_mod(nm) { find_pre_post_native_mod(nm); }
|
item_native_mod(nm) { find_pre_post_native_mod(nm); }
|
||||||
|
@ -72,7 +72,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
|
||||||
id: dtor_id,
|
id: dtor_id,
|
||||||
name: i.ident,
|
name: i.ident,
|
||||||
ccx: ccx};
|
ccx: ccx};
|
||||||
find_pre_post_fn(fcx, dtor);
|
find_pre_post_fn(fcx, dtor.body);
|
||||||
}
|
}
|
||||||
item_obj(o, _, _) {for m in o.methods { find_pre_post_method(ccx, m); }}
|
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); } }
|
item_impl(_, _, ms) { for m in ms { find_pre_post_method(ccx, m); } }
|
||||||
|
@ -298,6 +298,15 @@ fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [ty::mode],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_pre_post_expr_fn_upvars(fcx: fn_ctxt, e: @expr) {
|
||||||
|
let rslt = expr_pp(fcx.ccx, e);
|
||||||
|
clear_pp(rslt);
|
||||||
|
for def in *freevars::get_freevars(fcx.ccx.tcx, e.id) {
|
||||||
|
log ("handle_var_def: def=", def);
|
||||||
|
handle_var_def(fcx, rslt, def.def, "upvar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Fills in annotations as a side effect. Does not rebuild the expr */
|
/* Fills in annotations as a side effect. Does not rebuild the expr */
|
||||||
fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
||||||
let enclosing = fcx.enclosing;
|
let enclosing = fcx.enclosing;
|
||||||
|
@ -340,12 +349,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
||||||
copy_pre_post(fcx.ccx, e.id, arg);
|
copy_pre_post(fcx.ccx, e.id, arg);
|
||||||
}
|
}
|
||||||
expr_fn(f, cap_clause) {
|
expr_fn(f, cap_clause) {
|
||||||
let rslt = expr_pp(fcx.ccx, e);
|
find_pre_post_expr_fn_upvars(fcx, e);
|
||||||
clear_pp(rslt);
|
|
||||||
for def in *freevars::get_freevars(fcx.ccx.tcx, e.id) {
|
|
||||||
log ("handle_var_def: def=", def);
|
|
||||||
handle_var_def(fcx, rslt, def.def, "upvar");
|
|
||||||
}
|
|
||||||
|
|
||||||
let use_cap_item = lambda(&&cap_item: @capture_item) {
|
let use_cap_item = lambda(&&cap_item: @capture_item) {
|
||||||
let d = local_node_id_to_local_def_id(fcx, cap_item.id);
|
let d = local_node_id_to_local_def_id(fcx, cap_item.id);
|
||||||
|
@ -358,9 +362,9 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
||||||
log ("forget_in_postcond: ", cap_item);
|
log ("forget_in_postcond: ", cap_item);
|
||||||
forget_in_postcond(fcx, e.id, cap_item.id);
|
forget_in_postcond(fcx, e.id, cap_item.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let ann = node_id_to_ts_ann(fcx.ccx, e.id);
|
expr_fn_block(_, _) {
|
||||||
log_cond(tritv::to_vec(ann.conditions.postcondition));
|
find_pre_post_expr_fn_upvars(fcx, e);
|
||||||
}
|
}
|
||||||
expr_block(b) {
|
expr_block(b) {
|
||||||
find_pre_post_block(fcx, b);
|
find_pre_post_block(fcx, b);
|
||||||
|
@ -711,32 +715,33 @@ fn find_pre_post_block(fcx: fn_ctxt, b: blk) {
|
||||||
set_pre_and_post(fcx.ccx, b.node.id, block_precond, block_postcond);
|
set_pre_and_post(fcx.ccx, b.node.id, block_precond, block_postcond);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_pre_post_fn(fcx: fn_ctxt, f: _fn) {
|
fn find_pre_post_fn(fcx: fn_ctxt, body: blk) {
|
||||||
// hack
|
// hack
|
||||||
use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_return));
|
use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_return));
|
||||||
use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_diverge));
|
use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_diverge));
|
||||||
|
|
||||||
find_pre_post_block(fcx, f.body);
|
find_pre_post_block(fcx, body);
|
||||||
|
|
||||||
|
|
||||||
// Treat the tail expression as a return statement
|
// Treat the tail expression as a return statement
|
||||||
alt f.body.node.expr {
|
alt body.node.expr {
|
||||||
some(tailexpr) { set_postcond_false(fcx.ccx, tailexpr.id); }
|
some(tailexpr) { set_postcond_false(fcx.ccx, tailexpr.id); }
|
||||||
none. {/* fallthrough */ }
|
none. {/* fallthrough */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_pre_post(f: _fn, tps: [ty_param], sp: span, i: fn_ident, id: node_id,
|
fn fn_pre_post(decl: fn_decl, body: blk, sp: span,
|
||||||
|
i: fn_ident, id: node_id,
|
||||||
ccx: crate_ctxt, v: visit::vt<crate_ctxt>) {
|
ccx: crate_ctxt, v: visit::vt<crate_ctxt>) {
|
||||||
visit::visit_fn(f, tps, sp, i, id, ccx, v);
|
visit::visit_fn_body(decl, body, sp, i, id, ccx, v);
|
||||||
assert (ccx.fm.contains_key(id));
|
assert (ccx.fm.contains_key(id));
|
||||||
let fcx =
|
let fcx =
|
||||||
{enclosing: ccx.fm.get(id),
|
{enclosing: ccx.fm.get(id),
|
||||||
id: id,
|
id: id,
|
||||||
name: fn_ident_to_string(id, i),
|
name: fn_ident_to_string(id, i),
|
||||||
ccx: ccx};
|
ccx: ccx};
|
||||||
find_pre_post_fn(fcx, f);
|
find_pre_post_fn(fcx, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
|
|
|
@ -374,6 +374,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
|
||||||
expr_fn(_, cap_clause) {
|
expr_fn(_, cap_clause) {
|
||||||
ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause);
|
ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause);
|
||||||
}
|
}
|
||||||
|
expr_fn_block(_, _) { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||||
expr_block(b) {
|
expr_block(b) {
|
||||||
ret find_pre_post_state_block(fcx, pres, b) |
|
ret find_pre_post_state_block(fcx, pres, b) |
|
||||||
set_prestate_ann(fcx.ccx, e.id, pres) |
|
set_prestate_ann(fcx.ccx, e.id, pres) |
|
||||||
|
@ -732,28 +733,30 @@ fn find_pre_post_state_block(fcx: fn_ctxt, pres0: prestate, b: blk) -> bool {
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_pre_post_state_fn(fcx: fn_ctxt, f: _fn) -> bool {
|
fn find_pre_post_state_fn(fcx: fn_ctxt,
|
||||||
|
f_decl: fn_decl,
|
||||||
|
f_body: blk) -> bool {
|
||||||
let num_constrs = num_constraints(fcx.enclosing);
|
let num_constrs = num_constraints(fcx.enclosing);
|
||||||
// All constraints are considered false until proven otherwise.
|
// All constraints are considered false until proven otherwise.
|
||||||
// This ensures that intersect works correctly.
|
// This ensures that intersect works correctly.
|
||||||
kill_all_prestate(fcx, f.body.node.id);
|
kill_all_prestate(fcx, f_body.node.id);
|
||||||
|
|
||||||
// Arguments start out initialized
|
// Arguments start out initialized
|
||||||
let block_pre = block_prestate(fcx.ccx, f.body);
|
let block_pre = block_prestate(fcx.ccx, f_body);
|
||||||
for a: arg in f.decl.inputs {
|
for a: arg in f_decl.inputs {
|
||||||
set_in_prestate_constr(fcx, ninit(a.id, a.ident), block_pre);
|
set_in_prestate_constr(fcx, ninit(a.id, a.ident), block_pre);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate any constraints on the arguments so we can use them
|
// Instantiate any constraints on the arguments so we can use them
|
||||||
for c: @constr in f.decl.constraints {
|
for c: @constr in f_decl.constraints {
|
||||||
let tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f.decl.inputs, c);
|
let tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f_decl.inputs, c);
|
||||||
set_in_prestate_constr(fcx, tsc, block_pre);
|
set_in_prestate_constr(fcx, tsc, block_pre);
|
||||||
}
|
}
|
||||||
|
|
||||||
let changed = find_pre_post_state_block(fcx, block_pre, f.body);
|
let changed = find_pre_post_state_block(fcx, block_pre, f_body);
|
||||||
|
|
||||||
// Treat the tail expression as a return statement
|
// Treat the tail expression as a return statement
|
||||||
alt f.body.node.expr {
|
alt f_body.node.expr {
|
||||||
some(tailexpr) {
|
some(tailexpr) {
|
||||||
|
|
||||||
// We don't want to clear the diverges bit for bottom typed things,
|
// We don't want to clear the diverges bit for bottom typed things,
|
||||||
|
@ -763,7 +766,7 @@ fn find_pre_post_state_fn(fcx: fn_ctxt, f: _fn) -> bool {
|
||||||
let post = false_postcond(num_constrs);
|
let post = false_postcond(num_constrs);
|
||||||
// except for the "diverges" bit...
|
// except for the "diverges" bit...
|
||||||
kill_poststate_(fcx, fcx.enclosing.i_diverge, post);
|
kill_poststate_(fcx, fcx.enclosing.i_diverge, post);
|
||||||
set_poststate_ann(fcx.ccx, f.body.node.id, post);
|
set_poststate_ann(fcx.ccx, f_body.node.id, post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
none. {/* fallthrough */ }
|
none. {/* fallthrough */ }
|
||||||
|
@ -772,7 +775,7 @@ fn find_pre_post_state_fn(fcx: fn_ctxt, f: _fn) -> bool {
|
||||||
/*
|
/*
|
||||||
log_err "find_pre_post_state_fn";
|
log_err "find_pre_post_state_fn";
|
||||||
log_err changed;
|
log_err changed;
|
||||||
fcx.ccx.tcx.sess.span_note(f.body.span, fcx.name);
|
fcx.ccx.tcx.sess.span_note(f_body.span, fcx.name);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret changed;
|
ret changed;
|
||||||
|
|
|
@ -999,8 +999,9 @@ mod writeback {
|
||||||
if !wbcx.success { ret; }
|
if !wbcx.success { ret; }
|
||||||
resolve_type_vars_for_node(wbcx, e.span, e.id);
|
resolve_type_vars_for_node(wbcx, e.span, e.id);
|
||||||
alt e.node {
|
alt e.node {
|
||||||
ast::expr_fn(f, _) { // NDM captures?
|
ast::expr_fn({decl: decl, _}, _) |
|
||||||
for input in f.decl.inputs {
|
ast::expr_fn_block(decl, _) {
|
||||||
|
for input in decl.inputs {
|
||||||
resolve_type_vars_for_node(wbcx, e.span, input.id);
|
resolve_type_vars_for_node(wbcx, e.span, input.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1077,7 +1078,10 @@ type gather_result =
|
||||||
next_var_id: @mutable int};
|
next_var_id: @mutable int};
|
||||||
|
|
||||||
// Used only as a helper for check_fn.
|
// Used only as a helper for check_fn.
|
||||||
fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
fn gather_locals(ccx: @crate_ctxt,
|
||||||
|
decl: ast::fn_decl,
|
||||||
|
body: ast::blk,
|
||||||
|
id: ast::node_id,
|
||||||
old_fcx: option::t<@fn_ctxt>) -> gather_result {
|
old_fcx: option::t<@fn_ctxt>) -> gather_result {
|
||||||
let {vb: vb, locals: locals, nvi: nvi} =
|
let {vb: vb, locals: locals, nvi: nvi} =
|
||||||
alt old_fcx {
|
alt old_fcx {
|
||||||
|
@ -1121,7 +1125,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
||||||
let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
|
let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
|
||||||
let i = 0u;
|
let i = 0u;
|
||||||
for arg: ty::arg in args {
|
for arg: ty::arg in args {
|
||||||
assign(f.decl.inputs[i].id, some(arg.ty));
|
assign(decl.inputs[i].id, some(arg.ty));
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,20 +1148,20 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't descend into fns and items
|
// Don't descend into fns and items
|
||||||
fn visit_fn<E>(_f: ast::_fn, _tp: [ast::ty_param], _sp: span,
|
fn visit_fn_body<T>(_decl: ast::fn_decl, _body: ast::blk,
|
||||||
_i: ast::fn_ident, _id: ast::node_id, _e: E,
|
_sp: span, _nm: ast::fn_ident, _id: ast::node_id,
|
||||||
_v: visit::vt<E>) {
|
_t: T, _v: visit::vt<T>) {
|
||||||
}
|
}
|
||||||
fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { }
|
fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { }
|
||||||
|
|
||||||
let visit =
|
let visit =
|
||||||
@{visit_local: visit_local,
|
@{visit_local: visit_local,
|
||||||
visit_pat: visit_pat,
|
visit_pat: visit_pat,
|
||||||
visit_fn: bind visit_fn(_, _, _, _, _, _, _),
|
visit_fn_body: bind visit_fn_body(_, _, _, _, _, _, _),
|
||||||
visit_item: bind visit_item(_, _, _)
|
visit_item: bind visit_item(_, _, _)
|
||||||
with *visit::default_visitor()};
|
with *visit::default_visitor()};
|
||||||
|
|
||||||
visit::visit_block(f.body, (), visit::mk_vt(visit));
|
visit::visit_block(body, (), visit::mk_vt(visit));
|
||||||
ret {var_bindings: vb,
|
ret {var_bindings: vb,
|
||||||
locals: locals,
|
locals: locals,
|
||||||
next_var_id: nvi};
|
next_var_id: nvi};
|
||||||
|
@ -1496,6 +1500,32 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
|
||||||
|
expr: @ast::expr,
|
||||||
|
decl: ast::fn_decl,
|
||||||
|
proto: ast::proto,
|
||||||
|
body: ast::blk,
|
||||||
|
unify: unifier,
|
||||||
|
expected: ty::t) {
|
||||||
|
let tcx = fcx.ccx.tcx;
|
||||||
|
|
||||||
|
let fty = ty_of_fn_decl(tcx, m_check_tyvar(fcx), decl,
|
||||||
|
proto, [], none).ty;
|
||||||
|
|
||||||
|
write::ty_only_fixup(fcx, expr.id, fty);
|
||||||
|
|
||||||
|
// Unify the type of the function with the expected type before we
|
||||||
|
// typecheck the body so that we have more information about the
|
||||||
|
// argument types in the body. This is needed to make binops and
|
||||||
|
// record projection work on type inferred arguments.
|
||||||
|
unify(fcx, expr.span, expected, fty);
|
||||||
|
|
||||||
|
check_fn1(fcx.ccx, decl, proto, body, expr.id, some(fcx));
|
||||||
|
if proto == ast::proto_block {
|
||||||
|
write::ty_only_fixup(fcx, expr.id, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||||
expected: ty::t) -> bool {
|
expected: ty::t) -> bool {
|
||||||
//log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr);
|
//log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr);
|
||||||
|
@ -1563,7 +1593,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||||
some(a) {
|
some(a) {
|
||||||
let is_block =
|
let is_block =
|
||||||
alt a.node {
|
alt a.node {
|
||||||
ast::expr_fn(_, _) { true }
|
ast::expr_fn_block(_, _) { true }
|
||||||
_ { false }
|
_ { false }
|
||||||
};
|
};
|
||||||
if is_block == check_blocks {
|
if is_block == check_blocks {
|
||||||
|
@ -1940,24 +1970,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||||
write::ty_only_fixup(fcx, id, result_ty);
|
write::ty_only_fixup(fcx, id, result_ty);
|
||||||
}
|
}
|
||||||
ast::expr_fn(f, captures) {
|
ast::expr_fn(f, captures) {
|
||||||
let fty = ty_of_fn_decl(tcx, m_check_tyvar(fcx), f.decl,
|
check_expr_fn_with_unifier(fcx, expr, f.decl,
|
||||||
f.proto, [], none).ty;
|
f.proto, f.body,
|
||||||
|
unify, expected);
|
||||||
write::ty_only_fixup(fcx, id, fty);
|
|
||||||
|
|
||||||
// Unify the type of the function with the expected type before we
|
|
||||||
// typecheck the body so that we have more information about the
|
|
||||||
// argument types in the body. This is needed to make binops and
|
|
||||||
// record projection work on type inferred arguments.
|
|
||||||
unify(fcx, expr.span, expected, fty);
|
|
||||||
|
|
||||||
check_fn(fcx.ccx, f, id, some(fcx));
|
|
||||||
if f.proto == ast::proto_block {
|
|
||||||
write::ty_only_fixup(fcx, id, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
capture::check_capture_clause(tcx, expr.id, f.proto, *captures);
|
capture::check_capture_clause(tcx, expr.id, f.proto, *captures);
|
||||||
}
|
}
|
||||||
|
ast::expr_fn_block(decl, body) {
|
||||||
|
// Take the prototype from the expected type, but default to block:
|
||||||
|
let proto = alt ty::struct(tcx, expected) {
|
||||||
|
ty::ty_fn(proto, _, _, _, _) { proto }
|
||||||
|
_ { ast::proto_block }
|
||||||
|
};
|
||||||
|
check_expr_fn_with_unifier(fcx, expr, decl,
|
||||||
|
proto, body,
|
||||||
|
unify, expected);
|
||||||
|
}
|
||||||
ast::expr_block(b) {
|
ast::expr_block(b) {
|
||||||
// If this is an unchecked block, turn off purity-checking
|
// If this is an unchecked block, turn off purity-checking
|
||||||
bot = check_block(fcx, b);
|
bot = check_block(fcx, b);
|
||||||
|
@ -2581,12 +2608,19 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
fn check_fn(ccx: @crate_ctxt,
|
||||||
|
f: ast::_fn,
|
||||||
|
id: ast::node_id,
|
||||||
old_fcx: option::t<@fn_ctxt>) {
|
old_fcx: option::t<@fn_ctxt>) {
|
||||||
|
check_fn1(ccx, f.decl, f.proto, f.body, id, old_fcx);
|
||||||
|
}
|
||||||
|
|
||||||
let decl = f.decl;
|
fn check_fn1(ccx: @crate_ctxt,
|
||||||
let body = f.body;
|
decl: ast::fn_decl,
|
||||||
|
proto: ast::proto,
|
||||||
|
body: ast::blk,
|
||||||
|
id: ast::node_id,
|
||||||
|
old_fcx: option::t<@fn_ctxt>) {
|
||||||
// If old_fcx is some(...), this is a block fn { |x| ... }.
|
// If old_fcx is some(...), this is a block fn { |x| ... }.
|
||||||
// In that case, the purity is inherited from the context.
|
// In that case, the purity is inherited from the context.
|
||||||
let purity = alt old_fcx {
|
let purity = alt old_fcx {
|
||||||
|
@ -2594,12 +2628,12 @@ fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
||||||
some(f) { assert decl.purity == ast::impure_fn; f.purity }
|
some(f) { assert decl.purity == ast::impure_fn; f.purity }
|
||||||
};
|
};
|
||||||
|
|
||||||
let gather_result = gather_locals(ccx, f, id, old_fcx);
|
let gather_result = gather_locals(ccx, decl, body, id, old_fcx);
|
||||||
let fixups: [ast::node_id] = [];
|
let fixups: [ast::node_id] = [];
|
||||||
let fcx: @fn_ctxt =
|
let fcx: @fn_ctxt =
|
||||||
@{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
|
@{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
|
||||||
purity: purity,
|
purity: purity,
|
||||||
proto: f.proto,
|
proto: proto,
|
||||||
var_bindings: gather_result.var_bindings,
|
var_bindings: gather_result.var_bindings,
|
||||||
locals: gather_result.locals,
|
locals: gather_result.locals,
|
||||||
next_var_id: gather_result.next_var_id,
|
next_var_id: gather_result.next_var_id,
|
||||||
|
@ -2622,7 +2656,7 @@ fn check_fn(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id,
|
||||||
let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
|
let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
|
||||||
let i = 0u;
|
let i = 0u;
|
||||||
for arg: ty::arg in args {
|
for arg: ty::arg in args {
|
||||||
write::ty_only_fixup(fcx, f.decl.inputs[i].id, arg.ty);
|
write::ty_only_fixup(fcx, decl.inputs[i].id, arg.ty);
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ tag def {
|
||||||
def_use(def_id);
|
def_use(def_id);
|
||||||
def_native_ty(def_id);
|
def_native_ty(def_id);
|
||||||
def_native_fn(def_id, purity);
|
def_native_fn(def_id, purity);
|
||||||
def_upvar(def_id, @def, /* writable */bool);
|
def_upvar(def_id, @def, node_id); // node_id == expr_fn or expr_fn_block
|
||||||
}
|
}
|
||||||
|
|
||||||
// The set of meta_items that define the compilation environment of the crate,
|
// The set of meta_items that define the compilation environment of the crate,
|
||||||
|
@ -227,6 +227,7 @@ tag expr_ {
|
||||||
expr_do_while(blk, @expr);
|
expr_do_while(blk, @expr);
|
||||||
expr_alt(@expr, [arm]);
|
expr_alt(@expr, [arm]);
|
||||||
expr_fn(_fn, @capture_clause);
|
expr_fn(_fn, @capture_clause);
|
||||||
|
expr_fn_block(fn_decl, blk);
|
||||||
expr_block(blk);
|
expr_block(blk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -261,10 +262,6 @@ tag expr_ {
|
||||||
expr_mac(mac);
|
expr_mac(mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AST nodes that represent a capture clause, which is used to declare
|
|
||||||
// variables that are copied or moved explicitly into the closure. In some
|
|
||||||
// cases, local variables can also be copied implicitly into the closure if
|
|
||||||
// they are used in the closure body.
|
|
||||||
type capture_item = {
|
type capture_item = {
|
||||||
id: int,
|
id: int,
|
||||||
name: ident, // Currently, can only capture a local var.
|
name: ident, // Currently, can only capture a local var.
|
||||||
|
|
|
@ -145,6 +145,14 @@ fn fold_mac_(m: mac, fld: ast_fold) -> mac {
|
||||||
span: m.span};
|
span: m.span};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl {
|
||||||
|
ret {inputs: vec::map(decl.inputs, bind fold_arg_(_, fld)),
|
||||||
|
output: fld.fold_ty(decl.output),
|
||||||
|
purity: decl.purity,
|
||||||
|
il: decl.il,
|
||||||
|
cf: decl.cf,
|
||||||
|
constraints: vec::map(decl.constraints, fld.fold_constr)}
|
||||||
|
}
|
||||||
|
|
||||||
fn noop_fold_crate(c: crate_, fld: ast_fold) -> crate_ {
|
fn noop_fold_crate(c: crate_, fld: ast_fold) -> crate_ {
|
||||||
let fold_meta_item = bind fold_meta_item_(_, fld);
|
let fold_meta_item = bind fold_meta_item_(_, fld);
|
||||||
|
@ -385,8 +393,10 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
|
||||||
expr_alt(expr, arms) {
|
expr_alt(expr, arms) {
|
||||||
expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm))
|
expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm))
|
||||||
}
|
}
|
||||||
// NDM fold_captures
|
|
||||||
expr_fn(f, captures) { expr_fn(fld.fold_fn(f), captures) }
|
expr_fn(f, captures) { expr_fn(fld.fold_fn(f), captures) }
|
||||||
|
expr_fn_block(decl, body) {
|
||||||
|
expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body))
|
||||||
|
}
|
||||||
expr_block(blk) { expr_block(fld.fold_block(blk)) }
|
expr_block(blk) { expr_block(fld.fold_block(blk)) }
|
||||||
expr_move(el, er) {
|
expr_move(el, er) {
|
||||||
expr_move(fld.fold_expr(el), fld.fold_expr(er))
|
expr_move(fld.fold_expr(el), fld.fold_expr(er))
|
||||||
|
@ -437,15 +447,7 @@ fn noop_fold_constr(c: constr_, fld: ast_fold) -> constr_ {
|
||||||
|
|
||||||
// functions just don't get spans, for some reason
|
// functions just don't get spans, for some reason
|
||||||
fn noop_fold_fn(f: _fn, fld: ast_fold) -> _fn {
|
fn noop_fold_fn(f: _fn, fld: ast_fold) -> _fn {
|
||||||
let fold_arg = bind fold_arg_(_, fld);
|
ret {decl: fold_fn_decl(f.decl, fld),
|
||||||
|
|
||||||
ret {decl:
|
|
||||||
{inputs: vec::map(f.decl.inputs, fold_arg),
|
|
||||||
output: fld.fold_ty(f.decl.output),
|
|
||||||
purity: f.decl.purity,
|
|
||||||
il: f.decl.il,
|
|
||||||
cf: f.decl.cf,
|
|
||||||
constraints: vec::map(f.decl.constraints, fld.fold_constr)},
|
|
||||||
proto: f.proto,
|
proto: f.proto,
|
||||||
body: fld.fold_block(f.body)};
|
body: fld.fold_block(f.body)};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1317,9 +1317,7 @@ fn parse_fn_block_expr(p: parser) -> @ast::expr {
|
||||||
let lo = p.get_last_lo_pos();
|
let lo = p.get_last_lo_pos();
|
||||||
let decl = parse_fn_block_decl(p);
|
let decl = parse_fn_block_decl(p);
|
||||||
let body = parse_block_tail(p, lo, ast::default_blk);
|
let body = parse_block_tail(p, lo, ast::default_blk);
|
||||||
let _fn = {decl: decl, proto: ast::proto_block, body: body};
|
ret mk_expr(p, lo, body.span.hi, ast::expr_fn_block(decl, body));
|
||||||
let captures = @{copies: [], moves: []};
|
|
||||||
ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn, captures));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_else_expr(p: parser) -> @ast::expr {
|
fn parse_else_expr(p: parser) -> @ast::expr {
|
||||||
|
|
|
@ -827,24 +827,19 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||||
bclose_(s, expr.span, alt_indent_unit);
|
bclose_(s, expr.span, alt_indent_unit);
|
||||||
}
|
}
|
||||||
ast::expr_fn(f, captures) { // NDM captures
|
ast::expr_fn(f, captures) { // NDM captures
|
||||||
|
head(s, proto_to_str(f.proto));
|
||||||
// If the return type is the magic ty_infer, then we need to
|
print_fn_args_and_ret(s, f.decl, []);
|
||||||
// pretty print as a lambda-block
|
space(s.s);
|
||||||
if f.decl.output.node == ast::ty_infer {
|
print_block(s, f.body);
|
||||||
// containing cbox, will be closed by print-block at }
|
}
|
||||||
cbox(s, indent_unit);
|
ast::expr_fn_block(decl, body) {
|
||||||
// head-box, will be closed by print-block at start
|
// containing cbox, will be closed by print-block at }
|
||||||
ibox(s, 0u);
|
cbox(s, indent_unit);
|
||||||
word(s.s, "{");
|
// head-box, will be closed by print-block at start
|
||||||
print_fn_block_args(s, f.decl);
|
ibox(s, 0u);
|
||||||
print_possibly_embedded_block(s, f.body, block_block_fn,
|
word(s.s, "{");
|
||||||
indent_unit);
|
print_fn_block_args(s, decl);
|
||||||
} else {
|
print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
|
||||||
head(s, proto_to_str(f.proto));
|
|
||||||
print_fn_args_and_ret(s, f.decl, []);
|
|
||||||
space(s.s);
|
|
||||||
print_block(s, f.body);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast::expr_block(blk) {
|
ast::expr_block(blk) {
|
||||||
// containing cbox, will be closed by print-block at }
|
// containing cbox, will be closed by print-block at }
|
||||||
|
|
|
@ -31,7 +31,15 @@ type visitor<E> =
|
||||||
visit_expr: fn@(@expr, E, vt<E>),
|
visit_expr: fn@(@expr, E, vt<E>),
|
||||||
visit_ty: fn@(@ty, E, vt<E>),
|
visit_ty: fn@(@ty, E, vt<E>),
|
||||||
visit_constr: fn@(@path, span, node_id, E, vt<E>),
|
visit_constr: fn@(@path, span, node_id, E, vt<E>),
|
||||||
visit_fn: fn@(_fn, [ty_param], span, fn_ident, node_id, E, vt<E>)};
|
|
||||||
|
// A function with a fully specified prototype:
|
||||||
|
visit_fn_proto: fn@(_fn, [ty_param], span, fn_ident, node_id, E, vt<E>),
|
||||||
|
|
||||||
|
// Function sugar like { || ... }:
|
||||||
|
visit_fn_block: fn@(fn_decl, blk, span, node_id, E, vt<E>),
|
||||||
|
|
||||||
|
// Invoked by both visit_fn_proto and visit_fn_block above.
|
||||||
|
visit_fn_body: fn@(fn_decl, blk, span, fn_ident, node_id, E, vt<E>)};
|
||||||
|
|
||||||
fn default_visitor<E>() -> visitor<E> {
|
fn default_visitor<E>() -> visitor<E> {
|
||||||
ret @{visit_mod: bind visit_mod::<E>(_, _, _, _),
|
ret @{visit_mod: bind visit_mod::<E>(_, _, _, _),
|
||||||
|
@ -47,7 +55,9 @@ fn default_visitor<E>() -> visitor<E> {
|
||||||
visit_expr: bind visit_expr::<E>(_, _, _),
|
visit_expr: bind visit_expr::<E>(_, _, _),
|
||||||
visit_ty: bind skip_ty::<E>(_, _, _),
|
visit_ty: bind skip_ty::<E>(_, _, _),
|
||||||
visit_constr: bind visit_constr::<E>(_, _, _, _, _),
|
visit_constr: bind visit_constr::<E>(_, _, _, _, _),
|
||||||
visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _)};
|
visit_fn_proto: bind visit_fn_proto::<E>(_, _, _, _, _, _, _),
|
||||||
|
visit_fn_block: bind visit_fn_block::<E>(_, _, _, _, _, _),
|
||||||
|
visit_fn_body: bind visit_fn_body::<E>(_, _, _, _, _, _, _)};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
|
fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
|
||||||
|
@ -83,7 +93,8 @@ fn visit_local<E>(loc: @local, e: E, v: vt<E>) {
|
||||||
fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
||||||
alt i.node {
|
alt i.node {
|
||||||
item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); }
|
item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); }
|
||||||
item_fn(f, tp) { v.visit_fn(f, tp, i.span, some(i.ident), i.id, e, v); }
|
item_fn(f, tp) { v.visit_fn_proto(f, tp, i.span,
|
||||||
|
some(i.ident), i.id, e, v); }
|
||||||
item_mod(m) { v.visit_mod(m, i.span, e, v); }
|
item_mod(m) { v.visit_mod(m, i.span, e, v); }
|
||||||
item_native_mod(nm) {
|
item_native_mod(nm) {
|
||||||
for vi: @view_item in nm.view_items { v.visit_view_item(vi, e, v); }
|
for vi: @view_item in nm.view_items { v.visit_view_item(vi, e, v); }
|
||||||
|
@ -91,7 +102,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
||||||
}
|
}
|
||||||
item_ty(t, _) { v.visit_ty(t, e, v); }
|
item_ty(t, _) { v.visit_ty(t, e, v); }
|
||||||
item_res(f, dtor_id, tps, _) {
|
item_res(f, dtor_id, tps, _) {
|
||||||
v.visit_fn(f, tps, i.span, some(i.ident), dtor_id, e, v);
|
v.visit_fn_proto(f, tps, i.span, some(i.ident), dtor_id, e, v);
|
||||||
}
|
}
|
||||||
item_tag(variants, _) {
|
item_tag(variants, _) {
|
||||||
for vr: variant in variants {
|
for vr: variant in variants {
|
||||||
|
@ -101,15 +112,15 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
||||||
item_obj(ob, _, _) {
|
item_obj(ob, _, _) {
|
||||||
for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
|
for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
|
||||||
for m: @method in ob.methods {
|
for m: @method in ob.methods {
|
||||||
v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
|
v.visit_fn_proto(m.node.meth, m.node.tps, m.span,
|
||||||
m.node.id, e, v);
|
some(m.node.ident), m.node.id, e, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item_impl(_, ty, methods) {
|
item_impl(_, ty, methods) {
|
||||||
visit_ty(ty, e, v);
|
visit_ty(ty, e, v);
|
||||||
for m in methods {
|
for m in methods {
|
||||||
v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
|
v.visit_fn_proto(m.node.meth, m.node.tps, m.span,
|
||||||
m.node.id, e, v);
|
some(m.node.ident), m.node.id, e, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,10 +204,21 @@ fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
|
||||||
v.visit_ty(fd.output, e, v);
|
v.visit_ty(fd.output, e, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn<E>(f: _fn, _tp: [ty_param], _sp: span, _i: fn_ident, _id: node_id,
|
fn visit_fn_proto<E>(f: _fn, _tp: [ty_param], sp: span, i: fn_ident,
|
||||||
e: E, v: vt<E>) {
|
id: node_id, e: E, v: vt<E>) {
|
||||||
visit_fn_decl(f.decl, e, v);
|
v.visit_fn_body(f.decl, f.body, sp, i, id, e, v);
|
||||||
v.visit_block(f.body, e, v);
|
}
|
||||||
|
|
||||||
|
fn visit_fn_block<E>(decl: fn_decl, body: blk, sp: span, id: node_id,
|
||||||
|
e: E, v: vt<E>) {
|
||||||
|
v.visit_fn_body(decl, body, sp, option::none, id, e, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_fn_body<E>(decl: fn_decl, body: blk, _sp: span,
|
||||||
|
_name: fn_ident, _id: node_id,
|
||||||
|
e: E, v: vt<E>) {
|
||||||
|
visit_fn_decl(decl, e, v);
|
||||||
|
v.visit_block(body, e, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block<E>(b: ast::blk, e: E, v: vt<E>) {
|
fn visit_block<E>(b: ast::blk, e: E, v: vt<E>) {
|
||||||
|
@ -284,8 +306,12 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||||
v.visit_expr(x, e, v);
|
v.visit_expr(x, e, v);
|
||||||
for a: arm in arms { v.visit_arm(a, e, v); }
|
for a: arm in arms { v.visit_arm(a, e, v); }
|
||||||
}
|
}
|
||||||
// NDM add visit routine?
|
expr_fn(f, captures) {
|
||||||
expr_fn(f, captures) { v.visit_fn(f, [], ex.span, none, ex.id, e, v); }
|
v.visit_fn_proto(f, [], ex.span, none, ex.id, e, v);
|
||||||
|
}
|
||||||
|
expr_fn_block(decl, body) {
|
||||||
|
v.visit_fn_block(decl, body, ex.span, ex.id, e, v);
|
||||||
|
}
|
||||||
expr_block(b) { v.visit_block(b, e, v); }
|
expr_block(b) { v.visit_block(b, e, v); }
|
||||||
expr_assign(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); }
|
expr_assign(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); }
|
||||||
expr_copy(a) { v.visit_expr(a, e, v); }
|
expr_copy(a) { v.visit_expr(a, e, v); }
|
||||||
|
@ -324,8 +350,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||||
some(ex) { v.visit_expr(ex, e, v); }
|
some(ex) { v.visit_expr(ex, e, v); }
|
||||||
}
|
}
|
||||||
for m: @method in anon_obj.methods {
|
for m: @method in anon_obj.methods {
|
||||||
v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
|
v.visit_fn_proto(m.node.meth, m.node.tps, m.span,
|
||||||
m.node.id, e, v);
|
some(m.node.ident), m.node.id, e, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr_mac(mac) { visit_mac(mac, e, v); }
|
expr_mac(mac) { visit_mac(mac, e, v); }
|
||||||
|
@ -357,7 +383,9 @@ type simple_visitor =
|
||||||
visit_expr: fn@(@expr),
|
visit_expr: fn@(@expr),
|
||||||
visit_ty: fn@(@ty),
|
visit_ty: fn@(@ty),
|
||||||
visit_constr: fn@(@path, span, node_id),
|
visit_constr: fn@(@path, span, node_id),
|
||||||
visit_fn: fn@(_fn, [ty_param], span, fn_ident, node_id)};
|
visit_fn_proto: fn@(_fn, [ty_param], span, fn_ident, node_id),
|
||||||
|
visit_fn_block: fn@(fn_decl, blk, span, node_id),
|
||||||
|
visit_fn_body: fn@(fn_decl, blk, span, fn_ident, node_id)};
|
||||||
|
|
||||||
fn simple_ignore_ty(_t: @ty) {}
|
fn simple_ignore_ty(_t: @ty) {}
|
||||||
|
|
||||||
|
@ -375,10 +403,15 @@ fn default_simple_visitor() -> simple_visitor {
|
||||||
visit_expr: fn(_e: @expr) { },
|
visit_expr: fn(_e: @expr) { },
|
||||||
visit_ty: simple_ignore_ty,
|
visit_ty: simple_ignore_ty,
|
||||||
visit_constr: fn(_p: @path, _sp: span, _id: node_id) { },
|
visit_constr: fn(_p: @path, _sp: span, _id: node_id) { },
|
||||||
visit_fn:
|
visit_fn_proto:
|
||||||
fn(_f: _fn, _tps: [ty_param], _sp: span, _ident: fn_ident,
|
fn(_f: _fn, _tps: [ty_param], _sp: span, _ident: fn_ident,
|
||||||
_id: node_id) {
|
_id: node_id) { },
|
||||||
}};
|
visit_fn_block:
|
||||||
|
fn(_f: fn_decl, _b: blk, _sp: span, _node_id: node_id) { },
|
||||||
|
visit_fn_body:
|
||||||
|
fn(_f: fn_decl, _b: blk, _sp: span,
|
||||||
|
_nm: fn_ident, _node_id: node_id) { }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
|
fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
|
||||||
|
@ -440,7 +473,21 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
|
||||||
tps: [ty_param], sp: span, ident: fn_ident, id: node_id, &&e: (),
|
tps: [ty_param], sp: span, ident: fn_ident, id: node_id, &&e: (),
|
||||||
v: vt<()>) {
|
v: vt<()>) {
|
||||||
f(ff, tps, sp, ident, id);
|
f(ff, tps, sp, ident, id);
|
||||||
visit_fn(ff, tps, sp, ident, id, e, v);
|
visit_fn_proto(ff, tps, sp, ident, id, e, v);
|
||||||
|
}
|
||||||
|
fn v_fn_block(f: fn@(fn_decl, blk, span, node_id),
|
||||||
|
fn_decl: fn_decl, blk: blk,
|
||||||
|
sp: span, node_id: node_id,
|
||||||
|
&&e: (), v: vt<()>) {
|
||||||
|
f(fn_decl, blk, sp, node_id);
|
||||||
|
visit_fn_block(fn_decl, blk, sp, node_id, e, v);
|
||||||
|
}
|
||||||
|
fn v_fn_body(f: fn@(fn_decl, blk, span, fn_ident, node_id),
|
||||||
|
fn_decl: fn_decl, blk: blk,
|
||||||
|
sp: span, name: fn_ident, node_id: node_id,
|
||||||
|
&&e: (), v: vt<()>) {
|
||||||
|
f(fn_decl, blk, sp, name, node_id);
|
||||||
|
visit_fn_body(fn_decl, blk, sp, name, node_id, e, v);
|
||||||
}
|
}
|
||||||
let visit_ty = if v.visit_ty == simple_ignore_ty {
|
let visit_ty = if v.visit_ty == simple_ignore_ty {
|
||||||
bind skip_ty(_, _, _)
|
bind skip_ty(_, _, _)
|
||||||
|
@ -461,7 +508,13 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
|
||||||
visit_expr: bind v_expr(v.visit_expr, _, _, _),
|
visit_expr: bind v_expr(v.visit_expr, _, _, _),
|
||||||
visit_ty: visit_ty,
|
visit_ty: visit_ty,
|
||||||
visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _),
|
visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _),
|
||||||
visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _)});
|
visit_fn_proto:
|
||||||
|
bind v_fn(v.visit_fn_proto, _, _, _, _, _, _, _),
|
||||||
|
visit_fn_block:
|
||||||
|
bind v_fn_block(v.visit_fn_block, _, _, _, _, _, _),
|
||||||
|
visit_fn_body:
|
||||||
|
bind v_fn_body(v.visit_fn_body, _, _, _, _, _, _, _),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue