bind resolve::resolve_crate(sess, ast_map, crate));
auto freevars =
time(time_passes, "freevar finding",
- bind freevars::annotate_freevars(sess, d._0, crate));
- auto ty_cx = ty::mk_ctxt(sess, d._0, d._1, ast_map, freevars);
+ bind freevars::annotate_freevars(sess, d, crate));
+ auto ty_cx = ty::mk_ctxt(sess, d, ast_map, freevars);
time[()](time_passes, "typechecking",
bind typeck::check_crate(ty_cx, crate));
if (sess.get_opts().run_typestate) {
case (ppm_typed) {
auto amap = middle::ast_map::map_crate(*crate);
auto d = resolve::resolve_crate(sess, amap, crate);
- auto freevars = freevars::annotate_freevars(sess, d._0, crate);
- auto ty_cx = ty::mk_ctxt(sess, d._0, d._1, amap, freevars);
+ auto freevars = freevars::annotate_freevars(sess, d, crate);
+ auto ty_cx = ty::mk_ctxt(sess, d, amap, freevars);
typeck::check_crate(ty_cx, crate);
ann = rec(pre=ann_paren_for_expr,
post=bind ann_typed_post(ty_cx, _));
import std::option::none;
import std::option::some;
import syntax::ast;
+import syntax::ast::*;
import ast::respan;
import middle::ty;
}
}
-fn parse_constrs(@pstate st, str_def sd) -> (@ty::constr_def)[] {
- let (@ty::constr_def)[] rslt = ~[];
+fn parse_constrs(@pstate st, str_def sd) -> (@ty::constr)[] {
+ let (@ty::constr)[] rslt = ~[];
alt (peek(st) as char) {
case (':') {
- do {
+ do {
next(st);
- rslt += ~[parse_constr(st, sd)];
+ let @ty::constr one = parse_constr[uint](st, sd,
+ parse_constr_arg);
+ rslt += ~[one];
} while (peek(st) as char == ';')
}
case (_) { }
fail "parse_path: ill-formed path";
}
-fn parse_constr(@pstate st, str_def sd) -> @ty::constr_def {
- let (@ast::constr_arg)[] args = ~[];
+type arg_parser[T] = fn (@pstate st, str_def sd)
+ -> ast::constr_arg_general_[T];
+
+fn parse_constr_arg(@pstate st, str_def sd) -> ast::fn_constr_arg {
+ alt (peek(st) as char) {
+ case ('*') {
+ st.pos += 1u;
+ ret ast::carg_base;
+ }
+ case (?c) {
+ /* how will we disambiguate between
+ an arg index and a lit argument? */
+ if (c >= '0' && c <= '9') {
+ next(st);
+ // FIXME
+ ret ast::carg_ident((c as uint) - 48u);
+ }
+ else {
+ log_err("Lit args are unimplemented");
+ fail; // FIXME
+ }
+ /*
+ else {
+ auto lit = parse_lit(st, sd, ',');
+ args += [respan(st.span, ast::carg_lit(lit))];
+ }
+ */
+ }
+ }
+}
+
+fn parse_constr[T](@pstate st, str_def sd, arg_parser[T] pser)
+ -> @ty::constr_general[T] {
auto sp = rec(lo=0u,hi=0u); // FIXME: use a real span
- let ast::path pth = parse_path(st, sd);
+ let (@sp_constr_arg[T])[] args = ~[];
+ let path pth = parse_path(st, sd);
let char ignore = next(st) as char;
assert(ignore as char == '(');
auto def = parse_def(st, sd);
+ let constr_arg_general_[T] an_arg;
do {
- alt (peek(st) as char) {
- case ('*') {
- st.pos += 1u;
- args += ~[@respan(sp, ast::carg_base)];
- }
- case (?c) {
- /* how will we disambiguate between
- an arg index and a lit argument? */
- if (c >= '0' && c <= '9') {
- // FIXME
- args += ~[@respan(sp,
- ast::carg_ident((c as uint) - 48u))];
- ignore = next(st) as char;
- }
- else {
- log_err("Lit args are unimplemented");
- fail; // FIXME
- }
- /*
- else {
- auto lit = parse_lit(st, sd, ',');
- args += [respan(st.span, ast::carg_lit(lit))];
- }
- */
- }
- }
+ an_arg = pser(st, sd);
+ // FIXME use a real span
+ args += ~[@respan(sp, an_arg)];
ignore = next(st) as char;
} while (ignore == ';');
assert(ignore == ')');
}
fn parse_ty_fn(@pstate st, str_def sd) ->
- tup(ty::arg[], ty::t, ast::controlflow, (@ty::constr_def)[]) {
+ tup(ty::arg[], ty::t, ast::controlflow, (@ty::constr)[]) {
assert (next(st) as char == '[');
let ty::arg[] inputs = ~[];
while (peek(st) as char != ']') {
auto def_id = uint::parse_buf(def_part_vec, 10u) as int;
ret tup(crate_num, def_id);
}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
import std::uint;
import syntax::ast::*;
import middle::ty;
-import syntax::print::pprust::lit_to_str;
+import syntax::print::pprust::*;
import util::common;
export ctxt;
case (proto_fn) { w.write_char('F'); }
}
}
+
fn enc_ty_fn(&ioivec::writer w, &@ctxt cx, &ty::arg[] args, &ty::t out,
- &controlflow cf, &(@ty::constr_def)[] constrs) {
+ &controlflow cf, &(@ty::constr)[] constrs) {
w.write_char('[');
for (ty::arg arg in args) {
alt (arg.mode) {
}
w.write_char(']');
auto colon = true;
- for (@ty::constr_def c in constrs) {
+ for (@ty::constr c in constrs) {
if (colon) {
w.write_char(':');
colon = false;
}
}
-fn enc_constr(&ioivec::writer w, &@ctxt cx, &@ty::constr_def c) {
+
+fn enc_constr(&ioivec::writer w, &@ctxt cx, &@ty::constr c) {
w.write_str(path_to_str(c.node.path));
w.write_char('(');
w.write_str(cx.ds(c.node.id));
import syntax::ast;
+import syntax::ast::*;
import ast::ident;
import ast::fn_ident;
import ast::def;
import syntax::visit;
import visit::vt;
import std::ivec;
+import std::int;
import std::map::hashmap;
import std::list;
import std::list::list;
import std::option::some;
import std::option::none;
import std::str;
+import syntax::print::pprust::*;
export resolve_crate;
export def_map;
type env =
rec(cstore::cstore cstore,
def_map def_map,
- constr_table fn_constrs,
ast_map::map ast_map,
hashmap[ast::node_id, import_state] imports,
hashmap[ast::node_id, @indexed_mod] mod_map,
tag namespace { ns_value; ns_type; ns_module; }
-fn resolve_crate(session sess, &ast_map::map amap, @ast::crate crate) ->
- tup(def_map, constr_table) {
+fn resolve_crate(session sess, &ast_map::map amap, @ast::crate crate)
+ -> def_map {
auto e =
@rec(cstore=sess.get_cstore(),
def_map=new_int_hash[def](),
- fn_constrs = new_int_hash[ty::constr_def[]](),
ast_map=amap,
imports=new_int_hash[import_state](),
mod_map=new_int_hash[@indexed_mod](),
resolve_imports(*e);
check_for_collisions(e, *crate);
resolve_names(e, crate);
- ret tup(e.def_map, e.fn_constrs);
+ ret e.def_map;
}
visit_arm=bind walk_arm(e, _, _, _),
visit_expr=bind walk_expr(e, _, _, _),
visit_ty=bind walk_ty(e, _, _, _),
- visit_constr=bind walk_constr(e, _, _, _),
+ visit_constr=bind walk_constr(e, _, _, _, _, _),
visit_fn=bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
with *visit::default_visitor());
visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v));
case (_) { }
}
}
- fn walk_constr(@env e, &@ast::constr c, &scopes sc, &vt[scopes] v) {
- maybe_insert(e, c.node.id,
- lookup_path_strict(*e, sc, c.span, c.node.path.node,
- ns_value));
+ fn walk_constr(@env e, &ast::path p, &span sp, node_id id,
+ &scopes sc, &vt[scopes] v) {
+ maybe_insert(e, id, lookup_path_strict(*e, sc, sp, p.node, ns_value));
}
fn walk_arm(@env e, &ast::arm a, &scopes sc, &vt[scopes] v) {
for (@ast::pat p in a.pats) { walk_pat(*e, sc, p); }
if (option::is_some(new_def)) {
alt (option::get(new_def)) {
case (ast::def_fn(?pred_id, ast::pure_fn)) {
- let ty::constr_general[uint] c_ =
- rec(path=c.node.path, args=c.node.args, id=pred_id);
- let ty::constr_def new_constr = respan(c.span, c_);
- add_constr(e, id, new_constr);
+ e.def_map.insert(c.node.id, ast::def_fn(pred_id,
+ ast::pure_fn));
}
case (_) {
e.sess.span_err(c.span,
"Non-predicate in constraint: " +
- ast::path_to_str(c.node.path));
+ path_to_str(c.node.path));
}
}
}
}
-fn add_constr(&@env e, node_id id, &ty::constr_def c) {
- e.fn_constrs.insert(id,
- alt (e.fn_constrs.find(id)) {
- case (none) { ~[c] }
- case (some(?cs)) { cs + ~[c] }
- });
-}
-
-
// Import resolution
fn resolve_import(&env e, &@ast::view_item it, scopes sc) {
auto defid;
ret rslt;
}
-fn constraint_to_str(&ty::ctxt tcx, &constr c) -> str {
- alt (c.node.c) {
- case (ninit(?i)) {
+fn constraint_to_str(&ty::ctxt tcx, &sp_constr c) -> str {
+ alt (c.node) {
+ case (ninit(_,?i)) {
ret "init(" + i + " [" + tcx.sess.span_str(c.span) + "])";
}
- case (npred(?p, ?args)) {
+ case (npred(?p, _, ?args)) {
ret path_to_str(p) + "(" + comma_str(args) + ")" + "[" +
tcx.sess.span_str(c.span) + "]";
}
Both types store an ident and span, for error-logging purposes.
*/
-type pred_desc_ = rec((@constr_arg_use)[] args, uint bit_num);
+type pred_args_ = rec((@constr_arg_use)[] args, uint bit_num);
-type pred_desc = spanned[pred_desc_];
+type pred_args = spanned[pred_args_];
-// FIXME: Should be node_id, since we can only talk
-// about locals.
-type constr_arg_use = constr_arg_general[tup(ident, def_id)];
+// The attached node ID is the *defining* node ID
+// for this local.
+type constr_arg_use = spanned[constr_arg_general_[inst]];
tag constraint {
cinit(uint, span, ident);
- cpred(path, @mutable pred_desc[]);
+ // FIXME: really only want it to be mutable during collect_locals.
+ // freeze it after that.
+ cpred(path, @mutable (pred_args[]));
}
-tag constr__ {
- ninit(ident);
- npred(path, (@constr_arg_use)[]);
+// An ninit variant has a node_id because it refers to a local var.
+// An npred has a def_id since the definition of the typestate
+// predicate need not be local.
+// FIXME: would be nice to give both a def_id field,
+// and give ninit a constraint saying it's local.
+tag tsconstr {
+ ninit(node_id, ident);
+ npred(path, def_id, (@constr_arg_use)[]);
}
-type constr_ = rec(node_id id, constr__ c);
+type sp_constr = spanned[tsconstr];
-type constr = spanned[constr_];
+type norm_constraint = rec(uint bit_num, sp_constr c);
-type norm_constraint = rec(uint bit_num, constr c);
-
-type constr_map = @std::map::hashmap[node_id, constraint];
+type constr_map = @std::map::hashmap[def_id, constraint];
type fn_info = rec(constr_map constrs,
uint num_constraints,
// bug?
@mutable node_id[] used_vars);
+fn tsconstr_to_def_id(&tsconstr t) -> def_id {
+ alt (t) {
+ case (ninit(?id,_)) { local_def(id) }
+ case (npred(_,?id,_)) { id }
+ }
+}
/* mapping from node ID to typestate annotation */
type node_ann_table = @mutable ts_ann[mutable];
}
}
-fn constraints_expr(&ty::ctxt cx, @expr e) -> (@ty::constr_def)[] {
+fn constraints_expr(&ty::ctxt cx, @expr e) -> (@ty::constr)[] {
alt (ty::struct(cx, ty::node_id_to_type(cx, e.id))) {
case (ty::ty_fn(_, _, _, _, ?cs)) { ret cs; }
case (_) { ret ~[]; }
ret ccx.tcx.def_map.find(id);
}
-fn norm_a_constraint(node_id id, &constraint c) -> norm_constraint[] {
+fn norm_a_constraint(def_id id, &constraint c) -> norm_constraint[] {
alt (c) {
case (cinit(?n, ?sp, ?i)) {
- ret ~[rec(bit_num=n, c=respan(sp, rec(id=id, c=ninit(i))))];
+ ret ~[rec(bit_num=n, c=respan(sp, ninit(id._1, i)))];
}
case (cpred(?p, ?descs)) {
let norm_constraint[] rslt = ~[];
- for (pred_desc pd in *descs) {
+ for (pred_args pd in *descs) {
rslt += ~[rec(bit_num=pd.node.bit_num,
c=respan(pd.span,
- rec(id=id,
- c=npred(p, pd.node.args))))];
+ npred(p, id, pd.node.args)))];
}
ret rslt;
}
// non-exhaustive match in trans.
fn constraints(&fn_ctxt fcx) -> norm_constraint[] {
let norm_constraint[] rslt = ~[];
- for each (@tup(node_id, constraint) p in fcx.enclosing.constrs.items()) {
+ for each (@tup(def_id, constraint) p in fcx.enclosing.constrs.items()) {
rslt += norm_a_constraint(p._0, p._1);
}
ret rslt;
}
-fn match_args(&fn_ctxt fcx, &pred_desc[] occs, &(@constr_arg_use)[] occ) ->
+// FIXME
+// Would rather take an immutable vec as an argument,
+// should freeze it at some earlier point.
+fn match_args(&fn_ctxt fcx, &(@mutable pred_args[]) occs,
+ &(@constr_arg_use)[] occ) ->
uint {
log "match_args: looking at " +
- constr_args_to_str(std::util::fst[ident, def_id], occ);
- for (pred_desc pd in occs) {
- log "match_args: candidate " + pred_desc_to_str(pd);
- fn eq(&tup(ident, def_id) p, &tup(ident, def_id) q) -> bool {
+ constr_args_to_str(std::util::fst[ident, node_id], occ);
+ for (pred_args pd in *occs) {
+ log "match_args: candidate " + pred_args_to_str(pd);
+ fn eq(&inst p, &inst q) -> bool {
ret p._1 == q._1;
}
if (ty::args_eq(eq, pd.node.args, occ)) { ret pd.node.bit_num; }
fcx.ccx.tcx.sess.bug("match_args: no match for occurring args");
}
-fn node_id_for_constr(ty::ctxt tcx, node_id t) -> node_id {
+fn def_id_for_constr(ty::ctxt tcx, node_id t) -> def_id {
alt (tcx.def_map.find(t)) {
case (none) {
tcx.sess.bug("node_id_for_constr: bad node_id " + int::str(t));
}
- case (some(def_fn(?i,_))) { ret i._1; }
+ case (some(def_fn(?i,_))) { ret i; }
case (_) {
tcx.sess.bug("node_id_for_constr: pred is not a function");
}
alt (tcx.def_map.find(e.id)) {
case (some(def_local(?l_id))) {
ret @respan(p.span, carg_ident(tup(p.node.idents.(0),
- l_id)));
+ l_id._1)));
}
case (some(def_arg(?a_id))) {
ret @respan(p.span, carg_ident(tup(p.node.idents.(0),
- a_id)));
+ a_id._1)));
}
case (_) {
tcx.sess.bug("exprs_to_constr_args: non-local variable " +
rslt
}
-fn expr_to_constr(ty::ctxt tcx, &@expr e) -> constr {
+fn expr_to_constr(ty::ctxt tcx, &@expr e) -> sp_constr {
alt (e.node) {
case (
// FIXME change the first pattern to expr_path to test a
alt (operator.node) {
case (expr_path(?p)) {
ret respan(e.span,
- rec(id=node_id_for_constr(tcx, operator.id),
- c=npred(p, exprs_to_constr_args(tcx,
- args))));
+ npred(p, def_id_for_constr(tcx, operator.id),
+ exprs_to_constr_args(tcx, args)));
}
case (_) {
tcx.sess.span_fatal(operator.span,
}
}
-fn pred_desc_to_str(&pred_desc p) -> str {
+fn pred_args_to_str(&pred_args p) -> str {
"<" + uint::str(p.node.bit_num) + ", " +
- constr_args_to_str(std::util::fst[ident, def_id],
+ constr_args_to_str(std::util::fst[ident, node_id],
p.node.args) + ">"
}
fn substitute_constr_args(&ty::ctxt cx, &(@expr)[] actuals,
- &@ty::constr_def c) -> constr__ {
+ &@ty::constr c) -> tsconstr {
let (@constr_arg_use)[] rslt = ~[];
for (@constr_arg a in c.node.args) {
rslt += ~[substitute_arg(cx, actuals, a)];
}
- ret npred(c.node.path, rslt);
+ ret npred(c.node.path, c.node.id, rslt);
}
fn substitute_arg(&ty::ctxt cx, &(@expr)[] actuals, @constr_arg a) ->
}
}
-fn pred_desc_matches(&(constr_arg_general_[tup(ident, def_id)])[] pattern,
- &pred_desc desc) -> bool {
+fn pred_args_matches(&(constr_arg_general_[inst])[] pattern,
+ &pred_args desc) -> bool {
auto i = 0u;
for (@constr_arg_use c in desc.node.args) {
auto n = pattern.(i);
ret true;
}
-fn find_instance_(&(constr_arg_general_[tup(ident, def_id)])[] pattern,
- &pred_desc[] descs) -> option::t[uint] {
- for (pred_desc d in descs) {
- if (pred_desc_matches(pattern, d)) {
+fn find_instance_(&(constr_arg_general_[inst])[] pattern,
+ &pred_args[] descs) -> option::t[uint] {
+ for (pred_args d in descs) {
+ if (pred_args_matches(pattern, d)) {
ret some(d.node.bit_num);
}
}
ret none;
}
-type inst = tup(ident, def_id);
+type inst = tup(ident, node_id);
type subst = tup(inst, inst)[];
fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
alt (c) {
case (cinit(_,_,_)) { /* this is dealt with separately */ }
case (cpred(?p, ?descs)) {
- for (pred_desc d in *descs) {
+ for (pred_args d in *descs) {
if (args_mention(d.node.args, find_in_subst_bool, subst)) {
auto old_bit_num = d.node.bit_num;
auto new = replace(subst, d);
rslt
}
-fn find_in_subst(def_id id, &subst s) -> option::t[inst] {
+fn find_in_subst(node_id id, &subst s) -> option::t[inst] {
for (tup(inst, inst) p in s) {
if (id == p._0._1) {
ret some(p._1);
ret none;
}
-fn find_in_subst_bool(&subst s, def_id id) -> bool {
+fn find_in_subst_bool(&subst s, node_id id) -> bool {
is_some(find_in_subst(id, s))
}
rslt
}
-fn replace(subst subst, pred_desc d) -> (constr_arg_general_[inst])[] {
+fn replace(subst subst, pred_args d) -> (constr_arg_general_[inst])[] {
let (constr_arg_general_[inst])[] rslt = ~[];
for (@constr_arg_use c in d.node.args) {
alt (c.node) {
}
}
+fn local_node_id_to_local_def_id(&fn_ctxt fcx, &node_id i)
+ -> option::t[node_id] {
+ alt (local_node_id_to_def(fcx, i)) {
+ case (some (def_local(?d_id))) { some(d_id._1) }
+ case (some (def_arg(?a_id))) { some(a_id._1) }
+ case (_) { none }
+ }
+}
+
fn copy_in_postcond(&fn_ctxt fcx, node_id parent_exp, inst dest, inst src,
oper_type ty) {
auto post = node_id_to_ts_ann(fcx.ccx, parent_exp).conditions.
}
}
- for each (@tup(node_id, constraint) p in
+ for each (@tup(def_id, constraint) p in
fcx.enclosing.constrs.items()) {
// replace any occurrences of the src def_id with the
// dest def_id
fn forget_in_postcond(&fn_ctxt fcx, node_id parent_exp, node_id dead_v) {
// In the postcondition given by parent_exp, clear the bits
// for any constraints mentioning dead_v
- auto d = local_node_id_to_def_id(fcx, dead_v);
+ auto d = local_node_id_to_local_def_id(fcx, dead_v);
alt (d) {
case (some(?d_id)) {
for (norm_constraint c in constraints(fcx)) {
node_id dead_v) {
// In the postcondition given by parent_exp, clear the bits
// for any constraints mentioning dead_v
- auto d = local_node_id_to_def_id(fcx, dead_v);
+ auto d = local_node_id_to_local_def_id(fcx, dead_v);
alt (d) {
case (some(?d_id)) {
for (norm_constraint c in constraints(fcx)) {
fn forget_in_poststate(&fn_ctxt fcx, &poststate p, node_id dead_v) -> bool {
// In the poststate given by parent_exp, clear the bits
// for any constraints mentioning dead_v
- auto d = local_node_id_to_def_id(fcx, dead_v);
+ auto d = local_node_id_to_local_def_id(fcx, dead_v);
auto changed = false;
alt (d) {
case (some(?d_id)) {
-> bool {
// In the poststate given by parent_exp, clear the bits
// for any constraints mentioning dead_v
- auto d = local_node_id_to_def_id(fcx, dead_v);
+ auto d = local_node_id_to_local_def_id(fcx, dead_v);
auto changed = false;
alt (d) {
case (some(?d_id)) {
ret changed;
}
-fn any_eq(&(def_id)[] v, def_id d) -> bool {
- for (def_id i in v) {
+fn any_eq(&(node_id)[] v, node_id d) -> bool {
+ for (node_id i in v) {
if (i == d) { ret true; }
}
false
}
-fn constraint_mentions(&fn_ctxt fcx, &norm_constraint c, def_id v) -> bool {
- ret (alt (c.c.node.c) {
- case (ninit(_)) {
- v == local_def(c.c.node.id)
- }
- case (npred(_, ?args)) {
+fn constraint_mentions(&fn_ctxt fcx, &norm_constraint c, node_id v) -> bool {
+ ret (alt (c.c.node) {
+ case (ninit(?id,_)) { v == id }
+ case (npred(_, _, ?args)) {
args_mention(args, any_eq, ~[v])
}
});
}
fn non_init_constraint_mentions(&fn_ctxt fcx, &norm_constraint c,
- &def_id v) -> bool {
- ret (alt (c.c.node.c) {
- case (ninit(_)) {
+ &node_id v) -> bool {
+ ret (alt (c.c.node) {
+ case (ninit(_,_)) {
false
}
- case (npred(_, ?args)) {
+ case (npred(_, _, ?args)) {
args_mention(args, any_eq, ~[v])
}
});
}
-fn args_mention[T](&(@constr_arg_use)[] args, fn(&(T)[], def_id) -> bool q,
+fn args_mention[T](&(@constr_arg_use)[] args, fn(&(T)[], node_id) -> bool q,
&(T)[] s) -> bool {
/*
FIXME
-
import syntax::ast::*;
import syntax::walk;
import std::ivec;
import std::option::*;
-import aux::constr_arg_use;
-import aux::local_node_id_to_def;
-import aux::fn_ctxt;
-import aux::fn_info;
-import aux::log_tritv;
-import aux::log_tritv_err;
-import aux::num_constraints;
-import aux::cinit;
-import aux::cpred;
-import aux::ninit;
-import aux::npred;
-import aux::pred_desc;
-import aux::match_args;
-import aux::constr_;
-import aux::block_precond;
-import aux::stmt_precond;
-import aux::expr_precond;
-import aux::block_prestate;
-import aux::expr_prestate;
-import aux::stmt_prestate;
-import tstate::aux::node_id_to_ts_ann;
+import aux::*;
import tstate::ann::pre_and_post;
import tstate::ann::precond;
import tstate::ann::postcond;
import tstate::ann::clear_in_poststate_;
import tritv::*;
-fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
- assert (fcx.enclosing.constrs.contains_key(c.id));
- auto rslt = fcx.enclosing.constrs.get(c.id);
- alt (c.c) {
- case (ninit(_)) {
+fn bit_num(&fn_ctxt fcx, &tsconstr c) -> uint {
+ auto d = tsconstr_to_def_id(c);
+ assert (fcx.enclosing.constrs.contains_key(d));
+ auto rslt = fcx.enclosing.constrs.get(d);
+ alt (c) {
+ case (ninit(_,_)) {
alt (rslt) {
case (cinit(?n, _, _)) { ret n; }
case (_) {
}
}
}
- case (npred(_, ?args)) {
+ case (npred(_, _, ?args)) {
alt (rslt) {
case (cpred(_, ?descs)) {
- auto d = *descs;
- ret match_args(fcx, d, args);
+ ret match_args(fcx, descs, args);
}
case (_) {
fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint,"
}
}
-fn promises(&fn_ctxt fcx, &poststate p, &constr_ c) -> bool {
+fn promises(&fn_ctxt fcx, &poststate p, &tsconstr c) -> bool {
ret promises_(bit_num(fcx, c), p);
}
ret rslt;
}
-fn gen(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
+fn gen(&fn_ctxt fcx, node_id id, &tsconstr c) -> bool {
ret set_in_postcond(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).conditions);
}
-fn declare_var(&fn_ctxt fcx, &constr_ c, prestate pre) -> prestate {
+fn declare_var(&fn_ctxt fcx, &tsconstr c, prestate pre) -> prestate {
auto rslt = clone(pre);
relax_prestate(bit_num(fcx, c), rslt);
// idea is this is scoped
walk::walk_block(v, b);
}
-fn gen_poststate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
+fn gen_poststate(&fn_ctxt fcx, node_id id, &tsconstr c) -> bool {
log "gen_poststate";
ret set_in_poststate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states);
}
-fn kill_prestate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
+fn kill_prestate(&fn_ctxt fcx, node_id id, &tsconstr c) -> bool {
ret clear_in_prestate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states);
}
-fn kill_poststate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
+fn kill_poststate(&fn_ctxt fcx, node_id id, &tsconstr c) -> bool {
log "kill_poststate";
ret clear_in_poststate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states);
case (some(?i)) {
alt (local_node_id_to_def(fcx, e.id)) {
case (some(def_local(?d_id))) {
- clear_in_poststate_(bit_num(fcx,
- rec(id=d_id._1,
- c=ninit(i))), t);
+ clear_in_poststate_(
+ bit_num(fcx,ninit(d_id._1, i)), t);
}
case (some(_)) { /* ignore args (for now...) */ }
case (_) {
fn set_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&poststate t) -> bool {
- ret set_in_poststate_(bit_num(fcx, rec(id=id, c=ninit(ident))), t);
+ ret set_in_poststate_(bit_num(fcx, ninit(id, ident)), t);
}
fn clear_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&node_id parent) -> bool {
- ret kill_poststate(fcx, parent, rec(id=id, c=ninit(ident)));
+ ret kill_poststate(fcx, parent, ninit(id, ident));
}
fn clear_in_prestate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&node_id parent) -> bool {
- ret kill_prestate(fcx, parent, rec(id=id, c=ninit(ident)));
+ ret kill_prestate(fcx, parent, ninit(id, ident));
}
//
fn check_unused_vars(&fn_ctxt fcx) {
// FIXME: could be more efficient
for (norm_constraint c in constraints(fcx)) {
- alt (c.c.node.c) {
- case (ninit(?v)) {
- if (!vec_contains(fcx.enclosing.used_vars,
- c.c.node.id)) {
+ alt (c.c.node) {
+ case (ninit(?id, ?v)) {
+ if (!vec_contains(fcx.enclosing.used_vars, id)) {
fcx.ccx.tcx.sess.span_warn(c.c.span,
"Unused variable " + v);
}
/* Check that the return value is initialized */
auto post = aux::block_poststate(fcx.ccx, f.body);
- let aux::constr_ ret_c = rec(id=fcx.id, c=aux::ninit(fcx.name));
+ let tsconstr ret_c = ninit(fcx.id, fcx.name);
if (f.proto == ast::proto_fn && !promises(fcx, post, ret_c) &&
!type_is_nil(fcx.ccx.tcx, ret_ty_of_fn(fcx.ccx.tcx, id)) &&
f.decl.cf == return) {
import syntax::codemap::span;
import syntax::ast::respan;
-type ctxt = rec(@mutable (aux::constr[]) cs, ty::ctxt tcx);
+type ctxt = rec(@mutable (sp_constr[]) cs, ty::ctxt tcx);
fn collect_local(&@local loc, &ctxt cx, &visit::vt[ctxt] v) {
log "collect_local: pushing " + loc.node.ident;
- *cx.cs += ~[respan(loc.span, rec(id=loc.node.id,
- c=ninit(loc.node.ident)))];
+ *cx.cs += ~[respan(loc.span, ninit(loc.node.id, loc.node.ident))];
visit::visit_local(loc, cx, v);
}
// If it's a call, generate appropriate instances of the
// call's constraints.
case (expr_call(?operator, ?operands)) {
- for (@ty::constr_def c in constraints_expr(cx.tcx, operator)) {
- let aux::constr ct = respan(c.span,
- rec(id=c.node.id._1,
- c=aux::substitute_constr_args(cx.tcx, operands,
- c)));
+ for (@ty::constr c in constraints_expr(cx.tcx, operator)) {
+ let sp_constr ct = respan(c.span,
+ aux::substitute_constr_args(cx.tcx, operands,
+ c));
*cx.cs += ~[ct];
}
}
ret cx;
}
-fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl) ->
+fn add_constraint(&ty::ctxt tcx, sp_constr c, uint next, constr_map tbl) ->
uint {
- log aux::constraint_to_str(tcx, c) + " |-> " + std::uint::str(next);
- alt (c.node.c) {
- case (ninit(?i)) { tbl.insert(c.node.id, cinit(next, c.span, i)); }
- case (npred(?p, ?args)) {
- alt (tbl.find(c.node.id)) {
+ log constraint_to_str(tcx, c) + " |-> " + std::uint::str(next);
+ alt (c.node) {
+ case (ninit(?id, ?i)) { tbl.insert(local_def(id),
+ cinit(next, c.span, i)); }
+ case (npred(?p, ?d_id, ?args)) {
+ alt (tbl.find(d_id)) {
case (some(?ct)) {
alt (ct) {
case (cinit(_, _, _)) {
}
case (cpred(_, ?pds)) {
*pds += ~[respan(c.span,
- rec(args=args, bit_num=next))];
+ rec(args=args, bit_num=next))];
}
}
}
case (none) {
- tbl.insert(c.node.id,
- cpred(p,
- @mutable ~[respan(c.span,
- rec(args=args,
- bit_num=next))]));
+ let @mutable(pred_args[]) rslt = @mutable(~[respan(c.span,
+ rec(args=args,
+ bit_num=next))]);
+ tbl.insert(d_id, cpred(p, rslt));
}
}
}
to a bit number in the precondition/postcondition vectors */
fn mk_fn_info(&crate_ctxt ccx, &_fn f, &ty_param[] tp,
&span f_sp, &fn_ident f_name, node_id id) {
- auto res_map = @new_int_hash[constraint]();
+ auto res_map = @new_def_hash[constraint]();
let uint next = 0u;
let ctxt cx = find_locals(ccx.tcx, f, tp, f_sp, f_name, id);
/* now we have to add bit nums for both the constraints
and the variables... */
- for (aux::constr c in { *cx.cs }) {
+ for (sp_constr c in { *cx.cs }) {
next = add_constraint(cx.tcx, c, next, res_map);
}
/* add a pseudo-entry for the function's return value
we can safely use the function's name itself for this purpose */
auto name = fn_ident_to_string(id, f_name);
- add_constraint(cx.tcx, respan(f_sp, rec(id=id, c=ninit(name))), next,
- res_map);
+ add_constraint(cx.tcx, respan(f_sp, ninit(id, name)), next, res_map);
let @mutable node_id[] v = @mutable ~[];
auto rslt =
rec(constrs=res_map,
// make a fake fcx
let @mutable node_id[] v = @mutable ~[];
auto fake_fcx =
- rec(enclosing=rec(constrs=@new_int_hash[constraint](),
+ rec(enclosing=rec(constrs=@new_def_hash[constraint](),
num_constraints=0u,
cf=return,
used_vars=v),
node_id id) {
find_pre_post_expr(fcx, index);
find_pre_post_block(fcx, body);
- auto v_init = rec(id=l.node.id, c=ninit(l.node.ident));
+ auto v_init = ninit(l.node.id, l.node.ident);
relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body);
// Hack: for-loop index variables are frequently ignored,
case (none) {
alt (chck) {
case (if_check) {
- let aux::constr c = expr_to_constr(fcx.ccx.tcx, antec);
+ let sp_constr c = expr_to_constr(fcx.ccx.tcx, antec);
gen(fcx, antec.id, c.node);
}
case (_) {}
so that it's *not* set in the alternative. */
alt (chck) {
case (if_check) {
- let aux::constr c = expr_to_constr(fcx.ccx.tcx, antec);
+ let sp_constr c = expr_to_constr(fcx.ccx.tcx, antec);
gen(fcx, antec.id, c.node);
}
case (_) {}
set_pre_and_post(fcx.ccx, larger_id, p.precondition,
p.postcondition);
gen(fcx, larger_id,
- rec(id=d_id._1,
- c=ninit(path_to_ident(fcx.ccx.tcx, pth))));
+ ninit(d_id._1, path_to_ident(fcx.ccx.tcx, pth)));
}
case (_) { find_pre_post_exprs(fcx, ~[lhs, rhs], larger_id); }
}
alt (df) {
case (def_local(?d_id)) {
auto i =
- bit_num(fcx,
- rec(id=d_id._1,
- c=ninit(path_to_ident(fcx.ccx.tcx, p))));
+ bit_num(fcx, ninit(d_id._1,
+ path_to_ident(fcx.ccx.tcx, p)));
require_and_preserve(i, expr_pp(fcx.ccx, lhs));
}
case (_) {}
gen_if_local(fcx, lhs, rhs, parent.id, lhs.id, p);
alt (rhs.node) {
case (expr_path(?p1)) {
- auto d = local_node_id_to_def_id(fcx, lhs.id);
- auto d1 = local_node_id_to_def_id(fcx, rhs.id);
+ auto d = local_node_id_to_local_def_id(fcx, lhs.id);
+ auto d1 = local_node_id_to_local_def_id(fcx, rhs.id);
alt (d) {
case (some(?id)) {
alt (d1) {
find_pre_post_exprs(fcx, args, e.id);
/* see if the call has any constraints on its type */
- for (@ty::constr_def c in constraints_expr(fcx.ccx.tcx, operator))
+ for (@ty::constr c in constraints_expr(fcx.ccx.tcx, operator))
{
auto i =
- bit_num(fcx,
- rec(id=c.node.id._1,
- c=substitute_constr_args(fcx.ccx.tcx,
- args, c)));
+ bit_num(fcx, substitute_constr_args(fcx.ccx.tcx,
+ args, c));
require(i, expr_pp(fcx.ccx, e));
}
case (def_local(?d_id)) {
auto i =
bit_num(fcx,
- rec(id=d_id._1,
- c=ninit(path_to_ident(fcx.ccx.tcx, p))));
+ ninit(d_id._1, path_to_ident(fcx.ccx.tcx, p)));
use_var(fcx, d_id._1);
require_and_preserve(i, rslt);
}
copy_pre_post(fcx.ccx, e.id, p);
/* predicate p holds after this expression executes */
- let aux::constr c = expr_to_constr(fcx.ccx.tcx, p);
+ let sp_constr c = expr_to_constr(fcx.ccx.tcx, p);
gen(fcx, e.id, c.node);
}
case (expr_if_check(?p, ?conseq, ?maybe_alt)) {
case (expr_path(?p)) {
copy_in_postcond(fcx, id,
tup(alocal.node.ident,
- local_def(alocal.node.id)),
+ alocal.node.id),
tup(path_to_ident(fcx.ccx.tcx, p),
- local_def(an_init.expr.id)),
- op_to_oper_ty(an_init.op));
+ an_init.expr.id),
+ op_to_oper_ty(an_init.op));
}
case (_) {}
}
gen(fcx, id,
- rec(id=alocal.node.id,
- c=ninit(alocal.node.ident)));
+ ninit(alocal.node.id,
+ alocal.node.ident));
if (an_init.op == init_move &&
is_path(an_init.expr)) {
}
fn find_pre_post_state_sub(&fn_ctxt fcx, &prestate pres, &@expr e,
- node_id parent, option::t[aux::constr_] c)
- -> bool {
+ node_id parent, option::t[tsconstr] c) -> bool {
auto changed = find_pre_post_state_expr(fcx, pres, e);
changed = set_prestate_ann(fcx.ccx, parent, pres) || changed;
gen_if_local(fcx, post, lhs);
alt (rhs.node) {
case (expr_path(?p1)) {
- auto d = local_node_id_to_def_id(fcx, lhs.id);
- auto d1 = local_node_id_to_def_id(fcx, rhs.id);
+ auto d = local_node_id_to_local_def_id(fcx, lhs.id);
+ auto d1 = local_node_id_to_local_def_id(fcx, rhs.id);
alt (d) {
case (some(?id)) {
alt (d1) {
auto conseq_prestate = expr_poststate(fcx.ccx, antec);
alt (chk) {
case (if_check) {
- let aux::constr c = expr_to_constr(fcx.ccx.tcx, antec);
+ let sp_constr c = expr_to_constr(fcx.ccx.tcx, antec);
conseq_prestate = tritv_clone(conseq_prestate);
tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue);
}
alt (fcx.enclosing.cf) {
case (noreturn) {
- kill_poststate(fcx, e.id, rec(id=fcx.id,
- c=ninit(fcx.name)));
+ kill_poststate(fcx, e.id, ninit(fcx.id, fcx.name));
}
case (_) { }
}
}
case (expr_check(_, ?p)) {
/* predicate p holds after this expression executes */
- let aux::constr c = expr_to_constr(fcx.ccx.tcx, p);
+ let sp_constr c = expr_to_constr(fcx.ccx.tcx, p);
ret find_pre_post_state_sub(fcx, pres, p, e.id, some(c.node));
}
case (expr_if_check(?p, ?conseq, ?maybe_alt)) {
auto instlhs =
tup(alocal.node.ident,
- local_def(alocal.node.id));
- auto rhs_d = local_node_id_to_def_id(fcx,
- an_init.expr.id);
+ alocal.node.id);
+ auto rhs_d = local_node_id_to_local_def_id
+ (fcx, an_init.expr.id);
alt (rhs_d) {
case (some(?rhsid)) {
auto instrhs =
import std::smallintmap;
import driver::session;
import syntax::ast;
-import ast::def_id;
-import ast::constr_arg_general;
-import ast::mutability;
-import ast::controlflow;
-import ast::path_to_str;
-import ast::spanned;
+import syntax::ast::*;
import syntax::codemap::span;
import metadata::csearch;
import util::common::*;
import syntax::util::interner;
import util::ppaux::ty_to_str;
+import util::ppaux::ty_constr_to_str;
import util::ppaux::mode_str_1;
-
+import syntax::print::pprust::*;
export node_id_to_monotype;
export node_id_to_type;
export args_eq;
export bind_params_in_type;
export block_ty;
-export constr_def;
+export constr;
+export constr_;
export constr_general;
export constr_table;
export count_ty_params;
export mk_box;
export mk_chan;
export mk_char;
+export mk_constr;
export mk_ctxt;
export mk_float;
export mk_fn;
export ty_box;
export ty_chan;
export ty_char;
+export ty_constr;
export ty_float;
export ty_fn;
export ty_fn_abi;
export ty_vec;
export ty_param_substs_opt_and_ty_to_monotype;
export ty_fn_args;
+export type_constr;
export type_contains_params;
export type_contains_vars;
export type_err;
arg[] inputs,
t output,
controlflow cf,
- (@constr_def)[] constrs);
+ (@constr)[] constrs);
-type constr_table = hashmap[ast::node_id, constr_def[]];
+type constr_table = hashmap[ast::node_id, constr[]];
type mt = rec(t ty, ast::mutability mut);
ast_map::map items,
freevars::freevar_map freevars,
- constr_table fn_constrs,
+ // constr_table fn_constrs,
type_cache tcache,
creader_cache rcache,
hashmap[t, str] short_names_cache,
ty_task;
ty_tup(mt[]);
ty_rec(field[]);
- ty_fn(ast::proto, arg[], t, controlflow, (@constr_def)[]);
+ ty_fn(ast::proto, arg[], t, controlflow, (@constr)[]);
ty_native_fn(ast::native_abi, arg[], t);
ty_obj(method[]);
ty_res(def_id, t, t[]);
ty_param(uint); // fn/tag type param
ty_type;
ty_native(def_id);
+ ty_constr(t, (@type_constr)[]);
// TODO: ty_fn_arg(t), for a possibly-aliased function argument
}
-type constr_def = spanned[constr_general[uint]];
-
-type constr_general[T] =
- rec(ast::path path, (@constr_arg_general[T])[] args, def_id id);
-
+// In the middle end, constraints have a def_id attached, referring
+// to the definition of the operator in the constraint.
+type constr_general[ARG] = spanned[constr_general_[ARG, def_id]];
+type type_constr = constr_general[path];
+type constr = constr_general[uint];
// Data structures used in type unification
tag type_err {
terr_obj_meths(ast::ident, ast::ident);
terr_arg_count;
terr_mode_mismatch(mode, mode);
+ terr_constr_len(uint, uint);
+ terr_constr_mismatch(@type_constr, @type_constr);
}
type ty_param_count_and_ty = tup(uint, t);
ret map::mk_hashmap[tup(int, uint, uint), t](h, e);
}
-fn mk_ctxt(session::session s, resolve::def_map dm, constr_table cs,
+
+fn mk_ctxt(session::session s, resolve::def_map dm,
ast_map::map amap, freevars::freevar_map freevars) -> ctxt {
let node_type_table ntt =
@smallintmap::mk[ty::ty_param_substs_opt_and_ty]();
node_types=ntt,
items=amap,
freevars=freevars,
- fn_constrs=cs,
tcache=tcache,
rcache=mk_rcache(),
short_names_cache=map::mk_hashmap[ty::t,
derive_flags_t(cx, has_params, has_vars, tt);
}
}
+ case (ty_constr(?tt, _)) {
+ derive_flags_t(cx, has_params, has_vars, tt);
+ }
}
ret rec(struct=st,
cname=cname,
fn mk_rec(&ctxt cx, &field[] fs) -> t { ret gen_ty(cx, ty_rec(fs)); }
+fn mk_constr(&ctxt cx, &t t, &(@type_constr)[] cs) -> t {
+ ret gen_ty(cx, ty_constr(t, cs));
+}
+
fn mk_fn(&ctxt cx, &ast::proto proto, &arg[] args, &t ty, &controlflow cf,
- &(@constr_def)[] constrs) -> t {
+ &(@constr)[] constrs) -> t {
ret gen_ty(cx, ty_fn(proto, args, ty, cf, constrs));
}
h += h << 5u + hash_ty(subty);
ret h;
}
+ fn hash_type_constr(uint id, &@type_constr c)
+ -> uint {
+ auto h = id;
+ h += h << 5u + hash_def(h, c.node.id);
+ ret hash_type_constr_args(h, c.node.args);
+ }
+ fn hash_type_constr_args(uint id, (@ty_constr_arg)[] args) -> uint {
+ auto h = id;
+ for (@ty_constr_arg a in args) {
+ alt (a.node) {
+ case (carg_base) {
+ h += h << 5u;
+ }
+ case (carg_lit(_)) {
+ // FIXME
+ fail "lit args not implemented yet";
+ }
+ case (carg_ident(?p)) {
+ // FIXME: Not sure what to do here.
+ h += h << 5u;
+ }
+ }
+ }
+ ret h;
+ }
+
+
fn hash_fn(uint id, &arg[] args, &t rty) -> uint {
auto h = id;
for (arg a in args) { h += h << 5u + hash_ty(a.ty); }
for (t tp in tps) { h += h << 5u + hash_ty(tp); }
ret h;
}
+ case (ty_constr(?t, ?cs)) {
+ auto h = 36u;
+ for (@type_constr c in cs) {
+ h += h << 5u + hash_type_constr(h, c);
+ }
+ ret h;
+ }
}
}
// users should use `eq_ty()` instead.
fn eq_int(&uint x, &uint y) -> bool { ret x == y; }
-fn arg_eq[T](&fn(&T, &T) -> bool eq, @ast::constr_arg_general[T] a,
- @ast::constr_arg_general[T] b) -> bool {
+fn arg_eq[T](&fn(&T, &T) -> bool eq, @sp_constr_arg[T] a,
+ @sp_constr_arg[T] b) -> bool {
alt (a.node) {
case (ast::carg_base) {
alt (b.node) {
}
}
-fn args_eq[T](fn(&T, &T) -> bool eq, &(@ast::constr_arg_general[T])[] a,
- &(@ast::constr_arg_general[T])[] b) -> bool {
+fn args_eq[T](fn(&T, &T) -> bool eq,
+ &(@sp_constr_arg[T])[] a, &(@sp_constr_arg[T])[] b) -> bool {
let uint i = 0u;
- for (@ast::constr_arg_general[T] arg in a) {
+ for (@sp_constr_arg[T] arg in a) {
if (!arg_eq(eq, arg, b.(i))) { ret false; }
i += 1u;
}
ret true;
}
-fn constr_eq(&@constr_def c, &@constr_def d) -> bool {
+fn constr_eq(&@constr c, &@constr d) -> bool {
ret path_to_str(c.node.path) == path_to_str(d.node.path) &&
// FIXME: hack
args_eq(eq_int, c.node.args, d.node.args);
}
-fn constrs_eq(&(@constr_def)[] cs, &(@constr_def)[] ds) -> bool {
+fn constrs_eq(&(@constr)[] cs, &(@constr)[] ds) -> bool {
if (ivec::len(cs) != ivec::len(ds)) { ret false; }
auto i = 0u;
- for (@constr_def c in cs) {
+ for (@constr c in cs) {
if (!constr_eq(c, ds.(i))) { ret false; }
i += 1u;
}
ret ures_err(terr_mismatch);
}
+ // Right now this just checks that the lists of constraints are
+ // pairwise equal.
+ fn unify_constrs(&t base_t, (@type_constr)[] expected,
+ &(@type_constr)[] actual) -> result {
+ auto expected_len = ivec::len(expected);
+ auto actual_len = ivec::len(actual);
+
+ if (expected_len != actual_len) {
+ ret ures_err(terr_constr_len(expected_len, actual_len));
+ }
+ auto i = 0u;
+ auto rslt;
+ for (@type_constr c in expected) {
+ rslt = unify_constr(base_t, c, actual.(i));
+ alt (rslt) {
+ case (ures_ok(_)) { }
+ case (ures_err(_)) { ret rslt; }
+ }
+ i += 1u;
+ }
+ ret ures_ok(base_t);
+ }
+ fn unify_constr(&t base_t, @type_constr expected,
+ &@type_constr actual_constr) -> result {
+ auto ok_res = ures_ok(base_t);
+ auto err_res = ures_err(terr_constr_mismatch(expected,
+ actual_constr));
+ if (expected.node.id != actual_constr.node.id) {
+ ret err_res;
+ }
+ auto expected_arg_len = ivec::len(expected.node.args);
+ auto actual_arg_len = ivec::len(actual_constr.node.args);
+ if (expected_arg_len != actual_arg_len) {
+ ret err_res;
+ }
+ auto i = 0u;
+ auto actual;
+ for (@ty_constr_arg a in expected.node.args) {
+ actual = actual_constr.node.args.(i);
+ alt (a.node) {
+ case (carg_base) {
+ alt (actual.node) {
+ case (carg_base) { }
+ case (_) { ret err_res; }
+ }
+ }
+ case (carg_lit(?l)) {
+ alt (actual.node) {
+ case (carg_lit(?m)) {
+ if (l != m) { ret err_res; }
+ }
+ case (_) { ret err_res; }
+ }
+ }
+ case (carg_ident(?p)) {
+ alt (actual.node) {
+ case (carg_ident(?q)) {
+ if (p.node != q.node) {
+ ret err_res;
+ }
+ }
+ case (_) { ret err_res; }
+ }
+ }
+ }
+ i += 1u;
+ }
+ ret ok_res;
+ }
+
// Unifies two mutability flags.
fn unify_mut(ast::mutability expected, ast::mutability actual) ->
option::t[ast::mutability] {
&t expected, &t actual, &arg[] expected_inputs,
&t expected_output, &arg[] actual_inputs, &t actual_output,
&controlflow expected_cf, &controlflow actual_cf,
- &(@constr_def)[] expected_constrs,
- &(@constr_def)[] actual_constrs) -> result {
+ &(@constr)[] expected_constrs,
+ &(@constr)[] actual_constrs) -> result {
if (e_proto != a_proto) { ret ures_err(terr_mismatch); }
alt (expected_cf) {
case (ast::return) { }
case (_) { ret ures_err(terr_mismatch); }
}
}
+ case (ty::ty_constr(?expected_t, ?expected_constrs)) {
+ // unify the base types...
+ alt (struct(cx.tcx, actual)) {
+ case (ty::ty_constr(?actual_t, ?actual_constrs)) {
+ auto rslt = unify_step(cx, expected_t, actual_t);
+ alt (rslt) {
+ case (ures_ok(?rty)) {
+ // FIXME: probably too restrictive --
+ // requires the constraints to be
+ // syntactically equal
+ ret unify_constrs(expected,
+ expected_constrs,
+ actual_constrs);
+ }
+ case (_) { ret rslt; }
+ }
+ }
+ case (_) {
+ // If the actual type is *not* a constrained type,
+ // then we go ahead and just ignore the constraints on
+ // the expected type. typestate handles the rest.
+ ret unify_step(cx, expected_t, actual);
+ }
+ }
+ }
}
}
fn unify(&t expected, &t actual, &@var_bindings vb, &ty_ctxt tcx) ->
+ mode_str_1(a_mode);
fail;
}
+ case (terr_constr_len(?e_len, ?a_len)) {
+ ret "Expected a type with " + uint::str(e_len) + " constraints, \
+ but found one with " + uint::str(a_len) + " constraints";
+ }
+ case (terr_constr_mismatch(?e_constr, ?a_constr)) {
+ ret "Expected a type with constraint "
+ + ty_constr_to_str(e_constr) + " but found one with constraint "
+ + ty_constr_to_str(a_constr);
+ }
}
}
import syntax::ast;
import ast::mutability;
import ast::local_def;
-import ast::path_to_str;
import ast::respan;
import ast::spanned;
import syntax::walk;
import std::option::from_maybe;
import std::smallintmap;
import middle::tstate::ann::ts_ann;
+import syntax::print::pprust::*;
export check_crate;
}
typ = ty::mk_obj(tcx, ty::sort_methods(tmeths));
}
+ case (ast::ty_constr(?t, ?cs)) {
+ auto out_cs = ~[];
+ for (@ast::ty_constr constr in cs) {
+ out_cs += ~[ast_constr_to_constr(tcx, constr)];
+ }
+ typ = ty::mk_constr(tcx, ast_ty_to_ty(tcx, getter, t), out_cs);
+ }
}
alt (cname) {
case (none) {/* no-op */ }
ret ivec::last[obj_info](ccx.obj_infos);
}
-fn ast_constr_to_constr(ty::ctxt tcx, &@ast::constr c)
- -> @ty::constr_def {
+fn ast_constr_to_constr[T](ty::ctxt tcx, &@ast::constr_general[T] c)
+ -> @ty::constr_general[T] {
alt (tcx.def_map.find(c.node.id)) {
case (some(ast::def_fn(?pred_id, ast::pure_fn))) {
ret @respan(c.span, rec(path=c.node.path, args=c.node.args,
}
case (_) {
tcx.sess.span_fatal(c.span, "Predicate "
- + path_to_str(c.node.path)
- + " is unbound or bound to a non-function or an\
- impure function");
+ + path_to_str(c.node.path)
+ + " is unbound or bound to a non-function or an \
+ impure function");
}
}
}
ty_obj(ty_method[]);
ty_path(path, node_id);
ty_type;
- ty_constr(@ty, (@constr)[]);
+ ty_constr(@ty, (@ty_constr)[]);
ty_mac(mac);
}
*/
tag constr_arg_general_[T] { carg_base; carg_ident(T); carg_lit(@lit); }
-type constr_arg = constr_arg_general[uint];
+type fn_constr_arg = constr_arg_general_[uint];
+type sp_constr_arg[T] = spanned[constr_arg_general_[T]];
+type ty_constr_arg = sp_constr_arg[path];
+type constr_arg = spanned[fn_constr_arg];
-type constr_arg_general[T] = spanned[constr_arg_general_[T]];
+// Constrained types' args are parameterized by paths, since
+// we refer to paths directly and not by indices.
+// The implicit root of such path, in the constraint-list for a
+// constrained type, is * (referring to the base record)
-type constr_ = rec(path path,
- (@constr_arg_general[uint])[] args,
- node_id id);
-
-type constr = spanned[constr_];
+type constr_general_[ARG, ID] = rec(path path,
+ (@(spanned[constr_arg_general_[ARG]]))[] args, ID id);
+// In the front end, constraints have a node ID attached.
+// Typeck turns this to a def_id, using the output of resolve.
+type constr_general[ARG] = spanned[constr_general_[ARG, node_id]];
+type constr_ = constr_general_[uint, node_id];
+type constr = spanned[constr_general_[uint, node_id]];
+type ty_constr_ = ast::constr_general_[ast::path, ast::node_id];
+type ty_constr = spanned[ty_constr_];
/* The parser generates ast::constrs; resolve generates
a mapping from each function to a list of ty::constr_defs,
}
}
-// Path stringification
-fn path_to_str(&ast::path pth) -> str {
- auto result = str::connect_ivec(pth.node.idents, "::");
- if (ivec::len[@ast::ty](pth.node.types) > 0u) {
- fn f(&@ast::ty t) -> str { ret print::pprust::ty_to_str(*t); }
- result += "[";
- result += str::connect_ivec(ivec::map(f, pth.node.types), ",");
- result += "]";
- }
- ret result;
-}
-
-
//
// Local Variables:
// mode: rust
fn (&decl_ d, ast_fold) -> decl_ fold_decl,
fn (&expr_ e, ast_fold) -> expr_ fold_expr,
fn (&ty_ t, ast_fold) -> ty_ fold_ty,
- fn (&constr_ c, ast_fold) -> constr_ fold_constr,
+ fn (&ast::constr_ c, ast_fold) -> constr_ fold_constr,
fn (&_fn f, ast_fold) -> _fn fold_fn,
fn (&_mod m, ast_fold) -> _mod fold_mod,
fn (&native_mod, ast_fold) -> native_mod fold_native_mod,
}
fn noop_fold_constr(&constr_ c, ast_fold fld) -> constr_ {
- ret rec(path=fld.fold_path(c.path), args=c.args, id=c.id);
+ rec(path=fld.fold_path(c.path), args=c.args, id=c.id)
}
// functions just don't get spans, for some reason
fn f_ty(&ast_fold_precursor afp, ast_fold f, &@ty x) -> @ty {
ret @rec(node=afp.fold_ty(x.node, f), span=x.span);
}
- fn f_constr(&ast_fold_precursor afp, ast_fold f, &@constr x) -> @constr {
+ fn f_constr(&ast_fold_precursor afp, ast_fold f, &@ast::constr x)
+ -> @ast::constr {
ret @rec(node=afp.fold_constr(x.node, f), span=x.span);
}
fn f_fn(&ast_fold_precursor afp, ast_fold f, &_fn x) -> _fn {
import codemap::span;
import std::map::new_str_hash;
import util::interner;
+import ast::node_id;
+import ast::spanned;
tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; }
tag ty_or_bang { a_ty(@ast::ty); a_bang; }
type parse_sess = @rec(codemap::codemap cm,
- mutable ast::node_id next_id);
+ mutable node_id next_id);
-fn next_node_id(&parse_sess sess) -> ast::node_id {
+fn next_node_id(&parse_sess sess) -> node_id {
auto rv = sess.next_id;
sess.next_id += 1;
ret rv;
fn get_bad_expr_words() -> hashmap[str, ()] ;
fn get_chpos() -> uint ;
fn get_byte_pos() -> uint ;
- fn get_id() -> ast::node_id ;
+ fn get_id() -> node_id ;
fn get_sess() -> parse_sess;
};
fn get_bad_expr_words() -> hashmap[str, ()] { ret bad_words; }
fn get_chpos() -> uint { ret rdr.get_chpos(); }
fn get_byte_pos() -> uint { ret rdr.get_byte_pos(); }
- fn get_id() -> ast::node_id { ret next_node_id(sess); }
+ fn get_id() -> node_id { ret next_node_id(sess); }
fn get_sess() -> parse_sess { ret sess; }
}
}
}
-fn spanned[T](uint lo, uint hi, &T node) -> ast::spanned[T] {
+fn spanned[T](uint lo, uint hi, &T node) -> spanned[T] {
ret rec(node=node, span=rec(lo=lo, hi=hi));
}
auto inputs =
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_fn_input_ty, p);
- auto constrs = parse_constrs(~[], p);
+ // FIXME: there's no syntax for this right now anyway
+ // auto constrs = parse_constrs(~[], p);
+ let (@ast::constr)[] constrs = ~[];
let @ast::ty output;
auto cf = ast::return;
if (p.peek() == token::RARROW) {
}
}
} else { output = @spanned(lo, inputs.span.hi, ast::ty_nil); }
- ret ast::ty_fn(proto, inputs.node, output, cf, constrs.node);
+ ret ast::ty_fn(proto, inputs.node, output, cf, constrs);
}
fn parse_proto(&parser p) -> ast::proto {
p.fatal("Unbound variable " + i + " in constraint arg");
}
+fn parse_type_constr_arg(&parser p) -> @ast::ty_constr_arg {
+ auto sp = p.get_span();
+ auto carg = ast::carg_base;
+ expect(p, token::BINOP(token::STAR));
+ if (p.peek() == token::DOT) {
+ // "*..." notation for record fields
+ p.bump();
+ let ast::path pth = parse_path(p);
+ carg = ast::carg_ident(pth);
+ }
+ // No literals yet, I guess?
+ ret @rec(node=carg, span=sp);
+}
+
fn parse_constr_arg(&ast::arg[] args, &parser p) -> @ast::constr_arg {
auto sp = p.get_span();
auto carg = ast::carg_base;
let rec((@ast::constr_arg)[] node, span span) args =
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), pf,
p);
- // FIXME fix the def_id
-
ret @spanned(lo, args.span.hi,
rec(path=path, args=args.node, id=p.get_id()));
}
-
-// Use the args list to translate each bound variable
-// mentioned in a constraint to an arg index.
-// Seems weird to do this in the parser, but I'm not sure how else to.
-fn parse_constrs(&ast::arg[] args, &parser p)
- -> ast::spanned[(@ast::constr)[]] {
+fn parse_constr_in_type(&parser p) -> @ast::ty_constr {
auto lo = p.get_lo_pos();
- auto hi = p.get_hi_pos();
- let (@ast::constr)[] constrs = ~[];
- if (p.peek() == token::COLON) {
- p.bump();
- while (true) {
- auto constr = parse_ty_constr(args, p);
- hi = constr.span.hi;
- constrs += ~[constr];
- if (p.peek() == token::COMMA) { p.bump(); } else { break; }
- }
- }
- ret spanned(lo, hi, constrs);
+ auto path = parse_path(p);
+ let (@ast::ty_constr_arg)[] args =
+ (parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
+ parse_type_constr_arg, p)).node;
+ auto hi = p.get_lo_pos();
+ let ast::ty_constr_ tc = rec(path=path, args=args, id=p.get_id());
+ ret @spanned(lo, hi, tc);
}
-fn parse_ty_constrs(@ast::ty t, &parser p) -> @ast::ty {
- if (p.peek() == token::COLON) {
- auto constrs = parse_constrs(~[], p);
- ret @spanned(t.span.lo, constrs.span.hi,
- ast::ty_constr(t, constrs.node));
+
+fn parse_constrs[T](fn(&parser p) ->
+ (@ast::constr_general[T]) pser, &parser p)
+ -> (@ast::constr_general[T])[] {
+ let (@ast::constr_general[T])[] constrs = ~[];
+ while (true) {
+ auto constr = pser(p);
+ constrs += ~[constr];
+ if (p.peek() == token::COMMA) { p.bump(); } else { break; }
}
- ret t;
+ constrs
+}
+
+fn parse_type_constraints(&parser p) -> (@ast::ty_constr)[] {
+ ret parse_constrs(parse_constr_in_type, p);
}
-fn parse_ty_postfix(@ast::ty orig_t, &parser p) -> @ast::ty {
+fn parse_ty_postfix(ast::ty_ orig_t, &parser p) -> @ast::ty {
auto lo = p.get_lo_pos();
if (p.peek() == token::LBRACKET) {
p.bump();
auto seq = parse_seq_to_end(token::RBRACKET,
some(token::COMMA), parse_ty, p);
- alt (orig_t.node) {
+ alt (orig_t) {
case (ast::ty_path(?pth, ?ann)) {
auto hi = p.get_hi_pos();
ret @spanned(lo, hi,
expect(p, token::RBRACKET);
auto hi = p.get_hi_pos();
- auto t = ast::ty_ivec(rec(ty=orig_t, mut=mut));
- ret parse_ty_postfix(@spanned(lo, hi, t), p);
+ // FIXME: spans are probably wrong
+ auto t = ast::ty_ivec(rec(ty=@spanned(lo, hi, orig_t), mut=mut));
+ ret parse_ty_postfix(t, p);
}
- ret parse_ty_constrs(orig_t, p);
+ ret @spanned(lo, p.get_lo_pos(), orig_t);
}
fn parse_ty_or_bang(&parser p) -> ty_or_bang {
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_ty_field, p);
hi = elems.span.hi;
+ // possible constrs
+ // FIXME: something seems dodgy or at least repetitive
+ // about how constrained types get parsed
t = ast::ty_rec(elems.node);
+ if (p.peek() == token::COLON) {
+ p.bump();
+ t = ast::ty_constr(@spanned(lo, hi, t),
+ parse_type_constraints(p));
+ }
} else if (eat_word(p, "fn")) {
auto flo = p.get_last_lo_pos();
t = parse_ty_fn(ast::proto_fn, p, flo);
t = ast::ty_path(path, p.get_id());
hi = path.span.hi;
} else { p.fatal("expecting type"); t = ast::ty_nil; fail; }
- ret parse_ty_postfix(@spanned(lo, hi, t), p);
+ ret parse_ty_postfix(t, p);
}
fn parse_arg(&parser p) -> ast::arg {
fn parse_seq[T](token::token bra, token::token ket,
option::t[token::token] sep,
- fn(&parser)->T f, &parser p) -> ast::spanned[T[]] {
+ fn(&parser)->T f, &parser p) -> spanned[T[]] {
auto lo = p.get_lo_pos();
expect(p, bra);
auto result = parse_seq_to_end[T](ket, sep, f, p);
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_arg, p);
let ty_or_bang rslt;
- auto constrs = parse_constrs(inputs.node, p).node;
+// Use the args list to translate each bound variable
+// mentioned in a constraint to an arg index.
+// Seems weird to do this in the parser, but I'm not sure how else to.
+ auto constrs = ~[];
+ if (p.peek() == token::COLON) {
+ p.bump();
+ constrs = parse_constrs(bind parse_ty_constr(inputs.node,_), p);
+ }
if (p.peek() == token::RARROW) {
p.bump();
rslt = parse_ty_or_bang(p);
space(s.s);
word(s.s, ":");
space(s.s);
- word(s.s, ast_constrs_str(cs));
+ word(s.s, ast_ty_constrs_str(cs));
}
}
end(s);
// Removing the aliases from the type of f in the next two functions
// triggers memory corruption, but I haven't isolated the bug yet. FIXME
fn constr_args_to_str[T](&fn(&T) -> str f,
- &(@ast::constr_arg_general[T])[] args) -> str {
+ &(@ast::sp_constr_arg[T])[] args) -> str {
auto comma = false;
auto s = "(";
- for (@ast::constr_arg_general[T] a in args) {
+ for (@ast::sp_constr_arg[T] a in args) {
if (comma) { s += ", "; } else { comma = true; }
s += constr_arg_to_str[T](f, a.node);
}
fn uint_to_str(&uint i) -> str { ret uint::str(i); }
fn ast_constr_to_str(&@ast::constr c) -> str {
- ret ast::path_to_str(c.node.path) +
- constr_args_to_str(uint_to_str, c.node.args);
+ ret path_to_str(c.node.path) +
+ constr_args_to_str(uint_to_str, c.node.args);
}
+// FIXME: fix repeated code
fn ast_constrs_str(&(@ast::constr)[] constrs) -> str {
auto s = "";
auto colon = true;
};
}
+fn ty_constr_to_str(&@ast::ty_constr c) -> str {
+ ret path_to_str(c.node.path) +
+ constr_args_to_str[ast::path](path_to_str, c.node.args);
+}
+
+
+fn ast_ty_constrs_str(&(@ast::ty_constr)[] constrs) -> str {
+ auto s = "";
+ auto colon = true;
+ for (@ast::ty_constr c in constrs) {
+ if (colon) { s += " : "; colon = false; } else { s += ", "; }
+ s += ty_constr_to_str(c);
+ }
+ ret s;
+}
+
//
// Local Variables:
// mode: rust
fn(&@decl, &E, &vt[E]) visit_decl,
fn(&@expr, &E, &vt[E]) visit_expr,
fn(&@ty, &E, &vt[E]) visit_ty,
- fn(&@constr, &E, &vt[E]) visit_constr,
+ // takes the components so that one function can be
+ // generic over constr and ty_constr
+ fn(&path, &span, node_id, &E, &vt[E]) visit_constr,
fn(&_fn, &ty_param[], &span, &fn_ident, node_id, &E, &vt[E])
visit_fn);
visit_decl=bind visit_decl[E](_, _, _),
visit_expr=bind visit_expr[E](_, _, _),
visit_ty=bind visit_ty[E](_, _, _),
- visit_constr=bind visit_constr[E](_, _, _),
+ visit_constr=bind visit_constr[E](_, _, _, _, _),
visit_fn=bind visit_fn[E](_, _, _, _, _, _, _));
}
}
case (ty_fn(_, ?args, ?out, _, ?constrs)) {
for (ty_arg a in args) { v.visit_ty(a.node.ty, e, v); }
- for (@constr c in constrs) { v.visit_constr(c, e, v); }
+ for (@constr c in constrs) { v.visit_constr(c.node.path,
+ c.span, c.node.id, e, v); }
v.visit_ty(out, e, v);
}
case (ty_obj(?tmeths)) {
for (@ty tp in p.node.types) { v.visit_ty(tp, e, v); }
}
case (ty_type) { /* no-op */ }
- case (ty_constr(?t, _)) { v.visit_ty(t, e, v); }
+ case (ty_constr(?t, ?cs)) {
+ v.visit_ty(t, e, v);
+ for (@spanned[constr_general_[path, node_id]] tc in cs) {
+ v.visit_constr(tc.node.path, tc.span, tc.node.id, e, v);
+ }
+ }
}
}
}
}
-fn visit_constr[E](&@constr c, &E e, &vt[E] v) {
+fn visit_constr[E](&path operator, &span sp, node_id id, &E e, &vt[E] v) {
// default
}
fn visit_fn_decl[E](&fn_decl fd, &E e, &vt[E] v) {
for (arg a in fd.inputs) { v.visit_ty(a.ty, e, v); }
- for (@constr c in fd.constraints) { v.visit_constr(c, e, v); }
+ for (@constr c in fd.constraints) {
+ v.visit_constr(c.node.path, c.span, c.node.id, e, v);
+ }
v.visit_ty(fd.output, e, v);
}
import metadata::encoder;
import syntax::print::pp;
import syntax::print::pprust;
+import syntax::print::pprust::path_to_str;
+import syntax::print::pprust::constr_args_to_str;
import pp::word;
import pp::eof;
import pp::zerobreak;
}
fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident,
&arg[] inputs, t output, ast::controlflow cf,
- &(@constr_def)[] constrs) -> str {
+ &(@constr)[] constrs) -> str {
auto s;
alt (proto) {
case (ast::proto_iter) { s = "iter"; }
ret s;
}
-fn constr_to_str(&@constr_def c) -> str {
- ret ast::path_to_str(c.node.path) +
+fn constr_to_str(&@constr c) -> str {
+ ret path_to_str(c.node.path) +
pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}
-fn constrs_str(&(@constr_def)[] constrs) -> str {
+fn constrs_str(&(@constr)[] constrs) -> str {
auto s = "";
auto colon = true;
- for (@constr_def c in constrs) {
+ for (@constr c in constrs) {
if (colon) { s += " : "; colon = false; } else { s += ", "; }
s += constr_to_str(c);
}
ret s;
}
+fn ty_constr_to_str[Q](&@ast::spanned[ast::constr_general_[ast::path,Q]]
+ c) -> str {
+ ret path_to_str(c.node.path) +
+ constr_args_to_str[ast::path](path_to_str, c.node.args);
+}
+
// Local Variables:
// mode: rust
// fill-column: 78;
--- /dev/null
+// -*- rust -*-
+// xfail-stage0
+// xfail-stage1
+// xfail-stage2
+// error-pattern:Unsatisfied precondition
+
+tag list {
+ cons(int,@list);
+ nil();
+}
+
+type bubu = rec(int x, int y);
+
+pred less_than(int x, int y) -> bool { ret x < y; }
+
+type ordered_range = rec(int low, int high) : less_than(*.low, *.high);
+
+fn main() {
+// Should fail to compile, b/c we're not doing the check
+// explicitly that a < b
+ let int a = 1;
+ let int b = 2;
+ let ordered_range c = rec(low=a, high=b);
+ log c.low;
+}
// xfail-stage0
-// xfail-stage1
-// xfail-stage2
// -*- rust -*-
-// Reported as issue #141, as a parse error. Ought to work in full though.
-
tag list {
cons(int,@list);
nil();
type bubu = rec(int x, int y);
-
-fn less_than(int x, int y) -> bool { ret x < y; }
+pred less_than(int x, int y) -> bool { ret x < y; }
type ordered_range = rec(int low, int high) : less_than(*.low, *.high);