From 985c32ef4c930cdfba23db2191014d772c354407 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Jul 2011 12:01:45 +0200 Subject: [PATCH] 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. --- src/comp/middle/alias.rs | 73 +++++------ src/comp/middle/freevars.rs | 10 +- src/comp/middle/resolve.rs | 119 +++++++++--------- src/comp/middle/trans.rs | 52 ++++---- src/comp/middle/trans_alt.rs | 48 ++++++- src/comp/middle/trans_dps.rs | 4 +- src/comp/middle/tstate/annotate.rs | 4 +- src/comp/middle/tstate/auxiliary.rs | 17 ++- src/comp/middle/tstate/collect_locals.rs | 7 +- src/comp/middle/tstate/pre_post_conditions.rs | 46 ++++--- src/comp/middle/tstate/states.rs | 30 ++--- src/comp/middle/ty.rs | 5 - src/comp/middle/typeck.rs | 69 +++++----- src/comp/syntax/ast.rs | 32 +++-- src/comp/syntax/fold.rs | 18 ++- src/comp/syntax/parse/parser.rs | 10 +- src/comp/syntax/print/pprust.rs | 11 +- src/comp/syntax/visit.rs | 1 + src/lib/vec.rs | 2 +- 19 files changed, 308 insertions(+), 250 deletions(-) diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index f73df362276..75b3dbf658c 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -127,7 +127,7 @@ fn visit_decl(cx: &@ctx, d: &@ast::decl, sc: &scope, v: &vt[scope]) { visit::visit_decl(d, sc, v); alt d.node { ast::decl_local(locs) { - for loc: @ast::local in locs { + for loc: @ast::local in locs { alt loc.node.init { some(init) { if init.op == ast::init_move { @@ -298,14 +298,12 @@ 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), - bindings: dnums, - tys: forbidden_tp, - depends_on: deps(sc, roots), - mutable ok: valid}]); + new_sc = @(*sc + ~[@{root_vars: roots, + block_defnum: dnums.(ivec::len(dnums) - 1u), + bindings: dnums, + tys: forbidden_tp, + depends_on: deps(sc, roots), + mutable ok: valid}]); } visit::visit_arm(a, new_sc, v); } @@ -336,14 +334,16 @@ 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], - tys: data.unsafe_ts, - depends_on: deps(sc, data.root_vars), - mutable ok: valid}; + 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}; visit::visit_block(blk, @(*sc + ~[new_sc]), v); } } @@ -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,13 +370,16 @@ 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], - tys: unsafe, - depends_on: deps(sc, root_def), - mutable ok: valid}; + 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}; visit::visit_block(blk, @(*sc + ~[new_sc]), v); } @@ -388,10 +390,10 @@ 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 { + for t: ty::t in r.tys { if ty_can_unsafely_include(cx, t, var_t, assign) { r.ok = val_taken(ex.span, p); } @@ -489,15 +491,14 @@ fn test_scope(cx: &ctx, sc: &scope, r: &restrict, p: &ast::path) { prob = sc.(dep).ok; } if prob != valid { - let msg = - alt prob { - overwritten(sp, wpt) { - {span: sp, msg: "overwriting " + ast::path_name(wpt)} - } - val_taken(sp, vpt) { - {span: sp, msg: "taking the value of " + ast::path_name(vpt)} - } - }; + let msg = alt prob { + overwritten(sp, wpt) { + {span: sp, msg: "overwriting " + ast::path_name(wpt)} + } + val_taken(sp, vpt) { + {span: sp, msg: "taking the value of " + ast::path_name(vpt)} + } + }; cx.tcx.sess.span_err(msg.span, msg.msg + " will invalidate alias " + ast::path_name(p) + ", which is still used"); diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs index e5230bb466d..fa44001e330 100644 --- a/src/comp/middle/freevars.rs +++ b/src/comp/middle/freevars.rs @@ -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); } _ { } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index db012eca5dd..e341855978d 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -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) { - 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)); - } - } + 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)); + } + _ { + 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, @@ -777,14 +772,17 @@ fn lookup_in_obj(name: &ident, ob: &ast::_obj, ty_params: &ast::ty_param[], fn lookup_in_block(name: &ident, b: &ast::blk_, ns: namespace) -> option::t[def] { - for st: @ast::stmt in b.stmts { + for st: @ast::stmt in b.stmts { alt st.node { ast::stmt_decl(d, _) { 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))); + for loc: @ast::local in locs { + 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, _, _, _), - 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()}; + 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::visit_crate(c, (), visit::mk_vt(v)); } @@ -1244,29 +1240,30 @@ fn check_item(e: &@env, i: &@ast::item, x: &(), v: &vt[()]) { } } +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 { check_pat(ch, child); } + } + ast::pat_rec(fields, _) { + for f: ast::field_pat in fields { check_pat(ch, f.pat); } + } + 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); - fn walk_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); } - } - ast::pat_rec(fields, _) { - for f: ast::field_pat in fields { walk_pat(ch, f.pat); } - } - ast::pat_box(inner) { walk_pat(ch, inner); } - _ { } - } - } 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. @@ -1297,8 +1294,8 @@ fn check_block(e: &@env, b: &ast::blk, x: &(), v: &vt[()]) { ast::stmt_decl(d, _) { alt d.node { ast::decl_local(locs) { - for loc: @ast::local in locs { - add_name(values, d.span, loc.node.ident); + for loc: @ast::local in locs { + check_pat(values, loc.node.pat); } } ast::decl_item(it) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index fc0e5d082a2..90ce96e415f 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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 { @@ -6040,7 +6039,7 @@ iter block_locals(b: &ast::blk) -> @ast::local { ast::stmt_decl(d, _) { alt d.node { ast::decl_local(locals) { - for local: @ast::local in locals { put local; } + for local: @ast::local in locals { put local; } } _ {/* fall through */ } } @@ -6110,26 +6109,31 @@ 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); - if bcx_ccx(cx).sess.get_opts().debuginfo { - llvm::LLVMSetValueName(r.val, str::buf(local.node.ident)); + alt local.node.pat.node { + ast::pat_bind(ident) { + if bcx_ccx(cx).sess.get_opts().debuginfo { + llvm::LLVMSetValueName(r.val, str::buf(ident)); + } + } + _ {} } - r.bcx.fcx.lllocals.insert(local.node.id, r.val); ret r; } fn trans_block(cx: &@block_ctxt, b: &ast::blk, output: &out_method) -> result { let bcx = cx; - for each local: @ast::local in block_locals(b) { + 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; } diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index ead0bcaf0b6..c77a3451266 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -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; } @@ -259,7 +258,7 @@ fn compile_submatch(bcx: @block_ctxt, m: &match, vals: ValueRef[], let fields = alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } }; let rec_vals = ~[]; - for field_name: ast::ident in rec_fields { + for field_name: ast::ident in rec_fields { let ix: uint = ty::field_idx(ccx.sess, {lo: 0u, hi: 0u}, field_name, fields); let r = trans::GEP_tup_like(bcx, rec_ty, val, ~[0, ix as int]); @@ -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 diff --git a/src/comp/middle/trans_dps.rs b/src/comp/middle/trans_dps.rs index 4e659349ef0..d59c07a7cd8 100644 --- a/src/comp/middle/trans_dps.rs +++ b/src/comp/middle/trans_dps.rs @@ -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); diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs index 03f5f2d7e64..f0bebcfc0c5 100644 --- a/src/comp/middle/tstate/annotate.rs +++ b/src/comp/middle/tstate/annotate.rs @@ -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, diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 1d78750cc09..7ad070446f8 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -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,8 +1058,8 @@ fn anon_bindings(es : &(@expr)[]) -> binding[] { {op: init_assign, expr: e} } ret ivec::map(fn (e : &@expr) -> binding { - {lhs: none, - rhs: some(expr_to_initializer(e)) } }, + {lhs: ~[], + rhs: some(expr_to_initializer(e)) } }, es); } diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index f9b3012f527..4dd9750c7db 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -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); } diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 99293239cb9..84c75fa1686 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -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); - 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); + 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, 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) { - copy_in_postcond(fcx, id, - {ident: alocal.node.ident, - node: alocal.node.id}, - {ident: + for pat: @pat in bindings { + let ident = alt pat.node { pat_bind(n) { n } }; + copy_in_postcond(fcx, 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)); + 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); } } diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 0aebc7659d1..90a7cd88eff 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -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, @@ -84,22 +83,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 - 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"); - } + } + none { + for i: inst in b.lhs { + // variables w/o an initializer + clear_in_poststate_ident_(fcx, i.node, i.ident, post); } } } @@ -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); diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index c25821b2b63..faabbfe6898 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index b2b49340fb5..84482ce46cf 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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; diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index fc2d64ddb49..5dfe6ba7463 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -142,7 +142,7 @@ fn pat_id_map(pat: &@pat) -> pat_id_map { fn walk(map: &pat_id_map, pat: &@pat) { alt pat.node { pat_bind(name) { map.insert(name, pat.id); } - pat_tag(_, sub) { for p: @pat in sub { walk(map, p); } } + pat_tag(_, sub) { for p: @pat in sub { walk(map, p); } } pat_rec(fields, _) { for f: field_pat in fields { walk(map, f.pat); } } @@ -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,12 +260,10 @@ 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, - init: option::t[initializer], - id: node_id}; +type local_ = {ty: option::t[@ty], + pat: @pat, + init: option::t[initializer], + id: node_id}; type local = spanned[local_]; diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index fee5b03174d..e2bb0380c04 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -486,16 +486,14 @@ 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 { - option::none[initializer]. { l.init } - option::some[initializer](init) { - option::some[initializer]({op: init.op, - expr: fld.fold_expr(init.expr)}) - } - }, + 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, + expr: fld.fold_expr(init.expr)}) + } + }, id: l.id}; } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 3fba6f614f0..9c929390bd2 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -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()}); } diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index bf5460452b4..7533eced7cf 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -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); } + _ { } } + end(s); 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. { } diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 3c2eb231647..673fa46d466 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -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); } } } diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 0bf6475d297..7687dce9370 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -237,7 +237,7 @@ fn position_pred[T](f: fn(&T) -> bool , v: &vec[T]) -> option::t[uint] { } fn member[T](x: &T, v: &array[T]) -> bool { - for elt: T in v { if x == elt { ret true; } } + for elt: T in v { if x == elt { ret true; } } ret false; }