提交 cb2f43cb 编写于 作者: M Marijn Haverbeke

Stop normalizing patterns

The check for whether a pat_ident is a variant or a binding
is simple and fast. Normalizing patterns again and again is
slow and error-prone (several places were forgetting to do it).
上级 a3b655f8
......@@ -332,7 +332,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 = pat_util::pat_id_map(cx.tcx, a.pats[0]);
let pat_id_map = pat_util::pat_id_map(cx.tcx.def_map, a.pats[0]);
type info = {
id: node_id,
mutable unsafe_tys: [unsafe_ty],
......@@ -596,13 +596,15 @@ fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat)
-> [pattern_root] {
fn walk(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat,
&set: [pattern_root]) {
alt normalize_pat(tcx, pat).node {
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) {}
ast::pat_ident(nm, sub) {
alt pat.node {
ast::pat_ident(nm, sub)
if !pat_util::pat_is_variant(tcx.def_map, pat) {
set += [{id: pat.id, name: path_to_ident(nm), mutbl: mutbl,
span: pat.span}];
alt sub { some(p) { walk(tcx, mutbl, p, set); } _ {} }
}
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
ast::pat_ident(_, _) {}
ast::pat_enum(_, ps) | ast::pat_tup(ps) {
for p in ps { walk(tcx, mutbl, p, set); }
}
......
......@@ -62,19 +62,25 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
visit::visit_fn(fk, decl, body, sp, id, cx, v);
}
fn map_local(loc: @local, cx: ctx, v: vt) {
pat_util::pat_bindings(loc.node.pat) {|p_id, _s, _p|
cx.map.insert(p_id, node_local(cx.local_id));
cx.local_id += 1u;
fn number_pat(cx: ctx, pat: @pat) {
pat_util::walk_pat(pat) {|p|
alt p.node {
pat_ident(_, _) {
cx.map.insert(p.id, node_local(cx.local_id));
cx.local_id += 1u;
}
_ {}
}
};
}
fn map_local(loc: @local, cx: ctx, v: vt) {
number_pat(cx, loc.node.pat);
visit::visit_local(loc, cx, v);
}
fn map_arm(arm: arm, cx: ctx, v: vt) {
pat_util::pat_bindings(arm.pats[0]) {|p_id, _s, _p|
cx.map.insert(p_id, node_local(cx.local_id));
cx.local_id += 1u;
};
number_pat(cx, arm.pats[0]);
visit::visit_arm(arm, cx, v);
}
......
......@@ -10,11 +10,11 @@
import middle::ty::*;
fn check_crate(tcx: ty::ctxt, crate: @crate) {
let v =
@{visit_expr: bind check_expr(tcx, _, _, _),
visit_local: bind check_local(tcx, _, _, _)
with *visit::default_visitor::<()>()};
visit::visit_crate(*crate, (), visit::mk_vt(v));
visit::visit_crate(*crate, (), visit::mk_vt(@{
visit_expr: bind check_expr(tcx, _, _, _),
visit_local: bind check_local(tcx, _, _, _)
with *visit::default_visitor::<()>()
}));
tcx.sess.abort_if_errors();
}
......@@ -22,7 +22,6 @@ fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
visit::visit_expr(ex, s, v);
alt ex.node {
expr_alt(scrut, arms, mode) {
let arms = pat_util::normalize_arms(tcx, arms);
check_arms(tcx, arms);
/* Check for exhaustiveness */
if mode == alt_exhaustive {
......@@ -66,8 +65,6 @@ fn raw_pat(p: @pat) -> @pat {
}
}
// Precondition: patterns have been normalized
// (not checked statically yet)
fn check_exhaustive(tcx: ty::ctxt, sp: span, pats: [@pat]) {
if pats.len() == 0u {
tcx.sess.span_err(sp, "non-exhaustive patterns");
......@@ -216,11 +213,13 @@ fn field_patterns_supersede(tcx: ty::ctxt, fas: [field_pat],
alt a.node {
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) }
_ { false }
pat_wild { true }
pat_ident(_, none) {
let opt_def_a = tcx.def_map.find(a.id);
alt opt_def_a {
some(def_variant(_, _)) { opt_def_a == tcx.def_map.find(b.id) }
// This is a binding
_ { true }
}
}
pat_enum(va, suba) {
......@@ -256,6 +255,12 @@ fn field_patterns_supersede(tcx: ty::ctxt, fas: [field_pat],
_ { pattern_supersedes(tcx, suba, b) }
}
}
pat_lit(la) {
alt b.node {
pat_lit(lb) { lit_expr_eq(la, lb) }
_ { false }
}
}
pat_range(begina, enda) {
alt b.node {
pat_lit(lb) {
......@@ -281,12 +286,19 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
}
fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
alt normalize_pat(tcx, pat).node {
alt tcx.def_map.find(pat.id) {
some(def_variant(enum_id, var_id)) {
if vec::len(*ty::enum_variants(tcx, enum_id)) != 1u { ret true; }
}
_ {}
}
alt pat.node {
pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) {
is_refutable(tcx, sub)
}
pat_wild | pat_ident(_, none) { false }
pat_lit(_) { true }
pat_lit(_) | pat_range(_, _) { true }
pat_rec(fields, _) {
for it: field_pat in fields {
if is_refutable(tcx, it.pat) { ret true; }
......@@ -298,12 +310,9 @@ fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
false
}
pat_enum(_, args) {
let vdef = variant_def_ids(tcx.def_map.get(pat.id));
if vec::len(*ty::enum_variants(tcx, vdef.enm)) != 1u { ret true; }
for p: @pat in args { if is_refutable(tcx, p) { ret true; } }
false
}
pat_range(_, _) { true }
}
}
......
......@@ -5,115 +5,66 @@
import syntax::fold::*;
import syntax::codemap::span;
export normalize_arms;
export normalize_pat;
export normalize_pat_def_map;
export pat_binding_ids;
export pat_bindings;
export pat_id_map;
export walk_pat;
export pat_binding_ids, pat_bindings, pat_id_map;
export pat_is_variant;
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_enum(a_path, subs) {
@{node: pat_enum(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(enum_path, _) { @{id: p.id,
node: pat_enum(enum_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<str, node_id>;
// 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::<node_id>();
pat_bindings(normalize_pat(tcx, pat)) {|p_id, _s, n|
fn pat_id_map(dm: resolve::def_map, pat: @pat) -> pat_id_map {
let map = std::map::new_str_hash();
pat_bindings(dm, pat) {|p_id, _s, n|
map.insert(path_to_ident(n), p_id);
};
ret map;
}
fn pat_is_variant(dm: resolve::def_map, pat: @pat) -> bool {
alt pat.node {
pat_enum(_, _) { true }
pat_ident(_, none) {
alt dm.find(pat.id) {
some(def_variant(_, _)) { true }
_ { false }
}
}
_ { false }
}
}
// 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: fn(node_id, span, @path)) {
alt pat.node {
pat_ident(pth, option::none) { it(pat.id, pat.span, pth); }
pat_ident(pth, option::some(sub)) { it(pat.id, pat.span, pth);
pat_bindings(sub, it); }
pat_enum(_, 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_bindings(dm: resolve::def_map, pat: @pat,
it: fn(node_id, span, @path)) {
walk_pat(pat) {|p|
alt p.node {
pat_ident(pth, _) if !pat_is_variant(dm, p) {
it(p.id, p.span, pth);
}
_ {}
}
}
}
fn pat_binding_ids(pat: @pat) -> [node_id] {
fn walk_pat(pat: @pat, it: fn(@pat)) {
it(pat);
alt pat.node {
pat_ident(pth, some(p)) { walk_pat(p, it); }
pat_rec(fields, _) { for f in fields { walk_pat(f.pat, it); } }
pat_enum(_, s) | pat_tup(s) { for p in s { walk_pat(p, it); } }
pat_box(s) | pat_uniq(s) { walk_pat(s, it); }
pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, none) {}
}
}
fn pat_binding_ids(dm: resolve::def_map, pat: @pat) -> [node_id] {
let found = [];
pat_bindings(pat) {|b_id, _sp, _pt| found += [b_id]; };
pat_bindings(dm, pat) {|b_id, _sp, _pt| 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; }
}
}
fn path_to_ident(p: @path) -> ident { vec::last_total(p.node.idents) }
......@@ -624,7 +624,7 @@ fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt<scopes>) {
// a single identifier unambiguous (does the pattern "foo" refer
// to enum foo, or is it binding a new name foo?)
alt loc.node.pat.node {
pat_ident(an_ident,_) {
pat_ident(an_ident, _) {
// Be sure to pass ns_an_enum 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,
......@@ -1139,8 +1139,7 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option<def_id> {
let found = none;
pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat))
{|p_id, _sp, n|
pat_util::pat_bindings(e.def_map, pat) {|p_id, _sp, n|
if str::eq(path_to_ident(n), name)
{ found = some(local_def(p_id)); }
};
......@@ -1776,7 +1775,7 @@ fn typaram_names(tps: [ast::ty_param]) -> [ident] {
}
fn check_pat(e: @env, ch: checker, p: @ast::pat) {
pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|_i, p_sp, n|
pat_util::pat_bindings(e.def_map, p) {|_i, p_sp, n|
add_name(ch, p_sp, path_to_ident(n));
};
}
......@@ -1823,13 +1822,12 @@ 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 {
pat_util::pat_bindings
(normalize_pat_def_map(e.def_map, loc.node.pat))
{|_i, p_sp, n|
let ident = path_to_ident(n);
add_name(local_values, p_sp, ident);
check_name(values, p_sp, ident);
};
pat_util::pat_bindings(e.def_map, loc.node.pat)
{|_i, p_sp, n|
let ident = path_to_ident(n);
add_name(local_values, p_sp, ident);
check_name(values, p_sp, ident);
};
}
}
ast::decl_item(it) {
......
......@@ -11,6 +11,7 @@
import syntax::codemap::span;
import syntax::print::pprust::pat_to_str;
import back::abi;
import resolve::def_map;
import common::*;
......@@ -63,9 +64,9 @@ fn trans_opt(bcx: block, o: opt) -> opt_result {
}
}
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::enum_variants(ccx.tcx, vdef.enm);
fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> opt {
let vdef = ast_util::variant_def_ids(tcx.def_map.get(pat_id));
let variants = ty::enum_variants(tcx, vdef.enm);
for v: ty::variant_info in *variants {
if vdef.var == v.id { ret var(v.disr_val, vdef); }
}
......@@ -116,24 +117,24 @@ fn expand_nested_bindings(m: match, col: uint, val: ValueRef) -> match {
result
}
type enter_pat = fn@(@ast::pat) -> option<[@ast::pat]>;
type enter_pat = fn(@ast::pat) -> option<[@ast::pat]>;
fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match {
fn enter_match(dm: def_map, m: match, col: uint, val: ValueRef,
e: enter_pat) -> match {
let result = [];
for br: match_branch in m {
alt e(br.pats[col]) {
some(sub) {
let pats = sub + vec::slice(br.pats, 0u, col) +
vec::slice(br.pats, col + 1u, br.pats.len());
let new_br = @{pats: pats,
bound: alt br.pats[col].node {
ast::pat_ident(name, none) {
br.bound + [{ident: path_to_ident(name),
val: val}]
}
_ { br.bound }
} with *br};
result += [new_br];
let self = br.pats[col];
let bound = alt self.node {
ast::pat_ident(name, none) if !pat_is_variant(dm, self) {
br.bound + [{ident: path_to_ident(name), val: val}]
}
_ { br.bound }
};
result += [@{pats: pats, bound: bound with *br}];
}
none { }
}
......@@ -141,48 +142,46 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match {
ret result;
}
fn enter_default(m: match, col: uint, val: ValueRef) -> match {
fn matches_always(p: @ast::pat) -> bool {
fn enter_default(dm: def_map, m: match, col: uint, val: ValueRef) -> match {
enter_match(dm, m, col, val) {|p|
alt p.node {
ast::pat_wild | ast::pat_rec(_, _) |
ast::pat_ident(_, none) | ast::pat_tup(_) { true }
_ { false }
ast::pat_wild | ast::pat_rec(_, _) | ast::pat_tup(_) { some([]) }
ast::pat_ident(_, none) if !pat_is_variant(dm, p) {
some([])
}
_ { none }
}
}
fn e(p: @ast::pat) -> option<[@ast::pat]> {
ret if matches_always(p) { some([]) } else { none };
}
ret enter_match(m, col, val, e);
}
fn enter_opt(ccx: crate_ctxt, m: match, opt: opt, col: uint, enum_size: uint,
val: ValueRef) -> match {
fn enter_opt(tcx: ty::ctxt, m: match, opt: opt, col: uint,
variant_size: uint, val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(ccx: crate_ctxt, dummy: @ast::pat, opt: opt, size: uint,
p: @ast::pat) -> option<[@ast::pat]> {
enter_match(tcx.def_map, m, col, val) {|p|
alt p.node {
ast::pat_enum(ctor, subpats) {
ret if opt_eq(variant_opt(ccx, p.id), opt) {
some(subpats)
} else { none };
ast::pat_enum(_, subpats) {
if opt_eq(variant_opt(tcx, p.id), opt) { some(subpats) }
else { none }
}
ast::pat_ident(_, none) if pat_is_variant(tcx.def_map, p) {
if opt_eq(variant_opt(tcx, p.id), opt) { some([]) }
else { none }
}
ast::pat_lit(l) {
ret if opt_eq(lit(l), opt) { some([]) } else { none };
if opt_eq(lit(l), opt) { some([]) } else { none }
}
ast::pat_range(l1, l2) {
ret if opt_eq(range(l1, l2), opt) { some([]) } else { none };
if opt_eq(range(l1, l2), opt) { some([]) } else { none }
}
_ { ret some(vec::init_elt(size, dummy)); }
_ { some(vec::init_elt(variant_size, dummy)) }
}
}
ret enter_match(m, col, val, bind e(ccx, dummy, opt, enum_size, _));
}
fn enter_rec(m: match, col: uint, fields: [ast::ident], val: ValueRef) ->
match {
fn enter_rec(dm: def_map, m: match, col: uint, fields: [ast::ident],
val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(dummy: @ast::pat, fields: [ast::ident], p: @ast::pat) ->
option<[@ast::pat]> {
enter_match(dm, m, col, val) {|p|
alt p.node {
ast::pat_rec(fpats, _) {
let pats = [];
......@@ -193,65 +192,63 @@ fn e(dummy: @ast::pat, fields: [ast::ident], p: @ast::pat) ->
}
pats += [pat];
}
ret some(pats);
some(pats)
}
_ { ret some(vec::init_elt(fields.len(), dummy)); }
_ { some(vec::init_elt(fields.len(), dummy)) }
}
}
ret enter_match(m, col, val, bind e(dummy, fields, _));
}
fn enter_tup(m: match, col: uint, val: ValueRef, n_elts: uint) -> match {
fn enter_tup(dm: def_map, m: match, col: uint, val: ValueRef,
n_elts: uint) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(dummy: @ast::pat, n_elts: uint, p: @ast::pat) ->
option<[@ast::pat]> {
enter_match(dm, m, col, val) {|p|
alt p.node {
ast::pat_tup(elts) { ret some(elts); }
_ { ret some(vec::init_elt(n_elts, dummy)); }
ast::pat_tup(elts) { some(elts) }
_ { some(vec::init_elt(n_elts, dummy)) }
}
}
ret enter_match(m, col, val, bind e(dummy, n_elts, _));
}
fn enter_box(m: match, col: uint, val: ValueRef) -> match {
fn enter_box(dm: def_map, m: match, col: uint, val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(dummy: @ast::pat, p: @ast::pat) -> option<[@ast::pat]> {
enter_match(dm, m, col, val) {|p|
alt p.node {
ast::pat_box(sub) { ret some([sub]); }
_ { ret some([dummy]); }
ast::pat_box(sub) { some([sub]) }
_ { some([dummy]) }
}
}
ret enter_match(m, col, val, bind e(dummy, _));
}
fn enter_uniq(m: match, col: uint, val: ValueRef) -> match {
fn enter_uniq(dm: def_map, m: match, col: uint, val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(dummy: @ast::pat, p: @ast::pat) -> option<[@ast::pat]> {
enter_match(dm, m, col, val) {|p|
alt p.node {
ast::pat_uniq(sub) { ret some([sub]); }
_ { ret some([dummy]); }
ast::pat_uniq(sub) { some([sub]) }
_ { some([dummy]) }
}
}
ret enter_match(m, col, val, bind e(dummy, _));
}
fn get_options(ccx: crate_ctxt, m: match, col: uint) -> [opt] {
fn add_to_set(&set: [opt], val: opt) {
for l: opt in set { if opt_eq(l, val) { ret; } }
for l in set { if opt_eq(l, val) { ret; } }
set += [val];
}
let found = [];
for br: match_branch in m {
alt br.pats[col].node {
ast::pat_lit(l) { add_to_set(found, lit(l)); }
ast::pat_range(l1, l2) {
add_to_set(found, range(l1, l2));
}
ast::pat_enum(_, _) {
add_to_set(found, variant_opt(ccx, br.pats[col].id));
}
_ { }
for br in m {
let cur = br.pats[col];
if pat_is_variant(ccx.tcx.def_map, cur) {
add_to_set(found, variant_opt(ccx.tcx, br.pats[col].id));
} else {
alt cur.node {
ast::pat_lit(l) { add_to_set(found, lit(l)); }
ast::pat_range(l1, l2) {
add_to_set(found, range(l1, l2));
}
_ {}
}
}
}
ret found;
......@@ -362,7 +359,7 @@ fn score(p: @ast::pat) -> uint {
fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
&exits: [exit_node]) {
let bcx = bcx;
let bcx = bcx, tcx = bcx.tcx(), dm = tcx.def_map;
if m.len() == 0u { Br(bcx, f()); ret; }
if m[0].pats.len() == 0u {
let data = m[0].data;
......@@ -422,7 +419,7 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
rec_vals += [r.val];
bcx = r.bcx;
}
compile_submatch(bcx, enter_rec(m, col, rec_fields, val),
compile_submatch(bcx, enter_rec(dm, m, col, rec_fields, val),
rec_vals + vals_left, f, exits);
ret;
}
......@@ -440,7 +437,7 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
bcx = r.bcx;
i += 1u;
}
compile_submatch(bcx, enter_tup(m, col, val, n_tup_elts),
compile_submatch(bcx, enter_tup(dm, m, col, val, n_tup_elts),
tup_vals + vals_left, f, exits);
ret;
}
......@@ -449,14 +446,14 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
if any_box_pat(m, col) {
let box = Load(bcx, val);
let unboxed = GEPi(bcx, box, [0, abi::box_field_body]);
compile_submatch(bcx, enter_box(m, col, val), [unboxed] + vals_left,
f, exits);
compile_submatch(bcx, enter_box(dm, m, col, val), [unboxed]
+ vals_left, f, exits);
ret;
}
if any_uniq_pat(m, col) {
let unboxed = Load(bcx, val);
compile_submatch(bcx, enter_uniq(m, col, val),
compile_submatch(bcx, enter_uniq(dm, m, col, val),
[unboxed] + vals_left, f, exits);
ret;
}
......@@ -469,7 +466,7 @@ enum branch_kind { no_branch, single, switch, compare, }
if opts.len() > 0u {
alt opts[0] {
var(_, vdef) {
if (*ty::enum_variants(ccx.tcx, vdef.enm)).len() == 1u {
if (*ty::enum_variants(tcx, vdef.enm)).len() == 1u {
kind = single;
} else {
let enumptr =
......@@ -512,13 +509,11 @@ enum branch_kind { no_branch, single, switch, compare, }
single { Br(bcx, opt_cx.llbb); }
switch {
let res = trans_opt(bcx, opt);
alt res {
alt check res {
single_result(r) {
llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
bcx = r.bcx;
}
_ { bcx.tcx().sess.bug("Someone forgot to\
document an invariant in compile_submatch"); }
}
}
compare {
......@@ -554,15 +549,15 @@ enum branch_kind { no_branch, single, switch, compare, }
}
lit(_) | range(_, _) { }
}
compile_submatch(opt_cx, enter_opt(ccx, m, opt, col, size, val),
compile_submatch(opt_cx, enter_opt(tcx, m, opt, col, size, val),
unpacked + vals_left, f, exits);
}
// Compile the fall-through case
if kind == compare { Br(bcx, else_cx.llbb); }
if kind != single {
compile_submatch(else_cx, enter_default(m, col, val), vals_left, f,
exits);
compile_submatch(else_cx, enter_default(dm, m, col, val), vals_left,
f, exits);
}
}
......@@ -625,14 +620,10 @@ fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: [ast::arm],
let {bcx, val, _} = trans_temp_expr(bcx, expr);
if bcx.unreachable { ret bcx; }
// n.b. nothing else in this module should need to normalize,
// b/c of this call
let arms = normalize_arms(tcx, arms);
for a in arms {
let body = scope_block(bcx, "case_body");
body.block_span = some(a.body.span);
let id_map = pat_util::pat_id_map(tcx, a.pats[0]);
let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]);
bodies += [body];
for p in a.pats {
match += [@{pats: [p],
......@@ -662,8 +653,8 @@ fn mk_fail(bcx: block, sp: span,
let arm_cxs = [], arm_dests = [], i = 0u;
for a in arms {
let body_cx = bodies[i];
if make_phi_bindings(body_cx, exit_map,
pat_util::pat_id_map(tcx, a.pats[0])) {
let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]);
if make_phi_bindings(body_cx, exit_map, id_map) {
let arm_dest = dup_for_join(dest);
arm_dests += [arm_dest];
let arm_cx = trans_block(body_cx, a.body, arm_dest);
......@@ -681,8 +672,9 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
let ccx = bcx.fcx.ccx, bcx = bcx;
// Necessary since bind_irrefutable_pat is called outside trans_alt
alt normalize_pat(bcx.tcx(), pat).node {
alt pat.node {
ast::pat_ident(_,inner) {
if pat_is_variant(bcx.tcx().def_map, pat) { ret bcx; }
if make_copy || ccx.copy_map.contains_key(pat.id) {
let ty = node_id_type(bcx, pat.id);
let llty = type_of::type_of(ccx, ty);
......@@ -698,7 +690,6 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
}
}
ast::pat_enum(_, sub) {
if sub.len() == 0u { ret bcx; }
let vdefs = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat.id));
let args = extract_variant_args(bcx, pat.id, vdefs, val);
let i = 0;
......
......@@ -3670,13 +3670,14 @@ fn alloc_ty(cx: block, t: ty::t) -> result {
fn alloc_local(cx: block, local: @ast::local) -> block {
let t = node_id_type(cx, local.node.id);
let p = normalize_pat(cx.tcx(), local.node.pat);
let is_simple = alt p.node {
ast::pat_ident(_, none) { true } _ { false }
let simple_name = alt local.node.pat.node {
ast::pat_ident(pth, none) { some(path_to_ident(pth)) }
_ { none }
};
// Do not allocate space for locals that can be kept immediate.
let ccx = cx.ccx();
if is_simple && !ccx.mutbl_map.contains_key(local.node.pat.id) &&
if option::is_some(simple_name) &&
!ccx.mutbl_map.contains_key(local.node.pat.id) &&
!ccx.last_uses.contains_key(local.node.pat.id) &&
ty::type_is_immediate(t) {
alt local.node.init {
......@@ -3684,19 +3685,16 @@ fn alloc_local(cx: block, local: @ast::local) -> block {
_ {}
}
}
let r = alloc_ty(cx, t);
alt p.node {
ast::pat_ident(pth, none) {
if cx.sess().opts.debuginfo {
let _: () = str::as_buf(path_to_ident(pth), {|buf|
llvm::LLVMSetValueName(r.val, buf)
let {bcx, val} = alloc_ty(cx, t);
if cx.sess().opts.debuginfo {
option::may(simple_name) {|name|
str::as_buf(name, {|buf|
llvm::LLVMSetValueName(val, buf)
});
}
}
_ { }
}
cx.fcx.lllocals.insert(local.node.id, local_mem(r.val));
ret r.bcx;
cx.fcx.lllocals.insert(local.node.id, local_mem(val));
ret bcx;
}
fn trans_block(bcx: block, b: ast::blk, dest: dest)
......
......@@ -686,12 +686,11 @@ fn create_local_var(bcx: block, local: @ast::local)
option::none {}
}
let name = path_to_ident(alt pat_util::normalize_pat(bcx.tcx(),
local.node.pat).node {
ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ }
_ { bcx.tcx().sess.span_bug(local.span, "create_local_var: \
weird pattern in local"); }
});
let name = alt local.node.pat.node {
ast::pat_ident(pth, _) { pat_util::path_to_ident(pth) }
// FIXME this should be handled
_ { fail "no single variable name for local"; }
};
let loc = codemap::lookup_char_pos(cx.sess.codemap,
local.span.lo);
let ty = node_id_type(bcx, local.node.id);
......
......@@ -22,17 +22,18 @@ fn collect_ids_stmt(s: @stmt, rs: @mutable [node_id]) {
}
}
fn collect_ids_local(l: @local, rs: @mutable [node_id]) {
*rs += pat_binding_ids(l.node.pat);
fn collect_ids_local(tcx: ty::ctxt, l: @local, rs: @mutable [node_id]) {
*rs += pat_binding_ids(tcx.def_map, l.node.pat);
}
fn node_ids_in_fn(body: blk, rs: @mutable [node_id]) {
fn node_ids_in_fn(tcx: ty::ctxt, body: blk, rs: @mutable [node_id]) {
let collect_ids =
visit::mk_simple_visitor(@{visit_expr: bind collect_ids_expr(_, rs),
visit_block: bind collect_ids_block(_, rs),
visit_stmt: bind collect_ids_stmt(_, rs),
visit_local: bind collect_ids_local(_, rs)
with *visit::default_simple_visitor()});
visit_local:
bind collect_ids_local(tcx, _, rs)
with *visit::default_simple_visitor()});
collect_ids.visit_block(body, (), collect_ids);
}
......@@ -45,7 +46,7 @@ fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) {
fn visit_fn(ccx: crate_ctxt, num_constraints: uint, body: blk) {
let node_ids: @mutable [node_id] = @mutable [];
node_ids_in_fn(body, node_ids);
node_ids_in_fn(ccx.tcx, body, node_ids);
let node_id_vec = *node_ids;
init_vecs(ccx, node_id_vec, num_constraints);
}
......
......@@ -1056,7 +1056,7 @@ fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: [arg], c: @constr) ->
fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding {
let lhs = [];
pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p_id, _s, name|
pat_bindings(tcx.def_map, loc.node.pat) {|p_id, _s, name|
lhs += [{ident: path_to_ident(name), node: p_id}];
};
{lhs: lhs, rhs: loc.node.init}
......
......@@ -12,8 +12,7 @@
type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt};
fn collect_local(loc: @local, cx: ctxt, v: visit::vt<ctxt>) {
pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat))
{|p_id, _s, id|
pat_bindings(cx.tcx.def_map, loc.node.pat) {|p_id, _s, id|
*cx.cs += [respan(loc.span, ninit(p_id, path_to_ident(id)))];
};
visit::visit_local(loc, cx, v);
......
......@@ -89,7 +89,7 @@ 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(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p_id, _s, n|
pat_bindings(fcx.ccx.tcx.def_map, l.node.pat) {|p_id, _s, n|
let v_init = ninit(p_id, path_to_ident(n));
relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body);
// Hack: for-loop index variables are frequently ignored,
......@@ -551,7 +551,8 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) {
/* LHS always becomes initialized,
whether or not this is a move */
find_pre_post_expr(fcx, an_init.expr);
pat_bindings(alocal.node.pat) {|p_id, _s, _n|
pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat)
{|p_id, _s, _n|
copy_pre_post(fcx.ccx, p_id, an_init.expr);
};
/* Inherit ann from initializer, and add var being
......@@ -564,7 +565,7 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) {
_ { }
}
pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat))
pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat)
{|p_id, _s, n|
let ident = path_to_ident(n);
alt p {
......@@ -592,7 +593,7 @@ 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(normalize_pat(fcx.ccx.tcx, alocal.node.pat))
pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat)
{|pat_id, _s, n|
set_in_postcond(bit_num(fcx,
ninit(pat_id, path_to_ident(n))), prev_pp);
......@@ -601,7 +602,8 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) {
prev_pp.postcondition);
}
none {
pat_bindings(alocal.node.pat) {|p_id, _s, _n|
pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat)
{|p_id, _s, _n|
clear_pp(node_id_to_ts_ann(fcx.ccx, p_id).conditions);
};
clear_pp(node_id_to_ts_ann(fcx.ccx, id).conditions);
......
......@@ -224,8 +224,7 @@ 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(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat))
{|p_id, _s, n|
pat_bindings(fcx.ccx.tcx.def_map, l.node.pat) {|p_id, _s, n|
set_in_poststate_ident(fcx, p_id, path_to_ident(n), index_post);
};
......
......@@ -1338,12 +1338,15 @@ fn gather_locals(ccx: @crate_ctxt,
// Add pattern bindings.
let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) {
alt normalize_pat(ccx.tcx, p).node {
ast::pat_ident(_, _) { assign(p.id, none); }
_ {/* no-op */ }
}
visit::visit_pat(p, e, v);
};
alt p.node {
ast::pat_ident(_, _)
if !pat_util::pat_is_variant(ccx.tcx.def_map, p) {
assign(p.id, none);
}
_ {}
}
visit::visit_pat(p, e, v);
};
// Don't descend into fns and items
fn visit_fn<T>(_fk: visit::fn_kind, _decl: ast::fn_decl, _body: ast::blk,
......@@ -1380,12 +1383,65 @@ fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool {
ast_util::compare_lit_exprs(from, to) <= 0
}
fn check_pat_variant(fcx: @fn_ctxt, map: pat_util::pat_id_map,
pat: @ast::pat, path: @ast::path, subpats: [@ast::pat],
expected: ty::t) {
// Typecheck the path.
let tcx = fcx.ccx.tcx;
let v_def = lookup_def(fcx, path.span, pat.id);
let v_def_ids = ast_util::variant_def_ids(v_def);
let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
instantiate_path(fcx, path, ctor_tpt, pat.span, pat.id);
// Take the enum type params out of `expected`.
alt structure_of(fcx, pat.span, expected) {
ty::ty_enum(_, expected_tps) {
let ctor_ty = ty::node_id_to_type(tcx, pat.id);
demand::with_substs(fcx, pat.span, expected, ctor_ty,
expected_tps);
// Get the number of arguments in this enum variant.
let arg_types = variant_arg_types(fcx.ccx, pat.span,
v_def_ids.var, expected_tps);
let subpats_len = subpats.len(), arg_len = arg_types.len();
if arg_len > 0u {
// N-ary variant.
if arg_len != subpats_len {
let s = #fmt["this pattern has %u field%s, but the \
corresponding variant has %u field%s",
subpats_len,
if subpats_len == 1u { "" } else { "s" },
arg_len,
if arg_len == 1u { "" } else { "s" }];
tcx.sess.span_err(pat.span, s);
}
vec::iter2(subpats, arg_types) {|subpat, arg_ty|
check_pat(fcx, map, subpat, arg_ty);
}
} else if subpats_len > 0u {
tcx.sess.span_err
(pat.span, #fmt["this pattern has %u field%s, \
but the corresponding variant has no fields",
subpats_len,
if subpats_len == 1u { "" }
else { "s" }]);
}
}
_ {
tcx.sess.span_err
(pat.span,
#fmt["mismatched types: expected enum but found `%s`",
ty_to_str(tcx, expected)]);
}
}
}
// Pattern checking is top-down rather than bottom-up so that bindings get
// their types immediately.
fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat,
expected: ty::t) {
let tcx = fcx.ccx.tcx;
alt normalize_pat(tcx, pat).node {
alt pat.node {
ast::pat_wild {
alt structure_of(fcx, pat.span, expected) {
ty::ty_enum(_, expected_tps) {
......@@ -1416,7 +1472,8 @@ fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat,
}
write_ty(tcx, pat.id, b_ty);
}
ast::pat_ident(name, sub) {
ast::pat_ident(name, sub)
if !pat_util::pat_is_variant(tcx.def_map, pat) {
let vid = lookup_local(fcx, pat.span, pat.id);
let typ = ty::mk_var(tcx, vid);
typ = demand::simple(fcx, pat.span, expected, typ);
......@@ -1431,55 +1488,11 @@ fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat,
_ {}
}
}
ast::pat_ident(path, _) {
check_pat_variant(fcx, map, pat, path, [], expected);
}
ast::pat_enum(path, subpats) {
// Typecheck the path.
let v_def = lookup_def(fcx, path.span, pat.id);
let v_def_ids = ast_util::variant_def_ids(v_def);
let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
instantiate_path(fcx, path, ctor_tpt, pat.span, pat.id);
// Take the enum type params out of `expected`.
alt structure_of(fcx, pat.span, expected) {
ty::ty_enum(_, expected_tps) {
let ctor_ty = ty::node_id_to_type(tcx, pat.id);
demand::with_substs(fcx, pat.span, expected, ctor_ty,
expected_tps);
// Get the number of arguments in this enum variant.
let arg_types = variant_arg_types(fcx.ccx, pat.span,
v_def_ids.var, expected_tps);
let subpats_len = subpats.len(), arg_len = arg_types.len();
if arg_len > 0u {
// N-ary variant.
if arg_len != subpats_len {
let s = #fmt["this pattern has %u field%s, but the \
corresponding variant has %u field%s",
subpats_len,
if subpats_len == 1u { "" } else { "s" },
arg_len,
if arg_len == 1u { "" } else { "s" }];
tcx.sess.span_err(pat.span, s);
}
vec::iter2(subpats, arg_types) {|subpat, arg_ty|
check_pat(fcx, map, subpat, arg_ty);
}
} else if subpats_len > 0u {
tcx.sess.span_err
(pat.span, #fmt["this pattern has %u field%s, \
but the corresponding \
variant has no fields",
subpats_len,
if subpats_len == 1u { "" }
else { "s" }]);
}
}
_ {
tcx.sess.span_err
(pat.span,
#fmt["mismatched types: expected enum but found `%s`",
ty_to_str(tcx, expected)]);
}
}
check_pat_variant(fcx, map, pat, path, subpats, expected);
}
ast::pat_rec(fields, etc) {
let ex_fields;
......@@ -2292,7 +2305,7 @@ fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str,
// bindings.
let pattern_ty = ty::expr_ty(tcx, expr);
for arm: ast::arm in arms {
let id_map = pat_util::pat_id_map(tcx, arm.pats[0]);
let id_map = pat_util::pat_id_map(tcx.def_map, arm.pats[0]);
for p: @ast::pat in arm.pats {
check_pat(fcx, id_map, p, pattern_ty);
}
......@@ -2636,7 +2649,7 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
}
_ {/* fall through */ }
}
let id_map = pat_util::pat_id_map(fcx.ccx.tcx, local.node.pat);
let id_map = pat_util::pat_id_map(fcx.ccx.tcx.def_map, local.node.pat);
check_pat(fcx, id_map, local.node.pat, t);
ret bot;
}
......
......@@ -108,9 +108,6 @@ enum pat_ {
// 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 enums")
// 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 enums into pat_enums.
pat_ident(@path, option<@pat>),
pat_enum(@path, [@pat]),
pat_rec([field_pat], bool),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册