Partially implement destructuring locals

You can now say

    let {bcx, val} = some_result_returner();

Similar for loop variables. Assigning to such variables is not safe
yet. Function arguments also remain a TODO.
This commit is contained in:
Marijn Haverbeke 2011-07-28 12:01:45 +02:00
parent 48ec25da42
commit 985c32ef4c
19 changed files with 308 additions and 250 deletions

View file

@ -298,10 +298,8 @@ fn check_alt(cx: &ctx, input: &@ast::expr, arms: &ast::arm[], sc: &scope,
let dnums = arm_defnums(a);
let new_sc = sc;
if ivec::len(dnums) > 0u {
new_sc =
@(*sc +
~[@{root_vars: roots,
block_defnum: dnums.(0),
new_sc = @(*sc + ~[@{root_vars: roots,
block_defnum: dnums.(ivec::len(dnums) - 1u),
bindings: dnums,
tys: forbidden_tp,
depends_on: deps(sc, roots),
@ -336,11 +334,13 @@ fn check_for_each(cx: &ctx, local: &@ast::local, call: &@ast::expr,
alt call.node {
ast::expr_call(f, args) {
let data = check_call(cx, f, args, sc);
let defnum = local.node.id;
let new_sc =
@{root_vars: data.root_vars,
block_defnum: defnum,
bindings: ~[defnum],
let bindings = ~[];
for p: @ast::pat in ast::pat_bindings(local.node.pat) {
bindings += ~[p.id];
}
let new_sc = @{root_vars: data.root_vars,
block_defnum: bindings.(ivec::len(bindings) - 1u),
bindings: bindings,
tys: data.unsafe_ts,
depends_on: deps(sc, data.root_vars),
mutable ok: valid};
@ -352,7 +352,6 @@ fn check_for_each(cx: &ctx, local: &@ast::local, call: &@ast::expr,
fn check_for(cx: &ctx, local: &@ast::local, seq: &@ast::expr, blk: &ast::blk,
sc: &scope, v: &vt[scope]) {
visit::visit_expr(seq, sc, v);
let defnum = local.node.id;
let root = expr_root(cx, seq, false);
let root_def =
alt path_def_id(cx, root.ex) { some(did) { ~[did.node] } _ { ~[] } };
@ -371,10 +370,13 @@ fn check_for(cx: &ctx, local: &@ast::local, seq: &@ast::expr, blk: &ast::blk,
util::ppaux::ty_to_str(cx.tcx, seq_t));
}
}
let new_sc =
@{root_vars: root_def,
block_defnum: defnum,
bindings: ~[defnum],
let bindings = ~[];
for p: @ast::pat in ast::pat_bindings(local.node.pat) {
bindings += ~[p.id];
}
let new_sc = @{root_vars: root_def,
block_defnum: bindings.(ivec::len(bindings) - 1u),
bindings: bindings,
tys: unsafe,
depends_on: deps(sc, root_def),
mutable ok: valid};
@ -388,8 +390,8 @@ fn check_var(cx: &ctx, ex: &@ast::expr, p: &ast::path, id: ast::node_id,
let my_defnum = ast::def_id_of_def(def).node;
let var_t = ty::expr_ty(cx.tcx, ex);
for r: restrict in *sc {
// excludes variables introduced since the alias was made
// FIXME This does not work anymore, now that we have macros.
if my_defnum < r.block_defnum {
for t: ty::t in r.tys {
if ty_can_unsafely_include(cx, t, var_t, assign) {
@ -489,8 +491,7 @@ fn test_scope(cx: &ctx, sc: &scope, r: &restrict, p: &ast::path) {
prob = sc.(dep).ok;
}
if prob != valid {
let msg =
alt prob {
let msg = alt prob {
overwritten(sp, wpt) {
{span: sp, msg: "overwriting " + ast::path_name(wpt)}
}

View file

@ -69,7 +69,9 @@ fn collect_freevars(def_map: &resolve::def_map, sess: &session::session,
}
}
fn walk_local(e: env, local: &@ast::local) {
set_add(e.decls, local.node.id);
for b: @ast::pat in ast::pat_bindings(local.node.pat) {
set_add(e.decls, b.id);
}
}
fn walk_pat(e: env, p: &@ast::pat) {
alt p.node { ast::pat_bind(_) { set_add(e.decls, p.id); } _ { } }
@ -131,9 +133,13 @@ fn annotate_freevars(sess: &session::session, def_map: &resolve::def_map,
fn start_walk(b: &ast::blk, v: &visit::vt[()]) {
v.visit_block(b, (), v);
}
let bound = ~[];
for b: @ast::pat in ast::pat_bindings(local.node.pat){
bound += ~[b.id];
}
let vars =
collect_freevars(e.def_map, e.sess, bind start_walk(body, _),
~[local.node.id]);
bound);
e.freevars.insert(body.node.id, vars);
}
_ { }

View file

@ -255,6 +255,7 @@ fn resolve_names(e: &@env, c: &@ast::crate) {
visit_item: visit_item_with_scope,
visit_block: visit_block_with_scope,
visit_arm: bind walk_arm(e, _, _, _),
visit_pat: bind walk_pat(e, _, _, _),
visit_expr: bind walk_expr(e, _, _, _),
visit_ty: bind walk_ty(e, _, _, _),
visit_constr: bind walk_constr(e, _, _, _, _, _),
@ -289,33 +290,23 @@ fn resolve_names(e: &@env, c: &@ast::crate) {
maybe_insert(e, id, lookup_path_strict(*e, sc, sp, p.node, ns_value));
}
fn walk_arm(e: @env, a: &ast::arm, sc: &scopes, v: &vt[scopes]) {
for p: @ast::pat in a.pats { walk_pat(*e, sc, p); }
visit_arm_with_scope(a, sc, v);
}
fn walk_pat(e: &env, sc: &scopes, pat: &@ast::pat) {
fn walk_pat(e: &@env, pat: &@ast::pat, sc: &scopes, v: &vt[scopes]) {
visit::visit_pat(pat, sc, v);
alt pat.node {
ast::pat_tag(p, children) {
let fnd = lookup_path_strict(e, sc, p.span, p.node, ns_value);
if option::is_some(fnd) {
ast::pat_tag(p, _) {
let fnd = lookup_path_strict(*e, sc, p.span, p.node, ns_value);
alt option::get(fnd) {
ast::def_variant(did, vid) {
e.def_map.insert(pat.id, option::get(fnd));
for child: @ast::pat in children {
walk_pat(e, sc, child);
}
}
_ {
e.sess.span_err(p.span,
"not a tag variant: " +
ast::path_name(p));
e.sess.span_err
(p.span, "not a tag variant: " + ast::path_name(p));
}
}
}
}
ast::pat_rec(fields, _) {
for f: ast::field_pat in fields { walk_pat(e, sc, f.pat); }
}
ast::pat_box(inner) { walk_pat(e, sc, inner); }
_ { }
}
}
@ -653,14 +644,18 @@ fn lookup_in_scope(e: &env, sc: scopes, sp: &span, name: &ident,
}
scope_loop(local) {
if ns == ns_value {
if str::eq(local.node.ident, name) {
ret some(ast::def_local(local_def(local.node.id)));
alt lookup_in_pat(name, *local.node.pat) {
some(did) { ret some(ast::def_local(did)); }
_ {}
}
}
}
scope_block(b) { ret lookup_in_block(name, b.node, ns); }
scope_arm(a) {
if ns == ns_value { ret lookup_in_pat(name, *a.pats.(0)); }
if ns == ns_value {
ret option::map(ast::def_binding,
lookup_in_pat(name, *a.pats.(0)));
}
}
}
ret none[def];
@ -716,11 +711,11 @@ fn lookup_in_ty_params(name: &ident, ty_params: &ast::ty_param[]) ->
ret none[def];
}
fn lookup_in_pat(name: &ident, pat: &ast::pat) -> option::t[def] {
fn lookup_in_pat(name: &ident, pat: &ast::pat) -> option::t[def_id] {
alt pat.node {
ast::pat_bind(p_name) {
if str::eq(p_name, name) {
ret some(ast::def_binding(local_def(pat.id)));
ret some(local_def(pat.id));
}
}
ast::pat_wild. { }
@ -739,7 +734,7 @@ fn lookup_in_pat(name: &ident, pat: &ast::pat) -> option::t[def] {
}
ast::pat_box(inner) { ret lookup_in_pat(name, *inner); }
}
ret none[def];
ret none;
}
fn lookup_in_fn(name: &ident, decl: &ast::fn_decl,
@ -783,8 +778,11 @@ fn lookup_in_block(name: &ident, b: &ast::blk_, ns: namespace) ->
alt d.node {
ast::decl_local(locs) {
for loc: @ast::local in locs {
if ns == ns_value && str::eq(name, loc.node.ident) {
ret some(ast::def_local(local_def(loc.node.id)));
if ns == ns_value {
alt lookup_in_pat(name, *loc.node.pat) {
some(did) { ret some(ast::def_local(did)); }
_ {}
}
}
}
}
@ -1154,22 +1152,20 @@ fn lookup_external(e: &env, cnum: int, ids: &ident[], ns: namespace) ->
fn check_for_collisions(e: &@env, c: &ast::crate) {
// Module indices make checking those relatively simple -- just check each
// name for multiple entities in the same namespace.
for each m: @{key: ast::node_id, val: @indexed_mod} in e.mod_map.items()
{
for each name: @{key: ident, val: list[mod_index_entry]} in
m.val.index.items() {
for each m: @{key: ast::node_id, val: @indexed_mod}
in e.mod_map.items() {
for each name: @{key: ident, val: list[mod_index_entry]}
in m.val.index.items() {
check_mod_name(*e, name.key, name.val);
}
}
// Other scopes have to be checked the hard way.
let v =
@{visit_item: bind check_item(e, _, _, _),
let v = @{visit_item: bind check_item(e, _, _, _),
visit_block: bind check_block(e, _, _, _),
visit_arm: bind check_arm(e, _, _, _),
visit_expr: bind check_expr(e, _, _, _),
visit_ty: bind check_ty(e, _, _, _) with *visit::default_visitor()};
visit_ty: bind check_ty(e, _, _, _)
with *visit::default_visitor()};
visit::visit_crate(c, (), visit::mk_vt(v));
}
@ -1244,29 +1240,30 @@ fn check_item(e: &@env, i: &@ast::item, x: &(), v: &vt[()]) {
}
}
fn check_arm(e: &@env, a: &ast::arm, x: &(), v: &vt[()]) {
visit::visit_arm(a, x, v);
fn walk_pat(ch: checker, p: &@ast::pat) {
fn check_pat(ch: checker, p: &@ast::pat) {
alt p.node {
ast::pat_bind(name) { add_name(ch, p.span, name); }
ast::pat_tag(_, children) {
for child: @ast::pat in children { walk_pat(ch, child); }
for child: @ast::pat in children { check_pat(ch, child); }
}
ast::pat_rec(fields, _) {
for f: ast::field_pat in fields { walk_pat(ch, f.pat); }
for f: ast::field_pat in fields { check_pat(ch, f.pat); }
}
ast::pat_box(inner) { walk_pat(ch, inner); }
ast::pat_box(inner) { check_pat(ch, inner); }
_ { }
}
}
}
fn check_arm(e: &@env, a: &ast::arm, x: &(), v: &vt[()]) {
visit::visit_arm(a, x, v);
let ch0 = checker(*e, "binding");
walk_pat(ch0, a.pats.(0));
check_pat(ch0, a.pats.(0));
let seen0 = ch0.seen;
let i = ivec::len(a.pats);
while i > 1u {
i -= 1u;
let ch = checker(*e, "binding");
walk_pat(ch, a.pats.(i));
check_pat(ch, a.pats.(i));
// Ensure the bindings introduced in this pattern are the same as in
// the first pattern.
@ -1298,7 +1295,7 @@ fn check_block(e: &@env, b: &ast::blk, x: &(), v: &vt[()]) {
alt d.node {
ast::decl_local(locs) {
for loc: @ast::local in locs {
add_name(values, d.span, loc.node.ident);
check_pat(values, loc.node.pat);
}
}
ast::decl_item(it) {

View file

@ -956,9 +956,8 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: &ty::t, escapes: bool,
bcx = align.bcx;
let v;
if escapes {
let /* for root*/
tydescs =
/* for root*/
let tydescs =
alloca(bcx,
T_array(T_ptr(bcx_ccx(bcx).tydesc_type), 1u + n_params));
let i = 0;
@ -3620,8 +3619,10 @@ fn trans_for(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
outer_next_cx, "for loop scope");
cx.build.Br(scope_cx.llbb);
let local_res = alloc_local(scope_cx, local);
let bcx = copy_val(local_res.bcx, INIT, local_res.val, curr, t).bcx;
let loc_r = copy_val(local_res.bcx, INIT, local_res.val, curr, t);
add_clean(scope_cx, local_res.val, t);
let bcx = trans_alt::bind_irrefutable_pat
(loc_r.bcx, local.node.pat, local_res.val, cx.fcx.lllocals);
bcx = trans_block(bcx, body, return).bcx;
if !bcx.build.is_terminated() {
bcx.build.Br(next_cx.llbb);
@ -3915,7 +3916,6 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
// FIXME: possibly support alias-mode here?
let decl_ty = node_id_type(lcx.ccx, local.node.id);
let decl_id = local.node.id;
let upvars = get_freevars(lcx.ccx.tcx, body.node.id);
let llenv = build_environment(cx, upvars);
@ -3941,9 +3941,11 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
// environment pointer.
load_environment(cx, fcx, llenv.ptrty, upvars);
// Add an upvar for the loop variable alias.
fcx.llupvars.insert(decl_id, llvm::LLVMGetParam(fcx.llfn, 3u));
let bcx = new_top_block_ctxt(fcx);
// Add bindings for the loop variable alias.
bcx = trans_alt::bind_irrefutable_pat
(bcx, local.node.pat, llvm::LLVMGetParam(fcx.llfn, 3u),
bcx.fcx.llupvars);
let lltop = bcx.llbb;
let r = trans_block(bcx, body, return);
finish_fn(fcx, lltop);
@ -5884,14 +5886,11 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
ret rslt(bcx, pair);
}
fn init_local(cx: &@block_ctxt, local: &@ast::local) -> result {
fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
let ty = node_id_type(bcx_ccx(bcx), local.node.id);
let llptr = bcx.fcx.lllocals.get(local.node.id);
// Make a note to drop this slot on the way out.
assert (cx.fcx.lllocals.contains_key(local.node.id));
let llptr = cx.fcx.lllocals.get(local.node.id);
let ty = node_id_type(bcx_ccx(cx), local.node.id);
let bcx = cx;
add_clean(cx, llptr, ty);
add_clean(bcx, llptr, ty);
alt local.node.init {
some(init) {
alt init.op {
@ -5899,8 +5898,7 @@ fn init_local(cx: &@block_ctxt, local: &@ast::local) -> result {
// Use the type of the RHS because if it's _|_, the LHS
// type might be something else, but we don't want to copy
// the value.
ty = node_id_type(bcx_ccx(cx), init.expr.id);
ty = node_id_type(bcx_ccx(bcx), init.expr.id);
let sub = trans_lval(bcx, init.expr);
bcx = move_val_if_temp(sub.res.bcx, INIT, llptr, sub, ty).bcx;
}
@ -5912,6 +5910,8 @@ fn init_local(cx: &@block_ctxt, local: &@ast::local) -> result {
}
_ { bcx = zero_alloca(bcx, llptr, ty).bcx; }
}
bcx = trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
bcx.fcx.lllocals);
ret rslt(bcx, llptr);
}
@ -6032,7 +6032,6 @@ fn trans_block_cleanups(cx: &@block_ctxt, cleanup_cx: &@block_ctxt) ->
}
iter block_locals(b: &ast::blk) -> @ast::local {
// FIXME: putting from inside an iter block doesn't work, so we can't
// use the index here.
for s: @ast::stmt in b.node.stmts {
@ -6110,10 +6109,14 @@ fn alloc_ty(cx: &@block_ctxt, t: &ty::t) -> result {
fn alloc_local(cx: &@block_ctxt, local: &@ast::local) -> result {
let t = node_id_type(bcx_ccx(cx), local.node.id);
let r = alloc_ty(cx, t);
alt local.node.pat.node {
ast::pat_bind(ident) {
if bcx_ccx(cx).sess.get_opts().debuginfo {
llvm::LLVMSetValueName(r.val, str::buf(local.node.ident));
llvm::LLVMSetValueName(r.val, str::buf(ident));
}
}
_ {}
}
r.bcx.fcx.lllocals.insert(local.node.id, r.val);
ret r;
}
@ -6122,14 +6125,15 @@ fn trans_block(cx: &@block_ctxt, b: &ast::blk, output: &out_method) ->
let bcx = cx;
for each local: @ast::local in block_locals(b) {
// FIXME Update bcx.sp
bcx = alloc_local(bcx, local).bcx;
let r = alloc_local(bcx, local);
bcx = r.bcx;
bcx.fcx.lllocals.insert(local.node.id, r.val);
}
let r = rslt(bcx, C_nil());
for s: @ast::stmt in b.node.stmts {
r = trans_stmt(bcx, *s);
bcx = r.bcx;
// If we hit a terminator, control won't go any further so
// we're in dead-code land. Stop here.
if is_terminated(bcx) { ret r; }

View file

@ -176,8 +176,8 @@ fn get_options(ccx: &@crate_ctxt, m: &match, col: uint) -> opt[] {
}
fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id,
vdefs: &{tg: def_id, var: def_id}, val: ValueRef) ->
{vals: ValueRef[], bcx: @block_ctxt} {
vdefs: &{tg: def_id, var: def_id}, val: ValueRef)
-> {vals: ValueRef[], bcx: @block_ctxt} {
let ccx = bcx.fcx.lcx.ccx;
let ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id);
let blobptr = val;
@ -246,7 +246,6 @@ fn compile_submatch(bcx: @block_ctxt, m: &match, vals: ValueRef[],
let ccx = bcx.fcx.lcx.ccx;
let pat_id = 0;
for br: match_branch in m {
// Find a real id (we're adding placeholder wildcard patterns, but
// each column is guaranteed to have at least one real pattern)
if pat_id == 0 { pat_id = br.pats.(col).id; }
@ -436,6 +435,47 @@ fn trans_alt(cx: &@block_ctxt, expr: &@ast::expr, arms: &ast::arm[],
ret rslt(trans::join_branches(cx, arm_results), C_nil());
}
// Not alt-related, but similar to the pattern-munging code above
fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
table: hashmap[ast::node_id, ValueRef])
-> @block_ctxt {
let ccx = bcx.fcx.lcx.ccx;
alt pat.node {
ast::pat_bind(_) {
table.insert(pat.id, val);
}
ast::pat_tag(_, sub) {
if ivec::len(sub) == 0u { ret bcx; }
let vdefs = ast::variant_def_ids(ccx.tcx.def_map.get(pat.id));
let args = extract_variant_args(bcx, pat.id, vdefs, val);
let i = 0;
for argval: ValueRef in args.vals {
bcx = bind_irrefutable_pat(bcx, sub.(i), argval, table);
i += 1;
}
}
ast::pat_rec(fields, _) {
let rec_ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
let rec_fields =
alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } };
for f: ast::field_pat in fields {
let ix: uint =
ty::field_idx(ccx.sess, pat.span, f.ident, rec_fields);
let r = trans::GEP_tup_like(bcx, rec_ty, val, ~[0, ix as int]);
bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table);
}
}
ast::pat_box(inner) {
let box = bcx.build.Load(val);
let unboxed = bcx.build.InBoundsGEP
(box, ~[C_int(0), C_int(back::abi::box_rc_field_body)]);
bcx = bind_irrefutable_pat(bcx, inner, unboxed, table);
}
ast::pat_wild. | ast::pat_lit(_) {}
}
ret bcx;
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil

View file

@ -580,9 +580,9 @@ fn trans_lit_common(ccx: &@crate_ctxt, lit: &ast::lit) -> ValueRef {
}
fn trans_init_local(bcx: &@block_ctxt, local: &@ast::local) -> @block_ctxt {
let llptr = bcx_fcx(bcx).lllocals.get(local.node.id);
let llptr = bcx_fcx(bcx).lllocals.get(local.node.pat.id); // FIXME DESTR
let t = type_of_node(bcx_ccx(bcx), local.node.id);
let t = type_of_node(bcx_ccx(bcx), local.node.pat.id);
tc::add_clean(bcx, llptr, t);

View file

@ -44,7 +44,9 @@ fn collect_ids_stmt(s: &@stmt, rs: @mutable node_id[]) {
}
fn collect_ids_local(l: &@local, rs: @mutable node_id[]) {
*rs += ~[l.node.id];
for p: @pat in pat_bindings(l.node.pat) {
*rs += ~[p.id];
}
}
fn node_ids_in_fn(f: &_fn, tps: &ty_param[], sp: &span, i: &fn_ident,

View file

@ -1037,15 +1037,20 @@ fn ast_constr_to_sp_constr(tcx: &ty::ctxt, args: &arg[], c: &@constr) ->
ret respan(c.span, tconstr);
}
type binding = {lhs: option::t[inst], rhs: option::t[initializer]};
type binding = {lhs: inst[], rhs: option::t[initializer]};
fn local_to_binding(loc : &@local) -> binding {
{lhs: some({ident: loc.node.ident, node: loc.node.id}),
fn local_to_bindings(loc : &@local) -> binding {
let lhs = ~[];
for p: @pat in pat_bindings(loc.node.pat) {
let ident = alt p.node { pat_bind(name) { name } };
lhs += ~[{ident: ident, node: p.id}];
}
{lhs: lhs,
rhs: loc.node.init}
}
fn locals_to_bindings(locals : &(@local)[]) -> binding[] {
ivec::map(local_to_binding, locals)
ivec::map(local_to_bindings, locals)
}
fn anon_bindings(es : &(@expr)[]) -> binding[] {
@ -1053,7 +1058,7 @@ fn anon_bindings(es : &(@expr)[]) -> binding[] {
{op: init_assign, expr: e}
}
ret ivec::map(fn (e : &@expr) -> binding {
{lhs: none,
{lhs: ~[],
rhs: some(expr_to_initializer(e)) } },
es);
}

View file

@ -14,8 +14,11 @@ import syntax::ast::respan;
type ctxt = {cs: @mutable sp_constr[], tcx: ty::ctxt};
fn collect_local(loc: &@local, cx: &ctxt, v: &visit::vt[ctxt]) {
log "collect_local: pushing " + loc.node.ident;
*cx.cs += ~[respan(loc.span, ninit(loc.node.id, loc.node.ident))];
for p: @pat in pat_bindings(loc.node.pat) {
let ident = alt p.node { pat_bind(id) { id } };
log "collect_local: pushing " + ident;
*cx.cs += ~[respan(loc.span, ninit(p.id, ident))];
}
visit::visit_local(loc, cx, v);
}

View file

@ -133,12 +133,14 @@ fn find_pre_post_loop(fcx: &fn_ctxt, l: &@local, index: &@expr, body: &blk,
id: node_id) {
find_pre_post_expr(fcx, index);
find_pre_post_block(fcx, body);
let v_init = ninit(l.node.id, l.node.ident);
for p: @pat in pat_bindings(l.node.pat) {
let ident = alt p.node { pat_bind(id) { id } };
let v_init = ninit(p.id, ident);
relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body);
// Hack: for-loop index variables are frequently ignored,
// so we pretend they're used
use_var(fcx, l.node.id);
use_var(fcx, p.id);
}
let loop_precond =
seq_preconds(fcx,
@ -573,41 +575,47 @@ fn find_pre_post_stmt(fcx: &fn_ctxt, s: &stmt) {
alt adecl.node {
decl_local(alocals) {
for alocal: @local in alocals {
let bindings = pat_bindings(alocal.node.pat);
alt alocal.node.init {
some(an_init) {
/* LHS always becomes initialized,
whether or not this is a move */
find_pre_post_expr(fcx, an_init.expr);
copy_pre_post(fcx.ccx, alocal.node.id, an_init.expr);
for p: @pat in bindings {
copy_pre_post(fcx.ccx, p.id, an_init.expr);
}
/* Inherit ann from initializer, and add var being
initialized to the postcondition */
copy_pre_post(fcx.ccx, id, an_init.expr);
alt an_init.expr.node {
expr_path(p) {
for pat: @pat in bindings {
let ident = alt pat.node { pat_bind(n) { n } };
copy_in_postcond(fcx, id,
{ident: alocal.node.ident,
node: alocal.node.id},
{ident: ident, node: pat.id},
{ident:
path_to_ident(fcx.ccx.tcx, p),
node: an_init.expr.id},
op_to_oper_ty(an_init.op));
}
}
_ { }
}
gen(fcx, id, ninit(alocal.node.id, alocal.node.ident));
for p: @pat in bindings {
let ident = alt p.node { pat_bind(name) { name } };
gen(fcx, id, ninit(p.id, ident));
}
if an_init.op == init_move && is_path(an_init.expr) {
forget_in_postcond(fcx, id, an_init.expr.id);
}
}
none. {
clear_pp(node_id_to_ts_ann(fcx.ccx,
alocal.node.id).conditions);
for p: @pat in bindings {
clear_pp(node_id_to_ts_ann(fcx.ccx, p.id).conditions);
}
clear_pp(node_id_to_ts_ann(fcx.ccx, id).conditions);
}
}

View file

@ -74,8 +74,7 @@ fn seq_states(fcx: &fn_ctxt, pres: &prestate, bindings: &binding[])
changed |= find_pre_post_state_expr(fcx, post, an_init.expr)
|| changed;
post = tritv_clone(expr_poststate(fcx.ccx, an_init.expr));
alt (b.lhs) {
some(i) {
for i: inst in b.lhs {
alt (an_init.expr.node) {
expr_path(p) {
handle_move_or_copy(fcx, post, p, an_init.expr.id, i,
@ -85,22 +84,12 @@ fn seq_states(fcx: &fn_ctxt, pres: &prestate, bindings: &binding[])
}
set_in_poststate_ident(fcx, i.node, i.ident, post);
}
_ {
//This is an expression that doesn't get named.
// So, nothing more to do.
}
}
}
none {
alt (b.lhs) {
some(i) {
// variable w/o an initializer
for i: inst in b.lhs {
// variables w/o an initializer
clear_in_poststate_ident_(fcx, i.node, i.ident, post);
}
none { fcx.ccx.tcx.sess.bug("seq_states: binding has \
neither an lhs nor an rhs");
}
}
}
}
}
@ -217,10 +206,13 @@ fn find_pre_post_state_loop(fcx: &fn_ctxt, pres: prestate, l: &@local,
set_prestate_ann(fcx.ccx, id, loop_pres) |
find_pre_post_state_expr(fcx, pres, index);
// Make sure the index var is considered initialized
// Make sure the index vars are considered initialized
// in the body
let index_post = tritv_clone(expr_poststate(fcx.ccx, index));
set_in_poststate_ident(fcx, l.node.id, l.node.ident, index_post);
for p: @pat in pat_bindings(l.node.pat) {
let ident = alt p.node { pat_bind(name) { name } };
set_in_poststate_ident(fcx, p.id, ident, index_post);
}
changed |= find_pre_post_state_block(fcx, index_post, body);

View file

@ -39,7 +39,6 @@ export constr_general;
export constr_table;
export count_ty_params;
export ctxt;
export decl_local_ty;
export def_has_ty_params;
export eq_ty;
export expr_has_ty_params;
@ -1893,10 +1892,6 @@ fn expr_has_ty_params(cx: &ctxt, expr: &@ast::expr) -> bool {
ret node_id_has_type_params(cx, expr.id);
}
fn decl_local_ty(cx: &ctxt, l: &@ast::local) -> t {
ret node_id_to_type(cx, l.node.id);
}
fn stmt_node_id(s: &@ast::stmt) -> ast::node_id {
alt s.node {
ast::stmt_decl(_, id) { ret id; }

View file

@ -52,10 +52,8 @@ type ty_table = hashmap[ast::def_id, ty::t];
// Used for typechecking the methods of an object.
tag obj_info {
// Regular objects have a node_id at compile time.
regular_obj(ast::obj_field[], ast::node_id);
// Anonymous objects only have a type at compile time. It's optional
// because not all anonymous objects have a inner_obj to attach to.
anon_obj(ast::obj_field[], option::t[ty::sty]);
@ -84,9 +82,8 @@ fn lookup_local(fcx: &@fn_ctxt, sp: &span, id: ast::node_id) -> int {
alt fcx.locals.find(id) {
some(x) { x }
_ {
fcx.ccx.tcx.sess.span_fatal(sp,
"internal error looking up a \
local var")
fcx.ccx.tcx.sess.span_fatal
(sp, "internal error looking up a local var")
}
}
}
@ -95,13 +92,19 @@ fn lookup_def(fcx: &@fn_ctxt, sp: &span, id: ast::node_id) -> ast::def {
alt fcx.ccx.tcx.def_map.find(id) {
some(x) { x }
_ {
fcx.ccx.tcx.sess.span_fatal(sp,
"internal error looking up \
a definition")
fcx.ccx.tcx.sess.span_fatal
(sp, "internal error looking up a definition")
}
}
}
fn ident_for_local(loc: &@ast::local) -> ast::ident {
ret alt loc.node.pat.node {
ast::pat_bind(name) { name }
_ { "local" } // FIXME DESTR
};
}
// Returns the type parameter count and the type for the given definition.
fn ty_param_kinds_and_ty_for_def(fcx: &@fn_ctxt, sp: &span, defn: &ast::def)
-> ty_param_kinds_and_ty {
@ -134,7 +137,6 @@ fn ty_param_kinds_and_ty_for_def(fcx: &@fn_ctxt, sp: &span, defn: &ast::def)
ast::def_mod(_) {
// Hopefully part of a path.
// TODO: return a type that's more poisonous, perhaps?
ret {kinds: no_kinds, ty: ty::mk_nil(fcx.ccx.tcx)};
}
ast::def_ty(_) {
@ -142,7 +144,6 @@ fn ty_param_kinds_and_ty_for_def(fcx: &@fn_ctxt, sp: &span, defn: &ast::def)
}
_ {
// FIXME: handle other names.
fcx.ccx.tcx.sess.unimpl("definition variant");
}
}
@ -190,7 +191,6 @@ fn instantiate_path(fcx: &@fn_ctxt, pth: &ast::path,
}
} else {
// We will acquire the type parameters through unification.
let ty_substs: ty::t[] = ~[];
let i = 0u;
while i < ty_param_count {
@ -213,16 +213,13 @@ fn ast_mode_to_mode(mode: ast::mode) -> ty::mode {
// Type tests
fn structurally_resolved_type(fcx: &@fn_ctxt, sp: &span, typ: ty::t) ->
fn structurally_resolved_type(fcx: &@fn_ctxt, sp: &span, tp: ty::t) ->
ty::t {
let r =
ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, typ);
alt r {
alt ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, tp) {
fix_ok(typ_s) { ret typ_s; }
fix_err(_) {
fcx.ccx.tcx.sess.span_fatal(sp,
"the type of this value must be \
known in this context");
fcx.ccx.tcx.sess.span_fatal
(sp, "the type of this value must be known in this context");
}
}
}
@ -763,12 +760,10 @@ mod collect {
alt it.node {
ast::item_mod(_) {
// ignore item_mod, it has no type.
}
ast::item_native_mod(native_mod) {
// Propagate the native ABI down to convert_native() below,
// but otherwise do nothing, as native modules have no types.
*abi = some[ast::native_abi](native_mod.abi);
}
ast::item_tag(variants, ty_params) {
@ -779,18 +774,16 @@ mod collect {
ast::item_obj(object, ty_params, ctor_id) {
// Now we need to call ty_of_obj_ctor(); this is the type that
// we write into the table for this item.
ty_of_item(cx, it);
let tpt =
ty_of_obj_ctor(cx, it.ident, object, ctor_id, ty_params);
let tpt = ty_of_obj_ctor(cx, it.ident, object,
ctor_id, ty_params);
write::ty_only(cx.tcx, ctor_id, tpt.ty);
// Write the methods into the type table.
//
// FIXME: Inefficient; this ends up calling
// get_obj_method_types() twice. (The first time was above in
// ty_of_obj().)
let method_types = get_obj_method_types(cx, object);
let i = 0u;
while i < ivec::len[@ast::method](object.methods) {
@ -803,7 +796,6 @@ mod collect {
//
// FIXME: We want to use uint::range() here, but that causes
// an assertion in trans.
let args = ty::ty_fn_args(cx.tcx, tpt.ty);
i = 0u;
while i < ivec::len[ty::arg](args) {
@ -833,7 +825,6 @@ mod collect {
// This call populates the type cache with the converted type
// of the item in passing. All we have to do here is to write
// it into the node type table.
let tpt = ty_of_item(cx, it);
write::ty_only(cx.tcx, it.id, tpt.ty);
}
@ -844,13 +835,11 @@ mod collect {
// As above, this call populates the type table with the converted
// type of the native item. We simply write it into the node type
// table.
let tpt =
ty_of_native_item(cx, i, option::get[ast::native_abi]({ *abi }));
alt i.node {
ast::native_item_ty. {
// FIXME: Native types have no annotation. Should they? --pcw
}
ast::native_item_fn(_, _, _) {
write::ty_only(cx.tcx, i.id, tpt.ty);
@ -860,11 +849,9 @@ mod collect {
fn collect_item_types(tcx: &ty::ctxt, crate: &@ast::crate) {
// We have to propagate the surrounding ABI to the native items
// contained within the native module.
let abi = @mutable none[ast::native_abi];
let cx = @{tcx: tcx};
let visit =
visit::mk_simple_visitor
let visit = visit::mk_simple_visitor
(@{visit_item: bind convert(cx, abi, _),
visit_native_item: bind convert_native(cx, abi, _)
with *visit::default_simple_visitor()});
@ -1211,6 +1198,8 @@ fn gather_locals(ccx: &@crate_ctxt, f: &ast::_fn, id: &ast::node_id,
local_names: &hashmap[ast::node_id, ast::ident],
nvi: @mutable int, nid: ast::node_id, ident: &ast::ident,
ty_opt: option::t[ty::t]) {
// FIXME DESTR
if locals.contains_key(nid) { ret; }
let var_id = next_var_id(nvi);
locals.insert(nid, var_id);
local_names.insert(nid, ident);
@ -1277,13 +1266,13 @@ fn gather_locals(ccx: &@crate_ctxt, f: &ast::_fn, id: &ast::node_id,
none. {
// Auto slot.
assign(ccx.tcx, vb, locals, local_names, nvi, local.node.id,
local.node.ident, none);
ident_for_local(local), none);
}
some(ast_ty) {
// Explicitly typed slot.
let local_ty = ast_ty_to_ty_crate(ccx, ast_ty);
assign(ccx.tcx, vb, locals, local_names, nvi, local.node.id,
local.node.ident, some[ty::t](local_ty));
ident_for_local(local), some(local_ty));
}
}
visit::visit_local(local, e, v);
@ -1623,7 +1612,8 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
let bot = check_decl_local(fcx, local);
check_block(fcx, body);
// Unify type of decl with element type of the seq
demand::simple(fcx, local.span, ty::decl_local_ty(fcx.ccx.tcx, local),
demand::simple(fcx, local.span,
ty::node_id_to_type(fcx.ccx.tcx, local.node.id),
element_ty);
let typ = ty::mk_nil(fcx.ccx.tcx);
write::ty_only_fixup(fcx, node_id, typ);
@ -1807,7 +1797,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
}
// The definition doesn't take type parameters. If the programmer
// supplied some, that's an error.
if ivec::len[@ast::ty](pth.node.types) > 0u {
fcx.ccx.tcx.sess.span_fatal(expr.span,
"this kind of value does not \
@ -2532,22 +2521,24 @@ fn check_decl_initializer(fcx: &@fn_ctxt, nid: ast::node_id,
}
fn check_decl_local(fcx: &@fn_ctxt, local: &@ast::local) -> bool {
let a_id = local.node.id;
let bot = false;
alt fcx.locals.find(a_id) {
alt fcx.locals.find(local.node.id) {
none. {
fcx.ccx.tcx.sess.bug("check_decl_local: local id not found " +
local.node.ident);
ident_for_local(local));
}
some(i) {
let t = ty::mk_var(fcx.ccx.tcx, i);
write::ty_only_fixup(fcx, a_id, t);
write::ty_only_fixup(fcx, local.node.id, t);
alt local.node.init {
some(init) {
bot = check_decl_initializer(fcx, local.node.id, init);
}
_ {/* fall through */ }
}
let id_map = ast::pat_id_map(local.node.pat);
check_pat(fcx, id_map, local.node.pat, t);
}
}
ret bot;

View file

@ -154,6 +154,26 @@ fn pat_id_map(pat: &@pat) -> pat_id_map {
ret map;
}
// FIXME This wanted to be an iter, but bug #791 got in the way.
fn pat_bindings(pat: &@pat) -> (@pat)[] {
let found = ~[];
fn recur(found: &mutable (@pat)[], pat: &@pat) {
alt pat.node {
pat_bind(_) { found += ~[pat]; }
pat_tag(_, sub) {
for p in sub { recur(found, p); }
}
pat_rec(fields, _) {
for f: field_pat in fields { recur(found, f.pat); }
}
pat_box(sub) { recur(found, sub); }
pat_wild. | pat_lit(_) {}
}
}
recur(found, pat);
ret found;
}
tag mutability { mut; imm; maybe_mut; }
tag kind { kind_pinned; kind_shared; kind_unique; }
@ -240,10 +260,8 @@ tag init_op { init_assign; init_recv; init_move; }
type initializer = {op: init_op, expr: @expr};
type local_ =
{ty: option::t[@ty],
infer: bool,
ident: ident,
type local_ = {ty: option::t[@ty],
pat: @pat,
init: option::t[initializer],
id: node_id};

View file

@ -486,10 +486,8 @@ fn noop_fold_path(p: &path_, fld: ast_fold) -> path_ {
fn noop_fold_local(l: &local_, fld: ast_fold) -> local_ {
ret {ty: option::map(fld.fold_ty, l.ty),
infer: l.infer,
ident: fld.fold_ident(l.ident),
init:
alt l.init {
pat: fld.fold_pat(l.pat),
init: alt l.init {
option::none[initializer]. { l.init }
option::some[initializer](init) {
option::some[initializer]({op: init.op,

View file

@ -1337,9 +1337,6 @@ fn parse_alt_expr(p: &parser) -> @ast::expr {
expect(p, token::LBRACE);
let arms: ast::arm[] = ~[];
while p.peek() != token::RBRACE {
// Optionally eat the case keyword.
// FIXME remove this (and the optional parens) once we've updated our
// code to not use the old syntax
let pats = parse_pats(p);
let blk = parse_block(p);
arms += ~[{pats: pats, block: blk}];
@ -1472,7 +1469,7 @@ fn parse_pat(p: &parser) -> @ast::pat {
_ { true }
}) {
hi = p.get_hi_pos();
pat = ast::pat_bind(parse_ident(p));
pat = ast::pat_bind(parse_value_ident(p));
} else {
let tag_path = parse_path_and_ty_param_substs(p);
hi = tag_path.span.hi;
@ -1497,14 +1494,13 @@ fn parse_pat(p: &parser) -> @ast::pat {
fn parse_local(p: &parser, allow_init: bool) -> @ast::local {
let lo = p.get_lo_pos();
let ident = parse_value_ident(p);
let pat = parse_pat(p);
let ty = none;
if eat(p, token::COLON) { ty = some(parse_ty(p)); }
let init = if allow_init { parse_initializer(p) } else { none };
ret @spanned(lo, p.get_last_hi_pos(),
{ty: ty,
infer: false,
ident: ident,
pat: pat,
init: init,
id: p.get_id()});
}

View file

@ -1002,15 +1002,16 @@ fn print_decl(s: &ps, decl: &@ast::decl) {
ibox(s, indent_unit);
word_nbsp(s, "let");
fn print_local(s: &ps, loc: &@ast::local) {
ibox(s, indent_unit);
print_pat(s, loc.node.pat);
alt loc.node.ty {
some(ty) {
ibox(s, indent_unit);
word_space(s, loc.node.ident + ":");
word_space(s, ":");
print_type(s, *ty);
}
_ { }
}
end(s);
}
_ { word(s.s, loc.node.ident); }
}
alt loc.node.init {
some(init) {
nbsp(s);
@ -1034,7 +1035,7 @@ fn print_decl(s: &ps, decl: &@ast::decl) {
fn print_ident(s: &ps, ident: &ast::ident) { word(s.s, ident); }
fn print_for_decl(s: &ps, loc: &@ast::local, coll: &@ast::expr) {
word(s.s, loc.node.ident);
print_pat(s, loc.node.pat);
alt loc.node.ty {
some(t) { word_space(s, ":"); print_type(s, *t); }
none. { }

View file

@ -78,6 +78,7 @@ fn visit_mod[E](m: &_mod, sp: &span, e: &E, v: &vt[E]) {
fn visit_view_item[E](vi: &@view_item, e: &E, v: &vt[E]) { }
fn visit_local[E](loc: &@local, e: &E, v: &vt[E]) {
v.visit_pat(loc.node.pat, e, v);
alt loc.node.ty { none. { } some(t) { v.visit_ty(t, e, v); } }
alt loc.node.init { none. { } some(i) { v.visit_expr(i.expr, e, v); } }
}