Allow omission of the '.' after nullary tag patterns

This commit allows patterns like:

alt x { some(_) { ... } none { } }

without the '.' after none. The parser suspends judgment about
whether a bare ident is a tag or a new bound variable; instead,
the resolver disambiguates.

This means that any code after resolution that pattern-matches on
patterns needs to call pat_util::normalize_pat, which consults
an environment to do this disambiguation.

In addition, local variables are no longer allowed to shadow
tag names, so this required changing some code (e.g. renaming
variables named "mut", and renaming ast::sub to subtract).

The parser currently accepts patterns with and without the '.'.
Once the compiler and libraries are changed, it will no longer
accept the '.'.
This commit is contained in:
Tim Chevalier 2012-01-14 16:05:07 -08:00
parent a7bd817017
commit c3bc8fada8
25 changed files with 405 additions and 190 deletions

View File

@ -9,6 +9,7 @@ import std::list;
import option::{some, none, is_none};
import list::list;
import driver::session::session;
import pat_util::*;
// This is not an alias-analyser (though it would merit from becoming one, or
// getting input from one, to be more precise). It is a pass that checks
@ -323,7 +324,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
for a: ast::arm in arms {
let new_bs = sc.bs;
let root_var = path_def_id(cx, root.ex);
let pat_id_map = ast_util::pat_id_map(a.pats[0]);
let pat_id_map = pat_util::pat_id_map(cx.tcx, a.pats[0]);
type info = {
id: node_id,
mutable unsafe_tys: [unsafe_ty],
@ -588,10 +589,11 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
-> [pattern_root] {
fn walk(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat,
&set: [pattern_root]) {
alt pat.node {
alt normalize_pat(tcx, pat).node {
ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {}
ast::pat_bind(nm, sub) {
set += [{id: pat.id, name: nm, mut: mut, span: pat.span}];
ast::pat_ident(nm, sub) {
set += [{id: pat.id, name: path_to_ident(nm), mut: mut,
span: pat.span}];
alt sub { some(p) { walk(tcx, mut, p, set); } _ {} }
}
ast::pat_tag(_, ps) | ast::pat_tup(ps) {

View File

@ -44,14 +44,14 @@ fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk,
}
fn map_local(cx: ctx, loc: @local) {
ast_util::pat_bindings(loc.node.pat) {|p|
pat_util::pat_bindings(loc.node.pat) {|p|
cx.map.insert(p.id, node_local(cx.local_id));
cx.local_id += 1u;
};
}
fn map_arm(cx: ctx, arm: arm) {
ast_util::pat_bindings(arm.pats[0]) {|p|
pat_util::pat_bindings(arm.pats[0]) {|p|
cx.map.insert(p.id, node_local(cx.local_id));
cx.local_id += 1u;
};

View File

@ -1,6 +1,7 @@
import syntax::ast::*;
import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs,
lit_expr_eq};
import pat_util::*;
import syntax::visit;
import option::{some, none};
import driver::session::session;
@ -16,7 +17,12 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
visit::visit_expr(ex, s, v);
alt ex.node { expr_alt(_, arms) { check_arms(tcx, arms); } _ { } }
alt ex.node {
expr_alt(_, arms) {
check_arms(tcx, pat_util::normalize_arms(tcx, arms));
}
_ { }
}
}
fn check_arms(tcx: ty::ctxt, arms: [arm]) {
@ -66,8 +72,8 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
}
alt a.node {
pat_bind(_, some(p)) { pattern_supersedes(tcx, p, b) }
pat_wild. | pat_bind(_, none.) { true }
pat_ident(_, some(p)) { pattern_supersedes(tcx, p, b) }
pat_wild. | pat_ident(_, none.) { true }
pat_lit(la) {
alt b.node {
pat_lit(lb) { lit_expr_eq(la, lb) }
@ -132,11 +138,11 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
}
fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
alt pat.node {
pat_box(sub) | pat_uniq(sub) | pat_bind(_, some(sub)) {
alt normalize_pat(tcx, pat).node {
pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) {
is_refutable(tcx, sub)
}
pat_wild. | pat_bind(_, none.) { false }
pat_wild. | pat_ident(_, none.) { false }
pat_lit(_) { true }
pat_rec(fields, _) {
for field: field_pat in fields {

View File

@ -8,6 +8,7 @@ import middle::trans_build::B;
import middle::ty;
import syntax::{ast, codemap};
import ast::ty;
import pat_util::*;
import util::ppaux::ty_to_str;
export create_local_var;
@ -629,9 +630,10 @@ fn create_local_var(bcx: @block_ctxt, local: @ast::local)
option::none. {}
}
let name = alt local.node.pat.node {
ast::pat_bind(ident, _) { ident /*XXX deal w/ optional node binding*/ }
};
let name = path_to_ident(alt pat_util::normalize_pat(bcx_tcx(bcx),
local.node.pat).node {
ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ }
});
let loc = codemap::lookup_char_pos(cx.sess.codemap,
local.span.lo);
let ty = trans::node_id_type(cx, local.node.id);

119
src/comp/middle/pat_util.rs Normal file
View File

@ -0,0 +1,119 @@
import syntax::ast::*;
import syntax::ast_util;
import syntax::ast_util::respan;
import syntax::fold;
import syntax::fold::*;
export normalize_arms;
export normalize_pat;
export normalize_pat_def_map;
export pat_binding_ids;
export pat_bindings;
export pat_id_map;
export path_to_ident;
fn normalize_pat_def_map(dm: resolve::def_map, p: @pat) -> @pat {
// have to do it the hard way b/c ast fold doesn't pass around
// node IDs. bother.
alt p.node {
pat_wild. { p }
pat_ident(_, none.) { normalize_one(dm, p) }
pat_ident(q, some(r)) {
@{node: pat_ident(q, some(normalize_pat_def_map(dm, r)))
with *p}
}
pat_tag(a_path, subs) {
@{node: pat_tag(a_path,
vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) with *p}
}
pat_rec(field_pats, b) {
@{node: pat_rec(vec::map(field_pats,
{|fp| {pat: normalize_pat_def_map(dm, fp.pat) with fp}}), b)
with *p}
}
pat_tup(subs) {
@{node: pat_tup(vec::map(subs, {|p| normalize_pat_def_map(dm, p)}))
with *p}
}
pat_box(q) {
@{node: pat_box(normalize_pat_def_map(dm, q))
with *p}
}
pat_uniq(q) {
@{node: pat_uniq(normalize_pat_def_map(dm, q))
with *p}
}
pat_lit(_) { p }
pat_range(_,_) { p }
}
}
fn normalize_one(dm: resolve::def_map, p: @pat) -> @pat {
alt dm.find(p.id) {
some(d) {
alt p.node {
pat_ident(tag_path, _) { @{id: p.id,
node: pat_tag(tag_path, []),
span: p.span} }
_ { p }
}
}
none. { p }
}
}
fn normalize_pat(tcx: ty::ctxt, p: @pat) -> @pat {
normalize_pat_def_map(tcx.def_map, p)
}
fn normalize_arms(tcx: ty::ctxt, arms:[arm]) -> [arm] {
vec::map(arms, {|a|
{pats:
vec::map(a.pats, {|p|
pat_util::normalize_pat(tcx, p)})
with a}})
}
type pat_id_map = std::map::hashmap<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)) {|bound|
let name = path_to_ident(alt bound.node
{ pat_ident(n, _) { n } });
map.insert(name, bound.id);
};
ret map;
}
// This does *not* normalize. The pattern should be already normalized
// if you want to get a normalized pattern out of it.
// Could return a constrained type in order to express that (future work)
fn pat_bindings(pat: @pat, it: block(@pat)) {
alt pat.node {
pat_ident(_, option::none.) { it(pat); }
pat_ident(_, option::some(sub)) { it(pat); pat_bindings(sub, it); }
pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } }
pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } }
pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } }
pat_box(sub) { pat_bindings(sub, it); }
pat_uniq(sub) { pat_bindings(sub, it); }
pat_wild. | pat_lit(_) | pat_range(_, _) { }
}
}
fn pat_binding_ids(pat: @pat) -> [node_id] {
let found = [];
pat_bindings(pat) {|b| found += [b.id]; };
ret found;
}
fn path_to_ident(p: @path) -> ident {
alt vec::last(p.node.idents) {
none. { // sigh
fail "Malformed path"; }
some(i) { ret i; }
}
}

View File

@ -3,6 +3,7 @@ import syntax::{ast, ast_util, codemap};
import syntax::ast::*;
import ast::{ident, fn_ident, def, def_id, node_id};
import syntax::ast_util::{local_def, def_id_of_def};
import pat_util::*;
import front::attr;
import metadata::{csearch, cstore};
@ -181,10 +182,12 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
sess: sess};
map_crate(e, crate);
resolve_imports(*e);
check_for_collisions(e, *crate);
check_exports(e);
resolve_names(e, crate);
resolve_impls(e, crate);
// check_for_collisions must happen after resolve_names so we
// don't complain if a pattern uses the same nullary tag twice
check_for_collisions(e, *crate);
if sess.opts.warn_unused_imports {
check_unused_imports(e);
}
@ -417,6 +420,20 @@ fn resolve_names(e: @env, c: @ast::crate) {
}
}
}
/* Here we determine whether a given pat_ident binds a new
variable a refers to a nullary tag. */
ast::pat_ident(p, none.) {
let fnd = lookup_in_scope(*e, sc, p.span, path_to_ident(p),
ns_val(ns_a_tag));
alt fnd {
some(ast::def_variant(did, vid)) {
e.def_map.insert(pat.id, ast::def_variant(did, vid));
}
_ {
// Binds a var -- nothing needs to be done
}
}
}
_ { }
}
}
@ -539,30 +556,32 @@ fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
}
}
// This is only for irrefutable patterns (e.g. ones that appear in a let)
// So if x occurs, and x is already known to be a tag, that's always an error.
fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt<scopes>) {
// Checks whether the given local has the same name as a tag that's
// Check whether the given local has the same name as a tag that's
// in scope
// We disallow this, in order to make alt patterns consisting of
// a single identifier unambiguous (does the pattern "foo" refer
// to tag foo, or is it binding a new name foo?)
alt loc.node.pat.node {
pat_bind(an_ident,_) {
pat_ident(an_ident,_) {
// Be sure to pass ns_a_tag to lookup_in_scope so that
// if this is a name that's being shadowed, we don't die
alt lookup_in_scope(*e, sc, loc.span, an_ident, ns_val(ns_a_tag)) {
alt lookup_in_scope(*e, sc, loc.span,
path_to_ident(an_ident), ns_val(ns_a_tag)) {
some(ast::def_variant(tag_id,variant_id)) {
// Declaration shadows a tag that's in scope.
// That's an error.
e.sess.span_err(loc.span,
#fmt("Declaration of %s shadows a tag that's in scope",
an_ident));
path_to_ident(an_ident)));
}
_ {}
}
}
_ {}
}
visit::visit_local(loc, sc, v);
}
@ -907,7 +926,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
}
scope_loop(local) {
if ns == ns_val(ns_any_value) {
alt lookup_in_pat(name, local.node.pat) {
alt lookup_in_pat(e, name, local.node.pat) {
some(did) { ret some(ast::def_binding(did)); }
_ { }
}
@ -918,7 +937,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
}
scope_arm(a) {
if ns == ns_val(ns_any_value) {
alt lookup_in_pat(name, a.pats[0]) {
alt lookup_in_pat(e, name, a.pats[0]) {
some(did) { ret some(ast::def_binding(did)); }
_ { ret none; }
}
@ -997,11 +1016,13 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
ret none::<def>;
}
fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t<def_id> {
fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option::t<def_id> {
let found = none;
ast_util::pat_bindings(pat) {|bound|
let p_name = alt bound.node { ast::pat_bind(n, _) { n } };
if str::eq(p_name, name) { found = some(local_def(bound.id)); }
pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat)) {|bound|
let p_name = alt bound.node { ast::pat_ident(n, _) { n } };
if str::eq(path_to_ident(p_name), name)
{ found = some(local_def(bound.id)); }
};
ret found;
}
@ -1041,7 +1062,7 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
let (style, loc) = locs[j];
if ns == ns_val(ns_any_value)
&& (i < pos || j < loc_pos) {
alt lookup_in_pat(name, loc.node.pat) {
alt lookup_in_pat(e, name, loc.node.pat) {
some(did) {
ret some(ast::def_local(did, style));
}
@ -1571,9 +1592,9 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
}
}
fn check_pat(ch: checker, p: @ast::pat) {
ast_util::pat_bindings(p) {|p|
let ident = alt p.node { pat_bind(n, _) { n } };
fn check_pat(e: @env, ch: checker, p: @ast::pat) {
pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|p|
let ident = path_to_ident(alt p.node { pat_ident(n, _) { n } });
add_name(ch, p.span, ident);
};
}
@ -1581,13 +1602,13 @@ fn check_pat(ch: checker, p: @ast::pat) {
fn check_arm(e: @env, a: ast::arm, &&x: (), v: vt<()>) {
visit::visit_arm(a, x, v);
let ch0 = checker(*e, "binding");
check_pat(ch0, a.pats[0]);
check_pat(e, ch0, a.pats[0]);
let seen0 = ch0.seen;
let i = vec::len(a.pats);
while i > 1u {
i -= 1u;
let ch = checker(*e, "binding");
check_pat(ch, a.pats[i]);
check_pat(e, ch, a.pats[i]);
// Ensure the bindings introduced in this pattern are the same as in
// the first pattern.
@ -1620,8 +1641,11 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
ast::decl_local(locs) {
let local_values = checker(*e, "value");
for (_, loc) in locs {
ast_util::pat_bindings(loc.node.pat) {|p|
let ident = alt p.node { pat_bind(n, _) { n } };
pat_util::pat_bindings
(normalize_pat_def_map(e.def_map, loc.node.pat))
{|p|
let ident = path_to_ident(alt p.node
{ pat_ident(n, _) { n } });
add_name(local_values, p.span, ident);
check_name(values, p.span, ident);
};

View File

@ -26,7 +26,8 @@ import back::{link, abi, upcall};
import syntax::{ast, ast_util, codemap};
import syntax::visit;
import syntax::codemap::span;
import syntax::print::pprust::{expr_to_str, stmt_to_str};
import syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str};
import pat_util::*;
import visit::vt;
import util::common::*;
import lib::llvm::{llvm, mk_target_data, mk_type_names};
@ -775,6 +776,8 @@ fn GEP_tag(cx: @block_ctxt, llblobptr: ValueRef, tag_id: ast::def_id,
let true_arg_tys: [ty::t] = [];
for aty: ty::t in arg_tys {
// Would be nice to have a way of stating the invariant
// that ty_substs is valid for aty
let arg_ty = ty::substitute_type_params(bcx_tcx(cx), ty_substs, aty);
true_arg_tys += [arg_ty];
}
@ -2203,7 +2206,7 @@ fn trans_eager_binop(cx: @block_ctxt, op: ast::binop, lhs: ValueRef,
if is_float { FAdd(cx, lhs, rhs) }
else { Add(cx, lhs, rhs) }
}
ast::sub. {
ast::subtract. {
if is_float { FSub(cx, lhs, rhs) }
else { Sub(cx, lhs, rhs) }
}
@ -2641,6 +2644,7 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result {
alt table.find(id) {
some(local_mem(v)) { {val: v, kind: owned} }
some(local_imm(v)) { {val: v, kind: owned_imm} }
r { fail("take_local: internal error"); }
}
}
alt def {
@ -2649,9 +2653,11 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> local_var_result {
ret { val: cx.fcx.llupvars.get(did.node), kind: owned };
}
ast::def_arg(did, _) {
assert (cx.fcx.llargs.contains_key(did.node));
ret take_local(cx.fcx.llargs, did.node);
}
ast::def_local(did, _) | ast::def_binding(did) {
assert (cx.fcx.lllocals.contains_key(did.node));
ret take_local(cx.fcx.lllocals, did.node);
}
ast::def_self(did) {
@ -3502,6 +3508,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
ret trans_expr(bcx, ast_util::ternary_to_if(e), dest);
}
ast::expr_alt(expr, arms) {
// tcx.sess.span_note(e.span, "about to call trans_alt");
ret trans_alt::trans_alt(bcx, expr, arms, dest);
}
ast::expr_block(blk) {
@ -4205,8 +4212,9 @@ fn alloc_ty(cx: @block_ctxt, t: ty::t) -> result {
fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt {
let t = node_id_type(bcx_ccx(cx), local.node.id);
let is_simple = alt local.node.pat.node {
ast::pat_bind(_, none.) { true } _ { false }
let p = normalize_pat(bcx_tcx(cx), local.node.pat);
let is_simple = alt p.node {
ast::pat_ident(_, none.) { true } _ { false }
};
// Do not allocate space for locals that can be kept immediate.
let ccx = bcx_ccx(cx);
@ -4219,10 +4227,10 @@ fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt {
}
}
let r = alloc_ty(cx, t);
alt local.node.pat.node {
ast::pat_bind(ident, none.) {
alt p.node {
ast::pat_ident(pth, none.) {
if bcx_ccx(cx).sess.opts.debuginfo {
let _: () = str::as_buf(ident, {|buf|
let _: () = str::as_buf(path_to_ident(pth), {|buf|
llvm::LLVMSetValueName(r.val, buf)
});
}
@ -4635,7 +4643,7 @@ fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
if is_float { llvm::LLVMConstFAdd(te1, te2) }
else { llvm::LLVMConstAdd(te1, te2) }
}
ast::sub. {
ast::subtract. {
if is_float { llvm::LLVMConstFSub(te1, te2) }
else { llvm::LLVMConstSub(te1, te2) }
}

View File

@ -1,8 +1,10 @@
import core::{str, vec, option};
import option::{some, none};
import driver::session::session;
import lib::llvm::llvm;
import lib::llvm::llvm::{ValueRef, BasicBlockRef};
import pat_util::*;
import trans_build::*;
import trans::{new_sub_block_ctxt, new_scope_block_ctxt, load_if_immediate};
import syntax::ast;
@ -10,6 +12,7 @@ import syntax::ast_util;
import syntax::ast_util::{dummy_sp};
import syntax::ast::def_id;
import syntax::codemap::span;
import syntax::print::pprust::pat_to_str;
import trans_common::*;
@ -61,6 +64,7 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
}
}
// FIXME: invariant -- pat_id is bound in the def_map?
fn variant_opt(ccx: @crate_ctxt, pat_id: ast::node_id) -> opt {
let vdef = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat_id));
let variants = ty::tag_variants(ccx.tcx, vdef.tg);
@ -83,13 +87,13 @@ type match_branch =
bound: bind_map,
data: @{body: BasicBlockRef,
guard: option::t<@ast::expr>,
id_map: ast_util::pat_id_map}};
id_map: pat_id_map}};
type match = [match_branch];
fn has_nested_bindings(m: match, col: uint) -> bool {
for br in m {
alt br.pats[col].node {
ast::pat_bind(_, some(_)) { ret true; }
ast::pat_ident(_, some(_)) { ret true; }
_ {}
}
}
@ -99,12 +103,13 @@ fn has_nested_bindings(m: match, col: uint) -> bool {
fn expand_nested_bindings(m: match, col: uint, val: ValueRef) -> match {
let result = [];
for br in m {
alt br.pats[col].node {
ast::pat_bind(name, some(inner)) {
alt br.pats[col].node {
ast::pat_ident(name, some(inner)) {
let pats = vec::slice(br.pats, 0u, col) + [inner] +
vec::slice(br.pats, col + 1u, vec::len(br.pats));
result += [@{pats: pats,
bound: br.bound + [{ident: name, val: val}]
bound: br.bound + [{ident: path_to_ident(name),
val: val}]
with *br}];
}
_ { result += [br]; }
@ -124,8 +129,9 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match {
vec::slice(br.pats, col + 1u, vec::len(br.pats));
let new_br = @{pats: pats,
bound: alt br.pats[col].node {
ast::pat_bind(name, none.) {
br.bound + [{ident: name, val: val}]
ast::pat_ident(name, none.) {
br.bound + [{ident: path_to_ident(name),
val: val}]
}
_ { br.bound }
} with *br};
@ -139,11 +145,11 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match {
fn enter_default(m: match, col: uint, val: ValueRef) -> match {
fn matches_always(p: @ast::pat) -> bool {
ret alt p.node {
ast::pat_wild. | ast::pat_bind(_, none.) | ast::pat_rec(_, _) |
ast::pat_tup(_) { true }
_ { false }
};
alt p.node {
ast::pat_wild. | ast::pat_rec(_, _) |
ast::pat_ident(_, none.) | ast::pat_tup(_) { true }
_ { false }
}
}
fn e(p: @ast::pat) -> option::t<[@ast::pat]> {
ret if matches_always(p) { some([]) } else { none };
@ -257,6 +263,8 @@ fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id,
vdefs: {tg: def_id, var: def_id}, val: ValueRef) ->
{vals: [ValueRef], bcx: @block_ctxt} {
let ccx = bcx.fcx.lcx.ccx, bcx = bcx;
// invariant:
// pat_id must have the same length ty_param_substs as vdefs?
let ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id);
let blobptr = val;
let variants = ty::tag_variants(ccx.tcx, vdefs.tg);
@ -274,6 +282,9 @@ fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id,
while i < size {
check (valid_variant_index(i, bcx, vdefs_tg, vdefs_var));
let r =
// invariant needed:
// how do we know it even makes sense to pass in ty_param_substs
// here? What if it's [] and the tag type has variables in it?
trans::GEP_tag(bcx, blobptr, vdefs_tg, vdefs_var, ty_param_substs,
i);
bcx = r.bcx;
@ -328,7 +339,7 @@ fn pick_col(m: match) -> uint {
fn score(p: @ast::pat) -> uint {
alt p.node {
ast::pat_lit(_) | ast::pat_tag(_, _) | ast::pat_range(_, _) { 1u }
ast::pat_bind(_, some(p)) { score(p) }
ast::pat_ident(_, some(p)) { score(p) }
_ { 0u }
}
}
@ -582,7 +593,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
// Returns false for unreachable blocks
fn make_phi_bindings(bcx: @block_ctxt, map: [exit_node],
ids: ast_util::pat_id_map) -> bool {
ids: pat_util::pat_id_map) -> bool {
let our_block = bcx.llbb as uint;
let success = true, bcx = bcx;
ids.items {|name, node_id|
@ -623,7 +634,7 @@ fn make_phi_bindings(bcx: @block_ctxt, map: [exit_node],
ret success;
}
fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm],
fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms_: [ast::arm],
dest: trans::dest) -> @block_ctxt {
let bodies = [];
let match: match = [];
@ -633,9 +644,15 @@ fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm],
let er = trans::trans_temp_expr(alt_cx, expr);
if er.bcx.unreachable { ret er.bcx; }
/*
n.b. nothing else in this module should need to normalize,
b/c of this call
*/
let arms = normalize_arms(bcx_tcx(cx), arms_);
for a: ast::arm in arms {
let body = new_scope_block_ctxt(er.bcx, "case_body");
let id_map = ast_util::pat_id_map(a.pats[0]);
let id_map = pat_util::pat_id_map(bcx_tcx(cx), a.pats[0]);
bodies += [body];
for p: @ast::pat in a.pats {
match +=
@ -666,7 +683,8 @@ fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm],
for a: ast::arm in arms {
let body_cx = bodies[i];
if make_phi_bindings(body_cx, exit_map,
ast_util::pat_id_map(a.pats[0])) {
pat_util::pat_id_map(bcx_tcx(cx),
a.pats[0])) {
let arm_dest = trans::dup_for_join(dest);
arm_dests += [arm_dest];
arm_cxs += [trans::trans_block_dps(body_cx, a.body, arm_dest)];
@ -684,8 +702,10 @@ fn trans_alt(cx: @block_ctxt, expr: @ast::expr, arms: [ast::arm],
fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
make_copy: bool) -> @block_ctxt {
let ccx = bcx.fcx.lcx.ccx, bcx = bcx;
alt pat.node {
ast::pat_bind(_, inner) {
// Necessary since bind_irrefutable_pat is called outside trans_alt
alt normalize_pat(bcx_tcx(bcx), pat).node {
ast::pat_ident(_,inner) {
if make_copy || ccx.copy_map.contains_key(pat.id) {
let ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
// FIXME: Could constrain pat_bind to make this

View File

@ -1,12 +1,12 @@
import core::{int, uint};
import syntax::ast::*;
import syntax::ast_util::pat_binding_ids;
import syntax::visit;
import syntax::codemap::span;
import util::common::{log_stmt};
import aux::{num_constraints, get_fn_info, crate_ctxt, add_node};
import middle::tstate::ann::empty_ann;
import ann::empty_ann;
import pat_util::pat_binding_ids;
fn collect_ids_expr(e: @expr, rs: @mutable [node_id]) { *rs += [e.id]; }

View File

@ -1,5 +1,6 @@
import core::{vec, int, uint, option};
import option::*;
import pat_util::*;
import syntax::ast::*;
import syntax::ast_util::*;
import syntax::{visit, codemap};
@ -69,10 +70,10 @@ fn tritv_to_str(fcx: fn_ctxt, v: tritv::t) -> str {
for p: norm_constraint in constraints(fcx) {
alt tritv_get(v, p.bit_num) {
dont_care. { }
t {
tt {
s +=
if comma { ", " } else { comma = true; "" } +
if t == tfalse { "!" } else { "" } +
if tt == tfalse { "!" } else { "" } +
constraint_to_str(fcx.ccx.tcx, p.c);
}
}
@ -313,7 +314,7 @@ fn node_id_to_ts_ann(ccx: crate_ctxt, id: node_id) -> ts_ann {
#error("node_id_to_ts_ann: no ts_ann for node_id %d", id);
fail;
}
some(t) { ret t; }
some(tt) { ret tt; }
}
}
@ -779,13 +780,6 @@ fn replace(subst: subst, d: pred_args) -> [constr_arg_general_<inst>] {
ret rslt;
}
fn path_to_ident(cx: ty::ctxt, p: @path) -> ident {
alt vec::last(p.node.idents) {
none. { cx.sess.span_fatal(p.span, "Malformed path"); }
some(i) { ret i; }
}
}
tag if_ty { if_check; plain_if; }
fn local_node_id_to_def_id_strict(fcx: fn_ctxt, sp: span, i: node_id) ->
@ -1059,18 +1053,20 @@ fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: [arg], c: @constr) ->
type binding = {lhs: [inst], rhs: option::t<initializer>};
fn local_to_bindings(loc: @local) -> binding {
fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding {
let lhs = [];
pat_bindings(loc.node.pat) {|p|
let ident = alt p.node { pat_bind(name, _) { name } };
pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p|
let ident = alt p.node
{ pat_ident(name, _) { path_to_ident(name) } };
lhs += [{ident: ident, node: p.id}];
};
{lhs: lhs, rhs: loc.node.init}
}
fn locals_to_bindings(locals: [(let_style, @local)]) -> [binding] {
fn locals_to_bindings(tcx: ty::ctxt,
locals: [(let_style, @local)]) -> [binding] {
let rslt = [];
for (_, loc) in locals { rslt += [local_to_bindings(loc)]; }
for (_, loc) in locals { rslt += [local_to_bindings(tcx, loc)]; }
ret rslt;
}

View File

@ -1,18 +1,20 @@
import option::*;
import pat_util::*;
import syntax::ast::*;
import syntax::ast_util::*;
import option::*;
import syntax::visit;
import aux::*;
import util::common::new_def_hash;
import syntax::codemap::span;
import syntax::ast_util::respan;
import driver::session::session;
import aux::*;
type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt};
fn collect_local(loc: @local, cx: ctxt, v: visit::vt<ctxt>) {
pat_bindings(loc.node.pat) {|p|
let ident = alt p.node { pat_bind(id, _) { id } };
pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat)) {|p|
let ident = alt p.node
{ pat_ident(id, _) { path_to_ident(id) } };
log(debug, "collect_local: pushing " + ident);;
*cx.cs += [respan(loc.span, ninit(p.id, ident))];
};

View File

@ -8,6 +8,8 @@ import bitvectors::{bit_num, seq_preconds, seq_postconds,
intersect_states,
relax_precond_block, gen};
import tritv::*;
import pat_util::*;
import syntax::ast::*;
import syntax::ast_util::*;
import syntax::visit;
@ -16,6 +18,7 @@ import util::common::{new_def_hash, log_expr, field_exprs,
import syntax::codemap::span;
import driver::session::session;
fn find_pre_post_mod(_m: _mod) -> _mod {
#debug("implement find_pre_post_mod!");
fail;
@ -103,8 +106,9 @@ fn find_pre_post_loop(fcx: fn_ctxt, l: @local, index: @expr, body: blk,
id: node_id) {
find_pre_post_expr(fcx, index);
find_pre_post_block(fcx, body);
pat_bindings(l.node.pat) {|p|
let ident = alt p.node { pat_bind(id, _) { id } };
pat_bindings(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p|
let ident = alt p.node
{ pat_ident(id, _) { path_to_ident(id) } };
let v_init = ninit(p.id, ident);
relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body);
// Hack: for-loop index variables are frequently ignored,
@ -197,7 +201,7 @@ fn gen_if_local(fcx: fn_ctxt, lhs: @expr, rhs: @expr, larger_id: node_id,
set_pre_and_post(fcx.ccx, larger_id, p.precondition,
p.postcondition);
gen(fcx, larger_id,
ninit(d_id.node, path_to_ident(fcx.ccx.tcx, pth)));
ninit(d_id.node, path_to_ident(pth)));
}
_ { find_pre_post_exprs(fcx, [lhs, rhs], larger_id); }
}
@ -232,7 +236,7 @@ fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr,
def_local(d_id, _) {
let i =
bit_num(fcx,
ninit(d_id.node, path_to_ident(fcx.ccx.tcx, p)));
ninit(d_id.node, path_to_ident(p)));
require_and_preserve(i, expr_pp(fcx.ccx, lhs));
}
_ { }
@ -250,9 +254,9 @@ fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr,
alt d1 {
some(id1) {
let instlhs =
{ident: path_to_ident(fcx.ccx.tcx, p), node: id};
{ident: path_to_ident(p), node: id};
let instrhs =
{ident: path_to_ident(fcx.ccx.tcx, p1), node: id1};
{ident: path_to_ident(p1), node: id1};
copy_in_poststate_two(fcx, tmp, post, instlhs, instrhs,
ty);
}
@ -340,7 +344,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
expr_path(p) {
let rslt = expr_pp(fcx.ccx, e);
clear_pp(rslt);
handle_var(fcx, rslt, e.id, path_to_ident(fcx.ccx.tcx, p));
handle_var(fcx, rslt, e.id, path_to_ident(p));
}
expr_log(_, lvl, arg) {
find_pre_post_exprs(fcx, [lvl, arg], e.id);
@ -581,18 +585,19 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) {
_ { }
}
pat_bindings(alocal.node.pat) {|pat|
pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat))
{|pat|
/* FIXME: This won't be necessary when typestate
works well enough for pat_bindings to return a
refinement-typed thing. */
let ident = alt pat.node { pat_bind(n, _) { n } };
let ident = alt pat.node
{ pat_ident(n, _) { path_to_ident(n) } };
alt p {
some(p) {
copy_in_postcond(fcx, id,
{ident: ident, node: pat.id},
{ident:
path_to_ident(fcx.ccx.tcx,
p),
path_to_ident(p),
node: an_init.expr.id},
op_to_oper_ty(an_init.op));
}
@ -612,11 +617,14 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) {
seq_preconds(fcx, [prev_pp, e_pp]));
/* Include the LHSs too, since those aren't in the
postconds of the RHSs themselves */
pat_bindings(alocal.node.pat) {|pat|
pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat))
{|pat|
// FIXME
// Generalize this pattern? map_if_ident...
alt pat.node {
pat_bind(n, _) {
set_in_postcond(bit_num(fcx, ninit(pat.id, n)),
prev_pp);
pat_ident(n, _) {
set_in_postcond(bit_num(fcx,
ninit(pat.id, path_to_ident(n))), prev_pp);
}
}
};

View File

@ -5,6 +5,7 @@ import aux::*;
import tritv::{tritv_clone, tritv_set, ttrue};
import bitvectors::*;
import pat_util::*;
import syntax::ast::*;
import syntax::ast_util::*;
import syntax::codemap::span;
@ -37,7 +38,7 @@ fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path,
some(rhsid) {
// RHS is a local var
let instrhs =
{ident: path_to_ident(fcx.ccx.tcx, rhs_path), node: rhsid.node};
{ident: path_to_ident(rhs_path), node: rhsid.node};
copy_in_poststate(fcx, post, instlhs, instrhs,
op_to_oper_ty(init_op));
}
@ -143,9 +144,9 @@ fn find_pre_post_state_two(fcx: fn_ctxt, pres: prestate, lhs: @expr,
alt d1 {
some(id1) {
let instlhs =
{ident: path_to_ident(fcx.ccx.tcx, p), node: id};
{ident: path_to_ident(p), node: id};
let instrhs =
{ident: path_to_ident(fcx.ccx.tcx, p1), node: id1};
{ident: path_to_ident(p1), node: id1};
copy_in_poststate_two(fcx, tmp, post, instlhs, instrhs,
ty);
}
@ -206,8 +207,9 @@ fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local,
// Make sure the index vars are considered initialized
// in the body
let index_post = tritv_clone(expr_poststate(fcx.ccx, index));
pat_bindings(l.node.pat) {|p|
let ident = alt p.node { pat_bind(name, _) { name } };
pat_bindings(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p|
let ident = alt p.node
{ pat_ident(name, _) { path_to_ident(name) } };
set_in_poststate_ident(fcx, p.id, ident, index_post);
};
@ -231,7 +233,7 @@ fn gen_if_local(fcx: fn_ctxt, p: poststate, e: @expr) -> bool {
alt fcx.ccx.tcx.def_map.find(e.id) {
some(def_local(loc, _)) {
ret set_in_poststate_ident(fcx, loc.node,
path_to_ident(fcx.ccx.tcx, pth), p);
path_to_ident(pth), p);
}
_ { ret false; }
}
@ -632,7 +634,8 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool {
alt adecl.node {
decl_local(alocals) {
set_prestate(stmt_ann, pres);
let c_and_p = seq_states(fcx, pres, locals_to_bindings(alocals));
let c_and_p = seq_states(fcx, pres,
locals_to_bindings(fcx.ccx.tcx, alocals));
/* important to do this in one step to ensure
termination (don't want to set changed to true
for intermediate changes) */

View File

@ -371,6 +371,8 @@ const idx_first_others: uint = 20u;
type type_store = interner::interner<@raw_t>;
// substs is a list of actuals that correspond to ty's
// formal parameters
type ty_param_substs_opt_and_ty = {substs: option::t<[ty::t]>, ty: ty::t};
type node_type_table =
@ -2215,7 +2217,7 @@ mod unify {
ty::ty_box(expected_mt) {
alt struct(cx.tcx, actual) {
ty::ty_box(actual_mt) {
let (mut, var) = alt unify_mut(
let (mutt, var) = alt unify_mut(
expected_mt.mut, actual_mt.mut, variance) {
none. { ret ures_err(terr_box_mutability); }
some(mv) { mv }
@ -2224,7 +2226,7 @@ mod unify {
cx, expected_mt.ty, actual_mt.ty, var);
alt result {
ures_ok(result_sub) {
let mt = {ty: result_sub, mut: mut};
let mt = {ty: result_sub, mut: mutt};
ret ures_ok(mk_box(cx.tcx, mt));
}
_ { ret result; }
@ -2236,7 +2238,7 @@ mod unify {
ty::ty_uniq(expected_mt) {
alt struct(cx.tcx, actual) {
ty::ty_uniq(actual_mt) {
let (mut, var) = alt unify_mut(
let (mutt, var) = alt unify_mut(
expected_mt.mut, actual_mt.mut, variance) {
none. { ret ures_err(terr_box_mutability); }
some(mv) { mv }
@ -2245,7 +2247,7 @@ mod unify {
cx, expected_mt.ty, actual_mt.ty, var);
alt result {
ures_ok(result_mt) {
let mt = {ty: result_mt, mut: mut};
let mt = {ty: result_mt, mut: mutt};
ret ures_ok(mk_uniq(cx.tcx, mt));
}
_ { ret result; }
@ -2257,7 +2259,7 @@ mod unify {
ty::ty_vec(expected_mt) {
alt struct(cx.tcx, actual) {
ty::ty_vec(actual_mt) {
let (mut, var) = alt unify_mut(
let (mutt, var) = alt unify_mut(
expected_mt.mut, actual_mt.mut, variance) {
none. { ret ures_err(terr_vec_mutability); }
some(mv) { mv }
@ -2266,7 +2268,7 @@ mod unify {
cx, expected_mt.ty, actual_mt.ty, var);
alt result {
ures_ok(result_sub) {
let mt = {ty: result_sub, mut: mut};
let mt = {ty: result_sub, mut: mutt};
ret ures_ok(mk_vec(cx.tcx, mt));
}
_ { ret result; }
@ -2278,7 +2280,7 @@ mod unify {
ty::ty_ptr(expected_mt) {
alt struct(cx.tcx, actual) {
ty::ty_ptr(actual_mt) {
let (mut, var) = alt unify_mut(
let (mutt, var) = alt unify_mut(
expected_mt.mut, actual_mt.mut, variance) {
none. { ret ures_err(terr_vec_mutability); }
some(mv) { mv }
@ -2287,7 +2289,7 @@ mod unify {
cx, expected_mt.ty, actual_mt.ty, var);
alt result {
ures_ok(result_sub) {
let mt = {ty: result_sub, mut: mut};
let mt = {ty: result_sub, mut: mutt};
ret ures_ok(mk_ptr(cx.tcx, mt));
}
_ { ret result; }
@ -2342,7 +2344,7 @@ mod unify {
while i < expected_len {
let expected_field = expected_fields[i];
let actual_field = actual_fields[i];
let (mut, var) = alt unify_mut(
let (mutt, var) = alt unify_mut(
expected_field.mt.mut, actual_field.mt.mut, variance)
{
none. { ret ures_err(terr_record_mutability); }
@ -2359,7 +2361,7 @@ mod unify {
actual_field.mt.ty, var);
alt result {
ures_ok(rty) {
let mt = {ty: rty, mut: mut};
let mt = {ty: rty, mut: mutt};
result_fields += [{mt: mt with expected_field}];
}
_ { ret result; }
@ -2579,11 +2581,18 @@ fn type_err_to_str(err: ty::type_err) -> str {
// Replaces type parameters in the given type using the given list of
// substitions.
fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
if !type_contains_params(cx, typ) { ret typ; }
if !type_contains_params(cx, typ) { ret typ; }
// Precondition? idx < vec::len(substs)
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
-> t {
// FIXME: bounds check can fail
ret substs[idx];
if idx < vec::len(*substs) {
ret substs[idx];
}
else {
fail #fmt("Internal error in substituter (substitute_type_params)\
%u %u", vec::len(*substs), idx);
}
}
ret fold_ty(cx, fm_param(bind substituter(cx, @substs, _, _)), typ);
}
@ -2729,7 +2738,7 @@ fn is_binopable(cx: ctxt, ty: t, op: ast::binop) -> bool {
fn opcat(op: ast::binop) -> int {
alt op {
ast::add. { opcat_add }
ast::sub. { opcat_sub }
ast::subtract. { opcat_sub }
ast::mul. { opcat_mult }
ast::div. { opcat_mult }
ast::rem. { opcat_mult }

View File

@ -6,6 +6,7 @@ import metadata::csearch;
import driver::session::session;
import util::common::*;
import syntax::codemap::span;
import pat_util::*;
import middle::ty;
import middle::ty::{node_id_to_type, arg, block_ty,
expr_ty, field, node_type_table, mk_nil,
@ -1137,8 +1138,8 @@ fn gather_locals(ccx: @crate_ctxt,
// Add pattern bindings.
let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) {
alt p.node {
ast::pat_bind(_, _) { assign(p.id, none); }
alt normalize_pat(ccx.tcx, p).node {
ast::pat_ident(_, _) { assign(p.id, none); }
_ {/* no-op */ }
}
visit::visit_pat(p, e, v);
@ -1181,9 +1182,9 @@ fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool {
// Pattern checking is top-down rather than bottom-up so that bindings get
// their types immediately.
fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat,
expected: ty::t) {
alt pat.node {
alt normalize_pat(fcx.ccx.tcx, pat).node {
ast::pat_wild. {
alt structure_of(fcx, pat.span, expected) {
ty::ty_tag(_, expected_tps) {
@ -1218,11 +1219,11 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
}
write::ty_only_fixup(fcx, pat.id, b_ty);
}
ast::pat_bind(name, sub) {
ast::pat_ident(name, sub) {
let vid = lookup_local(fcx, pat.span, pat.id);
let typ = ty::mk_var(fcx.ccx.tcx, vid);
typ = demand::simple(fcx, pat.span, expected, typ);
let canon_id = map.get(name);
let canon_id = map.get(path_to_ident(name));
if canon_id != pat.id {
let ct =
ty::mk_var(fcx.ccx.tcx,
@ -2014,7 +2015,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// bindings.
let pattern_ty = ty::expr_ty(tcx, expr);
for arm: ast::arm in arms {
let id_map = ast_util::pat_id_map(arm.pats[0]);
let id_map = pat_util::pat_id_map(tcx, arm.pats[0]);
for p: @ast::pat in arm.pats {
check_pat(fcx, id_map, p, pattern_ty);
}
@ -2360,7 +2361,7 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
}
_ {/* fall through */ }
}
let id_map = ast_util::pat_id_map(local.node.pat);
let id_map = pat_util::pat_id_map(fcx.ccx.tcx, local.node.pat);
check_pat(fcx, id_map, local.node.pat, t);
}
}

View File

@ -39,6 +39,7 @@ mod middle {
mod gc;
mod debuginfo;
mod capture;
mod pat_util;
mod tstate {
mod ck;

View File

@ -97,7 +97,17 @@ type field_pat = {ident: ident, pat: @pat};
tag pat_ {
pat_wild;
pat_bind(ident, option::t<@pat>);
// A pat_ident may either be a new bound variable,
// or a nullary tag (in which case the second field
// is none).
// In the nullary tag case, the parser can't determine
// which it is. The resolver determines this, and
// records this pattern's node_id in an auxiliary
// set (of "pat_idents that refer to nullary tags")
// After the resolution phase, code should never pattern-
// match on a pat directly! Always call pat_util::normalize_pat --
// it turns any pat_idents that refer to nullary tags into pat_tags.
pat_ident(@path, option::t<@pat>);
pat_tag(@path, [@pat]);
pat_rec([field_pat], bool);
pat_tup([@pat]);
@ -126,7 +136,7 @@ pure fn is_blockish(p: ast::proto) -> bool {
tag binop {
add;
sub;
subtract;
mul;
div;
rem;

View File

@ -33,43 +33,10 @@ fn def_id_of_def(d: def) -> def_id {
}
}
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(pat: @pat) -> pat_id_map {
let map = std::map::new_str_hash::<node_id>();
pat_bindings(pat) {|bound|
let name = alt bound.node { pat_bind(n, _) { n } };
map.insert(name, bound.id);
};
ret map;
}
// FIXME: could return a constrained type
fn pat_bindings(pat: @pat, it: block(@pat)) {
alt pat.node {
pat_bind(_, option::none.) { it(pat); }
pat_bind(_, option::some(sub)) { it(pat); pat_bindings(sub, it); }
pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } }
pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } }
pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } }
pat_box(sub) { pat_bindings(sub, it); }
pat_uniq(sub) { pat_bindings(sub, it); }
pat_wild. | pat_lit(_) | pat_range(_, _) { }
}
}
fn pat_binding_ids(pat: @pat) -> [node_id] {
let found = [];
pat_bindings(pat) {|b| found += [b.id]; };
ret found;
}
fn binop_to_str(op: binop) -> str {
alt op {
add. { ret "+"; }
sub. { ret "-"; }
subtract. { ret "-"; }
mul. { ret "*"; }
div. { ret "/"; }
rem. { ret "%"; }
@ -262,7 +229,7 @@ fn eval_const_expr(e: @expr) -> const_val {
alt (eval_const_expr(a), eval_const_expr(b)) {
(const_float(a), const_float(b)) {
alt op {
add. { const_float(a + b) } sub. { const_float(a - b) }
add. { const_float(a + b) } subtract. { const_float(a - b) }
mul. { const_float(a * b) } div. { const_float(a / b) }
rem. { const_float(a % b) } eq. { fromb(a == b) }
lt. { fromb(a < b) } le. { fromb(a <= b) } ne. { fromb(a != b) }
@ -271,7 +238,7 @@ fn eval_const_expr(e: @expr) -> const_val {
}
(const_int(a), const_int(b)) {
alt op {
add. { const_int(a + b) } sub. { const_int(a - b) }
add. { const_int(a + b) } subtract. { const_int(a - b) }
mul. { const_int(a * b) } div. { const_int(a / b) }
rem. { const_int(a % b) } and. | bitand. { const_int(a & b) }
or. | bitor. { const_int(a | b) } bitxor. { const_int(a ^ b) }
@ -282,7 +249,7 @@ fn eval_const_expr(e: @expr) -> const_val {
}
(const_uint(a), const_uint(b)) {
alt op {
add. { const_uint(a + b) } sub. { const_uint(a - b) }
add. { const_uint(a + b) } subtract. { const_uint(a - b) }
mul. { const_uint(a * b) } div. { const_uint(a / b) }
rem. { const_uint(a % b) } and. | bitand. { const_uint(a & b) }
or. | bitor. { const_uint(a | b) } bitxor. { const_uint(a ^ b) }
@ -327,6 +294,10 @@ fn lit_eq(a: @lit, b: @lit) -> bool {
compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0
}
fn ident_to_path(s: span, i: ident) -> @path {
@respan(s, {global: false, idents: [i], types: []})
}
// Local Variables:
// mode: rust
// fill-column: 78;

View File

@ -10,6 +10,7 @@ export make_fold;
export noop_fold_crate;
export noop_fold_item;
export noop_fold_expr;
export noop_fold_pat;
export noop_fold_mod;
export noop_fold_ty;
@ -273,8 +274,8 @@ fn noop_fold_arm(a: arm, fld: ast_fold) -> arm {
fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
ret alt p {
pat_wild. { p }
pat_bind(ident, sub) {
pat_bind(fld.fold_ident(ident), option::map(sub, fld.fold_pat))
pat_ident(pth, sub) {
pat_ident(fld.fold_path(pth), option::map(sub, fld.fold_pat))
}
pat_lit(_) { p }
pat_tag(pth, pats) {
@ -317,8 +318,8 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
let fold_mac = bind fold_mac_(_, fld);
ret alt e {
expr_vec(exprs, mut) {
expr_vec(fld.map_exprs(fld.fold_expr, exprs), mut)
expr_vec(exprs, mutt) {
expr_vec(fld.map_exprs(fld.fold_expr, exprs), mutt)
}
expr_rec(fields, maybe_expr) {
expr_rec(vec::map(fields, fold_field),
@ -390,8 +391,7 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
}
expr_path(pth) { expr_path(fld.fold_path(pth)) }
expr_fail(e) { expr_fail(option::map(e, fld.fold_expr)) }
expr_break. { e }
expr_cont. { e }
expr_break. | expr_cont. { e }
expr_ret(e) { expr_ret(option::map(e, fld.fold_expr)) }
expr_be(e) { expr_be(fld.fold_expr(e)) }
expr_log(i, lv, e) { expr_log(i, fld.fold_expr(lv),

View File

@ -8,6 +8,7 @@ import token::can_begin_expr;
import codemap::span;
import util::interner;
import ast::{node_id, spanned};
import ast_util::{mk_sp, ident_to_path};
import front::attr;
import lexer::reader;
import driver::diagnostic;
@ -1097,7 +1098,7 @@ fn prec_table() -> @[op_spec] {
{tok: token::BINOP(token::SLASH), op: ast::div, prec: 11},
{tok: token::BINOP(token::PERCENT), op: ast::rem, prec: 11},
{tok: token::BINOP(token::PLUS), op: ast::add, prec: 10},
{tok: token::BINOP(token::MINUS), op: ast::sub, prec: 10},
{tok: token::BINOP(token::MINUS), op: ast::subtract, prec: 10},
{tok: token::BINOP(token::LSL), op: ast::lsl, prec: 9},
{tok: token::BINOP(token::LSR), op: ast::lsr, prec: 9},
{tok: token::BINOP(token::ASR), op: ast::asr, prec: 9},
@ -1165,7 +1166,7 @@ fn parse_assign_expr(p: parser) -> @ast::expr {
let aop = ast::add;
alt op {
token::PLUS. { aop = ast::add; }
token::MINUS. { aop = ast::sub; }
token::MINUS. { aop = ast::subtract; }
token::STAR. { aop = ast::mul; }
token::SLASH. { aop = ast::div; }
token::PERCENT. { aop = ast::rem; }
@ -1426,7 +1427,11 @@ fn parse_pat(p: parser) -> @ast::pat {
break;
}
let lo1 = p.last_span.lo;
let fieldname = parse_ident(p);
let hi1 = p.last_span.lo;
let fieldpath = ast_util::ident_to_path(ast_util::mk_sp(lo1, hi1),
fieldname);
let subpat;
if p.token == token::COLON {
p.bump();
@ -1436,7 +1441,7 @@ fn parse_pat(p: parser) -> @ast::pat {
p.fatal("found " + fieldname + " in binding position");
}
subpat = @{id: p.get_id(),
node: ast::pat_bind(fieldname, none),
node: ast::pat_ident(fieldpath, none),
span: ast_util::mk_sp(lo, hi)};
}
fields += [{ident: fieldname, pat: subpat}];
@ -1478,7 +1483,10 @@ fn parse_pat(p: parser) -> @ast::pat {
}
} else if is_plain_ident(p) &&
alt p.look_ahead(1u) {
token::DOT. | token::LPAREN. | token::LBRACKET. {
// Take this out once the libraries change
token::DOT. |
token::LPAREN. | token::LBRACKET. |
token::LT. {
false
}
_ { true }
@ -1486,7 +1494,7 @@ fn parse_pat(p: parser) -> @ast::pat {
hi = p.span.hi;
let name = parse_value_ident(p);
let sub = eat(p, token::AT) ? some(parse_pat(p)) : none;
pat = ast::pat_bind(name, sub);
pat = ast::pat_ident(ident_to_path(mk_sp(lo, hi), name), sub);
} else {
let tag_path = parse_path_and_ty_param_substs(p, true);
hi = tag_path.span.hi;
@ -1499,10 +1507,19 @@ fn parse_pat(p: parser) -> @ast::pat {
args = a.node;
hi = a.span.hi;
}
token::LBRACE. { args = []; }
// take this out once the libraries change
token::DOT. { args = []; p.bump(); }
_ { expect(p, token::LPAREN); fail; }
}
pat = ast::pat_tag(tag_path, args);
// at this point, we're not sure whether it's a tag or a bind
if vec::len(args) == 0u &&
vec::len(tag_path.node.idents) == 1u {
pat = ast::pat_ident(tag_path, none);
}
else {
pat = ast::pat_tag(tag_path, args);
}
}
}
}

View File

@ -1055,10 +1055,12 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
maybe_print_comment(s, pat.span.lo);
let ann_node = node_pat(s, pat);
s.ann.pre(ann_node);
/* Pat isn't normalized, but the beauty of it
is that it doesn't matter */
alt pat.node {
ast::pat_wild. { word(s.s, "_"); }
ast::pat_bind(id, sub) {
word(s.s, id);
ast::pat_ident(path, sub) {
print_path(s, path, true);
alt sub {
some(p) { word(s.s, "@"); print_pat(s, p); }
_ {}
@ -1070,7 +1072,7 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
popen(s);
commasep(s, inconsistent, args, print_pat);
pclose(s);
} else { word(s.s, "."); }
} else { word(s.s, "."); } // FIXME
}
ast::pat_rec(fields, etc) {
word(s.s, "{");

View File

@ -195,9 +195,13 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
for f: field_pat in fields { v.visit_pat(f.pat, e, v); }
}
pat_tup(elts) { for elt in elts { v.visit_pat(elt, e, v); } }
pat_box(inner) | pat_uniq(inner) | pat_bind(_, some(inner)) {
pat_box(inner) | pat_uniq(inner) {
v.visit_pat(inner, e, v);
}
pat_ident(path, inner) {
visit_path(path, e, v);
option::may(inner, {|subpat| v.visit_pat(subpat, e, v)});
}
_ { }
}
}

View File

@ -1278,7 +1278,7 @@ mod node {
while true {
alt(get_current_or_next_leaf(it)) {
option::none. { ret option::none; }
option::some(leaf) {
option::some(_) {
let next_char = get_next_char_in_leaf(it);
alt(next_char) {
option::none. {
@ -1301,7 +1301,7 @@ mod node {
let next = leaf_iterator::next(it.leaf_iterator);
alt(next) {
option::none. { ret option::none }
option::some(leaf) {
option::some(_) {
it.leaf = next;
it.leaf_byte_pos = 0u;
ret next;
@ -1314,16 +1314,16 @@ mod node {
fn get_next_char_in_leaf(it: t) -> option::t<char> {
alt(it.leaf) {
option::none. { ret option::none }
option::some(leaf) {
if it.leaf_byte_pos >= leaf.byte_len {
option::some(aleaf) {
if it.leaf_byte_pos >= aleaf.byte_len {
//We are actually past the end of the leaf
it.leaf = option::none;
ret option::none
} else {
let {ch, next} =
str::char_range_at(*leaf.content,
it.leaf_byte_pos + leaf.byte_offset);
it.leaf_byte_pos = next - leaf.byte_offset;
str::char_range_at(*aleaf.content,
it.leaf_byte_pos + aleaf.byte_offset);
it.leaf_byte_pos = next - aleaf.byte_offset;
ret option::some(ch)
}
}

View File

@ -1,6 +1,6 @@
fn main() {
let i: int =
alt some::<int>(3) { none::<int>. { fail } some::<int>(_) { 5 } };
alt some::<int>(3) { none::<int> { fail } some::<int>(_) { 5 } };
log(debug, i);
}

View File

@ -0,0 +1,10 @@
tag blah { a; b; }
fn or_alt(q: blah) -> int {
alt q { a. | b. { 42 } }
}
fn main() {
assert (or_alt(a) == 42);
assert (or_alt(b) == 42);
}