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).
This commit is contained in:
parent
a3b655f8e3
commit
cb2f43cbf4
15 changed files with 285 additions and 320 deletions
|
|
@ -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;
|
|||
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 pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
|
|||
|
||||
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 pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
|
|||
_ { 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::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 check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
|
|||
}
|
||||
|
||||
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::ast::def_id;
|
|||
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 enter_rec(m: match, col: uint, fields: [ast::ident], val: ValueRef) ->
|
|||
}
|
||||
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 pick_col(m: match) -> 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 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
|
|||
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 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
|
|||
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 @@ fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail,
|
|||
}
|
||||
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 trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: [ast::arm],
|
|||
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 @@ type binding = {lhs: [inst], rhs: option<initializer>};
|
|||
|
||||
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 @@ import aux::*;
|
|||
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_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 = 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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue