Merge branch 'master' of github.com:graydon/rust into fastcall

This commit is contained in:
Eric Holk 2011-06-15 17:45:24 -07:00
commit 260aa408f3
28 changed files with 1144 additions and 738 deletions

View File

@ -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: $@)

View File

@ -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;

View File

@ -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.
*

View File

@ -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

View File

@ -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);

View File

@ -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 != ']') {

View File

@ -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 {

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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); }
}

View File

@ -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)];

View File

@ -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 (_) { }
}

View File

@ -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); }

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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
View 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:
//

View File

@ -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 {

View File

@ -22,6 +22,7 @@ mod task;
// Utility modules.
mod either;
mod option;
mod util;

View File

@ -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:

View 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() { }

View File

@ -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) {
}

View File

@ -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 } ;
}

View File

@ -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() {
}

View 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();
}

View File

@ -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);
}