diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index e10dec83a678..93239ec116e2 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -9,6 +9,7 @@ import std::list; import option::{some, none, is_none}; import list::list; import driver::session::session; +import pat_util::*; // This is not an alias-analyser (though it would merit from becoming one, or // getting input from one, to be more precise). It is a pass that checks @@ -323,7 +324,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope, for a: ast::arm in arms { let new_bs = sc.bs; let root_var = path_def_id(cx, root.ex); - let pat_id_map = ast_util::pat_id_map(a.pats[0]); + let pat_id_map = pat_util::pat_id_map(cx.tcx, a.pats[0]); type info = { id: node_id, mutable unsafe_tys: [unsafe_ty], @@ -588,10 +589,11 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t, pat: @ast::pat) -> [pattern_root] { fn walk(tcx: ty::ctxt, mut: option::t, pat: @ast::pat, &set: [pattern_root]) { - alt pat.node { + alt normalize_pat(tcx, pat).node { ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {} - ast::pat_bind(nm, sub) { - set += [{id: pat.id, name: nm, mut: mut, span: pat.span}]; + ast::pat_ident(nm, sub) { + set += [{id: pat.id, name: path_to_ident(nm), mut: mut, + span: pat.span}]; alt sub { some(p) { walk(tcx, mut, p, set); } _ {} } } ast::pat_tag(_, ps) | ast::pat_tup(ps) { diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs index 1af44c812098..de04da490141 100644 --- a/src/comp/middle/ast_map.rs +++ b/src/comp/middle/ast_map.rs @@ -44,14 +44,14 @@ fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk, } fn map_local(cx: ctx, loc: @local) { - ast_util::pat_bindings(loc.node.pat) {|p| + pat_util::pat_bindings(loc.node.pat) {|p| cx.map.insert(p.id, node_local(cx.local_id)); cx.local_id += 1u; }; } fn map_arm(cx: ctx, arm: arm) { - ast_util::pat_bindings(arm.pats[0]) {|p| + pat_util::pat_bindings(arm.pats[0]) {|p| cx.map.insert(p.id, node_local(cx.local_id)); cx.local_id += 1u; }; diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs index d2e3c15009d8..e32866e57494 100644 --- a/src/comp/middle/check_alt.rs +++ b/src/comp/middle/check_alt.rs @@ -1,6 +1,7 @@ import syntax::ast::*; import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs, lit_expr_eq}; +import pat_util::*; import syntax::visit; import option::{some, none}; import driver::session::session; @@ -16,7 +17,12 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) { fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) { visit::visit_expr(ex, s, v); - alt ex.node { expr_alt(_, arms) { check_arms(tcx, arms); } _ { } } + alt ex.node { + expr_alt(_, arms) { + check_arms(tcx, pat_util::normalize_arms(tcx, arms)); + } + _ { } + } } fn check_arms(tcx: ty::ctxt, arms: [arm]) { @@ -66,8 +72,8 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { } alt a.node { - pat_bind(_, some(p)) { pattern_supersedes(tcx, p, b) } - pat_wild. | pat_bind(_, none.) { true } + pat_ident(_, some(p)) { pattern_supersedes(tcx, p, b) } + pat_wild. | pat_ident(_, none.) { true } pat_lit(la) { alt b.node { pat_lit(lb) { lit_expr_eq(la, lb) } @@ -132,11 +138,11 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) { } fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool { - alt pat.node { - pat_box(sub) | pat_uniq(sub) | pat_bind(_, some(sub)) { + alt normalize_pat(tcx, pat).node { + pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) { is_refutable(tcx, sub) } - pat_wild. | pat_bind(_, none.) { false } + pat_wild. | pat_ident(_, none.) { false } pat_lit(_) { true } pat_rec(fields, _) { for field: field_pat in fields { diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs index f834fa8b58b8..938fcac52d35 100644 --- a/src/comp/middle/debuginfo.rs +++ b/src/comp/middle/debuginfo.rs @@ -8,6 +8,7 @@ import middle::trans_build::B; import middle::ty; import syntax::{ast, codemap}; import ast::ty; +import pat_util::*; import util::ppaux::ty_to_str; export create_local_var; @@ -629,9 +630,10 @@ fn create_local_var(bcx: @block_ctxt, local: @ast::local) option::none. {} } - let name = alt local.node.pat.node { - ast::pat_bind(ident, _) { ident /*XXX deal w/ optional node binding*/ } - }; + let name = path_to_ident(alt pat_util::normalize_pat(bcx_tcx(bcx), + local.node.pat).node { + ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ } + }); let loc = codemap::lookup_char_pos(cx.sess.codemap, local.span.lo); let ty = trans::node_id_type(cx, local.node.id); diff --git a/src/comp/middle/pat_util.rs b/src/comp/middle/pat_util.rs new file mode 100644 index 000000000000..f2d1b6ea6cab --- /dev/null +++ b/src/comp/middle/pat_util.rs @@ -0,0 +1,119 @@ +import syntax::ast::*; +import syntax::ast_util; +import syntax::ast_util::respan; +import syntax::fold; +import syntax::fold::*; + +export normalize_arms; +export normalize_pat; +export normalize_pat_def_map; +export pat_binding_ids; +export pat_bindings; +export pat_id_map; +export path_to_ident; + +fn normalize_pat_def_map(dm: resolve::def_map, p: @pat) -> @pat { + // have to do it the hard way b/c ast fold doesn't pass around + // node IDs. bother. + alt p.node { + pat_wild. { p } + pat_ident(_, none.) { normalize_one(dm, p) } + pat_ident(q, some(r)) { + @{node: pat_ident(q, some(normalize_pat_def_map(dm, r))) + with *p} + } + pat_tag(a_path, subs) { + @{node: pat_tag(a_path, + vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) with *p} + } + pat_rec(field_pats, b) { + @{node: pat_rec(vec::map(field_pats, + {|fp| {pat: normalize_pat_def_map(dm, fp.pat) with fp}}), b) + with *p} + } + pat_tup(subs) { + @{node: pat_tup(vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) + with *p} + } + pat_box(q) { + @{node: pat_box(normalize_pat_def_map(dm, q)) + with *p} + } + pat_uniq(q) { + @{node: pat_uniq(normalize_pat_def_map(dm, q)) + with *p} + } + pat_lit(_) { p } + pat_range(_,_) { p } + } +} + +fn normalize_one(dm: resolve::def_map, p: @pat) -> @pat { + alt dm.find(p.id) { + some(d) { + alt p.node { + pat_ident(tag_path, _) { @{id: p.id, + node: pat_tag(tag_path, []), + span: p.span} } + _ { p } + } + } + none. { p } + } +} + +fn normalize_pat(tcx: ty::ctxt, p: @pat) -> @pat { + normalize_pat_def_map(tcx.def_map, p) +} + +fn normalize_arms(tcx: ty::ctxt, arms:[arm]) -> [arm] { + vec::map(arms, {|a| + {pats: + vec::map(a.pats, {|p| + pat_util::normalize_pat(tcx, p)}) + with a}}) +} + +type pat_id_map = std::map::hashmap; + +// This is used because same-named variables in alternative patterns need to +// use the node_id of their namesake in the first pattern. +fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map { + let map = std::map::new_str_hash::(); + pat_bindings(normalize_pat(tcx, pat)) {|bound| + let name = path_to_ident(alt bound.node + { pat_ident(n, _) { n } }); + map.insert(name, bound.id); + }; + ret map; +} + +// This does *not* normalize. The pattern should be already normalized +// if you want to get a normalized pattern out of it. +// Could return a constrained type in order to express that (future work) +fn pat_bindings(pat: @pat, it: block(@pat)) { + alt pat.node { + pat_ident(_, option::none.) { it(pat); } + pat_ident(_, option::some(sub)) { it(pat); pat_bindings(sub, it); } + pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } } + pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } } + pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } } + pat_box(sub) { pat_bindings(sub, it); } + pat_uniq(sub) { pat_bindings(sub, it); } + pat_wild. | pat_lit(_) | pat_range(_, _) { } + } +} + +fn pat_binding_ids(pat: @pat) -> [node_id] { + let found = []; + pat_bindings(pat) {|b| found += [b.id]; }; + ret found; +} + +fn path_to_ident(p: @path) -> ident { + alt vec::last(p.node.idents) { + none. { // sigh + fail "Malformed path"; } + some(i) { ret i; } + } +} diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 5b9925c2ce5d..6ccc8cc12bea 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -3,6 +3,7 @@ import syntax::{ast, ast_util, codemap}; import syntax::ast::*; import ast::{ident, fn_ident, def, def_id, node_id}; import syntax::ast_util::{local_def, def_id_of_def}; +import pat_util::*; import front::attr; import metadata::{csearch, cstore}; @@ -181,10 +182,12 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) -> sess: sess}; map_crate(e, crate); resolve_imports(*e); - check_for_collisions(e, *crate); check_exports(e); resolve_names(e, crate); resolve_impls(e, crate); + // check_for_collisions must happen after resolve_names so we + // don't complain if a pattern uses the same nullary tag twice + check_for_collisions(e, *crate); if sess.opts.warn_unused_imports { check_unused_imports(e); } @@ -417,6 +420,20 @@ fn resolve_names(e: @env, c: @ast::crate) { } } } + /* Here we determine whether a given pat_ident binds a new + variable a refers to a nullary tag. */ + ast::pat_ident(p, none.) { + let fnd = lookup_in_scope(*e, sc, p.span, path_to_ident(p), + ns_val(ns_a_tag)); + alt fnd { + some(ast::def_variant(did, vid)) { + e.def_map.insert(pat.id, ast::def_variant(did, vid)); + } + _ { + // Binds a var -- nothing needs to be done + } + } + } _ { } } } @@ -539,30 +556,32 @@ fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt) { } } +// This is only for irrefutable patterns (e.g. ones that appear in a let) +// So if x occurs, and x is already known to be a tag, that's always an error. fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt) { - // Checks whether the given local has the same name as a tag that's + // Check whether the given local has the same name as a tag that's // in scope // We disallow this, in order to make alt patterns consisting of // a single identifier unambiguous (does the pattern "foo" refer // to tag foo, or is it binding a new name foo?) alt loc.node.pat.node { - pat_bind(an_ident,_) { + pat_ident(an_ident,_) { // Be sure to pass ns_a_tag to lookup_in_scope so that // if this is a name that's being shadowed, we don't die - alt lookup_in_scope(*e, sc, loc.span, an_ident, ns_val(ns_a_tag)) { + alt lookup_in_scope(*e, sc, loc.span, + path_to_ident(an_ident), ns_val(ns_a_tag)) { some(ast::def_variant(tag_id,variant_id)) { // Declaration shadows a tag that's in scope. // That's an error. e.sess.span_err(loc.span, #fmt("Declaration of %s shadows a tag that's in scope", - an_ident)); + path_to_ident(an_ident))); } _ {} } } _ {} } - visit::visit_local(loc, sc, v); } @@ -907,7 +926,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace) } scope_loop(local) { if ns == ns_val(ns_any_value) { - alt lookup_in_pat(name, local.node.pat) { + alt lookup_in_pat(e, name, local.node.pat) { some(did) { ret some(ast::def_binding(did)); } _ { } } @@ -918,7 +937,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace) } scope_arm(a) { if ns == ns_val(ns_any_value) { - alt lookup_in_pat(name, a.pats[0]) { + alt lookup_in_pat(e, name, a.pats[0]) { some(did) { ret some(ast::def_binding(did)); } _ { ret none; } } @@ -997,11 +1016,13 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param]) ret none::; } -fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t { +fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option::t { let found = none; - ast_util::pat_bindings(pat) {|bound| - let p_name = alt bound.node { ast::pat_bind(n, _) { n } }; - if str::eq(p_name, name) { found = some(local_def(bound.id)); } + + pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat)) {|bound| + let p_name = alt bound.node { ast::pat_ident(n, _) { n } }; + if str::eq(path_to_ident(p_name), name) + { found = some(local_def(bound.id)); } }; ret found; } @@ -1041,7 +1062,7 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint, let (style, loc) = locs[j]; if ns == ns_val(ns_any_value) && (i < pos || j < loc_pos) { - alt lookup_in_pat(name, loc.node.pat) { + alt lookup_in_pat(e, name, loc.node.pat) { some(did) { ret some(ast::def_local(did, style)); } @@ -1571,9 +1592,9 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) { } } -fn check_pat(ch: checker, p: @ast::pat) { - ast_util::pat_bindings(p) {|p| - let ident = alt p.node { pat_bind(n, _) { n } }; +fn check_pat(e: @env, ch: checker, p: @ast::pat) { + pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|p| + let ident = path_to_ident(alt p.node { pat_ident(n, _) { n } }); add_name(ch, p.span, ident); }; } @@ -1581,13 +1602,13 @@ fn check_pat(ch: checker, p: @ast::pat) { fn check_arm(e: @env, a: ast::arm, &&x: (), v: vt<()>) { visit::visit_arm(a, x, v); let ch0 = checker(*e, "binding"); - check_pat(ch0, a.pats[0]); + check_pat(e, ch0, a.pats[0]); let seen0 = ch0.seen; let i = vec::len(a.pats); while i > 1u { i -= 1u; let ch = checker(*e, "binding"); - check_pat(ch, a.pats[i]); + check_pat(e, ch, a.pats[i]); // Ensure the bindings introduced in this pattern are the same as in // the first pattern. @@ -1620,8 +1641,11 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) { ast::decl_local(locs) { let local_values = checker(*e, "value"); for (_, loc) in locs { - ast_util::pat_bindings(loc.node.pat) {|p| - let ident = alt p.node { pat_bind(n, _) { n } }; + pat_util::pat_bindings + (normalize_pat_def_map(e.def_map, loc.node.pat)) + {|p| + let ident = path_to_ident(alt p.node + { pat_ident(n, _) { n } }); add_name(local_values, p.span, ident); check_name(values, p.span, ident); }; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 2a029c22b3d5..314385a9f25a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -26,7 +26,8 @@ import back::{link, abi, upcall}; import syntax::{ast, ast_util, codemap}; import syntax::visit; import syntax::codemap::span; -import syntax::print::pprust::{expr_to_str, stmt_to_str}; +import syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str}; +import pat_util::*; import visit::vt; import util::common::*; import lib::llvm::{llvm, mk_target_data, mk_type_names}; @@ -775,6 +776,8 @@ fn GEP_tag(cx: @block_ctxt, llblobptr: ValueRef, tag_id: ast::def_id, let true_arg_tys: [ty::t] = []; for aty: ty::t in arg_tys { + // Would be nice to have a way of stating the invariant + // that ty_substs is valid for aty let arg_ty = ty::substitute_type_params(bcx_tcx(cx), ty_substs, aty); true_arg_tys += [arg_ty]; } @@ -2203,7 +2206,7 @@ fn trans_eager_binop(cx: @block_ctxt, op: ast::binop, lhs: ValueRef, if is_float { FAdd(cx, lhs, rhs) } else { Add(cx, lhs, rhs) } } - ast::sub. { + ast::subtract. { if is_float { FSub(cx, lhs, rhs) } else { Sub(cx, lhs, rhs) } } @@ -2641,6 +2644,7 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result { alt table.find(id) { some(local_mem(v)) { {val: v, kind: owned} } some(local_imm(v)) { {val: v, kind: owned_imm} } + r { fail("take_local: internal error"); } } } alt def { @@ -2649,9 +2653,11 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result { ret { val: cx.fcx.llupvars.get(did.node), kind: owned }; } ast::def_arg(did, _) { + assert (cx.fcx.llargs.contains_key(did.node)); ret take_local(cx.fcx.llargs, did.node); } ast::def_local(did, _) | ast::def_binding(did) { + assert (cx.fcx.lllocals.contains_key(did.node)); ret take_local(cx.fcx.lllocals, did.node); } ast::def_self(did) { @@ -3502,6 +3508,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { ret trans_expr(bcx, ast_util::ternary_to_if(e), dest); } ast::expr_alt(expr, arms) { + // tcx.sess.span_note(e.span, "about to call trans_alt"); ret trans_alt::trans_alt(bcx, expr, arms, dest); } ast::expr_block(blk) { @@ -4205,8 +4212,9 @@ fn alloc_ty(cx: @block_ctxt, t: ty::t) -> result { fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt { let t = node_id_type(bcx_ccx(cx), local.node.id); - let is_simple = alt local.node.pat.node { - ast::pat_bind(_, none.) { true } _ { false } + let p = normalize_pat(bcx_tcx(cx), local.node.pat); + let is_simple = alt p.node { + ast::pat_ident(_, none.) { true } _ { false } }; // Do not allocate space for locals that can be kept immediate. let ccx = bcx_ccx(cx); @@ -4219,10 +4227,10 @@ fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt { } } let r = alloc_ty(cx, t); - alt local.node.pat.node { - ast::pat_bind(ident, none.) { + alt p.node { + ast::pat_ident(pth, none.) { if bcx_ccx(cx).sess.opts.debuginfo { - let _: () = str::as_buf(ident, {|buf| + let _: () = str::as_buf(path_to_ident(pth), {|buf| llvm::LLVMSetValueName(r.val, buf) }); } @@ -4635,7 +4643,7 @@ fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { if is_float { llvm::LLVMConstFAdd(te1, te2) } else { llvm::LLVMConstAdd(te1, te2) } } - ast::sub. { + ast::subtract. { if is_float { llvm::LLVMConstFSub(te1, te2) } else { llvm::LLVMConstSub(te1, te2) } } diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index a7eb94b92886..5addbebddc1a 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -1,8 +1,10 @@ import core::{str, vec, option}; import option::{some, none}; +import driver::session::session; import lib::llvm::llvm; import lib::llvm::llvm::{ValueRef, BasicBlockRef}; +import pat_util::*; import trans_build::*; import trans::{new_sub_block_ctxt, new_scope_block_ctxt, load_if_immediate}; import syntax::ast; @@ -10,6 +12,7 @@ import syntax::ast_util; import syntax::ast_util::{dummy_sp}; import syntax::ast::def_id; import syntax::codemap::span; +import syntax::print::pprust::pat_to_str; import trans_common::*; @@ -61,6 +64,7 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result { } } +// FIXME: invariant -- pat_id is bound in the def_map? fn variant_opt(ccx: @crate_ctxt, pat_id: ast::node_id) -> opt { let vdef = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat_id)); let variants = ty::tag_variants(ccx.tcx, vdef.tg); @@ -83,13 +87,13 @@ type match_branch = bound: bind_map, data: @{body: BasicBlockRef, guard: option::t<@ast::expr>, - id_map: ast_util::pat_id_map}}; + id_map: pat_id_map}}; type match = [match_branch]; fn has_nested_bindings(m: match, col: uint) -> bool { for br in m { alt br.pats[col].node { - ast::pat_bind(_, some(_)) { ret true; } + ast::pat_ident(_, some(_)) { ret true; } _ {} } } @@ -99,12 +103,13 @@ fn has_nested_bindings(m: match, col: uint) -> bool { fn expand_nested_bindings(m: match, col: uint, val: ValueRef) -> match { let result = []; for br in m { - alt br.pats[col].node { - ast::pat_bind(name, some(inner)) { + alt br.pats[col].node { + ast::pat_ident(name, some(inner)) { let pats = vec::slice(br.pats, 0u, col) + [inner] + vec::slice(br.pats, col + 1u, vec::len(br.pats)); result += [@{pats: pats, - bound: br.bound + [{ident: name, val: val}] + bound: br.bound + [{ident: path_to_ident(name), + val: val}] with *br}]; } _ { result += [br]; } @@ -124,8 +129,9 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match { vec::slice(br.pats, col + 1u, vec::len(br.pats)); let new_br = @{pats: pats, bound: alt br.pats[col].node { - ast::pat_bind(name, none.) { - br.bound + [{ident: name, val: val}] + ast::pat_ident(name, none.) { + br.bound + [{ident: path_to_ident(name), + val: val}] } _ { br.bound } } with *br}; @@ -139,11 +145,11 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match { fn enter_default(m: match, col: uint, val: ValueRef) -> match { fn matches_always(p: @ast::pat) -> bool { - ret alt p.node { - ast::pat_wild. | ast::pat_bind(_, none.) | ast::pat_rec(_, _) | - ast::pat_tup(_) { true } - _ { false } - }; + alt p.node { + ast::pat_wild. | ast::pat_rec(_, _) | + ast::pat_ident(_, none.) | ast::pat_tup(_) { true } + _ { false } + } } fn e(p: @ast::pat) -> option::t<[@ast::pat]> { ret if matches_always(p) { some([]) } else { none }; @@ -257,6 +263,8 @@ 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} { let ccx = bcx.fcx.lcx.ccx, bcx = bcx; + // invariant: + // pat_id must have the same length ty_param_substs as vdefs? let ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id); let blobptr = val; let variants = ty::tag_variants(ccx.tcx, vdefs.tg); @@ -274,6 +282,9 @@ fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id, while i < size { check (valid_variant_index(i, bcx, vdefs_tg, vdefs_var)); let r = + // invariant needed: + // how do we know it even makes sense to pass in ty_param_substs + // here? What if it's [] and the tag type has variables in it? trans::GEP_tag(bcx, blobptr, vdefs_tg, vdefs_var, ty_param_substs, i); bcx = r.bcx; @@ -328,7 +339,7 @@ fn pick_col(m: match) -> uint { fn score(p: @ast::pat) -> uint { alt p.node { ast::pat_lit(_) | ast::pat_tag(_, _) | ast::pat_range(_, _) { 1u } - ast::pat_bind(_, some(p)) { score(p) } + ast::pat_ident(_, some(p)) { score(p) } _ { 0u } } } @@ -582,7 +593,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail, // Returns false for unreachable blocks fn make_phi_bindings(bcx: @block_ctxt, map: [exit_node], - ids: ast_util::pat_id_map) -> bool { + ids: pat_util::pat_id_map) -> bool { let our_block = bcx.llbb as uint; let success = true, bcx = bcx; ids.items {|name, node_id| @@ -623,7 +634,7 @@ fn make_phi_bindings(bcx: @block_ctxt, map: [exit_node], ret success; } -fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm], +fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms_: [ast::arm], dest: trans::dest) -> @block_ctxt { let bodies = []; let match: match = []; @@ -633,9 +644,15 @@ fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm], let er = trans::trans_temp_expr(alt_cx, expr); if er.bcx.unreachable { ret er.bcx; } + /* + n.b. nothing else in this module should need to normalize, + b/c of this call + */ + let arms = normalize_arms(bcx_tcx(cx), arms_); + for a: ast::arm in arms { let body = new_scope_block_ctxt(er.bcx, "case_body"); - let id_map = ast_util::pat_id_map(a.pats[0]); + let id_map = pat_util::pat_id_map(bcx_tcx(cx), a.pats[0]); bodies += [body]; for p: @ast::pat in a.pats { match += @@ -666,7 +683,8 @@ fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm], for a: ast::arm in arms { let body_cx = bodies[i]; if make_phi_bindings(body_cx, exit_map, - ast_util::pat_id_map(a.pats[0])) { + pat_util::pat_id_map(bcx_tcx(cx), + a.pats[0])) { let arm_dest = trans::dup_for_join(dest); arm_dests += [arm_dest]; arm_cxs += [trans::trans_block_dps(body_cx, a.body, arm_dest)]; @@ -684,8 +702,10 @@ fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm], fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef, make_copy: bool) -> @block_ctxt { let ccx = bcx.fcx.lcx.ccx, bcx = bcx; - alt pat.node { - ast::pat_bind(_, inner) { + + // Necessary since bind_irrefutable_pat is called outside trans_alt + alt normalize_pat(bcx_tcx(bcx), pat).node { + ast::pat_ident(_,inner) { if make_copy || ccx.copy_map.contains_key(pat.id) { let ty = ty::node_id_to_monotype(ccx.tcx, pat.id); // FIXME: Could constrain pat_bind to make this diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs index d4dbf830a5f3..f44ac06e4c16 100644 --- a/src/comp/middle/tstate/annotate.rs +++ b/src/comp/middle/tstate/annotate.rs @@ -1,12 +1,12 @@ import core::{int, uint}; import syntax::ast::*; -import syntax::ast_util::pat_binding_ids; import syntax::visit; import syntax::codemap::span; import util::common::{log_stmt}; import aux::{num_constraints, get_fn_info, crate_ctxt, add_node}; -import middle::tstate::ann::empty_ann; +import ann::empty_ann; +import pat_util::pat_binding_ids; fn collect_ids_expr(e: @expr, rs: @mutable [node_id]) { *rs += [e.id]; } diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 5c0c6c78b3a8..cb592be250c2 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -1,5 +1,6 @@ import core::{vec, int, uint, option}; import option::*; +import pat_util::*; import syntax::ast::*; import syntax::ast_util::*; import syntax::{visit, codemap}; @@ -69,10 +70,10 @@ fn tritv_to_str(fcx: fn_ctxt, v: tritv::t) -> str { for p: norm_constraint in constraints(fcx) { alt tritv_get(v, p.bit_num) { dont_care. { } - t { + tt { s += if comma { ", " } else { comma = true; "" } + - if t == tfalse { "!" } else { "" } + + if tt == tfalse { "!" } else { "" } + constraint_to_str(fcx.ccx.tcx, p.c); } } @@ -313,7 +314,7 @@ fn node_id_to_ts_ann(ccx: crate_ctxt, id: node_id) -> ts_ann { #error("node_id_to_ts_ann: no ts_ann for node_id %d", id); fail; } - some(t) { ret t; } + some(tt) { ret tt; } } } @@ -779,13 +780,6 @@ fn replace(subst: subst, d: pred_args) -> [constr_arg_general_] { ret rslt; } -fn path_to_ident(cx: ty::ctxt, p: @path) -> ident { - alt vec::last(p.node.idents) { - none. { cx.sess.span_fatal(p.span, "Malformed path"); } - some(i) { ret i; } - } -} - tag if_ty { if_check; plain_if; } fn local_node_id_to_def_id_strict(fcx: fn_ctxt, sp: span, i: node_id) -> @@ -1059,18 +1053,20 @@ fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: [arg], c: @constr) -> type binding = {lhs: [inst], rhs: option::t}; -fn local_to_bindings(loc: @local) -> binding { +fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding { let lhs = []; - pat_bindings(loc.node.pat) {|p| - let ident = alt p.node { pat_bind(name, _) { name } }; + pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p| + let ident = alt p.node + { pat_ident(name, _) { path_to_ident(name) } }; lhs += [{ident: ident, node: p.id}]; }; {lhs: lhs, rhs: loc.node.init} } -fn locals_to_bindings(locals: [(let_style, @local)]) -> [binding] { +fn locals_to_bindings(tcx: ty::ctxt, + locals: [(let_style, @local)]) -> [binding] { let rslt = []; - for (_, loc) in locals { rslt += [local_to_bindings(loc)]; } + for (_, loc) in locals { rslt += [local_to_bindings(tcx, loc)]; } ret rslt; } diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index f303e7901894..102451a6985f 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -1,18 +1,20 @@ +import option::*; +import pat_util::*; import syntax::ast::*; import syntax::ast_util::*; -import option::*; import syntax::visit; -import aux::*; import util::common::new_def_hash; import syntax::codemap::span; import syntax::ast_util::respan; import driver::session::session; +import aux::*; type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt}; fn collect_local(loc: @local, cx: ctxt, v: visit::vt) { - pat_bindings(loc.node.pat) {|p| - let ident = alt p.node { pat_bind(id, _) { id } }; + pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat)) {|p| + let ident = alt p.node + { pat_ident(id, _) { path_to_ident(id) } }; log(debug, "collect_local: pushing " + ident);; *cx.cs += [respan(loc.span, ninit(p.id, ident))]; }; diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 7d52c5882a3f..57bb03797792 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -8,6 +8,8 @@ import bitvectors::{bit_num, seq_preconds, seq_postconds, intersect_states, relax_precond_block, gen}; import tritv::*; + +import pat_util::*; import syntax::ast::*; import syntax::ast_util::*; import syntax::visit; @@ -16,6 +18,7 @@ import util::common::{new_def_hash, log_expr, field_exprs, import syntax::codemap::span; import driver::session::session; + fn find_pre_post_mod(_m: _mod) -> _mod { #debug("implement find_pre_post_mod!"); fail; @@ -103,8 +106,9 @@ 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); - pat_bindings(l.node.pat) {|p| - let ident = alt p.node { pat_bind(id, _) { id } }; + pat_bindings(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p| + let ident = alt p.node + { pat_ident(id, _) { path_to_ident(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, @@ -197,7 +201,7 @@ fn gen_if_local(fcx: fn_ctxt, lhs: @expr, rhs: @expr, larger_id: node_id, set_pre_and_post(fcx.ccx, larger_id, p.precondition, p.postcondition); gen(fcx, larger_id, - ninit(d_id.node, path_to_ident(fcx.ccx.tcx, pth))); + ninit(d_id.node, path_to_ident(pth))); } _ { find_pre_post_exprs(fcx, [lhs, rhs], larger_id); } } @@ -232,7 +236,7 @@ fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr, def_local(d_id, _) { let i = bit_num(fcx, - ninit(d_id.node, path_to_ident(fcx.ccx.tcx, p))); + ninit(d_id.node, path_to_ident(p))); require_and_preserve(i, expr_pp(fcx.ccx, lhs)); } _ { } @@ -250,9 +254,9 @@ fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr, alt d1 { some(id1) { let instlhs = - {ident: path_to_ident(fcx.ccx.tcx, p), node: id}; + {ident: path_to_ident(p), node: id}; let instrhs = - {ident: path_to_ident(fcx.ccx.tcx, p1), node: id1}; + {ident: path_to_ident(p1), node: id1}; copy_in_poststate_two(fcx, tmp, post, instlhs, instrhs, ty); } @@ -340,7 +344,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { expr_path(p) { let rslt = expr_pp(fcx.ccx, e); clear_pp(rslt); - handle_var(fcx, rslt, e.id, path_to_ident(fcx.ccx.tcx, p)); + handle_var(fcx, rslt, e.id, path_to_ident(p)); } expr_log(_, lvl, arg) { find_pre_post_exprs(fcx, [lvl, arg], e.id); @@ -581,18 +585,19 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { _ { } } - pat_bindings(alocal.node.pat) {|pat| + pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat)) + {|pat| /* FIXME: This won't be necessary when typestate works well enough for pat_bindings to return a refinement-typed thing. */ - let ident = alt pat.node { pat_bind(n, _) { n } }; + let ident = alt pat.node + { pat_ident(n, _) { path_to_ident(n) } }; alt p { some(p) { copy_in_postcond(fcx, id, {ident: ident, node: pat.id}, {ident: - path_to_ident(fcx.ccx.tcx, - p), + path_to_ident(p), node: an_init.expr.id}, op_to_oper_ty(an_init.op)); } @@ -612,11 +617,14 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { seq_preconds(fcx, [prev_pp, e_pp])); /* Include the LHSs too, since those aren't in the postconds of the RHSs themselves */ - pat_bindings(alocal.node.pat) {|pat| + pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat)) + {|pat| + // FIXME + // Generalize this pattern? map_if_ident... alt pat.node { - pat_bind(n, _) { - set_in_postcond(bit_num(fcx, ninit(pat.id, n)), - prev_pp); + pat_ident(n, _) { + set_in_postcond(bit_num(fcx, + ninit(pat.id, path_to_ident(n))), prev_pp); } } }; diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index adfc4411adb0..50208b9dacf2 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -5,6 +5,7 @@ import aux::*; import tritv::{tritv_clone, tritv_set, ttrue}; import bitvectors::*; +import pat_util::*; import syntax::ast::*; import syntax::ast_util::*; import syntax::codemap::span; @@ -37,7 +38,7 @@ fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path, some(rhsid) { // RHS is a local var let instrhs = - {ident: path_to_ident(fcx.ccx.tcx, rhs_path), node: rhsid.node}; + {ident: path_to_ident(rhs_path), node: rhsid.node}; copy_in_poststate(fcx, post, instlhs, instrhs, op_to_oper_ty(init_op)); } @@ -143,9 +144,9 @@ fn find_pre_post_state_two(fcx: fn_ctxt, pres: prestate, lhs: @expr, alt d1 { some(id1) { let instlhs = - {ident: path_to_ident(fcx.ccx.tcx, p), node: id}; + {ident: path_to_ident(p), node: id}; let instrhs = - {ident: path_to_ident(fcx.ccx.tcx, p1), node: id1}; + {ident: path_to_ident(p1), node: id1}; copy_in_poststate_two(fcx, tmp, post, instlhs, instrhs, ty); } @@ -206,8 +207,9 @@ fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local, // Make sure the index vars are considered initialized // in the body let index_post = tritv_clone(expr_poststate(fcx.ccx, index)); - pat_bindings(l.node.pat) {|p| - let ident = alt p.node { pat_bind(name, _) { name } }; + pat_bindings(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p| + let ident = alt p.node + { pat_ident(name, _) { path_to_ident(name) } }; set_in_poststate_ident(fcx, p.id, ident, index_post); }; @@ -231,7 +233,7 @@ fn gen_if_local(fcx: fn_ctxt, p: poststate, e: @expr) -> bool { alt fcx.ccx.tcx.def_map.find(e.id) { some(def_local(loc, _)) { ret set_in_poststate_ident(fcx, loc.node, - path_to_ident(fcx.ccx.tcx, pth), p); + path_to_ident(pth), p); } _ { ret false; } } @@ -632,7 +634,8 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool { alt adecl.node { decl_local(alocals) { set_prestate(stmt_ann, pres); - let c_and_p = seq_states(fcx, pres, locals_to_bindings(alocals)); + let c_and_p = seq_states(fcx, pres, + locals_to_bindings(fcx.ccx.tcx, alocals)); /* important to do this in one step to ensure termination (don't want to set changed to true for intermediate changes) */ diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index d44b0ee0072f..59fd826791a3 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -371,6 +371,8 @@ const idx_first_others: uint = 20u; type type_store = interner::interner<@raw_t>; +// substs is a list of actuals that correspond to ty's +// formal parameters type ty_param_substs_opt_and_ty = {substs: option::t<[ty::t]>, ty: ty::t}; type node_type_table = @@ -2215,7 +2217,7 @@ mod unify { ty::ty_box(expected_mt) { alt struct(cx.tcx, actual) { ty::ty_box(actual_mt) { - let (mut, var) = alt unify_mut( + let (mutt, var) = alt unify_mut( expected_mt.mut, actual_mt.mut, variance) { none. { ret ures_err(terr_box_mutability); } some(mv) { mv } @@ -2224,7 +2226,7 @@ mod unify { cx, expected_mt.ty, actual_mt.ty, var); alt result { ures_ok(result_sub) { - let mt = {ty: result_sub, mut: mut}; + let mt = {ty: result_sub, mut: mutt}; ret ures_ok(mk_box(cx.tcx, mt)); } _ { ret result; } @@ -2236,7 +2238,7 @@ mod unify { ty::ty_uniq(expected_mt) { alt struct(cx.tcx, actual) { ty::ty_uniq(actual_mt) { - let (mut, var) = alt unify_mut( + let (mutt, var) = alt unify_mut( expected_mt.mut, actual_mt.mut, variance) { none. { ret ures_err(terr_box_mutability); } some(mv) { mv } @@ -2245,7 +2247,7 @@ mod unify { cx, expected_mt.ty, actual_mt.ty, var); alt result { ures_ok(result_mt) { - let mt = {ty: result_mt, mut: mut}; + let mt = {ty: result_mt, mut: mutt}; ret ures_ok(mk_uniq(cx.tcx, mt)); } _ { ret result; } @@ -2257,7 +2259,7 @@ mod unify { ty::ty_vec(expected_mt) { alt struct(cx.tcx, actual) { ty::ty_vec(actual_mt) { - let (mut, var) = alt unify_mut( + let (mutt, var) = alt unify_mut( expected_mt.mut, actual_mt.mut, variance) { none. { ret ures_err(terr_vec_mutability); } some(mv) { mv } @@ -2266,7 +2268,7 @@ mod unify { cx, expected_mt.ty, actual_mt.ty, var); alt result { ures_ok(result_sub) { - let mt = {ty: result_sub, mut: mut}; + let mt = {ty: result_sub, mut: mutt}; ret ures_ok(mk_vec(cx.tcx, mt)); } _ { ret result; } @@ -2278,7 +2280,7 @@ mod unify { ty::ty_ptr(expected_mt) { alt struct(cx.tcx, actual) { ty::ty_ptr(actual_mt) { - let (mut, var) = alt unify_mut( + let (mutt, var) = alt unify_mut( expected_mt.mut, actual_mt.mut, variance) { none. { ret ures_err(terr_vec_mutability); } some(mv) { mv } @@ -2287,7 +2289,7 @@ mod unify { cx, expected_mt.ty, actual_mt.ty, var); alt result { ures_ok(result_sub) { - let mt = {ty: result_sub, mut: mut}; + let mt = {ty: result_sub, mut: mutt}; ret ures_ok(mk_ptr(cx.tcx, mt)); } _ { ret result; } @@ -2342,7 +2344,7 @@ mod unify { while i < expected_len { let expected_field = expected_fields[i]; let actual_field = actual_fields[i]; - let (mut, var) = alt unify_mut( + let (mutt, var) = alt unify_mut( expected_field.mt.mut, actual_field.mt.mut, variance) { none. { ret ures_err(terr_record_mutability); } @@ -2359,7 +2361,7 @@ mod unify { actual_field.mt.ty, var); alt result { ures_ok(rty) { - let mt = {ty: rty, mut: mut}; + let mt = {ty: rty, mut: mutt}; result_fields += [{mt: mt with expected_field}]; } _ { ret result; } @@ -2579,11 +2581,18 @@ fn type_err_to_str(err: ty::type_err) -> str { // Replaces type parameters in the given type using the given list of // substitions. fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t { - if !type_contains_params(cx, typ) { ret typ; } + + if !type_contains_params(cx, typ) { ret typ; } + // Precondition? idx < vec::len(substs) fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id) -> t { - // FIXME: bounds check can fail - ret substs[idx]; + if idx < vec::len(*substs) { + ret substs[idx]; + } + else { + fail #fmt("Internal error in substituter (substitute_type_params)\ + %u %u", vec::len(*substs), idx); + } } ret fold_ty(cx, fm_param(bind substituter(cx, @substs, _, _)), typ); } @@ -2729,7 +2738,7 @@ fn is_binopable(cx: ctxt, ty: t, op: ast::binop) -> bool { fn opcat(op: ast::binop) -> int { alt op { ast::add. { opcat_add } - ast::sub. { opcat_sub } + ast::subtract. { opcat_sub } ast::mul. { opcat_mult } ast::div. { opcat_mult } ast::rem. { opcat_mult } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index c7736056a502..d447dfcfce4b 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -6,6 +6,7 @@ import metadata::csearch; import driver::session::session; import util::common::*; import syntax::codemap::span; +import pat_util::*; import middle::ty; import middle::ty::{node_id_to_type, arg, block_ty, expr_ty, field, node_type_table, mk_nil, @@ -1137,8 +1138,8 @@ fn gather_locals(ccx: @crate_ctxt, // Add pattern bindings. let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) { - alt p.node { - ast::pat_bind(_, _) { assign(p.id, none); } + alt normalize_pat(ccx.tcx, p).node { + ast::pat_ident(_, _) { assign(p.id, none); } _ {/* no-op */ } } visit::visit_pat(p, e, v); @@ -1181,9 +1182,9 @@ fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool { // Pattern checking is top-down rather than bottom-up so that bindings get // their types immediately. -fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat, +fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat, expected: ty::t) { - alt pat.node { + alt normalize_pat(fcx.ccx.tcx, pat).node { ast::pat_wild. { alt structure_of(fcx, pat.span, expected) { ty::ty_tag(_, expected_tps) { @@ -1218,11 +1219,11 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat, } write::ty_only_fixup(fcx, pat.id, b_ty); } - ast::pat_bind(name, sub) { + ast::pat_ident(name, sub) { let vid = lookup_local(fcx, pat.span, pat.id); let typ = ty::mk_var(fcx.ccx.tcx, vid); typ = demand::simple(fcx, pat.span, expected, typ); - let canon_id = map.get(name); + let canon_id = map.get(path_to_ident(name)); if canon_id != pat.id { let ct = ty::mk_var(fcx.ccx.tcx, @@ -2014,7 +2015,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, // bindings. let pattern_ty = ty::expr_ty(tcx, expr); for arm: ast::arm in arms { - let id_map = ast_util::pat_id_map(arm.pats[0]); + let id_map = pat_util::pat_id_map(tcx, arm.pats[0]); for p: @ast::pat in arm.pats { check_pat(fcx, id_map, p, pattern_ty); } @@ -2360,7 +2361,7 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { } _ {/* fall through */ } } - let id_map = ast_util::pat_id_map(local.node.pat); + let id_map = pat_util::pat_id_map(fcx.ccx.tcx, local.node.pat); check_pat(fcx, id_map, local.node.pat, t); } } diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index f688be64374b..db36e6adc961 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -39,6 +39,7 @@ mod middle { mod gc; mod debuginfo; mod capture; + mod pat_util; mod tstate { mod ck; diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index b953362b1be8..6419e690c440 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -97,7 +97,17 @@ type field_pat = {ident: ident, pat: @pat}; tag pat_ { pat_wild; - pat_bind(ident, option::t<@pat>); + // A pat_ident may either be a new bound variable, + // or a nullary tag (in which case the second field + // is none). + // In the nullary tag case, the parser can't determine + // which it is. The resolver determines this, and + // records this pattern's node_id in an auxiliary + // set (of "pat_idents that refer to nullary tags") + // After the resolution phase, code should never pattern- + // match on a pat directly! Always call pat_util::normalize_pat -- + // it turns any pat_idents that refer to nullary tags into pat_tags. + pat_ident(@path, option::t<@pat>); pat_tag(@path, [@pat]); pat_rec([field_pat], bool); pat_tup([@pat]); @@ -126,7 +136,7 @@ pure fn is_blockish(p: ast::proto) -> bool { tag binop { add; - sub; + subtract; mul; div; rem; diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index eaac7fa9596a..ed65aa11df9e 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -33,43 +33,10 @@ fn def_id_of_def(d: def) -> def_id { } } -type pat_id_map = std::map::hashmap; - -// This is used because same-named variables in alternative patterns need to -// use the node_id of their namesake in the first pattern. -fn pat_id_map(pat: @pat) -> pat_id_map { - let map = std::map::new_str_hash::(); - pat_bindings(pat) {|bound| - let name = alt bound.node { pat_bind(n, _) { n } }; - map.insert(name, bound.id); - }; - ret map; -} - -// FIXME: could return a constrained type -fn pat_bindings(pat: @pat, it: block(@pat)) { - alt pat.node { - pat_bind(_, option::none.) { it(pat); } - pat_bind(_, option::some(sub)) { it(pat); pat_bindings(sub, it); } - pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } } - pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } } - pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } } - pat_box(sub) { pat_bindings(sub, it); } - pat_uniq(sub) { pat_bindings(sub, it); } - pat_wild. | pat_lit(_) | pat_range(_, _) { } - } -} - -fn pat_binding_ids(pat: @pat) -> [node_id] { - let found = []; - pat_bindings(pat) {|b| found += [b.id]; }; - ret found; -} - fn binop_to_str(op: binop) -> str { alt op { add. { ret "+"; } - sub. { ret "-"; } + subtract. { ret "-"; } mul. { ret "*"; } div. { ret "/"; } rem. { ret "%"; } @@ -262,7 +229,7 @@ fn eval_const_expr(e: @expr) -> const_val { alt (eval_const_expr(a), eval_const_expr(b)) { (const_float(a), const_float(b)) { alt op { - add. { const_float(a + b) } sub. { const_float(a - b) } + add. { const_float(a + b) } subtract. { const_float(a - b) } mul. { const_float(a * b) } div. { const_float(a / b) } rem. { const_float(a % b) } eq. { fromb(a == b) } lt. { fromb(a < b) } le. { fromb(a <= b) } ne. { fromb(a != b) } @@ -271,7 +238,7 @@ fn eval_const_expr(e: @expr) -> const_val { } (const_int(a), const_int(b)) { alt op { - add. { const_int(a + b) } sub. { const_int(a - b) } + add. { const_int(a + b) } subtract. { const_int(a - b) } mul. { const_int(a * b) } div. { const_int(a / b) } rem. { const_int(a % b) } and. | bitand. { const_int(a & b) } or. | bitor. { const_int(a | b) } bitxor. { const_int(a ^ b) } @@ -282,7 +249,7 @@ fn eval_const_expr(e: @expr) -> const_val { } (const_uint(a), const_uint(b)) { alt op { - add. { const_uint(a + b) } sub. { const_uint(a - b) } + add. { const_uint(a + b) } subtract. { const_uint(a - b) } mul. { const_uint(a * b) } div. { const_uint(a / b) } rem. { const_uint(a % b) } and. | bitand. { const_uint(a & b) } or. | bitor. { const_uint(a | b) } bitxor. { const_uint(a ^ b) } @@ -327,6 +294,10 @@ fn lit_eq(a: @lit, b: @lit) -> bool { compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0 } +fn ident_to_path(s: span, i: ident) -> @path { + @respan(s, {global: false, idents: [i], types: []}) +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index e74e1cd9ba75..a5ce71f8cd50 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -10,6 +10,7 @@ export make_fold; export noop_fold_crate; export noop_fold_item; export noop_fold_expr; +export noop_fold_pat; export noop_fold_mod; export noop_fold_ty; @@ -273,8 +274,8 @@ fn noop_fold_arm(a: arm, fld: ast_fold) -> arm { fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ { ret alt p { pat_wild. { p } - pat_bind(ident, sub) { - pat_bind(fld.fold_ident(ident), option::map(sub, fld.fold_pat)) + pat_ident(pth, sub) { + pat_ident(fld.fold_path(pth), option::map(sub, fld.fold_pat)) } pat_lit(_) { p } pat_tag(pth, pats) { @@ -317,8 +318,8 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { let fold_mac = bind fold_mac_(_, fld); ret alt e { - expr_vec(exprs, mut) { - expr_vec(fld.map_exprs(fld.fold_expr, exprs), mut) + expr_vec(exprs, mutt) { + expr_vec(fld.map_exprs(fld.fold_expr, exprs), mutt) } expr_rec(fields, maybe_expr) { expr_rec(vec::map(fields, fold_field), @@ -390,8 +391,7 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { } expr_path(pth) { expr_path(fld.fold_path(pth)) } expr_fail(e) { expr_fail(option::map(e, fld.fold_expr)) } - expr_break. { e } - expr_cont. { e } + expr_break. | expr_cont. { e } expr_ret(e) { expr_ret(option::map(e, fld.fold_expr)) } expr_be(e) { expr_be(fld.fold_expr(e)) } expr_log(i, lv, e) { expr_log(i, fld.fold_expr(lv), diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index ef65a0bd8971..b8f55dcba963 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -8,6 +8,7 @@ import token::can_begin_expr; import codemap::span; import util::interner; import ast::{node_id, spanned}; +import ast_util::{mk_sp, ident_to_path}; import front::attr; import lexer::reader; import driver::diagnostic; @@ -1097,7 +1098,7 @@ fn prec_table() -> @[op_spec] { {tok: token::BINOP(token::SLASH), op: ast::div, prec: 11}, {tok: token::BINOP(token::PERCENT), op: ast::rem, prec: 11}, {tok: token::BINOP(token::PLUS), op: ast::add, prec: 10}, - {tok: token::BINOP(token::MINUS), op: ast::sub, prec: 10}, + {tok: token::BINOP(token::MINUS), op: ast::subtract, prec: 10}, {tok: token::BINOP(token::LSL), op: ast::lsl, prec: 9}, {tok: token::BINOP(token::LSR), op: ast::lsr, prec: 9}, {tok: token::BINOP(token::ASR), op: ast::asr, prec: 9}, @@ -1165,7 +1166,7 @@ fn parse_assign_expr(p: parser) -> @ast::expr { let aop = ast::add; alt op { token::PLUS. { aop = ast::add; } - token::MINUS. { aop = ast::sub; } + token::MINUS. { aop = ast::subtract; } token::STAR. { aop = ast::mul; } token::SLASH. { aop = ast::div; } token::PERCENT. { aop = ast::rem; } @@ -1426,7 +1427,11 @@ fn parse_pat(p: parser) -> @ast::pat { break; } + let lo1 = p.last_span.lo; let fieldname = parse_ident(p); + let hi1 = p.last_span.lo; + let fieldpath = ast_util::ident_to_path(ast_util::mk_sp(lo1, hi1), + fieldname); let subpat; if p.token == token::COLON { p.bump(); @@ -1436,7 +1441,7 @@ fn parse_pat(p: parser) -> @ast::pat { p.fatal("found " + fieldname + " in binding position"); } subpat = @{id: p.get_id(), - node: ast::pat_bind(fieldname, none), + node: ast::pat_ident(fieldpath, none), span: ast_util::mk_sp(lo, hi)}; } fields += [{ident: fieldname, pat: subpat}]; @@ -1478,7 +1483,10 @@ fn parse_pat(p: parser) -> @ast::pat { } } else if is_plain_ident(p) && alt p.look_ahead(1u) { - token::DOT. | token::LPAREN. | token::LBRACKET. { + // Take this out once the libraries change + token::DOT. | + token::LPAREN. | token::LBRACKET. | + token::LT. { false } _ { true } @@ -1486,7 +1494,7 @@ fn parse_pat(p: parser) -> @ast::pat { hi = p.span.hi; let name = parse_value_ident(p); let sub = eat(p, token::AT) ? some(parse_pat(p)) : none; - pat = ast::pat_bind(name, sub); + pat = ast::pat_ident(ident_to_path(mk_sp(lo, hi), name), sub); } else { let tag_path = parse_path_and_ty_param_substs(p, true); hi = tag_path.span.hi; @@ -1499,10 +1507,19 @@ fn parse_pat(p: parser) -> @ast::pat { args = a.node; hi = a.span.hi; } + token::LBRACE. { args = []; } + // take this out once the libraries change token::DOT. { args = []; p.bump(); } _ { expect(p, token::LPAREN); fail; } } - pat = ast::pat_tag(tag_path, args); + // at this point, we're not sure whether it's a tag or a bind + if vec::len(args) == 0u && + vec::len(tag_path.node.idents) == 1u { + pat = ast::pat_ident(tag_path, none); + } + else { + pat = ast::pat_tag(tag_path, args); + } } } } diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 092fb5780b1f..258012c4f490 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -1055,10 +1055,12 @@ fn print_pat(s: ps, &&pat: @ast::pat) { maybe_print_comment(s, pat.span.lo); let ann_node = node_pat(s, pat); s.ann.pre(ann_node); + /* Pat isn't normalized, but the beauty of it + is that it doesn't matter */ alt pat.node { ast::pat_wild. { word(s.s, "_"); } - ast::pat_bind(id, sub) { - word(s.s, id); + ast::pat_ident(path, sub) { + print_path(s, path, true); alt sub { some(p) { word(s.s, "@"); print_pat(s, p); } _ {} @@ -1070,7 +1072,7 @@ fn print_pat(s: ps, &&pat: @ast::pat) { popen(s); commasep(s, inconsistent, args, print_pat); pclose(s); - } else { word(s.s, "."); } + } else { word(s.s, "."); } // FIXME } ast::pat_rec(fields, etc) { word(s.s, "{"); diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index d4cd956d2f19..a48b949bad1e 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -195,9 +195,13 @@ fn visit_pat(p: @pat, e: E, v: vt) { for f: field_pat in fields { v.visit_pat(f.pat, e, v); } } pat_tup(elts) { for elt in elts { v.visit_pat(elt, e, v); } } - pat_box(inner) | pat_uniq(inner) | pat_bind(_, some(inner)) { + pat_box(inner) | pat_uniq(inner) { v.visit_pat(inner, e, v); } + pat_ident(path, inner) { + visit_path(path, e, v); + option::may(inner, {|subpat| v.visit_pat(subpat, e, v)}); + } _ { } } } diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs index 8071ee728476..55175873f5a4 100644 --- a/src/libstd/rope.rs +++ b/src/libstd/rope.rs @@ -1278,7 +1278,7 @@ mod node { while true { alt(get_current_or_next_leaf(it)) { option::none. { ret option::none; } - option::some(leaf) { + option::some(_) { let next_char = get_next_char_in_leaf(it); alt(next_char) { option::none. { @@ -1301,7 +1301,7 @@ mod node { let next = leaf_iterator::next(it.leaf_iterator); alt(next) { option::none. { ret option::none } - option::some(leaf) { + option::some(_) { it.leaf = next; it.leaf_byte_pos = 0u; ret next; @@ -1314,16 +1314,16 @@ mod node { fn get_next_char_in_leaf(it: t) -> option::t { alt(it.leaf) { option::none. { ret option::none } - option::some(leaf) { - if it.leaf_byte_pos >= leaf.byte_len { + option::some(aleaf) { + if it.leaf_byte_pos >= aleaf.byte_len { //We are actually past the end of the leaf it.leaf = option::none; ret option::none } else { let {ch, next} = - str::char_range_at(*leaf.content, - it.leaf_byte_pos + leaf.byte_offset); - it.leaf_byte_pos = next - leaf.byte_offset; + str::char_range_at(*aleaf.content, + it.leaf_byte_pos + aleaf.byte_offset); + it.leaf_byte_pos = next - aleaf.byte_offset; ret option::some(ch) } } diff --git a/src/test/run-pass/alt-bot.rs b/src/test/run-pass/alt-bot.rs index ca9e04825192..bf5f963e9cc9 100644 --- a/src/test/run-pass/alt-bot.rs +++ b/src/test/run-pass/alt-bot.rs @@ -1,6 +1,6 @@ fn main() { let i: int = - alt some::(3) { none::. { fail } some::(_) { 5 } }; + alt some::(3) { none:: { fail } some::(_) { 5 } }; log(debug, i); } diff --git a/src/test/run-pass/nullary-or-pattern.rs b/src/test/run-pass/nullary-or-pattern.rs new file mode 100644 index 000000000000..8d4609f95d06 --- /dev/null +++ b/src/test/run-pass/nullary-or-pattern.rs @@ -0,0 +1,10 @@ +tag blah { a; b; } + +fn or_alt(q: blah) -> int { + alt q { a. | b. { 42 } } +} + +fn main() { + assert (or_alt(a) == 42); + assert (or_alt(b) == 42); +}