Merge branch 'master' of github.com:graydon/rust into fastcall
This commit is contained in:
commit
260aa408f3
11
mk/stage3.mk
11
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: $@)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 != ']') {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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); }
|
||||
}
|
||||
|
@ -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)];
|
||||
|
@ -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 (_) { }
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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 +=
|
||||
"<tag#" + util::common::istr(id._0) + ":" +
|
||||
util::common::istr(id._1) + ">";
|
||||
"<tag#" + istr(id._0) + ":" + istr(id._1) + ">";
|
||||
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 += "<T" + util::common::istr(v) + ">"; }
|
||||
case (ty_var(?v)) { s += "<T" + istr(v) + ">"; }
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
64
src/lib/either.rs
Normal file
64
src/lib/either.rs
Normal file
@ -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:
|
||||
//
|
@ -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 {
|
||||
|
@ -22,6 +22,7 @@ mod task;
|
||||
|
||||
// Utility modules.
|
||||
|
||||
mod either;
|
||||
mod option;
|
||||
mod util;
|
||||
|
||||
|
@ -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:
|
||||
|
8
src/test/compile-fail/ext-after-attrib.rs
Normal file
8
src/test/compile-fail/ext-after-attrib.rs
Normal file
@ -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() { }
|
@ -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) {
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
auto my_d = obj() { with my_a } ;
|
||||
|
||||
}
|
||||
|
@ -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() { }
|
||||
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() {
|
||||
}
|
||||
|
117
src/test/run-pass/lib-either.rs
Normal file
117
src/test/run-pass/lib-either.rs
Normal file
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
auto my_c = obj {
|
||||
fn baz() -> int {
|
||||
ret 4;
|
||||
}
|
||||
with my_b
|
||||
};
|
||||
|
||||
assert (my_c.baz() == 4);
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user