]> git.lizzy.rs Git - rust.git/commitdiff
Beginnings of support for constrained types
authorTim Chevalier <chevalier@alum.wellesley.edu>
Wed, 20 Jul 2011 00:52:34 +0000 (17:52 -0700)
committerTim Chevalier <chevalier@alum.wellesley.edu>
Wed, 20 Jul 2011 01:57:28 +0000 (18:57 -0700)
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.

20 files changed:
src/comp/driver/rustc.rs
src/comp/metadata/tydecode.rs
src/comp/metadata/tyencode.rs
src/comp/middle/resolve.rs
src/comp/middle/tstate/auxiliary.rs
src/comp/middle/tstate/bitvectors.rs
src/comp/middle/tstate/ck.rs
src/comp/middle/tstate/collect_locals.rs
src/comp/middle/tstate/pre_post_conditions.rs
src/comp/middle/tstate/states.rs
src/comp/middle/ty.rs
src/comp/middle/typeck.rs
src/comp/syntax/ast.rs
src/comp/syntax/fold.rs
src/comp/syntax/parse/parser.rs
src/comp/syntax/print/pprust.rs
src/comp/syntax/visit.rs
src/comp/util/ppaux.rs
src/test/compile-fail/constrained-type-missing-check.rs [new file with mode: 0644]
src/test/run-pass/constrained-type.rs

index b24dedffdd0c8f30444bbaebffe5057e0772d8f2..7e360e7f0e1382f69ba1c26d1293a2b1f69a6de8 100644 (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));
     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) {
@@ -200,8 +200,8 @@ fn ann_identified_post(&pprust::ann_node node) {
         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, _));
index 2804c53024052dae8cb8f4c6757e2537bfd995c9..6f55f6d097c2fc9ce2e0110e9e17ddf808431172 100644 (file)
@@ -7,6 +7,7 @@
 import std::option::none;
 import std::option::some;
 import syntax::ast;
+import syntax::ast::*;
 import ast::respan;
 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)[] {
-    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 (_) { }
@@ -102,40 +105,50 @@ fn is_last(char c) -> bool {
     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 == ')');
@@ -335,7 +348,7 @@ fn parse_hex(@pstate st) -> uint {
 }
 
 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 != ']') {
@@ -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;
     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:
+//
index 3b3ce6b3866af0341d3e6cef89257a08a211d2b7..e239d678174057b60ce0f0101248b2b1aa83b9bd 100644 (file)
@@ -8,7 +8,7 @@
 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;
@@ -199,8 +199,9 @@ fn enc_proto(&ioivec::writer w, proto proto) {
         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) {
@@ -214,7 +215,7 @@ fn enc_ty_fn(&ioivec::writer w, &@ctxt cx, &ty::arg[] args, &ty::t out,
     }
     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;
@@ -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_char('(');
     w.write_str(cx.ds(c.node.id));
index a0fbc6a7061f818921db72bcbbf989bcc28adb43..0a3d61b165a6d06a96ba27a13a24937d4abef269 100644 (file)
@@ -1,5 +1,6 @@
 
 import syntax::ast;
+import syntax::ast::*;
 import ast::ident;
 import ast::fn_ident;
 import ast::def;
@@ -19,6 +20,7 @@
 import syntax::visit;
 import visit::vt;
 import std::ivec;
+import std::int;
 import std::map::hashmap;
 import std::list;
 import std::list::list;
@@ -28,6 +30,7 @@
 import std::option::some;
 import std::option::none;
 import std::str;
+import syntax::print::pprust::*;
 
 export resolve_crate;
 export def_map;
@@ -109,7 +112,6 @@ fn eq(&tup(def_id, str, namespace) v1, &tup(def_id, str, namespace) v2) ->
 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,
@@ -124,12 +126,11 @@ fn eq(&tup(def_id, str, namespace) v1, &tup(def_id, str, namespace) v2) ->
 
 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](),
@@ -140,7 +141,7 @@ fn resolve_crate(session sess, &ast_map::map amap, @ast::crate crate) ->
     resolve_imports(*e);
     check_for_collisions(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_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));
@@ -277,10 +278,9 @@ fn walk_ty(@env e, &@ast::ty t, &scopes sc, &vt[scopes] 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); }
@@ -411,29 +411,18 @@ fn resolve_constr(@env e, node_id id, &@ast::constr c, &scopes sc,
     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;
index 6df2f3ff01615d257c4ab60201c8263606c6e3c7..d6303b15fe63de22d6fef054a803631cdebaee8c 100644 (file)
@@ -72,12 +72,12 @@ fn comma_str(&(@constr_arg_use)[] args) -> str {
     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) + "]";
         }
@@ -204,31 +204,36 @@ fn print_idents(&mutable ident[] idents) {
 
 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,
@@ -240,6 +245,12 @@ fn print_idents(&mutable ident[] idents) {
                    // 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];
@@ -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))) {
         case (ty::ty_fn(_, _, _, _, ?cs)) { ret cs; }
         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);
 }
 
-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;
         }
@@ -512,19 +522,23 @@ fn norm_a_constraint(node_id id, &constraint c) -> norm_constraint[] {
 // 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; }
@@ -532,12 +546,12 @@ fn eq(&tup(ident, def_id) p, &tup(ident, def_id) q) -> bool {
     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");
         }
@@ -550,11 +564,11 @@ fn expr_to_constr_arg(ty::ctxt tcx, &@expr e) -> @constr_arg_use {
             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 " +
@@ -582,7 +596,7 @@ fn exprs_to_constr_args(ty::ctxt tcx, &(@expr)[] args)
     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
@@ -591,9 +605,8 @@ fn expr_to_constr(ty::ctxt tcx, &@expr e) -> constr {
             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,
@@ -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) + ", " +
-        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) ->
@@ -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,
-                     &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);
@@ -679,17 +692,17 @@ fn pred_desc_matches(&(constr_arg_general_[tup(ident, def_id)])[] pattern,
     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)
@@ -703,7 +716,7 @@ 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);
@@ -720,7 +733,7 @@ fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
     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);
@@ -729,7 +742,7 @@ fn find_in_subst(def_id id, &subst s) -> option::t[inst] {
     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))
 }
 
@@ -745,7 +758,7 @@ fn insts_to_str(&(constr_arg_general_[inst])[] stuff) -> str {
     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) {
@@ -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,
                     oper_type ty) {
     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()) {
         // replace any occurrences of the src def_id with the
         // 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) {
     // 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)) {
@@ -896,7 +918,7 @@ fn forget_in_postcond_still_init(&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)) {
@@ -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 {
     // 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)) {
@@ -932,7 +954,7 @@ fn forget_in_poststate_still_init(&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)) {
@@ -947,37 +969,35 @@ fn forget_in_poststate_still_init(&fn_ctxt fcx, &poststate p, node_id dead_v)
     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
index d0d4f9bde8fcdcac9213a01097e8e837e139d354..e7afe85f34f777b40752d73ab2565de30202dda8 100644 (file)
@@ -1,29 +1,8 @@
-
 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 (_) {
@@ -60,11 +40,10 @@ fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
                 }
             }
         }
-        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,"
@@ -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);
 }
 
@@ -161,12 +140,12 @@ fn intersect_states(&prestate p, &prestate q) -> prestate {
     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
@@ -209,18 +188,18 @@ fn quit(@mutable bool keepgoing, &@item i) {
     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);
@@ -233,9 +212,8 @@ fn clear_in_poststate_expr(&fn_ctxt fcx, &@expr e, &poststate t) {
                 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 (_) {
@@ -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,
                           &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));
 }
 
 //
index 84e5232a34998818fd083115f6a45985e0d0acca..503fbf8fc121c0debbe7418a1cf7111df3325ccd 100644 (file)
 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);
                 }
@@ -140,7 +139,7 @@ fn check_states_against_conditions(&fn_ctxt fcx, &_fn f,
 
     /* 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) {
index fb2d342f9226dda204cefd74cb6607f1afcf488e..5005ad5132b2c0ab176af5a12785746ad055d3fb 100644 (file)
 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);
 }
 
@@ -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
         // 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];
             }
         }
@@ -61,13 +59,14 @@ fn find_locals(&ty::ctxt tcx, &_fn f, &ty_param[] tps, &span sp, &fn_ident i,
     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(_, _, _)) {
@@ -76,16 +75,15 @@ fn add_constraint(&ty::ctxt tcx, aux::constr c, uint next, constr_map tbl) ->
                         }
                         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));
                 }
             }
         }
@@ -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 */
 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,
index 14067f7d01bdd954b4b17bf0e06dca3bad52f375..8f802db30bd200cc80c5bc68a0f51610ec5895bc 100644 (file)
@@ -76,7 +76,7 @@ fn find_pre_post_item(&crate_ctxt ccx, &item i) {
             // 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),
@@ -135,7 +135,7 @@ fn find_pre_post_loop(&fn_ctxt fcx, &@local l, &@expr index, &block body,
                       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,
@@ -160,7 +160,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
         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 (_) {}
@@ -188,7 +188,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
              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 (_) {}
@@ -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,
                                      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); }
             }
@@ -256,9 +255,8 @@ fn handle_update(&fn_ctxt fcx, &@expr parent,
                     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 (_) {}
@@ -269,8 +267,8 @@ fn handle_update(&fn_ctxt fcx, &@expr parent,
             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) {
@@ -312,13 +310,11 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
 
             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));
                 }
 
@@ -347,8 +343,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr 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);
                 }
@@ -547,7 +542,7 @@ fn combine_pp(pre_and_post antec, fn_ctxt fcx, &pre_and_post pp,
             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)) {
@@ -608,17 +603,17 @@ fn find_pre_post_stmt(&fn_ctxt fcx, &stmt s) {
                                 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)) {
index b8cee2c67159ea09bc1c095ceee6621016546489..c806493bdeaa0f920e112a1b68bb2abd5424108a 100644 (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,
-                           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;
@@ -118,8 +117,8 @@ fn find_pre_post_state_two(&fn_ctxt fcx, &prestate pres, &@expr lhs,
             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) {
@@ -249,7 +248,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
             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);
                 }
@@ -387,8 +386,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
 
             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 (_) { }
             }
@@ -555,7 +553,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
         }
         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)) {
@@ -608,9 +606,9 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
 
                                     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 =
index 30c04a7492263c0ee9a14d3749a0fc5109e399be..138b98b75702bf0f5d766324fed29ce957ef20bc 100644 (file)
 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;
@@ -37,7 +33,8 @@
 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;
@@ -67,6 +64,7 @@
 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,
@@ -265,7 +265,7 @@ fn method_ty_to_fn_ty(&ctxt cx, method m) -> t {
     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[]);
@@ -273,14 +273,15 @@ fn method_ty_to_fn_ty(&ctxt cx, method m) -> 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 {
@@ -297,6 +298,8 @@ fn method_ty_to_fn_ty(&ctxt cx, method m) -> t {
     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);
@@ -392,7 +395,8 @@ fn eq_cache_entries(&tup(int, uint, uint) a, &tup(int, uint, uint) b) ->
     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]();
@@ -405,7 +409,6 @@ fn mk_ctxt(session::session s, resolve::def_map dm, constr_table cs,
             node_types=ntt,
             items=amap,
             freevars=freevars,
-            fn_constrs=cs,
             tcache=tcache,
             rcache=mk_rcache(),
             short_names_cache=map::mk_hashmap[ty::t,
@@ -501,6 +504,9 @@ fn derive_flags_sig(&ctxt cx, &mutable bool has_params,
                 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,
@@ -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_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));
 }
 
@@ -1300,6 +1310,33 @@ fn hash_subty(uint id, &t subty) -> uint {
         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); }
@@ -1371,6 +1408,13 @@ fn hash_fn(uint id, &arg[] args, &t rty) -> uint {
             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;
+        }
     }
 }
 
@@ -1392,8 +1436,8 @@ fn hash_type_info(&sty st, &option::t[str] cname_opt) -> uint {
 // 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) {
@@ -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,
-              &(@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;
     }
@@ -2053,6 +2097,76 @@ fn struct_cmp(@ctxt cx, t expected, t actual) -> result {
         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] {
@@ -2109,8 +2223,8 @@ fn unify_fn(&@ctxt cx, &ast::proto e_proto, &ast::proto a_proto,
                 &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) { }
@@ -2612,6 +2726,31 @@ fn unify_step(&@ctxt cx, &t expected, &t actual) -> result {
                     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) ->
@@ -2730,6 +2869,15 @@ fn type_err_to_str(&ty::type_err err) -> str {
                 + 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);
+        }
     }
 }
 
index b9ec14eef4472d9e8186aad7b5539674b293b5c0..4cae44ce142694bcdabd949041426c36aedd4218 100644 (file)
@@ -2,7 +2,6 @@
 import syntax::ast;
 import ast::mutability;
 import ast::local_def;
-import ast::path_to_str;
 import ast::respan;
 import ast::spanned;
 import syntax::walk;
@@ -47,6 +46,7 @@
 import std::option::from_maybe;
 import std::smallintmap;
 import middle::tstate::ann::ts_ann;
+import syntax::print::pprust::*;
 
 export check_crate;
 
@@ -396,6 +396,13 @@ fn instantiate(&ty::ctxt tcx, &span sp, &ty_getter getter,
             }
             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 */ }
@@ -2519,8 +2526,8 @@ fn get_obj_info(&@crate_ctxt ccx) -> option::t[obj_info] {
     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,
@@ -2528,9 +2535,9 @@ fn ast_constr_to_constr(ty::ctxt tcx, &@ast::constr c)
         }
         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");
         }
     }
 }
index 745aa4e1fcdeab94136a976dd149874ae629f0e9..e2b2e53df07ed1947c615ae88846e970df857e1c 100644 (file)
@@ -444,7 +444,7 @@ fn ty_mach_to_str(ty_mach tm) -> str {
     ty_obj(ty_method[]);
     ty_path(path, node_id);
     ty_type;
-    ty_constr(@ty, (@constr)[]);
+    ty_constr(@ty, (@ty_constr)[]);
     ty_mac(mac);
 }
 
@@ -459,16 +459,26 @@ fn ty_mach_to_str(ty_mach tm) -> str {
 */
 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,
@@ -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:
 // mode: rust
index a4921b46bcad140669bbe050d9a25401ae3261b3..a12a7da4aeffb9242fe62b59bbbb43448d935307 100644 (file)
@@ -35,7 +35,7 @@ fn (&pat_ p, ast_fold) -> pat_                    fold_pat,
         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,
@@ -473,7 +473,7 @@ fn noop_fold_ty(&ty_ t, ast_fold fld) -> ty_ {
 }
 
 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
@@ -664,7 +664,8 @@ fn f_expr(&ast_fold_precursor afp, ast_fold f, &@expr x) -> @expr {
     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 {
index 59dbf72f7c501470f62954d1b952d205506a3691..724fcd75386bbb81d30a16bd0371b2aa1d8ac281 100644 (file)
@@ -14,6 +14,8 @@
 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; }
 
@@ -22,9 +24,9 @@
 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;
@@ -51,7 +53,7 @@ fn next_node_id(&parse_sess sess) -> ast::node_id {
         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;
     };
 
@@ -116,7 +118,7 @@ fn get_str(token::str_num i) -> str {
         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; }
     }
 
@@ -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));
 }
 
@@ -261,7 +263,9 @@ fn parse_fn_input_ty(&parser p) -> ast::ty_arg {
     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) {
@@ -275,7 +279,7 @@ fn parse_fn_input_ty(&parser p) -> ast::ty_arg {
             }
         }
     } 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 {
@@ -336,6 +340,20 @@ fn ident_index(&parser p, &ast::arg[] args, &ast::ident i) -> uint {
     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;
@@ -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 =
         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();
@@ -413,7 +427,7 @@ fn parse_ty_postfix(@ast::ty orig_t, &parser p) -> @ast::ty {
             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,
@@ -432,10 +446,11 @@ fn parse_ty_postfix(@ast::ty orig_t, &parser p) -> @ast::ty {
 
         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 {
@@ -528,7 +543,15 @@ fn parse_ty(&parser p) -> @ast::ty {
             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);
@@ -559,7 +582,7 @@ fn parse_ty(&parser p) -> @ast::ty {
         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 {
@@ -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,
                      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);
@@ -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_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);
index caeba63ffd5bb6d2d4c9d41e3a73351ea9ce6eea..6d79acd64a7cd744c1c2fd51bcd217bb72dd8c31 100644 (file)
@@ -332,7 +332,7 @@ fn print_field(&ps s, &ast::ty_field f) {
             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);
@@ -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
 // 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);
     }
@@ -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 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;
@@ -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:
 // mode: rust
index 83bf548efeeb5e3ff1d38b1c6721c46b6683d860..afb965bb4960d9317ee585e3251b52e50fd7c2aa 100644 (file)
@@ -30,7 +30,9 @@
          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);
 
@@ -47,7 +49,7 @@ fn default_visitor[E]() -> visitor[E] {
              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](_, _, _, _, _, _, _));
 }
 
@@ -160,7 +162,8 @@ fn visit_ty[E](&@ty t, &E e, &vt[E] v) {
         }
         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)) {
@@ -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); }
         }
         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
 
 }
@@ -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) {
     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);
 }
 
index c1fb0798c0e285955d8534467f697c03dd685063..da76e7822ae147868b8af05d30f09663a4f36b6a 100644 (file)
@@ -9,6 +9,8 @@
 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;
@@ -46,7 +48,7 @@ fn fn_input_to_str(&ctxt cx, &rec(middle::ty::mode mode, t ty) input) ->
     }
     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"; }
@@ -154,21 +156,27 @@ fn ty_to_short_str(&ctxt cx, t typ) -> str {
     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;
diff --git a/src/test/compile-fail/constrained-type-missing-check.rs b/src/test/compile-fail/constrained-type-missing-check.rs
new file mode 100644 (file)
index 0000000..036d41a
--- /dev/null
@@ -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;
+}
index d15e229a67a1cfa05840b75a3339da5314722dc6..d3003e8f540b03e230797b94afc5024869783279 100644 (file)
@@ -1,10 +1,6 @@
 // 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();
@@ -12,8 +8,7 @@
 
 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);