Beginnings of support for constrained types

Programs with constrained types now parse and typecheck, but
typestate doesn't check them specially, so the one relevant test
case so far is XFAILed.

Also rewrote all of the constraint-related data structures in the
process (again), for some reason. I got rid of a superfluous
data structure in the context that was mapping front-end constraints
to resolved constraints, instead handling constraints in the same
way in which everything else gets resolved.
This commit is contained in:
Tim Chevalier 2011-07-19 17:52:34 -07:00
parent da2a7e5bd2
commit bd4aeef78b
20 changed files with 606 additions and 366 deletions

View file

@ -134,8 +134,8 @@ fn compile_input(session::session sess, ast::crate_cfg cfg, str input,
bind resolve::resolve_crate(sess, ast_map, crate)); bind resolve::resolve_crate(sess, ast_map, crate));
auto freevars = auto freevars =
time(time_passes, "freevar finding", time(time_passes, "freevar finding",
bind freevars::annotate_freevars(sess, d._0, crate)); bind freevars::annotate_freevars(sess, d, crate));
auto ty_cx = ty::mk_ctxt(sess, d._0, d._1, ast_map, freevars); auto ty_cx = ty::mk_ctxt(sess, d, ast_map, freevars);
time[()](time_passes, "typechecking", time[()](time_passes, "typechecking",
bind typeck::check_crate(ty_cx, crate)); bind typeck::check_crate(ty_cx, crate));
if (sess.get_opts().run_typestate) { if (sess.get_opts().run_typestate) {
@ -200,8 +200,8 @@ fn pretty_print_input(session::session sess, ast::crate_cfg cfg,
case (ppm_typed) { case (ppm_typed) {
auto amap = middle::ast_map::map_crate(*crate); auto amap = middle::ast_map::map_crate(*crate);
auto d = resolve::resolve_crate(sess, amap, crate); auto d = resolve::resolve_crate(sess, amap, crate);
auto freevars = freevars::annotate_freevars(sess, d._0, crate); auto freevars = freevars::annotate_freevars(sess, d, crate);
auto ty_cx = ty::mk_ctxt(sess, d._0, d._1, amap, freevars); auto ty_cx = ty::mk_ctxt(sess, d, amap, freevars);
typeck::check_crate(ty_cx, crate); typeck::check_crate(ty_cx, crate);
ann = rec(pre=ann_paren_for_expr, ann = rec(pre=ann_paren_for_expr,
post=bind ann_typed_post(ty_cx, _)); post=bind ann_typed_post(ty_cx, _));

View file

@ -7,6 +7,7 @@ import std::option;
import std::option::none; import std::option::none;
import std::option::some; import std::option::some;
import syntax::ast; import syntax::ast;
import syntax::ast::*;
import ast::respan; import ast::respan;
import middle::ty; import middle::ty;
@ -65,13 +66,15 @@ fn parse_ty_or_bang(@pstate st, str_def sd) -> ty_or_bang {
} }
} }
fn parse_constrs(@pstate st, str_def sd) -> (@ty::constr_def)[] { fn parse_constrs(@pstate st, str_def sd) -> (@ty::constr)[] {
let (@ty::constr_def)[] rslt = ~[]; let (@ty::constr)[] rslt = ~[];
alt (peek(st) as char) { alt (peek(st) as char) {
case (':') { case (':') {
do { do {
next(st); 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 == ';') } while (peek(st) as char == ';')
} }
case (_) { } case (_) { }
@ -102,40 +105,50 @@ fn parse_path(@pstate st, str_def sd) -> ast::path {
fail "parse_path: ill-formed path"; fail "parse_path: ill-formed path";
} }
fn parse_constr(@pstate st, str_def sd) -> @ty::constr_def { type arg_parser[T] = fn (@pstate st, str_def sd)
let (@ast::constr_arg)[] args = ~[]; -> 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 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; let char ignore = next(st) as char;
assert(ignore as char == '('); assert(ignore as char == '(');
auto def = parse_def(st, sd); auto def = parse_def(st, sd);
let constr_arg_general_[T] an_arg;
do { do {
alt (peek(st) as char) { an_arg = pser(st, sd);
case ('*') { // FIXME use a real span
st.pos += 1u; args += ~[@respan(sp, an_arg)];
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))];
}
*/
}
}
ignore = next(st) as char; ignore = next(st) as char;
} while (ignore == ';'); } while (ignore == ';');
assert(ignore == ')'); assert(ignore == ')');
@ -335,7 +348,7 @@ fn parse_hex(@pstate st) -> uint {
} }
fn parse_ty_fn(@pstate st, str_def sd) -> 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 == '['); assert (next(st) as char == '[');
let ty::arg[] inputs = ~[]; let ty::arg[] inputs = ~[];
while (peek(st) as char != ']') { while (peek(st) as char != ']') {
@ -384,3 +397,14 @@ fn parse_def_id(&u8[] buf) -> ast::def_id {
auto def_id = uint::parse_buf(def_part_vec, 10u) as int; auto def_id = uint::parse_buf(def_part_vec, 10u) as int;
ret tup(crate_num, def_id); 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:
//

View file

@ -8,7 +8,7 @@ import std::int;
import std::uint; import std::uint;
import syntax::ast::*; import syntax::ast::*;
import middle::ty; import middle::ty;
import syntax::print::pprust::lit_to_str; import syntax::print::pprust::*;
import util::common; import util::common;
export ctxt; export ctxt;
@ -199,8 +199,9 @@ fn enc_proto(&ioivec::writer w, proto proto) {
case (proto_fn) { w.write_char('F'); } case (proto_fn) { w.write_char('F'); }
} }
} }
fn enc_ty_fn(&ioivec::writer w, &@ctxt cx, &ty::arg[] args, &ty::t out, 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('['); w.write_char('[');
for (ty::arg arg in args) { for (ty::arg arg in args) {
alt (arg.mode) { alt (arg.mode) {
@ -214,7 +215,7 @@ fn enc_ty_fn(&ioivec::writer w, &@ctxt cx, &ty::arg[] args, &ty::t out,
} }
w.write_char(']'); w.write_char(']');
auto colon = true; auto colon = true;
for (@ty::constr_def c in constrs) { for (@ty::constr c in constrs) {
if (colon) { if (colon) {
w.write_char(':'); w.write_char(':');
colon = false; colon = false;
@ -227,7 +228,8 @@ fn enc_ty_fn(&ioivec::writer w, &@ctxt cx, &ty::arg[] args, &ty::t out,
} }
} }
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_str(path_to_str(c.node.path));
w.write_char('('); w.write_char('(');
w.write_str(cx.ds(c.node.id)); w.write_str(cx.ds(c.node.id));

View file

@ -1,5 +1,6 @@
import syntax::ast; import syntax::ast;
import syntax::ast::*;
import ast::ident; import ast::ident;
import ast::fn_ident; import ast::fn_ident;
import ast::def; import ast::def;
@ -19,6 +20,7 @@ import middle::ty::constr_table;
import syntax::visit; import syntax::visit;
import visit::vt; import visit::vt;
import std::ivec; import std::ivec;
import std::int;
import std::map::hashmap; import std::map::hashmap;
import std::list; import std::list;
import std::list::list; import std::list::list;
@ -28,6 +30,7 @@ import std::option;
import std::option::some; import std::option::some;
import std::option::none; import std::option::none;
import std::str; import std::str;
import syntax::print::pprust::*;
export resolve_crate; export resolve_crate;
export def_map; export def_map;
@ -109,7 +112,6 @@ type def_map = hashmap[node_id, def];
type env = type env =
rec(cstore::cstore cstore, rec(cstore::cstore cstore,
def_map def_map, def_map def_map,
constr_table fn_constrs,
ast_map::map ast_map, ast_map::map ast_map,
hashmap[ast::node_id, import_state] imports, hashmap[ast::node_id, import_state] imports,
hashmap[ast::node_id, @indexed_mod] mod_map, hashmap[ast::node_id, @indexed_mod] mod_map,
@ -124,12 +126,11 @@ tag dir { inside; outside; }
tag namespace { ns_value; ns_type; ns_module; } tag namespace { ns_value; ns_type; ns_module; }
fn resolve_crate(session sess, &ast_map::map amap, @ast::crate crate) -> fn resolve_crate(session sess, &ast_map::map amap, @ast::crate crate)
tup(def_map, constr_table) { -> def_map {
auto e = auto e =
@rec(cstore=sess.get_cstore(), @rec(cstore=sess.get_cstore(),
def_map=new_int_hash[def](), def_map=new_int_hash[def](),
fn_constrs = new_int_hash[ty::constr_def[]](),
ast_map=amap, ast_map=amap,
imports=new_int_hash[import_state](), imports=new_int_hash[import_state](),
mod_map=new_int_hash[@indexed_mod](), mod_map=new_int_hash[@indexed_mod](),
@ -140,7 +141,7 @@ fn resolve_crate(session sess, &ast_map::map amap, @ast::crate crate) ->
resolve_imports(*e); resolve_imports(*e);
check_for_collisions(e, *crate); check_for_collisions(e, *crate);
resolve_names(e, crate); resolve_names(e, crate);
ret tup(e.def_map, e.fn_constrs); ret e.def_map;
} }
@ -249,7 +250,7 @@ fn resolve_names(&@env e, &@ast::crate c) {
visit_arm=bind walk_arm(e, _, _, _), visit_arm=bind walk_arm(e, _, _, _),
visit_expr=bind walk_expr(e, _, _, _), visit_expr=bind walk_expr(e, _, _, _),
visit_ty=bind walk_ty(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, _, _, _, _, _, _, _) visit_fn=bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
with *visit::default_visitor()); with *visit::default_visitor());
visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v)); visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v));
@ -277,10 +278,9 @@ fn resolve_names(&@env e, &@ast::crate c) {
case (_) { } case (_) { }
} }
} }
fn walk_constr(@env e, &@ast::constr c, &scopes sc, &vt[scopes] v) { fn walk_constr(@env e, &ast::path p, &span sp, node_id id,
maybe_insert(e, c.node.id, &scopes sc, &vt[scopes] v) {
lookup_path_strict(*e, sc, c.span, c.node.path.node, maybe_insert(e, id, lookup_path_strict(*e, sc, sp, p.node, ns_value));
ns_value));
} }
fn walk_arm(@env e, &ast::arm a, &scopes sc, &vt[scopes] v) { 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); } for (@ast::pat p in a.pats) { walk_pat(*e, sc, p); }
@ -411,29 +411,18 @@ fn resolve_constr(@env e, node_id id, &@ast::constr c, &scopes sc,
if (option::is_some(new_def)) { if (option::is_some(new_def)) {
alt (option::get(new_def)) { alt (option::get(new_def)) {
case (ast::def_fn(?pred_id, ast::pure_fn)) { case (ast::def_fn(?pred_id, ast::pure_fn)) {
let ty::constr_general[uint] c_ = e.def_map.insert(c.node.id, ast::def_fn(pred_id,
rec(path=c.node.path, args=c.node.args, id=pred_id); ast::pure_fn));
let ty::constr_def new_constr = respan(c.span, c_);
add_constr(e, id, new_constr);
} }
case (_) { case (_) {
e.sess.span_err(c.span, e.sess.span_err(c.span,
"Non-predicate in constraint: " + "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 // Import resolution
fn resolve_import(&env e, &@ast::view_item it, scopes sc) { fn resolve_import(&env e, &@ast::view_item it, scopes sc) {
auto defid; auto defid;

View file

@ -72,12 +72,12 @@ fn comma_str(&(@constr_arg_use)[] args) -> str {
ret rslt; ret rslt;
} }
fn constraint_to_str(&ty::ctxt tcx, &constr c) -> str { fn constraint_to_str(&ty::ctxt tcx, &sp_constr c) -> str {
alt (c.node.c) { alt (c.node) {
case (ninit(?i)) { case (ninit(_,?i)) {
ret "init(" + i + " [" + tcx.sess.span_str(c.span) + "])"; 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) + ")" + "[" + ret path_to_str(p) + "(" + comma_str(args) + ")" + "[" +
tcx.sess.span_str(c.span) + "]"; tcx.sess.span_str(c.span) + "]";
} }
@ -204,31 +204,36 @@ to represent predicate *arguments* however. This type
Both types store an ident and span, for error-logging purposes. 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 // The attached node ID is the *defining* node ID
// about locals. // for this local.
type constr_arg_use = constr_arg_general[tup(ident, def_id)]; type constr_arg_use = spanned[constr_arg_general_[inst]];
tag constraint { tag constraint {
cinit(uint, span, ident); 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__ { // An ninit variant has a node_id because it refers to a local var.
ninit(ident); // An npred has a def_id since the definition of the typestate
npred(path, (@constr_arg_use)[]); // 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[def_id, constraint];
type constr_map = @std::map::hashmap[node_id, constraint];
type fn_info = rec(constr_map constrs, type fn_info = rec(constr_map constrs,
uint num_constraints, uint num_constraints,
@ -240,6 +245,12 @@ type fn_info = rec(constr_map constrs,
// bug? // bug?
@mutable node_id[] used_vars); @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 */ /* mapping from node ID to typestate annotation */
type node_ann_table = @mutable ts_ann[mutable]; type node_ann_table = @mutable ts_ann[mutable];
@ -468,7 +479,7 @@ fn controlflow_expr(&crate_ctxt ccx, @expr e) -> controlflow {
} }
} }
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))) { alt (ty::struct(cx, ty::node_id_to_type(cx, e.id))) {
case (ty::ty_fn(_, _, _, _, ?cs)) { ret cs; } case (ty::ty_fn(_, _, _, _, ?cs)) { ret cs; }
case (_) { ret ~[]; } case (_) { ret ~[]; }
@ -489,18 +500,17 @@ fn node_id_to_def(&crate_ctxt ccx, node_id id) -> option::t[def] {
ret ccx.tcx.def_map.find(id); 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) { alt (c) {
case (cinit(?n, ?sp, ?i)) { 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)) { case (cpred(?p, ?descs)) {
let norm_constraint[] rslt = ~[]; let norm_constraint[] rslt = ~[];
for (pred_desc pd in *descs) { for (pred_args pd in *descs) {
rslt += ~[rec(bit_num=pd.node.bit_num, rslt += ~[rec(bit_num=pd.node.bit_num,
c=respan(pd.span, c=respan(pd.span,
rec(id=id, npred(p, id, pd.node.args)))];
c=npred(p, pd.node.args))))];
} }
ret rslt; ret rslt;
} }
@ -512,19 +522,23 @@ fn norm_a_constraint(node_id id, &constraint c) -> norm_constraint[] {
// non-exhaustive match in trans. // non-exhaustive match in trans.
fn constraints(&fn_ctxt fcx) -> norm_constraint[] { fn constraints(&fn_ctxt fcx) -> norm_constraint[] {
let norm_constraint[] rslt = ~[]; 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); rslt += norm_a_constraint(p._0, p._1);
} }
ret rslt; 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 { uint {
log "match_args: looking at " + log "match_args: looking at " +
constr_args_to_str(std::util::fst[ident, def_id], occ); constr_args_to_str(std::util::fst[ident, node_id], occ);
for (pred_desc pd in occs) { for (pred_args pd in *occs) {
log "match_args: candidate " + pred_desc_to_str(pd); log "match_args: candidate " + pred_args_to_str(pd);
fn eq(&tup(ident, def_id) p, &tup(ident, def_id) q) -> bool { fn eq(&inst p, &inst q) -> bool {
ret p._1 == q._1; ret p._1 == q._1;
} }
if (ty::args_eq(eq, pd.node.args, occ)) { ret pd.node.bit_num; } if (ty::args_eq(eq, pd.node.args, occ)) { ret pd.node.bit_num; }
@ -532,12 +546,12 @@ fn match_args(&fn_ctxt fcx, &pred_desc[] occs, &(@constr_arg_use)[] occ) ->
fcx.ccx.tcx.sess.bug("match_args: no match for occurring args"); 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)) { alt (tcx.def_map.find(t)) {
case (none) { case (none) {
tcx.sess.bug("node_id_for_constr: bad node_id " + int::str(t)); 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 (_) { case (_) {
tcx.sess.bug("node_id_for_constr: pred is not a function"); tcx.sess.bug("node_id_for_constr: pred is not a function");
} }
@ -550,11 +564,11 @@ fn expr_to_constr_arg(ty::ctxt tcx, &@expr e) -> @constr_arg_use {
alt (tcx.def_map.find(e.id)) { alt (tcx.def_map.find(e.id)) {
case (some(def_local(?l_id))) { case (some(def_local(?l_id))) {
ret @respan(p.span, carg_ident(tup(p.node.idents.(0), ret @respan(p.span, carg_ident(tup(p.node.idents.(0),
l_id))); l_id._1)));
} }
case (some(def_arg(?a_id))) { case (some(def_arg(?a_id))) {
ret @respan(p.span, carg_ident(tup(p.node.idents.(0), ret @respan(p.span, carg_ident(tup(p.node.idents.(0),
a_id))); a_id._1)));
} }
case (_) { case (_) {
tcx.sess.bug("exprs_to_constr_args: non-local variable " + tcx.sess.bug("exprs_to_constr_args: non-local variable " +
@ -582,7 +596,7 @@ fn exprs_to_constr_args(ty::ctxt tcx, &(@expr)[] args)
rslt 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) { alt (e.node) {
case ( case (
// FIXME change the first pattern to expr_path to test a // FIXME change the first pattern to expr_path to test a
@ -591,9 +605,8 @@ fn expr_to_constr(ty::ctxt tcx, &@expr e) -> constr {
alt (operator.node) { alt (operator.node) {
case (expr_path(?p)) { case (expr_path(?p)) {
ret respan(e.span, ret respan(e.span,
rec(id=node_id_for_constr(tcx, operator.id), npred(p, def_id_for_constr(tcx, operator.id),
c=npred(p, exprs_to_constr_args(tcx, exprs_to_constr_args(tcx, args)));
args))));
} }
case (_) { case (_) {
tcx.sess.span_fatal(operator.span, tcx.sess.span_fatal(operator.span,
@ -610,19 +623,19 @@ fn expr_to_constr(ty::ctxt tcx, &@expr e) -> constr {
} }
} }
fn pred_desc_to_str(&pred_desc p) -> str { fn pred_args_to_str(&pred_args p) -> str {
"<" + uint::str(p.node.bit_num) + ", " + "<" + 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) + ">" p.node.args) + ">"
} }
fn substitute_constr_args(&ty::ctxt cx, &(@expr)[] actuals, fn substitute_constr_args(&ty::ctxt cx, &(@expr)[] actuals,
&@ty::constr_def c) -> constr__ { &@ty::constr c) -> tsconstr {
let (@constr_arg_use)[] rslt = ~[]; let (@constr_arg_use)[] rslt = ~[];
for (@constr_arg a in c.node.args) { for (@constr_arg a in c.node.args) {
rslt += ~[substitute_arg(cx, actuals, a)]; 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 substitute_arg(&ty::ctxt cx, &(@expr)[] actuals, @constr_arg a) ->
@ -642,8 +655,8 @@ fn substitute_arg(&ty::ctxt cx, &(@expr)[] actuals, @constr_arg a) ->
} }
} }
fn pred_desc_matches(&(constr_arg_general_[tup(ident, def_id)])[] pattern, fn pred_args_matches(&(constr_arg_general_[inst])[] pattern,
&pred_desc desc) -> bool { &pred_args desc) -> bool {
auto i = 0u; auto i = 0u;
for (@constr_arg_use c in desc.node.args) { for (@constr_arg_use c in desc.node.args) {
auto n = pattern.(i); auto n = pattern.(i);
@ -679,17 +692,17 @@ fn pred_desc_matches(&(constr_arg_general_[tup(ident, def_id)])[] pattern,
ret true; ret true;
} }
fn find_instance_(&(constr_arg_general_[tup(ident, def_id)])[] pattern, fn find_instance_(&(constr_arg_general_[inst])[] pattern,
&pred_desc[] descs) -> option::t[uint] { &pred_args[] descs) -> option::t[uint] {
for (pred_desc d in descs) { for (pred_args d in descs) {
if (pred_desc_matches(pattern, d)) { if (pred_args_matches(pattern, d)) {
ret some(d.node.bit_num); ret some(d.node.bit_num);
} }
} }
ret none; ret none;
} }
type inst = tup(ident, def_id); type inst = tup(ident, node_id);
type subst = tup(inst, inst)[]; type subst = tup(inst, inst)[];
fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c) fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
@ -703,7 +716,7 @@ fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
alt (c) { alt (c) {
case (cinit(_,_,_)) { /* this is dealt with separately */ } case (cinit(_,_,_)) { /* this is dealt with separately */ }
case (cpred(?p, ?descs)) { 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)) { if (args_mention(d.node.args, find_in_subst_bool, subst)) {
auto old_bit_num = d.node.bit_num; auto old_bit_num = d.node.bit_num;
auto new = replace(subst, d); auto new = replace(subst, d);
@ -720,7 +733,7 @@ fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
rslt 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) { for (tup(inst, inst) p in s) {
if (id == p._0._1) { if (id == p._0._1) {
ret some(p._1); ret some(p._1);
@ -729,7 +742,7 @@ fn find_in_subst(def_id id, &subst s) -> option::t[inst] {
ret none; 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)) is_some(find_in_subst(id, s))
} }
@ -745,7 +758,7 @@ fn insts_to_str(&(constr_arg_general_[inst])[] stuff) -> str {
rslt 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 = ~[]; let (constr_arg_general_[inst])[] rslt = ~[];
for (@constr_arg_use c in d.node.args) { for (@constr_arg_use c in d.node.args) {
alt (c.node) { alt (c.node) {
@ -824,6 +837,15 @@ fn local_node_id_to_def_id(&fn_ctxt fcx, &node_id i) -> option::t[def_id] {
} }
} }
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, fn copy_in_postcond(&fn_ctxt fcx, node_id parent_exp, inst dest, inst src,
oper_type ty) { oper_type ty) {
auto post = node_id_to_ts_ann(fcx.ccx, parent_exp).conditions. auto post = node_id_to_ts_ann(fcx.ccx, parent_exp).conditions.
@ -859,7 +881,7 @@ fn copy_in_poststate_two(&fn_ctxt fcx, &poststate src_post,
} }
} }
for each (@tup(node_id, constraint) p in for each (@tup(def_id, constraint) p in
fcx.enclosing.constrs.items()) { fcx.enclosing.constrs.items()) {
// replace any occurrences of the src def_id with the // replace any occurrences of the src def_id with the
// dest def_id // dest def_id
@ -878,7 +900,7 @@ fn copy_in_poststate_two(&fn_ctxt fcx, &poststate src_post,
fn forget_in_postcond(&fn_ctxt fcx, node_id parent_exp, node_id dead_v) { 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 // In the postcondition given by parent_exp, clear the bits
// for any constraints mentioning dead_v // 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) { alt (d) {
case (some(?d_id)) { case (some(?d_id)) {
for (norm_constraint c in constraints(fcx)) { for (norm_constraint c in constraints(fcx)) {
@ -896,7 +918,7 @@ fn forget_in_postcond_still_init(&fn_ctxt fcx, node_id parent_exp,
node_id dead_v) { node_id dead_v) {
// In the postcondition given by parent_exp, clear the bits // In the postcondition given by parent_exp, clear the bits
// for any constraints mentioning dead_v // 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) { alt (d) {
case (some(?d_id)) { case (some(?d_id)) {
for (norm_constraint c in constraints(fcx)) { for (norm_constraint c in constraints(fcx)) {
@ -913,7 +935,7 @@ fn forget_in_postcond_still_init(&fn_ctxt fcx, node_id parent_exp,
fn forget_in_poststate(&fn_ctxt fcx, &poststate p, node_id dead_v) -> bool { fn forget_in_poststate(&fn_ctxt fcx, &poststate p, node_id dead_v) -> bool {
// In the poststate given by parent_exp, clear the bits // In the poststate given by parent_exp, clear the bits
// for any constraints mentioning dead_v // 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; auto changed = false;
alt (d) { alt (d) {
case (some(?d_id)) { case (some(?d_id)) {
@ -932,7 +954,7 @@ fn forget_in_poststate_still_init(&fn_ctxt fcx, &poststate p, node_id dead_v)
-> bool { -> bool {
// In the poststate given by parent_exp, clear the bits // In the poststate given by parent_exp, clear the bits
// for any constraints mentioning dead_v // 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; auto changed = false;
alt (d) { alt (d) {
case (some(?d_id)) { case (some(?d_id)) {
@ -947,37 +969,35 @@ fn forget_in_poststate_still_init(&fn_ctxt fcx, &poststate p, node_id dead_v)
ret changed; ret changed;
} }
fn any_eq(&(def_id)[] v, def_id d) -> bool { fn any_eq(&(node_id)[] v, node_id d) -> bool {
for (def_id i in v) { for (node_id i in v) {
if (i == d) { ret true; } if (i == d) { ret true; }
} }
false false
} }
fn constraint_mentions(&fn_ctxt fcx, &norm_constraint c, def_id v) -> bool { fn constraint_mentions(&fn_ctxt fcx, &norm_constraint c, node_id v) -> bool {
ret (alt (c.c.node.c) { ret (alt (c.c.node) {
case (ninit(_)) { case (ninit(?id,_)) { v == id }
v == local_def(c.c.node.id) case (npred(_, _, ?args)) {
}
case (npred(_, ?args)) {
args_mention(args, any_eq, ~[v]) args_mention(args, any_eq, ~[v])
} }
}); });
} }
fn non_init_constraint_mentions(&fn_ctxt fcx, &norm_constraint c, fn non_init_constraint_mentions(&fn_ctxt fcx, &norm_constraint c,
&def_id v) -> bool { &node_id v) -> bool {
ret (alt (c.c.node.c) { ret (alt (c.c.node) {
case (ninit(_)) { case (ninit(_,_)) {
false false
} }
case (npred(_, ?args)) { case (npred(_, _, ?args)) {
args_mention(args, any_eq, ~[v]) 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 { &(T)[] s) -> bool {
/* /*
FIXME FIXME

View file

@ -1,29 +1,8 @@
import syntax::ast::*; import syntax::ast::*;
import syntax::walk; import syntax::walk;
import std::ivec; import std::ivec;
import std::option::*; import std::option::*;
import aux::constr_arg_use; import aux::*;
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 tstate::ann::pre_and_post; import tstate::ann::pre_and_post;
import tstate::ann::precond; import tstate::ann::precond;
import tstate::ann::postcond; import tstate::ann::postcond;
@ -47,11 +26,12 @@ import tstate::ann::clear_in_prestate;
import tstate::ann::clear_in_poststate_; import tstate::ann::clear_in_poststate_;
import tritv::*; import tritv::*;
fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint { fn bit_num(&fn_ctxt fcx, &tsconstr c) -> uint {
assert (fcx.enclosing.constrs.contains_key(c.id)); auto d = tsconstr_to_def_id(c);
auto rslt = fcx.enclosing.constrs.get(c.id); assert (fcx.enclosing.constrs.contains_key(d));
alt (c.c) { auto rslt = fcx.enclosing.constrs.get(d);
case (ninit(_)) { alt (c) {
case (ninit(_,_)) {
alt (rslt) { alt (rslt) {
case (cinit(?n, _, _)) { ret n; } case (cinit(?n, _, _)) { ret n; }
case (_) { case (_) {
@ -60,11 +40,10 @@ fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
} }
} }
} }
case (npred(_, ?args)) { case (npred(_, _, ?args)) {
alt (rslt) { alt (rslt) {
case (cpred(_, ?descs)) { case (cpred(_, ?descs)) {
auto d = *descs; ret match_args(fcx, descs, args);
ret match_args(fcx, d, args);
} }
case (_) { case (_) {
fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint," fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint,"
@ -75,7 +54,7 @@ fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
} }
} }
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 promises_(bit_num(fcx, c), p);
} }
@ -161,12 +140,12 @@ fn intersect_states(&prestate p, &prestate q) -> prestate {
ret rslt; 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), ret set_in_postcond(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).conditions); 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); auto rslt = clone(pre);
relax_prestate(bit_num(fcx, c), rslt); relax_prestate(bit_num(fcx, c), rslt);
// idea is this is scoped // idea is this is scoped
@ -209,18 +188,18 @@ fn relax_precond_block(&fn_ctxt fcx, node_id i, &block b) {
walk::walk_block(v, b); 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"; log "gen_poststate";
ret set_in_poststate(bit_num(fcx, c), ret set_in_poststate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states); 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), ret clear_in_prestate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states); 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"; log "kill_poststate";
ret clear_in_poststate(bit_num(fcx, c), ret clear_in_poststate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states); node_id_to_ts_ann(fcx.ccx, id).states);
@ -233,9 +212,8 @@ fn clear_in_poststate_expr(&fn_ctxt fcx, &@expr e, &poststate t) {
case (some(?i)) { case (some(?i)) {
alt (local_node_id_to_def(fcx, e.id)) { alt (local_node_id_to_def(fcx, e.id)) {
case (some(def_local(?d_id))) { case (some(def_local(?d_id))) {
clear_in_poststate_(bit_num(fcx, clear_in_poststate_(
rec(id=d_id._1, bit_num(fcx,ninit(d_id._1, i)), t);
c=ninit(i))), t);
} }
case (some(_)) { /* ignore args (for now...) */ } case (some(_)) { /* ignore args (for now...) */ }
case (_) { case (_) {
@ -252,17 +230,17 @@ fn clear_in_poststate_expr(&fn_ctxt fcx, &@expr e, &poststate t) {
fn set_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident, fn set_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&poststate t) -> bool { &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, fn clear_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&node_id parent) -> bool { &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, fn clear_in_prestate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&node_id parent) -> bool { &node_id parent) -> bool {
ret kill_prestate(fcx, parent, rec(id=id, c=ninit(ident))); ret kill_prestate(fcx, parent, ninit(id, ident));
} }
// //

View file

@ -49,10 +49,9 @@ import states::find_pre_post_state_fn;
fn check_unused_vars(&fn_ctxt fcx) { fn check_unused_vars(&fn_ctxt fcx) {
// FIXME: could be more efficient // FIXME: could be more efficient
for (norm_constraint c in constraints(fcx)) { for (norm_constraint c in constraints(fcx)) {
alt (c.c.node.c) { alt (c.c.node) {
case (ninit(?v)) { case (ninit(?id, ?v)) {
if (!vec_contains(fcx.enclosing.used_vars, if (!vec_contains(fcx.enclosing.used_vars, id)) {
c.c.node.id)) {
fcx.ccx.tcx.sess.span_warn(c.c.span, fcx.ccx.tcx.sess.span_warn(c.c.span,
"Unused variable " + v); "Unused variable " + v);
} }
@ -140,7 +139,7 @@ fn check_states_against_conditions(&fn_ctxt fcx, &_fn f,
/* Check that the return value is initialized */ /* Check that the return value is initialized */
auto post = aux::block_poststate(fcx.ccx, f.body); 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) && 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)) && !type_is_nil(fcx.ccx.tcx, ret_ty_of_fn(fcx.ccx.tcx, id)) &&
f.decl.cf == return) { f.decl.cf == return) {

View file

@ -14,12 +14,11 @@ import util::common::new_def_hash;
import syntax::codemap::span; import syntax::codemap::span;
import syntax::ast::respan; 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) { fn collect_local(&@local loc, &ctxt cx, &visit::vt[ctxt] v) {
log "collect_local: pushing " + loc.node.ident; log "collect_local: pushing " + loc.node.ident;
*cx.cs += ~[respan(loc.span, rec(id=loc.node.id, *cx.cs += ~[respan(loc.span, ninit(loc.node.id, loc.node.ident))];
c=ninit(loc.node.ident)))];
visit::visit_local(loc, cx, v); visit::visit_local(loc, cx, v);
} }
@ -34,11 +33,10 @@ fn collect_pred(&@expr e, &ctxt cx, &visit::vt[ctxt] v) {
// If it's a call, generate appropriate instances of the // If it's a call, generate appropriate instances of the
// call's constraints. // call's constraints.
case (expr_call(?operator, ?operands)) { case (expr_call(?operator, ?operands)) {
for (@ty::constr_def c in constraints_expr(cx.tcx, operator)) { for (@ty::constr c in constraints_expr(cx.tcx, operator)) {
let aux::constr ct = respan(c.span, let sp_constr ct = respan(c.span,
rec(id=c.node.id._1, aux::substitute_constr_args(cx.tcx, operands,
c=aux::substitute_constr_args(cx.tcx, operands, c));
c)));
*cx.cs += ~[ct]; *cx.cs += ~[ct];
} }
} }
@ -61,13 +59,14 @@ fn find_locals(&ty::ctxt tcx, &_fn f, &ty_param[] tps, &span sp, &fn_ident i,
ret cx; 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 { uint {
log aux::constraint_to_str(tcx, c) + " |-> " + std::uint::str(next); log constraint_to_str(tcx, c) + " |-> " + std::uint::str(next);
alt (c.node.c) { alt (c.node) {
case (ninit(?i)) { tbl.insert(c.node.id, cinit(next, c.span, i)); } case (ninit(?id, ?i)) { tbl.insert(local_def(id),
case (npred(?p, ?args)) { cinit(next, c.span, i)); }
alt (tbl.find(c.node.id)) { case (npred(?p, ?d_id, ?args)) {
alt (tbl.find(d_id)) {
case (some(?ct)) { case (some(?ct)) {
alt (ct) { alt (ct) {
case (cinit(_, _, _)) { case (cinit(_, _, _)) {
@ -76,16 +75,15 @@ fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl) ->
} }
case (cpred(_, ?pds)) { case (cpred(_, ?pds)) {
*pds += ~[respan(c.span, *pds += ~[respan(c.span,
rec(args=args, bit_num=next))]; rec(args=args, bit_num=next))];
} }
} }
} }
case (none) { case (none) {
tbl.insert(c.node.id, let @mutable(pred_args[]) rslt = @mutable(~[respan(c.span,
cpred(p, rec(args=args,
@mutable ~[respan(c.span, bit_num=next))]);
rec(args=args, tbl.insert(d_id, cpred(p, rslt));
bit_num=next))]));
} }
} }
} }
@ -98,22 +96,21 @@ fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl) ->
to a bit number in the precondition/postcondition vectors */ to a bit number in the precondition/postcondition vectors */
fn mk_fn_info(&crate_ctxt ccx, &_fn f, &ty_param[] tp, fn mk_fn_info(&crate_ctxt ccx, &_fn f, &ty_param[] tp,
&span f_sp, &fn_ident f_name, node_id id) { &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 uint next = 0u;
let ctxt cx = find_locals(ccx.tcx, f, tp, f_sp, f_name, id); 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 /* now we have to add bit nums for both the constraints
and the variables... */ 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); next = add_constraint(cx.tcx, c, next, res_map);
} }
/* add a pseudo-entry for the function's return value /* add a pseudo-entry for the function's return value
we can safely use the function's name itself for this purpose */ we can safely use the function's name itself for this purpose */
auto name = fn_ident_to_string(id, f_name); auto name = fn_ident_to_string(id, f_name);
add_constraint(cx.tcx, respan(f_sp, rec(id=id, c=ninit(name))), next, add_constraint(cx.tcx, respan(f_sp, ninit(id, name)), next, res_map);
res_map);
let @mutable node_id[] v = @mutable ~[]; let @mutable node_id[] v = @mutable ~[];
auto rslt = auto rslt =
rec(constrs=res_map, rec(constrs=res_map,

View file

@ -76,7 +76,7 @@ fn find_pre_post_item(&crate_ctxt ccx, &item i) {
// make a fake fcx // make a fake fcx
let @mutable node_id[] v = @mutable ~[]; let @mutable node_id[] v = @mutable ~[];
auto fake_fcx = auto fake_fcx =
rec(enclosing=rec(constrs=@new_int_hash[constraint](), rec(enclosing=rec(constrs=@new_def_hash[constraint](),
num_constraints=0u, num_constraints=0u,
cf=return, cf=return,
used_vars=v), used_vars=v),
@ -135,7 +135,7 @@ fn find_pre_post_loop(&fn_ctxt fcx, &@local l, &@expr index, &block body,
node_id id) { node_id id) {
find_pre_post_expr(fcx, index); find_pre_post_expr(fcx, index);
find_pre_post_block(fcx, body); 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); relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body);
// Hack: for-loop index variables are frequently ignored, // Hack: for-loop index variables are frequently ignored,
@ -160,7 +160,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
case (none) { case (none) {
alt (chck) { alt (chck) {
case (if_check) { 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); gen(fcx, antec.id, c.node);
} }
case (_) {} case (_) {}
@ -188,7 +188,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
so that it's *not* set in the alternative. */ so that it's *not* set in the alternative. */
alt (chck) { alt (chck) {
case (if_check) { 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); gen(fcx, antec.id, c.node);
} }
case (_) {} case (_) {}
@ -219,8 +219,7 @@ fn gen_if_local(&fn_ctxt fcx, @expr lhs, @expr rhs, node_id larger_id,
set_pre_and_post(fcx.ccx, larger_id, p.precondition, set_pre_and_post(fcx.ccx, larger_id, p.precondition,
p.postcondition); p.postcondition);
gen(fcx, larger_id, gen(fcx, larger_id,
rec(id=d_id._1, ninit(d_id._1, path_to_ident(fcx.ccx.tcx, pth)));
c=ninit(path_to_ident(fcx.ccx.tcx, pth))));
} }
case (_) { find_pre_post_exprs(fcx, ~[lhs, rhs], larger_id); } case (_) { find_pre_post_exprs(fcx, ~[lhs, rhs], larger_id); }
} }
@ -256,9 +255,8 @@ fn handle_update(&fn_ctxt fcx, &@expr parent,
alt (df) { alt (df) {
case (def_local(?d_id)) { case (def_local(?d_id)) {
auto i = auto i =
bit_num(fcx, bit_num(fcx, ninit(d_id._1,
rec(id=d_id._1, path_to_ident(fcx.ccx.tcx, p)));
c=ninit(path_to_ident(fcx.ccx.tcx, p))));
require_and_preserve(i, expr_pp(fcx.ccx, lhs)); require_and_preserve(i, expr_pp(fcx.ccx, lhs));
} }
case (_) {} case (_) {}
@ -269,8 +267,8 @@ fn handle_update(&fn_ctxt fcx, &@expr parent,
gen_if_local(fcx, lhs, rhs, parent.id, lhs.id, p); gen_if_local(fcx, lhs, rhs, parent.id, lhs.id, p);
alt (rhs.node) { alt (rhs.node) {
case (expr_path(?p1)) { case (expr_path(?p1)) {
auto d = local_node_id_to_def_id(fcx, lhs.id); auto d = local_node_id_to_local_def_id(fcx, lhs.id);
auto d1 = local_node_id_to_def_id(fcx, rhs.id); auto d1 = local_node_id_to_local_def_id(fcx, rhs.id);
alt (d) { alt (d) {
case (some(?id)) { case (some(?id)) {
alt (d1) { alt (d1) {
@ -312,13 +310,11 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
find_pre_post_exprs(fcx, args, e.id); find_pre_post_exprs(fcx, args, e.id);
/* see if the call has any constraints on its type */ /* 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 = auto i =
bit_num(fcx, bit_num(fcx, substitute_constr_args(fcx.ccx.tcx,
rec(id=c.node.id._1, args, c));
c=substitute_constr_args(fcx.ccx.tcx,
args, c)));
require(i, expr_pp(fcx.ccx, e)); require(i, expr_pp(fcx.ccx, e));
} }
@ -347,8 +343,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
case (def_local(?d_id)) { case (def_local(?d_id)) {
auto i = auto i =
bit_num(fcx, bit_num(fcx,
rec(id=d_id._1, ninit(d_id._1, path_to_ident(fcx.ccx.tcx, p)));
c=ninit(path_to_ident(fcx.ccx.tcx, p))));
use_var(fcx, d_id._1); use_var(fcx, d_id._1);
require_and_preserve(i, rslt); require_and_preserve(i, rslt);
} }
@ -547,7 +542,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
copy_pre_post(fcx.ccx, e.id, p); copy_pre_post(fcx.ccx, e.id, p);
/* predicate p holds after this expression executes */ /* 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); gen(fcx, e.id, c.node);
} }
case (expr_if_check(?p, ?conseq, ?maybe_alt)) { case (expr_if_check(?p, ?conseq, ?maybe_alt)) {
@ -608,17 +603,17 @@ fn find_pre_post_stmt(&fn_ctxt fcx, &stmt s) {
case (expr_path(?p)) { case (expr_path(?p)) {
copy_in_postcond(fcx, id, copy_in_postcond(fcx, id,
tup(alocal.node.ident, tup(alocal.node.ident,
local_def(alocal.node.id)), alocal.node.id),
tup(path_to_ident(fcx.ccx.tcx, p), tup(path_to_ident(fcx.ccx.tcx, p),
local_def(an_init.expr.id)), an_init.expr.id),
op_to_oper_ty(an_init.op)); op_to_oper_ty(an_init.op));
} }
case (_) {} case (_) {}
} }
gen(fcx, id, gen(fcx, id,
rec(id=alocal.node.id, ninit(alocal.node.id,
c=ninit(alocal.node.ident))); alocal.node.ident));
if (an_init.op == init_move && if (an_init.op == init_move &&
is_path(an_init.expr)) { is_path(an_init.expr)) {

View file

@ -63,8 +63,7 @@ fn seq_states(&fn_ctxt fcx, prestate pres, &(@expr)[] exprs) ->
} }
fn find_pre_post_state_sub(&fn_ctxt fcx, &prestate pres, &@expr e, fn find_pre_post_state_sub(&fn_ctxt fcx, &prestate pres, &@expr e,
node_id parent, option::t[aux::constr_] c) node_id parent, option::t[tsconstr] c) -> bool {
-> bool {
auto changed = find_pre_post_state_expr(fcx, pres, e); auto changed = find_pre_post_state_expr(fcx, pres, e);
changed = set_prestate_ann(fcx.ccx, parent, pres) || changed; changed = set_prestate_ann(fcx.ccx, parent, pres) || changed;
@ -118,8 +117,8 @@ fn find_pre_post_state_two(&fn_ctxt fcx, &prestate pres, &@expr lhs,
gen_if_local(fcx, post, lhs); gen_if_local(fcx, post, lhs);
alt (rhs.node) { alt (rhs.node) {
case (expr_path(?p1)) { case (expr_path(?p1)) {
auto d = local_node_id_to_def_id(fcx, lhs.id); auto d = local_node_id_to_local_def_id(fcx, lhs.id);
auto d1 = local_node_id_to_def_id(fcx, rhs.id); auto d1 = local_node_id_to_local_def_id(fcx, rhs.id);
alt (d) { alt (d) {
case (some(?id)) { case (some(?id)) {
alt (d1) { alt (d1) {
@ -249,7 +248,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
auto conseq_prestate = expr_poststate(fcx.ccx, antec); auto conseq_prestate = expr_poststate(fcx.ccx, antec);
alt (chk) { alt (chk) {
case (if_check) { 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); conseq_prestate = tritv_clone(conseq_prestate);
tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue); tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue);
} }
@ -387,8 +386,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
alt (fcx.enclosing.cf) { alt (fcx.enclosing.cf) {
case (noreturn) { case (noreturn) {
kill_poststate(fcx, e.id, rec(id=fcx.id, kill_poststate(fcx, e.id, ninit(fcx.id, fcx.name));
c=ninit(fcx.name)));
} }
case (_) { } case (_) { }
} }
@ -555,7 +553,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
} }
case (expr_check(_, ?p)) { case (expr_check(_, ?p)) {
/* predicate p holds after this expression executes */ /* 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)); ret find_pre_post_state_sub(fcx, pres, p, e.id, some(c.node));
} }
case (expr_if_check(?p, ?conseq, ?maybe_alt)) { case (expr_if_check(?p, ?conseq, ?maybe_alt)) {
@ -608,9 +606,9 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
auto instlhs = auto instlhs =
tup(alocal.node.ident, tup(alocal.node.ident,
local_def(alocal.node.id)); alocal.node.id);
auto rhs_d = local_node_id_to_def_id(fcx, auto rhs_d = local_node_id_to_local_def_id
an_init.expr.id); (fcx, an_init.expr.id);
alt (rhs_d) { alt (rhs_d) {
case (some(?rhsid)) { case (some(?rhsid)) {
auto instrhs = auto instrhs =

View file

@ -13,19 +13,15 @@ import std::option::some;
import std::smallintmap; import std::smallintmap;
import driver::session; import driver::session;
import syntax::ast; import syntax::ast;
import ast::def_id; import syntax::ast::*;
import ast::constr_arg_general;
import ast::mutability;
import ast::controlflow;
import ast::path_to_str;
import ast::spanned;
import syntax::codemap::span; import syntax::codemap::span;
import metadata::csearch; import metadata::csearch;
import util::common::*; import util::common::*;
import syntax::util::interner; import syntax::util::interner;
import util::ppaux::ty_to_str; import util::ppaux::ty_to_str;
import util::ppaux::ty_constr_to_str;
import util::ppaux::mode_str_1; import util::ppaux::mode_str_1;
import syntax::print::pprust::*;
export node_id_to_monotype; export node_id_to_monotype;
export node_id_to_type; export node_id_to_type;
@ -37,7 +33,8 @@ export arg;
export args_eq; export args_eq;
export bind_params_in_type; export bind_params_in_type;
export block_ty; export block_ty;
export constr_def; export constr;
export constr_;
export constr_general; export constr_general;
export constr_table; export constr_table;
export count_ty_params; export count_ty_params;
@ -67,6 +64,7 @@ export mk_bot;
export mk_box; export mk_box;
export mk_chan; export mk_chan;
export mk_char; export mk_char;
export mk_constr;
export mk_ctxt; export mk_ctxt;
export mk_float; export mk_float;
export mk_fn; export mk_fn;
@ -123,6 +121,7 @@ export ty_bot;
export ty_box; export ty_box;
export ty_chan; export ty_chan;
export ty_char; export ty_char;
export ty_constr;
export ty_float; export ty_float;
export ty_fn; export ty_fn;
export ty_fn_abi; export ty_fn_abi;
@ -151,6 +150,7 @@ export ty_var_id;
export ty_vec; export ty_vec;
export ty_param_substs_opt_and_ty_to_monotype; export ty_param_substs_opt_and_ty_to_monotype;
export ty_fn_args; export ty_fn_args;
export type_constr;
export type_contains_params; export type_contains_params;
export type_contains_vars; export type_contains_vars;
export type_err; export type_err;
@ -193,9 +193,9 @@ type method =
arg[] inputs, arg[] inputs,
t output, t output,
controlflow cf, 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); type mt = rec(t ty, ast::mutability mut);
@ -212,7 +212,7 @@ type ctxt =
ast_map::map items, ast_map::map items,
freevars::freevar_map freevars, freevars::freevar_map freevars,
constr_table fn_constrs, // constr_table fn_constrs,
type_cache tcache, type_cache tcache,
creader_cache rcache, creader_cache rcache,
hashmap[t, str] short_names_cache, hashmap[t, str] short_names_cache,
@ -265,7 +265,7 @@ tag sty {
ty_task; ty_task;
ty_tup(mt[]); ty_tup(mt[]);
ty_rec(field[]); 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_native_fn(ast::native_abi, arg[], t);
ty_obj(method[]); ty_obj(method[]);
ty_res(def_id, t, t[]); ty_res(def_id, t, t[]);
@ -273,14 +273,15 @@ tag sty {
ty_param(uint); // fn/tag type param ty_param(uint); // fn/tag type param
ty_type; ty_type;
ty_native(def_id); ty_native(def_id);
ty_constr(t, (@type_constr)[]);
// TODO: ty_fn_arg(t), for a possibly-aliased function argument // TODO: ty_fn_arg(t), for a possibly-aliased function argument
} }
type constr_def = spanned[constr_general[uint]]; // In the middle end, constraints have a def_id attached, referring
// to the definition of the operator in the constraint.
type constr_general[T] = type constr_general[ARG] = spanned[constr_general_[ARG, def_id]];
rec(ast::path path, (@constr_arg_general[T])[] args, def_id id); type type_constr = constr_general[path];
type constr = constr_general[uint];
// Data structures used in type unification // Data structures used in type unification
tag type_err { tag type_err {
@ -297,6 +298,8 @@ tag type_err {
terr_obj_meths(ast::ident, ast::ident); terr_obj_meths(ast::ident, ast::ident);
terr_arg_count; terr_arg_count;
terr_mode_mismatch(mode, mode); 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); type ty_param_count_and_ty = tup(uint, t);
@ -392,7 +395,8 @@ fn mk_rcache() -> creader_cache {
ret map::mk_hashmap[tup(int, uint, uint), t](h, e); 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 { ast_map::map amap, freevars::freevar_map freevars) -> ctxt {
let node_type_table ntt = let node_type_table ntt =
@smallintmap::mk[ty::ty_param_substs_opt_and_ty](); @smallintmap::mk[ty::ty_param_substs_opt_and_ty]();
@ -405,7 +409,6 @@ fn mk_ctxt(session::session s, resolve::def_map dm, constr_table cs,
node_types=ntt, node_types=ntt,
items=amap, items=amap,
freevars=freevars, freevars=freevars,
fn_constrs=cs,
tcache=tcache, tcache=tcache,
rcache=mk_rcache(), rcache=mk_rcache(),
short_names_cache=map::mk_hashmap[ty::t, short_names_cache=map::mk_hashmap[ty::t,
@ -501,6 +504,9 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t {
derive_flags_t(cx, has_params, has_vars, tt); 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, ret rec(struct=st,
cname=cname, cname=cname,
@ -594,8 +600,12 @@ fn mk_imm_tup(&ctxt cx, &t[] tys) -> t {
fn mk_rec(&ctxt cx, &field[] fs) -> t { ret gen_ty(cx, ty_rec(fs)); } 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, 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)); ret gen_ty(cx, ty_fn(proto, args, ty, cf, constrs));
} }
@ -1300,6 +1310,33 @@ fn hash_type_structure(&sty st) -> uint {
h += h << 5u + hash_ty(subty); h += h << 5u + hash_ty(subty);
ret h; 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 { fn hash_fn(uint id, &arg[] args, &t rty) -> uint {
auto h = id; auto h = id;
for (arg a in args) { h += h << 5u + hash_ty(a.ty); } for (arg a in args) { h += h << 5u + hash_ty(a.ty); }
@ -1371,6 +1408,13 @@ fn hash_type_structure(&sty st) -> uint {
for (t tp in tps) { h += h << 5u + hash_ty(tp); } for (t tp in tps) { h += h << 5u + hash_ty(tp); }
ret h; 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;
}
} }
} }
@ -1392,8 +1436,8 @@ fn hash_ty(&t typ) -> uint { ret typ; }
// users should use `eq_ty()` instead. // users should use `eq_ty()` instead.
fn eq_int(&uint x, &uint y) -> bool { ret x == y; } 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, fn arg_eq[T](&fn(&T, &T) -> bool eq, @sp_constr_arg[T] a,
@ast::constr_arg_general[T] b) -> bool { @sp_constr_arg[T] b) -> bool {
alt (a.node) { alt (a.node) {
case (ast::carg_base) { case (ast::carg_base) {
alt (b.node) { alt (b.node) {
@ -1416,26 +1460,26 @@ fn arg_eq[T](&fn(&T, &T) -> bool eq, @ast::constr_arg_general[T] a,
} }
} }
fn args_eq[T](fn(&T, &T) -> bool eq, &(@ast::constr_arg_general[T])[] a, fn args_eq[T](fn(&T, &T) -> bool eq,
&(@ast::constr_arg_general[T])[] b) -> bool { &(@sp_constr_arg[T])[] a, &(@sp_constr_arg[T])[] b) -> bool {
let uint i = 0u; 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; } if (!arg_eq(eq, arg, b.(i))) { ret false; }
i += 1u; i += 1u;
} }
ret true; 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) && ret path_to_str(c.node.path) == path_to_str(d.node.path) &&
// FIXME: hack // FIXME: hack
args_eq(eq_int, c.node.args, d.node.args); 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; } if (ivec::len(cs) != ivec::len(ds)) { ret false; }
auto i = 0u; auto i = 0u;
for (@constr_def c in cs) { for (@constr c in cs) {
if (!constr_eq(c, ds.(i))) { ret false; } if (!constr_eq(c, ds.(i))) { ret false; }
i += 1u; i += 1u;
} }
@ -2053,6 +2097,76 @@ mod unify {
ret ures_err(terr_mismatch); 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. // Unifies two mutability flags.
fn unify_mut(ast::mutability expected, ast::mutability actual) -> fn unify_mut(ast::mutability expected, ast::mutability actual) ->
option::t[ast::mutability] { option::t[ast::mutability] {
@ -2109,8 +2223,8 @@ mod unify {
&t expected, &t actual, &arg[] expected_inputs, &t expected, &t actual, &arg[] expected_inputs,
&t expected_output, &arg[] actual_inputs, &t actual_output, &t expected_output, &arg[] actual_inputs, &t actual_output,
&controlflow expected_cf, &controlflow actual_cf, &controlflow expected_cf, &controlflow actual_cf,
&(@constr_def)[] expected_constrs, &(@constr)[] expected_constrs,
&(@constr_def)[] actual_constrs) -> result { &(@constr)[] actual_constrs) -> result {
if (e_proto != a_proto) { ret ures_err(terr_mismatch); } if (e_proto != a_proto) { ret ures_err(terr_mismatch); }
alt (expected_cf) { alt (expected_cf) {
case (ast::return) { } case (ast::return) { }
@ -2612,6 +2726,31 @@ mod unify {
case (_) { ret ures_err(terr_mismatch); } 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) -> fn unify(&t expected, &t actual, &@var_bindings vb, &ty_ctxt tcx) ->
@ -2730,6 +2869,15 @@ fn type_err_to_str(&ty::type_err err) -> str {
+ mode_str_1(a_mode); + mode_str_1(a_mode);
fail; 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);
}
} }
} }

View file

@ -2,7 +2,6 @@
import syntax::ast; import syntax::ast;
import ast::mutability; import ast::mutability;
import ast::local_def; import ast::local_def;
import ast::path_to_str;
import ast::respan; import ast::respan;
import ast::spanned; import ast::spanned;
import syntax::walk; import syntax::walk;
@ -47,6 +46,7 @@ import std::option::some;
import std::option::from_maybe; import std::option::from_maybe;
import std::smallintmap; import std::smallintmap;
import middle::tstate::ann::ts_ann; import middle::tstate::ann::ts_ann;
import syntax::print::pprust::*;
export check_crate; export check_crate;
@ -396,6 +396,13 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
} }
typ = ty::mk_obj(tcx, ty::sort_methods(tmeths)); 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) { alt (cname) {
case (none) {/* no-op */ } case (none) {/* no-op */ }
@ -2519,8 +2526,8 @@ fn get_obj_info(&@crate_ctxt ccx) -> option::t[obj_info] {
ret ivec::last[obj_info](ccx.obj_infos); ret ivec::last[obj_info](ccx.obj_infos);
} }
fn ast_constr_to_constr(ty::ctxt tcx, &@ast::constr c) fn ast_constr_to_constr[T](ty::ctxt tcx, &@ast::constr_general[T] c)
-> @ty::constr_def { -> @ty::constr_general[T] {
alt (tcx.def_map.find(c.node.id)) { alt (tcx.def_map.find(c.node.id)) {
case (some(ast::def_fn(?pred_id, ast::pure_fn))) { case (some(ast::def_fn(?pred_id, ast::pure_fn))) {
ret @respan(c.span, rec(path=c.node.path, args=c.node.args, ret @respan(c.span, rec(path=c.node.path, args=c.node.args,
@ -2528,9 +2535,9 @@ fn ast_constr_to_constr(ty::ctxt tcx, &@ast::constr c)
} }
case (_) { case (_) {
tcx.sess.span_fatal(c.span, "Predicate " tcx.sess.span_fatal(c.span, "Predicate "
+ path_to_str(c.node.path) + path_to_str(c.node.path)
+ " is unbound or bound to a non-function or an\ + " is unbound or bound to a non-function or an \
impure function"); impure function");
} }
} }
} }

View file

@ -444,7 +444,7 @@ tag ty_ {
ty_obj(ty_method[]); ty_obj(ty_method[]);
ty_path(path, node_id); ty_path(path, node_id);
ty_type; ty_type;
ty_constr(@ty, (@constr)[]); ty_constr(@ty, (@ty_constr)[]);
ty_mac(mac); ty_mac(mac);
} }
@ -459,16 +459,26 @@ declarations, and ident for uses.
*/ */
tag constr_arg_general_[T] { carg_base; carg_ident(T); carg_lit(@lit); } 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, type constr_general_[ARG, ID] = rec(path path,
(@constr_arg_general[uint])[] args, (@(spanned[constr_arg_general_[ARG]]))[] args, ID id);
node_id id);
type constr = spanned[constr_];
// 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 /* The parser generates ast::constrs; resolve generates
a mapping from each function to a list of ty::constr_defs, a mapping from each function to a list of ty::constr_defs,
@ -671,19 +681,6 @@ fn ternary_to_if(&@expr e) -> @ast::expr {
} }
} }
// 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: // Local Variables:
// mode: rust // mode: rust

View file

@ -35,7 +35,7 @@ type ast_fold_precursor =
fn (&decl_ d, ast_fold) -> decl_ fold_decl, fn (&decl_ d, ast_fold) -> decl_ fold_decl,
fn (&expr_ e, ast_fold) -> expr_ fold_expr, fn (&expr_ e, ast_fold) -> expr_ fold_expr,
fn (&ty_ t, ast_fold) -> ty_ fold_ty, 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 (&_fn f, ast_fold) -> _fn fold_fn,
fn (&_mod m, ast_fold) -> _mod fold_mod, fn (&_mod m, ast_fold) -> _mod fold_mod,
fn (&native_mod, ast_fold) -> native_mod fold_native_mod, fn (&native_mod, ast_fold) -> native_mod fold_native_mod,
@ -473,7 +473,7 @@ fn noop_fold_ty(&ty_ t, ast_fold fld) -> ty_ {
} }
fn noop_fold_constr(&constr_ c, ast_fold fld) -> constr_ { 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 // functions just don't get spans, for some reason
@ -664,7 +664,8 @@ fn make_fold(&ast_fold_precursor afp) -> ast_fold {
fn f_ty(&ast_fold_precursor afp, ast_fold f, &@ty x) -> @ty { 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); 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); 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 { fn f_fn(&ast_fold_precursor afp, ast_fold f, &_fn x) -> _fn {

View file

@ -14,6 +14,8 @@ import ex=ext::base;
import codemap::span; import codemap::span;
import std::map::new_str_hash; import std::map::new_str_hash;
import util::interner; import util::interner;
import ast::node_id;
import ast::spanned;
tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; } tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; }
@ -22,9 +24,9 @@ tag file_type { CRATE_FILE; SOURCE_FILE; }
tag ty_or_bang { a_ty(@ast::ty); a_bang; } tag ty_or_bang { a_ty(@ast::ty); a_bang; }
type parse_sess = @rec(codemap::codemap cm, 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; auto rv = sess.next_id;
sess.next_id += 1; sess.next_id += 1;
ret rv; ret rv;
@ -51,7 +53,7 @@ type parser =
fn get_bad_expr_words() -> hashmap[str, ()] ; fn get_bad_expr_words() -> hashmap[str, ()] ;
fn get_chpos() -> uint ; fn get_chpos() -> uint ;
fn get_byte_pos() -> uint ; fn get_byte_pos() -> uint ;
fn get_id() -> ast::node_id ; fn get_id() -> node_id ;
fn get_sess() -> parse_sess; fn get_sess() -> parse_sess;
}; };
@ -116,7 +118,7 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr,
fn get_bad_expr_words() -> hashmap[str, ()] { ret bad_words; } fn get_bad_expr_words() -> hashmap[str, ()] { ret bad_words; }
fn get_chpos() -> uint { ret rdr.get_chpos(); } fn get_chpos() -> uint { ret rdr.get_chpos(); }
fn get_byte_pos() -> uint { ret rdr.get_byte_pos(); } 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 get_sess() -> parse_sess { ret sess; }
} }
@ -188,7 +190,7 @@ fn expect(&parser p, token::token t) {
} }
} }
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)); ret rec(node=node, span=rec(lo=lo, hi=hi));
} }
@ -261,7 +263,9 @@ fn parse_ty_fn(ast::proto proto, &parser p, uint lo) -> ast::ty_ {
auto inputs = auto inputs =
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_fn_input_ty, p); 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; let @ast::ty output;
auto cf = ast::return; auto cf = ast::return;
if (p.peek() == token::RARROW) { if (p.peek() == token::RARROW) {
@ -275,7 +279,7 @@ fn parse_ty_fn(ast::proto proto, &parser p, uint lo) -> ast::ty_ {
} }
} }
} else { output = @spanned(lo, inputs.span.hi, ast::ty_nil); } } 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 { fn parse_proto(&parser p) -> ast::proto {
@ -336,6 +340,20 @@ fn ident_index(&parser p, &ast::arg[] args, &ast::ident i) -> uint {
p.fatal("Unbound variable " + i + " in constraint arg"); 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 { fn parse_constr_arg(&ast::arg[] args, &parser p) -> @ast::constr_arg {
auto sp = p.get_span(); auto sp = p.get_span();
auto carg = ast::carg_base; auto carg = ast::carg_base;
@ -355,43 +373,39 @@ fn parse_ty_constr(&ast::arg[] fn_args, &parser p) -> @ast::constr {
let rec((@ast::constr_arg)[] node, span span) args = let rec((@ast::constr_arg)[] node, span span) args =
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), pf, parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), pf,
p); p);
// FIXME fix the def_id
ret @spanned(lo, args.span.hi, ret @spanned(lo, args.span.hi,
rec(path=path, args=args.node, id=p.get_id())); rec(path=path, args=args.node, id=p.get_id()));
} }
fn parse_constr_in_type(&parser p) -> @ast::ty_constr {
// 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)[]] {
auto lo = p.get_lo_pos(); auto lo = p.get_lo_pos();
auto hi = p.get_hi_pos(); auto path = parse_path(p);
let (@ast::constr)[] constrs = ~[]; let (@ast::ty_constr_arg)[] args =
if (p.peek() == token::COLON) { (parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
p.bump(); parse_type_constr_arg, p)).node;
while (true) { auto hi = p.get_lo_pos();
auto constr = parse_ty_constr(args, p); let ast::ty_constr_ tc = rec(path=path, args=args, id=p.get_id());
hi = constr.span.hi; ret @spanned(lo, hi, tc);
constrs += ~[constr];
if (p.peek() == token::COMMA) { p.bump(); } else { break; }
}
}
ret spanned(lo, hi, constrs);
} }
fn parse_ty_constrs(@ast::ty t, &parser p) -> @ast::ty {
if (p.peek() == token::COLON) { fn parse_constrs[T](fn(&parser p) ->
auto constrs = parse_constrs(~[], p); (@ast::constr_general[T]) pser, &parser p)
ret @spanned(t.span.lo, constrs.span.hi, -> (@ast::constr_general[T])[] {
ast::ty_constr(t, constrs.node)); 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_ty_postfix(@ast::ty orig_t, &parser p) -> @ast::ty { 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 {
auto lo = p.get_lo_pos(); auto lo = p.get_lo_pos();
if (p.peek() == token::LBRACKET) { if (p.peek() == token::LBRACKET) {
p.bump(); p.bump();
@ -413,7 +427,7 @@ fn parse_ty_postfix(@ast::ty orig_t, &parser p) -> @ast::ty {
auto seq = parse_seq_to_end(token::RBRACKET, auto seq = parse_seq_to_end(token::RBRACKET,
some(token::COMMA), parse_ty, p); some(token::COMMA), parse_ty, p);
alt (orig_t.node) { alt (orig_t) {
case (ast::ty_path(?pth, ?ann)) { case (ast::ty_path(?pth, ?ann)) {
auto hi = p.get_hi_pos(); auto hi = p.get_hi_pos();
ret @spanned(lo, hi, ret @spanned(lo, hi,
@ -432,10 +446,11 @@ fn parse_ty_postfix(@ast::ty orig_t, &parser p) -> @ast::ty {
expect(p, token::RBRACKET); expect(p, token::RBRACKET);
auto hi = p.get_hi_pos(); auto hi = p.get_hi_pos();
auto t = ast::ty_ivec(rec(ty=orig_t, mut=mut)); // FIXME: spans are probably wrong
ret parse_ty_postfix(@spanned(lo, hi, t), p); 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 { fn parse_ty_or_bang(&parser p) -> ty_or_bang {
@ -528,7 +543,15 @@ fn parse_ty(&parser p) -> @ast::ty {
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_ty_field, p); parse_ty_field, p);
hi = elems.span.hi; 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); 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")) { } else if (eat_word(p, "fn")) {
auto flo = p.get_last_lo_pos(); auto flo = p.get_last_lo_pos();
t = parse_ty_fn(ast::proto_fn, p, flo); t = parse_ty_fn(ast::proto_fn, p, flo);
@ -559,7 +582,7 @@ fn parse_ty(&parser p) -> @ast::ty {
t = ast::ty_path(path, p.get_id()); t = ast::ty_path(path, p.get_id());
hi = path.span.hi; hi = path.span.hi;
} else { p.fatal("expecting type"); t = ast::ty_nil; fail; } } 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_arg(&parser p) -> ast::arg {
@ -593,7 +616,7 @@ fn parse_seq_to_end[T](token::token ket, option::t[token::token] sep,
fn parse_seq[T](token::token bra, token::token ket, fn parse_seq[T](token::token bra, token::token ket,
option::t[token::token] sep, 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(); auto lo = p.get_lo_pos();
expect(p, bra); expect(p, bra);
auto result = parse_seq_to_end[T](ket, sep, f, p); auto result = parse_seq_to_end[T](ket, sep, f, p);
@ -1739,7 +1762,14 @@ fn parse_fn_decl(&parser p, ast::purity purity) -> ast::fn_decl {
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_arg, p); parse_arg, p);
let ty_or_bang rslt; 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) { if (p.peek() == token::RARROW) {
p.bump(); p.bump();
rslt = parse_ty_or_bang(p); rslt = parse_ty_or_bang(p);

View file

@ -332,7 +332,7 @@ fn print_type(&ps s, &ast::ty ty) {
space(s.s); space(s.s);
word(s.s, ":"); word(s.s, ":");
space(s.s); space(s.s);
word(s.s, ast_constrs_str(cs)); word(s.s, ast_ty_constrs_str(cs));
} }
} }
end(s); end(s);
@ -1521,10 +1521,10 @@ fn next_comment(&ps s) -> option::t[lexer::cmnt] {
// Removing the aliases from the type of f in the next two functions // 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 // triggers memory corruption, but I haven't isolated the bug yet. FIXME
fn constr_args_to_str[T](&fn(&T) -> str f, 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 comma = false;
auto s = "("; 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; } if (comma) { s += ", "; } else { comma = true; }
s += constr_arg_to_str[T](f, a.node); s += constr_arg_to_str[T](f, a.node);
} }
@ -1547,10 +1547,11 @@ fn constr_arg_to_str[T](&fn(&T) -> str f, &ast::constr_arg_general_[T] c) ->
fn uint_to_str(&uint i) -> str { ret uint::str(i); } fn uint_to_str(&uint i) -> str { ret uint::str(i); }
fn ast_constr_to_str(&@ast::constr c) -> str { fn ast_constr_to_str(&@ast::constr c) -> str {
ret ast::path_to_str(c.node.path) + ret path_to_str(c.node.path) +
constr_args_to_str(uint_to_str, c.node.args); constr_args_to_str(uint_to_str, c.node.args);
} }
// FIXME: fix repeated code
fn ast_constrs_str(&(@ast::constr)[] constrs) -> str { fn ast_constrs_str(&(@ast::constr)[] constrs) -> str {
auto s = ""; auto s = "";
auto colon = true; auto colon = true;
@ -1568,6 +1569,22 @@ fn proto_to_str(&ast::proto p) -> str {
}; };
} }
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: // Local Variables:
// mode: rust // mode: rust

View file

@ -30,7 +30,9 @@ type visitor[E] =
fn(&@decl, &E, &vt[E]) visit_decl, fn(&@decl, &E, &vt[E]) visit_decl,
fn(&@expr, &E, &vt[E]) visit_expr, fn(&@expr, &E, &vt[E]) visit_expr,
fn(&@ty, &E, &vt[E]) visit_ty, 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]) fn(&_fn, &ty_param[], &span, &fn_ident, node_id, &E, &vt[E])
visit_fn); visit_fn);
@ -47,7 +49,7 @@ fn default_visitor[E]() -> visitor[E] {
visit_decl=bind visit_decl[E](_, _, _), visit_decl=bind visit_decl[E](_, _, _),
visit_expr=bind visit_expr[E](_, _, _), visit_expr=bind visit_expr[E](_, _, _),
visit_ty=bind visit_ty[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](_, _, _, _, _, _, _)); visit_fn=bind visit_fn[E](_, _, _, _, _, _, _));
} }
@ -160,7 +162,8 @@ fn visit_ty[E](&@ty t, &E e, &vt[E] v) {
} }
case (ty_fn(_, ?args, ?out, _, ?constrs)) { case (ty_fn(_, ?args, ?out, _, ?constrs)) {
for (ty_arg a in args) { v.visit_ty(a.node.ty, e, v); } 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); v.visit_ty(out, e, v);
} }
case (ty_obj(?tmeths)) { case (ty_obj(?tmeths)) {
@ -175,7 +178,12 @@ fn visit_ty[E](&@ty t, &E e, &vt[E] v) {
for (@ty tp in p.node.types) { v.visit_ty(tp, e, v); } for (@ty tp in p.node.types) { v.visit_ty(tp, e, v); }
} }
case (ty_type) { /* no-op */ } 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);
}
}
} }
} }
@ -186,7 +194,7 @@ fn visit_ty_opt[E](&option::t[@ty] ot, &E e, &vt[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 // default
} }
@ -214,7 +222,9 @@ fn visit_native_item[E](&@native_item ni, &E e, &vt[E] v) {
fn visit_fn_decl[E](&fn_decl fd, &E e, &vt[E] v) { 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 (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); v.visit_ty(fd.output, e, v);
} }

View file

@ -9,6 +9,8 @@ import middle::ty::*;
import metadata::encoder; import metadata::encoder;
import syntax::print::pp; import syntax::print::pp;
import syntax::print::pprust; import syntax::print::pprust;
import syntax::print::pprust::path_to_str;
import syntax::print::pprust::constr_args_to_str;
import pp::word; import pp::word;
import pp::eof; import pp::eof;
import pp::zerobreak; import pp::zerobreak;
@ -46,7 +48,7 @@ fn ty_to_str(&ctxt cx, &t typ) -> str {
} }
fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident, fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident,
&arg[] inputs, t output, ast::controlflow cf, &arg[] inputs, t output, ast::controlflow cf,
&(@constr_def)[] constrs) -> str { &(@constr)[] constrs) -> str {
auto s; auto s;
alt (proto) { alt (proto) {
case (ast::proto_iter) { s = "iter"; } case (ast::proto_iter) { s = "iter"; }
@ -154,21 +156,27 @@ fn ty_to_short_str(&ctxt cx, t typ) -> str {
ret s; ret s;
} }
fn constr_to_str(&@constr_def c) -> str { fn constr_to_str(&@constr c) -> str {
ret ast::path_to_str(c.node.path) + ret path_to_str(c.node.path) +
pprust::constr_args_to_str(pprust::uint_to_str, c.node.args); 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 s = "";
auto colon = true; auto colon = true;
for (@constr_def c in constrs) { for (@constr c in constrs) {
if (colon) { s += " : "; colon = false; } else { s += ", "; } if (colon) { s += " : "; colon = false; } else { s += ", "; }
s += constr_to_str(c); s += constr_to_str(c);
} }
ret s; 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: // Local Variables:
// mode: rust // mode: rust
// fill-column: 78; // fill-column: 78;

View file

@ -0,0 +1,25 @@
// -*- 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;
}

View file

@ -1,10 +1,6 @@
// xfail-stage0 // xfail-stage0
// xfail-stage1
// xfail-stage2
// -*- rust -*- // -*- rust -*-
// Reported as issue #141, as a parse error. Ought to work in full though.
tag list { tag list {
cons(int,@list); cons(int,@list);
nil(); nil();
@ -12,8 +8,7 @@ tag list {
type bubu = rec(int x, int y); type bubu = rec(int x, int y);
pred less_than(int x, int y) -> bool { ret x < y; }
fn less_than(int x, int y) -> bool { ret x < y; }
type ordered_range = rec(int low, int high) : less_than(*.low, *.high); type ordered_range = rec(int low, int high) : less_than(*.low, *.high);