diff --git a/mk/stage3.mk b/mk/stage3.mk index 70d3f26d309..d8604ed999e 100644 --- a/mk/stage3.mk +++ b/mk/stage3.mk @@ -1,13 +1,8 @@ -stage3/std.o: $(STDLIB_CRATE) $(STDLIB_INPUTS) \ +stage3/$(CFG_STDLIB): $(STDLIB_CRATE) $(STDLIB_INPUTS) \ stage2/rustc$(X) stage2/$(CFG_STDLIB) stage2/intrinsics.bc \ $(LREQ) $(MKFILES) - @$(call E, compile: $@) - $(STAGE2) -c --shared -o $@ $< - -stage3/$(CFG_STDLIB): stage2/std.o stage2/glue.o - @$(call E, link: $@) - $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o $(CFG_GCCISH_LINK_FLAGS) -o \ - $@ $< -Lstage2 -Lrt -lrustrt + @$(call E, compile_and_link: $@) + $(STAGE2) --shared -o $@ $< stage3/librustc.o: $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ2) @$(call E, compile: $@) diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs index 79039cb55d4..d79ff61748c 100644 --- a/src/comp/back/abi.rs +++ b/src/comp/back/abi.rs @@ -104,7 +104,7 @@ const int closure_elt_bindings = 2; const int closure_elt_ty_params = 3; -const uint ivec_default_length = 8u; +const uint ivec_default_length = 4u; const uint ivec_elt_len = 0u; diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index bb20d79d7c9..c986842e9ae 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -209,7 +209,7 @@ mod write { * * There are a few issues to handle: * - * - Linkers operate on a flat namespace, so we have to flatten names. + * - Linnkers operate on a flat namespace, so we have to flatten names. * We do this using the C++ namespace-mangling technique. Foo::bar * symbols and such. * @@ -221,7 +221,7 @@ mod write { * symbols in the same process before you're even hitting birthday-paradox * collision probability. * - * - Symbols in dirrerent crates but with same names "within" the crate need + * - Symbols in different crates but with same names "within" the crate need * to get different linkage-names. * * So here is what we do: @@ -229,7 +229,7 @@ mod write { * - Separate the meta tags into two sets: exported and local. Only work with * the exported ones when considering linkage. * - * - Consider two exported tags as special (and madatory): name and vers. + * - Consider two exported tags as special (and mandatory): name and vers. * Every crate gets them; if it doesn't name them explicitly we infer them * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS. * diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 9aef46058ee..e0a6d28f2b7 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -81,10 +81,10 @@ fn compile_input(session::session sess, eval::env env, str input, auto crate = time(time_passes, "parsing", bind parse_input(sess, p, input)); if (sess.get_opts().output_type == link::output_type_none) { ret; } - auto def_map = + auto d = time(time_passes, "resolution", bind resolve::resolve_crate(sess, crate)); - auto ty_cx = ty::mk_ctxt(sess, def_map); + auto ty_cx = ty::mk_ctxt(sess, d._0, d._1); time[()](time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate)); if (sess.get_opts().run_typestate) { @@ -92,7 +92,7 @@ fn compile_input(session::session sess, eval::env env, str input, bind middle::tstate::ck::check_crate(ty_cx, crate)); } time(time_passes, "alias checking", - bind middle::alias::check_crate(@ty_cx, def_map, crate)); + bind middle::alias::check_crate(@ty_cx, crate)); auto llmod = time[llvm::llvm::ModuleRef](time_passes, "translation", bind trans::trans_crate(sess, crate, @@ -109,8 +109,8 @@ fn pretty_print_input(session::session sess, eval::env env, str input, auto mode; alt (ppm) { case (ppm_typed) { - auto def_map = resolve::resolve_crate(sess, crate); - auto ty_cx = ty::mk_ctxt(sess, def_map); + auto d = resolve::resolve_crate(sess, crate); + auto ty_cx = ty::mk_ctxt(sess, d._0, d._1); typeck::check_crate(ty_cx, crate); mode = ppaux::mo_typed(ty_cx); } @@ -399,37 +399,34 @@ fn main(vec[str] args) { let str prog = "gcc"; // The invocations of gcc share some flags across platforms - let vec[str] common_cflags = - ["-fno-strict-aliasing", "-fPIC", "-Wall", "-fno-rtti", - "-fno-exceptions", "-g"]; - let vec[str] common_libs = - [stage, "-Lrustllvm", "-Lrt", "-lrustrt", "-lrustllvm", "-lstd", - "-lm"]; + let vec[str] common_args = [stage, "-Lrt", "-lrustrt", + "-fno-strict-aliasing", "-fPIC", "-Wall", + "-fno-rtti", "-fno-exceptions", "-g", glu, "-o", + saved_out_filename, saved_out_filename + ".o"]; + + auto shared_cmd; + alt (sess.get_targ_cfg().os) { case (session::os_win32) { - gcc_args = - common_cflags + - ["-march=i686", "-O2", glu, main, "-o", - saved_out_filename, saved_out_filename + ".o"] + - common_libs; + shared_cmd = "-shared"; + gcc_args = common_args + ["-march=i686", "-O2"]; } case (session::os_macos) { - gcc_args = - common_cflags + - ["-arch i386", "-O0", "-m32", glu, main, "-o", - saved_out_filename, saved_out_filename + ".o"] + - common_libs; + shared_cmd = "-dynamiclib"; + gcc_args = common_args + ["-arch i386", "-O0", "-m32"]; } case (session::os_linux) { - gcc_args = - common_cflags + - ["-march=i686", "-O2", "-m32", glu, main, "-o", - saved_out_filename, saved_out_filename + ".o"] + - common_libs; + shared_cmd = "-shared"; + gcc_args = common_args + ["-march=i686", "-O2", "-m32"]; } } - // We run 'gcc' here + if (sopts.shared) { + gcc_args += [shared_cmd]; + } else { + gcc_args += ["-Lrustllvm", "-lrustllvm", "-lstd", "-lm", main]; + } + // We run 'gcc' here run::run_program(prog, gcc_args); // Clean up on Darwin diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 6a2f4d986ff..b66c286f325 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -359,19 +359,17 @@ tag constr_arg_general_[T] { carg_base; carg_ident(T); carg_lit(@lit); } type constr_arg = constr_arg_general[uint]; -type constr_arg_use = constr_arg_general[ident]; - type constr_arg_general[T] = spanned[constr_arg_general_[T]]; +type constr_ = rec(path path, + vec[@constr_arg_general[uint]] args, + ann ann); -// The ann field is there so that using the def_map in the type -// context, we can get the def_id for the path. -type constr_general[T] = - rec(path path, vec[@constr_arg_general[T]] args, ann ann); +type constr = spanned[constr_]; -type constr = spanned[constr_general[uint]]; - -type constr_use = spanned[constr_general[ident]]; +/* The parser generates ast::constrs; resolve generates + a mapping from each function to a list of ty::constr_defs, + corresponding to these. */ type arg = rec(mode mode, @ty ty, ident ident, def_id id); diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs index 0270717edd9..98004bf6961 100644 --- a/src/comp/front/creader.rs +++ b/src/comp/front/creader.rs @@ -78,8 +78,8 @@ fn parse_ty_or_bang(@pstate st, str_def sd) -> ty_or_bang { } } -fn parse_constrs(@pstate st, str_def sd) -> vec[@ast::constr] { - let vec[@ast::constr] res = []; +fn parse_constrs(@pstate st, str_def sd) -> vec[@ty::constr_def] { + let vec[@ty::constr_def] res = []; alt (peek(st) as char) { case (':') { do { @@ -92,7 +92,7 @@ fn parse_constrs(@pstate st, str_def sd) -> vec[@ast::constr] { ret res; } -fn parse_constr(@pstate st, str_def sd) -> @ast::constr { +fn parse_constr(@pstate st, str_def sd) -> @ty::constr_def { st.tcx.sess.unimpl("Reading constraints " + " isn't implemented"); /* let vec[@ast::constr_arg] args = []; @@ -318,7 +318,7 @@ fn parse_hex(@pstate st) -> uint { } fn parse_ty_fn(@pstate st, str_def sd) -> - tup(vec[ty::arg], ty::t, ast::controlflow, vec[@ast::constr]) { + tup(vec[ty::arg], ty::t, ast::controlflow, vec[@ty::constr_def]) { assert (next(st) as char == '['); let vec[ty::arg] inputs = []; while (peek(st) as char != ']') { diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 72eda8ca309..88d8516043b 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -5,6 +5,9 @@ import std::str; import std::option; import std::option::some; import std::option::none; +import std::either; +import std::either::left; +import std::either::right; import std::map::hashmap; import driver::session; import util::common; @@ -816,14 +819,9 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { hi = es.span.hi; ex = ast::expr_bind(e, es.node, p.get_ann()); } else if (p.peek() == token::POUND) { - p.bump(); - auto pth = parse_path(p); - auto es = - parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), - parse_expr, p); - hi = es.span.hi; - auto ext_span = rec(lo=lo, hi=hi); - ex = expand_syntax_ext(p, ext_span, pth, es.node, none); + auto ex_ext = parse_syntax_ext(p); + lo = ex_ext.span.lo; + ex = ex_ext.node; } else if (eat_word(p, "fail")) { auto msg; alt (p.peek()) { @@ -917,6 +915,21 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { ret @spanned(lo, hi, ex); } +fn parse_syntax_ext(&parser p) -> @ast::expr { + auto lo = p.get_lo_pos(); + expect(p, token::POUND); + ret parse_syntax_ext_inner(p, lo); +} + +fn parse_syntax_ext_inner(&parser p, uint lo) -> @ast::expr { + auto pth = parse_path(p); + auto es = parse_seq(token::LPAREN, token::RPAREN, + some(token::COMMA), parse_expr, p); + auto hi = es.span.hi; + auto ext_span = rec(lo=lo, hi=hi); + auto ex = expand_syntax_ext(p, ext_span, pth, es.node, none); + ret @spanned(lo, hi, ex); +} /* * FIXME: This is a crude approximation of the syntax-extension system, @@ -1423,7 +1436,22 @@ fn parse_source_stmt(&parser p) -> @ast::stmt { auto hi = p.get_span(); ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_ann())); } else { - alt (parse_item(p, [])) { + + auto item_attrs; + alt (parse_attrs_or_ext(p)) { + case (none) { + item_attrs = []; + } + case (some(left(?attrs))) { + item_attrs = attrs; + } + case (some(right(?ext))) { + ret @spanned(lo, ext.span.hi, + ast::stmt_expr(ext, p.get_ann())); + } + } + + alt (parse_item(p, item_attrs)) { case (got_item(?i)) { auto hi = i.span.hi; auto decl = @spanned(lo, hi, ast::decl_item(i)); @@ -1936,6 +1964,26 @@ fn parse_item(&parser p, vec[ast::attribute] attrs) -> parsed_item { } else { ret no_item; } } +// A type to distingush between the parsing of item attributes or syntax +// extensions, which both begin with token.POUND +type attr_or_ext = option::t[either::t[vec[ast::attribute], + @ast::expr]]; + +fn parse_attrs_or_ext(&parser p) -> attr_or_ext { + if (p.peek() == token::POUND) { + auto lo = p.get_lo_pos(); + p.bump(); + if (p.peek() == token::LBRACKET) { + auto first_attr = parse_attribute_inner(p, lo); + ret some(left([first_attr] + parse_attributes(p))); + } else { + ret some(right(parse_syntax_ext_inner(p, lo))); + } + } else { + ret none; + } +} + fn parse_attributes(&parser p) -> vec[ast::attribute] { let vec[ast::attribute] attrs = []; while (p.peek() == token::POUND) { attrs += [parse_attribute(p)]; } @@ -1945,6 +1993,10 @@ fn parse_attributes(&parser p) -> vec[ast::attribute] { fn parse_attribute(&parser p) -> ast::attribute { auto lo = p.get_lo_pos(); expect(p, token::POUND); + ret parse_attribute_inner(p, lo); +} + +fn parse_attribute_inner(&parser p, uint lo) -> ast::attribute { expect(p, token::LBRACKET); auto meta_item = parse_meta_item(p); expect(p, token::RBRACKET); @@ -2181,13 +2233,7 @@ fn parse_crate_directive(&parser p) -> ast::crate_directive { auto hi = p.get_hi_pos(); expect(p, token::RBRACE); ret spanned(lo, hi, ast::cdir_let(id, x, v)); - } else if (is_word(p, "use")) { - auto vi = parse_view_item(p); - ret spanned(lo, vi.span.hi, ast::cdir_view_item(vi)); - } else if (is_word(p, "import")) { - auto vi = parse_view_item(p); - ret spanned(lo, vi.span.hi, ast::cdir_view_item(vi)); - } else if (is_word(p, "export")) { + } else if (is_view_item(p)) { auto vi = parse_view_item(p); ret spanned(lo, vi.span.hi, ast::cdir_view_item(vi)); } else { diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index d9ef386de62..57cb33b8af6 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -35,14 +35,11 @@ tag local_info { arg(ast::mode); objfield(ast::mutability); } type ctx = rec(@ty::ctxt tcx, - resolve::def_map dm, std::map::hashmap[def_num, local_info] local_map); -fn check_crate(@ty::ctxt tcx, resolve::def_map dm, &@ast::crate crate) { +fn check_crate(@ty::ctxt tcx, &@ast::crate crate) { auto cx = @rec(tcx=tcx, - dm=dm, - // Stores information about object fields and function // arguments that's otherwise not easily available. local_map=util::common::new_int_hash()); @@ -77,12 +74,18 @@ fn visit_item(@ctx cx, &@ast::item i, &scope sc, &vt[scope] v) { } fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) { - auto handled = false; + auto handled = true; alt (ex.node) { - case (ast::expr_call(?f, ?args, _)) { check_call(*cx, f, args, sc); } + case (ast::expr_call(?f, ?args, _)) { + check_call(*cx, f, args, sc); + handled = false; + } + case (ast::expr_be(?cl, _)) { + check_tail_call(*cx, cl); + visit::visit_expr(cl, sc, v); + } case (ast::expr_alt(?input, ?arms, _)) { check_alt(*cx, input, arms, sc, v); - handled = true; } case (ast::expr_put(?val, _)) { alt (val) { @@ -97,32 +100,27 @@ fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) { } case (_) { } } - handled = true; } case (ast::expr_for_each(?decl, ?call, ?block, _)) { check_for_each(*cx, decl, call, block, sc, v); - handled = true; } case (ast::expr_for(?decl, ?seq, ?block, _)) { check_for(*cx, decl, seq, block, sc, v); - handled = true; } case (ast::expr_path(?pt, ?ann)) { check_var(*cx, ex, pt, ann, false, sc); + handled = false; } case (ast::expr_move(?dest, ?src, _)) { check_assign(cx, dest, src, sc, v); - handled = true; } case (ast::expr_assign(?dest, ?src, _)) { check_assign(cx, dest, src, sc, v); - handled = true; } case (ast::expr_assign_op(_, ?dest, ?src, _)) { check_assign(cx, dest, src, sc, v); - handled = true; } - case (_) { } + case (_) { handled = false; } } if (!handled) { visit::visit_expr(ex, sc, v); } } @@ -130,11 +128,8 @@ fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) { fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) -> rec(vec[def_num] root_vars, vec[ty::t] unsafe_ts) { auto fty = ty::expr_ty(*cx.tcx, f); - auto arg_ts = - alt (ty::struct(*cx.tcx, fty)) { - case (ty::ty_fn(_, ?args, _, _, _)) { args } - case (ty::ty_native_fn(_, ?args, _)) { args } - }; + auto arg_ts = fty_args(cx, fty); + let vec[def_num] roots = []; let vec[tup(uint, def_num)] mut_roots = []; let vec[ty::t] unsafe_ts = []; @@ -175,11 +170,11 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) -> if (vec::len(unsafe_ts) > 0u) { alt (f.node) { case (ast::expr_path(_, ?ann)) { - if (def_is_local(cx.dm.get(ann.id))) { - cx.tcx.sess.span_err(f.span, - #fmt("function may alias with \ - argument %u, which is not immutably rooted", - unsafe_t_offsets.(0))); + if (def_is_local(cx.tcx.def_map.get(ann.id), true)) { + cx.tcx.sess.span_err + (f.span, #fmt("function may alias with argument \ + %u, which is not immutably rooted", + unsafe_t_offsets.(0))); } } case (_) { } @@ -221,8 +216,47 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) -> ret rec(root_vars=roots, unsafe_ts=unsafe_ts); } -fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, &scope sc, - &vt[scope] v) { +fn check_tail_call(&ctx cx, &@ast::expr call) { + auto args; + auto f = alt (call.node) { + case (ast::expr_call(?f, ?args_, _)) { args = args_; f } + }; + auto i = 0u; + for (ty::arg arg_t in fty_args(cx, ty::expr_ty(*cx.tcx, f))) { + if (arg_t.mode != ty::mo_val) { + auto mut_a = arg_t.mode == ty::mo_alias(true); + auto ok = true; + alt (args.(i).node) { + case (ast::expr_path(_, ?ann)) { + auto def = cx.tcx.def_map.get(ann.id); + auto dnum = ast::def_id_of_def(def)._1; + alt (cx.local_map.find(dnum)) { + case (some(arg(ast::alias(?mut)))) { + if (mut_a && !mut) { + cx.tcx.sess.span_warn + (args.(i).span, "passing an immutable \ + alias by mutable alias"); + } + } + case (_) { + ok = !def_is_local(def, false); + } + } + } + case (_) { ok = false; } + } + if (!ok) { + cx.tcx.sess.span_warn + (args.(i).span, "can not pass a local value by alias to \ + a tail call"); + } + } + i += 1u; + } +} + +fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, + &scope sc, &vt[scope] v) { visit::visit_expr(input, sc, v); auto root = expr_root(cx, input, true); auto roots = @@ -316,8 +350,8 @@ fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq, &ast::block block, fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign, &scope sc) { - auto def = cx.dm.get(ann.id); - if (!def_is_local(def)) { ret; } + auto def = cx.tcx.def_map.get(ann.id); + if (!def_is_local(def, true)) { ret; } auto my_defnum = ast::def_id_of_def(def)._1; auto var_t = ty::expr_ty(*cx.tcx, ex); for (restrict r in sc) { @@ -342,7 +376,7 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, &scope sc, visit_expr(cx, src, sc, v); alt (dest.node) { case (ast::expr_path(?p, ?ann)) { - auto dnum = ast::def_id_of_def(cx.dm.get(ann.id))._1; + auto dnum = ast::def_id_of_def(cx.tcx.def_map.get(ann.id))._1; if (is_immutable_alias(cx, sc, dnum)) { cx.tcx.sess.span_err(dest.span, "assigning to immutable alias"); @@ -529,7 +563,7 @@ fn inner_mut(&vec[deref] ds) -> option::t[ty::t] { fn path_def_id(&ctx cx, &@ast::expr ex) -> option::t[ast::def_id] { alt (ex.node) { case (ast::expr_path(_, ?ann)) { - ret some(ast::def_id_of_def(cx.dm.get(ann.id))); + ret some(ast::def_id_of_def(cx.tcx.def_map.get(ann.id))); } case (_) { ret none; } } @@ -594,15 +628,23 @@ fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut) -> ret helper(*cx.tcx, needle, haystack, mut); } -fn def_is_local(&ast::def d) -> bool { +fn def_is_local(&ast::def d, bool objfields_count) -> bool { ret alt (d) { - case (ast::def_local(_)) { true } - case (ast::def_arg(_)) { true } - case (ast::def_obj_field(_)) { true } - case (ast::def_binding(_)) { true } - case (_) { false } - }; + case (ast::def_local(_)) { true } + case (ast::def_arg(_)) { true } + case (ast::def_obj_field(_)) { objfields_count } + case (ast::def_binding(_)) { true } + case (_) { false } + }; } + +fn fty_args(&ctx cx, ty::t fty) -> vec[ty::arg] { + ret alt (ty::struct(*cx.tcx, fty)) { + case (ty::ty_fn(_, ?args, _, _, _)) { args } + case (ty::ty_native_fn(_, ?args, _)) { args } + }; +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs index b64bab69eaf..dc2acfa6ca7 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -221,8 +221,7 @@ mod Encode { case (ast::native_abi_cdecl) { w.write_char('c'); } case (ast::native_abi_llvm) { w.write_char('l'); } } - let vec[@constr] res_constrs = []; - enc_ty_fn(w, cx, args, out, ast::return, res_constrs); + enc_ty_fn(w, cx, args, out, ast::return, []); } case (ty::ty_obj(?methods)) { w.write_str("O["); @@ -253,7 +252,7 @@ mod Encode { } } fn enc_ty_fn(&io::writer w, &@ctxt cx, &vec[ty::arg] args, &ty::t out, - &ast::controlflow cf, &vec[@ast::constr] constrs) { + &ast::controlflow cf, &vec[@ty::constr_def] constrs) { w.write_char('['); for (ty::arg arg in args) { alt (arg.mode) { @@ -271,7 +270,7 @@ mod Encode { case (_) { enc_ty(w, cx, out); } } auto colon = true; - for (@ast::constr c in constrs) { + for (@ty::constr_def c in constrs) { if (colon) { w.write_char(':'); colon = false; @@ -279,7 +278,7 @@ mod Encode { enc_constr(w, cx, c); } } - fn enc_constr(&io::writer w, &@ctxt cx, &@ast::constr c) { + fn enc_constr(&io::writer w, &@ctxt cx, &@ty::constr_def c) { w.write_str(path_to_str(c.node.path)); w.write_char('('); // FIXME diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 1da8fa0d410..4d20216564c 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -11,7 +11,8 @@ import util::common::new_int_hash; import util::common::new_uint_hash; import util::common::new_str_hash; import util::common::span; -import middle::tstate::ann::ts_ann; +import util::common::respan; +import middle::ty::constr_table; import visit::vt; import std::map::hashmap; import std::list; @@ -111,6 +112,7 @@ type def_map = hashmap[uint, def]; type env = rec(crate_map crate_map, def_map def_map, + constr_table fn_constrs, hashmap[def_id, @ast::item] ast_map, hashmap[ast::def_num, import_state] imports, hashmap[ast::def_num, @indexed_mod] mod_map, @@ -118,17 +120,18 @@ type env = ext_hash ext_cache, session sess); - // Used to distinguish between lookups from outside and from inside modules, // since export restrictions should only be applied for the former. tag dir { inside; outside; } tag namespace { ns_value; ns_type; ns_module; } -fn resolve_crate(session sess, @ast::crate crate) -> def_map { +fn resolve_crate(session sess, @ast::crate crate) + -> tup(def_map, constr_table) { auto e = @rec(crate_map=new_uint_hash[ast::crate_num](), def_map=new_uint_hash[def](), + fn_constrs = new_def_hash[vec[ty::constr_def]](), ast_map=new_def_hash[@ast::item](), imports=new_int_hash[import_state](), mod_map=new_int_hash[@indexed_mod](), @@ -140,7 +143,7 @@ fn resolve_crate(session sess, @ast::crate crate) -> def_map { resolve_imports(*e); check_for_collisions(e, *crate); resolve_names(e, crate); - ret e.def_map; + ret tup(e.def_map, e.fn_constrs); } @@ -266,8 +269,9 @@ 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_fn=visit_fn_with_scope, - 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(c), @nil), visit::vtor(v)); fn walk_expr(@env e, &@ast::expr exp, &scopes sc, &vt[scopes] v) { @@ -282,12 +286,7 @@ fn resolve_names(&@env e, &@ast::crate c) { case (_) { } } } - fn walk_constr(@env e, &@ast::constr c, &scopes sc, &vt[scopes] v) { - auto new_def = - lookup_path_strict(*e, sc, c.span, c.node.path.node.idents, - ns_value); - e.def_map.insert(c.node.ann.id, new_def); - } + fn walk_ty(@env e, &@ast::ty t, &scopes sc, &vt[scopes] v) { visit::visit_ty(t, sc, v); alt (t.node) { @@ -300,6 +299,13 @@ fn resolve_names(&@env e, &@ast::crate c) { case (_) { } } } + + fn walk_constr(@env e, &@ast::constr c, &scopes sc, &vt[scopes] v) { + auto new_def = lookup_path_strict(*e, sc, c.span, + c.node.path.node.idents, ns_value); + e.def_map.insert(c.node.ann.id, new_def); + } + fn walk_arm(@env e, &ast::arm a, &scopes sc, &vt[scopes] v) { walk_pat(*e, sc, a.pat); visit_arm_with_scope(a, sc, v); @@ -338,11 +344,16 @@ fn visit_native_item_with_scope(&@ast::native_item ni, &scopes sc, visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v); } -fn visit_fn_with_scope(&ast::_fn f, &vec[ast::ty_param] tp, &span sp, +fn visit_fn_with_scope(&@env e, &ast::_fn f, &vec[ast::ty_param] tp, &span sp, &ident name, &def_id d_id, &ann a, &scopes sc, &vt[scopes] v) { - visit::visit_fn(f, tp, sp, name, d_id, a, cons(scope_fn(f.decl, tp), @sc), - v); + // here's where we need to set up the mapping + // for f's constrs in the table. + for (@ast::constr c in f.decl.constraints) { + resolve_constr(e, d_id, c, sc, v); + } + visit::visit_fn(f, tp, sp, name, d_id, a, + cons(scope_fn(f.decl, tp), @sc), v); } fn visit_block_with_scope(&ast::block b, &scopes sc, &vt[scopes] v) { @@ -389,6 +400,37 @@ fn follow_import(&env e, &scopes sc, vec[ident] path, &span sp) -> def { } } +fn resolve_constr(@env e, &def_id d_id, &@ast::constr c, &scopes sc, + &vt[scopes] v) { + let def new_def = lookup_path_strict(*e, sc, c.span, + c.node.path.node.idents, + ns_value); + alt (new_def) { + case (ast::def_fn(?pred_id)) { + 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, d_id, new_constr); + } + case (_) { + e.sess.span_err(c.span, "Non-predicate in constraint: " + + ty::path_to_str(c.node.path)); + } + } +} + +fn add_constr(&@env e, &def_id d_id, &ty::constr_def c) { + e.fn_constrs.insert(d_id, + alt (e.fn_constrs.find(d_id)) { + case (none) { + [c] + } + case (some(?cs)) { + cs + [c] + } + }); +} // Import resolution fn resolve_import(&env e, &@ast::view_item it, &scopes sc) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a01650dc1ac..7bde65f40d8 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -113,6 +113,7 @@ type stats = mutable uint n_null_glues, mutable uint n_real_glues); +// Crate context. Every crate we compile has one of these. type crate_ctxt = rec(session::session sess, ModuleRef llmod, @@ -120,6 +121,10 @@ type crate_ctxt = type_names tn, hashmap[str, ValueRef] externs, hashmap[str, ValueRef] intrinsics, + + // A mapping from the def_id of each item in this crate to the address + // of the first instruction of the item's definition in the executable + // we're generating. hashmap[ast::def_id, ValueRef] item_ids, hashmap[ast::def_id, @ast::item] items, hashmap[ast::def_id, @ast::native_item] native_items, @@ -1110,7 +1115,7 @@ fn trans_non_gc_free(&@block_ctxt cx, ValueRef v) -> result { fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt { if (cx.kind != NON_SCOPE_BLOCK) { ret cx; } alt (cx.parent) { - case (parent_some(?b)) { be find_scope_cx(b); } + case (parent_some(?b)) { ret find_scope_cx(b); } case (parent_none) { cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " + "called on parentless block_ctxt"); @@ -2369,7 +2374,7 @@ fn make_numerical_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, // Returns the length of an interior vector and a pointer to its first // element, in that order. -fn get_ivec_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) -> +fn get_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) -> tup(ValueRef, ValueRef, @block_ctxt) { auto llunitty = type_of_or_i8(bcx, unit_ty); auto stack_len = @@ -2450,7 +2455,7 @@ fn iter_structural_ty(&@block_ctxt cx, ValueRef v, &ty::t t, val_and_ty_fn f) ty::t t) -> result { ret f(cx, av, t); } - be iter_structural_ty_full(cx, v, v, t, bind adaptor_fn(f, _, _, _, _)); + ret iter_structural_ty_full(cx, v, v, t, bind adaptor_fn(f, _, _, _, _)); } fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, @@ -2481,11 +2486,13 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, auto rslt = size_of(bcx, unit_ty); auto unit_sz = rslt.val; bcx = rslt.bcx; - auto a_len_and_data = get_ivec_len_and_data(bcx, av, unit_ty); + + auto a_len_and_data = ivec::get_len_and_data(bcx, av, unit_ty); auto a_len = a_len_and_data._0; auto a_elem = a_len_and_data._1; bcx = a_len_and_data._2; - auto b_len_and_data = get_ivec_len_and_data(bcx, bv, unit_ty); + + auto b_len_and_data = ivec::get_len_and_data(bcx, bv, unit_ty); auto b_len = b_len_and_data._0; auto b_elem = b_len_and_data._1; bcx = b_len_and_data._2; @@ -2688,8 +2695,8 @@ fn iter_sequence_inner(&@block_ctxt cx, ValueRef src, ret f(cx, load_if_immediate(cx, p, elt_ty), elt_ty); } auto elt_sz = size_of(cx, elt_ty); - be iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val, - bind adaptor_fn(f, elt_ty, _, _, _)); + ret iter_sequence_raw(elt_sz.bcx, src, src, src_lim, elt_sz.val, + bind adaptor_fn(f, elt_ty, _, _, _)); } @@ -3209,209 +3216,292 @@ fn trans_vec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) -> } -// Returns a tuple consisting of a pointer to the newly-reserved space and a -// block context. Updates the length appropriately. -fn reserve_ivec_space(&@block_ctxt cx, TypeRef llunitty, ValueRef v, - ValueRef len_needed) -> result { - auto stack_len_ptr = - cx.build.InBoundsGEP(v, [C_int(0), C_uint(abi::ivec_elt_len)]); - auto stack_len = cx.build.Load(stack_len_ptr); - auto alen = - cx.build.Load(cx.build.InBoundsGEP(v, - [C_int(0), - C_uint(abi::ivec_elt_alen)])); - // There are four cases we have to consider: - // (1) On heap, no resize necessary. - // (2) On heap, need to resize. - // (3) On stack, no resize necessary. - // (4) On stack, need to spill to heap. - - auto maybe_on_heap = - cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0)); - auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap"); - auto on_stack_cx = new_sub_block_ctxt(cx, "on_stack"); - cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, on_stack_cx.llbb); - auto next_cx = new_sub_block_ctxt(cx, "next"); - // We're possibly on the heap, unless the vector is zero-length. - - auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]; - - auto stub_ptr = - maybe_on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty))); - auto heap_ptr = - { - auto m = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr, stub_p); - maybe_on_heap_cx.build.Load(m) +mod ivec { + // Returns the length of an interior vector and a pointer to its first + // element, in that order. + fn get_len_and_data(&@block_ctxt bcx, ValueRef v, ty::t unit_ty) -> + tup(ValueRef, ValueRef, @block_ctxt) { + auto llunitty = type_of_or_i8(bcx, unit_ty); + auto stack_len = + bcx.build.Load(bcx.build.InBoundsGEP(v, + [C_int(0), C_uint(abi::ivec_elt_len)])); + auto stack_elem = + bcx.build.InBoundsGEP(v, + [C_int(0), C_uint(abi::ivec_elt_elems), C_int(0)]); + auto on_heap = bcx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, + C_int(0)); + auto on_heap_cx = new_sub_block_ctxt(bcx, "on_heap"); + auto next_cx = new_sub_block_ctxt(bcx, "next"); + bcx.build.CondBr(on_heap, on_heap_cx.llbb, next_cx.llbb); + auto heap_stub = + on_heap_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty))); + auto heap_ptr = { + auto v = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]; + on_heap_cx.build.Load(on_heap_cx.build.InBoundsGEP(heap_stub, v)) }; - auto on_heap = - maybe_on_heap_cx.build.ICmp(lib::llvm::LLVMIntNE, heap_ptr, - C_null(val_ty(heap_ptr))); - auto on_heap_cx = new_sub_block_ctxt(cx, "on_heap"); - maybe_on_heap_cx.build.CondBr(on_heap, on_heap_cx.llbb, on_stack_cx.llbb); - // We're definitely on the heap. Check whether we need to resize. - auto heap_len_ptr = - on_heap_cx.build.InBoundsGEP(heap_ptr, - [C_int(0), - C_uint(abi::ivec_heap_elt_len)]); - auto heap_len = on_heap_cx.build.Load(heap_len_ptr); - auto new_heap_len = on_heap_cx.build.Add(heap_len, len_needed); - auto heap_len_unscaled = - on_heap_cx.build.UDiv(heap_len, llsize_of(llunitty)); - auto heap_no_resize_needed = - on_heap_cx.build.ICmp(lib::llvm::LLVMIntULE, new_heap_len, alen); - auto heap_no_resize_cx = new_sub_block_ctxt(cx, "heap_no_resize"); - auto heap_resize_cx = new_sub_block_ctxt(cx, "heap_resize"); - on_heap_cx.build.CondBr(heap_no_resize_needed, heap_no_resize_cx.llbb, - heap_resize_cx.llbb); - // Case (1): We're on the heap and don't need to resize. + // Check whether the heap pointer is null. If it is, the vector length + // is truly zero. - auto heap_data_no_resize = - heap_no_resize_cx.build.InBoundsGEP(heap_ptr, - [C_int(0), - C_uint(abi::ivec_heap_elt_elems), - heap_len_unscaled]); - heap_no_resize_cx.build.Store(new_heap_len, heap_len_ptr); - heap_no_resize_cx.build.Br(next_cx.llbb); - // Case (2): We're on the heap and need to resize. This path is rare, so - // we delegate to cold glue. + auto llstubty = T_ivec_heap(llunitty); + auto llheapptrty = struct_elt(llstubty, abi::ivec_heap_stub_elt_ptr); + auto heap_ptr_is_null = + on_heap_cx.build.ICmp(lib::llvm::LLVMIntEQ, heap_ptr, + C_null(T_ptr(llheapptrty))); + auto zero_len_cx = new_sub_block_ctxt(bcx, "zero_len"); + auto nonzero_len_cx = new_sub_block_ctxt(bcx, "nonzero_len"); + on_heap_cx.build.CondBr(heap_ptr_is_null, zero_len_cx.llbb, + nonzero_len_cx.llbb); + // Technically this context is unnecessary, but it makes this function + // clearer. - { - auto p = heap_resize_cx.build.PointerCast(v, T_ptr(T_opaque_ivec())); - heap_resize_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_resize, - [cx.fcx.lltaskptr, p, new_heap_len]); + auto zero_len = C_int(0); + auto zero_elem = C_null(T_ptr(llunitty)); + zero_len_cx.build.Br(next_cx.llbb); + // If we're here, then we actually have a heapified vector. + + auto heap_len = { + auto v = [C_int(0), C_uint(abi::ivec_heap_elt_len)]; + auto m = nonzero_len_cx.build.InBoundsGEP(heap_ptr, v); + nonzero_len_cx.build.Load(m) + }; + auto heap_elem = + nonzero_len_cx.build.InBoundsGEP(heap_ptr, + [C_int(0), C_uint(abi::ivec_heap_elt_elems), C_int(0)]); + nonzero_len_cx.build.Br(next_cx.llbb); + + // Now we can figure out the length of `v` and get a pointer to its + // first element. + + auto len = + next_cx.build.Phi(T_int(), + [stack_len, zero_len, heap_len], + [bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]); + auto elem = + next_cx.build.Phi(T_ptr(llunitty), + [stack_elem, zero_elem, heap_elem], + [bcx.llbb, zero_len_cx.llbb, nonzero_len_cx.llbb]); + ret tup(len, elem, next_cx); } - auto heap_ptr_resize = + // Returns a tuple consisting of a pointer to the newly-reserved space and + // a block context. Updates the length appropriately. + fn reserve_space(&@block_ctxt cx, TypeRef llunitty, ValueRef v, + ValueRef len_needed) -> result { + auto stack_len_ptr = + cx.build.InBoundsGEP(v, [C_int(0), C_uint(abi::ivec_elt_len)]); + auto stack_len = cx.build.Load(stack_len_ptr); + auto alen = + cx.build.Load(cx.build.InBoundsGEP(v, + [C_int(0), + C_uint(abi::ivec_elt_alen)])); + // There are four cases we have to consider: + // (1) On heap, no resize necessary. + // (2) On heap, need to resize. + // (3) On stack, no resize necessary. + // (4) On stack, need to spill to heap. + + auto maybe_on_heap = + cx.build.ICmp(lib::llvm::LLVMIntEQ, stack_len, C_int(0)); + auto maybe_on_heap_cx = new_sub_block_ctxt(cx, "maybe_on_heap"); + auto on_stack_cx = new_sub_block_ctxt(cx, "on_stack"); + cx.build.CondBr(maybe_on_heap, maybe_on_heap_cx.llbb, + on_stack_cx.llbb); + auto next_cx = new_sub_block_ctxt(cx, "next"); + // We're possibly on the heap, unless the vector is zero-length. + + auto stub_p = [C_int(0), C_uint(abi::ivec_heap_stub_elt_ptr)]; + + auto stub_ptr = maybe_on_heap_cx.build.PointerCast(v, + T_ptr(T_ivec_heap(llunitty))); + auto heap_ptr = + { + auto m = maybe_on_heap_cx.build.InBoundsGEP(stub_ptr, stub_p); + maybe_on_heap_cx.build.Load(m) + }; + auto on_heap = + maybe_on_heap_cx.build.ICmp(lib::llvm::LLVMIntNE, heap_ptr, + C_null(val_ty(heap_ptr))); + auto on_heap_cx = new_sub_block_ctxt(cx, "on_heap"); + maybe_on_heap_cx.build.CondBr(on_heap, on_heap_cx.llbb, + on_stack_cx.llbb); + + // We're definitely on the heap. Check whether we need to resize. + auto heap_len_ptr = + on_heap_cx.build.InBoundsGEP(heap_ptr, + [C_int(0), + C_uint(abi::ivec_heap_elt_len)]); + auto heap_len = on_heap_cx.build.Load(heap_len_ptr); + auto new_heap_len = on_heap_cx.build.Add(heap_len, len_needed); + auto heap_len_unscaled = + on_heap_cx.build.UDiv(heap_len, llsize_of(llunitty)); + auto heap_no_resize_needed = + on_heap_cx.build.ICmp(lib::llvm::LLVMIntULE, new_heap_len, alen); + auto heap_no_resize_cx = new_sub_block_ctxt(cx, "heap_no_resize"); + auto heap_resize_cx = new_sub_block_ctxt(cx, "heap_resize"); + on_heap_cx.build.CondBr(heap_no_resize_needed, heap_no_resize_cx.llbb, + heap_resize_cx.llbb); + // Case (1): We're on the heap and don't need to resize. + + auto heap_data_no_resize = + heap_no_resize_cx.build.InBoundsGEP(heap_ptr, + [C_int(0), + C_uint(abi::ivec_heap_elt_elems), + heap_len_unscaled]); + heap_no_resize_cx.build.Store(new_heap_len, heap_len_ptr); + heap_no_resize_cx.build.Br(next_cx.llbb); + + // Case (2): We're on the heap and need to resize. This path is rare, + // so we delegate to cold glue. + { + auto p = heap_resize_cx.build.PointerCast(v, + T_ptr(T_opaque_ivec())); + heap_resize_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_resize, + [cx.fcx.lltaskptr, p, new_heap_len]); + } + + auto heap_ptr_resize = { auto m = heap_resize_cx.build.InBoundsGEP(stub_ptr, stub_p); heap_resize_cx.build.Load(m) }; - auto heap_data_resize = - heap_resize_cx.build.InBoundsGEP(heap_ptr_resize, - [C_int(0), - C_uint(abi::ivec_heap_elt_elems), - heap_len_unscaled]); - heap_resize_cx.build.Br(next_cx.llbb); - // We're on the stack. Check whether we need to spill to the heap. + auto heap_data_resize = + heap_resize_cx.build.InBoundsGEP(heap_ptr_resize, + [C_int(0), + C_uint(abi::ivec_heap_elt_elems), + heap_len_unscaled]); + heap_resize_cx.build.Br(next_cx.llbb); - auto new_stack_len = on_stack_cx.build.Add(stack_len, len_needed); - auto stack_no_spill_needed = - on_stack_cx.build.ICmp(lib::llvm::LLVMIntULE, new_stack_len, alen); - auto stack_len_unscaled = - on_stack_cx.build.UDiv(stack_len, llsize_of(llunitty)); - auto stack_no_spill_cx = new_sub_block_ctxt(cx, "stack_no_spill"); - auto stack_spill_cx = new_sub_block_ctxt(cx, "stack_spill"); - on_stack_cx.build.CondBr(stack_no_spill_needed, stack_no_spill_cx.llbb, - stack_spill_cx.llbb); - // Case (3): We're on the stack and don't need to spill. + // We're on the stack. Check whether we need to spill to the heap. + auto new_stack_len = on_stack_cx.build.Add(stack_len, len_needed); + auto stack_no_spill_needed = + on_stack_cx.build.ICmp(lib::llvm::LLVMIntULE, new_stack_len, + alen); + auto stack_len_unscaled = + on_stack_cx.build.UDiv(stack_len, llsize_of(llunitty)); + auto stack_no_spill_cx = new_sub_block_ctxt(cx, "stack_no_spill"); + auto stack_spill_cx = new_sub_block_ctxt(cx, "stack_spill"); + on_stack_cx.build.CondBr(stack_no_spill_needed, + stack_no_spill_cx.llbb, + stack_spill_cx.llbb); - auto stack_data_no_spill = - stack_no_spill_cx.build.InBoundsGEP(v, - [C_int(0), - C_uint(abi::ivec_elt_elems), - stack_len_unscaled]); - stack_no_spill_cx.build.Store(new_stack_len, stack_len_ptr); - stack_no_spill_cx.build.Br(next_cx.llbb); - // Case (4): We're on the stack and need to spill. Like case (2), this - // path is rare, so we delegate to cold glue. + // Case (3): We're on the stack and don't need to spill. + auto stack_data_no_spill = + stack_no_spill_cx.build.InBoundsGEP(v, + [C_int(0), + C_uint(abi::ivec_elt_elems), + stack_len_unscaled]); + stack_no_spill_cx.build.Store(new_stack_len, stack_len_ptr); + stack_no_spill_cx.build.Br(next_cx.llbb); - { - auto p = stack_spill_cx.build.PointerCast(v, T_ptr(T_opaque_ivec())); - stack_spill_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_spill, - [cx.fcx.lltaskptr, p, new_stack_len]); - } - auto spill_stub = - stack_spill_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty))); - auto heap_ptr_spill = - stack_spill_cx.build.Load(stack_spill_cx.build.InBoundsGEP(spill_stub, - stub_p)); - auto heap_len_ptr_spill = - stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, - [C_int(0), - C_uint(abi::ivec_heap_elt_len)]); - auto heap_data_spill = - stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, - [C_int(0), - C_uint(abi::ivec_heap_elt_elems), - stack_len_unscaled]); - stack_spill_cx.build.Br(next_cx.llbb); - // Phi together the different data pointers to get the result. - - auto data_ptr = - next_cx.build.Phi(T_ptr(llunitty), - [heap_data_no_resize, heap_data_resize, - stack_data_no_spill, heap_data_spill], - [heap_no_resize_cx.llbb, heap_resize_cx.llbb, - stack_no_spill_cx.llbb, stack_spill_cx.llbb]); - ret res(next_cx, data_ptr); -} - -fn trans_ivec_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) -> - result { - auto unit_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t); - auto llunitty = type_of_or_i8(cx, unit_ty); - auto skip_null; - alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) { - case (ty::ty_istr) { skip_null = true; } - case (ty::ty_ivec(_)) { skip_null = false; } - case (_) { - cx.fcx.lcx.ccx.tcx.sess.bug("non-istr/ivec in trans_ivec_append"); + // Case (4): We're on the stack and need to spill. Like case (2), this + // path is rare, so we delegate to cold glue. + { + auto p = stack_spill_cx.build.PointerCast(v, + T_ptr(T_opaque_ivec())); + stack_spill_cx.build.Call(cx.fcx.lcx.ccx.upcalls.ivec_spill, + [cx.fcx.lltaskptr, p, new_stack_len]); } + + auto spill_stub = + stack_spill_cx.build.PointerCast(v, T_ptr(T_ivec_heap(llunitty))); + auto heap_ptr_spill = + stack_spill_cx.build.Load( + stack_spill_cx.build.InBoundsGEP(spill_stub, stub_p)); + auto heap_len_ptr_spill = + stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, + [C_int(0), C_uint(abi::ivec_heap_elt_len)]); + auto heap_data_spill = + stack_spill_cx.build.InBoundsGEP(heap_ptr_spill, + [C_int(0), + C_uint(abi::ivec_heap_elt_elems), + stack_len_unscaled]); + stack_spill_cx.build.Br(next_cx.llbb); + + // Phi together the different data pointers to get the result. + auto data_ptr = + next_cx.build.Phi(T_ptr(llunitty), + [heap_data_no_resize, heap_data_resize, + stack_data_no_spill, heap_data_spill], + [heap_no_resize_cx.llbb, heap_resize_cx.llbb, + stack_no_spill_cx.llbb, stack_spill_cx.llbb]); + ret res(next_cx, data_ptr); } - // Gather the various type descriptors we'll need. - auto rslt = get_tydesc(cx, t, false, none); - auto vec_tydesc = rslt.val; - auto bcx = rslt.bcx; - rslt = get_tydesc(bcx, unit_ty, false, none); - auto unit_tydesc = rslt.val; - bcx = rslt.bcx; - lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, none); - lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none); - lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, none); - auto rhs_len_and_data = get_ivec_len_and_data(bcx, rhs, unit_ty); - auto rhs_len = rhs_len_and_data._0; - auto rhs_data = rhs_len_and_data._1; - bcx = rhs_len_and_data._2; - rslt = reserve_ivec_space(bcx, llunitty, lhs, rhs_len); - auto lhs_data = rslt.val; - bcx = rslt.bcx; - // Work out the end pointer. + fn trans_append(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) -> + result { + auto unit_ty = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t); + auto llunitty = type_of_or_i8(cx, unit_ty); + auto skip_null; + alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) { + case (ty::ty_istr) { skip_null = true; } + case (ty::ty_ivec(_)) { skip_null = false; } + case (_) { + cx.fcx.lcx.ccx.tcx.sess.bug("non-istr/ivec in trans_append"); + } + } + // Gather the various type descriptors we'll need. - auto lhs_unscaled_idx = bcx.build.UDiv(rhs_len, llsize_of(llunitty)); - auto lhs_end = bcx.build.InBoundsGEP(lhs_data, [lhs_unscaled_idx]); - // Now emit the copy loop. + auto rslt = get_tydesc(cx, t, false, none); + auto vec_tydesc = rslt.val; + auto bcx = rslt.bcx; + rslt = get_tydesc(bcx, unit_ty, false, none); + auto unit_tydesc = rslt.val; + bcx = rslt.bcx; - auto dest_ptr = alloca(bcx, T_ptr(llunitty)); - bcx.build.Store(lhs_data, dest_ptr); - auto src_ptr = alloca(bcx, T_ptr(llunitty)); - bcx.build.Store(rhs_data, src_ptr); - auto copy_loop_header_cx = new_sub_block_ctxt(bcx, "copy_loop_header"); - bcx.build.Br(copy_loop_header_cx.llbb); - auto copy_dest_ptr = copy_loop_header_cx.build.Load(dest_ptr); - auto not_yet_at_end = - copy_loop_header_cx.build.ICmp(lib::llvm::LLVMIntNE, copy_dest_ptr, - lhs_end); - auto copy_loop_body_cx = new_sub_block_ctxt(bcx, "copy_loop_body"); - auto next_cx = new_sub_block_ctxt(bcx, "next"); - copy_loop_header_cx.build.CondBr(not_yet_at_end, copy_loop_body_cx.llbb, - next_cx.llbb); - auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr); - rslt = copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src_ptr, t); - auto post_copy_cx = rslt.bcx; - // Increment both pointers. + lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, none); + lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none); + lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, none); - post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_dest_ptr, - [C_int(1)]), - dest_ptr); - post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_src_ptr, - [C_int(1)]), - src_ptr); - post_copy_cx.build.Br(copy_loop_header_cx.llbb); - ret res(next_cx, C_nil()); + auto rhs_len_and_data = get_len_and_data(bcx, rhs, unit_ty); + auto rhs_len = rhs_len_and_data._0; + auto rhs_data = rhs_len_and_data._1; + + bcx = rhs_len_and_data._2; + rslt = reserve_space(bcx, llunitty, lhs, rhs_len); + auto lhs_data = rslt.val; + bcx = rslt.bcx; + + // Work out the end pointer. + auto lhs_unscaled_idx = bcx.build.UDiv(rhs_len, llsize_of(llunitty)); + auto lhs_end = bcx.build.InBoundsGEP(lhs_data, [lhs_unscaled_idx]); + + // Now emit the copy loop. + auto dest_ptr = alloca(bcx, T_ptr(llunitty)); + bcx.build.Store(lhs_data, dest_ptr); + auto src_ptr = alloca(bcx, T_ptr(llunitty)); + bcx.build.Store(rhs_data, src_ptr); + auto copy_loop_header_cx = new_sub_block_ctxt(bcx, + "copy_loop_header"); + bcx.build.Br(copy_loop_header_cx.llbb); + auto copy_dest_ptr = copy_loop_header_cx.build.Load(dest_ptr); + auto not_yet_at_end = + copy_loop_header_cx.build.ICmp(lib::llvm::LLVMIntNE, + copy_dest_ptr, + lhs_end); + auto copy_loop_body_cx = new_sub_block_ctxt(bcx, "copy_loop_body"); + auto next_cx = new_sub_block_ctxt(bcx, "next"); + copy_loop_header_cx.build.CondBr(not_yet_at_end, + copy_loop_body_cx.llbb, + next_cx.llbb); + auto copy_src_ptr = copy_loop_body_cx.build.Load(src_ptr); + rslt = copy_val(copy_loop_body_cx, INIT, copy_dest_ptr, copy_src_ptr, + t); + auto post_copy_cx = rslt.bcx; + // Increment both pointers. + + post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_dest_ptr, + [C_int(1)]), + dest_ptr); + post_copy_cx.build.Store(post_copy_cx.build.InBoundsGEP(copy_src_ptr, + [C_int(1)]), + src_ptr); + post_copy_cx.build.Br(copy_loop_header_cx.llbb); + ret res(next_cx, C_nil()); + } } + fn trans_vec_add(&@block_ctxt cx, &ty::t t, ValueRef lhs, ValueRef rhs) -> result { auto r = alloc_ty(cx, t); @@ -4359,7 +4449,7 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx, maybe_name_value(cx.fcx.lcx.ccx, scaled_ix, "scaled_ix"); auto interior_len_and_data; if (is_interior) { - auto rslt = get_ivec_len_and_data(bcx, v, unit_ty); + auto rslt = get_len_and_data(bcx, v, unit_ty); interior_len_and_data = some(tup(rslt._0, rslt._1)); bcx = rslt._2; } else { interior_len_and_data = none; } @@ -5081,7 +5171,7 @@ fn trans_vec(&@block_ctxt cx, &vec[@ast::expr] args, &ast::ann ann) -> } fn trans_ivec(@block_ctxt bcx, &vec[@ast::expr] args, &ast::ann ann) -> - result { + result { auto typ = node_ann_type(bcx.fcx.lcx.ccx, ann); auto unit_ty; alt (ty::struct(bcx.fcx.lcx.ccx.tcx, typ)) { @@ -5325,9 +5415,9 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) -> alt (op) { case (ast::add) { if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) { - ret trans_ivec_append(rhs_res.bcx, t, - lhs_res.res.val, - rhs_res.val); + ret ivec::trans_append(rhs_res.bcx, t, + lhs_res.res.val, + rhs_res.val); } ret trans_vec_append(rhs_res.bcx, t, lhs_res.res.val, rhs_res.val); @@ -5967,24 +6057,26 @@ fn recv_val(&@block_ctxt cx, ValueRef lhs, &@ast::expr rhs, &ty::t unit_ty, */ -// trans_anon_obj: create (and return!) an LLVM function that is the object -// constructor for the anonymous object being translated. -// -// This code differs from trans_obj in that, rather than creating an object -// constructor function and putting it in the generated code as an object -// item, we are instead "inlining" the construction of the object. -fn trans_anon_obj(@block_ctxt cx, &span sp, &ast::anon_obj anon_obj, +// trans_anon_obj: create and return a pointer to an object. This code +// differs from trans_obj in that, rather than creating an object constructor +// function and putting it in the generated code as an object item, we are +// instead "inlining" the construction of the object and returning the object +// itself. +fn trans_anon_obj(@block_ctxt bcx, &span sp, &ast::anon_obj anon_obj, &vec[ast::ty_param] ty_params, ast::def_id oid, &ast::ann ann) -> result { - auto ccx = cx.fcx.lcx.ccx; - // A crate_ctxt has an item_ids hashmap, which has all of the def_ids of - // everything in the crate. By looking up a def_id, you can get the - // ValueRef of that item. - auto llctor_decl = ccx.item_ids.get(oid); + // Right now, we're assuming that anon objs don't take ty params, even + // though the AST supports it. It's nonsensical to write an expression + // like "obj[T](){ ... with ... }", since T is never instantiated; + // nevertheless, such an expression will parse. FIXME for the future: + // support typarams (issue #n). + assert vec::len(ty_params) == 0u; + + auto ccx = bcx.fcx.lcx.ccx; + // If with_obj (the object being extended) exists, translate it, producing // a result. - let option::t[result] with_obj_val = none[result]; alt (anon_obj.with_obj) { case (none) { } @@ -5993,81 +6085,44 @@ fn trans_anon_obj(@block_ctxt cx, &span sp, &ast::anon_obj anon_obj, // value) wrapped in a result. We want to allocate space for this // value in our outer object, then copy it into the outer object. - with_obj_val = some[result](trans_expr(cx, e)); + with_obj_val = some[result](trans_expr(bcx, e)); } } - // If the anonymous object we're translating adds any additional fields, - // they'll become the arguments to the function we're creating. // FIXME (part of issue #417): all of the following code is copypasta from // trans_obj for translating the anonymous wrapper object. Eventually we // should abstract this code out of trans_anon_obj and trans_obj. - // For the anon obj's additional fields, if any exist, translate object - // constructor arguments to function arguments. - - let vec[ast::obj_field] addtl_fields = []; - let vec[ast::arg] addtl_fn_args = []; - alt (anon_obj.fields) { - case (none) { } - case (some(?fields)) { - addtl_fields = fields; - for (ast::obj_field f in fields) { - addtl_fn_args += - [rec(mode=ast::alias(false), - ty=f.ty, - ident=f.ident, - id=f.id)]; - } - } - } - auto fcx = new_fn_ctxt(cx.fcx.lcx, sp, llctor_decl); - // Both regular arguments and type parameters are handled here. - - create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair], - ret_ty_of_fn(ccx, ann), addtl_fn_args, - ty_params); - let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann); - copy_args_to_allocas(fcx, addtl_fn_args, arg_tys); - // Create the first block context in the function and keep a handle on it - // to pass to finish_fn later. - - auto bcx = new_top_block_ctxt(fcx); - auto lltop = bcx.llbb; - // Pick up the type of this object by looking at our own output type, that - // is, the output type of the object constructor we're building. - - auto self_ty = ret_ty_of_fn(ccx, ann); + auto self_ty = ty::ann_to_type(ccx.tcx, ann); auto llself_ty = type_of(ccx, sp, self_ty); - // Set up the two-word pair that we're going to return from the object - // constructor we're building. The two elements of this pair will be a - // vtable pointer and a body pointer. (llretptr already points to the - // place where this two-word pair should go; it was pre-allocated by the - // caller of the function.) - auto pair = bcx.fcx.llretptr; + // Allocate the object that we're going to return. It's a two-word pair + // containing a vtable pointer and a body pointer. + auto pair = alloca(bcx, llself_ty); + // Grab onto the first and second elements of the pair. // abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1 // of 'pair'. - auto pair_vtbl = bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_vtbl)]); auto pair_box = bcx.build.GEP(pair, [C_int(0), C_int(abi::obj_field_box)]); - // Make a vtable for this object: a static array of pointers to functions. - // It will be located in the read-only memory of the executable we're - // creating and will contain ValueRefs for all of this object's methods. - // create_vtbl returns a pointer to the vtable, which we store. - // create_vtbl() wants an ast::_obj and all we have is an - // ast::anon_obj, so we need to roll our own. + // Make a vtable for the outer object. create_vtbl() wants an ast::_obj + // and all we have is an ast::anon_obj, so we need to roll our own. + let vec[ast::obj_field] addtl_fields = []; + alt (anon_obj.fields) { + case (none) { } + case (some(?fields)) { addtl_fields = fields; } + } + let ast::_obj wrapper_obj = rec( + fields = addtl_fields, + methods = anon_obj.methods, + dtor = none[@ast::method]); + + auto vtbl = create_vtbl(bcx.fcx.lcx, llself_ty, self_ty, wrapper_obj, + ty_params); - let ast::_obj wrapper_obj = - rec(fields=addtl_fields, - methods=anon_obj.methods, - dtor=none[@ast::method]); - auto vtbl = - create_vtbl(cx.fcx.lcx, llself_ty, self_ty, wrapper_obj, ty_params); bcx.build.Store(vtbl, pair_vtbl); // FIXME (part of issue #417): This vtable needs to contain "forwarding // slots" for the methods that exist in the with_obj, as well. How do we @@ -6081,127 +6136,29 @@ fn trans_anon_obj(@block_ctxt cx, &span sp, &ast::anon_obj anon_obj, // also have to fill in the with_obj field of this tuple. let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn); - // FIXME: we should probably also allocate a box for empty objs that have - // a dtor, since otherwise they are never dropped, and the dtor never - // runs. + + alt (anon_obj.fields) { + case (none) { + // If the object we're translating has no fields or type + // parameters, there's not much to do. - if (vec::len[ast::ty_param](ty_params) == 0u && - vec::len[ty::arg](arg_tys) == 0u) { - // If the object we're translating has no fields or type parameters, - // there's not much to do. + // Store null into pair, if no args or typarams. + bcx.build.Store(C_null(llbox_ty), pair_box); - // Store null into pair, if no args or typarams. - - bcx.build.Store(C_null(llbox_ty), pair_box); - } else { - // Otherwise, we have to synthesize a big structural type for the - // object body. - - let vec[ty::t] obj_fields = []; - for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); } - // Tuple type for fields: [field, ...] - - let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields); - // Tuple type for typarams: [typaram, ...] - - auto tydesc_ty = ty::mk_type(ccx.tcx); - let vec[ty::t] tps = []; - for (ast::ty_param tp in ty_params) { - vec::push[ty::t](tps, tydesc_ty); } - let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps); - // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]] - let ty::t body_ty = - ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]); - // Hand this type we've synthesized off to trans_malloc_boxed, which - // allocates a box, including space for a refcount. + case (some(?fields)) { + // For the moment let's pretend that there are no additional + // fields. + bcx.fcx.lcx.ccx.sess.unimpl("anon objs don't support " + + "adding fields yet"); - auto box = trans_malloc_boxed(bcx, body_ty); - bcx = box.bcx; - // mk_imm_box throws a refcount into the type we're synthesizing, so - // that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]] - - let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty); - // Grab onto the refcount and body parts of the box we allocated. - - auto rc = - GEP_tup_like(bcx, boxed_body_ty, box.val, - [0, abi::box_rc_field_refcnt]); - bcx = rc.bcx; - auto body = - GEP_tup_like(bcx, boxed_body_ty, box.val, - [0, abi::box_rc_field_body]); - bcx = body.bcx; - bcx.build.Store(C_int(1), rc.val); - // Put together a tydesc for the body, so that the object can later be - // freed by calling through its tydesc. - - // Every object (not just those with type parameters) needs to have a - // tydesc to describe its body, since all objects have unknown type to - // the user of the object. So the tydesc is needed to keep track of - // the types of the object's fields, so that the fields can be freed - // later. - - auto body_tydesc = - GEP_tup_like(bcx, body_ty, body.val, - [0, abi::obj_body_elt_tydesc]); - bcx = body_tydesc.bcx; - auto ti = none[@tydesc_info]; - auto body_td = get_tydesc(bcx, body_ty, true, ti); - lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti); - lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti); - bcx = body_td.bcx; - bcx.build.Store(body_td.val, body_tydesc.val); - // Copy the object's type parameters and fields into the space we - // allocated for the object body. (This is something like saving the - // lexical environment of a function in its closure: the "captured - // typarams" are any type parameters that are passed to the object - // constructor and are then available to the object's methods. - // Likewise for the object's fields.) - - // Copy typarams into captured typarams. - - auto body_typarams = - GEP_tup_like(bcx, body_ty, body.val, - [0, abi::obj_body_elt_typarams]); - bcx = body_typarams.bcx; - let int i = 0; - for (ast::ty_param tp in ty_params) { - auto typaram = bcx.fcx.lltydescs.(i); - auto capture = - GEP_tup_like(bcx, typarams_ty, body_typarams.val, [0, i]); - bcx = capture.bcx; - bcx = copy_val(bcx, INIT, capture.val, typaram, tydesc_ty).bcx; - i += 1; + // FIXME (issue #417): drop these fields into the newly created + // object. } - // Copy args into body fields. - - auto body_fields = - GEP_tup_like(bcx, body_ty, body.val, - [0, abi::obj_body_elt_fields]); - bcx = body_fields.bcx; - i = 0; - for (ast::obj_field f in wrapper_obj.fields) { - auto arg = bcx.fcx.llargs.get(f.id); - arg = load_if_immediate(bcx, arg, arg_tys.(i).ty); - auto field = - GEP_tup_like(bcx, fields_ty, body_fields.val, [0, i]); - bcx = field.bcx; - bcx = copy_val(bcx, INIT, field.val, arg, arg_tys.(i).ty).bcx; - i += 1; - } - // Store box ptr in outer pair. - - auto p = bcx.build.PointerCast(box.val, llbox_ty); - bcx.build.Store(p, pair_box); } - bcx.build.RetVoid(); - // Insert the mandatory first few basic blocks before lltop. - finish_fn(fcx, lltop); // Return the object we built. - ret res(bcx, pair); } @@ -6658,6 +6615,10 @@ fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] { fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { alt (ty::struct(ccx.tcx, t)) { case (ty::ty_fn(_, _, ?ret_ty, _, _)) { ret ret_ty; } + case (_) { + ccx.sess.bug("ret_ty_of_fn_ty() called on non-function type: " + + ty_to_str(ccx.tcx, t)); + } } } @@ -6807,6 +6768,10 @@ fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty, let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); + + // Every method on an object gets its def_id inserted into the + // crate-wide item_ids map, together with the ValueRef that points to + // where that method's definition will be in the executable. cx.ccx.item_ids.insert(m.node.id, llfn); cx.ccx.item_symbols.insert(m.node.id, s); trans_fn(mcx, m.span, m.node.meth, llfn, @@ -7157,6 +7122,11 @@ fn trans_item(@local_ctxt cx, &ast::item item) { } } +// Translate a module. Doing this amounts to translating the items in the +// module; there ends up being no artifact (aside from linkage names) of +// separate modules in the compiled program. That's because modules exist +// only as a convenience for humans working with the code, to organize names +// and control visibility. fn trans_mod(@local_ctxt cx, &ast::_mod m) { for (@ast::item item in m.items) { trans_item(cx, *item); } } diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 689d00b47ff..db61c9be189 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -198,8 +198,9 @@ to represent predicate *arguments* however. This type Both types store an ident and span, for error-logging purposes. */ type pred_desc_ = rec(vec[@constr_arg_use] args, uint bit_num); - type pred_desc = spanned[pred_desc_]; +type constr_arg_use = constr_arg_general[ident]; + tag constraint { cinit(uint, span, ident); @@ -456,7 +457,7 @@ fn controlflow_expr(&crate_ctxt ccx, @expr e) -> controlflow { } } -fn constraints_expr(&ty::ctxt cx, @expr e) -> vec[@ast::constr] { +fn constraints_expr(&ty::ctxt cx, @expr e) -> vec[@ty::constr_def] { alt (ty::struct(cx, ty::ann_to_type(cx, expr_ann(e)))) { case (ty::ty_fn(_, _, _, _, ?cs)) { ret cs; } case (_) { ret []; } @@ -511,9 +512,11 @@ fn constraints(&fn_ctxt fcx) -> vec[norm_constraint] { // FIXME: // this probably doesn't handle name shadowing well (or at all) // variables should really always be id'd by def_id and not ident + fn match_args(&fn_ctxt fcx, vec[pred_desc] occs, vec[@constr_arg_use] occ) -> uint { - log "match_args: looking at " + pretty::ppaux::constr_args_to_str_1(occ); + log ("match_args: looking at " + + pretty::ppaux::constr_args_to_str(std::util::id[str], occ)); for (pred_desc pd in occs) { log "match_args: candidate " + pred_desc_to_str(pd); if (ty::args_eq(str::eq, pd.node.args, occ)) { ret pd.node.bit_num; } @@ -586,11 +589,13 @@ fn expr_to_constr(ty::ctxt tcx, &@expr e) -> constr { fn pred_desc_to_str(&pred_desc p) -> str { ret "<" + uistr(p.node.bit_num) + ", " + - pretty::ppaux::constr_args_to_str_1(p.node.args) + ">"; + pretty::ppaux::constr_args_to_str(std::util::id[str], p.node.args) + + ">"; } -fn substitute_constr_args(&ty::ctxt cx, &vec[@expr] actuals, &@ast::constr c) - -> constr__ { +fn substitute_constr_args(&ty::ctxt cx, + &vec[@expr] actuals, &@ty::constr_def c) + -> constr__ { let vec[@constr_arg_use] res = []; for (@constr_arg a in c.node.args) { res += [substitute_arg(cx, actuals, a)]; diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index 3c7efcdbe1e..f669afa965d 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -37,30 +37,16 @@ fn collect_pred(&ctxt cx, &@expr e) { case (expr_check(?e, _)) { vec::push(*cx.cs, expr_to_constr(cx.tcx, e)); } - case ( - // If it's a call, generate appropriate instances of the - // call's constraints. - expr_call(?operator, ?operands, ?a)) { - for (@ast::constr c in constraints_expr(cx.tcx, operator)) { - auto d_id = ann_to_def_strict(cx.tcx, c.node.ann); - alt (d_id) { - case (def_fn(?an_id)) { - let aux::constr ct = - respan(c.span, - rec(id=an_id, - c=aux::substitute_constr_args(cx.tcx, - operands, - c))); - vec::push(*cx.cs, ct); - } - case (_) { - cx.tcx.sess.span_err(c.span, - "Non-pred in constraint"); - } - } + // If it's a call, generate appropriate instances of the + // call's constraints. + case (expr_call(?operator, ?operands, ?a)) { + for (@ty::constr_def c in constraints_expr(cx.tcx, operator)) { + let aux::constr ct = respan(c.span, + rec(id=c.node.id, + c=aux::substitute_constr_args(cx.tcx, + operands, c))); + vec::push(*cx.cs, ct); } - // FIXME: constraints on result type - } case (_) { } } diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 98c7821235a..a355c9f3f12 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -208,38 +208,16 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) { auto args = vec::clone[@expr](operands); vec::push[@expr](args, operator); find_pre_post_exprs(fcx, args, a); - /* should test higher-order constrained functions */ - - /* FIXME */ - - /* see if the call has any constraints on its in type */ - - log "a function: "; + /* see if the call has any constraints on its type */ + log("a function: " ); log_expr(*operator); auto pp = expr_pp(fcx.ccx, e); - for (@constr c in constraints_expr(fcx.ccx.tcx, operator)) { - auto id = ann_to_def(fcx.ccx, c.node.ann); - alt (id) { - case (some(def_fn(?d_id))) { - auto i = - bit_num(fcx, - rec(id=d_id, - c=substitute_constr_args(fcx.ccx.tcx, - operands, - c))); - require(i, pp); - } - case (_) { - fcx.ccx.tcx.sess.span_err(c.span, - "Unbound pred " + - " or pred that's not \ - bound to a function"); - } - } + for (@ty::constr_def c in + constraints_expr(fcx.ccx.tcx, operator)) { + auto i = bit_num(fcx, rec(id=c.node.id, + c=substitute_constr_args(fcx.ccx.tcx, operands, c))); + require(i, pp); } - - // FIXME: constraints on result type - /* if this is a failing call, its postcondition sets everything */ alt (controlflow_expr(fcx.ccx, operator)) { case (noreturn) { set_postcond_false(fcx.ccx, a); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 027c8b333ae..6ef2384d8f1 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -13,23 +13,14 @@ import std::option::some; import std::smallintmap; import driver::session; import front::ast; +import front::ast::def_id; +import front::ast::constr_arg_general; import front::ast::mutability; import front::ast::controlflow; import front::creader; import middle::metadata; -import util::common; -import util::common::ty_u8; -import util::common::ty_u16; -import util::common::ty_u32; -import util::common::ty_u64; -import util::common::ty_i8; -import util::common::ty_i16; -import util::common::ty_i32; -import util::common::ty_i64; -import util::common::ty_f32; -import util::common::ty_f64; -import util::common::new_def_hash; -import util::common::span; +import util::common::*; + import util::data::interner; @@ -46,7 +37,7 @@ type method = vec[arg] inputs, t output, controlflow cf, - vec[@ast::constr] constrs); + vec[@constr_def] constrs); tag any_item { any_item_rust(@ast::item); @@ -54,12 +45,14 @@ tag any_item { } type item_table = hashmap[ast::def_id, any_item]; +type constr_table = hashmap[ast::def_id, vec[constr_def]]; type mt = rec(t ty, ast::mutability mut); // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. + type creader_cache = hashmap[tup(int, uint, uint), ty::t]; type ctxt = @@ -68,7 +61,7 @@ type ctxt = resolve::def_map def_map, node_type_table node_types, item_table items, // Only contains type items - + constr_table fn_constrs, type_cache tcache, creader_cache rcache, hashmap[t, str] short_names_cache, @@ -83,7 +76,6 @@ type ty_ctxt = ctxt; ret mk_fn(cx, m.proto, m.inputs, m.output, m.cf, m.constrs); } - // Never construct these manually. These are interned. // // TODO: It'd be really nice to be able to hide this definition from the @@ -107,11 +99,11 @@ tag sty { ty_int; ty_float; ty_uint; - ty_machine(util::common::ty_mach); + ty_machine(ty_mach); ty_char; ty_str; ty_istr; - ty_tag(ast::def_id, vec[t]); + ty_tag(def_id, vec[t]); ty_box(mt); ty_vec(mt); ty_ivec(mt); @@ -121,7 +113,7 @@ tag sty { ty_task; ty_tup(vec[mt]); ty_rec(vec[field]); - ty_fn(ast::proto, vec[arg], t, controlflow, vec[@ast::constr]); + ty_fn(ast::proto, vec[arg], t, controlflow, vec[@constr_def]); ty_native_fn(ast::native_abi, vec[arg], t); ty_obj(vec[method]); ty_var(int); // type variable @@ -134,6 +126,10 @@ tag sty { } +type constr_def = spanned[constr_general[uint]]; +type constr_general[T] = rec(path path, + vec[@constr_arg_general[T]] args, + def_id id); // Data structures used in type unification tag type_err { @@ -247,12 +243,13 @@ 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) -> ctxt { +fn mk_ctxt(session::session s, resolve::def_map dm, constr_table cs) -> ctxt { + let vec[mutable option::t[ty::ty_param_substs_opt_and_ty]] ntt_sub = [mutable ]; let node_type_table ntt = @mutable ntt_sub; - auto tcache = common::new_def_hash[ty::ty_param_count_and_ty](); - auto items = common::new_def_hash[any_item](); + auto tcache = new_def_hash[ty::ty_param_count_and_ty](); + auto items = new_def_hash[any_item](); auto ts = @interner::mk[raw_t](hash_raw_ty, eq_raw_ty); auto cx = rec(ts=ts, @@ -260,6 +257,7 @@ fn mk_ctxt(session::session s, resolve::def_map dm) -> ctxt { def_map=dm, node_types=ntt, items=items, + fn_constrs = cs, tcache=tcache, rcache=mk_rcache(), short_names_cache=map::mk_hashmap[ty::t, @@ -379,7 +377,7 @@ fn mk_float(&ctxt cx) -> t { ret idx_float; } fn mk_uint(&ctxt cx) -> t { ret idx_uint; } -fn mk_mach(&ctxt cx, &util::common::ty_mach tm) -> t { +fn mk_mach(&ctxt cx, &ty_mach tm) -> t { alt (tm) { case (ty_u8) { ret idx_u8; } case (ty_u16) { ret idx_u16; } @@ -439,7 +437,7 @@ fn mk_imm_tup(&ctxt cx, &vec[t] tys) -> t { fn mk_rec(&ctxt cx, &vec[field] fs) -> t { ret gen_ty(cx, ty_rec(fs)); } fn mk_fn(&ctxt cx, &ast::proto proto, &vec[arg] args, &t ty, &controlflow cf, - &vec[@ast::constr] constrs) -> t { + &vec[@constr_def] constrs) -> t { ret gen_ty(cx, ty_fn(proto, args, ty, cf, constrs)); } @@ -759,8 +757,8 @@ fn sequence_is_interior(&ctxt cx, &t ty) -> bool { fn sequence_element_type(&ctxt cx, &t ty) -> t { alt (struct(cx, ty)) { - case (ty_str) { ret mk_mach(cx, common::ty_u8); } - case (ty_istr) { ret mk_mach(cx, common::ty_u8); } + case (ty_str) { ret mk_mach(cx, ty_u8); } + case (ty_istr) { ret mk_mach(cx, ty_u8); } case (ty_vec(?mt)) { ret mt.ty; } case (ty_ivec(?mt)) { ret mt.ty; } case (_) { @@ -915,14 +913,14 @@ fn type_is_integral(&ctxt cx, &t ty) -> bool { case (ty_uint) { ret true; } case (ty_machine(?m)) { alt (m) { - case (common::ty_i8) { ret true; } - case (common::ty_i16) { ret true; } - case (common::ty_i32) { ret true; } - case (common::ty_i64) { ret true; } - case (common::ty_u8) { ret true; } - case (common::ty_u16) { ret true; } - case (common::ty_u32) { ret true; } - case (common::ty_u64) { ret true; } + case (ty_i8) { ret true; } + case (ty_i16) { ret true; } + case (ty_i32) { ret true; } + case (ty_i64) { ret true; } + case (ty_u8) { ret true; } + case (ty_u16) { ret true; } + case (ty_u32) { ret true; } + case (ty_u64) { ret true; } case (_) { ret false; } } } @@ -935,8 +933,8 @@ fn type_is_fp(&ctxt cx, &t ty) -> bool { alt (struct(cx, ty)) { case (ty_machine(?tm)) { alt (tm) { - case (common::ty_f32) { ret true; } - case (common::ty_f64) { ret true; } + case (ty_f32) { ret true; } + case (ty_f64) { ret true; } case (_) { ret false; } } } @@ -950,10 +948,10 @@ fn type_is_signed(&ctxt cx, &t ty) -> bool { case (ty_int) { ret true; } case (ty_machine(?tm)) { alt (tm) { - case (common::ty_i8) { ret true; } - case (common::ty_i16) { ret true; } - case (common::ty_i32) { ret true; } - case (common::ty_i64) { ret true; } + case (ty_i8) { ret true; } + case (ty_i16) { ret true; } + case (ty_i32) { ret true; } + case (ty_i64) { ret true; } case (_) { ret false; } } } @@ -1005,16 +1003,16 @@ fn hash_type_structure(&sty st) -> uint { case (ty_uint) { ret 4u; } case (ty_machine(?tm)) { alt (tm) { - case (common::ty_i8) { ret 5u; } - case (common::ty_i16) { ret 6u; } - case (common::ty_i32) { ret 7u; } - case (common::ty_i64) { ret 8u; } - case (common::ty_u8) { ret 9u; } - case (common::ty_u16) { ret 10u; } - case (common::ty_u32) { ret 11u; } - case (common::ty_u64) { ret 12u; } - case (common::ty_f32) { ret 13u; } - case (common::ty_f64) { ret 14u; } + case (ty_i8) { ret 5u; } + case (ty_i16) { ret 6u; } + case (ty_i32) { ret 7u; } + case (ty_i64) { ret 8u; } + case (ty_u8) { ret 9u; } + case (ty_u16) { ret 10u; } + case (ty_u32) { ret 11u; } + case (ty_u64) { ret 12u; } + case (ty_f32) { ret 13u; } + case (ty_f64) { ret 14u; } } } case (ty_char) { ret 15u; } @@ -1096,7 +1094,7 @@ fn arg_eq[T](&fn(&T, &T) -> bool eq, @ast::constr_arg_general[T] a, } case (ast::carg_lit(?l)) { alt (b.node) { - case (ast::carg_lit(?m)) { ret util::common::lit_eq(l, m); } + case (ast::carg_lit(?m)) { ret lit_eq(l, m); } case (_) { ret false; } } } @@ -1113,18 +1111,18 @@ fn args_eq[T](fn(&T, &T) -> bool eq, vec[@ast::constr_arg_general[T]] a, ret true; } -fn constr_eq(&@ast::constr c, &@ast::constr d) -> bool { +fn constr_eq(&@constr_def c, &@constr_def 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(&vec[@ast::constr] cs, &vec[@ast::constr] ds) -> bool { +fn constrs_eq(&vec[@constr_def] cs, &vec[@constr_def] ds) -> bool { if (vec::len(cs) != vec::len(ds)) { ret false; } - auto i = 0; - for (@ast::constr c in cs) { + auto i = 0u; + for (@constr_def c in cs) { if (!constr_eq(c, ds.(i))) { ret false; } - i += 1; + i += 1u; } ret true; } @@ -1829,8 +1827,8 @@ mod unify { &t expected, &t actual, &vec[arg] expected_inputs, &t expected_output, &vec[arg] actual_inputs, &t actual_output, &controlflow expected_cf, &controlflow actual_cf, - &vec[@ast::constr] expected_constrs, - &vec[@ast::constr] actual_constrs) -> result { + &vec[@constr_def] expected_constrs, + &vec[@constr_def] actual_constrs) -> result { if (e_proto != a_proto) { ret ures_err(terr_mismatch); } alt (expected_cf) { case (ast::return) { } @@ -2473,7 +2471,7 @@ fn tag_variant_with_id(&ctxt cx, &ast::def_id tag_id, &ast::def_id variant_id) auto i = 0u; while (i < vec::len[variant_info](variants)) { auto variant = variants.(i); - if (common::def_eq(variant.id, variant_id)) { ret variant; } + if (def_eq(variant.id, variant_id)) { ret variant; } i += 1u; } cx.sess.bug("tag_variant_with_id(): no variant exists with that ID"); diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index d86aa74c1bd..bd804b97bd2 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -6,6 +6,7 @@ import front::creader; import driver::session; import util::common; import util::common::span; +import util::common::respan; import util::common::new_def_hash; import util::common::log_expr_err; import middle::ty; @@ -312,7 +313,10 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { auto f = bind ast_arg_to_arg(tcx, getter, _); auto i = vec::map[ast::ty_arg, arg](f, inputs); auto out_ty = ast_ty_to_ty(tcx, getter, output); - typ = ty::mk_fn(tcx, proto, i, out_ty, cf, constrs); + let fn(&@ast::constr) -> @ty::constr_def g = + bind ast_constr_to_constr(tcx, _); + let vec[@ty::constr_def] out_constrs = vec::map(g, constrs); + typ = ty::mk_fn(tcx, proto, i, out_ty, cf, out_constrs); } case (ast::ty_path(?path, ?ann)) { alt (tcx.def_map.get(ann.id)) { @@ -341,13 +345,17 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { for (ast::ty_method m in meths) { auto ins = vec::map[ast::ty_arg, arg](f, m.node.inputs); auto out = ast_ty_to_ty(tcx, getter, m.node.output); + let fn(&@ast::constr) -> @ty::constr_def g = + bind ast_constr_to_constr(tcx, _); + let vec[@ty::constr_def] out_constrs = + vec::map(g, m.node.constrs); let ty::method new_m = rec(proto=m.node.proto, ident=m.node.ident, inputs=ins, output=out, cf=m.node.cf, - constrs=m.node.constrs); + constrs=out_constrs); vec::push[ty::method](tmeths, new_m); } typ = ty::mk_obj(tcx, ty::sort_methods(tmeths)); @@ -388,7 +396,7 @@ mod write { // Writes a type parameter count and type pair into the node type table. fn ty(&ty::ctxt tcx, uint node_id, &ty_param_substs_opt_and_ty tpot) { assert (!ty::type_contains_vars(tcx, tpot._1)); - be inner(tcx.node_types, node_id, tpot); + ret inner(tcx.node_types, node_id, tpot); } // Writes a type parameter count and type pair into the node type table. @@ -404,23 +412,23 @@ mod write { // Writes a type with no type parameters into the node type table. fn ty_only(&ty::ctxt tcx, uint node_id, ty::t typ) { - be ty(tcx, node_id, tup(none[vec[ty::t]], typ)); + ret ty(tcx, node_id, tup(none[vec[ty::t]], typ)); } // Writes a type with no type parameters into the node type table. This // function allows for the possibility of type variables. fn ty_only_fixup(@fn_ctxt fcx, uint node_id, ty::t typ) { - be ty_fixup(fcx, node_id, tup(none[vec[ty::t]], typ)); + ret ty_fixup(fcx, node_id, tup(none[vec[ty::t]], typ)); } // Writes a nil type into the node type table. fn nil_ty(&ty::ctxt tcx, uint node_id) { - be ty(tcx, node_id, tup(none[vec[ty::t]], ty::mk_nil(tcx))); + ret ty(tcx, node_id, tup(none[vec[ty::t]], ty::mk_nil(tcx))); } // Writes the bottom type into the node type table. fn bot_ty(&ty::ctxt tcx, uint node_id) { - be ty(tcx, node_id, tup(none[vec[ty::t]], ty::mk_bot(tcx))); + ret ty(tcx, node_id, tup(none[vec[ty::t]], ty::mk_bot(tcx))); } } @@ -449,9 +457,12 @@ mod collect { ty::ty_param_count_and_ty { auto input_tys = vec::map[ast::arg, arg](ty_of_arg, decl.inputs); auto output_ty = convert(decl.output); + let fn(&@ast::constr) -> @ty::constr_def g = + bind ast_constr_to_constr(cx.tcx, _); + let vec[@ty::constr_def] out_constrs = vec::map(g, decl.constraints); auto t_fn = ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf, - decl.constraints); + out_constrs); auto ty_param_count = vec::len[ast::ty_param](ty_params); auto tpt = tup(ty_param_count, t_fn); alt (def_id) { @@ -512,12 +523,13 @@ mod collect { auto f = bind ty_of_arg(cx, _); auto inputs = vec::map[ast::arg, arg](f, m.node.meth.decl.inputs); auto output = convert(m.node.meth.decl.output); - ret rec(proto=m.node.meth.proto, - ident=m.node.ident, - inputs=inputs, - output=output, - cf=m.node.meth.decl.cf, - constrs=m.node.meth.decl.constraints); + let fn(&@ast::constr) -> @ty::constr_def g = + bind ast_constr_to_constr(cx.tcx, _); + let vec[@ty::constr_def] out_constrs = + vec::map(g, m.node.meth.decl.constraints); + ret rec(proto=m.node.meth.proto, ident=m.node.ident, + inputs=inputs, output=output, cf=m.node.meth.decl.cf, + constrs=out_constrs); } fn ty_of_obj(@ctxt cx, &ast::ident id, &ast::_obj obj_info, &vec[ast::ty_param] ty_params) -> ty::ty_param_count_and_ty { @@ -537,10 +549,8 @@ mod collect { auto t_field = ast_ty_to_ty(cx.tcx, g, f.ty); vec::push(t_inputs, rec(mode=ty::mo_alias(false), ty=t_field)); } - let vec[@ast::constr] constrs = []; - auto t_fn = - ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj._1, ast::return, - constrs); + auto t_fn = ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj._1, + ast::return, []); auto tpt = tup(t_obj._0, t_fn); cx.tcx.tcache.insert(ctor_id, tpt); ret tpt; @@ -652,11 +662,8 @@ mod collect { } auto tag_t = ty::mk_tag(cx.tcx, tag_id, ty_param_tys); // FIXME: this will be different for constrained types - - let vec[@ast::constr] res_constrs = []; - result_ty = - ty::mk_fn(cx.tcx, ast::proto_fn, args, tag_t, ast::return, - res_constrs); + result_ty = ty::mk_fn(cx.tcx, ast::proto_fn, args, tag_t, + ast::return, []); } auto tpt = tup(ty_param_count, result_ty); cx.tcx.tcache.insert(variant.node.id, tpt); @@ -752,12 +759,8 @@ mod collect { alt (object.dtor) { case (none) {/* nothing to do */ } case (some(?m)) { - let vec[@ast::constr] constrs = []; - let vec[arg] res_inputs = []; - auto t = - ty::mk_fn(cx.tcx, ast::proto_fn, res_inputs, - ty::mk_nil(cx.tcx), ast::return, - constrs); + auto t = ty::mk_fn(cx.tcx, ast::proto_fn, [], + ty::mk_nil(cx.tcx), ast::return, []); write::ty_only(cx.tcx, m.node.ann.id, t); } } @@ -1421,9 +1424,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { &@ast::expr rhs, &ast::ann a) { check_expr(fcx, lhs); check_expr(fcx, rhs); - auto typ = - demand::simple(fcx, sp, expr_ty(fcx.ccx.tcx, lhs), - expr_ty(fcx.ccx.tcx, rhs)); + demand::simple(fcx, sp, expr_ty(fcx.ccx.tcx, lhs), + expr_ty(fcx.ccx.tcx, rhs)); write::ty_only_fixup(fcx, a.id, ty::mk_nil(fcx.ccx.tcx)); } // A generic function for checking call expressions @@ -2123,12 +2125,13 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto inputs = vec::map[ast::arg, arg](f, m.node.meth.decl.inputs); auto output = convert(m.node.meth.decl.output); - ret rec(proto=m.node.meth.proto, - ident=m.node.ident, - inputs=inputs, - output=output, - cf=m.node.meth.decl.cf, - constrs=m.node.meth.decl.constraints); + let fn(&@ast::constr) -> @ty::constr_def g = + bind ast_constr_to_constr(ccx.tcx, _); + let vec[@ty::constr_def] out_constrs = + vec::map(g, m.node.meth.decl.constraints); + ret rec(proto=m.node.meth.proto, ident=m.node.ident, + inputs=inputs, output=output, cf=m.node.meth.decl.cf, + constrs=out_constrs); } fn get_anon_obj_method_types(@crate_ctxt ccx, &ast::anon_obj anon_obj) -> @@ -2180,6 +2183,21 @@ fn get_obj_info(&@crate_ctxt ccx) -> option::t[obj_info] { ret vec::last[obj_info](ccx.obj_infos); } +fn ast_constr_to_constr(ty::ctxt tcx, &@ast::constr c) + -> @ty::constr_def { + alt (tcx.def_map.find(c.node.ann.id)) { + case (some(ast::def_fn(?pred_id))) { + ret @respan(c.span, rec(path=c.node.path, args=c.node.args, + id=pred_id)); + } + case (_) { + tcx.sess.span_err(c.span, "Predicate " + + path_to_str(c.node.path) + + " is unbound or bound to a non-function"); + } + } +} + fn check_decl_initializer(&@fn_ctxt fcx, &ast::def_id lid, &ast::initializer init) { check_expr(fcx, init.expr); diff --git a/src/comp/pretty/ppaux.rs b/src/comp/pretty/ppaux.rs index f1a85287c7f..929bfdcc25c 100644 --- a/src/comp/pretty/ppaux.rs +++ b/src/comp/pretty/ppaux.rs @@ -1,7 +1,6 @@ import std::io; import middle::ty::*; -import front::ast::constr_arg; import front::lexer; import pp::word; import pp::eof; @@ -21,9 +20,10 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { }; ret s + ty_to_str(cx, input.ty); } + fn fn_to_str(&ctxt cx, ast::proto proto, option::t[ast::ident] ident, vec[arg] inputs, t output, ast::controlflow cf, - &vec[@ast::constr] constrs) -> str { + &vec[@constr_def] constrs) -> str { auto f = bind fn_input_to_str(cx, _); auto s; alt (proto) { @@ -69,7 +69,7 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { case (ty_int) { s += "int"; } case (ty_float) { s += "float"; } case (ty_uint) { s += "uint"; } - case (ty_machine(?tm)) { s += common::ty_mach_to_str(tm); } + case (ty_machine(?tm)) { s += ty_mach_to_str(tm); } case (ty_char) { s += "char"; } case (ty_str) { s += "str"; } case (ty_istr) { s += "istr"; } @@ -92,10 +92,8 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { } case (ty_tag(?id, ?tps)) { // The user should never see this if the cname is set properly! - s += - ""; + ""; if (vec::len[t](tps) > 0u) { auto f = bind ty_to_str(cx, _); auto strs = vec::map[t, str](f, tps); @@ -104,21 +102,20 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { } case (ty_fn(?proto, ?inputs, ?output, ?cf, ?constrs)) { s += - fn_to_str(cx, proto, none[ast::ident], inputs, output, cf, + fn_to_str(cx, proto, none, inputs, output, cf, constrs); } case (ty_native_fn(_, ?inputs, ?output)) { - let vec[@ast::constr] constrs = []; s += - fn_to_str(cx, ast::proto_fn, none[ast::ident], inputs, output, - ast::return, constrs); + fn_to_str(cx, ast::proto_fn, none, inputs, output, + ast::return, []); } case (ty_obj(?meths)) { auto f = bind method_to_str(cx, _); auto m = vec::map[method, str](f, meths); s += "obj {\n\t" + str::connect(m, "\n\t") + "\n}"; } - case (ty_var(?v)) { s += ""; } + case (ty_var(?v)) { s += ""; } case (ty_param(?id)) { s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]); } @@ -144,7 +141,7 @@ fn constr_arg_to_str[T](fn(&T) -> str f, &ast::constr_arg_general_[T] c) -> } } -fn constr_arg_to_str_1(&ast::constr_arg_general_[str] c) -> str { +fn constr_arg_to_str_1(&front::ast::constr_arg_general_[str] c) -> str { alt (c) { case (ast::carg_base) { ret "*"; } case (ast::carg_ident(?i)) { ret i; } @@ -164,18 +161,7 @@ fn constr_args_to_str[T](fn(&T) -> str f, ret s; } -fn constr_args_to_str_1(&vec[@ast::constr_arg_use] args) -> str { - auto comma = false; - auto s = "("; - for (@ast::constr_arg_use a in args) { - if (comma) { s += ", "; } else { comma = true; } - s += constr_arg_to_str_1(a.node); - } - s += ")"; - ret s; -} - -fn print_literal(&ps s, &@ast::lit lit) { +fn print_literal(&ps s, &@front::ast::lit lit) { maybe_print_comment(s, lit.span.lo); alt (next_lit(s)) { case (some(?lt)) { @@ -196,18 +182,18 @@ fn print_literal(&ps s, &@ast::lit lit) { word(s.s, "'" + escape_str(str::from_bytes([ch as u8]), '\'') + "'"); } - case (ast::lit_int(?val)) { word(s.s, common::istr(val)); } - case (ast::lit_uint(?val)) { word(s.s, common::uistr(val) + "u"); } + case (ast::lit_int(?val)) { word(s.s, istr(val)); } + case (ast::lit_uint(?val)) { word(s.s, uistr(val) + "u"); } case (ast::lit_float(?fstr)) { word(s.s, fstr); } case (ast::lit_mach_int(?mach, ?val)) { - word(s.s, common::istr(val as int)); - word(s.s, common::ty_mach_to_str(mach)); + word(s.s, istr(val as int)); + word(s.s, ty_mach_to_str(mach)); } case (ast::lit_mach_float(?mach, ?val)) { // val is already a str word(s.s, val); - word(s.s, common::ty_mach_to_str(mach)); + word(s.s, ty_mach_to_str(mach)); } case (ast::lit_nil) { word(s.s, "()"); } case (ast::lit_bool(?val)) { @@ -216,7 +202,7 @@ fn print_literal(&ps s, &@ast::lit lit) { } } -fn lit_to_str(&@ast::lit l) -> str { be to_str(l, print_literal); } +fn lit_to_str(&@front::ast::lit l) -> str { be to_str(l, print_literal); } fn next_lit(&ps s) -> option::t[lexer::lit] { alt (s.literals) { @@ -360,22 +346,46 @@ const uint default_columns = 78u; // needed b/c constr_args_to_str needs // something that takes an alias // (argh) -fn uint_to_str(&uint i) -> str { ret util::common::uistr(i); } -fn constr_to_str(&@ast::constr c) -> str { - ret path_to_str(c.node.path) + - constr_args_to_str(uint_to_str, c.node.args); +fn uint_to_str(&uint i) -> str { ret uistr(i); } + +fn constr_to_str(&@constr_def c) -> str { + ret path_to_str(c.node.path) + + constr_args_to_str(uint_to_str, c.node.args); } -fn constrs_str(&vec[@ast::constr] constrs) -> str { + +fn ast_constr_to_str(&@front::ast::constr c) -> str { + ret path_to_str(c.node.path) + + constr_args_to_str(uint_to_str, c.node.args); +} + +fn constrs_str(&vec[@constr_def] constrs) -> str { auto s = ""; auto colon = true; - for (@ast::constr c in constrs) { + for (@constr_def c in constrs) { if (colon) { s += " : "; colon = false; } else { s += ", "; } s += constr_to_str(c); } ret s; } + +fn ast_constrs_str(&vec[@ast::constr] constrs) -> str { + auto s = ""; + auto colon = true; + for (@ast::constr c in constrs) { + if (colon) { + s += " : "; + colon = false; + } + else { + s += ", "; + } + s += ast_constr_to_str(c); + } + ret s; +} + // // Local Variables: // mode: rust diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 1c2b40c3212..8db88541c2f 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -802,7 +802,7 @@ fn print_expr(&ps s, &@ast::expr expr) { } case (ast::expr_anon_obj(_, _, _, _)) { word(s.s, "anon obj"); - // TODO: nicer pretty-printing of anon objs + // FIXME (issue #499): nicer pretty-printing of anon objs } } @@ -1094,7 +1094,7 @@ fn print_ty_fn(&ps s, &ast::proto proto, &option::t[str] id, } end(s); } - word_space(s, constrs_str(constrs)); + word_space(s, ast_constrs_str(constrs)); end(s); } diff --git a/src/lib/either.rs b/src/lib/either.rs new file mode 100644 index 00000000000..12ccbb2bbfb --- /dev/null +++ b/src/lib/either.rs @@ -0,0 +1,64 @@ +import option; +import option::some; +import option::none; + +tag t[T, U] { + left(T); + right(U); +} + +type operator[T, U] = fn(&T) -> U; + +fn either[T, U, V](&operator[T, V] f_left, + &operator[U, V] f_right, + &t[T, U] value) -> V { + alt (value) { + case (left(?l)) { f_left(l) } + case (right(?r)) { f_right(r) } + } +} + +fn lefts[T, U](&vec[t[T, U]] eithers) -> vec[T] { + let vec[T] result = []; + for (t[T, U] elt in eithers) { + alt (elt) { + case (left(?l)) { result += [l] } + case (_) { /* fallthrough */ } + } + } + ret result; +} + +fn rights[T, U](&vec[t[T, U]] eithers) -> vec[U] { + let vec[U] result = []; + for (t[T, U] elt in eithers) { + alt (elt) { + case (right(?r)) { result += [r] } + case (_) { /* fallthrough */ } + } + } + ret result; +} + +fn partition[T, U](&vec[t[T, U]] eithers) -> tup(vec[T], vec[U]) { + let vec[T] lefts = []; + let vec[U] rights = []; + for (t[T, U] elt in eithers) { + alt (elt) { + case (left(?l)) { lefts += [l] } + case (right(?r)) { rights += [r] } + } + } + ret tup(lefts, rights); +} + +// +// 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/lib/list.rs b/src/lib/list.rs index edd14a30133..a752e005b5e 100644 --- a/src/lib/list.rs +++ b/src/lib/list.rs @@ -18,35 +18,52 @@ fn from_vec[T](vec[T] v) -> list[T] { ret l; } -fn foldl[T, U](&list[T] ls, &U u, fn(&T, &U) -> U f) -> U { - alt (ls) { - case (cons(?hd, ?tl)) { - auto u_ = f(hd, u); - be foldl[T, U](*tl, u_, f); - } - case (nil) { ret u; } - } -} - -fn find[T, U](&list[T] ls, fn(&T) -> option::t[U] f) -> option::t[U] { - alt (ls) { - case (cons(?hd, ?tl)) { - alt (f(hd)) { - case (none) { be find[T, U](*tl, f); } - case (some(?res)) { ret some[U](res); } +fn foldl[T, U](&list[T] ls_, &U u, fn(&T, &U) -> U f) -> U { + let U accum = u; + auto ls = ls_; + while (true) { + alt (ls) { + case (cons(?hd, ?tl)) { + accum = f(hd, accum); + ls = *tl; } + case (nil) { break; } } - case (nil) { ret none[U]; } } + ret accum; } -fn has[T](&list[T] ls, &T elt) -> bool { - alt (ls) { - case (cons(?hd, ?tl)) { - if (elt == hd) { ret true; } else { be has(*tl, elt); } +fn find[T, U](&list[T] ls_, fn(&T) -> option::t[U] f) -> option::t[U] { + auto ls = ls_; + while (true) { + alt (ls) { + case (cons(?hd, ?tl)) { + alt (f(hd)) { + case (none) { ls = *tl; } + case (some(?res)) { ret some(res); } + } + } + case (nil) { break; } } - case (nil) { ret false; } } + ret none; +} + +fn has[T](&list[T] ls_, &T elt) -> bool { + auto ls = ls_; + while (true) { + alt (ls) { + case (cons(?hd, ?tl)) { + if (elt == hd) { + ret true; + } else { + ls = *tl; + } + } + case (nil) { ret false; } + } + } + ret false; // Typestate checker doesn't understand infinite loops } fn length[T](&list[T] ls) -> uint { diff --git a/src/lib/std.rc b/src/lib/std.rc index 60cecd7cf68..26d36257bd5 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -22,6 +22,7 @@ mod task; // Utility modules. +mod either; mod option; mod util; diff --git a/src/lib/term.rs b/src/lib/term.rs index 33ca245551c..14fddb55633 100644 --- a/src/lib/term.rs +++ b/src/lib/term.rs @@ -48,7 +48,17 @@ fn reset(io::buf_writer writer) { } fn color_supported() -> bool { - ret generic_os::getenv("TERM") == option::some[str]("xterm-color"); + auto supported_terms = ["xterm-color", + "xterm", + "screen-bce"]; + ret alt (generic_os::getenv("TERM")) { + case (option::some(?env)) { + vec::member(env, supported_terms) + } + case (option::none) { + false + } + }; } fn set_color(io::buf_writer writer, u8 first_char, u8 color) { @@ -67,3 +77,11 @@ fn bg(io::buf_writer writer, u8 color) { } // export fg; // export bg; + +// Local Variables: +// 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/test/compile-fail/ext-after-attrib.rs b/src/test/compile-fail/ext-after-attrib.rs new file mode 100644 index 00000000000..31786fcaf65 --- /dev/null +++ b/src/test/compile-fail/ext-after-attrib.rs @@ -0,0 +1,8 @@ +// xfail-stage0 +// error-pattern:expecting \[, found fmt + +// Don't know how to deal with a syntax extension appearing after an +// item attribute. Probably could use a better error message. +#[foo = "bar"] +#fmt("baz") +fn main() { } \ No newline at end of file diff --git a/src/test/compile-fail/not-a-pred.rs b/src/test/compile-fail/not-a-pred.rs index 4a899512e31..ae8068d05e1 100644 --- a/src/test/compile-fail/not-a-pred.rs +++ b/src/test/compile-fail/not-a-pred.rs @@ -1,6 +1,6 @@ // -*- rust -*- - -// error-pattern: mismatched types +// xfail-stage0 +// error-pattern: Non-predicate in constraint: lt fn f(int a, int b) : lt(a,b) { } diff --git a/src/test/run-pass/anon-objs.rs b/src/test/run-pass/anon-objs.rs index 94a14b89e77..5c7df451bf2 100644 --- a/src/test/run-pass/anon-objs.rs +++ b/src/test/run-pass/anon-objs.rs @@ -5,18 +5,30 @@ use std; fn main() { + obj a() { - fn foo() -> int { ret 2; } - fn bar() -> int { ret self.foo(); } + fn foo() -> int { + ret 2; + } + fn bar() -> int { + ret self.foo(); + } } + auto my_a = a(); + // Extending an object with a new method + auto my_b = obj { + fn baz() -> int { + ret self.foo(); + } + with my_a + }; - auto my_b = anon obj; // Extending an object with a new field + auto my_c = obj(int quux) { with my_a } ; - auto my_c = anon obj; // Should this be legal? - - auto my_d = anon obj; -} \ No newline at end of file + auto my_d = obj() { with my_a } ; + +} diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index df18f786f05..c407a386d60 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -1,14 +1,16 @@ - - - // xfail-stage0 + mod test_single_attr_outer { #[attr = "val"] const int x = 10; #[attr = "val"] - mod mod1 { } + fn f() {} + + #[attr = "val"] + mod mod1 { + } #[attr = "val"] native "rust" mod rustrt { } @@ -29,7 +31,12 @@ mod test_multi_attr_outer { #[attr1 = "val"] #[attr2 = "val"] - mod mod1 { } + fn f() {} + + #[attr1 = "val"] + #[attr2 = "val"] + mod mod1 { + } #[attr1 = "val"] #[attr2 = "val"] @@ -45,4 +52,69 @@ mod test_multi_attr_outer { obj o() { } } -fn main() { } \ No newline at end of file +mod test_stmt_single_attr_outer { + + fn f() { + + #[attr = "val"] + const int x = 10; + + #[attr = "val"] + fn f() {} + + /* FIXME: Issue #493 + #[attr = "val"] + mod mod1 { + } + + #[attr = "val"] + native "rust" mod rustrt { + } + */ + + #[attr = "val"] + type t = obj { }; + + #[attr = "val"] + obj o() { } + + } +} + +mod test_stmt_multi_attr_outer { + + fn f() { + + #[attr1 = "val"] + #[attr2 = "val"] + const int x = 10; + + #[attr1 = "val"] + #[attr2 = "val"] + fn f() {} + + /* FIXME: Issue #493 + #[attr1 = "val"] + #[attr2 = "val"] + mod mod1 { + } + + #[attr1 = "val"] + #[attr2 = "val"] + native "rust" mod rustrt { + } + */ + + #[attr1 = "val"] + #[attr2 = "val"] + type t = obj { }; + + #[attr1 = "val"] + #[attr2 = "val"] + obj o() { } + + } +} + +fn main() { +} diff --git a/src/test/run-pass/lib-either.rs b/src/test/run-pass/lib-either.rs new file mode 100644 index 00000000000..0ece8be64e9 --- /dev/null +++ b/src/test/run-pass/lib-either.rs @@ -0,0 +1,117 @@ +// xfail-stage0 + +use std; +import std::either::*; +import std::vec::len; + +fn test_either_left() { + auto val = left(10); + fn f_left(&int x) -> bool { x == 10 } + fn f_right(&uint x) -> bool { false } + assert (either(f_left, f_right, val)); +} + +fn test_either_right() { + auto val = right(10u); + fn f_left(&int x) -> bool { false } + fn f_right(&uint x) -> bool { x == 10u } + assert (either(f_left, f_right, val)); +} + +fn test_lefts() { + auto input = [left(10), + right(11), + left(12), + right(13), + left(14)]; + auto result = lefts(input); + assert (result == [10, 12, 14]); +} + +fn test_lefts_none() { + let vec[t[int, int]] input = [right(10), + right(10)]; + auto result = lefts(input); + assert (len(result) == 0u); +} + +fn test_lefts_empty() { + let vec[t[int, int]] input = []; + auto result = lefts(input); + assert (len(result) == 0u); +} + +fn test_rights() { + auto input = [left(10), + right(11), + left(12), + right(13), + left(14)]; + auto result = rights(input); + assert (result == [11, 13]); +} + +fn test_rights_none() { + let vec[t[int, int]] input = [left(10), + left(10)]; + auto result = rights(input); + assert (len(result) == 0u); +} + +fn test_rights_empty() { + let vec[t[int, int]] input = []; + auto result = rights(input); + assert (len(result) == 0u); +} + +fn test_partition() { + auto input = [left(10), + right(11), + left(12), + right(13), + left(14)]; + auto result = partition(input); + assert (result._0.(0) == 10); + assert (result._0.(1) == 12); + assert (result._0.(2) == 14); + assert (result._1.(0) == 11); + assert (result._1.(1) == 13); +} + +fn test_partition_no_lefts() { + let vec[t[int, int]] input = [right(10), + right(11)]; + auto result = partition(input); + assert (len(result._0) == 0u); + assert (len(result._1) == 2u); +} + +fn test_partition_no_rights() { + let vec[t[int, int]] input = [left(10), + left(11)]; + auto result = partition(input); + assert (len(result._0) == 2u); + assert (len(result._1) == 0u); +} + +fn test_partition_empty() { + let vec[t[int, int]] input = []; + auto result = partition(input); + assert (len(result._0) == 0u); + assert (len(result._1) == 0u); +} + +fn main() { + test_either_left(); + test_either_right(); + test_lefts(); + test_lefts_none(); + test_lefts_empty(); + test_rights(); + test_rights_none(); + test_rights_empty(); + test_partition(); + test_partition_no_lefts(); + test_partition_no_rights(); + test_partition_empty(); +} \ No newline at end of file diff --git a/src/test/run-pass/simple-anon-objs.rs b/src/test/run-pass/simple-anon-objs.rs index 323c427e485..df56f4810ee 100644 --- a/src/test/run-pass/simple-anon-objs.rs +++ b/src/test/run-pass/simple-anon-objs.rs @@ -1,7 +1,6 @@ // xfail-stage0 -// xfail-stage1 use std; fn main() { @@ -11,10 +10,24 @@ fn main() { auto my_a = a(); // Extending an object with a new method - auto my_b = anon obj; - assert (my_a.foo() == 2); - // FIXME: these raise a runtime error - //assert my_b.foo() == 2; + auto my_b = obj { + fn bar() -> int { + ret 3; + } + with my_a + }; + assert (my_a.foo() == 2); assert (my_b.bar() == 3); -} \ No newline at end of file + + auto my_c = obj { + fn baz() -> int { + ret 4; + } + with my_b + }; + + assert (my_c.baz() == 4); + +} +