diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index b24dedffdd0..7e360e7f0e1 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -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 pretty_print_input(session::session sess, ast::crate_cfg cfg, 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, _)); diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index 2804c530240..6f55f6d097c 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -7,6 +7,7 @@ import std::option; 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 parse_path(@pstate st, str_def sd) -> ast::path { 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: +// diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 3b3ce6b3866..e239d678174 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -8,7 +8,7 @@ import std::int; 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)); diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index a0fbc6a7061..0a3d61b165a 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -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 middle::ty::constr_table; 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; 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 @@ type def_map = hashmap[node_id, def]; 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 @@ tag dir { inside; outside; } 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 resolve_names(&@env e, &@ast::crate c) { 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; diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 6df2f3ff016..d6303b15fe6 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -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 @@ to represent predicate *arguments* however. This type 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 @@ type fn_info = rec(constr_map constrs, // 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 match_args(&fn_ctxt fcx, &pred_desc[] occs, &(@constr_arg_use)[] occ) -> 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 diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs index d0d4f9bde8f..e7afe85f34f 100644 --- a/src/comp/middle/tstate/bitvectors.rs +++ b/src/comp/middle/tstate/bitvectors.rs @@ -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; @@ -47,11 +26,12 @@ import tstate::ann::clear_in_prestate; 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 relax_precond_block(&fn_ctxt fcx, node_id i, &block 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"; 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)); } // diff --git a/src/comp/middle/tstate/ck.rs b/src/comp/middle/tstate/ck.rs index 84e5232a349..503fbf8fc12 100644 --- a/src/comp/middle/tstate/ck.rs +++ b/src/comp/middle/tstate/ck.rs @@ -49,10 +49,9 @@ import states::find_pre_post_state_fn; 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) { diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index fb2d342f922..5005ad5132b 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -14,12 +14,11 @@ import util::common::new_def_hash; 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, diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 14067f7d01b..8f802db30bd 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -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 find_pre_post_expr(&fn_ctxt fcx, @expr e) { 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)) { diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index b8cee2c6715..c806493bdea 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -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 = diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 30c04a74922..138b98b7570 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -13,19 +13,15 @@ import std::option::some; 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 arg; 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_bot; export mk_box; export mk_chan; export mk_char; +export mk_constr; export mk_ctxt; export mk_float; export mk_fn; @@ -123,6 +121,7 @@ export ty_bot; export ty_box; export ty_chan; export ty_char; +export ty_constr; export ty_float; export ty_fn; export ty_fn_abi; @@ -151,6 +150,7 @@ export ty_var_id; 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; @@ -193,9 +193,9 @@ type method = 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); @@ -212,7 +212,7 @@ type ctxt = 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 @@ tag sty { 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 @@ tag sty { 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 @@ tag type_err { terr_obj_meths(ast::ident, ast::ident); terr_arg_count; terr_mode_mismatch(mode, mode); + terr_constr_len(uint, uint); + terr_constr_mismatch(@type_constr, @type_constr); } type ty_param_count_and_ty = tup(uint, t); @@ -392,7 +395,8 @@ fn mk_rcache() -> creader_cache { 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 mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t { derive_flags_t(cx, has_params, has_vars, tt); } } + case (ty_constr(?tt, _)) { + derive_flags_t(cx, has_params, has_vars, tt); + } } ret rec(struct=st, cname=cname, @@ -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_type_structure(&sty st) -> 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_type_structure(&sty st) -> 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_ty(&t typ) -> uint { ret typ; } // 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 @@ mod unify { 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 @@ mod unify { &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 @@ mod unify { 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); + } } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index b9ec14eef44..4cae44ce142 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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::some; 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 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)); } + 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"); } } } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 745aa4e1fcd..e2b2e53df07 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -444,7 +444,7 @@ tag ty_ { 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 @@ declarations, and ident for uses. */ 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 diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index a4921b46bca..a12a7da4aef 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -35,7 +35,7 @@ type ast_fold_precursor = 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 make_fold(&ast_fold_precursor afp) -> ast_fold { 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 { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 59dbf72f7c5..724fcd75386 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -14,6 +14,8 @@ import ex=ext::base; 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 file_type { CRATE_FILE; SOURCE_FILE; } 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 @@ type parser = 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 new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr, 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_ty_fn(ast::proto proto, &parser p, uint lo) -> ast::ty_ { 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_ty_fn(ast::proto proto, &parser p, uint lo) -> ast::ty_ { } } } 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_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(); 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); diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index caeba63ffd5..6d79acd64a7 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -332,7 +332,7 @@ fn print_type(&ps s, &ast::ty ty) { 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 diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 83bf548efee..afb965bb496 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -30,7 +30,9 @@ type visitor[E] = 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); } diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs index c1fb0798c0e..da76e7822ae 100644 --- a/src/comp/util/ppaux.rs +++ b/src/comp/util/ppaux.rs @@ -9,6 +9,8 @@ import middle::ty::*; 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 ty_to_str(&ctxt cx, &t typ) -> str { } 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 index 00000000000..036d41ad5d4 --- /dev/null +++ b/src/test/compile-fail/constrained-type-missing-check.rs @@ -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; +} diff --git a/src/test/run-pass/constrained-type.rs b/src/test/run-pass/constrained-type.rs index d15e229a67a..d3003e8f540 100644 --- a/src/test/run-pass/constrained-type.rs +++ b/src/test/run-pass/constrained-type.rs @@ -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 @@ tag list { 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);