From cb2f43cbf4332ffe90b8963f1bdbaa85febe1b92 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 22 Feb 2012 16:57:23 +0100 Subject: [PATCH] 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). --- src/comp/middle/alias.rs | 10 +- src/comp/middle/ast_map.rs | 22 ++- src/comp/middle/check_alt.rs | 45 +++-- src/comp/middle/pat_util.rs | 133 +++++--------- src/comp/middle/resolve.rs | 20 +- src/comp/middle/trans/alt.rs | 173 +++++++++--------- src/comp/middle/trans/base.rs | 26 ++- src/comp/middle/trans/debuginfo.rs | 11 +- src/comp/middle/tstate/annotate.rs | 13 +- src/comp/middle/tstate/auxiliary.rs | 2 +- src/comp/middle/tstate/collect_locals.rs | 3 +- src/comp/middle/tstate/pre_post_conditions.rs | 12 +- src/comp/middle/tstate/states.rs | 3 +- src/comp/middle/typeck.rs | 129 +++++++------ src/comp/syntax/ast.rs | 3 - 15 files changed, 285 insertions(+), 320 deletions(-) diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 34caf927662..4a04bbff6ff 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -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, pat: @ast::pat) -> [pattern_root] { fn walk(tcx: ty::ctxt, mutbl: option, 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); } } diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs index 1504f5f738e..aad8afe0b0c 100644 --- a/src/comp/middle/ast_map.rs +++ b/src/comp/middle/ast_map.rs @@ -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); } diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs index e1bf34ce5e4..894aa6af371 100644 --- a/src/comp/middle/check_alt.rs +++ b/src/comp/middle/check_alt.rs @@ -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 } } } diff --git a/src/comp/middle/pat_util.rs b/src/comp/middle/pat_util.rs index 8a5c2706bb1..1a6856e36bf 100644 --- a/src/comp/middle/pat_util.rs +++ b/src/comp/middle/pat_util.rs @@ -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; // 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)) {|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) } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 76aea3a1e3b..413821894a9 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -624,7 +624,7 @@ fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt) { // 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 { 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) { diff --git a/src/comp/middle/trans/alt.rs b/src/comp/middle/trans/alt.rs index c15acf64af0..d461781e719 100644 --- a/src/comp/middle/trans/alt.rs +++ b/src/comp/middle/trans/alt.rs @@ -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; diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs index d0370d992a8..a86681da8ce 100644 --- a/src/comp/middle/trans/base.rs +++ b/src/comp/middle/trans/base.rs @@ -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) diff --git a/src/comp/middle/trans/debuginfo.rs b/src/comp/middle/trans/debuginfo.rs index 9ef09929773..39da8cf2c57 100644 --- a/src/comp/middle/trans/debuginfo.rs +++ b/src/comp/middle/trans/debuginfo.rs @@ -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); diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs index 1689696f207..d4271693112 100644 --- a/src/comp/middle/tstate/annotate.rs +++ b/src/comp/middle/tstate/annotate.rs @@ -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); } diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index cd0cd7e11c3..60d799a89de 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -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} diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index 1abc9903d5c..9b39814e141 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -12,8 +12,7 @@ type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt}; fn collect_local(loc: @local, cx: ctxt, v: visit::vt) { - 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); diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 326c768cabe..f46cd39bf65 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -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); diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 7a7c1cd399a..e9d73ec8e77 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -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); }; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ed9eb3c3560..75f3deb670f 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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(_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; } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index a76b6f9919f..262eac3ca01 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -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), -- GitLab