Peter Hull <peterhull90@gmail.com>
Ralph Giles <giles@thaumas.net>
Rafael Ávila de Espíndola <respindola@mozilla.com>
+Rob Arnold <robarnold@cs.cmu.edu>
Roy Frostig <rfrostig@mozilla.com>
Tim Chevalier <chevalier@alum.wellesley.edu>
CFG_RUNTIME :=$(call CFG_LIB_NAME,rustrt)
CFG_RUSTLLVM :=$(call CFG_LIB_NAME,rustllvm)
CFG_STDLIB :=$(call CFG_LIB_NAME,std)
+CFG_LIBRUSTC :=$(call CFG_LIB_NAME,rustc)
# version-string calculation
CFG_GIT_DIR := $(CFG_SRC_DIR).git
-# At the moment the fuzzer only exists in stage2. That's the first
-# stage built by the non-snapshot compiler so it seems a convenient
-# stage to work at.
+# At the moment the fuzzer only exists in stage1.
FUZZER_CRATE := $(S)src/fuzzer/fuzzer.rc
FUZZER_INPUTS := $(wildcard $(addprefix $(S)src/fuzzer/, *.rs))
-stage2/fuzzer.o: $(FUZZER_CRATE) $(FUZZER_INPUTS) $(SREQ1)
- @$(call E, compile: $@)
- $(STAGE1) -c -o $@ $<
-
-stage2/fuzzer$(X): stage2/fuzzer.o $(SREQ1)
- @$(call E, link [gcc]: $@)
- $(Q)gcc $(CFG_GCCISH_CFLAGS) rt/main.o stage2/glue.o -o $@ $< \
- -Lstage2 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm -lrustc
- @# dsymutil sometimes fails or prints a warning, but the
- @# program still runs. Since it simplifies debugging other
- @# programs, I\'ll live with the noise.
- -$(Q)$(CFG_DSYMUTIL) $@
+stage1/fuzzer$(X): $(FUZZER_CRATE) $(FUZZER_INPUTS) $(SREQ1)
+ @$(call E, compile_and_link: $@)
+ $(STAGE1) -o $@ $<
stage1/%$(X): $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ0) stage0/intrinsics.bc
@$(call E, compile_and_link: $@)
$(STAGE0) -o $@ $<
+
+stage1/lib/$(CFG_LIBRUSTC): $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ1) \
+ stage1/intrinsics.bc
+ @$(call E, compile_and_link: $@)
+ $(STAGE1) --shared -o $@ $<
sha.input_str(len_and_str(name));
}
case (ast::meta_list(_, _)) {
+ // FIXME (#607): Implement this
fail "unimplemented meta_item variant";
}
}
import front::token;
import front::eval;
import front::ast;
+import front::attr;
import middle::trans;
import middle::resolve;
import middle::ty;
tag pp_mode { ppm_normal; ppm_typed; ppm_identified; }
-fn default_environment(session::session sess, str argv0, str input) ->
- eval::env {
+fn default_configuration(session::session sess, str argv0, str input) ->
+ ast::crate_cfg {
auto libc =
alt (sess.get_targ_cfg().os) {
case (session::os_win32) { "msvcrt.dll" }
case (session::os_linux) { "libc.so.6" }
case (_) { "libc.so" }
};
+
+ auto mk = attr::mk_name_value_item;
+
ret [ // Target bindings.
- tup("target_os", eval::val_str(std::os::target_os())),
- tup("target_arch", eval::val_str("x86")),
- tup("target_libc", eval::val_str(libc)),
+ mk("target_os", std::os::target_os()),
+ mk("target_arch", "x86"),
+ mk("target_libc", libc),
// Build bindings.
- tup("build_compiler", eval::val_str(argv0)),
- tup("build_input", eval::val_str(input))];
+ mk("build_compiler", argv0),
+ mk("build_input", input)];
+}
+
+fn build_configuration(session::session sess, str argv0,
+ str input) -> ast::crate_cfg {
+ // Combine the configuration requested by the session (command line) with
+ // some default configuration items
+ ret sess.get_opts().cfg + default_configuration(sess, argv0, input);
+}
+
+// Convert strings provided as --cfg [cfgspec] into a crate_cfg
+fn parse_cfgspecs(&vec[str] cfgspecs) -> ast::crate_cfg {
+ // FIXME: It would be nice to use the parser to parse all varieties of
+ // meta_item here. At the moment we just support the meta_word variant.
+ fn to_meta_word(&str cfgspec) -> @ast::meta_item {
+ attr::mk_word_item(cfgspec)
+ }
+ ret vec::map(to_meta_word, cfgspecs);
}
fn parse_input(session::session sess, parser::parser p, str input) ->
ret rv;
}
-fn compile_input(session::session sess, eval::env env, str input,
+fn compile_input(session::session sess, ast::crate_cfg cfg, str input,
str output) {
auto time_passes = sess.get_opts().time_passes;
- auto p = parser::new_parser(sess, env, input, 0u, 0);
+ auto p = parser::new_parser(sess, cfg, input, 0u, 0);
auto crate =
time(time_passes, "parsing", bind parse_input(sess, p, input));
if (sess.get_opts().output_type == link::output_type_none) { ret; }
bind link::write::run_passes(sess, llmod, output));
}
-fn pretty_print_input(session::session sess, eval::env env, str input,
- pp_mode ppm) {
- auto p = front::parser::new_parser(sess, env, input, 0u, 0);
+fn pretty_print_input(session::session sess, ast::crate_cfg cfg,
+ str input, pp_mode ppm) {
+ auto p = front::parser::new_parser(sess, cfg, input, 0u, 0);
auto crate = parse_input(sess, p, input);
auto mode;
alt (ppm) {
--emit-llvm produce an LLVM bitcode file
--save-temps write intermediate files in addition to normal output
--stats gather and report various compilation statistics
+ --cfg [cfgspec] configure the compilation environment
--time-passes time the individual phases of the compiler
--time-llvm-passes time the individual phases of the LLVM backend
--sysroot <path> override the system root (default: rustc's directory)
case (none) { get_default_sysroot(binary) }
case (some(?s)) { s }
};
+ auto cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg"));
let @session::options sopts =
@rec(shared=shared,
optimize=opt_level,
time_llvm_passes=time_llvm_passes,
output_type=output_type,
library_search_paths=library_search_paths,
- sysroot=sysroot);
+ sysroot=sysroot,
+ cfg=cfg);
ret sopts;
}
auto target_crate_num = 0;
auto sess =
session::session(target_crate_num, target_cfg, sopts, crate_cache, [],
- [], front::codemap::new_codemap(), 0u);
+ [], [], front::codemap::new_codemap(), 0u);
ret sess;
}
optflag("c"), optopt("o"), optflag("g"), optflag("save-temps"),
optopt("sysroot"), optflag("stats"), optflag("time-passes"),
optflag("time-llvm-passes"), optflag("no-typestate"),
- optflag("noverify")];
+ optflag("noverify"), optmulti("cfg")];
auto binary = vec::shift[str](args);
auto binary_dir = fs::dirname(binary);
auto match =
}
auto ifile = match.free.(0);
let str saved_out_filename = "";
- auto env = default_environment(sess, binary, ifile);
+ auto cfg = build_configuration(sess, binary, ifile);
auto pretty =
option::map[str,
pp_mode](bind parse_pretty(sess, _),
auto ls = opt_present(match, "ls");
alt (pretty) {
case (some[pp_mode](?ppm)) {
- pretty_print_input(sess, env, ifile, ppm);
+ pretty_print_input(sess, cfg, ifile, ppm);
ret;
}
case (none[pp_mode]) {/* continue */ }
case (link::output_type_exe) { parts += ["o"]; }
}
auto ofile = str::connect(parts, ".");
- compile_input(sess, env, ifile, ofile);
+ compile_input(sess, cfg, ifile, ofile);
}
case (some(?ofile)) {
// FIXME: what about windows? This will create a foo.exe.o.
}
case (_) { temp_filename = ofile; }
}
- compile_input(sess, env, ifile, temp_filename);
+ compile_input(sess, cfg, ifile, temp_filename);
}
}
saved_out_filename, saved_out_filename + ".o"];
auto shared_cmd;
- alt (sess.get_targ_cfg().os) {
- case (session::os_win32) {
- shared_cmd = "-shared";
- }
- case (session::os_macos) {
+ auto os = sess.get_targ_cfg().os;
+ if (os == session::os_macos) {
shared_cmd = "-dynamiclib";
- }
- case (session::os_linux) {
+ } else {
shared_cmd = "-shared";
- }
}
// Converts a library file name into a gcc -l argument
case (_) { rmext(filename) }
};
}
-
+
for (str cratepath in sess.get_used_crate_files()) {
auto dir = fs::dirname(cratepath);
if (dir != "") {
gcc_args += ["-l" + libarg];
}
+ gcc_args += sess.get_used_link_args();
auto used_libs = sess.get_used_libraries();
for (str l in used_libs) {
gcc_args += ["-l" + l];
if (sopts.shared) {
gcc_args += [shared_cmd];
} else {
- // FIXME: having -Lrustllvm hardcoded in here is hack
- // FIXME: same for -lm
- gcc_args += ["-Lrustllvm", "-lm", main];
+ // FIXME: why do we hardcode -lm?
+ gcc_args += ["-lm", main];
}
// We run 'gcc' here
import std::option;
import std::option::some;
import std::option::none;
+import std::str;
tag os { os_win32; os_macos; os_linux; }
bool time_llvm_passes,
back::link::output_type output_type,
vec[str] library_search_paths,
- str sysroot);
+ str sysroot,
+ // The crate config requested for the session, which may be combined
+ // with additional crate configurations during the compile process
+ ast::crate_cfg cfg);
type crate_metadata = rec(str name, vec[u8] data);
map::hashmap[int, crate_metadata] crates,
mutable vec[str] used_crate_files,
mutable vec[str] used_libraries,
+ mutable vec[str] used_link_args,
codemap::codemap cm,
mutable uint err_count) {
fn get_targ_cfg() -> @config { ret targ_cfg; }
crates.insert(num, metadata);
}
fn has_external_crate(int num) -> bool { ret crates.contains_key(num); }
- fn add_used_library(&str lib) {
+ fn add_used_link_args(&str args) {
+ used_link_args += str::split(args, ' ' as u8);
+ }
+ fn get_used_link_args() -> vec[str] {
+ ret used_link_args;
+ }
+ fn add_used_library(&str lib) -> bool {
if (lib == "") {
- ret;
+ ret false;
}
// A program has a small number of libraries, so a vector is probably
// a good data structure in here.
for (str l in used_libraries) {
if (l == lib) {
- ret;
+ ret false;
}
}
used_libraries += [lib];
+ ret true;
}
fn get_used_libraries() -> vec[str] {
ret used_libraries;
crate_cfg config);
tag crate_directive_ {
- cdir_expr(@expr);
-
- // FIXME: cdir_let should be eliminated
- // and redirected to the use of const stmt_decls inside
- // crate directive blocks.
- cdir_let(ident, @expr, vec[@crate_directive]);
cdir_src_mod(ident, option::t[filename], vec[attribute]);
cdir_dir_mod(ident, option::t[filename],
vec[@crate_directive], vec[attribute]);
type block_ = rec(vec[@stmt] stmts, option::t[@expr] expr, node_id id);
-type pat = spanned[pat_];
+type pat = rec(node_id id,
+ pat_ node,
+ span span);
tag pat_ {
- pat_wild(node_id);
- pat_bind(ident, node_id);
- pat_lit(@lit, node_id);
- pat_tag(path, vec[@pat], node_id);
+ pat_wild;
+ pat_bind(ident);
+ pat_lit(@lit);
+ pat_tag(path, vec[@pat]);
}
tag mutability { mut; imm; maybe_mut; }
expr_index(@expr, @expr);
expr_path(path);
expr_ext(path, vec[@expr], option::t[str], @expr);
- expr_fail(option::t[str]);
+ expr_fail(option::t[@expr]);
expr_break;
expr_cont;
expr_ret(option::t[@expr]);
}
}
+// Path stringification
+fn path_to_str(&ast::path pth) -> str {
+ auto result = str::connect(pth.node.idents, "::");
+ if (vec::len[@ast::ty](pth.node.types) > 0u) {
+ fn f(&@ast::ty t) -> str { ret pretty::pprust::ty_to_str(*t); }
+ result += "[";
+ result += str::connect(vec::map(f, pth.node.types), ",");
+ result += "]";
+ }
+ ret result;
+}
+
+
//
// Local Variables:
// mode: rust
import std::vec;
import std::option;
import front::ast;
+import util::common;
export attr_metas;
export find_linkage_metas;
export sort_meta_items;
export remove_meta_items_by_name;
export get_attr_name;
+export mk_name_value_item;
+export mk_list_item;
+export mk_word_item;
+export mk_attr;
// From a list of crate attributes get only the meta_items that impact crate
// linkage
metas += items;
}
case (_) {
- // FIXME: Maybe need a warning that this attr isn't
- // being used for linkage
+ log "ignoring link attribute that has incorrect type";
}
}
}
}
}
case (ast::meta_list(?na, ?la)) {
- // FIXME (#487): This involves probably sorting the list by name
+ // FIXME (#607): Needs implementing
+ // This involves probably sorting the list by name and
+ // meta_item variant
fail "unimplemented meta_item variant"
}
}
ret false;
}
+// FIXME: This needs to sort by meta_item variant in addition to the item name
fn sort_meta_items(&vec[@ast::meta_item] items) -> vec[@ast::meta_item] {
fn lteq(&@ast::meta_item ma, &@ast::meta_item mb) -> bool {
fn key(&@ast::meta_item m) -> ast::ident {
ret vec::filter_map(filter, items);
}
+fn span[T](&T item) -> common::spanned[T] {
+ ret rec(node=item, span=rec(lo=0u, hi=0u));
+}
+
+fn mk_name_value_item(ast::ident name, str value) -> @ast::meta_item {
+ ret @span(ast::meta_name_value(name, value));
+}
+
+fn mk_list_item(ast::ident name,
+ &vec[@ast::meta_item] items) -> @ast::meta_item {
+ ret @span(ast::meta_list(name, items));
+}
+
+fn mk_word_item(ast::ident name) -> @ast::meta_item {
+ ret @span(ast::meta_word(name));
+}
+
+fn mk_attr(@ast::meta_item item) -> ast::attribute {
+ ret span(rec(style = ast::attr_inner,
+ value = *item));
+}
+
//
// Local Variables:
// mode: rust
import std::option;
import std::option::some;
import std::option::none;
-import std::map::hashmap;
import driver::session;
-import ast::ident;
import front::parser::parser;
-import front::parser::spanned;
import front::parser::new_parser;
import front::parser::parse_inner_attrs_and_next;
import front::parser::parse_mod_items;
-import util::common;
-import util::common::filename;
-import util::common::span;
-import util::common::new_str_hash;
-
-// Simple dynamic-typed value type for eval_expr.
-tag val { val_bool(bool); val_int(int); val_str(str); }
+export eval_crate_directives_to_mod;
+export mode_parse;
tag eval_mode { mode_depend; mode_parse; }
-type env = vec[tup(ident, val)];
-
type ctx =
@rec(parser p,
eval_mode mode,
mutable vec[str] deps,
session::session sess,
mutable uint chpos,
- mutable int next_id);
-
-fn mk_env() -> env { ret []; }
-
-fn val_is_bool(val v) -> bool {
- alt (v) { case (val_bool(_)) { true } case (_) { false } }
-}
-
-fn val_is_int(val v) -> bool {
- alt (v) { case (val_int(_)) { true } case (_) { false } }
-}
-
-fn val_is_str(val v) -> bool {
- alt (v) { case (val_str(_)) { true } case (_) { false } }
-}
-
-fn val_as_bool(val v) -> bool {
- alt (v) { case (val_bool(?b)) { b } case (_) { fail } }
-}
-
-fn val_as_int(val v) -> int {
- alt (v) { case (val_int(?i)) { i } case (_) { fail } }
-}
-
-fn val_as_str(val v) -> str {
- alt (v) { case (val_str(?s)) { s } case (_) { fail } }
-}
-
-fn lookup(session::session sess, env e, span sp, ident i) -> val {
- for (tup(ident, val) pair in e) {
- if (str::eq(i, pair._0)) { ret pair._1; }
- }
- sess.span_fatal(sp, "unknown variable: " + i)
-}
-
-fn eval_lit(ctx cx, span sp, @ast::lit lit) -> val {
- alt (lit.node) {
- case (ast::lit_bool(?b)) { val_bool(b) }
- case (ast::lit_int(?i)) { val_int(i) }
- case (ast::lit_str(?s, _)) { val_str(s) }
- case (_) { cx.sess.span_fatal(sp, "evaluating unsupported literal") }
- }
-}
-
-fn eval_expr(ctx cx, env e, @ast::expr x) -> val {
- alt (x.node) {
- case (ast::expr_path(?pth)) {
- if (vec::len[ident](pth.node.idents) == 1u &&
- vec::len[@ast::ty](pth.node.types) == 0u) {
- ret lookup(cx.sess, e, x.span, pth.node.idents.(0));
- }
- cx.sess.span_fatal(x.span, "evaluating structured path-name");
- }
- case (ast::expr_lit(?lit)) { ret eval_lit(cx, x.span, lit); }
- case (ast::expr_unary(?op, ?a)) {
- auto av = eval_expr(cx, e, a);
- alt (op) {
- case (ast::not) {
- if (val_is_bool(av)) { ret val_bool(!val_as_bool(av)); }
- cx.sess.span_fatal(x.span, "bad types in '!' expression");
- }
- case (_) {
- cx.sess.span_fatal(x.span, "evaluating unsupported unop");
- }
- }
- }
- case (ast::expr_binary(?op, ?a, ?b)) {
- auto av = eval_expr(cx, e, a);
- auto bv = eval_expr(cx, e, b);
- alt (op) {
- case (ast::add) {
- if (val_is_int(av) && val_is_int(bv)) {
- ret val_int(val_as_int(av) + val_as_int(bv));
- }
- if (val_is_str(av) && val_is_str(bv)) {
- ret val_str(val_as_str(av) + val_as_str(bv));
- }
- cx.sess.span_fatal(x.span, "bad types in '+' expression");
- }
- case (ast::sub) {
- if (val_is_int(av) && val_is_int(bv)) {
- ret val_int(val_as_int(av) - val_as_int(bv));
- }
- cx.sess.span_fatal(x.span, "bad types in '-' expression");
- }
- case (ast::mul) {
- if (val_is_int(av) && val_is_int(bv)) {
- ret val_int(val_as_int(av) * val_as_int(bv));
- }
- cx.sess.span_fatal(x.span, "bad types in '*' expression");
- }
- case (ast::div) {
- if (val_is_int(av) && val_is_int(bv)) {
- ret val_int(val_as_int(av) / val_as_int(bv));
- }
- cx.sess.span_fatal(x.span, "bad types in '/' expression");
- }
- case (ast::rem) {
- if (val_is_int(av) && val_is_int(bv)) {
- ret val_int(val_as_int(av) % val_as_int(bv));
- }
- cx.sess.span_fatal(x.span, "bad types in '%' expression");
- }
- case (ast::and) {
- if (val_is_bool(av) && val_is_bool(bv)) {
- ret val_bool(val_as_bool(av) && val_as_bool(bv));
- }
- cx.sess.span_fatal(x.span,
- "bad types in '&&' expression");
- }
- case (ast::or) {
- if (val_is_bool(av) && val_is_bool(bv)) {
- ret val_bool(val_as_bool(av) || val_as_bool(bv));
- }
- cx.sess.span_fatal(x.span,
- "bad types in '||' expression");
- }
- case (ast::eq) {
- ret val_bool(val_eq(cx.sess, x.span, av, bv));
- }
- case (ast::ne) {
- ret val_bool(!val_eq(cx.sess, x.span, av, bv));
- }
- case (_) {
- cx.sess.span_fatal(x.span,
- "evaluating unsupported binop");
- }
- }
- }
- case (_) {
- cx.sess.span_fatal(x.span, "evaluating unsupported expression");
- }
- }
- fail;
-}
-
-fn val_eq(session::session sess, span sp, val av, val bv) -> bool {
- if (val_is_bool(av) && val_is_bool(bv)) {
- val_as_bool(av) == val_as_bool(bv)
- } else if (val_is_int(av) && val_is_int(bv)) {
- val_as_int(av) == val_as_int(bv)
- } else if (val_is_str(av) && val_is_str(bv)) {
- str::eq(val_as_str(av), val_as_str(bv))
- } else { sess.span_fatal(sp, "bad types in comparison") }
-}
+ mutable int next_id,
+ ast::crate_cfg cfg);
-fn eval_crate_directives(ctx cx, env e, vec[@ast::crate_directive] cdirs,
+fn eval_crate_directives(ctx cx, vec[@ast::crate_directive] cdirs,
str prefix, &mutable vec[@ast::view_item] view_items,
&mutable vec[@ast::item] items) {
for (@ast::crate_directive sub_cdir in cdirs) {
- eval_crate_directive(cx, e, sub_cdir, prefix, view_items, items);
+ eval_crate_directive(cx, sub_cdir, prefix, view_items, items);
}
}
-fn eval_crate_directives_to_mod(ctx cx, env e,
+fn eval_crate_directives_to_mod(ctx cx,
vec[@ast::crate_directive] cdirs, str prefix)
-> ast::_mod {
let vec[@ast::view_item] view_items = [];
let vec[@ast::item] items = [];
- eval_crate_directives(cx, e, cdirs, prefix, view_items, items);
+ eval_crate_directives(cx, cdirs, prefix, view_items, items);
ret rec(view_items=view_items, items=items);
}
-fn eval_crate_directive_block(ctx cx, env e, &ast::block blk, str prefix,
+fn eval_crate_directive_block(ctx cx, &ast::block blk, str prefix,
&mutable vec[@ast::view_item] view_items,
&mutable vec[@ast::item] items) {
for (@ast::stmt s in blk.node.stmts) {
alt (s.node) {
case (ast::stmt_crate_directive(?cdir)) {
- eval_crate_directive(cx, e, cdir, prefix, view_items, items);
+ eval_crate_directive(cx, cdir, prefix, view_items, items);
}
case (_) {
cx.sess.span_fatal(s.span,
}
}
-fn eval_crate_directive_expr(ctx cx, env e, @ast::expr x, str prefix,
- &mutable vec[@ast::view_item] view_items,
- &mutable vec[@ast::item] items) {
- alt (x.node) {
- case (ast::expr_if(?cond, ?thn, ?elopt)) {
- auto cv = eval_expr(cx, e, cond);
- if (!val_is_bool(cv)) {
- cx.sess.span_fatal(x.span, "bad cond type in 'if'");
- }
- if (val_as_bool(cv)) {
- ret eval_crate_directive_block(cx, e, thn, prefix, view_items,
- items);
- }
- alt (elopt) {
- case (some(?els)) {
- ret eval_crate_directive_expr(cx, e, els, prefix,
- view_items, items);
- }
- case (_) {
- // Absent-else is ok.
-
- }
- }
- }
- case (ast::expr_alt(?v, ?arms)) {
- auto vv = eval_expr(cx, e, v);
- for (ast::arm arm in arms) {
- alt (arm.pat.node) {
- case (ast::pat_lit(?lit, _)) {
- auto pv = eval_lit(cx, arm.pat.span, lit);
- if (val_eq(cx.sess, arm.pat.span, vv, pv)) {
- ret eval_crate_directive_block(cx, e, arm.block,
- prefix, view_items,
- items);
- }
- }
- case (ast::pat_wild(_)) {
- ret eval_crate_directive_block(cx, e, arm.block,
- prefix, view_items,
- items);
- }
- case (_) {
- cx.sess.span_fatal(arm.pat.span,
- "bad pattern type in 'alt'");
- }
- }
- }
- cx.sess.span_fatal(x.span, "no cases matched in 'alt'");
- }
- case (ast::expr_block(?block)) {
- ret eval_crate_directive_block(cx, e, block, prefix, view_items,
- items);
- }
- case (_) { cx.sess.span_fatal(x.span, "unsupported expr type"); }
- }
-}
-
-fn eval_crate_directive(ctx cx, env e, @ast::crate_directive cdir, str prefix,
+fn eval_crate_directive(ctx cx, @ast::crate_directive cdir, str prefix,
&mutable vec[@ast::view_item] view_items,
&mutable vec[@ast::item] items) {
alt (cdir.node) {
- case (ast::cdir_let(?id, ?x, ?cdirs)) {
- auto v = eval_expr(cx, e, x);
- auto e0 = [tup(id, v)] + e;
- eval_crate_directives(cx, e0, cdirs, prefix, view_items, items);
- }
- case (ast::cdir_expr(?x)) {
- eval_crate_directive_expr(cx, e, x, prefix, view_items, items);
- }
case (ast::cdir_src_mod(?id, ?file_opt, ?attrs)) {
auto file_path = id + ".rs";
alt (file_opt) {
};
if (cx.mode == mode_depend) { cx.deps += [full_path]; ret; }
auto p0 =
- new_parser(cx.sess, e, full_path, cx.chpos,
+ new_parser(cx.sess, cx.cfg, full_path, cx.chpos,
cx.next_id);
auto inner_attrs = parse_inner_attrs_and_next(p0);
auto mod_attrs = attrs + inner_attrs._0;
} else {
prefix + std::fs::path_sep() + path
};
- auto m0 = eval_crate_directives_to_mod(cx, e, cdirs, full_path);
+ auto m0 = eval_crate_directives_to_mod(cx, cdirs, full_path);
auto i = @rec(ident=id,
attrs=attrs,
id=cx.next_id,
fn noop_fold_crate_directive(&crate_directive_ cd, ast_fold fld)
-> crate_directive_ {
ret alt(cd) {
- case(cdir_expr(?e)) { cdir_expr(fld.fold_expr(e)) }
- case(cdir_let(?id, ?e, ?cds)) {
- cdir_let(fld.fold_ident(id), fld.fold_expr(e),
- map(fld.fold_crate_directive, cds))
- }
case(cdir_src_mod(?id,?fname,?attrs)) {
cdir_src_mod(fld.fold_ident(id), fname, attrs)
}
fn noop_fold_pat(&pat_ p, ast_fold fld) -> pat_ {
ret alt (p) {
- case (pat_wild(_)) { p }
- case (pat_bind(?id, ?d)) { pat_bind(fld.fold_ident(id), d)}
- case (pat_lit(_, _)) { p }
- case (pat_tag(?pth, ?pats, ?nid)) {
- pat_tag(fld.fold_path(pth), map(fld.fold_pat, pats), nid)
- }
+ case (pat_wild) { p }
+ case (pat_bind(?ident)) { pat_bind(fld.fold_ident(ident))}
+ case (pat_lit(_)) { p }
+ case (pat_tag(?pth, ?pats)) {
+ pat_tag(fld.fold_path(pth), map(fld.fold_pat, pats))
+ }
};
}
ret afp.fold_arm(x, f);
}
fn f_pat(&ast_fold_precursor afp, ast_fold f, &@pat x) -> @pat {
- ret @rec(node=afp.fold_pat(x.node, f), span=x.span);
+ ret @rec(id=x.id, node=afp.fold_pat(x.node, f), span=x.span);
}
fn f_decl(&ast_fold_precursor afp, ast_fold f, &@decl x) -> @decl {
ret @rec(node=afp.fold_decl(x.node, f), span=x.span);
import std::either::left;
import std::either::right;
import std::map::hashmap;
+import token::can_begin_expr;
import driver::session;
import util::common;
import util::common::filename;
fn restrict(restriction) ;
fn get_restriction() -> restriction ;
fn get_file_type() -> file_type ;
- fn get_env() -> eval::env ;
fn get_cfg() -> ast::crate_cfg;
fn get_session() -> session::session ;
fn get_span() -> common::span ;
fn next_id() -> ast::node_id ;
};
-fn new_parser(session::session sess, eval::env env,
+fn new_parser(session::session sess, ast::crate_cfg cfg,
str path, uint pos, ast::node_id next_id) -> parser {
obj stdio_parser(session::session sess,
- eval::env env,
ast::crate_cfg cfg,
file_type ftype,
mutable token::token tok,
fn get_hi_pos() -> uint { ret hi; }
fn get_last_lo_pos() -> uint { ret last_lo; }
fn get_file_type() -> file_type { ret ftype; }
- fn get_env() -> eval::env { ret env; }
fn get_cfg() -> ast::crate_cfg { ret cfg; }
fn get_prec_table() -> vec[op_spec] { ret precs; }
fn get_str(token::str_num i) -> str {
fn next_id() -> ast::node_id { ret next_id_var; }
}
- auto cfg = {
- fn m(&tup(ast::ident, eval::val) item) -> @ast::meta_item {
- auto name = item._0;
- auto value = eval::val_as_str(item._1);
- auto meta_item_ = ast::meta_name_value(name, value);
- ret @rec(node=meta_item_,
- span=rec(lo=0u,hi=0u));
- }
- vec::map(m, env)
- };
-
auto ftype = SOURCE_FILE;
if (str::ends_with(path, ".rc")) { ftype = CRATE_FILE; }
auto srdr = io::file_reader(path);
lexer::consume_whitespace_and_comments(rdr);
auto npos = rdr.get_chpos();
- ret stdio_parser(sess, env, cfg, ftype, lexer::next_token(rdr),
+ ret stdio_parser(sess, cfg, ftype, lexer::next_token(rdr),
npos, npos, npos, UNRESTRICTED, rdr,
prec_table(), next_id, bad_expr_word_table(),
ext::syntax_expander_table());
}
-
// These are the words that shouldn't be allowed as value identifiers,
// because, if used at the start of a line, they will cause the line to be
// interpreted as a specific kind of statement, which would be confusing.
lo = ex_ext.span.lo;
ex = ex_ext.node;
} else if (eat_word(p, "fail")) {
- auto msg;
- alt (p.peek()) {
- case (token::LIT_STR(?s)) { msg = some(p.get_str(s)); p.bump(); }
- case (_) { msg = none; }
+ if (can_begin_expr(p.peek())) {
+ auto e = parse_expr(p);
+ hi = e.span.hi;
+ ex = ast::expr_fail(some(e));
+ }
+ else {
+ ex = ast::expr_fail(none);
}
- ex = ast::expr_fail(msg);
} else if (eat_word(p, "log")) {
auto e = parse_expr(p);
ex = ast::expr_log(1, e);
hi = es.span.hi;
ex = ast::expr_call(f, es.node);
} else if (is_ident(p.peek()) && !is_word(p, "true") &&
- !is_word(p, "false")) {
+ !is_word(p, "false")) {
check_bad_word(p);
auto pth = parse_path_and_ty_param_substs(p);
hi = pth.span.hi;
fn parse_syntax_ext_naked(&parser p, uint lo) -> @ast::expr {
auto pth = parse_path(p);
+ if (vec::len(pth.node.idents) == 0u) {
+ p.fatal("expected a syntax expander name");
+ }
auto es = parse_seq(token::LPAREN, token::RPAREN,
some(token::COMMA), parse_expr, p);
auto hi = es.span.hi;
alt (p.peek()) {
case (token::UNDERSCORE) {
p.bump();
- pat = ast::pat_wild(p.get_id());
+ pat = ast::pat_wild;
}
case (token::QUES) {
p.bump();
case (token::IDENT(?id, _)) {
hi = p.get_hi_pos();
p.bump();
- pat =
- ast::pat_bind(p.get_str(id), p.get_id());
+ pat = ast::pat_bind(p.get_str(id));
}
case (?tok) {
p.fatal("expected identifier after '?' in pattern but " +
if (!is_ident(tok) || is_word(p, "true") || is_word(p, "false")) {
auto lit = parse_lit(p);
hi = lit.span.hi;
- pat = ast::pat_lit(@lit, p.get_id());
+ pat = ast::pat_lit(@lit);
} else {
auto tag_path = parse_path_and_ty_param_substs(p);
hi = tag_path.span.hi;
}
case (_) { args = []; }
}
- pat = ast::pat_tag(tag_path, args, p.get_id());
+ pat = ast::pat_tag(tag_path, args);
}
}
}
- ret @spanned(lo, hi, pat);
+ ret @rec(id=p.get_id(), node=pat, span=rec(lo=lo, hi=hi));
}
fn parse_local_full(&option::t[@ast::ty] tyopt, &parser p)
auto id = parse_ident(p);
auto ty_params = parse_ty_params(p);
let vec[ast::variant] variants = [];
+ // Newtype syntax
+ if (p.peek() == token::EQ) {
+ if (p.get_bad_expr_words().contains_key(id)) {
+ p.fatal("found " + id + " in tag constructor position");
+ }
+ p.bump();
+ auto ty = parse_ty(p);
+ expect(p, token::SEMI);
+ auto variant = spanned(ty.span.lo, ty.span.hi,
+ rec(name=id,
+ args=[rec(ty=ty, id=p.get_id())],
+ id=p.get_id()));
+ ret mk_item(p, lo, ty.span.hi, id,
+ ast::item_tag([variant], ty_params), attrs);
+ }
expect(p, token::LBRACE);
while (p.peek() != token::RBRACE) {
auto tok = p.peek();
auto hi = p.get_hi_pos();
expect(p, token::SEMI);
ret spanned(lo, hi, ast::cdir_auth(n, a));
- } else if (eat_word(p, "let")) {
- expect(p, token::LPAREN);
- auto id = parse_value_ident(p);
- expect(p, token::EQ);
- auto x = parse_expr(p);
- expect(p, token::RPAREN);
- expect(p, token::LBRACE);
- auto v = parse_crate_directives(p, token::RBRACE, []);
- auto hi = p.get_hi_pos();
- expect(p, token::RBRACE);
- ret spanned(lo, hi, ast::cdir_let(id, x, v));
} else if (is_view_item(p)) {
auto vi = parse_view_item(p);
ret spanned(lo, vi.span.hi, ast::cdir_view_item(vi));
} else {
- auto x = parse_expr(p);
- ret spanned(lo, x.span.hi, ast::cdir_expr(x));
+ ret p.fatal("expected crate directive");
}
- fail;
}
fn parse_crate_directives(&parser p, token::token term,
mutable deps=deps,
sess=p.get_session(),
mutable chpos=p.get_chpos(),
- mutable next_id=p.next_id());
+ mutable next_id=p.next_id(),
+ cfg = p.get_cfg());
auto m =
- eval::eval_crate_directives_to_mod(cx, p.get_env(), cdirs, prefix);
+ eval::eval_crate_directives_to_mod(cx, cdirs, prefix);
auto hi = p.get_hi_pos();
expect(p, token::EOF);
ret @spanned(lo, hi, rec(directives=cdirs,
case (EOF) { ret "<eof>"; }
}
}
+
+
+pred can_begin_expr(token t) -> bool {
+ alt (t) {
+ case (LPAREN) { true }
+ case (LBRACE) { true }
+ case (IDENT(_,_)) { true }
+ case (UNDERSCORE) { true }
+ case (TILDE) { true }
+ case (LIT_INT(_)) { true }
+ case (LIT_UINT(_)) { true }
+ case (LIT_MACH_INT(_,_)) { true }
+ case (LIT_FLOAT(_)) { true }
+ case (LIT_MACH_FLOAT(_,_)) { true }
+ case (LIT_STR(_)) { true }
+ case (LIT_CHAR(_)) { true }
+ case (POUND) { true }
+ case (AT) { true }
+ case (_) { false }
+ }
+}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
const uint LLVMRealULE = 13u;
const uint LLVMRealUNE = 14u;
+#[link_args = "-Lrustllvm"]
native mod llvm = "rustllvm" {
type ModuleRef;
str::buf(""));
}
+ fn is_terminated() -> bool {
+ ret *terminated;
+ }
+
drop {
llvm::LLVMDisposeBuilder(B);
}
fn visit_item(env e, &@ast::item i) {
alt (i.node) {
case (ast::item_native_mod(?m)) {
- alt (m.abi) {
- case (ast::native_abi_rust) {
- e.sess.add_used_library(m.native_name);
- }
- case (ast::native_abi_cdecl) {
- e.sess.add_used_library(m.native_name);
- }
- case (ast::native_abi_llvm) {
- }
- case (ast::native_abi_rust_intrinsic) {
+ if (m.abi != ast::native_abi_rust &&
+ m.abi != ast::native_abi_cdecl) {
+ ret;
+ }
+ if (!e.sess.add_used_library(m.native_name)) {
+ ret;
+ }
+ for (ast::attribute a in i.attrs) {
+ auto v = a.node.value.node;
+ alt (v) {
+ case (ast::meta_name_value(?i, ?s)) {
+ if (i != "link_args") {
+ cont;
+ }
+ e.sess.add_used_link_args(s);
+ }
+ case (_) {
+ }
}
}
}
import std::io;
import std::map::hashmap;
import front::ast;
+import front::attr;
import middle::ty;
import tags::*;
import tydecode::parse_def_id;
ebml::tagged_docs(md, tag_meta_item_word)) {
auto nd = ebml::get_doc(meta_item_doc, tag_meta_item_name);
auto n = str::unsafe_from_bytes(ebml::doc_data(nd));
- items += [@rec(node=ast::meta_word(n),
- span=rec(lo=0u, hi=0u))];
+ items += [attr::mk_word_item(n)];
}
for each (ebml::doc meta_item_doc in
ebml::tagged_docs(md, tag_meta_item_name_value)) {
auto vd = ebml::get_doc(meta_item_doc, tag_meta_item_value);
auto n = str::unsafe_from_bytes(ebml::doc_data(nd));
auto v = str::unsafe_from_bytes(ebml::doc_data(vd));
- items += [@rec(node=ast::meta_name_value(n, v),
- span=rec(lo=0u, hi=0u))];
+ items += [attr::mk_name_value_item(n, v)];
}
for each (ebml::doc meta_item_doc in
ebml::tagged_docs(md, tag_meta_item_list)) {
auto nd = ebml::get_doc(meta_item_doc, tag_meta_item_name);
auto n = str::unsafe_from_bytes(ebml::doc_data(nd));
auto subitems = get_meta_items(meta_item_doc);
- items += [@rec(node=ast::meta_list(n, subitems),
- span=rec(lo=0u, hi=0u))];
+ items += [attr::mk_list_item(n, subitems)];
}
ret items;
}
case (native_item_ty) {
encode_def_id(ebml_w, local_def(nitem.id));
encode_kind(ebml_w, 'T' as u8);
- encode_type(cx, ebml_w, ty::mk_native(cx.tcx));
+ encode_type(cx, ebml_w,
+ ty::mk_native(cx.tcx, local_def(nitem.id)));
}
case (native_item_fn(_, _, ?tps)) {
encode_def_id(ebml_w, local_def(nitem.id));
// So there's a special crate attribute called 'link' which defines the
// metadata that Rust cares about for linking crates. This attribute requires
-// name and value attributes, so if the user didn't provide them we will throw
+// 'name' and 'vers' items, so if the user didn't provide them we will throw
// them in anyway with default values.
fn synthesize_crate_attrs(&@crate_ctxt cx,
&@crate crate) -> vec[attribute] {
&vec[@meta_item] items)
-> attribute {
- auto bogus_span = rec(lo = 0u, hi = 0u);
+ assert cx.link_meta.name != "";
+ assert cx.link_meta.vers != "";
- auto name_item_ = meta_name_value("name", cx.link_meta.name);
- auto name_item = rec(node=name_item_,
- span=bogus_span);
-
- auto vers_item_ = meta_name_value("vers", cx.link_meta.vers);
- auto vers_item = rec(node=vers_item_,
- span=bogus_span);
+ auto name_item = attr::mk_name_value_item("name",
+ cx.link_meta.name);
+ auto vers_item = attr::mk_name_value_item("vers",
+ cx.link_meta.vers);
auto other_items = {
auto tmp = attr::remove_meta_items_by_name(items, "name");
attr::remove_meta_items_by_name(tmp, "vers")
};
- auto meta_items = [@name_item] + [@vers_item] + other_items;
-
- auto link_item_ = meta_list("link", meta_items);
- auto link_item = rec(node=link_item_,
- span=bogus_span);
-
- auto attr_ = rec(style = attr_inner,
- value = link_item);
- auto attr = rec(node=attr_,
- span=bogus_span);
+ auto meta_items = [name_item] + [vers_item] + other_items;
+ auto link_item = attr::mk_list_item("link", meta_items);
- ret attr;
+ ret attr::mk_attr(link_item);
}
let vec[attribute] attrs = [];
ret ty::mk_res(st.tcx, def, inner, params);
}
case ('X') { ret ty::mk_var(st.tcx, parse_int(st)); }
- case ('E') { ret ty::mk_native(st.tcx); }
+ case ('E') {
+ auto def = parse_def(st, sd);
+ ret ty::mk_native(st.tcx, def);
+ }
case ('Y') { ret ty::mk_type(st.tcx); }
case ('#') {
auto pos = parse_hex(st);
w.write_char('X');
w.write_str(common::istr(id));
}
- case (ty::ty_native) { w.write_char('E'); }
+ case (ty::ty_native(?def)) {
+ w.write_char('E');
+ w.write_str(cx.ds(def));
+ w.write_char('|');
+ }
case (ty::ty_param(?id)) {
w.write_char('p');
w.write_str(common::uistr(id));
}
fn enc_constr(&io::writer w, &@ctxt cx, &@ty::constr_def c) {
- w.write_str(ty::path_to_str(c.node.path));
+ w.write_str(path_to_str(c.node.path));
w.write_char('(');
w.write_str(cx.ds(c.node.id));
w.write_char('|');
visit_expr=bind visit_expr(cx, _, _, _)
with *visit::default_visitor[scope]());
visit::visit_crate(*crate, [], visit::vtor(v));
+ tcx.sess.abort_if_errors();
}
fn visit_fn(@ctx cx, &ast::_fn f, &vec[ast::ty_param] tp, &span sp,
case (some(?ex)) {
auto root = expr_root(*cx, ex, false);
if (mut_field(root.ds)) {
- cx.tcx.sess.span_fatal(ex.span,
+ cx.tcx.sess.span_err(ex.span,
"result of put must be" +
" immutably rooted");
}
auto m =
"passing a temporary value or \
immutable field by mutable alias";
- cx.tcx.sess.span_fatal(arg.span, m);
+ cx.tcx.sess.span_err(arg.span, m);
}
}
}
alt (f.node) {
case (ast::expr_path(_)) {
if (def_is_local(cx.tcx.def_map.get(f.id), true)) {
- cx.tcx.sess.span_fatal(f.span,
+ cx.tcx.sess.span_err(f.span,
#fmt("function may alias with \
argument %u, which is not immutably rooted",
unsafe_t_offsets.(0)));
if (i != offset &&
ty_can_unsafely_include(cx, unsafe, arg_t.ty, mut_alias))
{
- cx.tcx.sess.span_fatal(args.(i).span,
+ cx.tcx.sess.span_err(args.(i).span,
#fmt("argument %u may alias with \
argument %u, which is not immutably rooted",
i, offset));
}
}
if (mut_alias_to_root) {
- cx.tcx.sess.span_fatal(args.(root._0).span,
+ cx.tcx.sess.span_err(args.(root._0).span,
"passing a mutable alias to a \
variable that roots another alias");
}
alt (cx.local_map.find(dnum)) {
case (some(arg(ast::alias(?mut)))) {
if (mut_a && !mut) {
- cx.tcx.sess.span_fatal(args.(i).span,
+ cx.tcx.sess.span_err(args.(i).span,
"passing an immutable \
alias by mutable alias");
}
case (_) { ok = false; }
}
if (!ok) {
- cx.tcx.sess.span_fatal(args.(i).span,
+ cx.tcx.sess.span_err(args.(i).span,
"can not pass a local value by \
alias to a tail call");
}
auto dnums = [];
fn walk_pat(&mutable vec[node_id] found, &@ast::pat p) {
alt (p.node) {
- case (ast::pat_bind(_, ?id)) { vec::push(found, id); }
- case (ast::pat_tag(_, ?children, _)) {
+ case (ast::pat_bind(_)) { vec::push(found, p.id); }
+ case (ast::pat_tag(_, ?children)) {
for (@ast::pat child in children) { walk_pat(found, child); }
}
case (_) { }
case (ast::expr_path(?p)) {
auto dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id))._1;
if (is_immutable_alias(cx, sc, dnum)) {
- cx.tcx.sess.span_fatal(dest.span,
+ cx.tcx.sess.span_err(dest.span,
"assigning to immutable alias");
} else if (is_immutable_objfield(cx, dnum)) {
- cx.tcx.sess.span_fatal(dest.span,
+ cx.tcx.sess.span_err(dest.span,
"assigning to immutable obj field");
}
for (restrict r in sc) {
case (_) {
auto root = expr_root(*cx, dest, false);
if (vec::len(root.ds) == 0u) {
- cx.tcx.sess.span_fatal(dest.span, "assignment to non-lvalue");
+ cx.tcx.sess.span_err(dest.span, "assignment to non-lvalue");
} else if (!root.ds.(0).mut) {
auto name =
alt (root.ds.(0).kind) {
case (field) { "field" }
case (index) { "vec content" }
};
- cx.tcx.sess.span_fatal(dest.span,
+ cx.tcx.sess.span_err(dest.span,
"assignment to immutable " + name);
}
visit_expr(cx, dest, sc, v);
tup(sp, "taking the value of " + ast::path_name(vpt))
}
};
- cx.tcx.sess.span_fatal(msg._0,
+ cx.tcx.sess.span_err(msg._0,
msg._1 + " will invalidate alias " +
ast::path_name(p) + ", which is still used");
}
case (ast::expr_unary(?op, ?base)) {
if (op == ast::deref) {
auto base_t = ty::expr_ty(*cx.tcx, base);
+ auto mut = false;
alt (ty::struct(*cx.tcx, base_t)) {
- case (ty::ty_box(?mt)) {
- vec::push(ds, rec(mut=mt.mut != ast::imm,
- kind=unbox,
- outer_t=base_t));
- }
- case (ty::ty_res(_, ?inner, _)) {
- vec::push(ds, rec(mut=false,
- kind=unbox,
- outer_t=base_t));
- }
+ case (ty::ty_box(?mt)) { mut = mt.mut != ast::imm; }
+ case (ty::ty_res(_, _, _)) {}
+ case (ty::ty_tag(_, _)) {}
}
+ vec::push(ds, rec(mut=mut, kind=unbox, outer_t=base_t));
ex = base;
} else { break; }
}
}
fn fty_args(&ctx cx, ty::t fty) -> ty::arg[] {
- ret alt (ty::struct(*cx.tcx, fty)) {
+ ret alt (ty::struct(*cx.tcx, ty::type_autoderef(*cx.tcx, fty))) {
case (ty::ty_fn(_, ?args, _, _, _)) { args }
case (ty::ty_native_fn(_, ?args, _)) { args }
};
}
fn walk_pat(&env e, &scopes sc, &@ast::pat pat) {
alt (pat.node) {
- case (ast::pat_tag(?p, ?children, ?id)) {
+ case (ast::pat_tag(?p, ?children)) {
auto fnd =
lookup_path_strict(e, sc, p.span, p.node.idents,
ns_value);
if (option::is_some(fnd)) {
alt (option::get(fnd)) {
case (ast::def_variant(?did, ?vid)) {
- e.def_map.insert(id, option::get(fnd));
+ e.def_map.insert(pat.id, option::get(fnd));
for (@ast::pat child in children) {
walk_pat(e, sc, child);
}
case (_) {
e.sess.span_err(c.span,
"Non-predicate in constraint: " +
- ty::path_to_str(c.node.path));
+ ast::path_to_str(c.node.path));
}
}
}
fn lookup_in_pat(&ident name, &ast::pat pat) -> option::t[def] {
alt (pat.node) {
- case (ast::pat_bind(?p_name, ?id)) {
+ case (ast::pat_bind(?p_name)) {
if (str::eq(p_name, name)) {
- ret some(ast::def_binding(local_def(id)));
+ ret some(ast::def_binding(local_def(pat.id)));
}
}
- case (ast::pat_wild(_)) { }
- case (ast::pat_lit(_, _)) { }
- case (ast::pat_tag(_, ?pats, _)) {
+ case (ast::pat_wild) { }
+ case (ast::pat_lit(_)) { }
+ case (ast::pat_tag(_, ?pats)) {
for (@ast::pat p in pats) {
auto found = lookup_in_pat(name, *p);
if (!option::is_none(found)) { ret found; }
visit::visit_arm(a, x, v);
fn walk_pat(checker ch, &@ast::pat p) {
alt (p.node) {
- case (ast::pat_bind(?name, _)) { add_name(ch, p.span, name); }
- case (ast::pat_tag(_, ?children, _)) {
+ case (ast::pat_bind(?name)) { add_name(ch, p.span, name); }
+ case (ast::pat_tag(_, ?children)) {
for (@ast::pat child in children) { walk_pat(ch, child); }
}
case (_) { }
tag block_parent { parent_none; parent_some(@block_ctxt); }
type result = rec(@block_ctxt bcx, ValueRef val);
+type result_t = rec(@block_ctxt bcx, ValueRef val, ty::t ty);
fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt {
ret @rec(path=cx.path + [name] with *cx);
if (cx.lltypes.contains_key(t)) { ret cx.lltypes.get(t); }
let TypeRef llty = 0 as TypeRef;
alt (ty::struct(cx.tcx, t)) {
- case (ty::ty_native) { llty = T_ptr(T_i8()); }
+ case (ty::ty_native(_)) { llty = T_ptr(T_i8()); }
case (ty::ty_nil) { llty = T_nil(); }
case (ty::ty_bot) {
llty = T_nil(); /* ...I guess? */
case (ty::ty_char) { llty = T_char(); }
case (ty::ty_str) { llty = T_ptr(T_str()); }
case (ty::ty_istr) { llty = T_ivec(T_i8()); }
- case (ty::ty_tag(_, _)) {
- if (ty::type_has_dynamic_size(cx.tcx, t)) {
- llty = T_opaque_tag(cx.tn);
- } else {
- auto size = static_size_of_tag(cx, sp, t);
- llty = T_tag(cx.tn, size);
- }
- }
+ case (ty::ty_tag(?did, _)) { llty = type_of_tag(cx, sp, did, t); }
case (ty::ty_box(?mt)) {
llty = T_ptr(T_box(type_of_inner(cx, sp, mt.ty)));
}
ret llty;
}
+fn type_of_tag(&@crate_ctxt cx, &span sp, &ast::def_id did, &ty::t t)
+ -> TypeRef {
+ auto degen = vec::len(ty::tag_variants(cx.tcx, did)) == 1u;
+ if (ty::type_has_dynamic_size(cx.tcx, t)) {
+ if (degen) { ret T_i8(); }
+ else { ret T_opaque_tag(cx.tn); }
+ } else {
+ auto size = static_size_of_tag(cx, sp, t);
+ if (!degen) { ret T_tag(cx.tn, size); }
+ // LLVM does not like 0-size arrays, apparently
+ if (size == 0u) { size = 1u; }
+ ret T_array(T_i8(), size);
+ }
+}
+
+
fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef {
alt (ty::struct(cx.ccx.tcx, arg.ty)) {
case (ty::ty_param(_)) {
bcx.build.Store(umax(bcx, this_size, old_max_size), max_size);
}
auto max_size_val = bcx.build.Load(max_size);
- auto total_size = bcx.build.Add(max_size_val, llsize_of(T_int()));
+ auto total_size = if (vec::len(variants) != 1u) {
+ bcx.build.Add(max_size_val, llsize_of(T_int()))
+ } else { max_size_val };
ret rslt(bcx, total_size);
}
case (ty::ty_ivec(?mt)) {
if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
bcx = incr_refcnt_of_boxed(cx, cx.build.Load(v)).bcx;
} else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t)) {
- bcx = iter_structural_ty(cx, v, t, bind copy_ty(_, _, _)).bcx;
- bcx = duplicate_heap_parts_if_necessary(bcx, v, t).bcx;
+ bcx = duplicate_heap_parts_if_necessary(cx, v, t).bcx;
+ bcx = iter_structural_ty(bcx, v, t, bind copy_ty(_, _, _)).bcx;
} else { bcx = cx; }
bcx.build.RetVoid();
}
ret rslt(new_sub_block_ctxt(cx, "after_fail_dummy"),
C_bool(false));
}
- case (ty::ty_native) {
+ case (ty::ty_native(_)) {
trans_fail(cx, none[common::span],
"attempt to compare values of type native");
ret rslt(new_sub_block_ctxt(cx, "after_fail_dummy"),
r.bcx.build.Br(next_cx.llbb);
ret rslt(next_cx, C_nil());
}
+
fn iter_ivec(@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty,
&val_pair_and_ty_fn f) -> result {
// FIXME: "unimplemented rebinding existing function" workaround
ret rslt(next_cx, C_nil());
}
+
+ fn iter_variant(@block_ctxt cx, ValueRef a_tup, ValueRef b_tup,
+ &ty::variant_info variant, &vec[ty::t] tps,
+ &ast::def_id tid, &val_pair_and_ty_fn f) -> result {
+ if (vec::len[ty::t](variant.args) == 0u) {
+ ret rslt(cx, C_nil());
+ }
+ auto fn_ty = variant.ctor_ty;
+ auto ccx = cx.fcx.lcx.ccx;
+ alt (ty::struct(ccx.tcx, fn_ty)) {
+ case (ty::ty_fn(_, ?args, _, _, _)) {
+ auto j = 0;
+ for (ty::arg a in args) {
+ auto rslt = GEP_tag(cx, a_tup, tid,
+ variant.id, tps, j);
+ auto llfldp_a = rslt.val;
+ cx = rslt.bcx;
+ rslt = GEP_tag(cx, b_tup, tid,
+ variant.id, tps, j);
+ auto llfldp_b = rslt.val;
+ cx = rslt.bcx;
+ auto ty_subst =
+ ty::substitute_type_params(ccx.tcx, tps, a.ty);
+ auto llfld_a =
+ load_if_immediate(cx, llfldp_a, ty_subst);
+ auto llfld_b =
+ load_if_immediate(cx, llfldp_b, ty_subst);
+ rslt = f(cx, llfld_a, llfld_b, ty_subst);
+ cx = rslt.bcx;
+ j += 1;
+ }
+ }
+ }
+ ret rslt(cx, C_nil());
+ }
+
let result r = rslt(cx, C_nil());
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
case (ty::ty_tup(?args)) {
auto elt_a = r.val;
r = GEP_tup_like(r.bcx, t, bv, [0, i]);
auto elt_b = r.val;
- r =
- f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty),
+ r = f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty),
load_if_immediate(r.bcx, elt_b, arg.ty), arg.ty);
i += 1;
}
auto llfld_a = r.val;
r = GEP_tup_like(r.bcx, t, bv, [0, i]);
auto llfld_b = r.val;
- r =
- f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
+ r = f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty),
load_if_immediate(r.bcx, llfld_b, fld.mt.ty),
fld.mt.ty);
i += 1;
}
case (ty::ty_tag(?tid, ?tps)) {
auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
- auto n_variants = vec::len[ty::variant_info](variants);
+ auto n_variants = vec::len(variants);
+
// Cast the tags to types we can GEP into.
+ if (n_variants == 1u) {
+ ret iter_variant(cx, av, bv, variants.(0), tps, tid, f);
+ }
auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn);
auto av_tag = cx.build.PointerCast(av, lltagty);
auto lldiscrim_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(0)]);
auto llunion_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(1)]);
auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr);
+
// NB: we must hit the discriminant first so that structural
// comparison know not to proceed when the discriminants differ.
-
auto bcx = cx;
bcx =
f(bcx, lldiscrim_a, lldiscrim_b,
"tag-iter-variant-" +
uint::to_str(i, 10u));
llvm::LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb);
- if (vec::len[ty::t](variant.args) > 0u) {
- // N-ary variant.
-
- auto fn_ty = variant.ctor_ty;
- alt (ty::struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) {
- case (ty::ty_fn(_, ?args, _, _, _)) {
- auto j = 0;
- for (ty::arg a in args) {
- auto rslt =
- GEP_tag(variant_cx, llunion_a_ptr, tid,
- variant.id, tps, j);
- auto llfldp_a = rslt.val;
- variant_cx = rslt.bcx;
- rslt =
- GEP_tag(variant_cx, llunion_b_ptr, tid,
- variant.id, tps, j);
- auto llfldp_b = rslt.val;
- variant_cx = rslt.bcx;
- auto tcx = cx.fcx.lcx.ccx.tcx;
- auto ty_subst =
- ty::substitute_type_params(tcx, tps,
- a.ty);
- auto llfld_a =
- load_if_immediate(variant_cx, llfldp_a,
- ty_subst);
- auto llfld_b =
- load_if_immediate(variant_cx, llfldp_b,
- ty_subst);
- rslt =
- f(variant_cx, llfld_a, llfld_b, ty_subst);
- variant_cx = rslt.bcx;
- j += 1;
- }
- }
- }
- variant_cx.build.Br(next_cx.llbb);
- } else {
- // Nullary variant; nothing to do.
-
- variant_cx.build.Br(next_cx.llbb);
- }
+ variant_cx = iter_variant
+ (variant_cx, llunion_a_ptr, llunion_b_ptr, variant,
+ tps, tid, f).bcx;
+ variant_cx.build.Br(next_cx.llbb);
i += 1u;
}
ret rslt(next_cx, C_nil());
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
alt (op) {
case (ast::not) {
- sub =
- autoderef(sub.bcx, sub.val,
- ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
- ret rslt(sub.bcx, sub.bcx.build.Not(sub.val));
+ auto dr = autoderef(sub.bcx, sub.val,
+ ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
+ ret rslt(dr.bcx, dr.bcx.build.Not(dr.val));
}
case (ast::neg) {
- sub =
- autoderef(sub.bcx, sub.val,
- ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
+ auto dr = autoderef(sub.bcx, sub.val,
+ ty::expr_ty(cx.fcx.lcx.ccx.tcx, e));
if (ty::struct(cx.fcx.lcx.ccx.tcx, e_ty) == ty::ty_float) {
- ret rslt(sub.bcx, sub.bcx.build.FNeg(sub.val));
- } else { ret rslt(sub.bcx, sub.bcx.build.Neg(sub.val)); }
+ ret rslt(dr.bcx, dr.bcx.build.FNeg(dr.val));
+ } else { ret rslt(dr.bcx, sub.bcx.build.Neg(dr.val)); }
}
case (ast::box(_)) {
auto e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
auto rhs_r = autoderef(cx, rhs0, t0);
auto rhs = rhs_r.val;
cx = rhs_r.bcx;
- auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
// Determine the operation we need.
// FIXME: Use or-patterns when we have them.
case (ast::ge) { llop = C_u8(abi::cmp_glue_op_lt); }
case (ast::gt) { llop = C_u8(abi::cmp_glue_op_le); }
}
- auto rs = compare(cx, lhs, rhs, t, llop);
+ auto rs = compare(cx, lhs, rhs, rhs_r.ty, llop);
// Invert the result if necessary.
// FIXME: Use or-patterns when we have them.
}
}
-fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
+fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
+ -> result_t {
let ValueRef v1 = v;
let ty::t t1 = t;
+ auto ccx = cx.fcx.lcx.ccx;
while (true) {
- alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
+ alt (ty::struct(ccx.tcx, t1)) {
case (ty::ty_box(?mt)) {
+ // If we are working with an lval, we want to
+ // unconditionally load at the top of the loop
+ // to get rid of the extra indirection
+ if (is_lval) { v1 = cx.build.Load(v1); }
+
auto body =
cx.build.GEP(v1,
[C_int(0), C_int(abi::box_rc_field_body)]);
// to cast this pointer, since statically-sized tag types have
// different types depending on whether they're behind a box
// or not.
-
- if (!ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, mt.ty)) {
- auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
+ if (!ty::type_has_dynamic_size(ccx.tcx, mt.ty)) {
+ auto llty = type_of(ccx, cx.sp, mt.ty);
v1 = cx.build.PointerCast(body, T_ptr(llty));
} else { v1 = body; }
- v1 = load_if_immediate(cx, v1, t1);
+ }
+ case (ty::ty_res(?did, ?inner, ?tps)) {
+ if (is_lval) { v1 = cx.build.Load(v1); }
+ t1 = ty::substitute_type_params(ccx.tcx, tps, inner);
+ v1 = cx.build.GEP(v1, [C_int(0), C_int(1)]);
+ }
+ case (ty::ty_tag(?did, ?tps)) {
+ auto variants = ty::tag_variants(ccx.tcx, did);
+ if (vec::len(variants) != 1u ||
+ vec::len(variants.(0).args) != 1u) {
+ break;
+ }
+ if (is_lval) { v1 = cx.build.Load(v1); }
+ t1 = ty::substitute_type_params
+ (ccx.tcx, tps, variants.(0).args.(0));
+ if (!ty::type_has_dynamic_size(ccx.tcx, t1)) {
+ v1 = cx.build.PointerCast
+ (v1, T_ptr(type_of(ccx, cx.sp, t1)));
+ }
}
case (_) { break; }
}
+ // But if we aren't working with an lval, we get rid of
+ // a layer of indirection at the bottom of the loop so
+ // that it is gone when we return...
+ if (!is_lval) { v1 = load_if_immediate(cx, v1, t1); }
}
- ret rslt(cx, v1);
+ ret rec(bcx=cx, val=v1, ty=t1);
}
-fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
- let ty::t t1 = t;
- while (true) {
- alt (ty::struct(ccx.tcx, t1)) {
- case (ty::ty_box(?mt)) { t1 = mt.ty; }
- case (_) { break; }
- }
- }
- ret t1;
+fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result_t {
+ ret autoderef_lval(cx, v, t, false);
}
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
alt (op) {
case (ast::and) {
// Lazy-eval and
-
- auto lhs_res = trans_expr(cx, a);
- lhs_res =
- autoderef(lhs_res.bcx, lhs_res.val,
+ auto lhs_expr = trans_expr(cx, a);
+ auto lhs_res =
+ autoderef(lhs_expr.bcx, lhs_expr.val,
ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
- auto rhs_res = trans_expr(rhs_cx, b);
- rhs_res =
- autoderef(rhs_res.bcx, rhs_res.val,
+ auto rhs_expr = trans_expr(rhs_cx, b);
+ auto rhs_res =
+ autoderef(rhs_expr.bcx, rhs_expr.val,
ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
auto lhs_false_res = rslt(lhs_false_cx, C_bool(false));
lhs_res.bcx.build.CondBr(lhs_res.val, rhs_cx.llbb,
lhs_false_cx.llbb);
ret join_results(cx, T_bool(),
- [lhs_false_res, rec(bcx=rhs_bcx with rhs_res)]);
+ [lhs_false_res, rec(bcx=rhs_bcx,
+ val=rhs_res.val)]);
}
case (ast::or) {
// Lazy-eval or
-
- auto lhs_res = trans_expr(cx, a);
- lhs_res =
- autoderef(lhs_res.bcx, lhs_res.val,
- ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
+ auto lhs_expr = trans_expr(cx, a);
+ auto lhs_res = autoderef(lhs_expr.bcx, lhs_expr.val,
+ ty::expr_ty(cx.fcx.lcx.ccx.tcx, a));
auto rhs_cx = new_scope_block_ctxt(cx, "rhs");
- auto rhs_res = trans_expr(rhs_cx, b);
- rhs_res =
- autoderef(rhs_res.bcx, rhs_res.val,
- ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
+ auto rhs_expr = trans_expr(rhs_cx, b);
+ auto rhs_res = autoderef(rhs_expr.bcx, rhs_expr.val,
+ ty::expr_ty(cx.fcx.lcx.ccx.tcx, b));
auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
auto lhs_true_res = rslt(lhs_true_cx, C_bool(true));
// see the and case for an explanation
lhs_res.bcx.build.CondBr(lhs_res.val, lhs_true_cx.llbb,
rhs_cx.llbb);
ret join_results(cx, T_bool(),
- [lhs_true_res, rec(bcx=rhs_bcx with rhs_res)]);
+ [lhs_true_res, rec(bcx=rhs_bcx,
+ val=rhs_res.val)]);
}
case (_) {
// Remaining cases are eager:
- auto lhs = trans_expr(cx, a);
+ auto lhs_expr = trans_expr(cx, a);
auto lhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, a);
- lhs = autoderef(lhs.bcx, lhs.val, lhty);
- auto rhs = trans_expr(lhs.bcx, b);
+ auto lhs = autoderef(lhs_expr.bcx, lhs_expr.val, lhty);
+ auto rhs_expr = trans_expr(lhs.bcx, b);
auto rhty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, b);
- rhs = autoderef(rhs.bcx, rhs.val, rhty);
- ret trans_eager_binop(rhs.bcx, op,
- autoderefed_ty(cx.fcx.lcx.ccx, lhty),
+ auto rhs = autoderef(rhs_expr.bcx, rhs_expr.val, rhty);
+ ret trans_eager_binop(rhs.bcx, op, lhs.ty,
lhs.val, rhs.val);
}
}
fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
&@block_ctxt next_cx) -> result {
alt (pat.node) {
- case (ast::pat_wild(_)) { ret rslt(cx, llval); }
- case (ast::pat_bind(_, _)) { ret rslt(cx, llval); }
- case (ast::pat_lit(?lt, ?id)) {
- auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, id);
- auto lltype = ty::node_id_to_type(cx.fcx.lcx.ccx.tcx, id);
+ case (ast::pat_wild) { ret rslt(cx, llval); }
+ case (ast::pat_bind(_)) { ret rslt(cx, llval); }
+ case (ast::pat_lit(?lt)) {
+ auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, pat.id);
+ auto lltype = ty::node_id_to_type(cx.fcx.lcx.ccx.tcx, pat.id);
auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit);
auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx");
lleq.bcx.build.CondBr(lleq.val, matched_cx.llbb, next_cx.llbb);
ret rslt(matched_cx, llval);
}
- case (ast::pat_tag(?ident, ?subpats, ?id)) {
- auto lltagptr =
- cx.build.PointerCast(llval,
- T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
- auto lldiscrimptr = cx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
- auto lldiscrim = cx.build.Load(lldiscrimptr);
+ case (ast::pat_tag(?ident, ?subpats)) {
auto vdef =
- ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(id));
- auto variant_tag = 0;
+ ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(pat.id));
auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0);
- auto i = 0;
- for (ty::variant_info v in variants) {
- auto this_variant_id = v.id;
- if (vdef._1._0 == this_variant_id._0 &&
+ auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
+ auto llblobptr = llval;
+
+ if (vec::len(variants) == 1u) {
+ cx.build.Br(matched_cx.llbb);
+ } else {
+ auto lltagptr =
+ cx.build.PointerCast(llval,
+ T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
+ auto lldiscrimptr = cx.build.GEP(lltagptr,
+ [C_int(0), C_int(0)]);
+ auto lldiscrim = cx.build.Load(lldiscrimptr);
+ auto variant_tag = 0;
+ auto i = 0;
+ for (ty::variant_info v in variants) {
+ auto this_variant_id = v.id;
+ if (vdef._1._0 == this_variant_id._0 &&
vdef._1._1 == this_variant_id._1) {
- variant_tag = i;
+ variant_tag = i;
+ }
+ i += 1;
+ }
+ auto lleq =
+ cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
+ C_int(variant_tag));
+ cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
+ if (vec::len(subpats) > 0u) {
+ llblobptr =
+ matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
}
- i += 1;
}
- auto matched_cx = new_sub_block_ctxt(cx, "matched_cx");
- auto lleq =
- cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim,
- C_int(variant_tag));
- cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb);
auto ty_params = ty::node_id_to_type_params
- (cx.fcx.lcx.ccx.tcx, id);
- if (vec::len[@ast::pat](subpats) > 0u) {
- auto llblobptr =
- matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
+ (cx.fcx.lcx.ccx.tcx, pat.id);
+ if (vec::len(subpats) > 0u) {
auto i = 0;
for (@ast::pat subpat in subpats) {
auto rslt =
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
bool bind_alias) -> result {
alt (pat.node) {
- case (ast::pat_wild(_)) { ret rslt(cx, llval); }
- case (ast::pat_lit(_, _)) { ret rslt(cx, llval); }
- case (ast::pat_bind(?name, ?id)) {
+ case (ast::pat_wild) { ret rslt(cx, llval); }
+ case (ast::pat_lit(_)) { ret rslt(cx, llval); }
+ case (ast::pat_bind(?name)) {
if (bind_alias) {
- cx.fcx.lllocals.insert(id, llval);
+ cx.fcx.lllocals.insert(pat.id, llval);
ret rslt(cx, llval);
} else {
- auto t = node_id_type(cx.fcx.lcx.ccx, id);
+ auto t = node_id_type(cx.fcx.lcx.ccx, pat.id);
auto rslt = alloc_ty(cx, t);
auto dst = rslt.val;
auto bcx = rslt.bcx;
maybe_name_value(cx.fcx.lcx.ccx, dst, name);
- bcx.fcx.lllocals.insert(id, dst);
+ bcx.fcx.lllocals.insert(pat.id, dst);
bcx.cleanups += [clean(bind drop_slot(_, dst, t))];
ret copy_val(bcx, INIT, dst, llval, t);
}
}
- case (ast::pat_tag(_, ?subpats, ?id)) {
+ case (ast::pat_tag(_, ?subpats)) {
if (vec::len[@ast::pat](subpats) == 0u) { ret rslt(cx, llval); }
// Get the appropriate variant for this tag.
auto vdef =
- ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(id));
- auto lltagptr =
- cx.build.PointerCast(llval,
- T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
- auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
+ ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(pat.id));
+ auto llblobptr = llval;
+ if (vec::len(ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0))!=1u) {
+ auto lltagptr = cx.build.PointerCast
+ (llval, T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn));
+ llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
+ }
auto ty_param_substs =
- ty::node_id_to_type_params(cx.fcx.lcx.ccx.tcx, id);
+ ty::node_id_to_type_params(cx.fcx.lcx.ccx.tcx, pat.id);
auto this_cx = cx;
auto i = 0;
for (@ast::pat subpat in subpats) {
}
fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result {
+ auto ccx = cx.fcx.lcx.ccx;
alt (cx.fcx.lcx.ccx.tcx.def_map.get(id)) {
case (ast::def_arg(?did)) {
alt (cx.fcx.llargs.find(did._1)) {
ret lval_mem(cx, cx.fcx.llobjfields.get(did._1));
}
case (ast::def_fn(?did, _)) {
- auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
+ auto tyt = ty::lookup_item_type(ccx.tcx, did);
ret lval_generic_fn(cx, tyt, did, id);
}
case (ast::def_variant(?tid, ?vid)) {
- auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid);
- alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) {
+ auto v_tyt = ty::lookup_item_type(ccx.tcx, vid);
+ alt (ty::struct(ccx.tcx, v_tyt._1)) {
case (ty::ty_fn(_, _, _, _, _)) {
// N-ary variant.
}
case (_) {
// Nullary variant.
-
- auto tag_ty = node_id_type(cx.fcx.lcx.ccx, id);
- auto lldiscrim_gv =
- lookup_discriminant(cx.fcx.lcx, tid, vid);
- auto lldiscrim = cx.build.Load(lldiscrim_gv);
+ auto tag_ty = node_id_type(ccx, id);
auto alloc_result = alloc_ty(cx, tag_ty);
auto lltagblob = alloc_result.val;
- auto lltagty;
- if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tag_ty))
- {
- lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn);
- } else {
- lltagty = type_of(cx.fcx.lcx.ccx, p.span, tag_ty);
+ auto lltagty = type_of_tag(ccx, p.span, tid, tag_ty);
+ auto bcx = alloc_result.bcx;
+ auto lltagptr = bcx.build.PointerCast
+ (lltagblob, T_ptr(lltagty));
+ if (vec::len(ty::tag_variants(ccx.tcx, tid)) != 1u) {
+ auto lldiscrim_gv =
+ lookup_discriminant(bcx.fcx.lcx, tid, vid);
+ auto lldiscrim = bcx.build.Load(lldiscrim_gv);
+ auto lldiscrimptr = bcx.build.GEP
+ (lltagptr, [C_int(0), C_int(0)]);
+ bcx.build.Store(lldiscrim, lldiscrimptr);
}
- auto lltagptr =
- alloc_result.bcx.build.PointerCast(lltagblob,
- T_ptr(lltagty));
- auto lldiscrimptr =
- alloc_result.bcx.build.GEP(lltagptr,
- [C_int(0), C_int(0)]);
- alloc_result.bcx.build.Store(lldiscrim, lldiscrimptr);
- ret lval_val(alloc_result.bcx, lltagptr);
+ ret lval_val(bcx, lltagptr);
}
}
}
case (ast::def_const(?did)) {
// TODO: externals
-
- assert (cx.fcx.lcx.ccx.consts.contains_key(did._1));
- ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did._1));
+ assert (ccx.consts.contains_key(did._1));
+ ret lval_mem(cx, ccx.consts.get(did._1));
}
case (ast::def_native_fn(?did)) {
- auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did);
+ auto tyt = ty::lookup_item_type(ccx.tcx, did);
ret lval_generic_fn(cx, tyt, did, id);
}
case (_) {
- cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans");
+ ccx.sess.span_unimpl(cx.sp, "def variant in trans");
}
}
}
fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0,
&ast::ident field, ast::node_id id) -> lval_result {
auto r = autoderef(cx, v, t0);
- auto t = autoderefed_ty(cx.fcx.lcx.ccx, t0);
+ auto t = r.ty;
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
case (ty::ty_tup(_)) {
let uint ix = ty::field_num(cx.fcx.lcx.ccx.sess, sp, field);
// Is this an interior vector?
auto base_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
- auto base_ty_no_boxes = ty::strip_boxes(cx.fcx.lcx.ccx.tcx, base_ty);
+ auto exp = trans_expr(cx, base);
+ auto lv = autoderef(exp.bcx, exp.val, base_ty);
+ auto base_ty_no_boxes = lv.ty;
auto is_interior =
ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, base_ty_no_boxes);
- auto lv = trans_expr(cx, base);
- lv = autoderef(lv.bcx, lv.val, base_ty);
auto ix = trans_expr(lv.bcx, idx);
auto v = lv.val;
auto bcx = ix.bcx;
ret trans_index(cx, e.span, base, idx, e.id);
}
case (ast::expr_unary(?unop, ?base)) {
+ auto ccx = cx.fcx.lcx.ccx;
assert (unop == ast::deref);
auto sub = trans_expr(cx, base);
- auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
- auto offset = alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
- case (ty::ty_box(_)) { abi::box_rc_field_body }
- case (ty::ty_res(_, _, _)) { 1 }
+ auto t = ty::expr_ty(ccx.tcx, base);
+ auto val = alt (ty::struct(ccx.tcx, t)) {
+ case (ty::ty_box(_)) {
+ sub.bcx.build.GEP
+ (sub.val, [C_int(0), C_int(abi::box_rc_field_body)])
+ }
+ case (ty::ty_res(_, _, _)) {
+ sub.bcx.build.GEP(sub.val, [C_int(0), C_int(1)])
+ }
+ case (ty::ty_tag(_, _)) {
+ auto ety = ty::expr_ty(ccx.tcx, e);
+ auto ellty;
+ if (ty::type_has_dynamic_size(ccx.tcx, ety)) {
+ ellty = T_typaram_ptr(ccx.tn);
+ } else {
+ ellty = T_ptr(type_of(ccx, e.span, ety));
+ };
+ sub.bcx.build.PointerCast(sub.val, ellty)
+ }
};
- auto val = sub.bcx.build.GEP(sub.val, [C_int(0), C_int(offset)]);
ret lval_mem(sub.bcx, val);
}
case (ast::expr_self_method(?ident)) {
val = do_spill(lv.res.bcx, lv.res.val);
}
} else { auto re = trans_expr(bcx, e); val = re.val; bcx = re.bcx; }
+ auto is_bot = ty::type_is_bot(cx.fcx.lcx.ccx.tcx, e_ty);
// Make a copy here if the type is structural and we're passing by value.
- if (arg.mode == ty::mo_val) {
+ if (arg.mode == ty::mo_val && !is_bot) {
if (ty::type_owns_heap_mem(cx.fcx.lcx.ccx.tcx, e_ty)) {
auto rslt = alloc_ty(bcx, e_ty);
bcx = rslt.bcx;
}
}
- if (ty::type_is_bot(cx.fcx.lcx.ccx.tcx, e_ty)) {
+ if (is_bot) {
// For values of type _|_, we generate an
// "undef" value, as such a value should never
// be inspected. It's important for the value
// to have type lldestty0 (the callee's expected type).
-
val = llvm::LLVMGetUndef(lldestty0);
} else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) {
auto lldestty = lldestty0;
auto arg_tys = type_of_explicit_args(cx.fcx.lcx.ccx, cx.sp, args);
auto i = 0u;
for (@ast::expr e in es) {
+ if (bcx.build.is_terminated()) {
+ // This means an earlier arg was divergent.
+ // So this arg can't be evaluated.
+ break;
+ }
auto r = trans_arg_expr(bcx, args.(i), arg_tys.(i), e);
bcx = r.bcx;
llargs += [r.val];
// with trans_call.
auto f_res = trans_lval(cx, f);
+ let ty::t fn_ty;
+ alt (f_res.method_ty) {
+ case (some(?meth)) {
+ // self-call
+ fn_ty = meth;
+ }
+ case (_) {
+ fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
+ }
+ }
+
+ auto bcx = f_res.res.bcx;
+
auto faddr = f_res.res.val;
auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
alt (f_res.llobj) {
case (some(_)) {
// It's a vtbl entry.
- faddr = f_res.res.bcx.build.Load(faddr);
+ faddr = bcx.build.Load(faddr);
}
case (none) {
- // It's a closure.
- auto bcx = f_res.res.bcx;
- auto pair = faddr;
+ // It's a closure. We have to autoderef.
+ auto res = autoderef_lval(bcx, f_res.res.val, fn_ty, true);
+ bcx = res.bcx;
+ fn_ty = res.ty;
+
+ auto pair = res.val;
faddr =
bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
faddr = bcx.build.Load(faddr);
llenv = bcx.build.Load(llclosure);
}
}
- let ty::t fn_ty;
- alt (f_res.method_ty) {
- case (some(?meth)) {
- // self-call
- fn_ty = meth;
- }
- case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
- }
+
auto ret_ty = ty::node_id_to_type(cx.fcx.lcx.ccx.tcx, id);
auto args_res =
- trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
+ trans_args(bcx, llenv, f_res.llobj, f_res.generic,
lliterbody, args, fn_ty);
- auto bcx = args_res._0;
+ bcx = args_res._0;
auto llargs = args_res._1;
auto llretslot = args_res._2;
/*
}
*/
- bcx.build.FastCall(faddr, llargs);
+ /* If the block is terminated,
+ then one or more of the args has
+ type _|_. Since that means it diverges, the code
+ for the call itself is unreachable. */
auto retval = C_nil();
- alt (lliterbody) {
- case (none) {
- if (!ty::type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
- retval = load_if_immediate(bcx, llretslot, ret_ty);
- // Retval doesn't correspond to anything really tangible in
- // the frame, but it's a ref all the same, so we put a note
- // here to drop it when we're done in this scope.
-
- find_scope_cx(cx).cleanups +=
- [clean(bind drop_ty(_, retval, ret_ty))];
+ if (!bcx.build.is_terminated()) {
+ bcx.build.FastCall(faddr, llargs);
+ alt (lliterbody) {
+ case (none) {
+ if (!ty::type_is_nil(cx.fcx.lcx.ccx.tcx, ret_ty)) {
+ retval = load_if_immediate(bcx, llretslot, ret_ty);
+ // Retval doesn't correspond to anything really tangible
+ // in the frame, but it's a ref all the same, so we put a
+ // note here to drop it when we're done in this scope.
+
+ find_scope_cx(cx).cleanups +=
+ [clean(bind drop_ty(_, retval, ret_ty))];
+ }
+ }
+ case (some(_)) {
+ // If there was an lliterbody, it means we were calling an
+ // iter, and we are *not* the party using its 'output' value,
+ // we should ignore llretslot.
}
- }
- case (some(_)) {
- // If there was an lliterbody, it means we were calling an
- // iter, and we are *not* the party using its 'output' value,
- // we should ignore llretslot.
-
}
}
ret rslt(bcx, retval);
case (ast::expr_ext(_, _, _, ?expanded)) {
ret trans_expr(cx, expanded);
}
- case (ast::expr_fail(?str)) {
- auto failmsg;
- alt (str) {
- case (some(?msg)) { failmsg = msg; }
- case (_) { failmsg = "explicit failure"; }
- }
- ret trans_fail(cx, some(e.span), failmsg);
+ case (ast::expr_fail(?expr)) {
+ ret trans_fail_expr(cx, some(e.span), expr);
}
case (ast::expr_log(?lvl, ?a)) { ret trans_log(lvl, cx, a); }
case (ast::expr_assert(?a)) {
ret rslt(next_cx, C_nil());
}
+fn trans_fail_expr(&@block_ctxt cx, &option::t[common::span] sp_opt,
+ &option::t[@ast::expr] fail_expr)
+ -> result {
+ auto bcx = cx;
+ alt (fail_expr) {
+ case (some(?expr)) {
+ auto tcx = bcx.fcx.lcx.ccx.tcx;
+ auto expr_res = trans_expr(bcx, expr);
+ auto e_ty = ty::expr_ty(tcx, expr);
+ bcx = expr_res.bcx;
+
+ if (ty::type_is_str(tcx, e_ty)) {
+ auto elt = bcx.build.GEP(expr_res.val,
+ [C_int(0), C_int(abi::vec_elt_data)]);
+ ret trans_fail_value(bcx, sp_opt, elt);
+ } else {
+ cx.fcx.lcx.ccx.sess.span_bug(expr.span,
+ "fail called with unsupported \
+ type " + ty_to_str(tcx, e_ty));
+ }
+ }
+ case (_) {
+ ret trans_fail(bcx, sp_opt, "explicit failure");
+ }
+ }
+}
+
fn trans_fail(&@block_ctxt cx, &option::t[common::span] sp_opt, &str fail_str)
-> result {
auto V_fail_str = C_cstr(cx.fcx.lcx.ccx, fail_str);
+ ret trans_fail_value(cx, sp_opt, V_fail_str);
+}
+
+fn trans_fail_value(&@block_ctxt cx, &option::t[common::span] sp_opt,
+ &ValueRef V_fail_str)
+ -> result {
auto V_filename;
auto V_line;
alt (sp_opt) {
V_line = 0;
}
}
- V_fail_str = cx.build.PointerCast(V_fail_str, T_ptr(T_i8()));
+ auto V_str = cx.build.PointerCast(V_fail_str, T_ptr(T_i8()));
V_filename = cx.build.PointerCast(V_filename, T_ptr(T_i8()));
- auto args = [cx.fcx.lltaskptr, V_fail_str, V_filename, C_int(V_line)];
+ auto args = [cx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
cx.build.Call(cx.fcx.lcx.ccx.upcalls._fail, args);
cx.build.Unreachable();
ret rslt(cx, C_nil());
fn trans_tag_variant(@local_ctxt cx, ast::node_id tag_id,
- &ast::variant variant, int index,
+ &ast::variant variant, int index, bool is_degen,
&vec[ast::ty_param] ty_params) {
if (vec::len[ast::variant_arg](variant.node.args) == 0u) {
ret; // nullary constructors are just constants
copy_args_to_allocas(fcx, fn_args, arg_tys);
auto bcx = new_top_block_ctxt(fcx);
auto lltop = bcx.llbb;
- // Cast the tag to a type we can GEP into.
- auto lltagptr =
- bcx.build.PointerCast(fcx.llretptr, T_opaque_tag_ptr(fcx.lcx.ccx.tn));
- auto lldiscrimptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
- bcx.build.Store(C_int(index), lldiscrimptr);
- auto llblobptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]);
+ auto llblobptr = if (is_degen) {
+ fcx.llretptr
+ } else {
+ // Cast the tag to a type we can GEP into.
+ auto lltagptr = bcx.build.PointerCast
+ (fcx.llretptr, T_opaque_tag_ptr(fcx.lcx.ccx.tn));
+ auto lldiscrimptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(0)]);
+ bcx.build.Store(C_int(index), lldiscrimptr);
+ bcx.build.GEP(lltagptr, [C_int(0), C_int(1)])
+ };
i = 0u;
for (ast::variant_arg va in variant.node.args) {
auto rslt =
}
case (ast::item_tag(?variants, ?tps)) {
auto sub_cx = extend_path(cx, item.ident);
+ auto degen = vec::len(variants) == 1u;
auto i = 0;
for (ast::variant variant in variants) {
- trans_tag_variant(sub_cx, item.id, variant, i, tps);
+ trans_tag_variant(sub_cx, item.id, variant, i, degen, tps);
i += 1;
}
}
auto n_variants = vec::len[ast::variant](variants);
while (i < n_variants) {
auto variant = variants.(i);
- auto discrim_val = C_int(i as int);
auto p = new_pt + [it.ident, variant.node.name, "discrim"];
auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
auto discrim_gvar =
llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s));
- llvm::LLVMSetInitializer(discrim_gvar, discrim_val);
- llvm::LLVMSetGlobalConstant(discrim_gvar, True);
+ if (n_variants != 1u) {
+ llvm::LLVMSetInitializer(discrim_gvar, C_int(i as int));
+ llvm::LLVMSetGlobalConstant(discrim_gvar, True);
+ }
ccx.discrims.insert(variant.node.id, discrim_gvar);
ccx.discrim_symbols.insert(variant.node.id, s);
i += 1u;
find_pre_post_expr(fcx, operator);
copy_pre_post(fcx.ccx, e.id, operator);
}
- case (expr_fail(_)) {
+ case (expr_fail(?maybe_val)) {
+ auto prestate;
+ alt (maybe_val) {
+ case (none) { prestate = empty_prestate(num_local_vars); }
+ case (some(?fail_val)) {
+ find_pre_post_expr(fcx, fail_val);
+ prestate = expr_precond(fcx.ccx, fail_val);
+ }
+ }
set_pre_and_post(fcx.ccx, e.id,
/* if execution continues after fail,
then everything is true! */
- empty_prestate(num_local_vars),
+ prestate,
false_postcond(num_local_vars));
}
case (expr_assert(?p)) {
case (expr_cast(?operand, _)) {
ret find_pre_post_state_sub(fcx, pres, operand, e.id, none);
}
- case (expr_fail(_)) {
+ case (expr_fail(?maybe_fail_val)) {
ret set_prestate_ann(fcx.ccx, e.id, pres) |
/* if execution continues after fail, then everything is true!
woo! */
set_poststate_ann(fcx.ccx, e.id,
- false_postcond(num_constrs));
+ false_postcond(num_constrs)) |
+ alt(maybe_fail_val) {
+ case (none) { false }
+ case (some(?fail_val)) {
+ find_pre_post_state_expr(fcx, pres, fail_val)
+ }
+ }
}
case (expr_assert(?p)) {
ret find_pre_post_state_sub(fcx, pres, p, e.id, none);
import front::ast::constr_arg_general;
import front::ast::mutability;
import front::ast::controlflow;
+import front::ast::path_to_str;
import metadata::creader;
import metadata::decoder;
import util::common::*;
export mo_alias;
export mt;
export node_type_table;
-export pat_node_id;
export pat_ty;
export cname;
-export path_to_str;
export rename;
export ret_ty_of_fn;
export ret_ty_of_fn_ty;
export struct;
export sort_methods;
export stmt_node_id;
-export strip_boxes;
export sty;
export substitute_type_params;
export t;
export type_is_tup_like;
export type_is_str;
export type_owns_heap_mem;
+export type_autoderef;
export type_param;
export def_to_str;
export unify;
ty_var(int); // type variable
ty_param(uint); // fn/tag type param
ty_type;
- ty_native;
+ ty_native(def_id);
// TODO: ty_fn_arg(t), for a possibly-aliased function argument
}
const uint idx_task = 18u;
-const uint idx_native = 19u;
+const uint idx_type = 19u;
-const uint idx_type = 20u;
+const uint idx_bot = 20u;
-const uint idx_bot = 21u;
-
-const uint idx_first_others = 22u;
+const uint idx_first_others = 21u;
type type_store = interner::interner[raw_t];
intern(cx, ty_str, none[str]);
intern(cx, ty_istr, none[str]);
intern(cx, ty_task, none[str]);
- intern(cx, ty_native, none[str]);
intern(cx, ty_type, none[str]);
intern(cx, ty_bot, none[str]);
assert (vec::len(cx.ts.vect) == idx_first_others);
case (ty_istr) {/* no-op */ }
case (ty_task) {/* no-op */ }
case (ty_type) {/* no-op */ }
- case (ty_native) {/* no-op */ }
+ case (ty_native(_)) {/* no-op */ }
case (ty_param(_)) { has_params = true; }
case (ty_var(_)) { has_vars = true; }
case (ty_tag(_, ?tys)) {
fn mk_type(&ctxt cx) -> t { ret idx_type; }
-fn mk_native(&ctxt cx) -> t { ret idx_native; }
+fn mk_native(&ctxt cx, &def_id did) -> t { ret gen_ty(cx, ty_native(did)); }
// Returns the one-level-deep type structure of the given type.
}
-// Stringification
-fn path_to_str(&ast::path pth) -> str {
- auto result = str::connect(pth.node.idents, "::");
- if (vec::len[@ast::ty](pth.node.types) > 0u) {
- fn f(&@ast::ty t) -> str { ret pretty::pprust::ty_to_str(*t); }
- result += "[";
- result += str::connect(vec::map(f, pth.node.types), ",");
- result += "]";
- }
- ret result;
-}
-
-
// Type folds
type ty_walk = fn(t) ;
case (ty_str) {/* no-op */ }
case (ty_istr) {/* no-op */ }
case (ty_type) {/* no-op */ }
- case (ty_native) {/* no-op */ }
+ case (ty_native(_)) {/* no-op */ }
case (ty_box(?tm)) { walk_ty(cx, walker, tm.ty); }
case (ty_vec(?tm)) { walk_ty(cx, walker, tm.ty); }
case (ty_ivec(?tm)) { walk_ty(cx, walker, tm.ty); }
case (ty_str) {/* no-op */ }
case (ty_istr) {/* no-op */ }
case (ty_type) {/* no-op */ }
- case (ty_native) {/* no-op */ }
+ case (ty_native(_)) {/* no-op */ }
case (ty_task) {/* no-op */ }
case (ty_box(?tm)) {
ty =
case (ty_machine(_)) { ret true; }
case (ty_char) { ret true; }
case (ty_type) { ret true; }
- case (ty_native) { ret true; }
+ case (ty_native(_)) { ret true; }
case (ty_ptr(_)) { ret true; }
case (_) { ret false; }
}
case (ty_machine(_)) { /* no-op */ }
case (ty_char) { /* no-op */ }
case (ty_type) { /* no-op */ }
- case (ty_native) { /* no-op */ }
+ case (ty_native(_)) { /* no-op */ }
case (ty_tup(?elts)) {
for (mt m in elts) {
if (type_has_pointers(cx, m.ty)) { result = true; }
// type_is_scalar?
fn type_is_native(&ctxt cx, &t ty) -> bool {
alt (struct(cx, ty)) {
- case (ty_native) { ret true; }
+ case (ty_native(_)) { ret true; }
case (_) { ret false; }
}
}
case (ty_var(_)) { fail "ty_var in type_has_dynamic_size()"; }
case (ty_param(_)) { ret true; }
case (ty_type) { ret false; }
- case (ty_native) { ret false; }
+ case (ty_native(_)) { ret false; }
}
}
case (ty_machine(_)) { result = false; }
case (ty_char) { result = false; }
case (ty_type) { result = false; }
- case (ty_native) { result = false; }
+ case (ty_native(_)) { result = false; }
// boxed types
case (ty_str) { result = false; }
ret none[uint];
}
+fn type_autoderef(&ctxt cx, &ty::t t) -> ty::t {
+ let ty::t t1 = t;
+ while (true) {
+ alt (struct(cx, t1)) {
+ case (ty::ty_box(?mt)) { t1 = mt.ty; }
+ case (ty::ty_res(_, ?inner, ?tps)) {
+ t1 = substitute_type_params(cx, tps, inner);
+ }
+ case (ty::ty_tag(?did, ?tps)) {
+ auto variants = tag_variants(cx, did);
+ if (vec::len(variants) != 1u ||
+ vec::len(variants.(0).args) != 1u) {
+ break;
+ }
+ t1 = substitute_type_params(cx, tps, variants.(0).args.(0));
+ }
+ case (_) { break; }
+ }
+ }
+ ret t1;
+}
+
fn def_to_str(&ast::def_id did) -> str { ret #fmt("%d:%d", did._0, did._1); }
case (ty_var(?v)) { ret hash_uint(30u, v as uint); }
case (ty_param(?pid)) { ret hash_uint(31u, pid); }
case (ty_type) { ret 32u; }
- case (ty_native) { ret 33u; }
+ case (ty_native(?did)) { ret hash_def(33u, did); }
case (ty_bot) { ret 34u; }
case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); }
case (ty_res(?did, ?sub, ?tps)) {
case (ty_type) {
alt (b) { case (ty_type) { ret true; } case (_) { ret false; } }
}
- case (ty_native) {
- alt (b) { case (ty_native) { ret true; } case (_) { ret false; } }
+ case (ty_native(?a_id)) {
+ alt (b) {
+ case (ty_native(?b_id)) {
+ ret a_id._0 == b_id._0 && a_id._1 == b_id._1;
+ }
+ case (_) { ret false; } }
}
}
}
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
fn pat_ty(&ctxt cx, &@ast::pat pat) -> t {
- ret node_id_to_monotype(cx, pat_node_id(pat));
+ ret node_id_to_monotype(cx, pat.id);
}
}
}
-fn pat_node_id(&@ast::pat p) -> ast::node_id {
- alt (p.node) {
- case (ast::pat_wild(?id)) { ret id; }
- case (ast::pat_bind(_, ?id)) { ret id; }
- case (ast::pat_lit(_, ?id)) { ret id; }
- case (ast::pat_tag(_, _, ?id)) { ret id; }
- }
-}
-
-
// Expression utilities
fn field_num(&session::session sess, &span sp, &ast::ident id) -> uint {
let uint accum = 0u;
}
alt (struct(cx.tcx, expected)) {
case (ty::ty_nil) { ret struct_cmp(cx, expected, actual); }
- case (
- // _|_ unifies with anything
- ty::ty_bot) {
+ // _|_ unifies with anything
+ case (ty::ty_bot) {
ret ures_ok(actual);
}
case (ty::ty_bool) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_str) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_istr) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_type) { ret struct_cmp(cx, expected, actual); }
- case (ty::ty_native) { ret struct_cmp(cx, expected, actual); }
+ case (ty::ty_native(?ex_id)) {
+ alt (struct(cx.tcx, actual)) {
+ case (ty_native(?act_id)) {
+ if (ex_id._0 == act_id._0 && ex_id._1 == act_id._1) {
+ ret ures_ok(actual);
+ } else {
+ ret ures_err(terr_mismatch);
+ }
+ }
+ case (_) { ret ures_err(terr_mismatch); }
+ }
+ }
case (ty::ty_param(_)) { ret struct_cmp(cx, expected, actual); }
case (ty::ty_tag(?expected_id, ?expected_tps)) {
alt (struct(cx.tcx, actual)) {
// NB: This function requires that the given type has no variables. So, inside
-// typeck, you should use typeck::strip_boxes() instead.
+// typeck, you should use typeck::do_autoderef() instead.
fn strip_boxes(&ctxt cx, &ty::t t) -> ty::t {
auto t1 = t;
while (true) {
import front::ast;
import front::ast::mutability;
import front::ast::local_def;
+import front::ast::path_to_str;
import metadata::decoder;
import driver::session;
import util::common;
import middle::ty::mo_alias;
import middle::ty::node_type_table;
import middle::ty::pat_ty;
-import middle::ty::path_to_str;
import middle::ty::ty_param_substs_opt_and_ty;
import pretty::ppaux::ty_to_str;
import middle::ty::ty_param_count_and_ty;
// Used for ast_ty_to_ty() below.
type ty_getter = fn(&ast::def_id) -> ty::ty_param_count_and_ty ;
+fn lookup_local(&@fn_ctxt fcx, &span sp, ast::node_id id) -> int {
+ alt (fcx.locals.find(id)) {
+ case (some(?x)) { x }
+ case (_) {
+ fcx.ccx.tcx.sess.span_fatal(sp, "internal error looking up a \
+ local var")
+ }
+ }
+}
+
+fn lookup_def(&@fn_ctxt fcx, &span sp, ast::node_id id) -> ast::def {
+ alt (fcx.ccx.tcx.def_map.find(id)) {
+ case (some(?x)) { x }
+ case (_) {
+ fcx.ccx.tcx.sess.span_fatal(sp, "internal error looking up \
+ a definition")
+ }
+ }
+}
// Returns the type parameter count and the type for the given definition.
fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) ->
alt (defn) {
case (ast::def_arg(?id)) {
assert (fcx.locals.contains_key(id._1));
- auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id._1));
+ auto typ = ty::mk_var(fcx.ccx.tcx,
+ lookup_local(fcx, sp, id._1));
ret tup(0u, typ);
}
case (ast::def_local(?id)) {
assert (fcx.locals.contains_key(id._1));
- auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id._1));
+ auto typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id._1));
ret tup(0u, typ);
}
case (ast::def_obj_field(?id)) {
assert (fcx.locals.contains_key(id._1));
- auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id._1));
+ auto typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id._1));
ret tup(0u, typ);
}
case (ast::def_fn(?id, _)) {
}
case (ast::def_binding(?id)) {
assert (fcx.locals.contains_key(id._1));
- auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id._1));
+ auto typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id._1));
ret tup(0u, typ);
}
case (ast::def_mod(_)) {
typ = ty::mk_fn(tcx, proto, i, out_ty, cf, out_constrs);
}
case (ast::ty_path(?path, ?id)) {
- alt (tcx.def_map.get(id)) {
- case (ast::def_ty(?id)) {
+ alt (tcx.def_map.find(id)) {
+ case (some(ast::def_ty(?id))) {
typ =
instantiate(tcx, ast_ty.span, getter, id,
path.node.types);
}
- case (ast::def_native_ty(?id)) { typ = getter(id)._1; }
- case (ast::def_ty_arg(?id)) { typ = ty::mk_param(tcx, id); }
- case (_) {
+ case (some(ast::def_native_ty(?id))) { typ = getter(id)._1; }
+ case (some(ast::def_ty_arg(?id))) {
+ typ = ty::mk_param(tcx, id);
+ }
+ case (some(_)) {
tcx.sess.span_fatal(ast_ty.span,
"found type name used as a variable");
}
+ case (_) {
+ tcx.sess.span_fatal(ast_ty.span,
+ "internal error in instantiate");
+ }
}
cname = some(path_to_str(path));
}
ret decoder::get_type(cx.tcx, id);
}
- auto it = cx.tcx.items.get(id._1);
+ auto it = cx.tcx.items.find(id._1);
auto tpt;
alt (it) {
- case (ast_map::node_item(?item)) { tpt = ty_of_item(cx, item); }
- case (ast_map::node_native_item(?native_item)) {
+ case (some(ast_map::node_item(?item))) {
+ tpt = ty_of_item(cx, item);
+ }
+ case (some(ast_map::node_native_item(?native_item))) {
tpt = ty_of_native_item(cx, native_item,
ast::native_abi_cdecl);
}
+ case (_) {
+ cx.tcx.sess.fatal("internal error " +
+ util::common::istr(id._1));
+ }
}
ret tpt;
}
case (some(?tpt)) { ret tpt; }
case (none) { }
}
- auto t = ty::mk_native(cx.tcx);
+ auto t = ty::mk_native(cx.tcx, ast::local_def(it.id));
auto tpt = tup(0u, t);
cx.tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
tag autoderef_kind { AUTODEREF_OK; NO_AUTODEREF; }
-fn strip_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> ty::t {
+// FIXME This is almost a duplicate of ty::type_autoderef, with structure_of
+// instead of ty::struct.
+fn do_autoderef(&@fn_ctxt fcx, &span sp, &ty::t t) -> ty::t {
auto t1 = t;
while (true) {
alt (structure_of(fcx, sp, t1)) {
case (ty::ty_box(?inner)) { t1 = inner.ty; }
+ case (ty::ty_res(_, ?inner, ?tps)) {
+ t1 = ty::substitute_type_params(fcx.ccx.tcx, tps, inner);
+ }
+ case (ty::ty_tag(?did, ?tps)) {
+ auto variants = ty::tag_variants(fcx.ccx.tcx, did);
+ if (vec::len(variants) != 1u ||
+ vec::len(variants.(0).args) != 1u) {
+ ret t1;
+ }
+ t1 = ty::substitute_type_params(fcx.ccx.tcx, tps,
+ variants.(0).args.(0));
+ }
case (_) { ret t1; }
}
}
auto actual_1 = actual;
auto implicit_boxes = 0u;
if (adk == AUTODEREF_OK) {
- expected_1 = strip_boxes(fcx, sp, expected_1);
- actual_1 = strip_boxes(fcx, sp, actual_1);
+ expected_1 = do_autoderef(fcx, sp, expected_1);
+ actual_1 = do_autoderef(fcx, sp, actual_1);
implicit_boxes = count_boxes(fcx, sp, actual);
}
let vec[mutable ty::t] ty_param_substs = [mutable ];
resolve_type_vars_for_node(fcx, b.span, b.node.id);
}
fn visit_pat_pre(@fn_ctxt fcx, &@ast::pat p) {
- resolve_type_vars_for_node(fcx, p.span, ty::pat_node_id(p));
+ resolve_type_vars_for_node(fcx, p.span, p.id);
}
fn visit_local_pre(@fn_ctxt fcx, &@ast::local l) {
- auto var_id = fcx.locals.get(l.node.id);
+ auto var_id = lookup_local(fcx, l.span, l.node.id);
auto fix_rslt =
ty::unify::resolve_type_var(fcx.ccx.tcx, fcx.var_bindings,
var_id);
hashmap[ast::node_id, ast::ident] local_names,
@mutable int nvi, &@ast::pat p) {
alt (p.node) {
- case (ast::pat_bind(?ident, ?id)) {
+ case (ast::pat_bind(?ident)) {
assign(ccx.tcx, vb, locals, local_names, nvi,
- id, ident, none[ty::t]);
+ p.id, ident, none[ty::t]);
}
case (_) {/* no-op */ }
}
// their types immediately.
fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) {
alt (pat.node) {
- case (ast::pat_wild(?id)) {
- write::ty_only_fixup(fcx, id, expected);
+ case (ast::pat_wild) {
+ write::ty_only_fixup(fcx, pat.id, expected);
}
- case (ast::pat_lit(?lt, ?id)) {
+ case (ast::pat_lit(?lt)) {
auto typ = check_lit(fcx.ccx, lt);
typ = demand::simple(fcx, pat.span, expected, typ);
- write::ty_only_fixup(fcx, id, typ);
+ write::ty_only_fixup(fcx, pat.id, typ);
}
- case (ast::pat_bind(?name, ?id)) {
- auto vid = fcx.locals.get(id);
+ case (ast::pat_bind(?name)) {
+ auto vid = lookup_local(fcx, pat.span, pat.id);
auto typ = ty::mk_var(fcx.ccx.tcx, vid);
typ = demand::simple(fcx, pat.span, expected, typ);
- write::ty_only_fixup(fcx, id, typ);
+ write::ty_only_fixup(fcx, pat.id, typ);
}
- case (ast::pat_tag(?path, ?subpats, ?id)) {
+ case (ast::pat_tag(?path, ?subpats)) {
// Typecheck the path.
-
- auto v_def = fcx.ccx.tcx.def_map.get(id);
+ auto v_def = lookup_def(fcx, path.span, pat.id);
auto v_def_ids = ast::variant_def_ids(v_def);
auto tag_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids._0);
auto path_tpot = instantiate_path(fcx, path, tag_tpt, pat.span);
""
} else { "s" }));
}
- write::ty_fixup(fcx, id, path_tpot);
+ write::ty_fixup(fcx, pat.id, path_tpot);
}
}
}
alt (caller_purity) {
case (ast::impure_fn) { ret; }
case (ast::pure_fn) {
- alt (ccx.tcx.def_map.get(callee.id)) {
- case (ast::def_fn(_, ast::pure_fn)) {
+ alt (ccx.tcx.def_map.find(callee.id)) {
+ case (some(ast::def_fn(_, ast::pure_fn))) {
ret;
}
case (_) {
// expressions.
fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f,
- &vec[option::t[@ast::expr]] args) {
+ &vec[option::t[@ast::expr]] args, bool is_call) {
// Check the function.
check_expr(fcx, f);
// Get the function type.
auto fty = expr_ty(fcx.ccx.tcx, f);
- // Grab the argument types and the return type.
+ // We want to autoderef calls but not binds
+ auto fty_stripped =
+ if (is_call) { do_autoderef(fcx, sp, fty) } else { fty };
+
+ // Grab the argument types and the return type.
auto arg_tys;
- alt (structure_of(fcx, sp, fty)) {
+ alt (structure_of(fcx, sp, fty_stripped)) {
case (ty::ty_fn(_, ?arg_tys_0, _, _, _)) { arg_tys = arg_tys_0; }
case (ty::ty_native_fn(_, ?arg_tys_0, _)) { arg_tys = arg_tys_0; }
case (_) {
}
// Call the generic checker.
- check_call_or_bind(fcx, sp, f, args_opt_0);
+ check_call_or_bind(fcx, sp, f, args_opt_0, true);
}
// A generic function for checking for or for-each loops
case (ast::expr_call(?operator, ?operands)) {
alt (operator.node) {
case (ast::expr_path(?oper_name)) {
- alt (fcx.ccx.tcx.def_map.get(operator.id)) {
- case (ast::def_fn(?_d_id, ast::pure_fn)) {
+ alt (fcx.ccx.tcx.def_map.find(operator.id)) {
+ case (some(ast::def_fn(?_d_id,
+ ast::pure_fn))) {
// do nothing
}
case (_) {
case (ast::ne) { ty::mk_bool(fcx.ccx.tcx) }
case (ast::ge) { ty::mk_bool(fcx.ccx.tcx) }
case (ast::gt) { ty::mk_bool(fcx.ccx.tcx) }
- case (_) { strip_boxes(fcx, expr.span, lhs_t) }
+ case (_) { do_autoderef(fcx, expr.span, lhs_t) }
};
write::ty_only_fixup(fcx, id, t);
}
alt (structure_of(fcx, expr.span, oper_t)) {
case (ty::ty_box(?inner)) { oper_t = inner.ty; }
case (ty::ty_res(_, ?inner, _)) { oper_t = inner; }
+ case (ty::ty_tag(?id, ?tps)) {
+ auto variants = ty::tag_variants(fcx.ccx.tcx, id);
+ if (vec::len(variants) != 1u ||
+ vec::len(variants.(0).args) != 1u) {
+ fcx.ccx.tcx.sess.span_fatal
+ (expr.span, "can only dereference tags " +
+ "with a single variant which has a " +
+ "single argument");
+ }
+ oper_t = ty::substitute_type_params
+ (fcx.ccx.tcx, tps, variants.(0).args.(0));
+ }
case (_) {
- auto s = "dereferencing non-box type: " +
- ty_to_str(fcx.ccx.tcx, oper_t);
- fcx.ccx.tcx.sess.span_fatal(expr.span, s);
+ fcx.ccx.tcx.sess.span_fatal
+ (expr.span, "dereferencing non-" +
+ "dereferenceable type: " +
+ ty_to_str(fcx.ccx.tcx, oper_t));
}
}
}
oper_t)));
}
}
- case (_) { oper_t = strip_boxes(fcx, expr.span, oper_t); }
+ case (_) { oper_t = do_autoderef(fcx, expr.span, oper_t); }
}
write::ty_only_fixup(fcx, id, oper_t);
}
case (ast::expr_path(?pth)) {
- auto defn = fcx.ccx.tcx.def_map.get(id);
+ auto defn = lookup_def(fcx, pth.span, id);
auto tpt = ty_param_count_and_ty_for_def(fcx, expr.span, defn);
if (ty::def_has_ty_params(defn)) {
auto path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
auto t = expr_ty(fcx.ccx.tcx, expanded);
write::ty_only_fixup(fcx, id, t);
}
- case (ast::expr_fail(_)) { write::bot_ty(fcx.ccx.tcx, id); }
+ case (ast::expr_fail(?expr_opt)) {
+ alt (expr_opt) {
+ case (none) { /* do nothing */ }
+ case (some(?e)) {
+ check_expr(fcx, e);
+ auto tcx = fcx.ccx.tcx;
+ auto ety = expr_ty(tcx, e);
+ demand::simple(fcx, e.span, ty::mk_str(tcx), ety);
+ }
+ }
+ write::bot_ty(fcx.ccx.tcx, id);
+ }
case (ast::expr_break) { write::bot_ty(fcx.ccx.tcx, id); }
case (ast::expr_cont) { write::bot_ty(fcx.ccx.tcx, id); }
case (ast::expr_ret(?expr_opt)) {
case (ast::expr_bind(?f, ?args)) {
// Call the generic checker.
- check_call_or_bind(fcx, expr.span, f, args);
+ check_call_or_bind(fcx, expr.span, f, args, false);
// Pull the argument and return types out.
auto proto_1;
// Pull the return type out of the type of the function.
auto rt_1;
- auto fty = ty::expr_ty(fcx.ccx.tcx, f);
+ auto fty = do_autoderef(fcx, expr.span,
+ ty::expr_ty(fcx.ccx.tcx, f));
alt (structure_of(fcx, expr.span, fty)) {
case (ty::ty_fn(_, _, ?rt, _, _)) { rt_1 = rt; }
case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; }
case (ast::expr_field(?base, ?field)) {
check_expr(fcx, base);
auto base_t = expr_ty(fcx.ccx.tcx, base);
- base_t = strip_boxes(fcx, expr.span, base_t);
+ base_t = do_autoderef(fcx, expr.span, base_t);
alt (structure_of(fcx, expr.span, base_t)) {
case (ty::ty_tup(?args)) {
let uint ix =
case (ast::expr_index(?base, ?idx)) {
check_expr(fcx, base);
auto base_t = expr_ty(fcx.ccx.tcx, base);
- base_t = strip_boxes(fcx, expr.span, base_t);
+ base_t = do_autoderef(fcx, expr.span, base_t);
check_expr(fcx, idx);
auto idx_t = expr_ty(fcx.ccx.tcx, idx);
if (!type_is_integral(fcx, idx.span, idx_t)) {
fn check_decl_initializer(&@fn_ctxt fcx, ast::node_id nid,
&ast::initializer init) {
check_expr(fcx, init.expr);
- auto lty = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(nid));
+ auto lty = ty::mk_var(fcx.ccx.tcx,
+ lookup_local(fcx, init.expr.span, nid));
alt (init.op) {
case (ast::init_assign) {
demand::simple(fcx, init.expr.span, lty,
fn visit_crate_directive[E](&@crate_directive cd, &E e, &vt[E] v) {
alt (cd.node) {
- case (cdir_let(_, ?ex, ?cdirs)) {
- vt(v).visit_expr(ex, e, v);
- for (@crate_directive cdir in cdirs) {
- visit_crate_directive(cdir, e, v);
- }
- }
case (cdir_src_mod(_, _, _)) { }
case (cdir_dir_mod(_, _, ?cdirs, _)) {
for (@crate_directive cdir in cdirs) {
fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
alt (p.node) {
- case (pat_tag(?path, ?children, _)) {
+ case (pat_tag(?path, ?children)) {
for (@ty tp in path.node.types) { vt(v).visit_ty(tp, e, v); }
for (@pat child in children) { vt(v).visit_pat(child, e, v); }
}
case (expr_ext(_, _, _, ?expansion)) {
vt(v).visit_expr(expansion, e, v);
}
- case (expr_fail(_)) { }
+ case (expr_fail(?eo)) {
+ visit_expr_opt(eo, e, v);
+ }
case (expr_break) { }
case (expr_cont) { }
case (expr_ret(?eo)) { visit_expr_opt(eo, e, v); }
if (!v.want_crate_directives()) { ret; }
v.visit_crate_directive_pre(cd);
alt (cd.node) {
- case (ast::cdir_let(_, ?e, ?cdirs)) {
- walk_expr(v, e);
- for (@ast::crate_directive cdir in cdirs) {
- walk_crate_directive(v, cdir);
- }
- }
case (ast::cdir_src_mod(_, _, _)) { }
case (ast::cdir_dir_mod(_, _, ?cdirs, _)) {
for (@ast::crate_directive cdir in cdirs) {
fn walk_pat(&ast_visitor v, &@ast::pat p) {
v.visit_pat_pre(p);
alt (p.node) {
- case (ast::pat_tag(?path, ?children, _)) {
+ case (ast::pat_tag(?path, ?children)) {
for (@ast::ty tp in path.node.types) { walk_ty(v, tp); }
for (@ast::pat child in children) { walk_pat(v, child); }
}
walk_expr(v, expansion);
}
- case (ast::expr_fail(_)) { }
+ case (ast::expr_fail(?eo)) { walk_expr_opt(v, eo); }
case (ast::expr_break) { }
case (ast::expr_cont) { }
case (ast::expr_ret(?eo)) { walk_expr_opt(v, eo); }
alt (cname(cx, typ)) { case (some(?cs)) { ret cs; } case (_) { } }
auto s = "";
alt (struct(cx, typ)) {
- case (ty_native) { s += "native"; }
+ case (ty_native(_)) { s += "native"; }
case (ty_nil) { s += "()"; }
case (ty_bot) { s += "_|_"; }
case (ty_bool) { s += "bool"; }
auto m = vec::map[method, str](f, meths);
s += "obj {\n\t" + str::connect(m, "\n\t") + "\n}";
}
+ case (ty_res(?id, _, _)) {
+ s += "<resource#" + istr(id._0) + ":" + istr(id._1) + ">";
+ }
case (ty_var(?v)) { s += "<T" + istr(v) + ">"; }
case (ty_param(?id)) {
s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]);
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) +
+ ret ast::path_to_str(c.node.path) +
constr_args_to_str(uint_to_str, c.node.args);
}
fn ast_constr_to_str(&@front::ast::constr c) -> str {
- ret path_to_str(c.node.path) +
+ ret ast::path_to_str(c.node.path) +
constr_args_to_str(uint_to_str, c.node.args);
}
break_offset(s.s, 0u, 0);
}
case (ast::item_tag(?variants, ?params)) {
- head(s, "tag");
+ auto newtype = vec::len(variants) == 1u &&
+ str::eq(item.ident, variants.(0).node.name) &&
+ vec::len(variants.(0).node.args) == 1u;
+ if (newtype) {
+ ibox(s, indent_unit);
+ word_space(s, "tag");
+ } else {
+ head(s, "tag");
+ }
word(s.s, item.ident);
print_type_params(s, params);
space(s.s);
- bopen(s);
- for (ast::variant v in variants) {
- space(s.s);
- maybe_print_comment(s, v.span.lo);
- word(s.s, v.node.name);
- if (vec::len(v.node.args) > 0u) {
- popen(s);
- fn print_variant_arg(&ps s, &ast::variant_arg arg) {
- print_type(s, *arg.ty);
+ if (newtype) {
+ word_space(s, "=");
+ print_type(s, *variants.(0).node.args.(0).ty);
+ word(s.s, ";");
+ end(s);
+ } else {
+ bopen(s);
+ for (ast::variant v in variants) {
+ space(s.s);
+ maybe_print_comment(s, v.span.lo);
+ word(s.s, v.node.name);
+ if (vec::len(v.node.args) > 0u) {
+ popen(s);
+ fn print_variant_arg(&ps s, &ast::variant_arg arg) {
+ print_type(s, *arg.ty);
+ }
+ commasep(s, consistent, v.node.args,
+ print_variant_arg);
+ pclose(s);
}
- commasep(s, consistent, v.node.args, print_variant_arg);
- pclose(s);
+ word(s.s, ";");
+ maybe_print_trailing_comment(s, v.span, none[uint]);
}
- word(s.s, ";");
- maybe_print_trailing_comment(s, v.span, none[uint]);
+ bclose(s, item.span);
}
- bclose(s, item.span);
}
case (ast::item_obj(?_obj, ?params, _)) {
head(s, "obj");
bclose(s, item.span);
}
case (ast::item_res(?dt, ?dt_id, ?tps, ?ct_id)) {
- head(s, "res");
+ head(s, "resource");
word(s.s, item.ident);
print_type_params(s, tps);
popen(s);
pclose(s);
}
case (ast::expr_path(?path)) { print_path(s, path); }
- case (ast::expr_fail(?str)) {
+ case (ast::expr_fail(?maybe_fail_val)) {
word(s.s, "fail");
- alt (str) {
- case (some(?msg)) { word(s.s, #fmt(" \"%s\"", msg)); }
+ alt (maybe_fail_val) {
+ case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
case (_) { }
}
}
fn print_pat(&ps s, &@ast::pat pat) {
maybe_print_comment(s, pat.span.lo);
alt (pat.node) {
- case (ast::pat_wild(_)) { word(s.s, "_"); }
- case (ast::pat_bind(?id, _)) { word(s.s, "?" + id); }
- case (ast::pat_lit(?lit, _)) { print_literal(s, lit); }
- case (ast::pat_tag(?path, ?args, _)) {
+ case (ast::pat_wild) { word(s.s, "_"); }
+ case (ast::pat_bind(?id)) { word(s.s, "?" + id); }
+ case (ast::pat_lit(?lit)) { print_literal(s, lit); }
+ case (ast::pat_tag(?path, ?args)) {
print_path(s, path);
if (vec::len(args) > 0u) {
popen(s);
alt (s.mode) {
case (mo_identified) {
space(s.s);
- synth_comment(s, int::to_str(ty::pat_node_id(pat), 10u));
+ synth_comment(s, int::to_str(pat.id, 10u));
}
case (_) {/* no-op */ }
}
// -*- rust -*-
use std;
-use rustc;
mod fuzzer;
import std::io;
import std::vec;
-import rustc::front::ast;
-
type src_gen = iter() -> str;
iter dir_src_gen(str dir) -> str {
rust_chan::rust_chan(rust_task *task,
maybe_proxy<rust_port> *port,
size_t unit_sz) :
+ ref_count(1),
task(task),
port(port),
buffer(task, unit_sz) {
return;
}
+
+rust_chan *rust_chan::clone(maybe_proxy<rust_task> *target) {
+ size_t unit_sz = buffer.unit_sz;
+ maybe_proxy<rust_port> *port = this->port;
+ rust_task *target_task = NULL;
+ if (target->is_proxy() == false) {
+ port = this->port;
+ target_task = target->referent();
+ } else {
+ rust_handle<rust_port> *handle =
+ task->sched->kernel->get_port_handle(port->as_referent());
+ maybe_proxy<rust_port> *proxy = new rust_proxy<rust_port> (handle);
+ LOG(task, mem, "new proxy: " PTR, proxy);
+ port = proxy;
+ target_task = target->as_proxy()->handle()->referent();
+ }
+ return new (target_task) rust_chan(target_task, port, unit_sz);
+}
+
+/**
+ * Cannot Yield: If the task were to unwind, the dropped ref would still
+ * appear to be live, causing modify-after-free errors.
+ */
+void rust_chan::destroy() {
+ A(task->sched, ref_count == 0,
+ "Channel's ref count should be zero.");
+
+ if (is_associated()) {
+ if (port->is_proxy()) {
+ // Here is a good place to delete the port proxy we allocated
+ // in upcall_clone_chan.
+ rust_proxy<rust_port> *proxy = port->as_proxy();
+ disassociate();
+ delete proxy;
+ } else {
+ // We're trying to delete a channel that another task may be
+ // reading from. We have two options:
+ //
+ // 1. We can flush the channel by blocking in upcall_flush_chan()
+ // and resuming only when the channel is flushed. The problem
+ // here is that we can get ourselves in a deadlock if the
+ // parent task tries to join us.
+ //
+ // 2. We can leave the channel in a "dormnat" state by not freeing
+ // it and letting the receiver task delete it for us instead.
+ if (buffer.is_empty() == false) {
+ return;
+ }
+ disassociate();
+ }
+ }
+ delete this;
+}
+
//
// Local Variables:
// mode: C++
#ifndef RUST_CHAN_H
#define RUST_CHAN_H
-class rust_chan : public rc_base<rust_chan>,
- public task_owned<rust_chan>,
+class rust_chan : public task_owned<rust_chan>,
public rust_cond {
public:
+ RUST_REFCOUNTED_WITH_DTOR(rust_chan, destroy())
rust_chan(rust_task *task, maybe_proxy<rust_port> *port, size_t unit_sz);
~rust_chan();
bool is_associated();
void send(void *sptr);
+
+ rust_chan *clone(maybe_proxy<rust_task> *target);
+
+ // Called whenever the channel's ref count drops to zero.
+ void destroy();
};
//
static size_t const BUF_BYTES = 2048;
// Every reference counted object should derive from this base class.
+// Or use this macro. The macro is preferred as the base class will be
+// disappearing.
-template <typename T> struct rc_base {
- intptr_t ref_count;
-
- void ref() {
- ++ref_count;
- }
+#define RUST_REFCOUNTED(T) \
+ RUST_REFCOUNTED_WITH_DTOR(T, delete (T*)this)
+#define RUST_REFCOUNTED_WITH_DTOR(T, dtor) \
+ intptr_t ref_count; \
+ void ref() { ++ref_count; } \
+ void deref() { if (--ref_count == 0) { dtor; } }
- void deref() {
- if (--ref_count == 0) {
- delete (T*)this;
- }
- }
+template <typename T> struct rc_base {
+ RUST_REFCOUNTED(T)
rc_base();
~rc_base();
scoped_lock with(task->kernel->scheduler_lock);
LOG(task, comm, "upcall del_chan(0x%" PRIxPTR ")", (uintptr_t) chan);
-
- A(task->sched, chan->ref_count == 0,
- "Channel's ref count should be zero.");
-
- if (chan->is_associated()) {
- if (chan->port->is_proxy()) {
- // Here is a good place to delete the port proxy we allocated
- // in upcall_clone_chan.
- rust_proxy<rust_port> *proxy = chan->port->as_proxy();
- chan->disassociate();
- delete proxy;
- } else {
- // We're trying to delete a channel that another task may be
- // reading from. We have two options:
- //
- // 1. We can flush the channel by blocking in upcall_flush_chan()
- // and resuming only when the channel is flushed. The problem
- // here is that we can get ourselves in a deadlock if the
- // parent task tries to join us.
- //
- // 2. We can leave the channel in a "dormant" state by not freeing
- // it and letting the receiver task delete it for us instead.
- if (chan->buffer.is_empty() == false) {
- return;
- }
- chan->disassociate();
- }
- }
- delete chan;
+ chan->destroy();
}
/**
rust_chan *chan) {
LOG_UPCALL_ENTRY(task);
scoped_lock with(task->kernel->scheduler_lock);
- size_t unit_sz = chan->buffer.unit_sz;
- maybe_proxy<rust_port> *port = chan->port;
- rust_task *target_task = NULL;
- if (target->is_proxy() == false) {
- port = chan->port;
- target_task = target->referent();
- } else {
- rust_handle<rust_port> *handle =
- task->sched->kernel->get_port_handle(port->as_referent());
- maybe_proxy<rust_port> *proxy = new rust_proxy<rust_port> (handle);
- LOG(task, mem, "new proxy: " PTR, proxy);
- port = proxy;
- target_task = target->as_proxy()->handle()->referent();
- }
- return new (target_task) rust_chan(target_task, port, unit_sz);
+ return chan->clone(target);
}
extern "C" CDECL void
--- /dev/null
+// error-pattern: mismatched types
+
+fn add1(int i) -> int { ret i+1; }
+fn main() {
+ auto f = @add1;
+ auto g = bind f(5);
+}
--- /dev/null
+// error-pattern:expected a syntax expander name
+
+fn main() {
+ #();
+}
\ No newline at end of file
--- /dev/null
+// error-pattern:mismatched types
+
+fn main() {
+ fail 5;
+}
\ No newline at end of file
// -*- rust -*-
-// error-pattern: after expression but found
+// error-pattern:unexpected token
fn main() {
fail @ ;
}
--- /dev/null
+// error-pattern:can't find crate for 'std'
+
+use std (complex(meta(item)));
+
+fn main() {}
\ No newline at end of file
--- /dev/null
+// xfail-stage0
+// error-pattern:meep
+fn f(int a, int b, @int c) {
+ fail "moop";
+}
+
+fn main() {
+ f(1, fail "meep", @42);
+}
\ No newline at end of file
-
-// error-pattern:woooo
-fn main() { fail"woooo"; }
\ No newline at end of file
+// error-pattern:wooooo
+fn main() {
+ auto a = 1;
+ if (1 == 1) {
+ a = 2;
+ }
+ fail "woooo" + "o";
+}
\ No newline at end of file
--- /dev/null
+// xfail-stage0
+// error-pattern:woe
+fn f(int a) {
+ log a;
+}
+
+fn main() {
+ f(fail "woe");
+}
--- /dev/null
+// xfail-stage0
+// error-pattern:meh
+use std;
+import std::str;
+
+fn main() {
+ let str str_var = "meh";
+ fail #fmt("%s", str_var);
+}
\ No newline at end of file
--- /dev/null
+// xfail-stage0
+
+fn add1(int i) -> int { ret i+1; }
+fn main() {
+ auto f = @add1;
+ auto g = @f;
+ auto h = @@@add1;
+ assert(f(5) == 6);
+ assert(g(8) == 9);
+ assert(h(0x1badd00d) == 0x1badd00e);
+}
--- /dev/null
+tag myvec[X] = vec[X];
+
+fn myvec_deref[X](&myvec[X] mv) -> vec[X] {
+ ret *mv;
+}
+
+fn myvec_elt[X](&myvec[X] mv) -> X {
+ ret mv.(0);
+}
+
+fn main() {
+ auto mv = myvec([1, 2, 3]);
+ assert(myvec_deref(mv).(1) == 2);
+ assert(myvec_elt(mv) == 1);
+ assert(mv.(2) == 3);
+}
--- /dev/null
+tag mytype = rec(fn (&mytype i) -> int compute, int val);
+
+fn compute(&mytype i) -> int {
+ ret i.val + 20;
+}
+
+fn main() {
+ auto myval = mytype(rec(compute=compute, val=30));
+ assert(myval.compute(myval) == 50);
+}