diff --git a/AUTHORS.txt b/AUTHORS.txt index 38bfb6e90b6b4..e7efbd7aeaa69 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -17,6 +17,7 @@ Jason Orendorff Jeff Balogh Jeff Muizelaar Jeffrey Yasskin +Josh Matthews Kelly Wilson Lindsey Kuper Marijn Haverbeke diff --git a/Makefile.in b/Makefile.in index ecff84dc4c002..50224f62a0d8a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -144,9 +144,9 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/comp/, \ ###################################################################### LREQ := rt/$(CFG_RUNTIME) rustllvm/$(CFG_RUSTLLVM) -SREQ0 := stage0/rustc$(X) $(LREQ) stage1/glue.o stage1/$(CFG_STDLIB) -SREQ1 := stage1/rustc$(X) $(LREQ) stage2/glue.o stage2/$(CFG_STDLIB) -SREQ2 := stage2/rustc$(X) $(LREQ) stage3/glue.o stage3/$(CFG_STDLIB) +SREQ0 := stage0/rustc$(X) $(LREQ) rt/main.o stage1/glue.o stage1/$(CFG_STDLIB) +SREQ1 := stage1/rustc$(X) $(LREQ) rt/main.o stage2/glue.o stage2/$(CFG_STDLIB) +SREQ2 := stage2/rustc$(X) $(LREQ) rt/main.o stage3/glue.o stage3/$(CFG_STDLIB) ###################################################################### diff --git a/mk/clean.mk b/mk/clean.mk index 3f19953929e55..5353006fe7caf 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -28,6 +28,7 @@ clean: $(Q)rm -f stage3/rustc$(X) stage3/$(CFG_STDLIB) stage3/glue* $(Q)rm -f rustllvm/$(CFG_RUSTLLVM) rustllvm/rustllvmbits.a $(Q)rm -f rt/$(CFG_RUNTIME) + $(Q)rm -f rt/main.o $(Q)rm -Rf $(PKG_NAME)-*.tar.gz dist $(Q)rm -f $(foreach ext,o a d bc s exe,$(wildcard stage*/*.$(ext))) $(Q)rm -Rf $(foreach ext,out out.tmp \ diff --git a/mk/rt.mk b/mk/rt.mk index 8139f9e4e794e..566e5f285d4e0 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -76,6 +76,14 @@ rt/%.o: rt/%.s $(MKFILES) @$(call E, compile: $@) $(Q)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $< +ifdef CFG_WINDOWSY +rt/main.ll: rt/main.ll.in + sed 's/MAIN/WinMain@16/' < $^ > $@ +else +rt/main.ll: rt/main.ll.in + sed 's/MAIN/main/' < $^ > $@ +endif + rt/%.o: rt/%.ll $(MKFILES) @$(call E, llc: $@) $(Q)$(LLC) -filetype=obj -relocation-model=pic -march=x86 -o $@ $< diff --git a/mk/stage1.mk b/mk/stage1.mk index f2ca6321d9455..d3a2ca52853dc 100644 --- a/mk/stage1.mk +++ b/mk/stage1.mk @@ -44,7 +44,7 @@ stage1/%.o: stage1/%.s stage1/%$(X): stage1/%.o $(SREQ0) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage1/glue.o -o $@ $< \ - -Lstage1 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm + -Lstage1 -Lrustllvm -Lrt rt/main.o -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/stage2.mk b/mk/stage2.mk index e084a19a8d3a7..a1c8da05ba3e4 100644 --- a/mk/stage2.mk +++ b/mk/stage2.mk @@ -44,7 +44,7 @@ stage2/%.o: stage2/%.s stage2/%$(X): stage2/%.o $(SREQ1) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o -o $@ $< \ - -Lstage2 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm + -Lstage2 -Lrustllvm -Lrt rt/main.o -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/stage3.mk b/mk/stage3.mk index dc2792446e21e..3654c17aa4451 100644 --- a/mk/stage3.mk +++ b/mk/stage3.mk @@ -23,7 +23,7 @@ stage3/rustc.o: $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ2) $(STAGE2) -c -o $@ $< stage3/glue.o: stage2/rustc$(X) stage2/$(CFG_STDLIB) stage2/intrinsics.bc \ - rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME) + rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME) @$(call E, generate: $@) $(STAGE2) -c -o $@ --glue @@ -44,7 +44,7 @@ stage3/%.o: stage3/%.s stage3/%$(X): stage3/%.o $(SREQ2) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage3/glue.o -o $@ $< \ - -Lstage3 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm + -Lstage3 -Lrustllvm -Lrt rt/main.o -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/tests.mk b/mk/tests.mk index 5e30b352dfa5b..79ab8d3774b62 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -185,7 +185,7 @@ compile-check: tidy \ %.stage0$(X): %.stage0.o $(SREQ0) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage1/glue.o -o $@ $< \ - -Lstage1 -Lrt -lrustrt -lstd -lm + -Lstage1 -Lrt rt/main.o -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. @@ -194,7 +194,7 @@ compile-check: tidy \ %.stage1$(X): %.stage1.o $(SREQ1) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o -o $@ $< \ - -Lstage2 -Lrt -lrustrt -lstd -lm + -Lstage2 -Lrt rt/main.o -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. @@ -203,7 +203,7 @@ compile-check: tidy \ %.stage2$(X): %.stage2.o $(SREQ2) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage3/glue.o -o $@ $< \ - -Lstage3 -Lrt -lrustrt -lstd -lm + -Lstage3 -Lrt rt/main.o -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 2ae7b6a6fab30..81c0f5a265a15 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -1,8 +1,18 @@ import driver::session; import lib::llvm::llvm; import middle::trans; +import middle::metadata; +import middle::ty; import std::str; import std::fs; +import std::vec; +import std::option; +import option::some; +import option::none; +import std::sha1::sha1; +import std::sort; +import trans::crate_ctxt; +import front::ast; import lib::llvm::llvm::ModuleRef; import lib::llvm::llvm::ValueRef; @@ -49,7 +59,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) { auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod); llvm::LLVMDisposeModule(llintrinsicsmod); - + if (linkres == False) { llvm_err(sess, "couldn't link the module with the intrinsics"); fail; @@ -58,7 +68,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) { mod write { fn is_object_or_assembly_or_exe(output_type ot) -> bool { - if ( (ot == output_type_assembly) || + if ( (ot == output_type_assembly) || (ot == output_type_object) || (ot == output_type_exe) ) { ret true; @@ -143,7 +153,6 @@ mod write { True, // unit-at-a-time True, // unroll loops True, // simplify lib calls - True, // have exceptions threshold); // inline threshold } @@ -218,3 +227,236 @@ mod write { } } +/* + * Name mangling and its relationship to metadata. This is complex. Read + * carefully. + * + * The semantic model of Rust linkage is, broadly, that "there's no global + * namespace" between crates. Our aim is to preserve the illusion of this + * model despite the fact that it's not *quite* possible to implement on + * modern linkers. We initially didn't use system linkers at all, but have + * been convinced of their utility. + * + * There are a few issues to handle: + * + * - Linkers operate on a flat namespace, so we have to flatten names. + * We do this using the C++ namespace-mangling technique. Foo::bar + * symbols and such. + * + * - Symbols with the same name but different types need to get different + * linkage-names. We do this by hashing a string-encoding of the type into + * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF: + * we use SHA1) to "prevent collisions". This is not airtight but 16 hex + * digits on uniform probability means you're going to need 2**32 same-name + * symbols in the same process before you're even hitting birthday-paradox + * collision probability. + * + * - Symbols in dirrerent crates but with same names "within" the crate need + * to get different linkage-names. + * + * So here is what we do: + * + * - Separate the meta tags into two sets: exported and local. Only work with + * the exported ones when considering linkage. + * + * - Consider two exported tags as special (and madatory): name and vers. + * Every crate gets them; if it doesn't name them explicitly we infer them + * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS. + * + * - Define CMETA as all the non-name, non-vers exported meta tags in the + * crate (in sorted order). + * + * - Define CMH as hash(CMETA). + * + * - Compile our crate to lib CNAME-CMH-CVERS.so + * + * - Define STH(sym) as hash(CNAME, CMH, type_str(sym)) + * + * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the + * name, non-name metadata, and type sense, and versioned in the way + * system linkers understand. + * + */ + + +iter crate_export_metas(ast::crate c) -> @ast::meta_item { + for (@ast::crate_directive cdir in c.node.directives) { + alt (cdir.node) { + case (ast::cdir_meta(?v, ?mis)) { + if (v == ast::export_meta) { + for (@ast::meta_item mi in mis) { + put mi; + } + } + } + case (_) {} + } + } +} +fn get_crate_meta(&session::session sess, + &ast::crate c, str k, str default, + bool warn_default) -> str { + let vec[@ast::meta_item] v = []; + for each (@ast::meta_item mi in crate_export_metas(c)) { + if (mi.node.name == k) { + v += [mi]; + } + } + alt (vec::len(v)) { + case (0u) { + if (warn_default) { + sess.warn(#fmt("missing meta '%s', using '%s' as default", + k, default)); + } + ret default; + } + case (1u) { + ret v.(0).node.value; + } + case (_) { + sess.span_err(v.(1).span, #fmt("duplicate meta '%s'", k)); + } + } +} + +// This calculates CMH as defined above +fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str { + fn lteq(&@ast::meta_item ma, + &@ast::meta_item mb) -> bool { + ret ma.node.name <= mb.node.name; + } + + fn len_and_str(&str s) -> str { + ret #fmt("%u_%s", str::byte_len(s), s); + } + + let vec[mutable @ast::meta_item] v = [mutable]; + for each (@ast::meta_item mi in crate_export_metas(crate)) { + if (mi.node.name != "name" && + mi.node.name != "vers") { + v += [mutable mi]; + } + } + sort::quick_sort(lteq, v); + sha.reset(); + for (@ast::meta_item m_ in v) { + auto m = m_; + sha.input_str(len_and_str(m.node.name)); + sha.input_str(len_and_str(m.node.value)); + } + ret truncated_sha1_result(sha); +} + +fn crate_meta_name(&session::session sess, &ast::crate crate, + &str output) -> str { + auto os = str::split(fs::basename(output), '.' as u8); + assert vec::len(os) >= 2u; + vec::pop(os); + ret get_crate_meta(sess, crate, "name", str::connect(os, "."), + sess.get_opts().shared); +} + +fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str { + ret get_crate_meta(sess, crate, "vers", "0.0", + sess.get_opts().shared); +} + +fn truncated_sha1_result(sha1 sha) -> str { + ret str::substr(sha.result_str(), 0u, 16u); +} + + + +// This calculates STH for a symbol, as defined above +fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t, + str crate_meta_name, + str crate_meta_extras_hash) -> str { + // NB: do *not* use abbrevs here as we want the symbol names + // to be independent of one another in the crate. + auto cx = @rec(ds=metadata::def_to_str, tcx=tcx, + abbrevs=metadata::ac_no_abbrevs); + sha.reset(); + sha.input_str(crate_meta_name); + sha.input_str("-"); + sha.input_str(crate_meta_name); + sha.input_str("-"); + sha.input_str(metadata::Encode::ty_str(cx, t)); + auto hash = truncated_sha1_result(sha); + // Prefix with _ so that it never blends into adjacent digits + ret "_" + hash; +} + +fn get_symbol_hash(&@crate_ctxt ccx, &ty::t t) -> str { + auto hash = ""; + alt (ccx.type_sha1s.find(t)) { + case (some(?h)) { hash = h; } + case (none) { + hash = symbol_hash(ccx.tcx, ccx.sha, t, + ccx.crate_meta_name, + ccx.crate_meta_extras_hash); + ccx.type_sha1s.insert(t, hash); + } + } + ret hash; +} + + +fn mangle(&vec[str] ss) -> str { + + // Follow C++ namespace-mangling style + + auto n = "_ZN"; // Begin name-sequence. + + for (str s in ss) { + n += #fmt("%u%s", str::byte_len(s), s); + } + + n += "E"; // End name-sequence. + ret n; +} + + +fn exported_name(&vec[str] path, &str hash, &str vers) -> str { + // FIXME: versioning isn't working yet + ret mangle(path + [hash]); // + "@" + vers; +} + +fn mangle_exported_name(&@crate_ctxt ccx, &vec[str] path, + &ty::t t) -> str { + auto hash = get_symbol_hash(ccx, t); + ret exported_name(path, hash, ccx.crate_meta_vers); +} + +fn mangle_internal_name_by_type_only(&@crate_ctxt ccx, &ty::t t, + &str name) -> str { + auto f = metadata::def_to_str; + auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs); + auto s = ty::ty_to_short_str(ccx.tcx, t); + + auto hash = get_symbol_hash(ccx, t); + ret mangle([name, s, hash]); +} + +fn mangle_internal_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, + &str flav) -> str { + ret mangle(path + [ccx.names.next(flav)]); +} + +fn mangle_internal_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str { + ret mangle(path); +} + +fn mangle_internal_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { + ret ccx.names.next(flav); +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 0d5223d870233..a33416c8638b4 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -109,6 +109,9 @@ fn compile_input(session::session sess, bind middle::tstate::ck::check_crate(ty_cx, crate)); } + time(time_passes, "alias checking", + bind middle::alias::check_crate(@ty_cx, def_map, crate)); + auto llmod = time[llvm::llvm::ModuleRef](time_passes, "translation", bind trans::trans_crate(sess, crate, @@ -122,7 +125,7 @@ fn pretty_print_input(session::session sess, eval::env env, str input, pp_mode ppm) { auto def = tup(ast::local_crate, 0); auto p = front::parser::new_parser(sess, env, def, input, 0u, 0u); - auto crate = front::parser::parse_crate_from_source_file(p); + auto crate = parse_input(sess, p, input); auto mode; alt (ppm) { diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 9f025849402e6..e0080ca265156 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -6,6 +6,9 @@ import std::uint; import std::term; import std::io; import std::map; +import std::option; +import std::option::some; +import std::option::none; tag os { os_win32; @@ -48,9 +51,16 @@ fn span_to_str(span sp, codemap::codemap cm) -> str { lo.col, hi.line, hi.col)); } -fn emit_diagnostic(span sp, str msg, str kind, u8 color, +fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, codemap::codemap cm) { - io::stdout().write_str(span_to_str(sp, cm) + ": "); + auto ss = ":0:0:0:0"; + alt (sp) { + case (some(?ssp)) { + ss = span_to_str(ssp, cm); + } + case (none) {} + } + io::stdout().write_str(ss + ": "); if (term::color_supported()) { term::fg(io::stdout().get_buf_writer(), color); @@ -85,12 +95,12 @@ state obj session(ast::crate_num cnum, fn span_err(span sp, str msg) -> ! { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "error", 9u8, cm); + emit_diagnostic(some(sp), msg, "error", 9u8, cm); fail; } fn err(str msg) -> ! { - log_err #fmt("error: %s", msg); + emit_diagnostic(none[span], msg, "error", 9u8, cm); fail; } @@ -103,29 +113,32 @@ state obj session(ast::crate_num cnum, fn span_warn(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "warning", 11u8, cm); + emit_diagnostic(some(sp), msg, "warning", 11u8, cm); + } + + fn warn(str msg) { + emit_diagnostic(none[span], msg, "warning", 11u8, cm); } fn span_note(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "note", 10u8, cm); + emit_diagnostic(some(sp), msg, "note", 10u8, cm); + } + + fn span_bug(span sp, str msg) -> ! { + self.span_err(sp, #fmt("internal compiler error %s", msg)); } fn bug(str msg) -> ! { - log_err #fmt("error: internal compiler error %s", msg); - fail; + self.err(#fmt("internal compiler error %s", msg)); } fn span_unimpl(span sp, str msg) -> ! { - // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, "internal compiler error: unimplemented " + msg, - "error", 9u8, cm); - fail; + self.span_bug(sp, "unimplemented " + msg); } - + fn unimpl(str msg) -> ! { - log_err #fmt("error: unimplemented %s", msg); - fail; + self.bug("unimplemented " + msg); } fn get_external_crate(int num) -> crate_metadata { diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index da94195ab931f..fce15a556c6fd 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -11,6 +11,10 @@ type ident = str; type path_ = rec(vec[ident] idents, vec[@ty] types); type path = spanned[path_]; +fn path_name(&path p) -> str { + ret str::connect(p.node.idents, "::"); +} + type crate_num = int; const crate_num local_crate = 0; type def_num = int; @@ -71,6 +75,11 @@ type crate = spanned[crate_]; type crate_ = rec(vec[@crate_directive] directives, _mod module); +tag meta_visibility { + export_meta; + local_meta; +} + tag crate_directive_ { cdir_expr(@expr); // FIXME: cdir_let should be eliminated @@ -80,7 +89,7 @@ tag crate_directive_ { cdir_src_mod(ident, option::t[filename]); cdir_dir_mod(ident, option::t[filename], vec[@crate_directive]); cdir_view_item(@view_item); - cdir_meta(vec[@meta_item]); + cdir_meta(meta_visibility, vec[@meta_item]); cdir_syntax(path); cdir_auth(path, _auth); } @@ -267,7 +276,7 @@ tag expr_ { expr_index(@expr, @expr, ann); expr_path(path, ann); expr_ext(path, vec[@expr], option::t[str], @expr, ann); - expr_fail(ann); + expr_fail(ann, option::t[str]); expr_break(ann); expr_cont(ann); expr_ret(option::t[@expr], ann); @@ -300,11 +309,15 @@ tag lit_ { // type structure in middle/ty.rs as well. type mt = rec(@ty ty, mutability mut); -type ty_field = rec(ident ident, mt mt); -type ty_arg = rec(mode mode, @ty ty); -type ty_method = rec(proto proto, ident ident, +type ty_field_ = rec(ident ident, mt mt); +type ty_arg_ = rec(mode mode, @ty ty); +type ty_method_ = rec(proto proto, ident ident, vec[ty_arg] inputs, @ty output, controlflow cf); +type ty_field = spanned[ty_field_]; +type ty_arg = spanned[ty_arg_]; +type ty_method = spanned[ty_method_]; + type ty = spanned[ty_]; tag ty_ { ty_nil; @@ -323,6 +336,7 @@ tag ty_ { ty_str; ty_box(mt); ty_vec(mt); + ty_ptr(mt); ty_task; ty_port(@ty); ty_chan(@ty); diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs index 9ad6b51632a07..cae53bc74bf88 100644 --- a/src/comp/front/creader.rs +++ b/src/comp/front/creader.rs @@ -105,6 +105,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t { } case ('p') { ret ty::mk_param(st.tcx, parse_int(st) as uint); } case ('@') { ret ty::mk_box(st.tcx, parse_mt(st, sd)); } + case ('*') { ret ty::mk_ptr(st.tcx, parse_mt(st, sd)); } case ('V') { ret ty::mk_vec(st.tcx, parse_mt(st, sd)); } case ('a') { ret ty::mk_task(st.tcx); } case ('P') { ret ty::mk_port(st.tcx, parse_ty(st, sd)); } diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs index d5a76372846d6..a8e881ee036c3 100644 --- a/src/comp/front/eval.rs +++ b/src/comp/front/eval.rs @@ -418,8 +418,13 @@ fn eval_crate_directive(ctx cx, vec::push[@ast::view_item](view_items, vi); } - case (ast::cdir_meta(?mi)) { - cx.sess.add_metadata(mi); + case (ast::cdir_meta(?vi, ?mi)) { + // FIXME: we should actually record, for documentation-sake, + // the metadata that's not exported. It would be nice to have + // compiled-in to the target crate, not just in theh AST. + if (vi == ast::export_meta) { + cx.sess.add_metadata(mi); + } } case (ast::cdir_syntax(?pth)) {} diff --git a/src/comp/front/ext.rs b/src/comp/front/ext.rs new file mode 100644 index 0000000000000..d08fc3ef7d5ec --- /dev/null +++ b/src/comp/front/ext.rs @@ -0,0 +1,66 @@ +import std::option; +import std::map::hashmap; + +import driver::session::session; +import front::parser::parser; +import util::common::span; +import util::common::new_str_hash; + +type syntax_expander = fn(&ext_ctxt, span, + &vec[@ast::expr], + option::t[str]) -> @ast::expr; + +// Temporary: to introduce a tag in order to make a recursive type work +tag syntax_extension { + x(syntax_expander); +} + +// A temporary hard-coded map of methods for expanding syntax extension +// AST nodes into full ASTs +fn syntax_expander_table() -> hashmap[str, syntax_extension] { + auto syntax_expanders = new_str_hash[syntax_extension](); + syntax_expanders.insert("fmt", x(extfmt::expand_syntax_ext)); + syntax_expanders.insert("env", x(extenv::expand_syntax_ext)); + ret syntax_expanders; +} + +type span_msg_fn = fn (span sp, str msg) -> !; +type next_ann_fn = fn () -> ast::ann; + +// Provides a limited set of services necessary for syntax extensions +// to do their thing +type ext_ctxt = rec(span_msg_fn span_err, + span_msg_fn span_unimpl, + next_ann_fn next_ann); + +fn mk_ctxt(parser parser) -> ext_ctxt { + auto sess = parser.get_session(); + + fn ext_span_err_(session sess, span sp, str msg) -> ! { + sess.span_err(sp, msg); + } + auto ext_span_err = bind ext_span_err_(sess, _, _); + + fn ext_span_unimpl_(session sess, span sp, str msg) -> ! { + sess.span_unimpl(sp, msg); + } + auto ext_span_unimpl = bind ext_span_unimpl_(sess, _, _); + + fn ext_next_ann_(parser parser) -> ast::ann { parser.get_ann() } + auto ext_next_ann = bind ext_next_ann_(parser); + + ret rec(span_err = ext_span_err, + span_unimpl = ext_span_unimpl, + next_ann = ext_next_ann); +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs index 858f9f9f5689a..62e39c8488b40 100644 --- a/src/comp/front/extenv.rs +++ b/src/comp/front/extenv.rs @@ -11,35 +11,36 @@ import std::vec; import std::option; import std::generic_os; +import ext::*; + export expand_syntax_ext; -// FIXME: Need to thread parser through here to handle errors correctly -fn expand_syntax_ext(parser::parser p, +fn expand_syntax_ext(&ext_ctxt cx, common::span sp, - vec[@ast::expr] args, + &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { if (vec::len[@ast::expr](args) != 1u) { - p.err("malformed #env call"); + cx.span_err(sp, "malformed #env call"); } // FIXME: if this was more thorough it would manufacture an // option::t[str] rather than just an maybe-empty string. - auto var = expr_to_str(p, args.(0)); + auto var = expr_to_str(cx, args.(0)); alt (generic_os::getenv(var)) { case (option::none) { - ret make_new_str(p, sp, ""); + ret make_new_str(cx, sp, ""); } case (option::some(?s)) { - ret make_new_str(p, sp, s); + ret make_new_str(cx, sp, s); } } } // FIXME: duplicate code copied from extfmt: -fn expr_to_str(parser::parser p, +fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { alt (expr.node) { case (ast::expr_lit(?l, _)) { @@ -47,23 +48,27 @@ fn expr_to_str(parser::parser p, case (ast::lit_str(?s)) { ret s; } + case (_) { + cx.span_err(l.span, "malformed #env call"); + } } } + case (_) { + cx.span_err(expr.span, "malformed #env call"); + } } - p.err("malformed #env call"); - fail; } -fn make_new_lit(parser::parser p, common::span sp, ast::lit_ lit) +fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit) -> @ast::expr { auto sp_lit = @rec(node=lit, span=sp); - auto expr = ast::expr_lit(sp_lit, p.get_ann()); + auto expr = ast::expr_lit(sp_lit, cx.next_ann()); ret @rec(node=expr, span=sp); } -fn make_new_str(parser::parser p, common::span sp, str s) -> @ast::expr { +fn make_new_str(&ext_ctxt cx, common::span sp, str s) -> @ast::expr { auto lit = ast::lit_str(s); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } // diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index f6ad1d04a39de..c3d4fffcbab86 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -4,7 +4,6 @@ * compiler syntax extension plugin interface. */ -import front::parser::parser; import util::common; import std::str; @@ -13,136 +12,117 @@ import std::option; import std::option::none; import std::option::some; -import std::extfmt::ct::signedness; -import std::extfmt::ct::signed; -import std::extfmt::ct::unsigned; -import std::extfmt::ct::caseness; -import std::extfmt::ct::case_upper; -import std::extfmt::ct::case_lower; -import std::extfmt::ct::ty; -import std::extfmt::ct::ty_bool; -import std::extfmt::ct::ty_str; -import std::extfmt::ct::ty_char; -import std::extfmt::ct::ty_int; -import std::extfmt::ct::ty_bits; -import std::extfmt::ct::ty_hex; -import std::extfmt::ct::ty_octal; -import std::extfmt::ct::flag; -import std::extfmt::ct::flag_left_justify; -import std::extfmt::ct::flag_left_zero_pad; -import std::extfmt::ct::flag_space_for_sign; -import std::extfmt::ct::flag_sign_always; -import std::extfmt::ct::flag_alternate; -import std::extfmt::ct::count; -import std::extfmt::ct::count_is; -import std::extfmt::ct::count_is_param; -import std::extfmt::ct::count_is_next_param; -import std::extfmt::ct::count_implied; -import std::extfmt::ct::conv; -import std::extfmt::ct::piece; -import std::extfmt::ct::piece_string; -import std::extfmt::ct::piece_conv; -import std::extfmt::ct::parse_fmt_string; +import std::extfmt::ct::*; + +import ext::*; export expand_syntax_ext; -fn expand_syntax_ext(parser p, - vec[@ast::expr] args, +fn expand_syntax_ext(&ext_ctxt cx, + common::span sp, + &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { if (vec::len[@ast::expr](args) == 0u) { - // FIXME: Handle error correctly. - log_err "malformed #fmt call"; - fail; + cx.span_err(sp, "#fmt requires a format string"); } - auto fmt = expr_to_str(args.(0)); + auto fmt = expr_to_str(cx, args.(0)); + auto fmtspan = args.(0).span; + + log "Format string:"; + log fmt; - // log "Format string:"; - // log fmt; + fn parse_fmt_err_(&ext_ctxt cx, common::span sp, str msg) -> ! { + cx.span_err(sp, msg); + } - auto pieces = parse_fmt_string(fmt); + auto parse_fmt_err = bind parse_fmt_err_(cx, fmtspan, _); + auto pieces = parse_fmt_string(fmt, parse_fmt_err); auto args_len = vec::len[@ast::expr](args); auto fmt_args = vec::slice[@ast::expr](args, 1u, args_len - 1u); - ret pieces_to_expr(p, pieces, args); + ret pieces_to_expr(cx, sp, pieces, args); } -fn expr_to_str(@ast::expr expr) -> str { +fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { + auto err_msg = "first argument to #fmt must be a string literal"; alt (expr.node) { case (ast::expr_lit(?l, _)) { alt (l.node) { case (ast::lit_str(?s)) { ret s; } - case (_) { /* fallthrough */ } + case (_) { + cx.span_err(l.span, err_msg); + } } } - case (_) { /* fallthrough */ } + case (_) { + cx.span_err(expr.span, err_msg); + } } - log_err "first argument to #fmt must be a string literal"; - fail; } // FIXME: A lot of these functions for producing expressions can probably // be factored out in common with other code that builds expressions. -// FIXME: Probably should be using the parser's span functions // FIXME: Cleanup the naming of these functions -fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) - -> @ast::expr { +fn pieces_to_expr(&ext_ctxt cx, common::span sp, + vec[piece] pieces, vec[@ast::expr] args) -> @ast::expr { - fn make_new_lit(parser p, common::span sp, ast::lit_ lit) -> @ast::expr { + fn make_new_lit(&ext_ctxt cx, + common::span sp, ast::lit_ lit) -> @ast::expr { auto sp_lit = @rec(node=lit, span=sp); - auto expr = ast::expr_lit(sp_lit, p.get_ann()); + auto expr = ast::expr_lit(sp_lit, cx.next_ann()); ret @rec(node=expr, span=sp); } - fn make_new_str(parser p, common::span sp, str s) -> @ast::expr { + fn make_new_str(&ext_ctxt cx, common::span sp, str s) -> @ast::expr { auto lit = ast::lit_str(s); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } - fn make_new_int(parser p, common::span sp, int i) -> @ast::expr { + fn make_new_int(&ext_ctxt cx, common::span sp, int i) -> @ast::expr { auto lit = ast::lit_int(i); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } - fn make_new_uint(parser p, common::span sp, uint u) -> @ast::expr { + fn make_new_uint(&ext_ctxt cx, common::span sp, uint u) -> @ast::expr { auto lit = ast::lit_uint(u); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } - fn make_add_expr(parser p, common::span sp, + fn make_add_expr(&ext_ctxt cx, common::span sp, @ast::expr lhs, @ast::expr rhs) -> @ast::expr { - auto binexpr = ast::expr_binary(ast::add, lhs, rhs, p.get_ann()); + auto binexpr = ast::expr_binary(ast::add, lhs, rhs, cx.next_ann()); ret @rec(node=binexpr, span=sp); } - fn make_path_expr(parser p, common::span sp, vec[ast::ident] idents) + fn make_path_expr(&ext_ctxt cx, common::span sp, vec[ast::ident] idents) -> @ast::expr { let vec[@ast::ty] types = []; auto path = rec(idents=idents, types=types); auto sp_path = rec(node=path, span=sp); - auto pathexpr = ast::expr_path(sp_path, p.get_ann()); + auto pathexpr = ast::expr_path(sp_path, cx.next_ann()); auto sp_pathexpr = @rec(node=pathexpr, span=sp); ret sp_pathexpr; } - fn make_vec_expr(parser p, common::span sp, vec[@ast::expr] exprs) + fn make_vec_expr(&ext_ctxt cx, common::span sp, vec[@ast::expr] exprs) -> @ast::expr { - auto vecexpr = ast::expr_vec(exprs, ast::imm, p.get_ann()); + auto vecexpr = ast::expr_vec(exprs, ast::imm, cx.next_ann()); auto sp_vecexpr = @rec(node=vecexpr, span=sp); ret sp_vecexpr; } - fn make_call(parser p, common::span sp, vec[ast::ident] fn_path, + fn make_call(&ext_ctxt cx, common::span sp, vec[ast::ident] fn_path, vec[@ast::expr] args) -> @ast::expr { - auto pathexpr = make_path_expr(p, sp, fn_path); - auto callexpr = ast::expr_call(pathexpr, args, p.get_ann()); + auto pathexpr = make_path_expr(cx, sp, fn_path); + auto callexpr = ast::expr_call(pathexpr, args, cx.next_ann()); auto sp_callexpr = @rec(node=callexpr, span=sp); ret sp_callexpr; } - fn make_rec_expr(parser p, common::span sp, + fn make_rec_expr(&ext_ctxt cx, common::span sp, vec[tup(ast::ident, @ast::expr)] fields) -> @ast::expr { let vec[ast::field] astfields = []; for (tup(ast::ident, @ast::expr) field in fields) { @@ -156,7 +136,7 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) auto recexpr = ast::expr_rec(astfields, option::none[@ast::expr], - p.get_ann()); + cx.next_ann()); auto sp_recexpr = @rec(node=recexpr, span=sp); ret sp_recexpr; } @@ -167,16 +147,18 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) ret ["std", "extfmt", "rt", ident]; } - fn make_rt_path_expr(parser p, common::span sp, str ident) -> @ast::expr { + fn make_rt_path_expr(&ext_ctxt cx, + common::span sp, str ident) -> @ast::expr { auto path = make_path_vec(ident); - ret make_path_expr(p, sp, path); + ret make_path_expr(cx, sp, path); } // Produces an AST expression that represents a RT::conv record, // which tells the RT::conv* functions how to perform the conversion - fn make_rt_conv_expr(parser p, common::span sp, &conv cnv) -> @ast::expr { + fn make_rt_conv_expr(&ext_ctxt cx, + common::span sp, &conv cnv) -> @ast::expr { - fn make_flags(parser p, common::span sp, vec[flag] flags) + fn make_flags(&ext_ctxt cx, common::span sp, vec[flag] flags) -> @ast::expr { let vec[@ast::expr] flagexprs = []; for (flag f in flags) { @@ -198,38 +180,38 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) fstr = "flag_alternate"; } } - flagexprs += [make_rt_path_expr(p, sp, fstr)]; + flagexprs += [make_rt_path_expr(cx, sp, fstr)]; } // FIXME: 0-length vectors can't have their type inferred // through the rec that these flags are a member of, so // this is a hack placeholder flag if (vec::len[@ast::expr](flagexprs) == 0u) { - flagexprs += [make_rt_path_expr(p, sp, "flag_none")]; + flagexprs += [make_rt_path_expr(cx, sp, "flag_none")]; } - ret make_vec_expr(p, sp, flagexprs); + ret make_vec_expr(cx, sp, flagexprs); } - fn make_count(parser p, common::span sp, &count cnt) -> @ast::expr { + fn make_count(&ext_ctxt cx, + common::span sp, &count cnt) -> @ast::expr { alt (cnt) { case (count_implied) { - ret make_rt_path_expr(p, sp, "count_implied"); + ret make_rt_path_expr(cx, sp, "count_implied"); } case (count_is(?c)) { - auto count_lit = make_new_int(p, sp, c); + auto count_lit = make_new_int(cx, sp, c); auto count_is_path = make_path_vec("count_is"); auto count_is_args = [count_lit]; - ret make_call(p, sp, count_is_path, count_is_args); + ret make_call(cx, sp, count_is_path, count_is_args); } case (_) { - log_err "not implemented"; - fail; + cx.span_unimpl(sp, "unimplemented #fmt conversion"); } } } - fn make_ty(parser p, common::span sp, &ty t) -> @ast::expr { + fn make_ty(&ext_ctxt cx, common::span sp, &ty t) -> @ast::expr { auto rt_type; alt (t) { case (ty_hex(?c)) { @@ -253,26 +235,26 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) } } - ret make_rt_path_expr(p, sp, rt_type); + ret make_rt_path_expr(cx, sp, rt_type); } - fn make_conv_rec(parser p, + fn make_conv_rec(&ext_ctxt cx, common::span sp, @ast::expr flags_expr, @ast::expr width_expr, @ast::expr precision_expr, @ast::expr ty_expr) -> @ast::expr { - ret make_rec_expr(p, sp, [tup("flags", flags_expr), + ret make_rec_expr(cx, sp, [tup("flags", flags_expr), tup("width", width_expr), tup("precision", precision_expr), tup("ty", ty_expr)]); } - auto rt_conv_flags = make_flags(p, sp, cnv.flags); - auto rt_conv_width = make_count(p, sp, cnv.width); - auto rt_conv_precision = make_count(p, sp, cnv.precision); - auto rt_conv_ty = make_ty(p, sp, cnv.ty); - ret make_conv_rec(p, + auto rt_conv_flags = make_flags(cx, sp, cnv.flags); + auto rt_conv_width = make_count(cx, sp, cnv.width); + auto rt_conv_precision = make_count(cx, sp, cnv.precision); + auto rt_conv_ty = make_ty(cx, sp, cnv.ty); + ret make_conv_rec(cx, sp, rt_conv_flags, rt_conv_width, @@ -280,16 +262,17 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) rt_conv_ty); } - fn make_conv_call(parser p, common::span sp, str conv_type, + fn make_conv_call(&ext_ctxt cx, common::span sp, str conv_type, &conv cnv, @ast::expr arg) -> @ast::expr { auto fname = "conv_" + conv_type; auto path = make_path_vec(fname); - auto cnv_expr = make_rt_conv_expr(p, sp, cnv); + auto cnv_expr = make_rt_conv_expr(cx, sp, cnv); auto args = [cnv_expr, arg]; - ret make_call(p, arg.span, path, args); + ret make_call(cx, arg.span, path, args); } - fn make_new_conv(parser p, conv cnv, @ast::expr arg) -> @ast::expr { + fn make_new_conv(&ext_ctxt cx, common::span sp, + conv cnv, @ast::expr arg) -> @ast::expr { // FIXME: Extract all this validation into extfmt::ct fn is_signed_type(conv cnv) -> bool { @@ -316,8 +299,7 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) case (option::none) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } @@ -327,22 +309,20 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) } case (flag_sign_always) { if (!is_signed_type(cnv)) { - log_err "+ flag only valid in signed #fmt conversion"; - fail; + cx.span_err(sp, "+ flag only valid in " + + "signed #fmt conversion"); } } case (flag_space_for_sign) { if (!is_signed_type(cnv)) { - log_err "space flag only valid in " - + "signed #fmt conversions"; - fail; + cx.span_err(sp, "space flag only valid in " + + "signed #fmt conversions"); } } case (flag_left_zero_pad) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } } @@ -353,8 +333,7 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) case (count_is(_)) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } @@ -364,43 +343,41 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) case (count_is(_)) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } alt (cnv.ty) { case (ty_str) { - ret make_conv_call(p, arg.span, "str", cnv, arg); + ret make_conv_call(cx, arg.span, "str", cnv, arg); } case (ty_int(?sign)) { alt (sign) { case (signed) { - ret make_conv_call(p, arg.span, "int", cnv, arg); + ret make_conv_call(cx, arg.span, "int", cnv, arg); } case (unsigned) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } } } case (ty_bool) { - ret make_conv_call(p, arg.span, "bool", cnv, arg); + ret make_conv_call(cx, arg.span, "bool", cnv, arg); } case (ty_char) { - ret make_conv_call(p, arg.span, "char", cnv, arg); + ret make_conv_call(cx, arg.span, "char", cnv, arg); } case (ty_hex(_)) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } case (ty_bits) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } case (ty_octal) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } } @@ -494,48 +471,48 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) } } } + case (ty_octal) { + log "type: octal"; + } } } - auto sp = args.(0).span; + auto fmt_sp = args.(0).span; auto n = 0u; - auto tmp_expr = make_new_str(p, sp, ""); + auto tmp_expr = make_new_str(cx, sp, ""); auto nargs = vec::len[@ast::expr](args); for (piece pc in pieces) { alt (pc) { case (piece_string(?s)) { - auto s_expr = make_new_str(p, sp, s); - tmp_expr = make_add_expr(p, sp, tmp_expr, s_expr); + auto s_expr = make_new_str(cx, fmt_sp, s); + tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, s_expr); } case (piece_conv(?conv)) { + n += 1u; + if (n >= nargs) { - log_err "too many conversions in #fmt string"; - fail; + cx.span_err(sp, "not enough arguments to #fmt " + + "for the given format string"); } - // TODO: Remove debug logging - //log "Building conversion:"; - //log_conv(conv); + log "Building conversion:"; + log_conv(conv); - n += 1u; auto arg_expr = args.(n); - auto c_expr = make_new_conv(p, conv, arg_expr); - tmp_expr = make_add_expr(p, sp, tmp_expr, c_expr); + auto c_expr = make_new_conv(cx, fmt_sp, conv, arg_expr); + tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, c_expr); } } } auto expected_nargs = n + 1u; // n conversions + the fmt string if (expected_nargs < nargs) { - log_err #fmt("too many arguments to #fmt. found %u, expected %u", - nargs, expected_nargs); - fail; + cx.span_err(sp, + #fmt("too many arguments to #fmt. found %u, expected %u", + nargs, expected_nargs)); } - // TODO: Remove this debug logging - // log "dumping expanded ast:"; - // log pretty::print_expr(tmp_expr); ret tmp_expr; } diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs index b6f5ab9e9c3a6..08409bea14c32 100644 --- a/src/comp/front/lexer.rs +++ b/src/comp/front/lexer.rs @@ -632,6 +632,9 @@ fn next_token(&reader rdr) -> token::token { case ('"') { str::push_byte(accum_str, '"' as u8); } + case ('\n') { + consume_whitespace(rdr); + } case ('x') { str::push_char(accum_str, diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 688bfb01e1920..562bc0cc32e37 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -29,28 +29,29 @@ type ty_or_bang = util::common::ty_or_bang[@ast::ty]; state type parser = state obj { - fn peek() -> token::token; - fn bump(); - fn err(str s) -> !; - fn restrict(restriction r); - fn get_restriction() -> restriction; - fn get_file_type() -> file_type; - fn get_env() -> eval::env; - fn get_session() -> session::session; - fn get_span() -> common::span; - fn get_lo_pos() -> uint; - fn get_hi_pos() -> uint; - fn get_last_lo_pos() -> uint; - fn next_def_id() -> ast::def_id; - fn set_def(ast::def_num); - fn get_prec_table() -> vec[op_spec]; - fn get_str(token::str_num) -> str; - fn get_reader() -> lexer::reader; - fn get_filemap() -> codemap::filemap; - fn get_bad_expr_words() -> std::map::hashmap[str, ()]; - fn get_chpos() -> uint; - fn get_ann() -> ast::ann; - fn next_ann_num() -> uint; + fn peek() -> token::token; + fn bump(); + fn err(str s) -> !; + fn restrict(restriction r); + fn get_restriction() -> restriction; + fn get_file_type() -> file_type; + fn get_env() -> eval::env; + fn get_session() -> session::session; + fn get_span() -> common::span; + fn get_lo_pos() -> uint; + fn get_hi_pos() -> uint; + fn get_last_lo_pos() -> uint; + fn next_def_id() -> ast::def_id; + fn set_def(ast::def_num); + fn get_prec_table() -> vec[op_spec]; + fn get_str(token::str_num) -> str; + fn get_reader() -> lexer::reader; + fn get_filemap() -> codemap::filemap; + fn get_bad_expr_words() -> hashmap[str, ()]; + fn get_syntax_expanders() -> hashmap[str, ext::syntax_extension]; + fn get_chpos() -> uint; + fn get_ann() -> ast::ann; + fn next_ann_num() -> uint; }; fn new_parser(session::session sess, @@ -70,7 +71,9 @@ fn new_parser(session::session sess, lexer::reader rdr, vec[op_spec] precs, mutable uint next_ann_var, - std::map::hashmap[str, ()] bad_words) + hashmap[str, ()] bad_words, + hashmap[str, ext::syntax_extension] + syntax_expanders) { fn peek() -> token::token { ret tok; @@ -139,10 +142,14 @@ fn new_parser(session::session sess, ret rdr.get_filemap(); } - fn get_bad_expr_words() -> std::map::hashmap[str, ()] { + fn get_bad_expr_words() -> hashmap[str, ()] { ret bad_words; } + fn get_syntax_expanders() -> hashmap[str, ext::syntax_extension] { + ret syntax_expanders; + } + fn get_chpos() -> uint {ret rdr.get_chpos();} fn get_ann() -> ast::ann { @@ -169,13 +176,13 @@ fn new_parser(session::session sess, ret stdio_parser(sess, env, ftype, lexer::next_token(rdr), npos, npos, npos, initial_def._1, UNRESTRICTED, initial_def._0, rdr, prec_table(), next_ann, - bad_expr_word_table()); + 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. -fn bad_expr_word_table() -> std::map::hashmap[str, ()] { +fn bad_expr_word_table() -> hashmap[str, ()] { auto words = new_str_hash[()](); words.insert("mod", ()); words.insert("if", ()); @@ -249,7 +256,6 @@ fn parse_value_ident(&parser p) -> ast::ident { ret parse_ident(p); } - /* FIXME: gross hack copied from rustboot to make certain configuration-based * decisions work at build-time. We should probably change it to use a * lexical sytnax-extension or something similar. For now we just imitate @@ -287,7 +293,6 @@ fn eat_word(&parser p, &str word) -> bool { p.bump(); ret true; } else { ret false; } - } case (_) { ret false; } } @@ -312,7 +317,8 @@ fn check_bad_word(&parser p) { fn parse_ty_fn(ast::proto proto, &parser p, uint lo) -> ast::ty_ { - fn parse_fn_input_ty(&parser p) -> rec(ast::mode mode, @ast::ty ty) { + fn parse_fn_input_ty(&parser p) -> ast::ty_arg { + auto lo = p.get_lo_pos(); auto mode; if (p.peek() == token::BINOP(token::AND)) { p.bump(); @@ -332,14 +338,12 @@ fn parse_ty_fn(ast::proto proto, &parser p, uint lo) case (_) { /* no param name present */ } } - ret rec(mode=mode, ty=t); + ret spanned(lo, t.span.hi, rec(mode=mode, ty=t)); } auto lo = p.get_lo_pos(); - - auto f = parse_fn_input_ty; // FIXME: trans_const_lval bug - auto inputs = parse_seq[rec(ast::mode mode, @ast::ty ty)](token::LPAREN, - token::RPAREN, some(token::COMMA), f, p); + auto inputs = parse_seq(token::LPAREN, token::RPAREN, + some(token::COMMA), parse_fn_input_ty, p); // FIXME: dropping constrs on the floor at the moment. // pick them up when they're used by typestate pass. @@ -383,8 +387,9 @@ fn parse_ty_obj(&parser p, &mutable uint hi) -> ast::ty_ { expect(p, token::SEMI); alt (f) { case (ast::ty_fn(?proto, ?inputs, ?output, ?cf)) { - ret rec(proto=proto, ident=ident, - inputs=inputs, output=output, cf=cf); + ret spanned(flo, output.span.hi, + rec(proto=proto, ident=ident, + inputs=inputs, output=output, cf=cf)); } } fail; @@ -405,9 +410,10 @@ fn parse_mt(&parser p) -> ast::mt { } fn parse_ty_field(&parser p) -> ast::ty_field { + auto lo = p.get_lo_pos(); auto mt = parse_mt(p); auto id = parse_ident(p); - ret rec(ident=id, mt=mt); + ret spanned(lo, mt.ty.span.hi, rec(ident=id, mt=mt)); } fn parse_constr_arg(&parser p) -> @ast::constr_arg { @@ -511,6 +517,11 @@ fn parse_ty(&parser p) -> @ast::ty { auto mt = parse_mt(p); hi = mt.ty.span.hi; t = ast::ty_box(mt); + } else if (p.peek() == token::BINOP(token::STAR)) { + p.bump(); + auto mt = parse_mt(p); + hi = mt.ty.span.hi; + t = ast::ty_ptr(mt); } else if (eat_word(p, "vec")) { expect(p, token::LBRACKET); t = ast::ty_vec(parse_mt(p)); @@ -596,7 +607,6 @@ fn parse_arg(&parser p) -> ast::arg { fn parse_seq_to_end[T](token::token ket, option::t[token::token] sep, (fn(&parser) -> T) f, - uint hi, &parser p) -> vec[T] { let bool first = true; let vec[T] v = []; @@ -616,7 +626,6 @@ fn parse_seq_to_end[T](token::token ket, let T t = f(p); v += [t]; } - hi = p.get_hi_pos(); expect(p, ket); ret v; } @@ -627,9 +636,9 @@ fn parse_seq[T](token::token bra, (fn(&parser) -> T) f, &parser p) -> util::common::spanned[vec[T]] { auto lo = p.get_lo_pos(); - auto hi = p.get_hi_pos(); expect(p, bra); - auto result = parse_seq_to_end[T](ket, sep, f, hi, p); + auto result = parse_seq_to_end[T](ket, sep, f, p); + auto hi = p.get_hi_pos(); ret spanned(lo, hi, result); } @@ -811,7 +820,7 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { auto es = parse_seq_to_end[@ast::expr](token::RBRACKET, some(token::COMMA), - pf, hi, p); + pf, p); ex = ast::expr_vec(es, mut, p.get_ann()); } else if (eat_word(p, "obj")) { // Anonymous object @@ -824,7 +833,6 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { none[vec[ast::obj_field]]; if (p.peek() == token::LPAREN) { auto pf = parse_obj_field; - hi = p.get_hi_pos(); expect(p, token::LPAREN); @@ -832,7 +840,7 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { (parse_seq_to_end[ast::obj_field] (token::RPAREN, some(token::COMMA), - pf, hi, p)); + pf, p)); } let vec[@ast::method] meths = []; @@ -921,10 +929,21 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { some(token::COMMA), pf, p); hi = es.span.hi; - ex = expand_syntax_ext(p, es.span, pth, es.node, + auto ext_span = rec(lo=lo, hi=hi); + ex = expand_syntax_ext(p, ext_span, pth, es.node, none[str]); } else if (eat_word(p, "fail")) { - ex = ast::expr_fail(p.get_ann()); + auto msg; + alt (p.peek()) { + case (token::LIT_STR(?s)) { + msg = some[str](p.get_str(s)); + p.bump(); + } + case (_) { + msg = none[str]; + } + } + ex = ast::expr_fail(p.get_ann(), msg); } else if (eat_word(p, "log")) { auto e = parse_expr(p); auto hi = e.span.hi; @@ -1032,23 +1051,17 @@ fn expand_syntax_ext(&parser p, common::span sp, assert (vec::len[ast::ident](path.node.idents) > 0u); auto extname = path.node.idents.(0); - if (str::eq(extname, "fmt")) { - auto expanded = extfmt::expand_syntax_ext(p, args, body); - auto newexpr = ast::expr_ext(path, args, body, - expanded, - p.get_ann()); - - ret newexpr; - } else if (str::eq(extname, "env")) { - auto expanded = extenv::expand_syntax_ext(p, sp, args, body); - auto newexpr = ast::expr_ext(path, args, body, - expanded, - p.get_ann()); - - ret newexpr; - } else { - p.err("unknown syntax extension"); - fail; + + alt (p.get_syntax_expanders().find(extname)) { + case (none) { + p.err("unknown syntax expander: '" + extname + "'"); + } + case (some(ext::x(?ext))) { + auto ext_cx = ext::mk_ctxt(p); + ret ast::expr_ext(path, args, body, + ext(ext_cx, sp, args, body), + p.get_ann()); + } } } @@ -1639,7 +1652,7 @@ fn stmt_ends_with_semi(&ast::stmt stmt) -> bool { case (ast::expr_field(_,_,_)) { ret true; } case (ast::expr_index(_,_,_)) { ret true; } case (ast::expr_path(_,_)) { ret true; } - case (ast::expr_fail(_)) { ret true; } + case (ast::expr_fail(_,_)) { ret true; } case (ast::expr_break(_)) { ret true; } case (ast::expr_cont(_)) { ret true; } case (ast::expr_ret(_,_)) { ret true; } @@ -2358,10 +2371,14 @@ fn parse_crate_directive(&parser p) -> ast::crate_directive expect(p, token::SEMI); ret spanned(lo, hi, ast::cdir_auth(n, a)); } else if (eat_word(p, "meta")) { + auto mv = ast::local_meta; + if (eat_word(p, "export")) { + mv = ast::export_meta; + } auto mis = parse_meta(p); auto hi = p.get_hi_pos(); expect(p, token::SEMI); - ret spanned(lo, hi, ast::cdir_meta(mis)); + ret spanned(lo, hi, ast::cdir_meta(mv, mis)); } else if (eat_word(p, "mod")) { auto id = parse_ident(p); auto file_opt = none[filename]; diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 0de35b9f006a4..505e07e3f3fa0 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -88,6 +88,7 @@ const uint LLVMNoImplicitFloatAttribute = 8388608u; const uint LLVMNakedAttribute = 16777216u; const uint LLVMInlineHintAttribute = 33554432u; const uint LLVMStackAttribute = 469762048u; // 7 << 26 +const uint LLVMUWTableAttribute = 1073741824u; // 1 << 30 // Consts for the LLVM IntPredicate type, pre-cast to uint. @@ -813,7 +814,6 @@ native mod llvm = llvm_lib { Bool UnitAtATime, Bool UnrollLoops, Bool SimplifyLibCalls, - Bool HaveExceptions, uint InliningThreshold); /** Destroys a memory buffer. */ diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs new file mode 100644 index 0000000000000..bad328e028c0e --- /dev/null +++ b/src/comp/middle/alias.rs @@ -0,0 +1,522 @@ +import front::ast; +import front::ast::ident; +import front::ast::def_num; +import util::common::span; +import visit::vt; +import std::vec; +import std::str; +import std::option; +import std::option::some; +import std::option::none; +import std::option::is_none; + +tag valid { + valid; + overwritten(span, ast::path); + val_taken(span, ast::path); +} + +type restrict = @rec(vec[def_num] root_vars, + def_num block_defnum, + vec[def_num] bindings, + vec[ty::t] tys, + vec[uint] depends_on, + mutable valid ok); + +type scope = vec[restrict]; +type ctx = rec(@ty::ctxt tcx, + resolve::def_map dm); + +fn check_crate(@ty::ctxt tcx, resolve::def_map dm, &@ast::crate crate) { + auto cx = @rec(tcx = tcx, dm = dm); + auto v = @rec(visit_fn = visit_fn, + visit_expr = bind visit_expr(cx, _, _, _) + with *visit::default_visitor[scope]()); + visit::visit_crate(*crate, [], visit::vtor(v)); +} + +fn visit_fn(&ast::_fn f, &span sp, &ident name, &ast::def_id d_id, + &ast::ann a, &scope sc, &vt[scope] v) { + visit::visit_fn_decl(f.decl, sc, v); + vt(v).visit_block(f.body, [], v); +} + +fn visit_expr(&@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) { + auto handled = false; + alt (ex.node) { + case (ast::expr_call(?f, ?args, _)) { + check_call(*cx, f, args, sc); + } + case (ast::expr_alt(?input, ?arms, _)) { + check_alt(*cx, input, arms, sc, v); + handled = true; + } + case (ast::expr_put(?val, _)) { + alt (val) { + case (some(?ex)) { + auto root = expr_root(*cx, ex, false); + if (!is_none(root.inner_mut)) { + cx.tcx.sess.span_err + (ex.span, + "result of put must be immutably rooted"); + } + visit_expr(cx, ex, sc, v); + } + case (_) {} + } + handled = true; + } + case (ast::expr_for_each(?decl, ?call, ?block, _)) { + check_for_each(*cx, decl, call, block, sc, v); + handled = true; + } + case (ast::expr_for(?decl, ?seq, ?block, _)) { + check_for(*cx, decl, seq, block, sc, v); + handled = true; + } + + case (ast::expr_path(?pt, ?ann)) { + check_var(*cx, ex, pt, ann, false, sc); + } + case (ast::expr_move(?dest, ?src, _)) { + check_assign(cx, dest, src, sc, v); + handled = true; + } + case (ast::expr_assign(?dest, ?src, _)) { + check_assign(cx, dest, src, sc, v); + handled = true; + } + case (ast::expr_assign_op(_, ?dest, ?src, _)) { + check_assign(cx, dest, src, sc, v); + handled = true; + } + + case (_) {} + } + if (!handled) { visit::visit_expr(ex, sc, v); } +} + +fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) + -> rec(vec[def_num] root_vars, vec[ty::t] unsafe_ts) { + auto fty = ty::expr_ty(*cx.tcx, f); + auto arg_ts = alt (ty::struct(*cx.tcx, fty)) { + case (ty::ty_fn(_, ?args, _, _)) { args } + case (ty::ty_native_fn(_, ?args, _)) { args } + }; + + auto i = 0u; + let vec[def_num] roots = []; + let vec[ty::t] unsafe_ts = []; + let vec[uint] unsafe_t_offsets = []; + for (ty::arg arg_t in arg_ts) { + if (arg_t.mode != ty::mo_val) { + auto root = expr_root(cx, args.(i), false); + alt (path_def_id(cx, root.ex)) { + case (some(?did)) { vec::push(roots, did._1); } + case (_) {} + } + alt (root.inner_mut) { + case (some(?t)) { + vec::push(unsafe_ts, t); + vec::push(unsafe_t_offsets, i); + } + case (_) {} + } + } + i += 1u; + } + + if (vec::len(unsafe_ts) > 0u) { + alt (f.node) { + case (ast::expr_path(_, ?ann)) { + if (def_is_local(cx.dm.get(ann.id))) { + cx.tcx.sess.span_err + (f.span, #fmt("function may alias with argument \ + %u, which is not immutably rooted", + unsafe_t_offsets.(0))); + } + } + case (_) {} + } + } + auto j = 0u; + for (ty::t unsafe in unsafe_ts) { + auto offset = unsafe_t_offsets.(j); + j += 1u; + auto i = 0u; + for (ty::arg arg_t in arg_ts) { + if (i != offset && + // FIXME false should be replace with mutability of alias + ty_can_unsafely_include(cx, unsafe, arg_t.ty, false)) { + cx.tcx.sess.span_err + (args.(i).span, #fmt("argument %u may alias with \ + argument %u, which is not immutably rooted", i, offset)); + } + i += 1u; + } + } + // FIXME when mutable aliases can be distinguished, go over the args again + // and ensure that we're not passing a root variable by mutable alias + // (using roots and the scope root vars). + + ret rec(root_vars = roots, unsafe_ts = unsafe_ts); +} + +fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, + &scope sc, &vt[scope] v) { + visit::visit_expr(input, sc, v); + auto root = expr_root(cx, input, true); + auto roots = alt (path_def_id(cx, root.ex)) { + case (some(?did)) { [did._1] } + case (_) { [] } + }; + let vec[ty::t] forbidden_tp = alt (root.inner_mut) { + case (some(?t)) { [t] } + case (_) { [] } + }; + + for (ast::arm a in arms) { + auto dnums = arm_defnums(a); + auto new_sc = sc; + if (vec::len(dnums) > 0u) { + vec::push(new_sc, @rec(root_vars=roots, + block_defnum=dnums.(0), + bindings=dnums, + tys=forbidden_tp, + depends_on=deps(sc, roots), + mutable ok=valid)); + } + visit::visit_arm(a, new_sc, v); + } +} + +fn arm_defnums(&ast::arm arm) -> vec[def_num] { + auto dnums = []; + fn walk_pat(&mutable vec[def_num] found, &@ast::pat p) { + alt (p.node) { + case (ast::pat_bind(_, ?did, _)) { + vec::push(found, did._1); + } + case (ast::pat_tag(_, ?children, _)) { + for (@ast::pat child in children) { + walk_pat(found, child); + } + } + case (_) {} + } + } + walk_pat(dnums, arm.pat); + ret dnums; +} + +fn check_for_each(&ctx cx, &@ast::decl decl, &@ast::expr call, + &ast::block block, &scope sc, &vt[scope] v) { + visit::visit_expr(call, sc, v); + alt (call.node) { + case (ast::expr_call(?f, ?args, _)) { + auto data = check_call(cx, f, args, sc); + auto defnum = alt (decl.node) { + case (ast::decl_local(?l)) { l.id._1 } + }; + + auto new_sc = @rec(root_vars=data.root_vars, + block_defnum=defnum, + bindings=[defnum], + tys=data.unsafe_ts, + depends_on=deps(sc, data.root_vars), + mutable ok=valid); + visit::visit_block(block, sc + [new_sc], v); + } + } +} + +fn check_for(&ctx cx, &@ast::decl decl, &@ast::expr seq, + &ast::block block, &scope sc, &vt[scope] v) { + visit::visit_expr(seq, sc, v); + auto defnum = alt (decl.node) { + case (ast::decl_local(?l)) { l.id._1 } + }; + + auto root = expr_root(cx, seq, false); + auto root_def = alt (path_def_id(cx, root.ex)) { + case (some(?did)) { [did._1] } + case (_) { [] } + }; + auto unsafe = alt (root.inner_mut) { + case (some(?t)) { [t] } + case (_) { [] } + }; + // If this is a mutable vector, don't allow it to be touched. + auto seq_t = ty::expr_ty(*cx.tcx, seq); + alt (ty::struct(*cx.tcx, seq_t)) { + case (ty::ty_vec(?mt)) { + if (mt.mut != ast::imm) { unsafe = [seq_t]; } + } + case (ty::ty_str) {} + } + + auto new_sc = @rec(root_vars=root_def, + block_defnum=defnum, + bindings=[defnum], + tys=unsafe, + depends_on=deps(sc, root_def), + mutable ok=valid); + visit::visit_block(block, sc + [new_sc], v); +} + +fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign, + &scope sc) { + auto def = cx.dm.get(ann.id); + if (!def_is_local(def)) { ret; } + auto my_defnum = ast::def_id_of_def(def)._1; + auto var_t = ty::expr_ty(*cx.tcx, ex); + for (restrict r in sc) { + // excludes variables introduced since the alias was made + if (my_defnum < r.block_defnum) { + for (ty::t t in r.tys) { + if (ty_can_unsafely_include(cx, t, var_t, assign)) { + r.ok = val_taken(ex.span, p); + } + } + } else if (vec::member(my_defnum, r.bindings)) { + test_scope(cx, sc, r, p); + } + } +} + +fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, + &scope sc, &vt[scope] v) { + visit_expr(cx, src, sc, v); + alt (dest.node) { + case (ast::expr_path(?p, ?ann)) { + auto dnum = ast::def_id_of_def(cx.dm.get(ann.id))._1; + auto var_t = ty::expr_ty(*cx.tcx, dest); + for (restrict r in sc) { + if (vec::member(dnum, r.root_vars)) { + r.ok = overwritten(dest.span, p); + } + } + check_var(*cx, dest, p, ann, true, sc); + } + case (_) { + visit_expr(cx, dest, sc, v); + } + } +} + +fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) { + auto prob = r.ok; + for (uint dep in r.depends_on) { + if (prob != valid) { break; } + prob = sc.(dep).ok; + } + if (prob != valid) { + auto msg = alt (prob) { + case (overwritten(?sp, ?wpt)) { + tup(sp, "overwriting " + ast::path_name(wpt)) + } + case (val_taken(?sp, ?vpt)) { + tup(sp, "taking the value of " + ast::path_name(vpt)) + } + }; + cx.tcx.sess.span_err + (msg._0, msg._1 + " will invalidate alias " + + ast::path_name(p) + ", which is still used"); + } +} + +fn deps(&scope sc, vec[def_num] roots) -> vec[uint] { + auto i = 0u; + auto result = []; + for (restrict r in sc) { + for (def_num dn in roots) { + if (vec::member(dn, r.bindings)) { + vec::push(result, i); + } + } + i += 1u; + } + ret result; +} + +fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) + -> rec(@ast::expr ex, option::t[ty::t] inner_mut, bool mut_in_box) { + let option::t[ty::t] mut = none; + // This is not currently used but would make it possible to be more + // liberal -- only stuff in a mutable box needs full type-inclusion + // checking, things that aren't in a box need only be checked against + // locally live aliases and their root. + auto mut_in_box = false; + while (true) { + alt ({ex.node}) { + case (ast::expr_field(?base, ?ident, _)) { + auto base_t = ty::expr_ty(*cx.tcx, base); + auto auto_unbox = maybe_auto_unbox(cx, base_t); + alt (ty::struct(*cx.tcx, auto_unbox.t)) { + case (ty::ty_tup(?fields)) { + auto fnm = ty::field_num(cx.tcx.sess, ex.span, ident); + if (fields.(fnm).mut != ast::imm && is_none(mut)) { + mut = some(auto_unbox.t); + } + } + case (ty::ty_rec(?fields)) { + for (ty::field fld in fields) { + if (str::eq(ident, fld.ident)) { + if (fld.mt.mut != ast::imm && is_none(mut)) { + mut = some(auto_unbox.t); + } + break; + } + } + } + case (ty::ty_obj(_)) {} + } + if (auto_unbox.done) { + if (!is_none(mut)) { mut_in_box = true; } + else if (auto_unbox.mut) { mut = some(base_t); } + } + ex = base; + } + case (ast::expr_index(?base, _, _)) { + auto base_t = ty::expr_ty(*cx.tcx, base); + auto auto_unbox = maybe_auto_unbox(cx, base_t); + alt (ty::struct(*cx.tcx, auto_unbox.t)) { + case (ty::ty_vec(?mt)) { + if (mt.mut != ast::imm && is_none(mut)) { + mut = some(auto_unbox.t); + } + } + } + if (auto_unbox.done) { + if (!is_none(mut)) { mut_in_box = true; } + else if (auto_unbox.mut) { mut = some(base_t); } + } + if (auto_unbox.done && !is_none(mut)) { + } + ex = base; + } + case (ast::expr_unary(?op, ?base, _)) { + if (op == ast::deref) { + auto base_t = ty::expr_ty(*cx.tcx, base); + alt (ty::struct(*cx.tcx, base_t)) { + case (ty::ty_box(?mt)) { + if (mt.mut != ast::imm && is_none(mut)) { + mut = some(base_t); + } + if (!is_none(mut)) { + mut_in_box = true; + } + } + } + ex = base; + } else { + break; + } + } + case (_) { break; } + } + } + if (autoderef) { + auto ex_t = ty::expr_ty(*cx.tcx, ex); + auto auto_unbox = maybe_auto_unbox(cx, ex_t); + if (auto_unbox.done) { + if (!is_none(mut)) { mut_in_box = true; } + else if (auto_unbox.mut) { mut = some(ex_t); } + } + } + ret rec(ex = ex, inner_mut = mut, mut_in_box = mut_in_box); +} + +fn maybe_auto_unbox(&ctx cx, &ty::t t) + -> rec(ty::t t, bool done, bool mut) { + alt (ty::struct(*cx.tcx, t)) { + case (ty::ty_box(?mt)) { + ret rec(t=mt.ty, done=true, mut=mt.mut != ast::imm); + } + case (_) { + ret rec(t=t, done=false, mut=false); + } + } +} + +fn path_def_id(&ctx cx, &@ast::expr ex) -> option::t[ast::def_id] { + alt (ex.node) { + case (ast::expr_path(_, ?ann)) { + ret some(ast::def_id_of_def(cx.dm.get(ann.id))); + } + case (_) { + ret none; + } + } +} + +fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut) + -> bool { + fn get_mut(bool cur, &ty::mt mt) -> bool { + ret cur || mt.mut != ast::imm; + } + fn helper(&ty::ctxt tcx, ty::t needle, ty::t haystack, bool mut) -> bool { + if (needle == haystack) { ret true; } + alt (ty::struct(tcx, haystack)) { + case (ty::ty_tag(_, ?ts)) { + for (ty::t t in ts) { + if (helper(tcx, needle, t, mut)) { ret true; } + } + ret false; + } + case (ty::ty_box(?mt)) { + ret helper(tcx, needle, mt.ty, get_mut(mut, mt)); + } + case (ty::ty_vec(?mt)) { + ret helper(tcx, needle, mt.ty, get_mut(mut, mt)); + } + case (ty::ty_ptr(?mt)) { + ret helper(tcx, needle, mt.ty, get_mut(mut, mt)); + } + case (ty::ty_tup(?mts)) { + for (ty::mt mt in mts) { + if (helper(tcx, needle, mt.ty, get_mut(mut, mt))) { + ret true; + } + } + ret false; + } + case (ty::ty_rec(?fields)) { + for (ty::field f in fields) { + if (helper(tcx, needle, f.mt.ty, get_mut(mut, f.mt))) { + ret true; + } + } + ret false; + } + // These may contain anything. + case (ty::ty_fn(_, _, _, _)) { ret true; } + case (ty::ty_obj(_)) { ret true; } + // A type param may include everything, but can only be treated as + // opaque downstream, and is thus safe unless we saw mutable + // fields, in which case the whole thing can be overwritten. + case (ty::ty_param(_)) { ret mut; } + case (_) { ret false; } + } + } + ret helper(*cx.tcx, needle, haystack, mut); +} + +fn def_is_local(&ast::def d) -> bool { + ret alt (d) { + case (ast::def_local(_)) { true } + case (ast::def_arg(_)) { true } + case (ast::def_obj_field(_)) { true } + case (ast::def_binding(_)) { true } + case (_) { false } + }; +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs index bee1cd17ade1d..59f3cf56387c5 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -174,6 +174,7 @@ mod Encode { w.write_char(']'); } case (ty::ty_box(?mt)) {w.write_char('@'); enc_mt(w, cx, mt); } + case (ty::ty_ptr(?mt)) {w.write_char('*'); enc_mt(w, cx, mt); } case (ty::ty_vec(?mt)) {w.write_char('V'); enc_mt(w, cx, mt); } case (ty::ty_port(?t)) {w.write_char('P'); enc_ty(w, cx, t); } case (ty::ty_chan(?t)) {w.write_char('C'); enc_ty(w, cx, t); } @@ -229,17 +230,6 @@ mod Encode { } case (ty::ty_type) {w.write_char('Y');} case (ty::ty_task) {w.write_char('a');} - - // These two don't appear in crate metadata, but are here because - // `hash_ty()` uses this function. - case (ty::ty_bound_param(?id)) { - w.write_char('o'); - w.write_str(common::uistr(id)); - } - case (ty::ty_local(?def)) { - w.write_char('L'); - w.write_str(cx.ds(def)); - } } } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index f7ff7fdde7b2e..1bd7307a5abf5 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -150,7 +150,7 @@ fn map_crate(&@env e, &ast::crate c) { fn index_vi(@env e, @mutable list[scope] sc, &@ast::view_item i) { alt (i.node) { case (ast::view_item_import(_, ?ids, ?defid)) { - e.imports.insert(defid._1, todo(i, *sc)); + e.imports.insert(defid._1, todo(i, {*sc})); } case (_) {} } @@ -231,7 +231,7 @@ fn map_crate(&@env e, &ast::crate c) { //if it really is a glob import, that is case (ast::view_item_import_glob(?path, _)) { find_mod(e, *sc).glob_imports - += [follow_import(*e, *sc, path, vi.span)]; + += [follow_import(*e, {*sc}, path, vi.span)]; } case (_) {} } @@ -275,8 +275,8 @@ fn resolve_names(&@env e, &ast::crate c) { push_env_for_expr(sc, exp); alt (exp.node) { case (ast::expr_path(?p, ?a)) { - auto df = lookup_path_strict(*e, *sc, exp.span, p.node.idents, - ns_value); + auto df = lookup_path_strict(*e, {*sc}, exp.span, + p.node.idents, ns_value); e.def_map.insert(a.id, df); } case (_) {} @@ -285,7 +285,7 @@ fn resolve_names(&@env e, &ast::crate c) { fn walk_ty(@env e, @mutable list[scope] sc, &@ast::ty t) { alt (t.node) { case (ast::ty_path(?p, ?a)) { - auto new_def = lookup_path_strict(*e, *sc, t.span, + auto new_def = lookup_path_strict(*e, {*sc}, t.span, p.node.idents, ns_type); e.def_map.insert(a.id, new_def); } @@ -293,7 +293,7 @@ fn resolve_names(&@env e, &ast::crate c) { } } fn walk_arm(@env e, @mutable list[scope] sc, &ast::arm a) { - walk_pat(*e, *sc, a.pat); + walk_pat(*e, {*sc}, a.pat); push_env_for_arm(sc, a); } fn walk_pat(&env e, &list[scope] sc, &@ast::pat pat) { @@ -307,8 +307,7 @@ fn resolve_names(&@env e, &ast::crate c) { } case (_) { e.sess.span_err(p.span, "not a tag variant: " + - str::connect(p.node.idents, "::")); - fail; + ast::path_name(p)); } } for (@ast::pat child in children) { @@ -326,14 +325,14 @@ fn push_env_for_crate(@mutable list[scope] sc, &ast::crate c) { *sc = cons[scope](scope_crate(@c), @*sc); } fn pop_env_for_crate(@mutable list[scope] sc, &ast::crate c) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_item(@mutable list[scope] sc, &@ast::item i) { *sc = cons[scope](scope_item(i), @*sc); } fn pop_env_for_item(@mutable list[scope] sc, &@ast::item i) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_method(@mutable list[scope] sc, &@ast::method m) { @@ -347,21 +346,21 @@ fn push_env_for_method(@mutable list[scope] sc, &@ast::method m) { *sc = cons[scope](scope_item(i), @*sc); } fn pop_env_for_method(@mutable list[scope] sc, &@ast::method m) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) { *sc = cons[scope](scope_native_item(i), @*sc); } fn pop_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_block(@mutable list[scope] sc, &ast::block b) { *sc = cons[scope](scope_block(b), @*sc); } fn pop_env_for_block(@mutable list[scope] sc, &ast::block b) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_expr(@mutable list[scope] sc, &@ast::expr x) { @@ -378,10 +377,10 @@ fn push_env_for_expr(@mutable list[scope] sc, &@ast::expr x) { fn pop_env_for_expr(@mutable list[scope] sc, &@ast::expr x) { alt (x.node) { case (ast::expr_for(?d, _, _, _)) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } case (ast::expr_for_each(?d, _, _, _)) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } case (_) {} } @@ -391,7 +390,7 @@ fn push_env_for_arm(@mutable list[scope] sc, &ast::arm p) { *sc = cons[scope](scope_arm(p), @*sc); } fn pop_env_for_arm(@mutable list[scope] sc, &ast::arm p) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn follow_import(&env e, &list[scope] sc, vec[ident] path, &span sp) @@ -412,7 +411,6 @@ fn follow_import(&env e, &list[scope] sc, vec[ident] path, &span sp) case (_) { e.sess.span_err(sp, str::connect(path, "::") + " does not name a module."); - fail; } } } @@ -483,7 +481,7 @@ fn ns_name(namespace ns) -> str { } } -fn unresolved(&env e, &span sp, &ident id, &str kind) { +fn unresolved(&env e, &span sp, &ident id, &str kind) -> ! { e.sess.span_err(sp, "unresolved " + kind + ": " + id); } @@ -508,7 +506,6 @@ fn lookup_in_scope_strict(&env e, list[scope] sc, &span sp, &ident id, alt (lookup_in_scope(e, sc, sp, id, ns)) { case (none) { unresolved(e, sp, id, ns_name(ns)); - fail; } case (some(?d)) { ret d; @@ -616,7 +613,7 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns) // Used to determine whether obj fields are in scope auto left_fn_level2 = false; while (true) { - alt (sc) { + alt ({sc}) { case (nil) { ret none[def]; } @@ -640,7 +637,6 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns) } } e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh - fail; } fn lookup_in_ty_params(&ident id, &vec[ast::ty_param] ty_params) @@ -790,7 +786,6 @@ fn lookup_in_mod_strict(&env e, def m, &span sp, &ident id, alt (lookup_in_mod(e, m, sp, id, ns, dr)) { case (none) { unresolved(e, sp, id, ns_name(ns)); - fail; } case (some(?d)) { ret d; @@ -855,7 +850,6 @@ fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] { case (ns_module) { md } }; } } - fail; } @@ -875,7 +869,7 @@ fn lookup_in_local_mod(&env e, def_id defid, &span sp, case (none) { } case (some(?lst)) { while (true) { - alt (lst) { + alt ({lst}) { case (nil) { break; } case (cons(?hd, ?tl)) { auto found = lookup_in_mie(e, hd, ns); @@ -915,7 +909,6 @@ fn lookup_glob_in_mod(&env e, @indexed_mod info, &span sp, } e.sess.span_err(sp, "'" + id + "' is glob-imported from" + " multiple different modules."); - fail; } } // since we don't know what names we have in advance, @@ -1133,7 +1126,7 @@ fn check_mod_name(&env e, &ident name, &list[mod_index_entry] entries) { } while (true) { - alt (entries) { + alt ({entries}) { case (cons(?entry, ?rest)) { if (!option::is_none(lookup_in_mie(e, entry, ns_value))) { if (saw_value) { dup(e, mie_span(entry), "", name); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index acabb05661757..f08d450e81d83 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -6,7 +6,7 @@ // particular definition to the LLVM IR output we're producing. // // Hopefully useful general knowledge about trans: -// +// // * There's no way to find out the ty::t type of a ValueRef. Doing so // would be "trying to get the eggs out of an omelette" (credit: // pcwalton). You can, instead, find out its TypeRef by calling val_ty, @@ -24,6 +24,7 @@ import std::map::hashmap; import std::option; import std::option::some; import std::option::none; +import std::fs; import front::ast; import front::creader; @@ -62,6 +63,15 @@ import lib::llvm::False; import lib::llvm::True; import lib::llvm::Bool; +import link::mangle_internal_name_by_type_only; +import link::mangle_internal_name_by_seq; +import link::mangle_internal_name_by_path; +import link::mangle_internal_name_by_path_and_seq; +import link::mangle_exported_name; +import link::crate_meta_name; +import link::crate_meta_vers; +import link::crate_meta_extras_hash; + state obj namegen(mutable int i) { fn next(str prefix) -> str { i += 1; @@ -118,6 +128,10 @@ state type crate_ctxt = rec(session::session sess, hashmap[ast::def_id, @ast::native_item] native_items, hashmap[ast::def_id, str] item_symbols, + mutable option::t[ValueRef] main_fn, + str crate_meta_name, + str crate_meta_vers, + str crate_meta_extras_hash, // TODO: hashmap[tup(tag_id,subtys), @tag_info] hashmap[ty::t, uint] tag_sizes, hashmap[ast::def_id, ValueRef] discrims, @@ -150,7 +164,7 @@ type val_self_pair = rec(ValueRef v, ty::t t); type ty_self_pair = tup(TypeRef, ty::t); // Function context. Every LLVM function we create will have one of these. -state type fn_ctxt = rec( +type fn_ctxt = rec( // The ValueRef returned from a call to llvm::LLVMAddFunction; the address // of the first instruction in the sequence of instructions for this // function that will go in the .text section of the executable we're @@ -160,19 +174,19 @@ state type fn_ctxt = rec( // The three implicit arguments that arrive in the function we're // creating. For instance, foo(int, int) is really foo(ret*, task*, env*, // int, int). These are also available via llvm::LLVMGetParam(llfn, uint) - // where uint = 2, 0, 1 respectively, but we unpack them here for - // convenience. + // where uint = 1, 2, 0 respectively, but we unpack them into these fields + // for convenience. ValueRef lltaskptr, ValueRef llenv, ValueRef llretptr, - + // The next three elements: "hoisted basic blocks" containing // administrative activities that have to happen in only one place in the // function, due to LLVM's quirks. // A block for all the function's allocas, so that LLVM will coalesce them // into a single alloca call. - mutable BasicBlockRef llallocas, + mutable BasicBlockRef llallocas, // A block containing code that copies incoming arguments to space already // allocated by code in the llallocas block. (LLVM requires that @@ -305,67 +319,16 @@ tag block_parent { } -state type result = rec(mutable @block_ctxt bcx, - mutable ValueRef val); - -fn sep() -> str { - ret "_"; -} +state type result = rec(@block_ctxt bcx, + ValueRef val); fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { ret @rec(path = cx.path + [name] with *cx); } -fn path_name(&vec[str] path) -> str { - ret str::connect(path, sep()); -} - - -fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { - auto hash = ""; - alt (ccx.type_sha1s.find(t)) { - case (some(?h)) { hash = h; } - case (none) { - ccx.sha.reset(); - auto f = metadata::def_to_str; - // NB: do *not* use abbrevs here as we want the symbol names - // to be independent of one another in the crate. - auto cx = @rec(ds=f, - tcx=ccx.tcx, - abbrevs=metadata::ac_no_abbrevs); - - ccx.sha.input_str(metadata::Encode::ty_str(cx, t)); - hash = str::substr(ccx.sha.result_str(), 0u, 16u); - ccx.type_sha1s.insert(t, hash); - } - } - ret hash; -} - -fn mangle_name_by_type(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str { - auto hash = get_type_sha1(ccx, t); - ret sep() + "rust" + sep() + hash + sep() + path_name(path); -} - -fn mangle_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) -> str { - auto f = metadata::def_to_str; - auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs); - auto s = ty::ty_to_short_str(ccx.tcx, t); - - auto hash = get_type_sha1(ccx, t); - ret sep() + "rust" + sep() + hash + sep() + name + "_" + s; -} - -fn mangle_name_by_seq(&@crate_ctxt ccx, &vec[str] path, - &str flav) -> str { - ret sep() + "rust" + sep() - + ccx.names.next(flav) + sep() - + path_name(path); -} - fn res(@block_ctxt bcx, ValueRef val) -> result { - ret rec(mutable bcx = bcx, - mutable val = val); + ret rec(bcx = bcx, + val = val); } fn ty_str(type_names tn, TypeRef t) -> str { @@ -715,7 +678,6 @@ fn type_of(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { cx.sess.span_err (sp, "type_of() called on a type with dynamic size: " + ty::ty_to_str(cx.tcx, t)); - fail; } ret type_of_inner(cx, sp, t); @@ -882,6 +844,9 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { case (ty::ty_vec(?mt)) { llty = T_ptr(T_vec(type_of_inner(cx, sp, mt.ty))); } + case (ty::ty_ptr(?mt)) { + llty = T_ptr(type_of_inner(cx, sp, mt.ty)); + } case (ty::ty_port(?t)) { llty = T_ptr(T_port(type_of_inner(cx, sp, t))); } @@ -934,15 +899,11 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { llty = abs_pair; } case (ty::ty_var(_)) { - cx.tcx.sess.span_err(sp, "ty_var in trans::type_of"); + cx.tcx.sess.span_err(sp, "trans::type_of called on ty_var"); } case (ty::ty_param(_)) { llty = T_i8(); } - case (ty::ty_bound_param(_)) { - log_err "ty_bound_param in trans::type_of"; - fail; - } case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); } } @@ -1209,19 +1170,8 @@ fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt { be find_scope_cx(b); } case (parent_none) { - fail; - } - } -} - -fn find_outer_scope_cx(&@block_ctxt cx) -> @block_ctxt { - auto scope_cx = find_scope_cx(cx); - alt (cx.parent) { - case (parent_some(?b)) { - be find_scope_cx(b); - } - case (parent_none) { - fail; + cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " + + "called on parentless block_ctxt"); } } } @@ -1317,8 +1267,8 @@ fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t { // Computes the size of the data part of a non-dynamically-sized tag. fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint { if (ty::type_has_dynamic_size(cx.tcx, t)) { - log_err "dynamically sized type passed to static_size_of_tag()"; - fail; + cx.tcx.sess.span_err(sp, "dynamically sized type passed to " + + "static_size_of_tag()"); } if (cx.tag_sizes.contains_key(t)) { @@ -1333,8 +1283,8 @@ fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint { subtys = subtys_; } case (_) { - log_err "non-tag passed to static_size_of_tag()"; - fail; + cx.tcx.sess.span_err(sp, "non-tag passed to " + + "static_size_of_tag()"); } } @@ -1345,7 +1295,6 @@ fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint { auto tup_ty = simplify_type(cx, ty::mk_imm_tup(cx.tcx, variant.args)); // Perform any type parameter substitutions. - tup_ty = ty::bind_params_in_type(cx.tcx, tup_ty); tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty); // Here we possibly do a recursive call. @@ -1419,10 +1368,8 @@ fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result { let vec[ty::t] raw_tys = variant.args; let vec[ty::t] tys = []; for (ty::t raw_ty in raw_tys) { - auto t = ty::bind_params_in_type(cx.fcx.lcx.ccx.tcx, - raw_ty); - t = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, tps, - t); + auto t = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, + tps, raw_ty); tys += [t]; } @@ -1599,9 +1546,8 @@ fn GEP_tag(@block_ctxt cx, auto i = 0; let vec[ty::t] true_arg_tys = []; for (ty::t aty in arg_tys) { - auto arg_ty = ty::bind_params_in_type(cx.fcx.lcx.ccx.tcx, aty); - arg_ty = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, ty_substs, - arg_ty); + auto arg_ty = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, + ty_substs, aty); true_arg_tys += [arg_ty]; if (i == ix) { elem_ty = arg_ty; @@ -1638,6 +1584,8 @@ fn GEP_tag(@block_ctxt cx, } +// trans_raw_malloc: expects a type indicating which pointer type we want and +// a size indicating how much space we want malloc'd. fn trans_raw_malloc(&@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize) -> result { // FIXME: need a table to collect tydesc globals. @@ -1647,14 +1595,29 @@ fn trans_raw_malloc(&@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize) ret res(cx, cx.build.PointerCast(rval, llptr_ty)); } + +// trans_malloc_boxed: expects an unboxed type and returns a pointer to enough +// space for something of that type, along with space for a reference count; +// in other words, it allocates a box for something of that type. fn trans_malloc_boxed(&@block_ctxt cx, ty::t t) -> result { // Synthesize a fake box type structurally so we have something // to measure the size of. + + // We synthesize two types here because we want both the type of the + // pointer and the pointee. boxed_body is the type that we measure the + // size of; box_ptr is the type that's converted to a TypeRef and used as + // the pointer cast target in trans_raw_malloc. auto boxed_body = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, + // The mk_int here is the space being + // reserved for the refcount. [ty::mk_int(cx.fcx.lcx.ccx.tcx), t]); auto box_ptr = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, t); auto sz = size_of(cx, boxed_body); + + // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc + // wants. auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, box_ptr); + ret trans_raw_malloc(sz.bcx, llty, sz.val); } @@ -1857,6 +1820,11 @@ fn set_no_inline(ValueRef f) { lib::llvm::llvm::Attribute); } +fn set_uwtable(ValueRef f) { + llvm::LLVMAddFunctionAttr(f, lib::llvm::LLVMUWTableAttribute as + lib::llvm::llvm::Attribute); +} + fn set_always_inline(ValueRef f) { llvm::LLVMAddFunctionAttr(f, lib::llvm::LLVMAlwaysInlineAttribute as lib::llvm::llvm::Attribute); @@ -1892,10 +1860,10 @@ fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, auto name; if (cx.ccx.sess.get_opts().debuginfo) { - name = mangle_name_by_type_only(cx.ccx, t, "tydesc"); + name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc"); name = sanitize(name); } else { - name = mangle_name_by_seq(cx.ccx, cx.path, "tydesc"); + name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); } auto gvar = llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), @@ -1926,10 +1894,12 @@ fn declare_generic_glue(&@local_ctxt cx, &str name) -> ValueRef { auto fn_nm; if (cx.ccx.sess.get_opts().debuginfo) { - fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name); + fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, + "glue_" + name); fn_nm = sanitize(fn_nm); } else { - fn_nm = mangle_name_by_seq(cx.ccx, cx.path, "glue_" + name); + fn_nm = mangle_internal_name_by_seq(cx.ccx, + "glue_" + name); } auto llfn = decl_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty); set_glue_inlining(cx, llfn, t); @@ -2011,7 +1981,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { auto ti = pair._1; - auto take_glue = alt (ti.take_glue) { + auto take_glue = alt ({ti.take_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) @@ -2022,7 +1992,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { } }; - auto drop_glue = alt (ti.drop_glue) { + auto drop_glue = alt ({ti.drop_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) @@ -2033,7 +2003,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { } }; - auto free_glue = alt (ti.free_glue) { + auto free_glue = alt ({ti.free_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) @@ -2044,7 +2014,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { } }; - auto cmp_glue = alt (ti.cmp_glue) { + auto cmp_glue = alt ({ti.cmp_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(cmp_fn_ty) @@ -2550,7 +2520,8 @@ fn make_scalar_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, } case (_) { // Should never get here, because t is scalar. - fail; + cx.fcx.lcx.ccx.sess.bug("non-scalar type passed to " + + "make_scalar_cmp_glue"); } } } @@ -2771,10 +2742,8 @@ fn iter_structural_ty_full(&@block_ctxt cx, auto llfldp_b = rslt.val; variant_cx = rslt.bcx; - auto ty_subst = ty::bind_params_in_type( - cx.fcx.lcx.ccx.tcx, a.ty); - ty_subst = ty::substitute_type_params( - cx.fcx.lcx.ccx.tcx, tps, ty_subst); + auto ty_subst = ty::substitute_type_params( + cx.fcx.lcx.ccx.tcx, tps, a.ty); auto llfld_a = load_if_immediate(variant_cx, @@ -2792,7 +2761,6 @@ fn iter_structural_ty_full(&@block_ctxt cx, j += 1; } } - case (_) { fail; } } variant_cx.build.Br(next_cx.llbb); @@ -2964,7 +2932,6 @@ fn iter_sequence(@block_ctxt cx, cx.fcx.lcx.ccx.sess.bug("unexpected type in " + "trans::iter_sequence: " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); - fail; } } } @@ -2991,7 +2958,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, case (some(?ti)) { if(field == abi::tydesc_field_take_glue) { - alt (ti.take_glue) { + alt ({ti.take_glue}) { case (some(_)) {} case (none) { log #fmt("+++ lazily_emit_tydesc_glue TAKE %s", @@ -3012,7 +2979,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, } } } else if (field == abi::tydesc_field_drop_glue) { - alt (ti.drop_glue) { + alt ({ti.drop_glue}) { case (some(_)) { } case (none) { log #fmt("+++ lazily_emit_tydesc_glue DROP %s", @@ -3032,7 +2999,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, } } else if (field == abi::tydesc_field_free_glue) { - alt (ti.free_glue) { + alt ({ti.free_glue}) { case (some(_)) { } case (none) { log #fmt("+++ lazily_emit_tydesc_glue FREE %s", @@ -3053,7 +3020,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, } } else if (field == abi::tydesc_field_cmp_glue) { - alt (ti.cmp_glue) { + alt ({ti.cmp_glue}) { case (some(_)) { } case (none) { log #fmt("+++ lazily_emit_tydesc_glue CMP %s", @@ -3309,7 +3276,6 @@ fn copy_val(&@block_ctxt cx, cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::copy_val: " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); - fail; } // This works like copy_val, except that it deinitializes the source. @@ -3347,7 +3313,6 @@ fn move_val(&@block_ctxt cx, cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); - fail; } @@ -3470,12 +3435,11 @@ fn trans_unary(&@block_ctxt cx, ast::unop op, ret res(sub.bcx, box); } case (ast::deref) { - log_err "deref expressions should have been translated using " + - "trans_lval(), not trans_unary()"; - fail; + cx.fcx.lcx.ccx.sess.bug("deref expressions should have been " + + "translated using trans_lval(), not " + + "trans_unary()"); } } - fail; } fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, @@ -3639,7 +3603,6 @@ fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype, ret trans_compare(cx, op, intype, lhs, rhs); } } - fail; } fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result { @@ -3667,13 +3630,11 @@ fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result { v1 = load_if_immediate(cx, v1, t1); } - case (_) { - ret res(cx, v1); - } + case (_) { break; } } } - fail; // fools the return-checker + ret res(cx, v1); } fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t { @@ -3684,13 +3645,11 @@ fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t { case (ty::ty_box(?mt)) { t1 = mt.ty; } - case (_) { - ret t1; - } + case (_) { break; } } } - fail; // fools the return-checker + ret t1; } fn trans_binary(&@block_ctxt cx, ast::binop op, @@ -3763,7 +3722,6 @@ fn trans_binary(&@block_ctxt cx, ast::binop op, autoderefed_ty(cx.fcx.lcx.ccx, lhty), lhs.val, rhs.val); } } - fail; } fn join_results(&@block_ctxt parent_cx, @@ -3857,7 +3815,7 @@ fn trans_if(&@block_ctxt cx, &@ast::expr cond, } // FIXME: This isn't quite right, particularly re: dynamic types - auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, + auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) { expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn); @@ -3929,7 +3887,7 @@ fn trans_for(&@block_ctxt cx, fn collect_upvars(&@block_ctxt cx, &ast::block bloc, &ast::def_id initial_decl) -> vec[ast::def_id] { type env = @rec( - mutable vec[ast::def_id] refs, + vec[ast::def_id] refs, hashmap[ast::def_id,()] decls, resolve::def_map def_map ); @@ -3963,7 +3921,7 @@ fn collect_upvars(&@block_ctxt cx, &ast::block bloc, let vec[ast::def_id] refs = []; let hashmap[ast::def_id,()] decls = new_def_hash[()](); decls.insert(initial_decl, ()); - let env e = @rec(mutable refs=refs, + let env e = @rec(refs=refs, decls=decls, def_map=cx.fcx.lcx.ccx.tcx.def_map); @@ -4091,7 +4049,8 @@ fn trans_for_each(&@block_ctxt cx, // Step 2: Declare foreach body function. - let str s = mangle_name_by_seq(lcx.ccx, lcx.path, "foreach"); + let str s = mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, + "foreach"); // The 'env' arg entering the body function is a fake env member (as in // the env-part of the normal rust calling convention) that actually @@ -4191,7 +4150,6 @@ fn trans_for_each(&@block_ctxt cx, ret res(r.bcx, C_nil()); } } - fail; } @@ -4242,7 +4200,7 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, case (ast::pat_lit(?lt, ?ann)) { auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann); - auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit); auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx"); @@ -4280,7 +4238,7 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb); auto ty_params = - ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx.node_types, ann); + ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann); if (vec::len[@ast::pat](subpats) > 0u) { auto llblobptr = matched_cx.build.GEP(lltagptr, @@ -4305,8 +4263,6 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, ret res(matched_cx, llval); } } - - fail; } fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, @@ -4343,7 +4299,7 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]); auto ty_param_substs = - ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx.node_types, ann); + ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann); auto this_cx = cx; auto i = 0; @@ -4392,7 +4348,7 @@ fn trans_alt(&@block_ctxt cx, &@ast::expr expr, "non-exhaustive match failure"); // FIXME: This isn't quite right, particularly re: dynamic types - auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); auto expr_llty; if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) { expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn); @@ -4457,8 +4413,8 @@ fn lval_generic_fn(&@block_ctxt cx, lv = trans_external_path(cx, fn_id, tpt); } - auto tys = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx.node_types, ann); - auto monoty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto tys = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann); + auto monoty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); if (vec::len[ty::t](tys) != 0u) { auto bcx = lv.res.bcx; @@ -4630,7 +4586,6 @@ fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0, } case (_) {cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");} } - fail; } fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, @@ -4719,7 +4674,7 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { ret lval_mem(sub.bcx, val); } case (ast::expr_self_method(?ident, ?ann)) { - alt (cx.fcx.llself) { + alt ({cx.fcx.llself}) { case (some(?pair)) { auto r = pair.v; auto t = pair.t; @@ -4727,7 +4682,9 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { } case (_) { // Shouldn't happen. - fail; + cx.fcx.lcx.ccx.sess.bug( + "trans_lval called on expr_self_method in a context" + + "without llself"); } } @@ -4738,7 +4695,6 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { + pretty::pprust::expr_to_str(e)); } } - fail; } fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype, @@ -4766,12 +4722,15 @@ fn trans_cast(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result { // TODO: native-to-native casts if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) { - e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype); + e_res = res(e_res.bcx, + e_res.bcx.build.PtrToInt(e_res.val, lldsttype)); } else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) { - e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype); + e_res = res(e_res.bcx, + e_res.bcx.build.IntToPtr(e_res.val, lldsttype)); } else { - e_res.val = int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val, - ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)); + e_res = res(e_res.bcx, + int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val, + ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t))); } } else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); @@ -4790,7 +4749,8 @@ fn trans_bind_thunk(&@local_ctxt cx, // Construct a thunk-call with signature incoming_fty, and that copies // args forward into a call to outgoing_fty: - let str s = mangle_name_by_seq(cx.ccx, cx.path, "thunk"); + let str s = mangle_internal_name_by_path_and_seq(cx.ccx, cx.path, + "thunk"); let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty)); let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod, @@ -5342,7 +5302,8 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, } - auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); + auto args_res = trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic, @@ -5672,8 +5633,17 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ret trans_expr(cx, expanded); } - case (ast::expr_fail(_)) { - ret trans_fail(cx, some(e.span), "explicit failure"); + 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_log(?lvl, ?a, _)) { @@ -5768,7 +5738,7 @@ fn with_out_method(fn(&out_method) -> result work, &@block_ctxt cx, find_scope_cx(cx).cleanups += [clean(cleanup)]; auto done = work(save_in(res_alloca.val)); - done.val = load_if_immediate(done.bcx, res_alloca.val, tp); + done = res(done.bcx, load_if_immediate(done.bcx, res_alloca.val, tp)); ret done; } } @@ -5808,13 +5778,17 @@ fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef { fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result { auto lcx = cx.fcx.lcx; - auto modname = str::connect(lcx.module_path, "::"); + auto modname = link::mangle_internal_name_by_path(lcx.ccx, + lcx.module_path); auto global; if (lcx.ccx.module_data.contains_key(modname)) { global = lcx.ccx.module_data.get(modname); } else { - global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), - str::buf("_rust_mod_log_" + modname)); + auto s = + link::mangle_internal_name_by_path_and_seq(lcx.ccx, + lcx.module_path, + "loglevel"); + global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(s)); llvm::LLVMSetGlobalConstant(global, False); llvm::LLVMSetInitializer(global, C_null(T_int())); llvm::LLVMSetLinkage(global, lib::llvm::LLVMInternalLinkage @@ -5878,7 +5852,6 @@ fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result { cx.fcx.lcx.ccx.sess.span_err(e.span, "log called on unsupported type " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, e_ty)); - fail; } } } @@ -5934,7 +5907,7 @@ fn trans_put(&@block_ctxt cx, &option::t[@ast::expr] e) -> result { auto llcallee = C_nil(); auto llenv = C_nil(); - alt (cx.fcx.lliterbody) { + alt ({cx.fcx.lliterbody}) { case (some(?lli)) { auto slot = alloca(cx, val_ty(lli)); cx.build.Store(lli, slot); @@ -5973,7 +5946,7 @@ fn trans_break_cont(&@block_ctxt cx, bool to_end) -> result { auto cleanup_cx = cx; while (true) { bcx = trans_block_cleanups(bcx, cleanup_cx); - alt (cleanup_cx.kind) { + alt ({cleanup_cx.kind}) { case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) { if (to_end) { bcx.build.Br(_break.llbb); @@ -5991,13 +5964,15 @@ fn trans_break_cont(&@block_ctxt cx, bool to_end) -> result { C_nil()); } case (_) { - alt (cleanup_cx.parent) { + alt ({cleanup_cx.parent}) { case (parent_some(?cx)) { cleanup_cx = cx; } } } } } - fail; + + // If we get here without returning, it's a bug + cx.fcx.lcx.ccx.sess.bug("in trans::trans_break_cont()"); } fn trans_break(&@block_ctxt cx) -> result { @@ -6033,7 +6008,7 @@ fn trans_ret(&@block_ctxt cx, &option::t[@ast::expr] e) -> result { auto cleanup_cx = cx; while (more_cleanups) { bcx = trans_block_cleanups(bcx, cleanup_cx); - alt (cleanup_cx.parent) { + alt ({cleanup_cx.parent}) { case (parent_some(?b)) { cleanup_cx = b; } @@ -6065,7 +6040,6 @@ fn trans_port(&@block_ctxt cx, &ast::ann ann) -> result { } case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); - fail; } } @@ -6210,8 +6184,8 @@ fn trans_spawn(&@block_ctxt cx, ret res(bcx, new_task); } -fn mk_spawn_wrapper(&@block_ctxt cx, - &@ast::expr func, +fn mk_spawn_wrapper(&@block_ctxt cx, + &@ast::expr func, &ty::t args_ty) -> result { auto llmod = cx.fcx.lcx.ccx.llmod; let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty); @@ -6223,9 +6197,10 @@ fn mk_spawn_wrapper(&@block_ctxt cx, 0u); // TODO: construct a name based on tname - let str wrap_name = mangle_name_by_seq(cx.fcx.lcx.ccx, - [""], - "spawn_wrapper"); + let str wrap_name = + mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, + cx.fcx.lcx.path, + "spawn_wrapper"); auto llfndecl = decl_fastcall_fn(llmod, wrap_name, wrapper_fn_type); @@ -6236,7 +6211,7 @@ fn mk_spawn_wrapper(&@block_ctxt cx, // 3u to skip the three implicit args let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u); - let vec[ValueRef] child_args = + let vec[ValueRef] child_args = [llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u), llvm::LLVMGetParam(fcx.llfn, 2u)]; @@ -6255,19 +6230,19 @@ fn mk_spawn_wrapper(&@block_ctxt cx, } } } - + // Find the function auto fnptr = trans_lval(fbcx, func).res; fbcx = fnptr.bcx; - + auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]); auto llfn = fbcx.build.Load(llfnptr); - + fbcx.build.FastCall(llfn, child_args); fbcx.build.RetVoid(); - + finish_fn(fcx, fbcx.llbb); // TODO: make sure we clean up everything we need to. @@ -6290,7 +6265,6 @@ fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs, } case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); - fail; } } @@ -6412,7 +6386,6 @@ fn trans_anon_obj(&@block_ctxt cx, &span sp, // TODO: everything else. cx.fcx.lcx.ccx.sess.unimpl("support for anonymous objects"); - fail; } fn init_local(&@block_ctxt cx, &@ast::local local) -> result { @@ -6705,7 +6678,7 @@ fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt { let vec[ast::ty_param] obj_typarams = []; let vec[ast::obj_field] obj_fields = []; ret @rec(path=pth, - module_path=[crate_name(ccx, "main")], + module_path=[ccx.crate_meta_name], obj_typarams = obj_typarams, obj_fields = obj_fields, ccx = ccx); @@ -6834,7 +6807,7 @@ fn copy_any_self_to_alloca(@fn_ctxt fcx, auto bcx = llallocas_block_ctxt(fcx); - alt (fcx.llself) { + alt ({fcx.llself}) { case (some(?pair)) { alt (ty_self) { case (some[ty_self_pair](?tt)) { @@ -6892,12 +6865,11 @@ fn is_terminated(&@block_ctxt cx) -> bool { } fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] { - alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types, ann))) { + alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, ann))) { case (ty::ty_fn(_, ?arg_tys, _, _)) { ret arg_tys; } } - fail; } fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { @@ -6906,12 +6878,11 @@ fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { ret ret_ty; } } - fail; } fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t { - ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx.node_types, ann)); + ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx, ann)); } fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) { @@ -6996,7 +6967,9 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params, &ast::ann ann) { auto llfndecl = cx.ccx.item_ids.get(fid); + set_uwtable(llfndecl); + // Set up arguments to the function. auto fcx = new_fn_ctxt(cx, sp, llfndecl); create_llargs_for_fn_args(fcx, f.proto, ty_self, ret_ty_of_fn(cx.ccx, ann), @@ -7004,7 +6977,7 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, copy_any_self_to_alloca(fcx, ty_self); - alt (fcx.llself) { + alt ({fcx.llself}) { case (some(?llself)) { populate_fn_ctxt_from_llself(fcx, llself); } @@ -7015,9 +6988,10 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann); copy_args_to_allocas(fcx, f.decl.inputs, arg_tys); + // Create the first basic block in the function and keep a handle on it to + // pass to finish_fn later. auto bcx = new_top_block_ctxt(fcx); add_cleanups_for_args(bcx, f.decl.inputs, arg_tys); - auto lltop = bcx.llbb; auto block_ty = node_ann_type(cx.ccx, f.body.node.a); @@ -7038,9 +7012,12 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, res.bcx.build.RetVoid(); } + // Insert the mandatory first few basic blocks before lltop. finish_fn(fcx, lltop); } +// Create a vtable for an object being translated. Returns a pointer into +// read-only memory. fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty, @@ -7075,8 +7052,9 @@ fn create_vtbl(@local_ctxt cx, } } - let @local_ctxt mcx = extend_path(cx, m.node.ident); - let str s = mangle_name_by_seq(mcx.ccx, mcx.path, "method"); + let @local_ctxt mcx = @rec(path = cx.path + ["method", + m.node.ident] with *cx); + let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(m.node.id, llfn); @@ -7088,7 +7066,8 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_seq(cx.ccx, cx.path, "vtbl"); + auto vtbl_name = mangle_internal_name_by_path(cx.ccx, + cx.path + ["vtbl"]); auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name)); llvm::LLVMSetInitializer(gvar, vtbl); @@ -7105,13 +7084,12 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let @local_ctxt dcx = extend_path(cx, "drop"); - let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop"); + let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(dtor.node.id, llfn); cx.ccx.item_symbols.insert(dtor.node.id, s); - trans_fn(dcx, dtor.span, dtor.node.meth, dtor.node.id, + trans_fn(cx, dtor.span, dtor.node.meth, dtor.node.id, some[ty_self_pair](tup(llself_ty, self_ty)), ty_params, dtor.node.ann); @@ -7133,13 +7111,15 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, // starting with an ast::_obj rather than an ast::_fn, we have some setup // work to do. - // Translate obj ctor args to function arguments. + // The fields of our object will become the arguments to the function + // we're creating. let vec[ast::arg] fn_args = []; for (ast::obj_field f in ob.fields) { fn_args += [rec(mode=ast::alias, ty=f.ty, ident=f.ident, id=f.id)]; } - auto fcx = new_fn_ctxt(cx, sp, llctor_decl); + + // Both regular arguments and type parameters are handled here. create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair], ret_ty_of_fn(ccx, ann), @@ -7148,82 +7128,114 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann); copy_args_to_allocas(fcx, fn_args, arg_tys); - // Make the first block context in the function and keep a handle on it + // Create the first block context in the function and keep a handle on it // to pass to finish_fn later. auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; + // Pick up the type of this object by looking at our own output type, that + // is, the output type of the object constructor we're building. auto self_ty = ret_ty_of_fn(ccx, ann); auto llself_ty = type_of(ccx, sp, self_ty); - auto pair = bcx.fcx.llretptr; - auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params); + // Set up the two-word pair that we're going to return from the object + // constructor we're building. The two elements of this pair will be a + // vtable pointer and a body pointer. (llretptr already points to the + // place where this two-word pair should go; it was pre-allocated by the + // caller of the function.) + auto pair = bcx.fcx.llretptr; + // Grab onto the first and second elements of the pair. + // abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1 + // of 'pair'. auto pair_vtbl = bcx.build.GEP(pair, [C_int(0), - C_int(abi::obj_field_vtbl)]); + C_int(abi::obj_field_vtbl)]); auto pair_box = bcx.build.GEP(pair, [C_int(0), - C_int(abi::obj_field_box)]); + C_int(abi::obj_field_box)]); + + // Make a vtable for this object: a static array of pointers to functions. + // It will be located in the read-only memory of the executable we're + // creating and will contain ValueRefs for all of this object's methods. + // create_vtbl returns a pointer to the vtable, which we store. + auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params); bcx.build.Store(vtbl, pair_vtbl); - let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn); + // Next we have to take care of the other half of the pair we're + // returning: a boxed (reference-counted) tuple containing a tydesc, + // typarams, and fields. + + // FIXME: What about with_obj? Do we have to think about it here? + // (Pertains to issue #417.) - // FIXME we should probably also allocate a box for empty objs that have a - // dtor, since otherwise they are never dropped, and the dtor never runs + let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn); + + // FIXME: we should probably also allocate a box for empty objs that have + // a dtor, since otherwise they are never dropped, and the dtor never + // runs. if (vec::len[ast::ty_param](ty_params) == 0u && vec::len[ty::arg](arg_tys) == 0u) { + // If the object we're translating has no fields or type parameters, + // there's not much to do. + // Store null into pair, if no args or typarams. bcx.build.Store(C_null(llbox_ty), pair_box); } else { - // Malloc a box for the body and copy args in. + // Otherwise, we have to synthesize a big structural type for the + // object body. let vec[ty::t] obj_fields = []; for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); } - // Synthesize an obj body type. + // Tuple type for fields: [field, ...] + let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields); + + // Tuple type for typarams: [typaram, ...] auto tydesc_ty = ty::mk_type(ccx.tcx); let vec[ty::t] tps = []; for (ast::ty_param tp in ty_params) { vec::push[ty::t](tps, tydesc_ty); } - - // typarams_ty = [typaram_ty, ...] let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps); - - // fields_ty = [field_ty, ...] - let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields); - - // body_ty = [tydesc_ty, [typaram_ty, ...], [field_ty, ...]] + + // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]] let ty::t body_ty = ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]); - // boxed_body_ty = [[tydesc_ty, [typaram_ty, ...], [field_ty, ...]]] - let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty); - - // Malloc a box for the body. + // Hand this type we've synthesized off to trans_malloc_boxed, which + // allocates a box, including space for a refcount. auto box = trans_malloc_boxed(bcx, body_ty); bcx = box.bcx; + + // mk_imm_box throws a refcount into the type we're synthesizing, so + // that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]] + let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty); + + // Grab onto the refcount and body parts of the box we allocated. auto rc = GEP_tup_like(bcx, boxed_body_ty, box.val, - [0, abi::box_rc_field_refcnt]); + [0, + abi::box_rc_field_refcnt]); bcx = rc.bcx; - // We've now created a structure that looks like: - // [refcount, [tydesc_ty, [typaram_ty, ...], [field_ty, ...]]] - auto body = GEP_tup_like(bcx, boxed_body_ty, box.val, [0, abi::box_rc_field_body]); bcx = body.bcx; - bcx.build.Store(C_int(1), rc.val); // Put together a tydesc for the body, so that the object can later be // freed by calling through its tydesc. + + // Every object (not just those with type parameters) needs to have a + // tydesc to describe its body, since all objects have unknown type to + // the user of the object. So the tydesc is needed to keep track of + // the types of the object's fields, so that the fields can be freed + // later. auto body_tydesc = GEP_tup_like(bcx, body_ty, body.val, [0, abi::obj_body_elt_tydesc]); @@ -7234,17 +7246,16 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti); lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti); - auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn))); - alt (ob.dtor) { - case (some(?d)) { - dtor = trans_dtor(cx, llself_ty, self_ty, ty_params, d); - } - case (none) {} - } - bcx = body_td.bcx; bcx.build.Store(body_td.val, body_tydesc.val); + // Copy the object's type parameters and fields into the space we + // allocated for the object body. (This is something like saving the + // lexical environment of a function in its closure: the "captured + // typarams" are any type parameters that are passed to the object + // constructor and are then available to the object's methods. + // Likewise for the object's fields.) + // Copy typarams into captured typarams. auto body_typarams = GEP_tup_like(bcx, body_ty, body.val, @@ -7282,6 +7293,7 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, } bcx.build.RetVoid(); + // Insert the mandatory first few basic blocks before lltop. finish_fn(fcx, lltop); } @@ -7462,18 +7474,32 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } case (_) { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); - fail; } } + let bool is_main = (str::eq(vec::top(path), "main") && + !ccx.sess.get_opts().shared); + // Declare the function itself. - let str s = mangle_name_by_seq(ccx, path, flav); + let str s = + if (is_main) { "_rust_main" } + else { mangle_internal_name_by_path(ccx, path) }; + let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty); // Declare the global constant pair that points to it. - let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); - + let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, llpairty, llfn, id); + + if (is_main) { + if (ccx.main_fn != none[ValueRef]) { + ccx.sess.span_err(sp, "multiple 'main' functions"); + } + llvm::LLVMSetLinkage(llfn, lib::llvm::LLVMExternalLinkage + as llvm::Linkage); + ccx.main_fn = some(llfn); + } + } fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn, @@ -7504,8 +7530,7 @@ fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint { alt (native_item.node) { case (ast::native_item_ty(_,_)) { cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " + - "actually a fn?!"); - fail; + "actually a fn"); } case (ast::native_item_fn(_, _, _, ?tps, _, _)) { count = vec::len[ast::ty_param](tps); @@ -7521,7 +7546,6 @@ fn native_fn_wrapper_type(&@crate_ctxt cx, &span sp, uint ty_param_count, ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count); } } - fail; } fn decl_native_fn_and_pair(&@crate_ctxt ccx, @@ -7534,14 +7558,15 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, // Declare the wrapper. auto t = node_ann_type(ccx, ann); + auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t); - let str s = mangle_name_by_seq(ccx, path, "wrapper"); + let str s = mangle_internal_name_by_path(ccx, path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type); // Declare the global constant pair that points to it. auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type); - let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); + let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id); @@ -7878,9 +7903,8 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { auto discrim_val = C_int(i as int); - auto s = mangle_name_by_seq(ccx, wcx.path, - #fmt("_rust_tag_discrim_%s_%u", - ident, i)); + auto p = wcx.path + [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)); @@ -7899,8 +7923,8 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { // with consts. auto v = C_int(1); ccx.item_ids.insert(cid, v); - auto s = mangle_name_by_type(ccx, wcx.path + [name], - node_ann_type(ccx, ann)); + auto s = mangle_exported_name(ccx, wcx.path + [name], + node_ann_type(ccx, ann)); ccx.item_symbols.insert(cid, s); } @@ -7939,68 +7963,6 @@ fn create_typedefs(&@crate_ctxt cx) { llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn)); } -fn find_main_fn(&@crate_ctxt cx) -> ValueRef { - auto e = sep() + "main"; - let ValueRef v = C_nil(); - let uint n = 0u; - for each (@tup(ast::def_id, str) i in cx.item_symbols.items()) { - if (str::ends_with(i._1, e)) { - n += 1u; - v = cx.item_ids.get(i._0); - } - } - alt (n) { - case (0u) { - cx.sess.err("main fn not found"); - } - case (1u) { - ret v; - } - case (_) { - cx.sess.err("multiple main fns found"); - } - } - fail; -} - -fn trans_main_fn(@local_ctxt cx, ValueRef crate_map) { - auto T_main_args = [T_int(), T_int()]; - auto T_rust_start_args = [T_int(), T_int(), T_int(), T_int()]; - - auto main_name; - if (str::eq(std::os::target_os(), "win32")) { - main_name = "WinMain@16"; - } else { - main_name = "main"; - } - - auto llmain = - decl_cdecl_fn(cx.ccx.llmod, main_name, T_fn(T_main_args, T_int())); - - auto llrust_start = decl_cdecl_fn(cx.ccx.llmod, "rust_start", - T_fn(T_rust_start_args, T_int())); - - auto llargc = llvm::LLVMGetParam(llmain, 0u); - auto llargv = llvm::LLVMGetParam(llmain, 1u); - auto llrust_main = find_main_fn(cx.ccx); - - // - // Emit the moral equivalent of: - // - // main(int argc, char **argv) { - // rust_start(&_rust.main, argc, argv); - // } - // - - let BasicBlockRef llbb = - llvm::LLVMAppendBasicBlock(llmain, str::buf("")); - auto b = new_builder(llbb); - - auto start_args = [p2i(llrust_main), llargc, llargv, p2i(crate_map)]; - - b.Ret(b.Call(llrust_start, start_args)); -} - fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] { let vec[TypeRef] T_memmove32_args = [T_ptr(T_i8()), T_ptr(T_i8()), @@ -8171,8 +8133,6 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef { auto maptype = T_array(elttype, ccx.module_data.size() + 1u); auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf("_rust_mod_map")); - llvm::LLVMSetLinkage(map, lib::llvm::LLVMInternalLinkage - as llvm::Linkage); let vec[ValueRef] elts = []; for each (@tup(str, ValueRef) item in ccx.module_data.items()) { auto elt = C_struct([p2i(C_cstr(ccx, item._0)), p2i(item._1)]); @@ -8184,15 +8144,6 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef { ret map; } -fn crate_name(&@crate_ctxt ccx, &str deflt) -> str { - for (@ast::meta_item item in ccx.sess.get_metadata()) { - if (str::eq(item.node.name, "name")) { - ret item.node.value; - } - } - ret deflt; -} - // FIXME use hashed metadata instead of crate names once we have that fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { let vec[ValueRef] subcrates = []; @@ -8205,7 +8156,13 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { i += 1; } vec::push[ValueRef](subcrates, C_int(0)); - auto sym_name = "_rust_crate_map_" + crate_name(ccx, "__none__"); + auto mapname; + if (ccx.sess.get_opts().shared) { + mapname = ccx.crate_meta_name; + } else { + mapname = "toplevel"; + } + auto sym_name = "_rust_crate_map_" + mapname; auto arrtype = T_array(T_int(), vec::len[ValueRef](subcrates)); auto maptype = T_struct([T_int(), arrtype]); auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf(sym_name)); @@ -8239,7 +8196,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, auto sha1s = map::mk_hashmap[ty::t,str](hasher, eqer); auto abbrevs = map::mk_hashmap[ty::t,metadata::ty_abbrev](hasher, eqer); auto short_names = map::mk_hashmap[ty::t,str](hasher, eqer); - + auto sha = std::sha1::mk_sha1(); auto ccx = @rec(sess = sess, llmod = llmod, td = td, @@ -8250,6 +8207,11 @@ fn trans_crate(&session::session sess, &@ast::crate crate, items = new_def_hash[@ast::item](), native_items = new_def_hash[@ast::native_item](), item_symbols = new_def_hash[str](), + mutable main_fn = none[ValueRef], + crate_meta_name = crate_meta_name(sess, *crate, output), + crate_meta_vers = crate_meta_vers(sess, *crate), + crate_meta_extras_hash = + crate_meta_extras_hash(sha, *crate), tag_sizes = tag_sizes, discrims = new_def_hash[ValueRef](), discrim_symbols = new_def_hash[str](), @@ -8261,7 +8223,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, lltypes = lltypes, glues = glues, names = namegen(0), - sha = std::sha1::mk_sha1(), + sha = sha, type_sha1s = sha1s, type_abbrevs = abbrevs, type_short_names = short_names, @@ -8281,9 +8243,6 @@ fn trans_crate(&session::session sess, &@ast::crate crate, trans_constants(ccx, crate); trans_mod(cx, crate.node.module); auto crate_map = create_crate_map(ccx); - if (!sess.get_opts().shared) { - trans_main_fn(cx, crate_map); - } emit_tydescs(ccx); diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 4aa178d6c5c12..b801954b933e3 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -482,7 +482,7 @@ fn controlflow_def_id(&crate_ctxt ccx, &def_id d) -> controlflow { If it has a function type with a ! annotation, the answer is noreturn. */ fn controlflow_expr(&crate_ctxt ccx, @expr e) -> controlflow { - alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types, + alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, expr_ann(e)))) { case (ty::ty_fn(_,_,_,?cf)) { ret cf; diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index d1df649f7a61e..da4e333f0a625 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -459,7 +459,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () { find_pre_post_expr(fcx, operator); copy_pre_post(fcx.ccx, a, operator); } - case (expr_fail(?a)) { + case (expr_fail(?a, _)) { set_pre_and_post(fcx.ccx, a, /* if execution continues after fail, then everything is true! */ diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 37cc40b5c9eb5..369f307aa819b 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -508,7 +508,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool { expr_poststate(fcx.ccx, operand)) || changed; ret changed; } - case (expr_fail(?a)) { + case (expr_fail(?a, _)) { changed = extend_prestate_ann(fcx.ccx, a, pres) || changed; /* if execution continues after fail, then everything is true! woo! */ changed = set_poststate_ann(fcx.ccx, a, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 5f0c9a90362ab..3cd2602ed819f 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -9,6 +9,7 @@ import std::map::hashmap; import std::option; import std::option::none; import std::option::some; +import std::smallintmap; import driver::session; import front::ast; @@ -41,7 +42,6 @@ import util::data::interner; tag mode { mo_val; mo_alias; - mo_either; } type arg = rec(mode mode, t ty); @@ -88,9 +88,7 @@ type raw_t = rec(sty struct, option::t[str] cname, uint hash, bool has_params, - bool has_bound_params, - bool has_vars, - bool has_locals); + bool has_vars); type t = uint; @@ -109,6 +107,7 @@ tag sty { ty_tag(ast::def_id, vec[t]); ty_box(mt); ty_vec(mt); + ty_ptr(mt); ty_port(t); ty_chan(t); ty_task; @@ -117,10 +116,8 @@ tag sty { ty_fn(ast::proto, vec[arg], t, controlflow); ty_native_fn(ast::native_abi, vec[arg], t); ty_obj(vec[method]); - ty_var(int); // ephemeral type var - ty_local(ast::def_id); // type of a local var + ty_var(int); // type variable ty_param(uint); // fn/tag type param - ty_bound_param(uint); // bound param, only paths ty_type; ty_native; // TODO: ty_fn_arg(t), for a possibly-aliased function argument @@ -128,12 +125,6 @@ tag sty { // Data structures used in type unification -type unify_handler = obj { - fn resolve_local(ast::def_id id) -> option::t[t]; - fn record_local(ast::def_id id, t ty); // TODO: -> unify::result - fn record_param(uint index, t binding) -> unify::result; -}; - tag type_err { terr_mismatch; terr_controlflow_mismatch; @@ -258,132 +249,101 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t { auto h = hash_type_info(st, cname); let bool has_params = false; - let bool has_bound_params = false; let bool has_vars = false; - let bool has_locals = false; fn derive_flags_t(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &t tt) { auto rt = interner::get[raw_t](*cx.ts, tt); has_params = has_params || rt.has_params; - has_bound_params = has_bound_params || rt.has_bound_params; has_vars = has_vars || rt.has_vars; - has_locals = has_locals || rt.has_locals; } fn derive_flags_mt(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &mt m) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, m.ty); + derive_flags_t(cx, has_params, has_vars, m.ty); } fn derive_flags_arg(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &arg a) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, a.ty); + derive_flags_t(cx, has_params, has_vars, a.ty); } fn derive_flags_sig(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &vec[arg] args, &t tt) { for (arg a in args) { - derive_flags_arg(cx, has_params, has_bound_params, - has_vars, has_locals, a); + derive_flags_arg(cx, has_params, has_vars, a); } - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } alt (st) { case (ty_param(_)) { has_params = true; } - case (ty_bound_param(_)) { - has_bound_params = true; - } case (ty_var(_)) { has_vars = true; } - case (ty_local(_)) { has_locals = true; } case (ty_tag(_, ?tys)) { for (t tt in tys) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } } case (ty_box(?m)) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, m); + derive_flags_mt(cx, has_params, has_vars, m); } case (ty_vec(?m)) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, m); + derive_flags_mt(cx, has_params, has_vars, m); } case (ty_port(?tt)) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } case (ty_chan(?tt)) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } case (ty_tup(?mts)) { for (mt m in mts) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, m); + derive_flags_mt(cx, has_params, has_vars, m); } } case (ty_rec(?flds)) { for (field f in flds) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, f.mt); + derive_flags_mt(cx, has_params, has_vars, f.mt); } } case (ty_fn(_, ?args, ?tt, _)) { - derive_flags_sig(cx, has_params, has_bound_params, - has_vars, has_locals, args, tt); + derive_flags_sig(cx, has_params, has_vars, args, tt); } case (ty_native_fn(_, ?args, ?tt)) { - derive_flags_sig(cx, has_params, has_bound_params, - has_vars, has_locals, args, tt); + derive_flags_sig(cx, has_params, has_vars, args, tt); } case (ty_obj(?meths)) { for (method m in meths) { - derive_flags_sig(cx, has_params, has_bound_params, - has_vars, has_locals, m.inputs, m.output); + derive_flags_sig(cx, has_params, has_vars, m.inputs, + m.output); } } case (_) { } } ret rec(struct=st, cname=cname, hash=h, - has_params = has_params, - has_bound_params = has_bound_params, - has_vars = has_vars, - has_locals = has_locals); + has_params=has_params, + has_vars=has_vars); } fn intern(&ctxt cx, &sty st, &option::t[str] cname) { @@ -423,7 +383,6 @@ fn mk_mach(&ctxt cx, &util::common::ty_mach tm) -> t { case (ty_f32) { ret idx_f32; } case (ty_f64) { ret idx_f64; } } - fail; } fn mk_char(&ctxt cx) -> t { ret idx_char; } @@ -437,6 +396,10 @@ fn mk_box(&ctxt cx, &mt tm) -> t { ret gen_ty(cx, ty_box(tm)); } +fn mk_ptr(&ctxt cx, &mt tm) -> t { + ret gen_ty(cx, ty_ptr(tm)); +} + fn mk_imm_box(&ctxt cx, &t ty) -> t { ret mk_box(cx, rec(ty=ty, mut=ast::imm)); } @@ -481,18 +444,10 @@ fn mk_var(&ctxt cx, int v) -> t { ret gen_ty(cx, ty_var(v)); } -fn mk_local(&ctxt cx, ast::def_id did) -> t { - ret gen_ty(cx, ty_local(did)); -} - fn mk_param(&ctxt cx, uint n) -> t { ret gen_ty(cx, ty_param(n)); } -fn mk_bound_param(&ctxt cx, uint n) -> t { - ret gen_ty(cx, ty_bound_param(n)); -} - fn mk_type(&ctxt cx) -> t { ret idx_type; } fn mk_native(&ctxt cx) -> t { ret idx_native; } @@ -530,7 +485,6 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { alt (input.mode) { case (mo_val) { s = ""; } case (mo_alias) { s = "&"; } - case (mo_either) { s = "?"; } } ret s + ty_to_str(cx, input.ty); @@ -591,10 +545,8 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { } alt (cname(cx, typ)) { - case (some(?cs)) { - ret cs; - } - case (_) { } + case (some(?cs)) { ret cs; } + case (_) { /* fall through */ } } auto s = ""; @@ -611,6 +563,7 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { case (ty_char) { s += "char"; } case (ty_str) { s += "str"; } case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); } + case (ty_ptr(?tm)) { s += "*" + mt_to_str(cx, tm); } case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; } case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; } case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; } @@ -659,20 +612,10 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { s += ""; } - case (ty_local(?id)) { - s += ""; - } - case (ty_param(?id)) { s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]); } - case (ty_bound_param(?id)) { - s += "''" + str::unsafe_from_bytes([('a' as u8) + - (id as u8)]); - } - case (_) { s += ty_to_short_str(cx, typ); } @@ -748,9 +691,7 @@ fn walk_ty(&ctxt cx, ty_walk walker, t ty) { } } case (ty_var(_)) { /* no-op */ } - case (ty_local(_)) { /* no-op */ } case (ty_param(_)) { /* no-op */ } - case (ty_bound_param(_)) { /* no-op */ } } walker(ty); @@ -777,6 +718,10 @@ fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t { ty = copy_cname(cx, mk_box(cx, rec(ty=fold_ty(cx, fld, tm.ty), mut=tm.mut)), ty); } + case (ty_ptr(?tm)) { + ty = copy_cname(cx, mk_ptr(cx, rec(ty=fold_ty(cx, fld, tm.ty), + mut=tm.mut)), ty); + } case (ty_vec(?tm)) { ty = copy_cname(cx, mk_vec(cx, rec(ty=fold_ty(cx, fld, tm.ty), mut=tm.mut)), ty); @@ -844,9 +789,7 @@ fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t { ty = copy_cname(cx, mk_obj(cx, new_methods), ty); } case (ty_var(_)) { /* no-op */ } - case (ty_local(_)) { /* no-op */ } case (ty_param(_)) { /* no-op */ } - case (ty_bound_param(_)) { /* no-op */ } } ret fld(ty); @@ -895,7 +838,6 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool { case (ty_obj(_)) { ret true; } case (_) { ret false; } } - fail; } fn type_is_sequence(&ctxt cx, &t ty) -> bool { @@ -904,15 +846,16 @@ fn type_is_sequence(&ctxt cx, &t ty) -> bool { case (ty_vec(_)) { ret true; } case (_) { ret false; } } - fail; } fn sequence_element_type(&ctxt cx, &t ty) -> t { alt (struct(cx, ty)) { case (ty_str) { ret mk_mach(cx, common::ty_u8); } case (ty_vec(?mt)) { ret mt.ty; } + // NB: This is not exhaustive. } - fail; + + cx.sess.bug("sequence_element_type called on non-sequence value"); } fn type_is_tup_like(&ctxt cx, &t ty) -> bool { @@ -923,7 +866,6 @@ fn type_is_tup_like(&ctxt cx, &t ty) -> bool { case (ty_tag(_,_)) { ret true; } case (_) { ret false; } } - fail; } fn get_element_type(&ctxt cx, &t ty, uint i) -> t { @@ -935,8 +877,12 @@ fn get_element_type(&ctxt cx, &t ty, uint i) -> t { case (ty_rec(?flds)) { ret flds.(i).mt.ty; } + // NB: This is not exhaustive -- struct(cx, ty) could be a box or a + // tag. } - fail; + + cx.sess.bug("get_element_type called on a value other than a " + + "tuple or record"); } fn type_is_box(&ctxt cx, &t ty) -> bool { @@ -944,7 +890,6 @@ fn type_is_box(&ctxt cx, &t ty) -> bool { case (ty_box(_)) { ret true; } case (_) { ret false; } } - fail; } fn type_is_boxed(&ctxt cx, &t ty) -> bool { @@ -957,7 +902,6 @@ fn type_is_boxed(&ctxt cx, &t ty) -> bool { case (ty_task) { ret true; } case (_) { ret false; } } - fail; } fn type_is_scalar(&ctxt cx, &t ty) -> bool { @@ -971,12 +915,11 @@ fn type_is_scalar(&ctxt cx, &t ty) -> bool { case (ty_char) { ret true; } case (ty_type) { ret true; } case (ty_native) { ret true; } + case (ty_ptr(_)) { ret true; } case (_) { ret false; } } - fail; } - fn type_has_pointers(&ctxt cx, &t ty) -> bool { alt (struct(cx, ty)) { // scalar types @@ -1009,7 +952,6 @@ fn type_has_pointers(&ctxt cx, &t ty) -> bool { for (variant_info variant in variants) { auto tup_ty = mk_imm_tup(cx, variant.args); // Perform any type parameter substitutions. - tup_ty = bind_params_in_type(cx, tup_ty); tup_ty = substitute_type_params(cx, tps, tup_ty); if (type_has_pointers(cx, tup_ty)) { ret true; } } @@ -1017,7 +959,6 @@ fn type_has_pointers(&ctxt cx, &t ty) -> bool { } case (_) { ret true; } } - fail; } @@ -1028,7 +969,6 @@ fn type_is_native(&ctxt cx, &t ty) -> bool { case (ty_native) { ret true; } case (_) { ret false; } } - fail; } fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool { @@ -1083,7 +1023,6 @@ fn type_is_integral(&ctxt cx, &t ty) -> bool { case (ty_char) { ret true; } case (_) { ret false; } } - fail; } fn type_is_fp(&ctxt cx, &t ty) -> bool { @@ -1100,7 +1039,6 @@ fn type_is_fp(&ctxt cx, &t ty) -> bool { } case (_) { ret false; } } - fail; } fn type_is_signed(&ctxt cx, &t ty) -> bool { @@ -1117,7 +1055,6 @@ fn type_is_signed(&ctxt cx, &t ty) -> bool { } case (_) { ret false; } } - fail; } fn type_param(&ctxt cx, &t ty) -> option::t[uint] { @@ -1224,12 +1161,11 @@ fn hash_type_structure(&sty st) -> uint { ret h; } case (ty_var(?v)) { ret hash_uint(28u, v as uint); } - case (ty_local(?did)) { ret hash_def(29u, did); } - case (ty_param(?pid)) { ret hash_uint(30u, pid); } - case (ty_bound_param(?pid)) { ret hash_uint(31u, pid); } - case (ty_type) { ret 32u; } - case (ty_native) { ret 33u; } - case (ty_bot) { ret 34u; } + case (ty_param(?pid)) { ret hash_uint(29u, pid); } + case (ty_type) { ret 30u; } + case (ty_native) { ret 31u; } + case (ty_bot) { ret 32u; } + case (ty_ptr(?mt)) { ret hash_subty(33u, mt.ty); } } } @@ -1361,6 +1297,12 @@ fn equal_type_structures(&sty a, &sty b) -> bool { case (_) { ret false; } } } + case (ty_ptr(?mt_a)) { + alt (b) { + case (ty_ptr(?mt_b)) { ret equal_mt(mt_a, mt_b); } + case (_) { ret false; } + } + } case (ty_port(?t_a)) { alt (b) { case (ty_port(?t_b)) { ret eq_ty(t_a, t_b); } @@ -1459,24 +1401,12 @@ fn equal_type_structures(&sty a, &sty b) -> bool { case (_) { ret false; } } } - case (ty_local(?did_a)) { - alt (b) { - case (ty_local(?did_b)) { ret equal_def(did_a, did_b); } - case (_) { ret false; } - } - } case (ty_param(?pid_a)) { alt (b) { case (ty_param(?pid_b)) { ret pid_a == pid_b; } case (_) { ret false; } } } - case (ty_bound_param(?pid_a)) { - alt (b) { - case (ty_bound_param(?pid_b)) { ret pid_a == pid_b; } - case (_) { ret false; } - } - } case (ty_type) { alt (b) { case (ty_type) { ret true; } @@ -1531,24 +1461,25 @@ fn eq_ty(&t a, &t b) -> bool { ret a == b; } // Type lookups -fn ann_to_ty_param_substs_opt_and_ty(&node_type_table ntt, &ast::ann ann) - -> ty_param_substs_opt_and_ty { - alt (ntt.(ann.id)) { +fn ann_to_ty_param_substs_opt_and_ty(&ctxt cx, &ast::ann ann) + -> ty_param_substs_opt_and_ty { + + // Pull out the node type table. + alt ({cx.node_types.(ann.id)}) { case (none) { - log_err "ann_to_ty_param_substs_opt_and_ty() called on an " + - "untyped node"; - fail; + cx.sess.bug("ann_to_ty_param_substs_opt_and_ty() called on an " + + "untyped node"); } case (some(?tpot)) { ret tpot; } } } -fn ann_to_type(&node_type_table ntt, &ast::ann ann) -> t { - ret ann_to_ty_param_substs_opt_and_ty(ntt, ann)._1; +fn ann_to_type(&ctxt cx, &ast::ann ann) -> t { + ret ann_to_ty_param_substs_opt_and_ty(cx, ann)._1; } -fn ann_to_type_params(&node_type_table ntt, &ast::ann ann) -> vec[t] { - alt (ann_to_ty_param_substs_opt_and_ty(ntt, ann)._0) { +fn ann_to_type_params(&ctxt cx, &ast::ann ann) -> vec[t] { + alt (ann_to_ty_param_substs_opt_and_ty(cx, ann)._0) { case (none) { let vec[t] result = []; ret result; @@ -1557,24 +1488,29 @@ fn ann_to_type_params(&node_type_table ntt, &ast::ann ann) -> vec[t] { } } -fn ann_has_type_params(&node_type_table ntt, &ast::ann ann) -> bool { - auto tpt = ann_to_ty_param_substs_opt_and_ty(ntt, ann); +fn ann_has_type_params(&ctxt cx, &ast::ann ann) -> bool { + auto tpt = ann_to_ty_param_substs_opt_and_ty(cx, ann); ret !option::is_none[vec[t]](tpt._0); } -// Returns the type of an annotation, with type parameter substitutions -// performed if applicable. -fn ann_to_monotype(&ctxt cx, ast::ann a) -> t { - auto tpot = ann_to_ty_param_substs_opt_and_ty(cx.node_types, a); +// Returns a type with type parameter substitutions performed if applicable. +fn ty_param_substs_opt_and_ty_to_monotype(&ctxt cx, + &ty_param_substs_opt_and_ty tpot) + -> t { alt (tpot._0) { case (none) { ret tpot._1; } - case (some(?tps)) { - ret substitute_type_params(cx, tps, tpot._1); - } + case (some(?tps)) { ret substitute_type_params(cx, tps, tpot._1); } } } +// Returns the type of an annotation, with type parameter substitutions +// performed if applicable. +fn ann_to_monotype(&ctxt cx, ast::ann a) -> t { + auto tpot = ann_to_ty_param_substs_opt_and_ty(cx, a); + ret ty_param_substs_opt_and_ty_to_monotype(cx, tpot); +} + // Returns the number of distinct type parameters in the given type. fn count_ty_params(&ctxt cx, t ty) -> uint { @@ -1606,18 +1542,10 @@ fn type_contains_vars(&ctxt cx, &t typ) -> bool { ret interner::get[raw_t](*cx.ts, typ).has_vars; } -fn type_contains_locals(&ctxt cx, &t typ) -> bool { - ret interner::get[raw_t](*cx.ts, typ).has_locals; -} - fn type_contains_params(&ctxt cx, &t typ) -> bool { ret interner::get[raw_t](*cx.ts, typ).has_params; } -fn type_contains_bound_params(&ctxt cx, &t typ) -> bool { - ret interner::get[raw_t](*cx.ts, typ).has_bound_params; -} - // Type accessors for substructures of types fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] { @@ -1625,21 +1553,21 @@ fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] { case (ty::ty_fn(_, ?a, _, _)) { ret a; } case (ty::ty_native_fn(_, ?a, _)) { ret a; } } - fail; + cx.sess.bug("ty_fn_args() called on non-fn type"); } fn ty_fn_proto(&ctxt cx, &t fty) -> ast::proto { alt (struct(cx, fty)) { case (ty::ty_fn(?p, _, _, _)) { ret p; } } - fail; + cx.sess.bug("ty_fn_proto() called on non-fn type"); } fn ty_fn_abi(&ctxt cx, &t fty) -> ast::native_abi { alt (struct(cx, fty)) { case (ty::ty_native_fn(?a, _, _)) { ret a; } } - fail; + cx.sess.bug("ty_fn_abi() called on non-native-fn type"); } fn ty_fn_ret(&ctxt cx, &t fty) -> t { @@ -1647,7 +1575,7 @@ fn ty_fn_ret(&ctxt cx, &t fty) -> t { case (ty::ty_fn(_, _, ?r, _)) { ret r; } case (ty::ty_native_fn(_, _, ?r)) { ret r; } } - fail; + cx.sess.bug("ty_fn_ret() called on non-fn type"); } fn is_fn_ty(&ctxt cx, &t fty) -> bool { @@ -1656,72 +1584,20 @@ fn is_fn_ty(&ctxt cx, &t fty) -> bool { case (ty::ty_native_fn(_, _, _)) { ret true; } case (_) { ret false; } } - ret false; } - -// Type accessors for AST nodes - -// Given an item, returns the associated type as well as the number of type -// parameters it has. -fn native_item_ty(&node_type_table ntt, &@ast::native_item it) - -> ty_param_count_and_ty { - auto ty_param_count; - auto result_ty; - alt (it.node) { - case (ast::native_item_fn(_, _, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } +fn ty_var_id(&ctxt cx, t typ) -> int { + alt (struct(cx, typ)) { + case (ty::ty_var(?vid)) { ret vid; } + case (_) { log_err "ty_var_id called on non-var ty"; fail; } } - ret tup(ty_param_count, result_ty); } -fn item_ty(&node_type_table ntt, &@ast::item it) -> ty_param_count_and_ty { - auto ty_param_count; - auto result_ty; - alt (it.node) { - case (ast::item_const(_, _, _, _, ?ann)) { - ty_param_count = 0u; - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_fn(_, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_mod(_, _, _)) { - fail; // modules are typeless - } - case (ast::item_ty(_, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_tag(_, _, ?tps, ?did, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_obj(_, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - } - - ret tup(ty_param_count, result_ty); -} -fn stmt_ty(&ctxt cx, &@ast::stmt s) -> t { - alt (s.node) { - case (ast::stmt_expr(?e,_)) { - ret expr_ty(cx, e); - } - case (_) { - ret mk_nil(cx); - } - } -} +// Type accessors for AST nodes fn block_ty(&ctxt cx, &ast::block b) -> t { - ret ann_to_type(cx.node_types, b.node.a); + ret ann_to_type(cx, b.node.a); } // Returns the type of a pattern as a monotype. Like @expr_ty, this function @@ -1777,7 +1653,7 @@ fn expr_ann(&@ast::expr e) -> ast::ann { case (ast::expr_index(_,_,?a)) { ret a; } case (ast::expr_path(_,?a)) { ret a; } case (ast::expr_ext(_,_,_,_,?a)) { ret a; } - case (ast::expr_fail(?a)) { ret a; } + case (ast::expr_fail(?a,_)) { ret a; } case (ast::expr_ret(_,?a)) { ret a; } case (ast::expr_put(_,?a)) { ret a; } case (ast::expr_be(_,?a)) { ret a; } @@ -1808,18 +1684,18 @@ fn expr_ty_params_and_ty(&ctxt cx, &@ast::expr expr) -> tup(vec[t], t) { auto a = expr_ann(expr); - ret tup(ann_to_type_params(cx.node_types, a), - ann_to_type(cx.node_types, a)); + ret tup(ann_to_type_params(cx, a), + ann_to_type(cx, a)); } -fn expr_has_ty_params(&node_type_table ntt, &@ast::expr expr) -> bool { - ret ann_has_type_params(ntt, expr_ann(expr)); +fn expr_has_ty_params(&ctxt cx, &@ast::expr expr) -> bool { + ret ann_has_type_params(cx, expr_ann(expr)); } fn decl_local_ty(&ctxt cx, &@ast::decl d) -> t { alt (d.node) { case (ast::decl_local(?l)) { - ret ann_to_type(cx.node_types, l.ann); + ret ann_to_type(cx, l.ann); } case (_) { cx.sess.bug("decl_local_ty called on an item decl"); @@ -1889,7 +1765,6 @@ fn field_idx(&session::session sess, &span sp, i += 1u; } sess.span_err(sp, "unknown field '" + id + "' of record"); - fail; } fn method_idx(&session::session sess, &span sp, @@ -1902,7 +1777,6 @@ fn method_idx(&session::session sess, &span sp, i += 1u; } sess.span_err(sp, "unknown method '" + id + "' of obj"); - fail; } fn sort_methods(&vec[method] meths) -> vec[method] { @@ -1931,55 +1805,88 @@ fn is_lval(&@ast::expr expr) -> bool { mod unify { tag result { ures_ok(t); - ures_err(type_err, t, t); + ures_err(type_err); } - tag set_result { - usr_ok(vec[t]); - usr_err(type_err, t, t); + tag union_result { + unres_ok; + unres_err(type_err); } - type bindings[T] = rec(ufind::ufind sets, - hashmap[T,uint] ids, - mutable vec[mutable option::t[t]] types); + tag fixup_result { + fix_ok(t); // fixup succeeded + fix_err(int); // fixup failed because a type variable was unresolved + } - fn mk_bindings[T](map::hashfn[T] hasher, map::eqfn[T] eqer) - -> @bindings[T] { - let vec[mutable option::t[t]] types = [mutable]; - ret @rec(sets=ufind::make(), - ids=map::mk_hashmap[T,uint](hasher, eqer), - mutable types=types); + type var_bindings = rec(ufind::ufind sets, + smallintmap::smallintmap[t] types); + + type ctxt = rec(@var_bindings vb, ty_ctxt tcx); + + fn mk_var_bindings() -> @var_bindings { + ret @rec(sets=ufind::make(), types=smallintmap::mk[t]()); } - fn record_binding[T](&@ctxt cx, &@bindings[T] bindings, &T key, t typ) - -> result { - auto n = get_or_create_set[T](bindings, key); + // Unifies two sets. + fn union(&@ctxt cx, uint set_a, uint set_b) -> union_result { + ufind::grow(cx.vb.sets, uint::max(set_a, set_b) + 1u); - auto result_type = typ; - if (n < vec::len[option::t[t]](bindings.types)) { - alt (bindings.types.(n)) { - case (some(?old_type)) { - alt (unify_step(cx, old_type, typ)) { - case (ures_ok(?unified_type)) { - result_type = unified_type; + auto root_a = ufind::find(cx.vb.sets, set_a); + auto root_b = ufind::find(cx.vb.sets, set_b); + ufind::union(cx.vb.sets, set_a, set_b); + auto root_c = ufind::find(cx.vb.sets, set_a); + + alt (smallintmap::find[t](cx.vb.types, root_a)) { + case (none[t]) { + alt (smallintmap::find[t](cx.vb.types, root_b)) { + case (none[t]) { ret unres_ok; } + case (some[t](?t_b)) { + smallintmap::insert[t](cx.vb.types, root_c, t_b); + ret unres_ok; + } + } + } + case (some[t](?t_a)) { + alt (smallintmap::find[t](cx.vb.types, root_b)) { + case (none[t]) { + smallintmap::insert[t](cx.vb.types, root_c, t_a); + ret unres_ok; + } + case (some[t](?t_b)) { + alt (unify_step(cx, t_a, t_b)) { + case (ures_ok(?t_c)) { + smallintmap::insert[t](cx.vb.types, root_c, + t_c); + ret unres_ok; + } + case (ures_err(?terr)) { ret unres_err(terr); } } - case (?res) { ret res; } } } - case (none) { /* fall through */ } } } + } - vec::grow_set[option::t[t]](bindings.types, n, none[t], - some[t](result_type)); + fn record_var_binding(&@ctxt cx, int key, t typ) -> result { + ufind::grow(cx.vb.sets, (key as uint) + 1u); + auto result_type = typ; + alt (smallintmap::find[t](cx.vb.types, key as uint)) { + case (some(?old_type)) { + alt (unify_step(cx, old_type, typ)) { + case (ures_ok(?unified_type)) { + result_type = unified_type; + } + case (?res) { ret res; } + } + } + case (none) { /* fall through */ } + } + + smallintmap::insert[t](cx.vb.types, key as uint, result_type); ret ures_ok(typ); } - type ctxt = rec(@bindings[int] bindings, - unify_handler handler, - ty_ctxt tcx); - // Wraps the given type in an appropriate cname. // // TODO: This doesn't do anything yet. We should carry the cname up from @@ -1993,7 +1900,7 @@ mod unify { ret ures_ok(expected); } - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } // Unifies two mutability flags. @@ -2025,8 +1932,7 @@ mod unify { auto expected_len = vec::len[arg](expected_inputs); auto actual_len = vec::len[arg](actual_inputs); if (expected_len != actual_len) { - ret fn_common_res_err(ures_err(terr_arg_count, - expected, actual)); + ret fn_common_res_err(ures_err(terr_arg_count)); } // TODO: as above, we should have an iter2 iterator. @@ -2036,16 +1942,11 @@ mod unify { auto expected_input = expected_inputs.(i); auto actual_input = actual_inputs.(i); - // Unify the result modes. "mo_either" unifies with both modes. + // Unify the result modes. auto result_mode; - if (expected_input.mode == mo_either) { - result_mode = actual_input.mode; - } else if (actual_input.mode == mo_either) { - result_mode = expected_input.mode; - } else if (expected_input.mode != actual_input.mode) { + if (expected_input.mode != actual_input.mode) { // FIXME this is the wrong error - ret fn_common_res_err(ures_err(terr_arg_count, - expected, actual)); + ret fn_common_res_err(ures_err(terr_arg_count)); } else { result_mode = expected_input.mode; } @@ -2089,7 +1990,7 @@ mod unify { -> result { if (e_proto != a_proto) { - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } alt (expected_cf) { case (ast::return) { } // ok @@ -2104,8 +2005,7 @@ mod unify { this check is necessary to ensure that the annotation in an object method matches the declared object type */ - ret ures_err(terr_controlflow_mismatch, - expected, actual); + ret ures_err(terr_controlflow_mismatch); } } } @@ -2133,9 +2033,7 @@ mod unify { &vec[arg] expected_inputs, &t expected_output, &vec[arg] actual_inputs, &t actual_output) -> result { - if (e_abi != a_abi) { - ret ures_err(terr_mismatch, expected, actual); - } + if (e_abi != a_abi) { ret ures_err(terr_mismatch); } auto t = unify_fn_common(cx, expected, actual, expected_inputs, expected_output, @@ -2162,16 +2060,13 @@ mod unify { let uint expected_len = vec::len[method](expected_meths); let uint actual_len = vec::len[method](actual_meths); - if (expected_len != actual_len) { - ret ures_err(terr_meth_count, expected, actual); - } + if (expected_len != actual_len) { ret ures_err(terr_meth_count); } while (i < expected_len) { auto e_meth = expected_meths.(i); auto a_meth = actual_meths.(i); if (! str::eq(e_meth.ident, a_meth.ident)) { - ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident), - expected, actual); + ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident)); } auto r = unify_fn(cx, e_meth.proto, a_meth.proto, @@ -2200,16 +2095,54 @@ mod unify { ret ures_ok(t); } - fn get_or_create_set[T](&@bindings[T] bindings, &T key) -> uint { - auto set_num; - alt (bindings.ids.find(key)) { - case (none) { - set_num = ufind::make_set(bindings.sets); - bindings.ids.insert(key, set_num); + // FIXME: This function should not be necessary, but it is for now until + // we eliminate pushdown. The typechecker should never rely on early + // resolution of type variables. + fn resolve_all_vars(&ty_ctxt tcx, &@var_bindings vb, t typ) -> t { + if (!type_contains_vars(tcx, typ)) { ret typ; } + + fn folder(ty_ctxt tcx, @var_bindings vb, t typ) -> t { + alt (struct(tcx, typ)) { + case (ty_var(?vid)) { + // It's possible that we haven't even created the var set. + // Handle this case gracefully. + if ((vid as uint) >= ufind::set_count(vb.sets)) { + ret typ; + } + + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (some[t](?typ2)) { + ret fold_ty(tcx, bind folder(tcx, vb, _), typ2); + } + case (none[t]) { ret typ; } + } + } + + case (_) { ret typ; } + } + } + + ret fold_ty(tcx, bind folder(tcx, vb, _), typ); + } + + // If the given type is a variable, returns the structure of that type. + fn resolve_type_structure(&ty_ctxt tcx, &@var_bindings vb, t typ) + -> fixup_result { + alt (struct(tcx, typ)) { + case (ty_var(?vid)) { + if ((vid as uint) >= ufind::set_count(vb.sets)) { + ret fix_err(vid); + } + + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { ret fix_err(vid); } + case (some[t](?rt)) { ret fix_ok(rt); } + } } - case (some(?n)) { set_num = n; } + case (_) { ret fix_ok(typ); } } - ret set_num; } fn unify_step(&@ctxt cx, &t expected, &t actual) -> result { @@ -2222,71 +2155,57 @@ mod unify { // Fast path. if (eq_ty(expected, actual)) { ret ures_ok(expected); } - alt (struct(cx.tcx, actual)) { + // Stage 1: Handle the cases in which one side or another is a type + // variable. - // a _|_ type can be used anywhere - case (ty::ty_bot) { - ret ures_ok(expected); - } - + alt (struct(cx.tcx, actual)) { // If the RHS is a variable type, then just do the appropriate // binding. case (ty::ty_var(?actual_id)) { - auto actual_n = get_or_create_set[int](cx.bindings, - actual_id); + auto actual_n = actual_id as uint; alt (struct(cx.tcx, expected)) { case (ty::ty_var(?expected_id)) { - auto expected_n = get_or_create_set[int](cx.bindings, - expected_id); - ufind::union(cx.bindings.sets, expected_n, actual_n); + auto expected_n = expected_id as uint; + union(cx, expected_n, actual_n); } - case (_) { // Just bind the type variable to the expected type. - alt (record_binding[int](cx, cx.bindings, actual_id, - expected)) { + alt (record_var_binding(cx, actual_id, expected)) { case (ures_ok(_)) { /* fall through */ } case (?res) { ret res; } } } } - ret ures_ok(actual); - } - case (ty::ty_local(?actual_id)) { - auto result_ty; - alt (cx.handler.resolve_local(actual_id)) { - case (none) { result_ty = expected; } - case (some(?actual_ty)) { - auto result = unify_step(cx, expected, actual_ty); - alt (result) { - case (ures_ok(?rty)) { result_ty = rty; } - case (_) { ret result; } - } - } - } - - cx.handler.record_local(actual_id, result_ty); - ret ures_ok(result_ty); + ret ures_ok(mk_var(cx.tcx, actual_id)); } - case (ty::ty_bound_param(?actual_id)) { - alt (struct(cx.tcx, expected)) { - case (ty::ty_local(_)) { - log_err "TODO: bound param unifying with local"; - fail; - } - case (_) { - ret cx.handler.record_param(actual_id, expected); - } + case (_) { /* empty */ } + } + + alt (struct(cx.tcx, expected)) { + case (ty::ty_var(?expected_id)) { + // Add a binding. (`actual` can't actually be a var here.) + alt (record_var_binding(cx, expected_id, actual)) { + case (ures_ok(_)) { /* fall through */ } + case (?res) { ret res; } } + ret ures_ok(mk_var(cx.tcx, expected_id)); } - case (_) { /* empty */ } + + case (_) { /* fall through */ } + } + + // Stage 2: Handle all other cases. + + alt (struct(cx.tcx, actual)) { + case (ty::ty_bot) { ret ures_ok(expected); } + case (_) { /* fall through */ } } alt (struct(cx.tcx, expected)) { case (ty::ty_nil) { ret struct_cmp(cx, expected, actual); } // _|_ unifies with anything - case (ty::ty_bot) { ret ures_ok(expected); } + case (ty::ty_bot) { ret ures_ok(actual); } case (ty::ty_bool) { ret struct_cmp(cx, expected, actual); } case (ty::ty_int) { ret struct_cmp(cx, expected, actual); } case (ty::ty_uint) { ret struct_cmp(cx, expected, actual); } @@ -2303,7 +2222,7 @@ mod unify { case (ty::ty_tag(?actual_id, ?actual_tps)) { if (expected_id._0 != actual_id._0 || expected_id._1 != actual_id._1) { - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } // TODO: factor this cruft out, see the TODO in the @@ -2336,7 +2255,7 @@ mod unify { case (_) { /* fall through */ } } - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } case (ty::ty_box(?expected_mt)) { @@ -2344,10 +2263,7 @@ mod unify { case (ty::ty_box(?actual_mt)) { auto mut; alt (unify_mut(expected_mt.mut, actual_mt.mut)) { - case (none) { - ret ures_err(terr_box_mutability, expected, - actual); - } + case (none) { ret ures_err(terr_box_mutability); } case (some(?m)) { mut = m; } } @@ -2365,9 +2281,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2376,10 +2290,7 @@ mod unify { case (ty::ty_vec(?actual_mt)) { auto mut; alt (unify_mut(expected_mt.mut, actual_mt.mut)) { - case (none) { - ret ures_err(terr_vec_mutability, expected, - actual); - } + case (none) { ret ures_err(terr_vec_mutability); } case (some(?m)) { mut = m; } } @@ -2397,9 +2308,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2419,9 +2328,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2441,9 +2348,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2455,7 +2360,7 @@ mod unify { if (expected_len != actual_len) { auto err = terr_tuple_size(expected_len, actual_len); - ret ures_err(err, expected, actual); + ret ures_err(err); } // TODO: implement an iterator that can iterate over @@ -2471,7 +2376,7 @@ mod unify { actual_elem.mut)) { case (none) { auto err = terr_tuple_mutability; - ret ures_err(err, expected, actual); + ret ures_err(err); } case (some(?m)) { mut = m; } } @@ -2495,9 +2400,7 @@ mod unify { ret ures_ok(mk_tup(cx.tcx, result_elems)); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2509,7 +2412,7 @@ mod unify { if (expected_len != actual_len) { auto err = terr_record_size(expected_len, actual_len); - ret ures_err(err, expected, actual); + ret ures_err(err); } // TODO: implement an iterator that can iterate over @@ -2524,8 +2427,7 @@ mod unify { alt (unify_mut(expected_field.mt.mut, actual_field.mt.mut)) { case (none) { - ret ures_err(terr_record_mutability, - expected, actual); + ret ures_err(terr_record_mutability); } case (some(?m)) { mut = m; } } @@ -2535,7 +2437,7 @@ mod unify { auto err = terr_record_fields(expected_field.ident, actual_field.ident); - ret ures_err(err, expected, actual); + ret ures_err(err); } auto result = unify_step(cx, @@ -2559,9 +2461,7 @@ mod unify { ret ures_ok(mk_rec(cx.tcx, result_fields)); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2577,9 +2477,7 @@ mod unify { expected_cf, actual_cf); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2593,9 +2491,7 @@ mod unify { expected_inputs, expected_output, actual_inputs, actual_output); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2605,153 +2501,89 @@ mod unify { ret unify_obj(cx, expected, actual, expected_meths, actual_meths); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } + } + } - case (ty::ty_var(?expected_id)) { - // Add a binding. (`actual` can't actually be a var here.) - alt (record_binding[int](cx, cx.bindings, expected_id, - actual)) { - case (ures_ok(_)) { /* fall through */ } - case (?res) { ret res; } - } - ret ures_ok(expected); - } + fn unify(&t expected, + &t actual, + &@var_bindings vb, + &ty_ctxt tcx) -> result { + auto cx = @rec(vb=vb, tcx=tcx); + ret unify_step(cx, expected, actual); + } - case (ty::ty_local(?expected_id)) { - auto result_ty; - alt (cx.handler.resolve_local(expected_id)) { - case (none) { result_ty = actual; } - case (some(?expected_ty)) { - auto result = unify_step(cx, expected_ty, actual); - alt (result) { - case (ures_ok(?rty)) { result_ty = rty; } - case (_) { ret result; } - } - } + fn dump_var_bindings(ty_ctxt tcx, @var_bindings vb) { + auto i = 0u; + while (i < vec::len[ufind::node](vb.sets.nodes)) { + auto sets = ""; + auto j = 0u; + while (j < vec::len[option::t[uint]](vb.sets.nodes)) { + if (ufind::find(vb.sets, j) == i) { sets += #fmt(" %u", j); } + j += 1u; + } + + auto typespec; + alt (smallintmap::find[t](vb.types, i)) { + case (none[t]) { typespec = ""; } + case (some[t](?typ)) { + typespec = " =" + ty_to_str(tcx, typ); } - - cx.handler.record_local(expected_id, result_ty); - ret ures_ok(result_ty); } - case (ty::ty_bound_param(?expected_id)) { - ret cx.handler.record_param(expected_id, actual); - } + log_err #fmt("set %u:%s%s", i, typespec, sets); + i += 1u; } - - // TODO: remove me once match-exhaustiveness checking works - fail; } - // Performs type binding substitution. - fn substitute(&ty_ctxt tcx, - &@bindings[int] bindings, - &vec[t] set_types, - &t typ) -> t { - if (!type_contains_vars(tcx, typ)) { - ret typ; - } + // Fixups and substitutions - fn substituter(ty_ctxt tcx, - @bindings[int] bindings, - vec[t] types, - t typ) -> t { + fn fixup_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> fixup_result { + fn subst_vars(ty_ctxt tcx, @var_bindings vb, + @mutable option::t[int] unresolved, t typ) -> t { alt (struct(tcx, typ)) { - case (ty_var(?id)) { - alt (bindings.ids.find(id)) { - case (some(?n)) { - auto root = ufind::find(bindings.sets, n); - ret types.(root); - } - case (none) { ret typ; } + case (ty::ty_var(?vid)) { + if ((vid as uint) >= ufind::set_count(vb.sets)) { + *unresolved = some[int](vid); + ret typ; } - } - case (_) { ret typ; } - } - } - - auto f = bind substituter(tcx, bindings, set_types, _); - ret fold_ty(tcx, f, typ); - } - fn unify_sets[T](&ty_ctxt tcx, &@bindings[T] bindings) -> set_result { - obj handler() { - fn resolve_local(ast::def_id id) -> option::t[t] { - log_err "resolve_local in unify_sets"; - fail; - } - fn record_local(ast::def_id id, t ty) { - log_err "record_local in unify_sets"; - fail; - } - fn record_param(uint index, t binding) -> unify::result { - log_err "record_param in unify_sets"; - fail; - } - } - - auto node_count = vec::len[option::t[t]](bindings.types); - - let vec[option::t[t]] results = - vec::init_elt[option::t[t]](none[t], node_count); - - auto i = 0u; - while (i < node_count) { - auto root = ufind::find(bindings.sets, i); - alt (bindings.types.(i)) { - case (none) { /* nothing to do */ } - case (some(?actual)) { - alt (results.(root)) { - case (none) { results.(root) = some[t](actual); } - case (some(?expected)) { - // FIXME: Is this right? - auto bindings = mk_bindings[int](int::hash, - int::eq_alias); - alt (unify(expected, actual, handler(), bindings, - tcx)) { - case (ures_ok(?result_ty)) { - results.(i) = some[t](result_ty); - } - case (ures_err(?e, ?t_a, ?t_b)) { - ret usr_err(e, t_a, t_b); - } - } + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { + *unresolved = some[int](vid); + ret typ; + } + case (some[t](?rt)) { + ret fold_ty(tcx, + bind subst_vars(tcx, vb, unresolved, _), rt); } } } + case (_) { ret typ; } } - i += 1u; } - // FIXME: This is equivalent to map(option::get, results) but it - // causes an assertion in typeck at the moment. - let vec[t] real_results = []; - for (option::t[t] typ in results) { - real_results += [option::get[t](typ)]; - } + auto unresolved = @mutable none[int]; + auto rty = fold_ty(tcx, bind subst_vars(tcx, vb, unresolved, _), typ); - ret usr_ok(real_results); + auto ur = *unresolved; + alt (ur) { + case (none[int]) { ret fix_ok(rty); } + case (some[int](?var_id)) { ret fix_err(var_id); } + } } - fn unify(&t expected, - &t actual, - &unify_handler handler, - &@bindings[int] bindings, - &ty_ctxt tcx) -> result { - auto cx = @rec(bindings=bindings, handler=handler, tcx=tcx); - ret unify_step(cx, expected, actual); - } + fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) + -> fixup_result { + if ((vid as uint) >= ufind::set_count(vb.sets)) { ret fix_err(vid); } - fn fixup(&ty_ctxt tcx, &@bindings[int] bindings, t typ) -> result { - alt (unify_sets[int](tcx, bindings)) { - case (usr_ok(?set_types)) { - ret ures_ok(substitute(tcx, bindings, set_types, typ)); - } - case (usr_err(?terr, ?t0, ?t1)) { ret ures_err(terr, t0, t1); } + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { ret fix_err(vid); } + case (some[t](?rt)) { ret fixup_vars(tcx, vb, rt); } } } } @@ -2806,47 +2638,46 @@ fn type_err_to_str(&ty::type_err err) -> str { } } -// Performs bound type parameter replacement using the supplied mapping from -// parameter IDs to types. -fn substitute_type_params(&ctxt cx, &vec[t] bindings, &t typ) -> t { - if (!type_contains_bound_params(cx, typ)) { - ret typ; +// Converts type parameters in a type to type variables and returns the +// resulting type along with a list of type variable IDs. +fn bind_params_in_type(&ctxt cx, fn()->int next_ty_var, t typ, + uint ty_param_count) + -> tup(vec[int], t) { + let vec[int] param_var_ids = []; + auto i = 0u; + while (i < ty_param_count) { + param_var_ids += [next_ty_var()]; + i += 1u; } - fn replacer(&ctxt cx, vec[t] bindings, t typ) -> t { + + fn binder(ctxt cx, vec[int] param_var_ids, fn()->int next_ty_var, t typ) + -> t { alt (struct(cx, typ)) { - case (ty_bound_param(?param_index)) { - ret bindings.(param_index); - } + case (ty_param(?index)) { ret mk_var(cx, param_var_ids.(index)); } case (_) { ret typ; } } } - auto f = bind replacer(cx, bindings, _); - ret fold_ty(cx, f, typ); + auto f = bind binder(cx, param_var_ids, next_ty_var, _); + auto new_typ = fold_ty(cx, f, typ); + ret tup(param_var_ids, new_typ); } -// Converts type parameters in a type to bound type parameters. -fn bind_params_in_type(&ctxt cx, &t typ) -> t { - if (!type_contains_params(cx, typ)) { - ret typ; - } - fn binder(&ctxt cx, t typ) -> t { +// Replaces type parameters in the given type using the given list of +// substitions. +fn substitute_type_params(&ctxt cx, vec[ty::t] substs, t typ) -> t { + if (!type_contains_params(cx, typ)) { ret typ; } + + fn substituter(ctxt cx, vec[ty::t] substs, t typ) -> t { alt (struct(cx, typ)) { - case (ty_bound_param(?index)) { - log_err "bind_params_in_type() called on type that already " + - "has bound params in it"; - fail; - } - case (ty_param(?index)) { ret mk_bound_param(cx, index); } + case (ty_param(?idx)) { ret substs.(idx); } case (_) { ret typ; } } } - auto f = bind binder(cx, _); - ret fold_ty(cx, f, typ); + ret fold_ty(cx, bind substituter(cx, substs, _), typ); } - fn def_has_ty_params(&ast::def def) -> bool { alt (def) { case (ast::def_fn(_)) { ret true; } @@ -2901,7 +2732,6 @@ fn tag_variants(&ctxt cx, &ast::def_id id) -> vec[variant_info] { } } } - fail; // not reached } // Returns information about the tag variant with the given ID: @@ -2918,9 +2748,9 @@ fn tag_variant_with_id(&ctxt cx, } i += 1u; } + + cx.sess.bug("tag_variant_with_id(): no variant exists with that ID"); - log_err "tag_variant_with_id(): no variant exists with that ID"; - fail; } // If the given item is in an external crate, looks up its type and adds it to @@ -2942,19 +2772,19 @@ fn lookup_item_type(ctxt cx, ast::def_id did) -> ty_param_count_and_ty { } } -fn ret_ty_of_fn_ty(ty_ctxt tcx, t a_ty) -> t { - alt (ty::struct(tcx, a_ty)) { +fn ret_ty_of_fn_ty(ctxt cx, t a_ty) -> t { + alt (ty::struct(cx, a_ty)) { case (ty::ty_fn(_, _, ?ret_ty, _)) { ret ret_ty; } case (_) { - fail; + cx.sess.bug("ret_ty_of_fn_ty() called on non-function type"); } } } -fn ret_ty_of_fn(ty_ctxt tcx, ast::ann ann) -> t { - ret ret_ty_of_fn_ty(tcx, ann_to_type(tcx.node_types, ann)); +fn ret_ty_of_fn(ctxt cx, ast::ann ann) -> t { + ret ret_ty_of_fn_ty(cx, ann_to_type(cx, ann)); } // Local Variables: diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index d3786d8aad44f..a76a377eae844 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -18,11 +18,9 @@ import middle::ty::field; import middle::ty::method; import middle::ty::mo_val; import middle::ty::mo_alias; -import middle::ty::mo_either; import middle::ty::node_type_table; import middle::ty::pat_ty; import middle::ty::path_to_str; -import middle::ty::struct; import middle::ty::ty_param_substs_opt_and_ty; import middle::ty::ty_to_str; import middle::ty::type_is_integral; @@ -31,9 +29,13 @@ import middle::ty::ty_param_count_and_ty; import middle::ty::ty_nil; import middle::ty::unify::ures_ok; import middle::ty::unify::ures_err; +import middle::ty::unify::fixup_result; +import middle::ty::unify::fix_ok; +import middle::ty::unify::fix_err; import std::int; import std::str; +import std::ufind; import std::uint; import std::vec; import std::map; @@ -48,91 +50,49 @@ import middle::tstate::ann::ts_ann; type ty_table = hashmap[ast::def_id, ty::t]; type fn_purity_table = hashmap[ast::def_id, ast::purity]; -type unify_cache_entry = tup(ty::t,ty::t,vec[mutable ty::t]); -type unify_cache = hashmap[unify_cache_entry,ty::unify::result]; - type obj_info = rec(vec[ast::obj_field] obj_fields, ast::def_id this_obj); type crate_ctxt = rec(mutable vec[obj_info] obj_infos, @fn_purity_table fn_purity_table, - unify_cache unify_cache, - mutable uint cache_hits, - mutable uint cache_misses, ty::ctxt tcx); type fn_ctxt = rec(ty::t ret_ty, ast::purity purity, - @ty_table locals, + @ty::unify::var_bindings var_bindings, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + mutable int next_var_id, + mutable vec[uint] fixups, @crate_ctxt ccx); -type stmt_ctxt = rec(@fn_ctxt fcx, - mutable int next_var_id, - mutable vec[uint] fixups); - // Used for ast_ty_to_ty() below. type ty_getter = fn(&ast::def_id) -> ty::ty_param_count_and_ty; -// Creates a statement context and passes it to the given thunk, then runs -// fixups. This function has the signature it does so that the caller can -// never forget to run fixups! -fn with_stmt_ctxt(&@fn_ctxt fcx, fn(&@stmt_ctxt) f) { - let vec[uint] fixups = []; - auto scx = @rec(fcx=fcx, mutable next_var_id=0, mutable fixups=fixups); - f(scx); - // TODO: run fixups -} - -// Substitutes the user's explicit types for the parameters in a path -// expression. -fn substitute_ty_params(&@crate_ctxt ccx, - &ty::t typ, - uint ty_param_count, - &vec[ty::t] supplied, - &span sp) -> ty::t { - fn substituter(@crate_ctxt ccx, vec[ty::t] supplied, ty::t typ) -> ty::t { - alt (struct(ccx.tcx, typ)) { - case (ty::ty_bound_param(?pid)) { ret supplied.(pid); } - case (_) { ret typ; } - } - } - - auto supplied_len = vec::len[ty::t](supplied); - if (ty_param_count != supplied_len) { - ccx.tcx.sess.span_err(sp, "expected " + - uint::to_str(ty_param_count, 10u) + - " type parameter(s) but found " + - uint::to_str(supplied_len, 10u) + " parameter(s)"); - fail; - } - - if (!ty::type_contains_bound_params(ccx.tcx, typ)) { - ret typ; - } - - auto f = bind substituter(ccx, supplied, _); - ret ty::fold_ty(ccx.tcx, f, typ); -} - // 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) -> ty_param_count_and_ty { alt (defn) { case (ast::def_arg(?id)) { - // assert (fcx.locals.contains_key(id)); - ret tup(0u, fcx.locals.get(id)); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_local(?id)) { - auto t; - alt (fcx.locals.find(id)) { - case (some(?t1)) { t = t1; } - case (none) { t = ty::mk_local(fcx.ccx.tcx, id); } - } - ret tup(0u, t); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_obj_field(?id)) { - // assert (fcx.locals.contains_key(id)); - ret tup(0u, fcx.locals.get(id)); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_fn(?id)) { ret ty::lookup_item_type(fcx.ccx.tcx, id); @@ -147,8 +107,11 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) ret ty::lookup_item_type(fcx.ccx.tcx, vid); } case (ast::def_binding(?id)) { - // assert (fcx.locals.contains_key(id)); - ret tup(0u, fcx.locals.get(id)); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_obj(?id)) { ret ty::lookup_item_type(fcx.ccx.tcx, id); @@ -162,25 +125,29 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) case (ast::def_ty(_)) { fcx.ccx.tcx.sess.span_err(sp, "expected value but found type"); - fail; } case (_) { // FIXME: handle other names. fcx.ccx.tcx.sess.unimpl("definition variant"); - fail; } } } // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. -fn instantiate_path(&@stmt_ctxt scx, +fn instantiate_path(&@fn_ctxt fcx, &ast::path pth, &ty_param_count_and_ty tpt, &span sp) -> ty_param_substs_opt_and_ty { auto ty_param_count = tpt._0; - auto t = bind_params_in_type(scx.fcx.ccx.tcx, tpt._1); + + auto bind_result = bind_params_in_type(fcx.ccx.tcx, + bind next_ty_var_id(fcx), + tpt._1, + ty_param_count); + auto ty_param_vars = bind_result._0; + auto t = bind_result._1; auto ty_substs_opt; auto ty_substs_len = vec::len[@ast::ty](pth.node.types); @@ -188,16 +155,20 @@ fn instantiate_path(&@stmt_ctxt scx, let vec[ty::t] ty_substs = []; auto i = 0u; while (i < ty_substs_len) { - ty_substs += [ast_ty_to_ty_crate(scx.fcx.ccx, - pth.node.types.(i))]; + // TODO: Report an error if the number of type params in the item + // and the supplied number of type params don't match. + auto ty_var = ty::mk_var(fcx.ccx.tcx, ty_param_vars.(i)); + auto ty_subst = ast_ty_to_ty_crate(fcx.ccx, + pth.node.types.(i)); + auto res_ty = demand::simple(fcx, pth.span, ty_var, ty_subst); + ty_substs += [res_ty]; i += 1u; } ty_substs_opt = some[vec[ty::t]](ty_substs); if (ty_param_count == 0u) { - scx.fcx.ccx.tcx.sess.span_err(sp, - "this item does not take type " + - "parameters"); + fcx.ccx.tcx.sess.span_err(sp, "this item does not take type " + + "parameters"); fail; } } else { @@ -205,13 +176,13 @@ fn instantiate_path(&@stmt_ctxt scx, let vec[ty::t] ty_substs = []; auto i = 0u; while (i < ty_param_count) { - ty_substs += [next_ty_var(scx)]; + ty_substs += [ty::mk_var(fcx.ccx.tcx, ty_param_vars.(i))]; i += 1u; } ty_substs_opt = some[vec[ty::t]](ty_substs); } - ret tup(ty_substs_opt, t); + ret tup(ty_substs_opt, tpt._1); } fn ast_mode_to_mode(ast::mode mode) -> ty::mode { @@ -223,16 +194,29 @@ fn ast_mode_to_mode(ast::mode mode) -> ty::mode { ret ty_mode; } +// Returns the one-level-deep structure of the given type. +fn structure_of(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::sty { + auto r = ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, + typ); + alt (r) { + case (fix_ok(?typ_s)) { ret ty::struct(fcx.ccx.tcx, typ_s); } + case (fix_err(_)) { + fcx.ccx.tcx.sess.span_err(sp, "the type of this value must be " + + "known in this context"); + } + } +} + // Parses the programmer's textual representation of a type into our internal // notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { fn ast_arg_to_arg(&ty::ctxt tcx, &ty_getter getter, - &rec(ast::mode mode, @ast::ty ty) arg) + &ast::ty_arg arg) -> rec(ty::mode mode, ty::t ty) { - auto ty_mode = ast_mode_to_mode(arg.mode); - ret rec(mode=ty_mode, ty=ast_ty_to_ty(tcx, getter, arg.ty)); + auto ty_mode = ast_mode_to_mode(arg.node.mode); + ret rec(mode=ty_mode, ty=ast_ty_to_ty(tcx, getter, arg.node.ty)); } fn ast_mt_to_mt(&ty::ctxt tcx, @@ -248,7 +232,6 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { // TODO: maybe record cname chains so we can do // "foo = int" like OCaml? auto params_opt_and_ty = getter(id); - if (params_opt_and_ty._0 == 0u) { ret params_opt_and_ty._1; } @@ -257,12 +240,14 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { // // TODO: Make sure the number of supplied bindings matches the number // of type parameters in the typedef. Emit a friendly error otherwise. - auto bound_ty = bind_params_in_type(tcx, params_opt_and_ty._1); let vec[ty::t] param_bindings = []; for (@ast::ty ast_ty in args) { param_bindings += [ast_ty_to_ty(tcx, getter, ast_ty)]; } - ret ty::substitute_type_params(tcx, param_bindings, bound_ty); + + auto typ = ty::substitute_type_params(tcx, param_bindings, + params_opt_and_ty._1); + ret typ; } auto mut = ast::imm; @@ -284,6 +269,9 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { case (ast::ty_vec(?mt)) { typ = ty::mk_vec(tcx, ast_mt_to_mt(tcx, getter, mt)); } + case (ast::ty_ptr(?mt)) { + typ = ty::mk_ptr(tcx, ast_mt_to_mt(tcx, getter, mt)); + } case (ast::ty_task) { typ = ty::mk_task(tcx); } case (ast::ty_port(?t)) { typ = ty::mk_port(tcx, ast_ty_to_ty(tcx, getter, t)); @@ -303,8 +291,8 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { case (ast::ty_rec(?fields)) { let vec[field] flds = []; for (ast::ty_field f in fields) { - auto tm = ast_mt_to_mt(tcx, getter, f.mt); - vec::push[field](flds, rec(ident=f.ident, mt=tm)); + auto tm = ast_mt_to_mt(tcx, getter, f.node.mt); + vec::push[field](flds, rec(ident=f.node.ident, mt=tm)); } typ = ty::mk_rec(tcx, flds); } @@ -329,7 +317,7 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { case (_) { tcx.sess.span_err(ast_ty.span, "found type name used as a variable"); - fail; } + } } cname = some(path_to_str(path)); @@ -339,14 +327,14 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { let vec[ty::method] tmeths = []; auto f = bind ast_arg_to_arg(tcx, getter, _); for (ast::ty_method m in meths) { - auto ins = vec::map[ast::ty_arg, arg](f, m.inputs); - auto out = ast_ty_to_ty(tcx, getter, m.output); + auto ins = vec::map[ast::ty_arg, arg](f, m.node.inputs); + auto out = ast_ty_to_ty(tcx, getter, m.node.output); let ty::method new_m = - rec(proto=m.proto, - ident=m.ident, + rec(proto=m.node.proto, + ident=m.node.ident, inputs=ins, output=out, - cf=m.cf); + cf=m.node.cf); vec::push[ty::method](tmeths, new_m); } @@ -379,11 +367,13 @@ fn ast_ty_to_ty_crate(@crate_ctxt ccx, &@ast::ty ast_ty) -> ty::t { mod write { fn inner(&node_type_table ntt, uint node_id, &ty_param_substs_opt_and_ty tpot) { + auto ntt_ = *ntt; vec::grow_set[option::t[ty::ty_param_substs_opt_and_ty]] - (*ntt, + (ntt_, node_id, none[ty_param_substs_opt_and_ty], some[ty_param_substs_opt_and_ty](tpot)); + *ntt = ntt_; } // Writes a type parameter count and type pair into the node type table. @@ -396,11 +386,11 @@ mod write { // Writes a type parameter count and type pair into the node type table. // This function allows for the possibility of type variables, which will // be rewritten later during the fixup phase. - fn ty_fixup(&@stmt_ctxt scx, uint node_id, + fn ty_fixup(@fn_ctxt fcx, uint node_id, &ty_param_substs_opt_and_ty tpot) { - inner(scx.fcx.ccx.tcx.node_types, node_id, tpot); - if (ty::type_contains_vars(scx.fcx.ccx.tcx, tpot._1)) { - scx.fixups += [node_id]; + inner(fcx.ccx.tcx.node_types, node_id, tpot); + if (ty::type_contains_vars(fcx.ccx.tcx, tpot._1)) { + fcx.fixups += [node_id]; } } @@ -411,8 +401,8 @@ mod write { // Writes a type with no type parameters into the node type table. This // function allows for the possibility of type variables. - fn ty_only_fixup(&@stmt_ctxt scx, uint node_id, ty::t typ) { - be ty_fixup(scx, node_id, tup(none[vec[ty::t]], typ)); + fn ty_only_fixup(@fn_ctxt fcx, uint node_id, ty::t typ) { + be ty_fixup(fcx, node_id, tup(none[vec[ty::t]], typ)); } // Writes a nil type into the node type table. @@ -792,7 +782,7 @@ mod collect { // type of the native item. We simply write it into the node type // table. auto tpt = ty_of_native_item(cx, i, - option::get[ast::native_abi](*abi)); + option::get[ast::native_abi]({*abi})); alt (i.node) { case (ast::native_item_ty(_,_)) { @@ -832,106 +822,11 @@ mod collect { // Type unification +// TODO: rename to just "unify" mod unify { - fn simple(&@stmt_ctxt scx, &ty::t expected, &ty::t actual) + fn simple(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> ty::unify::result { - // FIXME: horrid botch - let vec[mutable ty::t] param_substs = - [mutable ty::mk_nil(scx.fcx.ccx.tcx)]; - vec::pop(param_substs); - ret with_params(scx, expected, actual, param_substs); - } - - fn with_params(&@stmt_ctxt scx, - &ty::t expected, - &ty::t actual, - &vec[mutable ty::t] param_substs) -> ty::unify::result { - auto cache_key = tup(expected, actual, param_substs); - alt (scx.fcx.ccx.unify_cache.find(cache_key)) { - case (some(?r)) { - scx.fcx.ccx.cache_hits += 1u; - ret r; - } - case (none) { - scx.fcx.ccx.cache_misses += 1u; - } - } - - obj unify_handler(@stmt_ctxt scx, vec[mutable ty::t] param_substs) { - fn resolve_local(ast::def_id id) -> option::t[ty::t] { - alt (scx.fcx.locals.find(id)) { - case (none) { ret none[ty::t]; } - case (some(?existing_type)) { - if (ty::type_contains_vars(scx.fcx.ccx.tcx, - existing_type)) { - // Not fully resolved yet. The writeback phase - // will mop up. - ret none[ty::t]; - } - ret some[ty::t](existing_type); - } - } - } - fn record_local(ast::def_id id, ty::t new_type) { - auto unified_type; - alt (scx.fcx.locals.find(id)) { - case (none) { unified_type = new_type; } - case (some(?old_type)) { - alt (with_params(scx, old_type, new_type, - param_substs)) { - case (ures_ok(?ut)) { unified_type = ut; } - case (_) { fail; /* FIXME */ } - } - } - } - - // TODO: "freeze" - let vec[ty::t] param_substs_1 = []; - for (ty::t subst in param_substs) { - param_substs_1 += [subst]; - } - - unified_type = ty::substitute_type_params(scx.fcx.ccx.tcx, - param_substs_1, - unified_type); - scx.fcx.locals.insert(id, unified_type); - } - fn record_param(uint index, ty::t binding) -> ty::unify::result { - // Unify with the appropriate type in the parameter - // substitution list: - auto old_subst = param_substs.(index); - - auto result = with_params(scx, old_subst, binding, - param_substs); - alt (result) { - case (ures_ok(?new_subst)) { - param_substs.(index) = new_subst; - ret ures_ok(ty::mk_bound_param(scx.fcx.ccx.tcx, - index)); - } - case (_) { ret result; } - } - } - } - - - auto handler = unify_handler(scx, param_substs); - - auto bindings = ty::unify::mk_bindings[int](int::hash, int::eq_alias); - auto result = ty::unify::unify(expected, actual, handler, bindings, - scx.fcx.ccx.tcx); - - alt (result) { - case (ures_ok(?rty)) { - if (ty::type_contains_vars(scx.fcx.ccx.tcx, rty)) { - result = ty::unify::fixup(scx.fcx.ccx.tcx, bindings, rty); - } - } - case (_) { /* nothing */ } - } - - scx.fcx.ccx.unify_cache.insert(cache_key, result); - ret result; + ret ty::unify::unify(expected, actual, fcx.var_bindings, fcx.ccx.tcx); } } @@ -941,10 +836,10 @@ tag autoderef_kind { NO_AUTODEREF; } -fn strip_boxes(&ty::ctxt tcx, &ty::t t) -> ty::t { +fn strip_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> ty::t { auto t1 = t; while (true) { - alt (struct(tcx, t1)) { + alt (structure_of(fcx, sp, t1)) { case (ty::ty_box(?inner)) { t1 = inner.ty; } case (_) { ret t1; } } @@ -962,11 +857,11 @@ fn add_boxes(&@crate_ctxt ccx, uint n, &ty::t t) -> ty::t { } -fn count_boxes(&ty::ctxt tcx, &ty::t t) -> uint { +fn count_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> uint { auto n = 0u; auto t1 = t; while (true) { - alt (struct(tcx, t1)) { + alt (structure_of(fcx, sp, t1)) { case (ty::ty_box(?inner)) { n += 1u; t1 = inner.ty; } case (_) { ret n; } } @@ -981,22 +876,22 @@ fn count_boxes(&ty::ctxt tcx, &ty::t t) -> uint { type ty_param_substs_and_ty = tup(vec[ty::t], ty::t); mod demand { - fn simple(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual) + fn simple(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual) -> ty::t { let vec[ty::t] tps = []; - ret full(scx, sp, expected, actual, tps, NO_AUTODEREF)._1; + ret full(fcx, sp, expected, actual, tps, NO_AUTODEREF)._1; } - fn autoderef(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual, + fn autoderef(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual, autoderef_kind adk) -> ty::t { let vec[ty::t] tps = []; - ret full(scx, sp, expected, actual, tps, adk)._1; + ret full(fcx, sp, expected, actual, tps, adk)._1; } // Requires that the two types unify, and prints an error message if they // don't. Returns the unified type and the type parameter substitutions. - fn full(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual, + fn full(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual, &vec[ty::t] ty_param_substs_0, autoderef_kind adk) -> ty_param_substs_and_ty { @@ -1005,40 +900,45 @@ mod demand { auto implicit_boxes = 0u; if (adk == AUTODEREF_OK) { - expected_1 = strip_boxes(scx.fcx.ccx.tcx, expected_1); - actual_1 = strip_boxes(scx.fcx.ccx.tcx, actual_1); - implicit_boxes = count_boxes(scx.fcx.ccx.tcx, actual); + expected_1 = strip_boxes(fcx, sp, expected_1); + actual_1 = strip_boxes(fcx, sp, actual_1); + implicit_boxes = count_boxes(fcx, sp, actual); } - let vec[mutable ty::t] ty_param_substs = - [mutable ty::mk_nil(scx.fcx.ccx.tcx)]; - vec::pop(ty_param_substs); // FIXME: horrid botch + let vec[mutable ty::t] ty_param_substs = [mutable]; + let vec[int] ty_param_subst_var_ids = []; for (ty::t ty_param_subst in ty_param_substs_0) { - ty_param_substs += [mutable ty_param_subst]; + // Generate a type variable and unify it with the type parameter + // substitution. We will then pull out these type variables. + auto t_0 = next_ty_var(fcx); + ty_param_substs += [mutable t_0]; + ty_param_subst_var_ids += [ty::ty_var_id(fcx.ccx.tcx, t_0)]; + + simple(fcx, sp, ty_param_subst, t_0); } - alt (unify::with_params(scx, expected_1, actual_1, ty_param_substs)) { + alt (unify::simple(fcx, expected_1, actual_1)) { case (ures_ok(?t)) { - // TODO: Use "freeze", when we have it. let vec[ty::t] result_ty_param_substs = []; - for (ty::t ty_param_subst in ty_param_substs) { - result_ty_param_substs += [ty_param_subst]; + for (int var_id in ty_param_subst_var_ids) { + auto tp_subst = ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, ty::mk_var(fcx.ccx.tcx, var_id)); + result_ty_param_substs += [tp_subst]; } ret tup(result_ty_param_substs, - add_boxes(scx.fcx.ccx, implicit_boxes, t)); + add_boxes(fcx.ccx, implicit_boxes, t)); } - case (ures_err(?err, ?expected, ?actual)) { - scx.fcx.ccx.tcx.sess.span_err + case (ures_err(?err)) { + fcx.ccx.tcx.sess.span_err (sp, "mismatched types: expected " - + ty_to_str(scx.fcx.ccx.tcx, expected) + " but found " - + ty_to_str(scx.fcx.ccx.tcx, actual) + " (" + + ty_to_str(fcx.ccx.tcx, expected_1) + " but found " + + ty_to_str(fcx.ccx.tcx, actual_1) + " (" + ty::type_err_to_str(err) + ")"); // TODO: In the future, try returning "expected", reporting // the error, and continue. - fail; } } } @@ -1046,10 +946,10 @@ mod demand { // Returns true if the two types unify and false if they don't. -fn are_compatible(&@stmt_ctxt scx, &ty::t expected, &ty::t actual) -> bool { - alt (unify::simple(scx, expected, actual)) { - case (ures_ok(_)) { ret true; } - case (ures_err(_, _, _)) { ret false; } +fn are_compatible(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> bool { + alt (unify::simple(fcx, expected, actual)) { + case (ures_ok(_)) { ret true; } + case (ures_err(_)) { ret false; } } } @@ -1061,13 +961,12 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, let vec[ty::t] result = []; auto tpt = ty::lookup_item_type(ccx.tcx, vid); - alt (struct(ccx.tcx, tpt._1)) { + alt (ty::struct(ccx.tcx, tpt._1)) { case (ty::ty_fn(_, ?ins, _, _)) { // N-ary variant. for (ty::arg arg in ins) { - auto arg_ty = bind_params_in_type(ccx.tcx, arg.ty); - arg_ty = substitute_ty_params(ccx, arg_ty, ty_param_count, - tag_ty_params, sp); + auto arg_ty = ty::substitute_type_params(ccx.tcx, + tag_ty_params, arg.ty); result += [arg_ty]; } } @@ -1081,540 +980,84 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, } -// The "push-down" phase, which takes a typed grammar production and pushes -// its type down into its constituent parts. -// -// For example, consider "auto x; x = 352;". check_expr() doesn't know the -// type of "x" at the time it sees it, so that function will simply store a -// type variable for the type of "x". However, after checking the entire -// assignment expression, check_expr() will assign the type of int to the -// expression "x = 352" as a whole. In this case, then, the job of these -// functions is to clean up by assigning the type of int to both sides of the -// assignment expression. +// Type resolution: the phase that finds all the types in the AST with +// unresolved type variables and replaces "ty_var" types with their +// substitutions. // -// TODO: We only need to do this once per statement: check_expr() bubbles the -// types up, and pushdown_expr() pushes the types down. However, in many cases -// we're more eager than we need to be, calling pushdown_expr() and friends -// directly inside check_expr(). This results in a quadratic algorithm. - -mod pushdown { - // Push-down over typed patterns. Note that the pattern that you pass to - // this function must have been passed to check_pat() first. - // - // TODO: enforce this via a predicate. - - fn pushdown_pat(&@stmt_ctxt scx, &ty::t expected, &@ast::pat pat) { - alt (pat.node) { - case (ast::pat_wild(?ann)) { - auto t = demand::simple(scx, pat.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::pat_lit(?lit, ?ann)) { - auto t = demand::simple(scx, pat.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::pat_bind(?id, ?did, ?ann)) { - auto t = demand::simple(scx, pat.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - scx.fcx.locals.insert(did, t); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::pat_tag(?id, ?subpats, ?ann)) { - // Take the variant's type parameters out of the expected - // type. - auto tag_tps; - alt (struct(scx.fcx.ccx.tcx, expected)) { - case (ty::ty_tag(_, ?tps)) { tag_tps = tps; } - case (_) { - scx.fcx.ccx.tcx.sess.span_err(pat.span, - "Non-constructor used in a pattern"); - } - } +// TODO: inefficient since not all types have vars in them. It would be better +// to maintain a list of fixups. - // Get the types of the arguments of the variant. - - let vec[ty::t] tparams = []; - auto j = 0u; - auto actual_ty_params = - ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann); - - for (ty::t some_ty in tag_tps) { - let ty::t t1 = some_ty; - let ty::t t2 = actual_ty_params.(j); - - let ty::t res = demand::simple(scx, pat.span, t1, t2); - - vec::push(tparams, res); - j += 1u; - } - - auto arg_tys; - alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) { - case (ast::def_variant(_, ?vdefid)) { - arg_tys = variant_arg_types(scx.fcx.ccx, pat.span, - vdefid, tparams); - } - } - - auto i = 0u; - for (@ast::pat subpat in subpats) { - pushdown_pat(scx, arg_tys.(i), subpat); - i += 1u; - } - - auto tps = - ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann); - auto tt = ann_to_type(scx.fcx.ccx.tcx.node_types, ann); - - let ty_param_substs_and_ty res_t = demand::full(scx, pat.span, - expected, tt, tps, NO_AUTODEREF); - - auto ty_params_subst = ty::ann_to_ty_param_substs_opt_and_ty - (scx.fcx.ccx.tcx.node_types, ann); - - auto ty_params_opt; - alt (ty_params_subst._0) { - case (none) { - ty_params_opt = none[vec[ty::t]]; - } - case (some(?tps)) { - ty_params_opt = some[vec[ty::t]](tag_tps); - } - } +mod writeback { + fn resolve_type_vars_in_type(&@fn_ctxt fcx, &span sp, ty::t typ) + -> ty::t { + if (!ty::type_contains_vars(fcx.ccx.tcx, typ)) { ret typ; } - write::ty_fixup(scx, ann.id, tup(ty_params_opt, tt)); + alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) { + case (fix_ok(?new_type)) { ret new_type; } + case (fix_err(?vid)) { + fcx.ccx.tcx.sess.span_err(sp, + "cannot determine a type for this expression"); } } } - // Push-down over typed expressions. Note that the expression that you - // pass to this function must have been passed to check_expr() first. - // - // TODO: enforce this via a predicate. - // TODO: This function is incomplete. + fn resolve_type_vars_for_node(&@fn_ctxt fcx, &span sp, &ast::ann ann) { + auto tpot = ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, ann); + auto new_ty = resolve_type_vars_in_type(fcx, sp, tpot._1); - fn pushdown_expr(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e) { - be pushdown_expr_full(scx, expected, e, NO_AUTODEREF); - } - - fn pushdown_expr_full(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e, - autoderef_kind adk) { - alt (e.node) { - case (ast::expr_vec(?es_0, ?mut, ?ann)) { - // TODO: enforce mutability - - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { - case (ty::ty_vec(?mt)) { - for (@ast::expr e_0 in es_0) { - pushdown_expr(scx, mt.ty, e_0); - } - } - case (_) { - log_err "vec expr doesn't have a vec type!"; - fail; - } - } - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_tup(?es_0, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { - case (ty::ty_tup(?mts)) { - auto i = 0u; - for (ast::elt elt_0 in es_0) { - pushdown_expr(scx, mts.(i).ty, elt_0.expr); - i += 1u; - } - } - case (_) { - log_err "tup expr doesn't have a tup type!"; - fail; - } + auto new_substs_opt; + alt (tpot._0) { + case (none[vec[ty::t]]) { new_substs_opt = none[vec[ty::t]]; } + case (some[vec[ty::t]](?substs)) { + let vec[ty::t] new_substs = []; + for (ty::t subst in substs) { + new_substs += [resolve_type_vars_in_type(fcx, sp, subst)]; } - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_rec(?fields_0, ?base_0, ?ann)) { - - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { - case (ty::ty_rec(?field_mts)) { - alt (base_0) { - case (none) { - auto i = 0u; - for (ast::field field_0 in fields_0) { - assert (str::eq(field_0.node.ident, - field_mts.(i).ident)); - pushdown_expr(scx, - field_mts.(i).mt.ty, - field_0.node.expr); - i += 1u; - } - } - case (some(?bx)) { - - let vec[field] base_fields = []; - - for (ast::field field_0 in fields_0) { - - for (ty::field ft in field_mts) { - if (str::eq(field_0.node.ident, - ft.ident)) { - pushdown_expr(scx, ft.mt.ty, - field_0.node.expr); - } - } - } - } - } - } - case (_) { - log_err "rec expr doesn't have a rec type!"; - fail; - } - } - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_bind(?sube, ?es, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_call(?sube, ?es, ?ann)) { - // NB: we call 'demand::autoderef' and pass in adk only in - // cases where e is an expression that could *possibly* - // produce a box; things like expr_binary or expr_bind can't, - // so there's no need. - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_self_method(?id, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_binary(?bop, ?lhs, ?rhs, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_unary(?uop, ?sube, ?ann)) { - // See note in expr_unary for why we're calling - // demand::autoderef. - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - - /* The following is a bit special-cased, but takes care of - the case where we say let @vec[whatever] v = @[]; */ - auto inner_ty = t; - alt (uop) { - case (ast::box(?mut)) { - alt (struct(scx.fcx.ccx.tcx, t)) { - case (ty::ty_box(?inner)) { inner_ty = inner.ty; } - case (_) { - scx.fcx.ccx.tcx.sess.span_err(e.span, - "Expecting an application of box" - + " to have a box type"); - } - } - } - case (ast::deref) { - inner_ty = ty::mk_box(scx.fcx.ccx.tcx, - // maybe_mut should work because it'll unify with - // the existing type? - rec(ty=t, mut=ast::maybe_mut)); - } - case (_) { inner_ty = strip_boxes(scx.fcx.ccx.tcx, t); } - } - - pushdown_expr(scx, inner_ty, sube); - } - case (ast::expr_lit(?lit, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_cast(?sube, ?ast_ty, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_if(?cond, ?then_0, ?else_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - - auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0); - pushdown_block(scx, expected, then_0); - - alt (else_0) { - case (none) { /* no-op */ } - case (some(?e_0)) { - auto else_t = ty::expr_ty(scx.fcx.ccx.tcx, e_0); - pushdown_expr(scx, expected, e_0); - } - } - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_for(?decl, ?seq, ?bloc, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_for_each(?decl, ?seq, ?bloc, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_while(?cond, ?bloc, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_do_while(?bloc, ?cond, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_block(?bloc, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - pushdown_block(scx, t, bloc); - } - case (ast::expr_move(?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_assign(?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_field(?lhs, ?rhs, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_index(?base, ?index, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::expr_path(?pth, ?ann)) { - auto tp_substs_0 = - ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann); - auto t_0 = ann_to_type(scx.fcx.ccx.tcx.node_types, ann); - - auto result_0 = demand::full(scx, e.span, expected, t_0, - tp_substs_0, adk); - auto t = result_0._1; - - // Fill in the type parameter substitutions if they weren't - // provided by the programmer. - auto ty_params_opt; - alt (ty::ann_to_ty_param_substs_opt_and_ty - (scx.fcx.ccx.tcx.node_types, ann)._0) { - case (none) { - ty_params_opt = none[vec[ty::t]]; - } - case (some(?tps)) { - ty_params_opt = some[vec[ty::t]](tps); - } - } - - write::ty_fixup(scx, ann.id, tup(ty_params_opt, t)); - } - case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - } - /* FIXME: should this check the type annotations? */ - case (ast::expr_fail(_)) { /* no-op */ } - case (ast::expr_log(_,_,_)) { /* no-op */ } - case (ast::expr_break(_)) { /* no-op */ } - case (ast::expr_cont(_)) { /* no-op */ } - case (ast::expr_ret(_,_)) { /* no-op */ } - case (ast::expr_put(_,_)) { /* no-op */ } - case (ast::expr_be(_,_)) { /* no-op */ } - case (ast::expr_check(_,_)) { /* no-op */ } - case (ast::expr_assert(_,_)) { /* no-op */ } - - case (ast::expr_port(?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - - case (ast::expr_chan(?es, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { - case (ty::ty_chan(?subty)) { - auto pt = ty::mk_port(scx.fcx.ccx.tcx, subty); - pushdown_expr(scx, pt, es); - } - case (_) { - log "chan expr doesn't have a chan type!"; - fail; - } - } - write::ty_only_fixup(scx, ann.id, t); - } - - case (ast::expr_alt(?discrim, ?arms_0, ?ann)) { - auto t = expected; - for (ast::arm arm_0 in arms_0) { - pushdown_block(scx, expected, arm_0.block); - auto bty = block_ty(scx.fcx.ccx.tcx, arm_0.block); - t = demand::simple(scx, e.span, t, bty); - } - write::ty_only_fixup(scx, ann.id, t); - } - - case (ast::expr_recv(?lval, ?expr, ?ann)) { - pushdown_expr(scx, next_ty_var(scx), lval); - auto t = expr_ty(scx.fcx.ccx.tcx, lval); - write::ty_only_fixup(scx, ann.id, t); - } - - case (ast::expr_send(?lval, ?expr, ?ann)) { - pushdown_expr(scx, next_ty_var(scx), expr); - auto t = expr_ty(scx.fcx.ccx.tcx, expr); - pushdown_expr(scx, ty::mk_chan(scx.fcx.ccx.tcx, t), lval); - } - - case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) { - // NB: we call 'demand::autoderef' and pass in adk only in - // cases where e is an expression that could *possibly* - // produce a box; things like expr_binary or expr_bind can't, - // so there's no need. - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - } - - case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) { - // NB: Not sure if this is correct, but not worrying too much - // about it since pushdown is going away anyway. - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - } - - case (_) { - scx.fcx.ccx.tcx.sess.span_unimpl(e.span, - #fmt("type unification for expression variant: %s", - pretty::pprust::expr_to_str(e))); - fail; - } - } - } - - // Push-down over typed blocks. - fn pushdown_block(&@stmt_ctxt scx, &ty::t expected, &ast::block bloc) { - alt (bloc.node.expr) { - case (some(?e_0)) { - pushdown_expr(scx, expected, e_0); - } - case (none) { - /* empty */ - } - } - demand::simple(scx, bloc.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, bloc.node.a)); - } -} - - -// Local variable resolution: the phase that finds all the types in the AST -// and replaces opaque "ty_local" types with the resolved local types. - -mod writeback { - fn wb_local(&@fn_ctxt fcx, &span sp, &@ast::local local) { - auto local_ty; - alt (fcx.locals.find(local.id)) { - case (none) { - fcx.ccx.tcx.sess.span_err(sp, - "unable to determine type of local: " + local.ident); - fail; - } - case (some(?lt)) { - local_ty = lt; - } - } - - if (ty::type_contains_vars(fcx.ccx.tcx, local_ty)) { - fcx.ccx.tcx.sess.span_err(sp, - "Ambiguous type " + ty_to_str(fcx.ccx.tcx, local_ty) - + "\n(Try adding more type annotations.)"); - } - write::ty_only(fcx.ccx.tcx, local.ann.id, local_ty); - } - - fn resolve_local_types(&@fn_ctxt fcx, &ast::ann ann) { - fn resolver(@fn_ctxt fcx, ty::t typ) -> ty::t { - alt (struct(fcx.ccx.tcx, typ)) { - case (ty::ty_local(?lid)) { ret fcx.locals.get(lid); } - case (_) { ret typ; } + new_substs_opt = some[vec[ty::t]](new_substs); } } - auto tpot = - ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx.node_types, - ann); - auto tt = tpot._1; - if (!ty::type_contains_locals(fcx.ccx.tcx, tt)) { ret; } - - auto f = bind resolver(fcx, _); - auto new_type = ty::fold_ty(fcx.ccx.tcx, f, tt); - write::ty(fcx.ccx.tcx, ann.id, tup(tpot._0, new_type)); + write::ty(fcx.ccx.tcx, ann.id, tup(new_substs_opt, new_ty)); } fn visit_stmt_pre(@fn_ctxt fcx, &@ast::stmt s) { - resolve_local_types(fcx, ty::stmt_ann(s)); + resolve_type_vars_for_node(fcx, s.span, ty::stmt_ann(s)); } fn visit_expr_pre(@fn_ctxt fcx, &@ast::expr e) { - resolve_local_types(fcx, ty::expr_ann(e)); + resolve_type_vars_for_node(fcx, e.span, ty::expr_ann(e)); } fn visit_block_pre(@fn_ctxt fcx, &ast::block b) { - resolve_local_types(fcx, b.node.a); + resolve_type_vars_for_node(fcx, b.span, b.node.a); } - fn visit_arm_pre(@fn_ctxt fcx, &ast::arm a) { - // FIXME: Need a visit_pat_pre - resolve_local_types(fcx, ty::pat_ann(a.pat)); + fn visit_pat_pre(@fn_ctxt fcx, &@ast::pat p) { + resolve_type_vars_for_node(fcx, p.span, ty::pat_ann(p)); } fn visit_decl_pre(@fn_ctxt fcx, &@ast::decl d) { alt (d.node) { - case (ast::decl_local(?l)) { wb_local(fcx, d.span, l); } - case (ast::decl_item(_)) { /* no annotation */ } + case (ast::decl_local(?l)) { + auto var_id = fcx.locals.get(l.id); + auto fix_rslt = ty::unify::resolve_type_var(fcx.ccx.tcx, + fcx.var_bindings, var_id); + alt (fix_rslt) { + case (fix_ok(?lty)) { + write::ty_only(fcx.ccx.tcx, l.ann.id, lty); + } + case (fix_err(_)) { + fcx.ccx.tcx.sess.span_err(d.span, + "cannot determine a type for this local " + + "variable"); + } + } + } + case (_) { /* no-op */ } } } - fn resolve_local_types_in_block(&@fn_ctxt fcx, &ast::block block) { + fn resolve_type_vars_in_block(&@fn_ctxt fcx, &ast::block block) { // A trick to ignore any contained items. auto ignore = @mutable false; fn visit_item_pre(@mutable bool ignore, &@ast::item item) { @@ -1631,7 +1074,7 @@ mod writeback { visit_stmt_pre=bind visit_stmt_pre(fcx, _), visit_expr_pre=bind visit_expr_pre(fcx, _), visit_block_pre=bind visit_block_pre(fcx, _), - visit_arm_pre=bind visit_arm_pre(fcx, _), + visit_pat_pre=bind visit_pat_pre(fcx, _), visit_decl_pre=bind visit_decl_pre(fcx, _) with walk::default_visitor()); walk::walk_block(visit, block); @@ -1639,19 +1082,151 @@ mod writeback { } +// Local variable gathering. We gather up all locals and create variable IDs +// for them before typechecking the function. + +type gather_result = rec( + @ty::unify::var_bindings var_bindings, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + int next_var_id +); + +fn gather_locals(&@crate_ctxt ccx, &ast::fn_decl decl, &ast::block body, + &ast::ann ann) -> gather_result { + fn next_var_id(@mutable int nvi) -> int { + auto rv = *nvi; + *nvi += 1; + ret rv; + } + + fn assign(&ty::ctxt tcx, + &@ty::unify::var_bindings var_bindings, + &hashmap[ast::def_id,int] locals, + &hashmap[ast::def_id,ast::ident] local_names, + @mutable int nvi, + ast::def_id lid, + &ast::ident ident, + option::t[ty::t] ty_opt) { + auto var_id = next_var_id(nvi); + locals.insert(lid, var_id); + local_names.insert(lid, ident); + + alt (ty_opt) { + case (none[ty::t]) { /* nothing to do */ } + case (some[ty::t](?typ)) { + ty::unify::unify(ty::mk_var(tcx, var_id), typ, var_bindings, + tcx); + } + } + } + + auto vb = ty::unify::mk_var_bindings(); + auto locals = new_def_hash[int](); + auto local_names = new_def_hash[ast::ident](); + auto nvi = @mutable 0; + + // Add object fields, if any. + alt (get_obj_info(ccx)) { + case (option::some(?oinfo)) { + for (ast::obj_field f in oinfo.obj_fields) { + auto field_ty = ty::ann_to_type(ccx.tcx, f.ann); + assign(ccx.tcx, vb, locals, local_names, nvi, f.id, f.ident, + some[ty::t](field_ty)); + } + } + case (option::none) { /* no fields */ } + } + + // Add formal parameters. + auto args = ty::ty_fn_args(ccx.tcx, ty::ann_to_type(ccx.tcx, ann)); + auto i = 0u; + for (ty::arg arg in args) { + assign(ccx.tcx, vb, locals, local_names, nvi, decl.inputs.(i).id, + decl.inputs.(i).ident, some[ty::t](arg.ty)); + i += 1u; + } + + // Add explicitly-declared locals. + fn visit_decl_pre(@crate_ctxt ccx, + @ty::unify::var_bindings vb, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + @mutable int nvi, + &@ast::decl d) { + alt (d.node) { + case (ast::decl_local(?local)) { + alt (local.ty) { + case (none) { + // Auto slot. + assign(ccx.tcx, vb, locals, local_names, nvi, + local.id, local.ident, none[ty::t]); + } + case (some(?ast_ty)) { + // Explicitly typed slot. + auto local_ty = ast_ty_to_ty_crate(ccx, ast_ty); + assign(ccx.tcx, vb, locals, local_names, nvi, + local.id, local.ident, some[ty::t](local_ty)); + } + } + } + case (_) { /* no-op */ } + } + } + + // Add pattern bindings. + fn visit_pat_pre(@crate_ctxt ccx, + @ty::unify::var_bindings vb, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + @mutable int nvi, + &@ast::pat p) { + alt (p.node) { + case (ast::pat_bind(?ident, ?did, _)) { + assign(ccx.tcx, vb, locals, local_names, nvi, did, ident, + none[ty::t]); + } + case (_) { /* no-op */ } + } + } + + auto visit = + rec(visit_decl_pre=bind visit_decl_pre(ccx, vb, locals, local_names, + nvi, _), + visit_pat_pre=bind visit_pat_pre(ccx, vb, locals, local_names, + nvi, _) + with walk::default_visitor()); + walk::walk_block(visit, body); + + ret rec( + var_bindings=vb, + locals=locals, + local_names=local_names, + next_var_id=*nvi + ); +} + + // AST fragment utilities -fn replace_expr_type(&@stmt_ctxt scx, +fn replace_expr_type(&@fn_ctxt fcx, &@ast::expr expr, &tup(vec[ty::t], ty::t) new_tyt) { auto new_tps; - if (ty::expr_has_ty_params(scx.fcx.ccx.tcx.node_types, expr)) { + if (ty::expr_has_ty_params(fcx.ccx.tcx, expr)) { new_tps = some[vec[ty::t]](new_tyt._0); } else { new_tps = none[vec[ty::t]]; } - write::ty_fixup(scx, ty::expr_ann(expr).id, tup(new_tps, new_tyt._1)); + write::ty_fixup(fcx, ty::expr_ann(expr).id, tup(new_tps, new_tyt._1)); +} + +fn replace_node_type_only(&ty::ctxt tcx, uint fixup, ty::t new_t) { + auto fixup_opt = tcx.node_types.(fixup); + auto tps = option::get[ty::ty_param_substs_opt_and_ty](fixup_opt)._0; + tcx.node_types.(fixup) = + some[ty::ty_param_substs_opt_and_ty](tup(tps, new_t)); } @@ -1669,79 +1244,93 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t { case (ast::lit_nil) { ret ty::mk_nil(ccx.tcx); } case (ast::lit_bool(_)) { ret ty::mk_bool(ccx.tcx); } } - - fail; // not reached } -fn check_pat(&@stmt_ctxt scx, &@ast::pat pat) { +// Pattern checking is top-down rather than bottom-up so that bindings get +// their types immediately. +fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) { alt (pat.node) { case (ast::pat_wild(?ann)) { - auto typ = next_ty_var(scx); - write::ty_only_fixup(scx, ann.id, typ); + write::ty_only_fixup(fcx, ann.id, expected); } case (ast::pat_lit(?lt, ?ann)) { - auto typ = check_lit(scx.fcx.ccx, lt); - write::ty_only_fixup(scx, ann.id, typ); - } - case (ast::pat_bind(?id, ?def_id, ?a)) { - auto typ = next_ty_var(scx); - write::ty_only_fixup(scx, a.id, typ); - } - case (ast::pat_tag(?p, ?subpats, ?old_ann)) { - auto vdef = ast::variant_def_ids - (scx.fcx.ccx.tcx.def_map.get(old_ann.id)); - auto t = ty::lookup_item_type(scx.fcx.ccx.tcx, - vdef._1)._1; - auto len = vec::len[ast::ident](p.node.idents); - auto last_id = p.node.idents.(len - 1u); - - auto tpt = ty::lookup_item_type(scx.fcx.ccx.tcx, - vdef._0); - - auto path_tpot = instantiate_path(scx, p, tpt, pat.span); - - alt (struct(scx.fcx.ccx.tcx, t)) { - // N-ary variants have function types. - case (ty::ty_fn(_, ?args, ?tag_ty, _)) { - auto arg_len = vec::len[arg](args); - auto subpats_len = vec::len[@ast::pat](subpats); - if (arg_len != subpats_len) { - // TODO: pluralize properly - auto err_msg = "tag type " + last_id + " has " + - uint::to_str(arg_len, 10u) + - " field(s), but this pattern has " + - uint::to_str(subpats_len, 10u) + - " field(s)"; - - scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg); - fail; // TODO: recover - } - - for (@ast::pat subpat in subpats) { - check_pat(scx, subpat); - } - - write::ty_fixup(scx, old_ann.id, path_tpot); - } - - // Nullary variants have tag types. - case (ty::ty_tag(?tid, _)) { - auto subpats_len = vec::len[@ast::pat](subpats); - if (subpats_len > 0u) { - // TODO: pluralize properly - auto err_msg = "tag type " + last_id + - " has no field(s)," + - " but this pattern has " + - uint::to_str(subpats_len, 10u) + - " field(s)"; - - scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg); - fail; // TODO: recover - } - - write::ty_fixup(scx, old_ann.id, path_tpot); + auto typ = check_lit(fcx.ccx, lt); + typ = demand::simple(fcx, pat.span, expected, typ); + write::ty_only_fixup(fcx, ann.id, typ); + } + case (ast::pat_bind(?id, ?def_id, ?ann)) { + auto vid = fcx.locals.get(def_id); + auto typ = ty::mk_var(fcx.ccx.tcx, vid); + typ = demand::simple(fcx, pat.span, expected, typ); + write::ty_only_fixup(fcx, ann.id, typ); + } + case (ast::pat_tag(?path, ?subpats, ?ann)) { + // Typecheck the path. + auto v_def = fcx.ccx.tcx.def_map.get(ann.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); + + // Take the tag type params out of `expected`. + auto expected_tps; + alt (structure_of(fcx, pat.span, expected)) { + case (ty::ty_tag(_, ?tps)) { expected_tps = tps; } + case (_) { + // FIXME: Switch expected and actual in this message? I + // can never tell. + fcx.ccx.tcx.sess.span_err(pat.span, + #fmt("mismatched types: expected tag but found %s", + ty::ty_to_str(fcx.ccx.tcx, expected))); + } + } + + // Unify with the expected tag type. + auto ctor_ty = ty::ty_param_substs_opt_and_ty_to_monotype( + fcx.ccx.tcx, path_tpot); + auto path_tpt = demand::full(fcx, pat.span, expected, ctor_ty, + expected_tps, NO_AUTODEREF); + path_tpot = tup(some[vec[ty::t]](path_tpt._0), path_tpt._1); + + // Get the number of arguments in this tag variant. + auto arg_types = variant_arg_types(fcx.ccx, pat.span, + v_def_ids._1, expected_tps); + + auto subpats_len = vec::len[@ast::pat](subpats); + + if (vec::len[ty::t](arg_types) > 0u) { + // N-ary variant. + auto arg_len = vec::len[ty::t](arg_types); + if (arg_len != subpats_len) { + // TODO: note definition of tag variant + // TODO (issue #448): Wrap a #fmt string over multiple + // lines... + fcx.ccx.tcx.sess.span_err(pat.span, #fmt( + "this pattern has %u field%s, but the corresponding variant has %u field%s", + subpats_len, + if (subpats_len == 0u) { "" } else { "s" }, + arg_len, + if (arg_len == 0u) { "" } else { "s" })); + } + + // TODO: vec::iter2 + auto i = 0u; + for (@ast::pat subpat in subpats) { + check_pat(fcx, subpat, arg_types.(i)); + i += 1u; } + } else if (subpats_len > 0u) { + // TODO: note definition of tag variant + // TODO (issue #448): Wrap a #fmt string over multiple + // lines... + fcx.ccx.tcx.sess.span_err(pat.span, #fmt( +"this pattern has %u field%s, but the corresponding variant has no fields", + subpats_len, + if (subpats_len == 0u) { "" } else { "s" })); } + + write::ty_fixup(fcx, ann.id, path_tpot); } } } @@ -1808,242 +1397,237 @@ fn require_pure_function(@crate_ctxt ccx, &ast::def_id d_id, &span sp) -> () { } } -fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { - // scx.fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " + +fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { + // fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " + // pretty::pprust::expr_to_str(expr)); // A generic function to factor out common logic from call and bind // expressions. - fn check_call_or_bind(&@stmt_ctxt scx, &@ast::expr f, + fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f, &vec[option::t[@ast::expr]] args) { // Check the function. - check_expr(scx, f); + check_expr(fcx, f); - // Check the arguments and generate the argument signature. - let vec[option::t[@ast::expr]] args_0 = []; - let vec[arg] arg_tys_0 = []; - for (option::t[@ast::expr] a_opt in args) { - alt (a_opt) { - case (some(?a)) { - check_expr(scx, a); - auto typ = expr_ty(scx.fcx.ccx.tcx, a); - vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); - } - case (none) { - auto typ = next_ty_var(scx); - vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); - } - } - } + // Get the function type. + auto fty = expr_ty(fcx.ccx.tcx, f); - auto rt_0 = next_ty_var(scx); - auto t_0; - alt (struct(scx.fcx.ccx.tcx, expr_ty(scx.fcx.ccx.tcx, f))) { - case (ty::ty_fn(?proto, _, _, ?cf)) { - t_0 = ty::mk_fn(scx.fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf); + // Grab the argument types and the return type. + auto arg_tys; + alt (structure_of(fcx, sp, fty)) { + case (ty::ty_fn(_, ?arg_tys_0, _, _)) { + arg_tys = arg_tys_0; } - case (ty::ty_native_fn(?abi, _, _)) { - t_0 = ty::mk_native_fn(scx.fcx.ccx.tcx, abi, arg_tys_0, rt_0); + case (ty::ty_native_fn(_, ?arg_tys_0, _)) { + arg_tys = arg_tys_0; } - case (?u) { - scx.fcx.ccx.tcx.sess.span_err(f.span, - "check_call_or_bind(): fn expr doesn't have fn type," - + " instead having: " + - ty_to_str(scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, f))); - fail; + case (_) { + fcx.ccx.tcx.sess.span_err(f.span, "mismatched types: " + + "expected function or native function but found " + + ty_to_str(fcx.ccx.tcx, fty)); } } - // Unify the callee and arguments. - auto tpt_0 = ty::expr_ty_params_and_ty(scx.fcx.ccx.tcx, f); - auto tpt_1 = demand::full(scx, f.span, tpt_0._1, t_0, tpt_0._0, - NO_AUTODEREF); - replace_expr_type(scx, f, tpt_1); + // Check that the correct number of arguments were supplied. + auto expected_arg_count = vec::len[ty::arg](arg_tys); + auto supplied_arg_count = vec::len[option::t[@ast::expr]](args); + if (expected_arg_count != supplied_arg_count) { + fcx.ccx.tcx.sess.span_err(sp, + #fmt("this function takes %u parameter%s but %u parameter%s \ + supplied", + expected_arg_count, + if (expected_arg_count == 1u) { "" } else { "s" }, + supplied_arg_count, + if (supplied_arg_count == 1u) { " was" } + else { "s were" })); + } + + // Check the arguments. + // TODO: iter2 + auto i = 0u; + for (option::t[@ast::expr] a_opt in args) { + alt (a_opt) { + case (some(?a)) { + check_expr(fcx, a); + demand::simple(fcx, a.span, arg_tys.(i).ty, + expr_ty(fcx.ccx.tcx, a)); + } + case (none) { /* no-op */ } + } + i += 1u; + } } // A generic function for checking assignment expressions - fn check_assignment(&@stmt_ctxt scx, &@ast::expr lhs, &@ast::expr rhs, - &ast::ann a) { - check_expr(scx, lhs); - check_expr(scx, rhs); - auto lhs_t0 = expr_ty(scx.fcx.ccx.tcx, lhs); - auto rhs_t0 = expr_ty(scx.fcx.ccx.tcx, rhs); - - pushdown::pushdown_expr(scx, rhs_t0, lhs); - auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs); - pushdown::pushdown_expr(scx, lhs_t1, rhs); - auto rhs_t1 = expr_ty(scx.fcx.ccx.tcx, rhs); - - write::ty_only_fixup(scx, a.id, rhs_t1); + fn check_assignment(&@fn_ctxt fcx, &span sp, &@ast::expr lhs, + &@ast::expr rhs, &ast::ann a) { + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto typ = demand::simple(fcx, sp, + expr_ty(fcx.ccx.tcx, lhs), + expr_ty(fcx.ccx.tcx, rhs)); + write::ty_only_fixup(fcx, a.id, typ); } // A generic function for checking call expressions - fn check_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) { + fn check_call(&@fn_ctxt fcx, &span sp, &@ast::expr f, + &vec[@ast::expr] args) { let vec[option::t[@ast::expr]] args_opt_0 = []; for (@ast::expr arg in args) { args_opt_0 += [some[@ast::expr](arg)]; } // Call the generic checker. - check_call_or_bind(scx, f, args_opt_0); + check_call_or_bind(fcx, sp, f, args_opt_0); } // A generic function for checking for or for-each loops - fn check_for_or_for_each(&@stmt_ctxt scx, &@ast::decl decl, + fn check_for_or_for_each(&@fn_ctxt fcx, &@ast::decl decl, &ty::t element_ty, &ast::block body, uint node_id) { - check_decl_local(scx.fcx, decl); - check_block(scx, body); + check_decl_local(fcx, decl); + check_block(fcx, body); // Unify type of decl with element type of the seq - demand::simple(scx, decl.span, ty::decl_local_ty(scx.fcx.ccx.tcx, + demand::simple(fcx, decl.span, ty::decl_local_ty(fcx.ccx.tcx, decl), element_ty); - auto typ = ty::mk_nil(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, node_id, typ); + auto typ = ty::mk_nil(fcx.ccx.tcx); + write::ty_only_fixup(fcx, node_id, typ); } alt (expr.node) { case (ast::expr_lit(?lit, ?a)) { - auto typ = check_lit(scx.fcx.ccx, lit); - write::ty_only_fixup(scx, a.id, typ); + auto typ = check_lit(fcx.ccx, lit); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_binary(?binop, ?lhs, ?rhs, ?a)) { - check_expr(scx, lhs); - check_expr(scx, rhs); - auto lhs_t0 = expr_ty(scx.fcx.ccx.tcx, lhs); - auto rhs_t0 = expr_ty(scx.fcx.ccx.tcx, rhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); - // FIXME: Binops have a bit more subtlety than this. - pushdown::pushdown_expr_full(scx, rhs_t0, lhs, AUTODEREF_OK); - auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs); - pushdown::pushdown_expr_full(scx, lhs_t1, rhs, AUTODEREF_OK); + auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); - auto t = strip_boxes(scx.fcx.ccx.tcx, lhs_t0); + // FIXME: Binops have a bit more subtlety than this. + auto t = strip_boxes(fcx, expr.span, lhs_t); alt (binop) { - case (ast::eq) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::lt) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::le) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::ne) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::ge) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::gt) { t = ty::mk_bool(scx.fcx.ccx.tcx); } + case (ast::eq) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::lt) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::le) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::ne) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::ge) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::gt) { t = ty::mk_bool(fcx.ccx.tcx); } case (_) { /* fall through */ } } - write::ty_only_fixup(scx, a.id, t); + write::ty_only_fixup(fcx, a.id, t); } case (ast::expr_unary(?unop, ?oper, ?a)) { - check_expr(scx, oper); + check_expr(fcx, oper); - auto oper_t = expr_ty(scx.fcx.ccx.tcx, oper); + auto oper_t = expr_ty(fcx.ccx.tcx, oper); alt (unop) { case (ast::box(?mut)) { - oper_t = ty::mk_box(scx.fcx.ccx.tcx, + oper_t = ty::mk_box(fcx.ccx.tcx, rec(ty=oper_t, mut=mut)); } case (ast::deref) { - alt (struct(scx.fcx.ccx.tcx, oper_t)) { + alt (structure_of(fcx, expr.span, oper_t)) { case (ty::ty_box(?inner)) { oper_t = inner.ty; } case (_) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "dereferencing non-box type: " - + ty_to_str(scx.fcx.ccx.tcx, oper_t)); + + ty_to_str(fcx.ccx.tcx, oper_t)); } } } - case (_) { oper_t = strip_boxes(scx.fcx.ccx.tcx, oper_t); } + case (_) { oper_t = strip_boxes(fcx, expr.span, oper_t); } } - write::ty_only_fixup(scx, a.id, oper_t); + write::ty_only_fixup(fcx, a.id, oper_t); } case (ast::expr_path(?pth, ?old_ann)) { - auto t = ty::mk_nil(scx.fcx.ccx.tcx); - auto defn = scx.fcx.ccx.tcx.def_map.get(old_ann.id); + auto t = ty::mk_nil(fcx.ccx.tcx); + auto defn = fcx.ccx.tcx.def_map.get(old_ann.id); - auto tpt = ty_param_count_and_ty_for_def(scx.fcx, expr.span, + 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(scx, pth, tpt, expr.span); - write::ty_fixup(scx, old_ann.id, path_tpot); + auto path_tpot = instantiate_path(fcx, pth, tpt, expr.span); + write::ty_fixup(fcx, old_ann.id, path_tpot); ret; } // The definition doesn't take type parameters. If the programmer // supplied some, that's an error. if (vec::len[@ast::ty](pth.node.types) > 0u) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "this kind of value does not take type parameters"); - fail; } - write::ty_only_fixup(scx, old_ann.id, tpt._1); + write::ty_only_fixup(fcx, old_ann.id, tpt._1); } case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?a)) { - check_expr(scx, expanded); - auto t = expr_ty(scx.fcx.ccx.tcx, expanded); - write::ty_only_fixup(scx, a.id, t); + check_expr(fcx, expanded); + auto t = expr_ty(fcx.ccx.tcx, expanded); + write::ty_only_fixup(fcx, a.id, t); } - case (ast::expr_fail(?a)) { - write::bot_ty(scx.fcx.ccx.tcx, a.id); + case (ast::expr_fail(?a, _)) { + write::bot_ty(fcx.ccx.tcx, a.id); } case (ast::expr_break(?a)) { - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (ast::expr_cont(?a)) { - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (ast::expr_ret(?expr_opt, ?a)) { alt (expr_opt) { case (none) { - auto nil = ty::mk_nil(scx.fcx.ccx.tcx); - if (!are_compatible(scx, scx.fcx.ret_ty, nil)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + auto nil = ty::mk_nil(fcx.ccx.tcx); + if (!are_compatible(fcx, fcx.ret_ty, nil)) { + fcx.ccx.tcx.sess.span_err(expr.span, "ret; in function returning non-nil"); } - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (some(?e)) { - check_expr(scx, e); - pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e); - - write::bot_ty(scx.fcx.ccx.tcx, a.id); + check_expr(fcx, e); + demand::simple(fcx, expr.span, fcx.ret_ty, + expr_ty(fcx.ccx.tcx, e)); + write::bot_ty(fcx.ccx.tcx, a.id); } } } case (ast::expr_put(?expr_opt, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); alt (expr_opt) { case (none) { - auto nil = ty::mk_nil(scx.fcx.ccx.tcx); - if (!are_compatible(scx, scx.fcx.ret_ty, nil)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + auto nil = ty::mk_nil(fcx.ccx.tcx); + if (!are_compatible(fcx, fcx.ret_ty, nil)) { + fcx.ccx.tcx.sess.span_err(expr.span, "put; in iterator yielding non-nil"); } - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (some(?e)) { - check_expr(scx, e); - pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e); - - write::nil_ty(scx.fcx.ccx.tcx, a.id); + check_expr(fcx, e); + write::nil_ty(fcx.ccx.tcx, a.id); } } } @@ -2052,21 +1636,21 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // FIXME: prove instead of assert assert (ast::is_call_expr(e)); - check_expr(scx, e); - pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e); + check_expr(fcx, e); + demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e)); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (ast::expr_log(?l, ?e, ?a)) { - auto expr_t = check_expr(scx, e); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + auto expr_t = check_expr(fcx, e); + write::nil_ty(fcx.ccx.tcx, a.id); } case (ast::expr_check(?e, ?a)) { - check_expr(scx, e); - demand::simple(scx, expr.span, ty::mk_bool(scx.fcx.ccx.tcx), - expr_ty(scx.fcx.ccx.tcx, e)); + check_expr(fcx, e); + demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), + expr_ty(fcx.ccx.tcx, e)); /* e must be a call expr where all arguments are either literals or slots */ alt (e.node) { @@ -2074,243 +1658,226 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { alt (operator.node) { case (ast::expr_path(?oper_name, ?ann)) { auto d_id; - alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) { + alt (fcx.ccx.tcx.def_map.get(ann.id)) { case (ast::def_fn(?_d_id)) { d_id = _d_id; } } for (@ast::expr operand in operands) { if (! ast::is_constraint_arg(operand)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "Constraint args must be " + "slot variables or literals"); } } - require_pure_function(scx.fcx.ccx, d_id, + require_pure_function(fcx.ccx, d_id, expr.span); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "In a constraint, expected the constraint name " + "to be an explicit name"); } } } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "check on non-predicate"); } } } case (ast::expr_assert(?e, ?a)) { - check_expr(scx, e); - auto ety = expr_ty(scx.fcx.ccx.tcx, e); - demand::simple(scx, expr.span, ty::mk_bool(scx.fcx.ccx.tcx), ety); + check_expr(fcx, e); + auto ety = expr_ty(fcx.ccx.tcx, e); + demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), ety); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (ast::expr_move(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); - check_assignment(scx, lhs, rhs, a); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, expr.span, lhs, rhs, a); } case (ast::expr_assign(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); - check_assignment(scx, lhs, rhs, a); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, expr.span, lhs, rhs, a); } case (ast::expr_assign_op(?op, ?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); - check_assignment(scx, lhs, rhs, a); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, expr.span, lhs, rhs, a); } case (ast::expr_send(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); - check_expr(scx, lhs); - check_expr(scx, rhs); - auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs); + auto chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t); - auto chan_t = ty::mk_chan(scx.fcx.ccx.tcx, rhs_t); - pushdown::pushdown_expr(scx, chan_t, lhs); auto item_t; - auto lhs_t = expr_ty(scx.fcx.ccx.tcx, lhs); - alt (struct(scx.fcx.ccx.tcx, lhs_t)) { + auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); + alt (structure_of(fcx, expr.span, lhs_t)) { case (ty::ty_chan(?it)) { item_t = it; } - case (_) { fail; } + case (_) { + fcx.ccx.tcx.sess.span_err(expr.span, + #fmt("mismatched types: expected chan but found %s", + ty_to_str(fcx.ccx.tcx, lhs_t))); + } } - pushdown::pushdown_expr(scx, item_t, rhs); - write::ty_only_fixup(scx, a.id, chan_t); + write::ty_only_fixup(fcx, a.id, chan_t); } case (ast::expr_recv(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_expr(scx, lhs); - check_expr(scx, rhs); - auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); - auto port_t = ty::mk_port(scx.fcx.ccx.tcx, lhs_t1); - pushdown::pushdown_expr(scx, port_t, rhs); - auto item_t; - auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs); - alt (struct(scx.fcx.ccx.tcx, rhs_t)) { - case (ty::ty_port(?it)) { item_t = it; } - case (_) { fail; } - } - pushdown::pushdown_expr(scx, item_t, lhs); + auto item_t = expr_ty(fcx.ccx.tcx, lhs); + auto port_t = ty::mk_port(fcx.ccx.tcx, item_t); + demand::simple(fcx, expr.span, port_t, expr_ty(fcx.ccx.tcx, rhs)); - write::ty_only_fixup(scx, a.id, item_t); + write::ty_only_fixup(fcx, a.id, item_t); } case (ast::expr_if(?cond, ?thn, ?elsopt, ?a)) { - check_expr(scx, cond); - pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), - cond); - - check_block(scx, thn); + check_expr(fcx, cond); + check_block(fcx, thn); auto if_t = alt (elsopt) { case (some(?els)) { - check_expr(scx, els); + check_expr(fcx, els); + + auto thn_t = block_ty(fcx.ccx.tcx, thn); + auto elsopt_t = expr_ty(fcx.ccx.tcx, els); - auto thn_t = block_ty(scx.fcx.ccx.tcx, thn); - auto elsopt_t = expr_ty(scx.fcx.ccx.tcx, els); - if (!ty::type_is_bot(scx.fcx.ccx.tcx, elsopt_t)) { + demand::simple(fcx, expr.span, thn_t, elsopt_t); + + if (!ty::type_is_bot(fcx.ccx.tcx, elsopt_t)) { elsopt_t } else { thn_t } } case (none) { - ty::mk_nil(scx.fcx.ccx.tcx) + ty::mk_nil(fcx.ccx.tcx) } }; - write::ty_only_fixup(scx, a.id, if_t); + write::ty_only_fixup(fcx, a.id, if_t); } case (ast::expr_for(?decl, ?seq, ?body, ?a)) { - check_expr(scx, seq); - alt (struct (scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, seq))) { + check_expr(fcx, seq); + alt (structure_of(fcx, expr.span, expr_ty(fcx.ccx.tcx, seq))) { // FIXME: I include the check_for_or_each call in // each case because of a bug in typestate. // The bug is fixed; once there's a new snapshot, // the call can be moved out of the alt expression case (ty::ty_vec(?vec_elt_ty)) { auto elt_ty = vec_elt_ty.ty; - check_for_or_for_each(scx, decl, elt_ty, body, a.id); + check_for_or_for_each(fcx, decl, elt_ty, body, a.id); } case (ty::ty_str) { - auto elt_ty = ty::mk_mach(scx.fcx.ccx.tcx, + auto elt_ty = ty::mk_mach(fcx.ccx.tcx, util::common::ty_u8); - check_for_or_for_each(scx, decl, elt_ty, body, a.id); + check_for_or_for_each(fcx, decl, elt_ty, body, a.id); } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "type of for loop iterator is not a vector or string"); } } } case (ast::expr_for_each(?decl, ?seq, ?body, ?a)) { - check_expr(scx, seq); - check_for_or_for_each(scx, decl, expr_ty(scx.fcx.ccx.tcx, seq), + check_expr(fcx, seq); + check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq), body, a.id); } case (ast::expr_while(?cond, ?body, ?a)) { - check_expr(scx, cond); - pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), cond); - check_block(scx, body); + check_expr(fcx, cond); + check_block(fcx, body); + + demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx), + expr_ty(fcx.ccx.tcx, cond)); - auto typ = ty::mk_nil(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_nil(fcx.ccx.tcx); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_do_while(?body, ?cond, ?a)) { - check_expr(scx, cond); - pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), cond); - check_block(scx, body); + check_expr(fcx, cond); + check_block(fcx, body); - auto typ = block_ty(scx.fcx.ccx.tcx, body); - write::ty_only_fixup(scx, a.id, typ); + auto typ = block_ty(fcx.ccx.tcx, body); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_alt(?expr, ?arms, ?a)) { - check_expr(scx, expr); + check_expr(fcx, expr); // Typecheck the patterns first, so that we get types for all the // bindings. - auto pattern_ty = expr_ty(scx.fcx.ccx.tcx, expr); + auto pattern_ty = ty::expr_ty(fcx.ccx.tcx, expr); let vec[@ast::pat] pats = []; for (ast::arm arm in arms) { - check_pat(scx, arm.pat); - pattern_ty = demand::simple(scx, arm.pat.span, pattern_ty, - pat_ty(scx.fcx.ccx.tcx, arm.pat)); + check_pat(fcx, arm.pat, pattern_ty); pats += [arm.pat]; } - for (@ast::pat pat in pats) { - pushdown::pushdown_pat(scx, pattern_ty, pat); - } - // Now typecheck the blocks. - auto result_ty = next_ty_var(scx); + auto result_ty = next_ty_var(fcx); let vec[ast::block] blocks = []; for (ast::arm arm in arms) { - check_block(scx, arm.block); + check_block(fcx, arm.block); - auto bty = block_ty(scx.fcx.ccx.tcx, arm.block); + auto bty = block_ty(fcx.ccx.tcx, arm.block); // Failing alt arms don't need to have a matching type - if (!ty::type_is_bot(scx.fcx.ccx.tcx, bty)) { - result_ty = demand::simple(scx, arm.block.span, + if (!ty::type_is_bot(fcx.ccx.tcx, bty)) { + result_ty = demand::simple(fcx, arm.block.span, result_ty, bty); } } - auto i = 0u; - for (ast::block bloc in blocks) { - pushdown::pushdown_block(scx, result_ty, bloc); - } - - pushdown::pushdown_expr(scx, pattern_ty, expr); - - write::ty_only_fixup(scx, a.id, result_ty); + write::ty_only_fixup(fcx, a.id, result_ty); } case (ast::expr_block(?b, ?a)) { - check_block(scx, b); + check_block(fcx, b); alt (b.node.expr) { case (some(?expr)) { - auto typ = expr_ty(scx.fcx.ccx.tcx, expr); - write::ty_only_fixup(scx, a.id, typ); + auto typ = expr_ty(fcx.ccx.tcx, expr); + write::ty_only_fixup(fcx, a.id, typ); } case (none) { - auto typ = ty::mk_nil(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_nil(fcx.ccx.tcx); + write::ty_only_fixup(fcx, a.id, typ); } } } case (ast::expr_bind(?f, ?args, ?a)) { // Call the generic checker. - check_call_or_bind(scx, f, args); + check_call_or_bind(fcx, expr.span, f, args); // Pull the argument and return types out. auto proto_1; let vec[ty::arg] arg_tys_1 = []; auto rt_1; - auto fty = expr_ty(scx.fcx.ccx.tcx, f); + auto fty = expr_ty(fcx.ccx.tcx, f); auto t_1; - alt (struct(scx.fcx.ccx.tcx, fty)) { + alt (structure_of(fcx, expr.span, fty)) { case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) { proto_1 = proto; rt_1 = rt; @@ -2327,7 +1894,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } i += 1u; } - t_1 = ty::mk_fn(scx.fcx.ccx.tcx, proto_1, arg_tys_1, rt_1, + t_1 = ty::mk_fn(fcx.ccx.tcx, proto_1, arg_tys_1, rt_1, cf); } case (_) { @@ -2335,7 +1902,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { fail; } } - write::ty_only_fixup(scx, a.id, t_1); + write::ty_only_fixup(fcx, a.id, t_1); } case (ast::expr_call(?f, ?args, ?a)) { @@ -2343,14 +1910,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { need to restrict it to being an explicit expr_path if we're inside a pure function, and need an environment mapping from function name onto purity-designation */ - require_pure_call(scx.fcx.ccx, scx.fcx.purity, f, expr.span); + require_pure_call(fcx.ccx, fcx.purity, f, expr.span); - check_call(scx, f, args); + check_call(fcx, expr.span, f, args); // Pull the return type out of the type of the function. - auto rt_1 = ty::mk_nil(scx.fcx.ccx.tcx); // FIXME: typestate botch - auto fty = expr_ty(scx.fcx.ccx.tcx, f); - alt (struct(scx.fcx.ccx.tcx, fty)) { + auto rt_1 = ty::mk_nil(fcx.ccx.tcx); // FIXME: typestate botch + auto fty = 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 (_) { @@ -2359,14 +1926,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } } - write::ty_only_fixup(scx, a.id, rt_1); + write::ty_only_fixup(fcx, a.id, rt_1); } case (ast::expr_self_method(?id, ?a)) { - auto t = ty::mk_nil(scx.fcx.ccx.tcx); + auto t = ty::mk_nil(fcx.ccx.tcx); let ty::t this_obj_ty; - let option::t[obj_info] this_obj_info = get_obj_info(scx.fcx.ccx); + let option::t[obj_info] this_obj_info = get_obj_info(fcx.ccx); alt (this_obj_info) { // If we're inside a current object, grab its type. @@ -2374,7 +1941,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // FIXME: In the case of anonymous objects with methods // containing self-calls, this lookup fails because // obj_info.this_obj is not in the type cache - this_obj_ty = ty::lookup_item_type(scx.fcx.ccx.tcx, + this_obj_ty = ty::lookup_item_type(fcx.ccx.tcx, obj_info.this_obj)._1; } @@ -2382,11 +1949,11 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } // Grab this method's type out of the current object type. - alt (struct(scx.fcx.ccx.tcx, this_obj_ty)) { + alt (structure_of(fcx, expr.span, this_obj_ty)) { case (ty::ty_obj(?methods)) { for (ty::method method in methods) { if (method.ident == id) { - t = ty::method_ty_to_fn_ty(scx.fcx.ccx.tcx, + t = ty::method_ty_to_fn_ty(fcx.ccx.tcx, method); } } @@ -2394,86 +1961,86 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { case (_) { fail; } } - write::ty_only_fixup(scx, a.id, t); + write::ty_only_fixup(fcx, a.id, t); - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); } case (ast::expr_spawn(_, _, ?f, ?args, ?a)) { - check_call(scx, f, args); + check_call(fcx, expr.span, f, args); - auto fty = expr_ty(scx.fcx.ccx.tcx, f); - auto ret_ty = ty::ret_ty_of_fn_ty(scx.fcx.ccx.tcx, fty); + auto fty = expr_ty(fcx.ccx.tcx, f); + auto ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty); - demand::simple(scx, f.span, ty::mk_nil(scx.fcx.ccx.tcx), ret_ty); + demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty); // FIXME: Other typechecks needed - auto typ = ty::mk_task(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_task(fcx.ccx.tcx); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_cast(?e, ?t, ?a)) { - check_expr(scx, e); - auto t_1 = ast_ty_to_ty_crate(scx.fcx.ccx, t); + check_expr(fcx, e); + auto t_1 = ast_ty_to_ty_crate(fcx.ccx, t); // FIXME: there are more forms of cast to support, eventually. - if (! (type_is_scalar(scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, e)) && - type_is_scalar(scx.fcx.ccx.tcx, t_1))) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + if (! (type_is_scalar(fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, e)) && + type_is_scalar(fcx.ccx.tcx, t_1))) { + fcx.ccx.tcx.sess.span_err(expr.span, "non-scalar cast: " + - ty_to_str(scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, e)) + - " as " + ty_to_str(scx.fcx.ccx.tcx, t_1)); + ty_to_str(fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, e)) + + " as " + ty_to_str(fcx.ccx.tcx, t_1)); } - write::ty_only_fixup(scx, a.id, t_1); + write::ty_only_fixup(fcx, a.id, t_1); } case (ast::expr_vec(?args, ?mut, ?a)) { let ty::t t; if (vec::len[@ast::expr](args) == 0u) { - t = next_ty_var(scx); + t = next_ty_var(fcx); } else { - check_expr(scx, args.(0)); - t = expr_ty(scx.fcx.ccx.tcx, args.(0)); + check_expr(fcx, args.(0)); + t = expr_ty(fcx.ccx.tcx, args.(0)); } for (@ast::expr e in args) { - check_expr(scx, e); - auto expr_t = expr_ty(scx.fcx.ccx.tcx, e); - demand::simple(scx, expr.span, t, expr_t); + check_expr(fcx, e); + auto expr_t = expr_ty(fcx.ccx.tcx, e); + demand::simple(fcx, expr.span, t, expr_t); } - auto typ = ty::mk_vec(scx.fcx.ccx.tcx, rec(ty=t, mut=mut)); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_vec(fcx.ccx.tcx, rec(ty=t, mut=mut)); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_tup(?elts, ?a)) { let vec[ty::mt] elts_mt = []; for (ast::elt e in elts) { - check_expr(scx, e.expr); - auto ety = expr_ty(scx.fcx.ccx.tcx, e.expr); + check_expr(fcx, e.expr); + auto ety = expr_ty(fcx.ccx.tcx, e.expr); elts_mt += [rec(ty=ety, mut=e.mut)]; } - auto typ = ty::mk_tup(scx.fcx.ccx.tcx, elts_mt); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_tup(fcx.ccx.tcx, elts_mt); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_rec(?fields, ?base, ?a)) { alt (base) { case (none) { /* no-op */} - case (some(?b_0)) { check_expr(scx, b_0); } + case (some(?b_0)) { check_expr(fcx, b_0); } } let vec[field] fields_t = []; for (ast::field f in fields) { - check_expr(scx, f.node.expr); - auto expr_t = expr_ty(scx.fcx.ccx.tcx, f.node.expr); + check_expr(fcx, f.node.expr); + auto expr_t = expr_ty(fcx.ccx.tcx, f.node.expr); auto expr_mt = rec(ty=expr_t, mut=f.node.mut); vec::push[field](fields_t, rec(ident=f.node.ident, @@ -2482,38 +2049,38 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { alt (base) { case (none) { - auto typ = ty::mk_rec(scx.fcx.ccx.tcx, fields_t); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_rec(fcx.ccx.tcx, fields_t); + write::ty_only_fixup(fcx, a.id, typ); } case (some(?bexpr)) { - check_expr(scx, bexpr); - auto bexpr_t = expr_ty(scx.fcx.ccx.tcx, bexpr); + check_expr(fcx, bexpr); + auto bexpr_t = expr_ty(fcx.ccx.tcx, bexpr); let vec[field] base_fields = []; - alt (struct(scx.fcx.ccx.tcx, bexpr_t)) { + alt (structure_of(fcx, expr.span, bexpr_t)) { case (ty::ty_rec(?flds)) { base_fields = flds; } case (_) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "record update non-record base"); } } - write::ty_only_fixup(scx, a.id, bexpr_t); + write::ty_only_fixup(fcx, a.id, bexpr_t); for (ty::field f in fields_t) { auto found = false; for (ty::field bf in base_fields) { if (str::eq(f.ident, bf.ident)) { - demand::simple(scx, expr.span, f.mt.ty, + demand::simple(fcx, expr.span, f.mt.ty, bf.mt.ty); found = true; } } if (!found) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "unknown field in record update: " + f.ident); @@ -2524,106 +2091,108 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } case (ast::expr_field(?base, ?field, ?a)) { - check_expr(scx, base); - auto base_t = expr_ty(scx.fcx.ccx.tcx, base); - base_t = strip_boxes(scx.fcx.ccx.tcx, base_t); - alt (struct(scx.fcx.ccx.tcx, base_t)) { + check_expr(fcx, base); + auto base_t = expr_ty(fcx.ccx.tcx, base); + base_t = strip_boxes(fcx, expr.span, base_t); + base_t = ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, base_t); + alt (structure_of(fcx, expr.span, base_t)) { case (ty::ty_tup(?args)) { - let uint ix = ty::field_num(scx.fcx.ccx.tcx.sess, + let uint ix = ty::field_num(fcx.ccx.tcx.sess, expr.span, field); if (ix >= vec::len[ty::mt](args)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad index on tuple"); } - write::ty_only_fixup(scx, a.id, args.(ix).ty); + write::ty_only_fixup(fcx, a.id, args.(ix).ty); } case (ty::ty_rec(?fields)) { - let uint ix = ty::field_idx(scx.fcx.ccx.tcx.sess, + let uint ix = ty::field_idx(fcx.ccx.tcx.sess, expr.span, field, fields); if (ix >= vec::len[ty::field](fields)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad index on record"); } - write::ty_only_fixup(scx, a.id, fields.(ix).mt.ty); + write::ty_only_fixup(fcx, a.id, fields.(ix).mt.ty); } case (ty::ty_obj(?methods)) { - let uint ix = ty::method_idx(scx.fcx.ccx.tcx.sess, + let uint ix = ty::method_idx(fcx.ccx.tcx.sess, expr.span, field, methods); if (ix >= vec::len[ty::method](methods)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad index on obj"); } auto meth = methods.(ix); - auto t = ty::mk_fn(scx.fcx.ccx.tcx, meth.proto, + auto t = ty::mk_fn(fcx.ccx.tcx, meth.proto, meth.inputs, meth.output, meth.cf); - write::ty_only_fixup(scx, a.id, t); + write::ty_only_fixup(fcx, a.id, t); } case (_) { - scx.fcx.ccx.tcx.sess.span_unimpl(expr.span, + fcx.ccx.tcx.sess.span_unimpl(expr.span, "base type for expr_field in typeck::check_expr: " + - ty_to_str(scx.fcx.ccx.tcx, base_t)); + ty_to_str(fcx.ccx.tcx, base_t)); } } } case (ast::expr_index(?base, ?idx, ?a)) { - check_expr(scx, base); - auto base_t = expr_ty(scx.fcx.ccx.tcx, base); - base_t = strip_boxes(scx.fcx.ccx.tcx, base_t); + check_expr(fcx, base); + auto base_t = expr_ty(fcx.ccx.tcx, base); + base_t = strip_boxes(fcx, expr.span, base_t); - check_expr(scx, idx); - auto idx_t = expr_ty(scx.fcx.ccx.tcx, idx); - alt (struct(scx.fcx.ccx.tcx, base_t)) { + check_expr(fcx, idx); + auto idx_t = expr_ty(fcx.ccx.tcx, idx); + alt (structure_of(fcx, expr.span, base_t)) { case (ty::ty_vec(?mt)) { - if (! type_is_integral(scx.fcx.ccx.tcx, idx_t)) { - scx.fcx.ccx.tcx.sess.span_err + if (! type_is_integral(fcx.ccx.tcx, idx_t)) { + fcx.ccx.tcx.sess.span_err (idx.span, "non-integral type of vec index: " - + ty_to_str(scx.fcx.ccx.tcx, idx_t)); + + ty_to_str(fcx.ccx.tcx, idx_t)); } - write::ty_only_fixup(scx, a.id, mt.ty); + write::ty_only_fixup(fcx, a.id, mt.ty); } case (ty::ty_str) { - if (! type_is_integral(scx.fcx.ccx.tcx, idx_t)) { - scx.fcx.ccx.tcx.sess.span_err + if (! type_is_integral(fcx.ccx.tcx, idx_t)) { + fcx.ccx.tcx.sess.span_err (idx.span, "non-integral type of str index: " - + ty_to_str(scx.fcx.ccx.tcx, idx_t)); + + ty_to_str(fcx.ccx.tcx, idx_t)); } - auto typ = ty::mk_mach(scx.fcx.ccx.tcx, common::ty_u8); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_mach(fcx.ccx.tcx, common::ty_u8); + write::ty_only_fixup(fcx, a.id, typ); } case (_) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "vector-indexing bad type: " - + ty_to_str(scx.fcx.ccx.tcx, base_t)); + + ty_to_str(fcx.ccx.tcx, base_t)); } } } case (ast::expr_port(?a)) { - auto t = next_ty_var(scx); - auto pt = ty::mk_port(scx.fcx.ccx.tcx, t); - write::ty_only_fixup(scx, a.id, pt); + auto t = next_ty_var(fcx); + auto pt = ty::mk_port(fcx.ccx.tcx, t); + write::ty_only_fixup(fcx, a.id, pt); } case (ast::expr_chan(?x, ?a)) { - check_expr(scx, x); - auto port_t = expr_ty(scx.fcx.ccx.tcx, x); - alt (struct(scx.fcx.ccx.tcx, port_t)) { + check_expr(fcx, x); + auto port_t = expr_ty(fcx.ccx.tcx, x); + alt (structure_of(fcx, expr.span, port_t)) { case (ty::ty_port(?subtype)) { - auto ct = ty::mk_chan(scx.fcx.ccx.tcx, subtype); - write::ty_only_fixup(scx, a.id, ct); + auto ct = ty::mk_chan(fcx.ccx.tcx, subtype); + write::ty_only_fixup(fcx, a.id, ct); } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad port type: " + - ty_to_str(scx.fcx.ccx.tcx, port_t)); + ty_to_str(fcx.ccx.tcx, port_t)); } } } @@ -2640,7 +2209,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } let ast::def_id di = obj_def_ids.ty; - vec::push[obj_info](scx.fcx.ccx.obj_infos, + vec::push[obj_info](fcx.ccx.obj_infos, rec(obj_fields=fields, this_obj=di)); // Typecheck 'with_obj', if it exists. @@ -2651,16 +2220,16 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // This had better have object type. TOOD: report an // error if the user is trying to extend a non-object // with_obj. - check_expr(scx, e); + check_expr(fcx, e); } } // Typecheck the methods. for (@ast::method method in anon_obj.methods) { - check_method(scx.fcx.ccx, method); + check_method(fcx.ccx, method); } - auto t = next_ty_var(scx); + auto t = next_ty_var(fcx); // FIXME: These next three functions are largely ripped off from @@ -2688,46 +2257,53 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { anon_obj.methods); } - auto methods = get_anon_obj_method_types(scx.fcx.ccx, anon_obj); - auto ot = ty::mk_obj(scx.fcx.ccx.tcx, + auto methods = get_anon_obj_method_types(fcx.ccx, anon_obj); + auto ot = ty::mk_obj(fcx.ccx.tcx, ty::sort_methods(methods)); - write::ty_only_fixup(scx, a.id, ot); + write::ty_only_fixup(fcx, a.id, ot); // Now remove the info from the stack. - vec::pop[obj_info](scx.fcx.ccx.obj_infos); + vec::pop[obj_info](fcx.ccx.obj_infos); } case (_) { - scx.fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr"); + fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr"); } } } -fn next_ty_var(&@stmt_ctxt scx) -> ty::t { - auto t = ty::mk_var(scx.fcx.ccx.tcx, scx.next_var_id); - scx.next_var_id += 1; - ret t; +fn next_ty_var_id(@fn_ctxt fcx) -> int { + auto id = fcx.next_var_id; + fcx.next_var_id += 1; + ret id; +} + +fn next_ty_var(&@fn_ctxt fcx) -> ty::t { + ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx)); } fn get_obj_info(&@crate_ctxt ccx) -> option::t[obj_info] { ret vec::last[obj_info](ccx.obj_infos); } -fn check_decl_initializer(&@stmt_ctxt scx, &ast::def_id lid, +fn check_decl_initializer(&@fn_ctxt fcx, &ast::def_id lid, &ast::initializer init) { - check_expr(scx, init.expr); + check_expr(fcx, init.expr); - auto lty = ty::mk_local(scx.fcx.ccx.tcx, lid); + auto lty = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(lid)); alt (init.op) { case (ast::init_assign) { - pushdown::pushdown_expr(scx, lty, init.expr); + demand::simple(fcx, init.expr.span, lty, + expr_ty(fcx.ccx.tcx, init.expr)); } case (ast::init_move) { - pushdown::pushdown_expr(scx, lty, init.expr); + demand::simple(fcx, init.expr.span, lty, + expr_ty(fcx.ccx.tcx, init.expr)); } case (ast::init_recv) { - auto port_ty = ty::mk_port(scx.fcx.ccx.tcx, lty); - pushdown::pushdown_expr(scx, port_ty, init.expr); + auto port_ty = ty::mk_port(fcx.ccx.tcx, lty); + demand::simple(fcx, init.expr.span, port_ty, + expr_ty(fcx.ccx.tcx, init.expr)); } } } @@ -2735,43 +2311,23 @@ fn check_decl_initializer(&@stmt_ctxt scx, &ast::def_id lid, fn check_decl_local(&@fn_ctxt fcx, &@ast::decl decl) -> @ast::decl { alt (decl.node) { case (ast::decl_local(?local)) { - auto t = ty::mk_nil(fcx.ccx.tcx); - - alt (local.ty) { - case (none) { - // Auto slot. Do nothing for now. - } - - case (some(?ast_ty)) { - auto local_ty = ast_ty_to_ty_crate(fcx.ccx, ast_ty); - fcx.locals.insert(local.id, local_ty); - t = local_ty; - } - } - auto a_res = local.ann; - write::ty_only(fcx.ccx.tcx, a_res.id, t); + auto t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.id)); + write::ty_only_fixup(fcx, a_res.id, t); auto initopt = local.init; alt (local.init) { case (some(?init)) { - with_stmt_ctxt(fcx, - bind check_decl_initializer(_, local.id, init)); + check_decl_initializer(fcx, local.id, init); } case (_) { /* fall through */ } } - auto local_1 = @rec(init = initopt, ann = a_res with *local); + auto local_1 = @rec(init=initopt, ann=a_res with *local); ret @rec(node=ast::decl_local(local_1) with *decl); } } } -fn check_and_pushdown_expr(&@stmt_ctxt scx, &@ast::expr expr) { - check_expr(scx, expr); - auto ety = expr_ty(scx.fcx.ccx.tcx, expr); - pushdown::pushdown_expr(scx, ety, expr); -} - fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { auto node_id; alt (stmt.node) { @@ -2784,25 +2340,22 @@ fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { } case (ast::stmt_expr(?expr,?a)) { node_id = a.id; - with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, expr)); + check_expr(fcx, expr); } } write::nil_ty(fcx.ccx.tcx, node_id); } -fn check_block(&@stmt_ctxt scx, &ast::block block) { - for (@ast::stmt s in block.node.stmts) { check_stmt(scx.fcx, s); } +fn check_block(&@fn_ctxt fcx, &ast::block block) { + for (@ast::stmt s in block.node.stmts) { check_stmt(fcx, s); } alt (block.node.expr) { - case (none) { - write::nil_ty(scx.fcx.ccx.tcx, block.node.a.id); - } + case (none) { write::nil_ty(fcx.ccx.tcx, block.node.a.id); } case (some(?e)) { - check_expr(scx, e); - auto ety = expr_ty(scx.fcx.ccx.tcx, e); - pushdown::pushdown_expr(scx, ety, e); - write::ty_only_fixup(scx, block.node.a.id, ety); + check_expr(fcx, e); + auto ety = expr_ty(fcx.ccx.tcx, e); + write::ty_only_fixup(fcx, block.node.a.id, ety); } } @@ -2811,46 +2364,36 @@ fn check_block(&@stmt_ctxt scx, &ast::block block) { fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::ann ann) { // FIXME: this is kinda a kludge; we manufacture a fake function context // and statement context for checking the initializer expression. - auto rty = ann_to_type(ccx.tcx.node_types, ann); - let @fn_ctxt fcx = @rec(ret_ty = rty, - purity = ast::pure_fn, - locals = @common::new_def_hash[ty::t](), - ccx = ccx); - - with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, e)); + auto rty = ann_to_type(ccx.tcx, ann); + let vec[uint] fixups = []; + let @fn_ctxt fcx = @rec(ret_ty=rty, + purity=ast::pure_fn, + var_bindings=ty::unify::mk_var_bindings(), + locals=new_def_hash[int](), + local_names=new_def_hash[ast::ident](), + mutable next_var_id=0, + mutable fixups=fixups, + ccx=ccx); + + check_expr(fcx, e); } fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, - &ast::block body) { - auto local_ty_table = @common::new_def_hash[ty::t](); - - // FIXME: duplicate work: the item annotation already has the arg types - // and return type translated to typeck::ty values. We don't need do to it - // again here, we can extract them. - - alt (get_obj_info(ccx)) { - case (option::some(?oinfo)) { - for (ast::obj_field f in oinfo.obj_fields) { - auto field_ty = ty::ann_to_type(ccx.tcx.node_types, f.ann); - local_ty_table.insert(f.id, field_ty); - } - } - case (option::none) { /* no fields */ } - } - - // Store the type of each argument in the table. - for (ast::arg arg in decl.inputs) { - auto input_ty = ast_ty_to_ty_crate(ccx, arg.ty); - local_ty_table.insert(arg.id, input_ty); - } + &ast::block body, &ast::ann ann) { + auto gather_result = gather_locals(ccx, decl, body, ann); - let @fn_ctxt fcx = @rec(ret_ty = ast_ty_to_ty_crate(ccx, decl.output), - purity = decl.purity, - locals = local_ty_table, - ccx = ccx); + let vec[uint] fixups = []; + let @fn_ctxt fcx = @rec(ret_ty=ast_ty_to_ty_crate(ccx, decl.output), + purity=decl.purity, + var_bindings=gather_result.var_bindings, + locals=gather_result.locals, + local_names=gather_result.local_names, + mutable next_var_id=gather_result.next_var_id, + mutable fixups=fixups, + ccx=ccx); // TODO: Make sure the type of the block agrees with the function type. - with_stmt_ctxt(fcx, bind check_block(_, body)); + check_block(fcx, body); alt (decl.purity) { case (ast::pure_fn) { @@ -2864,12 +2407,12 @@ fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, case (_) {} } - writeback::resolve_local_types_in_block(fcx, body); + writeback::resolve_type_vars_in_block(fcx, body); } fn check_method(&@crate_ctxt ccx, &@ast::method method) { - check_fn(ccx, method.node.meth.decl, method.node.meth.proto, - method.node.meth.body); + auto m = method.node.meth; + check_fn(ccx, m.decl, m.proto, m.body, method.node.ann); } fn check_item(@crate_ctxt ccx, &@ast::item it) { @@ -2877,8 +2420,8 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) { case (ast::item_const(_, _, ?e, _, ?a)) { check_const(ccx, it.span, e, a); } - case (ast::item_fn(_, ?f, _, _, _)) { - check_fn(ccx, f.decl, f.proto, f.body); + case (ast::item_fn(_, ?f, _, _, ?a)) { + check_fn(ccx, f.decl, f.proto, f.body, a); } case (ast::item_obj(_, ?ob, _, ?obj_def_ids, _)) { // We're entering an object, so gather up the info we need. @@ -2899,37 +2442,6 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) { } } -// Utilities for the unification cache - -fn hash_unify_cache_entry(&unify_cache_entry uce) -> uint { - auto h = ty::hash_ty(uce._0); - h += h << 5u + ty::hash_ty(uce._1); - - auto i = 0u; - auto tys_len = vec::len(uce._2); - while (i < tys_len) { - h += h << 5u + ty::hash_ty(uce._2.(i)); - i += 1u; - } - - ret h; -} - -fn eq_unify_cache_entry(&unify_cache_entry a, &unify_cache_entry b) -> bool { - if (!ty::eq_ty(a._0, b._0) || !ty::eq_ty(a._1, b._1)) { ret false; } - - auto i = 0u; - auto tys_len = vec::len(a._2); - if (vec::len(b._2) != tys_len) { ret false; } - - while (i < tys_len) { - if (!ty::eq_ty(a._2.(i), b._2.(i))) { ret false; } - i += 1u; - } - - ret true; -} - fn mk_fn_purity_table(&@ast::crate crate) -> @fn_purity_table { auto res = @new_def_hash[ast::purity](); @@ -2957,26 +2469,16 @@ fn check_crate(&ty::ctxt tcx, &@ast::crate crate) { let vec[obj_info] obj_infos = []; - auto hasher = hash_unify_cache_entry; - auto eqer = eq_unify_cache_entry; - auto unify_cache = - map::mk_hashmap[unify_cache_entry,ty::unify::result](hasher, eqer); auto fpt = mk_fn_purity_table(crate); // use a variation on collect auto ccx = @rec(mutable obj_infos=obj_infos, fn_purity_table=fpt, - unify_cache=unify_cache, - mutable cache_hits=0u, - mutable cache_misses=0u, tcx=tcx); auto visit = rec(visit_item_pre = bind check_item(ccx, _) with walk::default_visitor()); walk::walk_crate(visit, *crate); - - log #fmt("cache hit rate: %u/%u", ccx.cache_hits, - ccx.cache_hits + ccx.cache_misses); } // diff --git a/src/comp/middle/visit.rs b/src/comp/middle/visit.rs new file mode 100644 index 0000000000000..79f74c8f3e890 --- /dev/null +++ b/src/comp/middle/visit.rs @@ -0,0 +1,381 @@ +import front::ast::*; +import std::option; +import std::option::some; +import std::option::none; +import util::common::span; + +// Lots of redundant indirection and refcounting. Our typesystem doesn't do +// circular types, so the visitor record can not hold functions that take +// visitors. A tag breaks the cycle. +tag vt[E] { vtor(visitor[E]); } +fn vt[E](&vt[E] x) -> visitor[E] { + alt (x) { case (vtor(?v)) { ret v; } } +} + +type visitor[E] = + @rec(fn(&_mod m, &span sp, &E e, &vt[E] v) visit_mod, + fn(&@native_item i, &E e, &vt[E] v) visit_native_item, + fn(&@item i, &E e, &vt[E] v) visit_item, + fn(&block b, &E e, &vt[E] v) visit_block, + fn(&@stmt s, &E e, &vt[E] v) visit_stmt, + fn(&arm a, &E e, &vt[E] v) visit_arm, + fn(&@pat p, &E e, &vt[E] v) visit_pat, + fn(&@decl d, &E e, &vt[E] v) visit_decl, + fn(&@expr ex, &E e, &vt[E] v) visit_expr, + fn(&@ty t, &E e, &vt[E] v) visit_ty, + fn(&_fn f, &span sp, &ident name, + &def_id d_id, &ann a, + &E e, &vt[E] v) visit_fn); + +fn default_visitor[E]() -> visitor[E] { + ret @rec(visit_mod = bind visit_mod[E](_, _, _, _), + visit_native_item = bind visit_native_item[E](_, _, _), + visit_item = bind visit_item[E](_, _, _), + visit_block = bind visit_block[E](_, _, _), + visit_stmt = bind visit_stmt[E](_, _, _), + visit_arm = bind visit_arm[E](_, _, _), + visit_pat = bind visit_pat[E](_, _, _), + visit_decl = bind visit_decl[E](_, _, _), + visit_expr = bind visit_expr[E](_, _, _), + visit_ty = bind visit_ty[E](_, _, _), + visit_fn = bind visit_fn[E](_, _, _, _, _, _, _)); +} + +fn visit_crate[E](&crate c, &E e, &vt[E] v) { + vt(v).visit_mod(c.node.module, c.span, e, v); +} + +fn visit_mod[E](&_mod m, &span sp, &E e, &vt[E] v) { + for (@item i in m.items) { + vt(v).visit_item(i, e, v); + } +} + +fn visit_item[E](&@item i, &E e, &vt[E] v) { + alt (i.node) { + case (item_const(_, ?t, ?ex, _, _)) { + vt(v).visit_ty(t, e, v); + vt(v).visit_expr(ex, e, v); + } + case (item_fn(?nm, ?f, _, ?d, ?a)) { + vt(v).visit_fn(f, i.span, nm, d, a, e, v); + } + case (item_mod(_, ?m, _)) { + vt(v).visit_mod(m, i.span, e, v); + } + case (item_native_mod(_, ?nm, _)) { + for (@native_item ni in nm.items) { + vt(v).visit_native_item(ni, e, v); + } + } + case (item_ty(_, ?t, _, _, _)) { + vt(v).visit_ty(t, e, v); + } + case (item_tag(_, ?variants, _, _, _)) { + for (variant vr in variants) { + for (variant_arg va in vr.node.args) { + vt(v).visit_ty(va.ty, e, v); + } + } + } + case (item_obj(_, ?ob, _, _, _)) { + for (obj_field f in ob.fields) { + vt(v).visit_ty(f.ty, e, v); + } + for (@method m in ob.methods) { + vt(v).visit_fn(m.node.meth, m.span, m.node.ident, m.node.id, + m.node.ann, e, v); + } + alt (ob.dtor) { + case (none) {} + case (some(?m)) { + vt(v).visit_fn(m.node.meth, m.span, m.node.ident, + m.node.id, m.node.ann, e, v); + } + } + } + + } +} + +fn visit_ty[E](&@ty t, &E e, &vt[E] v) { + alt (t.node) { + case (ty_box(?mt)) { vt(v).visit_ty(mt.ty, e, v); } + case (ty_vec(?mt)) { vt(v).visit_ty(mt.ty, e, v); } + case (ty_ptr(?mt)) { vt(v).visit_ty(mt.ty, e, v); } + case (ty_port(?t)) { vt(v).visit_ty(t, e, v); } + case (ty_chan(?t)) { vt(v).visit_ty(t, e, v); } + case (ty_tup(?mts)) { + for (mt mt in mts) { + vt(v).visit_ty(mt.ty, e, v); + } + } + case (ty_rec(?flds)) { + for (ty_field f in flds) { + vt(v).visit_ty(f.node.mt.ty, e, v); + } + } + case (ty_fn(_, ?args, ?out, _)) { + for (ty_arg a in args) { + vt(v).visit_ty(a.node.ty, e, v); + } + vt(v).visit_ty(out, e, v); + } + case (ty_obj(?tmeths)) { + for (ty_method m in tmeths) { + for (ty_arg a in m.node.inputs) { + vt(v).visit_ty(a.node.ty, e, v); + } + vt(v).visit_ty(m.node.output, e, v); + } + } + case (ty_path(?p, _)) { + for (@ty tp in p.node.types) { + vt(v).visit_ty(tp, e, v); + } + } + case (ty_constr(?t, _)) { vt(v).visit_ty(t, e, v); } + case (_) {} + } +} + +fn visit_pat[E](&@pat p, &E e, &vt[E] v) { + alt (p.node) { + case (pat_tag(?path, ?children, _)) { + for (@pat child in children) { + vt(v).visit_pat(child, e, v); + } + } + case (_) {} + } +} + +fn visit_native_item[E](&@native_item ni, &E e, &vt[E] v) { + alt (ni.node) { + case (native_item_fn(_, _, ?fd, _, _, _)) { + visit_fn_decl(fd, e, v); + } + case (native_item_ty(_, _)) {} + } +} + +fn visit_fn_decl[E](&fn_decl fd, &E e, &vt[E] v) { + for (arg a in fd.inputs) { + vt(v).visit_ty(a.ty, e, v); + } + vt(v).visit_ty(fd.output, e, v); +} + +fn visit_fn[E](&_fn f, &span sp, &ident i, &def_id d, &ann a, + &E e, &vt[E] v) { + visit_fn_decl(f.decl, e, v); + vt(v).visit_block(f.body, e, v); +} + +fn visit_block[E](&block b, &E e, &vt[E] v) { + for (@stmt s in b.node.stmts) { vt(v).visit_stmt(s, e, v); } + visit_expr_opt(b.node.expr, e, v); +} + +fn visit_stmt[E](&@stmt s, &E e, &vt[E] v) { + alt (s.node) { + case (stmt_decl(?d, _)) { vt(v).visit_decl(d, e, v); } + case (stmt_expr(?ex, _)) { vt(v).visit_expr(ex, e, v); } + case (stmt_crate_directive(?cdir)) {} + } +} + +fn visit_decl[E](&@decl d, &E e, &vt[E] v) { + alt (d.node) { + case (decl_local(?loc)) { + alt (loc.ty) { + case (none) {} + case (some(?t)) { vt(v).visit_ty(t, e, v); } + } + alt (loc.init) { + case (none) {} + case (some(?i)) { vt(v).visit_expr(i.expr, e, v); } + } + } + case (decl_item(?it)) { vt(v).visit_item(it, e, v); } + } +} + +fn visit_expr_opt[E](option::t[@expr] eo, &E e, &vt[E] v) { + alt (eo) { + case (none) {} + case (some(?ex)) { vt(v).visit_expr(ex, e, v); + } + } +} + +fn visit_exprs[E](vec[@expr] exprs, &E e, &vt[E] v) { + for (@expr ex in exprs) { vt(v).visit_expr(ex, e, v); } +} + +fn visit_expr[E](&@expr ex, &E e, &vt[E] v) { + alt (ex.node) { + case (expr_vec(?es, _, _)) { + visit_exprs(es, e, v); + } + case (expr_tup(?elts, _)) { + for (elt el in elts) { vt(v).visit_expr(el.expr, e, v); } + } + case (expr_rec(?flds, ?base, _)) { + for (field f in flds) { vt(v).visit_expr(f.node.expr, e, v); } + visit_expr_opt(base, e, v); + } + case (expr_call(?callee, ?args, _)) { + vt(v).visit_expr(callee, e, v); + visit_exprs(args, e, v); + } + case (expr_self_method(_, _)) { } + case (expr_bind(?callee, ?args, _)) { + vt(v).visit_expr(callee, e, v); + for (option::t[@expr] eo in args) { visit_expr_opt(eo, e, v); } + } + case (expr_spawn(_, _, ?callee, ?args, _)) { + vt(v).visit_expr(callee, e, v); + visit_exprs(args, e, v); + } + case (expr_binary(_, ?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_unary(_, ?a, _)) { + vt(v).visit_expr(a, e, v); + } + case (expr_lit(_, _)) { } + case (expr_cast(?x, ?t, _)) { + vt(v).visit_expr(x, e, v); + vt(v).visit_ty(t, e, v); + } + case (expr_if(?x, ?b, ?eo, _)) { + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + visit_expr_opt(eo, e, v); + } + case (expr_while(?x, ?b, _)) { + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + } + case (expr_for(?dcl, ?x, ?b, _)) { + vt(v).visit_decl(dcl, e, v); + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + } + case (expr_for_each(?dcl, ?x, ?b, _)) { + vt(v).visit_decl(dcl, e, v); + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + } + case (expr_do_while(?b, ?x, _)) { + vt(v).visit_block(b, e, v); + vt(v).visit_expr(x, e, v); + } + case (expr_alt(?x, ?arms, _)) { + vt(v).visit_expr(x, e, v); + for (arm a in arms) { + vt(v).visit_arm(a, e, v); + } + } + case (expr_block(?b, _)) { + vt(v).visit_block(b, e, v); + } + case (expr_assign(?a, ?b, _)) { + vt(v).visit_expr(b, e, v); + vt(v).visit_expr(a, e, v); + } + case (expr_move(?a, ?b, _)) { + vt(v).visit_expr(b, e, v); + vt(v).visit_expr(a, e, v); + } + case (expr_assign_op(_, ?a, ?b, _)) { + vt(v).visit_expr(b, e, v); + vt(v).visit_expr(a, e, v); + } + case (expr_send(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_recv(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_field(?x, _, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_index(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_path(?p, _)) { + for (@ty tp in p.node.types) { + vt(v).visit_ty(tp, e, v); + } + } + case (expr_ext(_, _, _, ?expansion, _)) { + vt(v).visit_expr(expansion, e, v); + } + case (expr_fail(_, _)) { } + case (expr_break(_)) { } + case (expr_cont(_)) { } + case (expr_ret(?eo, _)) { + visit_expr_opt(eo, e, v); + } + case (expr_put(?eo, _)) { + visit_expr_opt(eo, e, v); + } + case (expr_be(?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_log(_,?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_check(?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_assert(?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_port(_)) { } + case (expr_chan(?x, _)) { + vt(v).visit_expr(x, e, v); + } + + case (expr_anon_obj(?anon_obj,_,_,_)) { + alt (anon_obj.fields) { + case (none) { } + case (some(?fields)) { + for (obj_field f in fields) { + vt(v).visit_ty(f.ty, e, v); + } + } + } + alt (anon_obj.with_obj) { + case (none) { } + case (some(?ex)) { + vt(v).visit_expr(ex, e, v); + } + } + for (@method m in anon_obj.methods) { + vt(v).visit_fn(m.node.meth, m.span, m.node.ident, + m.node.id, m.node.ann, e, v); + } + } + } +} + +fn visit_arm[E](&arm a, &E e, &vt[E] v) { + vt(v).visit_pat(a.pat, e, v); + vt(v).visit_block(a.block, e, v); +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index e08a27f2dbade..214846a5ecf7a 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -68,7 +68,7 @@ fn walk_crate_directive(&ast_visitor v, @ast::crate_directive cd) { case (ast::cdir_view_item(?vi)) { walk_view_item(v, vi); } - case (ast::cdir_meta(_)) {} + case (ast::cdir_meta(_,_)) {} case (ast::cdir_syntax(_)) {} case (ast::cdir_auth(_, _)) {} } @@ -156,6 +156,7 @@ fn walk_ty(&ast_visitor v, @ast::ty t) { case (ast::ty_str) {} case (ast::ty_box(?mt)) { walk_ty(v, mt.ty); } case (ast::ty_vec(?mt)) { walk_ty(v, mt.ty); } + case (ast::ty_ptr(?mt)) { walk_ty(v, mt.ty); } case (ast::ty_task) {} case (ast::ty_port(?t)) { walk_ty(v, t); } case (ast::ty_chan(?t)) { walk_ty(v, t); } @@ -166,21 +167,21 @@ fn walk_ty(&ast_visitor v, @ast::ty t) { } case (ast::ty_rec(?flds)) { for (ast::ty_field f in flds) { - walk_ty(v, f.mt.ty); + walk_ty(v, f.node.mt.ty); } } case (ast::ty_fn(_, ?args, ?out, _)) { for (ast::ty_arg a in args) { - walk_ty(v, a.ty); + walk_ty(v, a.node.ty); } walk_ty(v, out); } case (ast::ty_obj(?tmeths)) { for (ast::ty_method m in tmeths) { - for (ast::ty_arg a in m.inputs) { - walk_ty(v, a.ty); + for (ast::ty_arg a in m.node.inputs) { + walk_ty(v, a.node.ty); } - walk_ty(v, m.output); + walk_ty(v, m.node.output); } } case (ast::ty_path(?p, _)) { @@ -430,7 +431,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { // Only walk expansion, not args/body. walk_expr(v, expansion); } - case (ast::expr_fail(_)) { } + case (ast::expr_fail(_, _)) { } case (ast::expr_break(_)) { } case (ast::expr_cont(_)) { } case (ast::expr_ret(?eo, _)) { diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 926435d29282d..db6d62bdbc848 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -204,7 +204,8 @@ fn commasep_cmnt[IN](&ps s, breaks b, vec[IN] elts, fn(&ps, &IN) op, i += 1u; if (i < len) { word(s.s, ","); - maybe_print_trailing_comment(s, get_span(elt)); + maybe_print_trailing_comment(s, get_span(elt), + some(get_span(elts.(i)).hi)); space(s.s); } } @@ -268,16 +269,13 @@ fn print_type(&ps s, &ast::ty ty) { popen(s); fn print_field(&ps s, &ast::ty_field f) { cbox(s, indent_unit); - print_mt(s, f.mt); + print_mt(s, f.node.mt); space(s.s); - word(s.s, f.ident); + word(s.s, f.node.ident); end(s); } fn get_span(&ast::ty_field f) -> common::span { - // Try to reconstruct the span for this field - auto sp = f.mt.ty.span; - auto hi = sp.hi + str::char_len(f.ident) + 1u; - ret rec(hi=hi with sp); + ret f.span; } auto f = print_field; auto gs = get_span; @@ -290,8 +288,9 @@ fn print_type(&ps s, &ast::ty ty) { for (ast::ty_method m in methods) { hardbreak(s.s); cbox(s, indent_unit); - print_ty_fn(s, m.proto, some(m.ident), - m.inputs, m.output, m.cf); + maybe_print_comment(s, m.span.lo); + print_ty_fn(s, m.node.proto, some(m.node.ident), + m.node.inputs, m.node.output, m.node.cf); word(s.s, ";"); end(s); } @@ -406,7 +405,7 @@ fn print_item(&ps s, &@ast::item item) { pclose(s); } word(s.s, ";"); - maybe_print_trailing_comment(s, v.span); + maybe_print_trailing_comment(s, v.span, none[uint]); } bclose(s, item.span); } @@ -471,13 +470,12 @@ fn print_stmt(&ps s, &ast::stmt st) { } } if (front::parser::stmt_ends_with_semi(st)) {word(s.s, ";");} - maybe_print_trailing_comment(s, st.span); + maybe_print_trailing_comment(s, st.span, none[uint]); } fn print_block(&ps s, ast::block blk) { maybe_print_comment(s, blk.span.lo); bopen(s); - auto first = true; for (@ast::stmt st in blk.node.stmts) { print_stmt(s, *st) @@ -486,7 +484,8 @@ fn print_block(&ps s, ast::block blk) { case (some(?expr)) { space(s.s); print_expr(s, expr); - maybe_print_trailing_comment(s, expr.span); + maybe_print_trailing_comment(s, expr.span, + some(blk.span.hi)); } case (_) {} } @@ -625,7 +624,6 @@ fn print_expr(&ps s, &@ast::expr expr) { } case (ast::expr_call(?func,?args,_)) { print_expr(s, func); - zerobreak(s.s); popen(s); commasep_exprs(s, inconsistent, args); pclose(s); @@ -827,8 +825,13 @@ fn print_expr(&ps s, &@ast::expr expr) { case (ast::expr_path(?path,_)) { print_path(s, path); } - case (ast::expr_fail(_)) { + case (ast::expr_fail(_, ?str)) { word(s.s, "fail"); + alt (str) { + case (some(?msg)) { + word(s.s, #fmt("\"%s\"", msg)); + } + } } case (ast::expr_break(_)) { word(s.s, "break"); @@ -947,7 +950,7 @@ fn print_decl(&ps s, &@ast::decl decl) { case (mo_untyped) { /* no-op */ } case (mo_typed(?tcx)) { auto lty = - ty::ann_to_type(tcx.node_types, loc.ann); + ty::ann_to_type(tcx, loc.ann); word_space(s, ty::ty_to_str(tcx, lty)); } case (mo_identified) { /* no-op */ } @@ -1208,13 +1211,17 @@ fn print_ty_fn(&ps s, &ast::proto proto, &option::t[str] id, if (proto == ast::proto_fn) {word(s.s, "fn");} else {word(s.s, "iter");} alt (id) { - case (some(?id)) {space(s.s); word(s.s, id);} + case (some(?id)) { + word(s.s, " "); + word(s.s, id); + } case (_) {} } + zerobreak(s.s); popen(s); fn print_arg(&ps s, &ast::ty_arg input) { - if (input.mode == ast::alias) {word(s.s, "&");} - print_type(s, *input.ty); + if (input.node.mode == ast::alias) {word(s.s, "&");} + print_type(s, *input.node.ty); } auto f = print_arg; commasep[ast::ty_arg](s, inconsistent, inputs, f); @@ -1262,7 +1269,8 @@ fn maybe_print_comment(&ps s, uint pos) { } } -fn maybe_print_trailing_comment(&ps s, common::span span) { +fn maybe_print_trailing_comment(&ps s, common::span span, + option::t[uint] next_pos) { auto cm; alt (s.cm) { case (some(?ccm)) { @@ -1276,9 +1284,14 @@ fn maybe_print_trailing_comment(&ps s, common::span span) { auto span_line = codemap::lookup_pos(cm, span.hi); auto comment_line = codemap::lookup_pos(cm, cmnt.pos); + auto next = cmnt.pos + 1u; + alt (next_pos) { + case (none) { } + case (some(?p)) { next = p; } + } if (span.hi < cmnt.pos && + cmnt.pos < next && span_line.line == comment_line.line) { - word(s.s, " "); print_comment(s, cmnt); s.cur_cmnt += 1u; } @@ -1325,6 +1338,7 @@ fn print_comment(&ps s, lexer::cmnt cmnt) { } case (lexer::trailing) { + word(s.s, " "); if (vec::len(cmnt.lines) == 1u) { word(s.s, cmnt.lines.(0)); hardbreak(s.s); diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 7fe5d603585e6..1b323182cf0cd 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -1,11 +1,14 @@ // -*- rust -*- -meta (name = "rustc", - desc = "The Rust compiler", - uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", - url = "http://rust-lang.org/src/rustc", - ver = "0.0.1"); +meta export (name = "rustc", + uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", + url = "http://rust-lang.org/src/rustc", + ver = "0.1"); + +meta (desc = "The Rust compiler", + license = "BSD"); + use std; @@ -13,9 +16,11 @@ mod middle { mod trans; mod ty; mod walk; + mod visit; mod metadata; mod resolve; mod typeck; + mod alias; mod tstate { mod ck; @@ -38,6 +43,7 @@ mod pretty { mod front { mod ast; mod creader; + mod ext; mod extfmt; mod extenv; mod codemap; diff --git a/src/lib/extfmt.rs b/src/lib/extfmt.rs index 2df831c0cab73..43ff490757b3d 100644 --- a/src/lib/extfmt.rs +++ b/src/lib/extfmt.rs @@ -78,7 +78,9 @@ mod ct { piece_conv(conv); } - fn parse_fmt_string(str s) -> vec[piece] { + type error_fn = fn (str) -> !; + + fn parse_fmt_string(str s, error_fn error) -> vec[piece] { let vec[piece] pieces = []; auto lim = str::byte_len(s); auto buf = ""; @@ -97,15 +99,14 @@ mod ct { if (str::eq(curr, "%")) { i += 1u; if (i >= lim) { - log_err "unterminated conversion at end of string"; - fail; + error("unterminated conversion at end of string"); } auto curr2 = str::substr(s, i, 1u); if (str::eq(curr2, "%")) { i += 1u; } else { buf = flush_buf(buf, pieces); - auto res = parse_conversion(s, i, lim); + auto res = parse_conversion(s, i, lim, error); pieces += [res._0]; i = res._1; } @@ -141,12 +142,13 @@ mod ct { }; } - fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) { + fn parse_conversion(str s, uint i, uint lim, + error_fn error) -> tup(piece, uint) { auto parm = parse_parameter(s, i, lim); auto flags = parse_flags(s, parm._1, lim); auto width = parse_count(s, flags._1, lim); auto prec = parse_precision(s, width._1, lim); - auto ty = parse_type(s, prec._1, lim); + auto ty = parse_type(s, prec._1, lim, error); ret tup(piece_conv(rec(param = parm._0, flags = flags._0, width = width._0, @@ -258,10 +260,9 @@ mod ct { }; } - fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) { + fn parse_type(str s, uint i, uint lim, error_fn error) -> tup(ty, uint) { if (i >= lim) { - log_err "missing type in conversion"; - fail; + error("missing type in conversion"); } auto tstr = str::substr(s, i, 1u); @@ -287,7 +288,8 @@ mod ct { } else if (str::eq(tstr, "o")) { ty_octal } else { - log_err "unknown type in conversion"; + // FIXME: Shouldn't need explicit fail here. Issue #542 + error("unknown type in conversion: " + tstr); fail }; diff --git a/src/lib/fs.rs b/src/lib/fs.rs index d051d574fd2f1..92e90e62cbf42 100644 --- a/src/lib/fs.rs +++ b/src/lib/fs.rs @@ -19,6 +19,20 @@ fn dirname(path p) -> path { ret str::substr(p, 0u, i as uint); } +fn basename(path p) -> path { + let int i = str::rindex(p, os_fs::path_sep as u8); + if (i == -1) { + i = str::rindex(p, os_fs::alt_path_sep as u8); + if (i == -1) { + ret p; + } + } + auto len = str::byte_len(p); + if ((i+1) as uint >= len) { ret p; } + + ret str::slice(p, i+1 as uint, len); +} + // FIXME: Need some typestate to avoid bounds check when len(pre) == 0 fn connect(path pre, path post) -> path { auto len = str::byte_len(pre); diff --git a/src/lib/map.rs b/src/lib/map.rs index 3b7f01acbe19c..854ab74df9a81 100644 --- a/src/lib/map.rs +++ b/src/lib/map.rs @@ -76,8 +76,10 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { let uint j = hash(h, nbkts, i); alt (bkts.(j)) { case (some(?k, _)) { - if (eqer(key, k)) { - bkts.(j) = some[K, V](k, val); + // Copy key to please alias analysis. + auto k_ = k; + if (eqer(key, k_)) { + bkts.(j) = some[K, V](k_, val); ret false; } i += 1u; @@ -104,8 +106,11 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { let uint j = (hash(h, nbkts, i)); alt (bkts.(j)) { case (some(?k, ?v)) { - if (eqer(key, k)) { - ret option::some[V](v); + // Copy to please alias analysis. + auto k_ = k; + auto v_ = v; + if (eqer(key, k_)) { + ret option::some[V](v_); } } case (nil) { @@ -126,7 +131,8 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { { for (bucket[K, V] b in oldbkts) { alt (b) { - case (some(?k, ?v)) { + case (some(?k_, ?v_)) { + auto k = k_; auto v = v_; insert_common[K, V](hasher, eqer, newbkts, nnewbkts, k, v); } @@ -190,10 +196,11 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { let uint j = (hash(h, nbkts, i)); alt (bkts.(j)) { case (some(?k, ?v)) { - if (eqer(key, k)) { + auto k_ = k; auto vo = option::some(v); + if (eqer(key, k_)) { bkts.(j) = deleted[K, V]; nelts -= 1u; - ret option::some[V](v); + ret vo; } } case (deleted) { } diff --git a/src/lib/smallintmap.rs b/src/lib/smallintmap.rs new file mode 100644 index 0000000000000..49e9efa20f4c5 --- /dev/null +++ b/src/lib/smallintmap.rs @@ -0,0 +1,44 @@ +/// A simple map based on a vector for small integer keys. Space requirements +/// are O(highest integer key). + +import option::none; +import option::some; + +type smallintmap[T] = rec(mutable vec[mutable option::t[T]] v); + +fn mk[T]() -> smallintmap[T] { + let vec[mutable option::t[T]] v = [mutable]; + ret rec(mutable v=v); +} + +fn insert[T](&smallintmap[T] m, uint key, &T val) { + vec::grow_set[option::t[T]](m.v, key, none[T], some[T](val)); +} + +fn find[T](&smallintmap[T] m, uint key) -> option::t[T] { + if (key < vec::len[option::t[T]](m.v)) { ret m.v.(key); } + ret none[T]; +} + +fn get[T](&smallintmap[T] m, uint key) -> T { + alt (find[T](m, key)) { + case (none[T]) { + log_err "smallintmap::get(): key not present"; + fail; + } + case (some[T](?v)) { ret v; } + } +} + +fn contains_key[T](&smallintmap[T] m, uint key) -> bool { + ret !option::is_none(find[T](m, key)); +} + +fn truncate[T](&smallintmap[T] m, uint len) { + m.v = vec::slice_mut[option::t[T]](m.v, 0u, len); +} + +fn max_key[T](&smallintmap[T] m) -> uint { + ret vec::len[option::t[T]](m.v); +} + diff --git a/src/lib/sort.rs b/src/lib/sort.rs index ede8d229fa599..8a16c1858becb 100644 --- a/src/lib/sort.rs +++ b/src/lib/sort.rs @@ -58,7 +58,7 @@ fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left, let uint storage_index = left; let uint i = left; while (i uint { ret idx; } +/// Creates sets as necessary to ensure that least `n` sets are present in the +/// data structure. +fn grow(&ufind ufnd, uint n) { + while (set_count(ufnd) < n) { make_set(ufnd); } +} + fn find(&ufind ufnd, uint n) -> uint { alt (ufnd.nodes.(n)) { case (none) { ret n; } - case (some(?m)) { be find(ufnd, m); } + case (some(?m)) { auto m_ = m; be find(ufnd, m_); } } } @@ -37,12 +43,17 @@ fn union(&ufind ufnd, uint m, uint n) { } } +fn set_count(&ufind ufnd) -> uint { + ret vec::len[node](ufnd.nodes); +} + // Removes all sets with IDs greater than or equal to the given value. fn prune(&ufind ufnd, uint n) { // TODO: Use "slice" once we get rid of "mutable?" - while (n != 0u) { + auto len = vec::len[node](ufnd.nodes); + while (len != n) { vec::pop[node](ufnd.nodes); - n -= 1u; + len -= 1u; } } diff --git a/src/lib/uint.rs b/src/lib/uint.rs index 044eeff4fc4d4..c5aeb49d80b72 100644 --- a/src/lib/uint.rs +++ b/src/lib/uint.rs @@ -12,6 +12,11 @@ fn ne(uint x, uint y) -> bool { ret x != y; } fn ge(uint x, uint y) -> bool { ret x >= y; } fn gt(uint x, uint y) -> bool { ret x > y; } +fn max(uint x, uint y) -> uint { + if (x > y) { ret x; } + ret y; +} + iter range(uint lo, uint hi) -> uint { auto lo_ = lo; while (lo_ < hi) { diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 969fca9a17ed5..742562f17a93f 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -163,6 +163,19 @@ fn slice[T](array[T] v, uint start, uint end) -> vec[T] { ret result; } +// FIXME: Should go away eventually. +fn slice_mut[T](array[T] v, uint start, uint end) -> vec[mutable T] { + assert (start <= end); + assert (end <= len[T](v)); + auto result = alloc_mut[T](end - start); + let uint i = start; + while (i < end) { + result += [mutable v.(i)]; + i += 1u; + } + ret result; +} + fn shift[T](&mutable array[T] v) -> T { auto ln = len[T](v); assert (ln > 0u); @@ -180,6 +193,12 @@ fn pop[T](&mutable array[T] v) -> T { ret e; } +fn top[T](&array[T] v) -> T { + auto ln = len[T](v); + assert (ln > 0u); + ret v.(ln-1u); +} + fn push[T](&mutable array[T] v, &T t) { v += [t]; } @@ -191,7 +210,7 @@ fn unshift[T](&mutable array[T] v, &T t) { v = res; } -fn grow[T](&array[T] v, uint n, &T initval) { +fn grow[T](&mutable array[T] v, uint n, &T initval) { let uint i = n; while (i > 0u) { i -= 1u; @@ -199,7 +218,7 @@ fn grow[T](&array[T] v, uint n, &T initval) { } } -fn grow_set[T](&vec[mutable T] v, uint index, &T initval, &T val) { +fn grow_set[T](&mutable vec[mutable T] v, uint index, &T initval, &T val) { auto length = vec::len(v); if (index >= length) { grow(v, index - length + 1u, initval); @@ -222,7 +241,7 @@ fn grow_init_fn_set[T](&array[T] v, uint index, fn()->T init_fn, &T val) { } -fn map[T, U](&fn(&T) -> U f, &array[T] v) -> vec[U] { +fn map[T, U](&fn(&T) -> U f, &vec[T] v) -> vec[U] { let vec[U] res = alloc[U](len[T](v)); for (T ve in v) { res += [f(ve)]; @@ -230,8 +249,8 @@ fn map[T, U](&fn(&T) -> U f, &array[T] v) -> vec[U] { ret res; } -fn filter_map[T, U](&fn(&T) -> option::t[U] f, &array[T] v) -> vec[U] { - let vec[U] res = []; //TODO does this work these days? +fn filter_map[T, U](&fn(&T) -> option::t[U] f, &vec[T] v) -> vec[U] { + let vec[U] res = []; for(T ve in v) { alt(f(ve)) { case (some(?elt)) { res += [elt]; } @@ -241,7 +260,7 @@ fn filter_map[T, U](&fn(&T) -> option::t[U] f, &array[T] v) -> vec[U] { ret res; } -fn map2[T,U,V](&operator2[T,U,V] f, &array[T] v0, &array[U] v1) -> vec[V] { +fn map2[T,U,V](&operator2[T,U,V] f, &vec[T] v0, &vec[U] v1) -> vec[V] { auto v0_len = len[T](v0); if (v0_len != len[U](v1)) { fail; @@ -250,14 +269,14 @@ fn map2[T,U,V](&operator2[T,U,V] f, &array[T] v0, &array[U] v1) -> vec[V] { let vec[V] u = alloc[V](v0_len); auto i = 0u; while (i < v0_len) { - u += [f(v0.(i), v1.(i))]; + u += [f({v0.(i)}, {v1.(i)})]; i += 1u; } ret u; } -fn find[T](fn (&T) -> bool f, &array[T] v) -> option::t[T] { +fn find[T](fn (&T) -> bool f, &vec[T] v) -> option::t[T] { for (T elt in v) { if (f(elt)) { ret some[T](elt); @@ -267,6 +286,13 @@ fn find[T](fn (&T) -> bool f, &array[T] v) -> option::t[T] { ret none[T]; } +fn member[T](&T x, &array[T] v) -> bool { + for (T elt in v) { + if (x == elt) { ret true; } + } + ret false; +} + fn foldl[T, U](fn (&U, &T) -> U p, &U z, &vec[T] v) -> U { auto sz = len[T](v); @@ -374,6 +400,12 @@ fn reversed[T](vec[T] v) -> vec[T] { ret res; } +/// Truncates the vector to length `new_len`. +/// FIXME: This relies on a typechecker bug (covariance vs. invariance). +fn truncate[T](&mutable vec[mutable? T] v, uint new_len) { + v = slice[T](v, 0u, new_len); +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/rt/main.ll.in b/src/rt/main.ll.in new file mode 100644 index 0000000000000..d956fb8681724 --- /dev/null +++ b/src/rt/main.ll.in @@ -0,0 +1,24 @@ +%0 = type { i32, [1 x i32] } +%1 = type { i32, i32 } +%2 = type { i32, %3 } +%3 = type { %tydesc*, %4, i1, {} } +%4 = type { i1*, i1* } +%5 = type { i32, i32, i32, i32, [0 x %6*] } +%6 = type { i32, i32, i32, i32, [0 x i8] } + + +@_rust_crate_map_toplevel = external global %0 + +declare fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %5*); +declare i32 @rust_start(i32, i32, i32, i32) + +%tydesc = type { %tydesc**, i32, i32, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*, i8*, i8)* } + +%task = type { i32, i32, i32, i32, i32, i32, i32, i32 } + +@_rust_fetch_this_object_hack = global i32 0 + +define i32 @"MAIN"(i32, i32) { + %3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %5*)* @_rust_main to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32)) + ret i32 %3 +} diff --git a/src/rustllvm/Passes2.cpp b/src/rustllvm/Passes2.cpp index c4ead0de5aa92..dcc549b511f6b 100644 --- a/src/rustllvm/Passes2.cpp +++ b/src/rustllvm/Passes2.cpp @@ -1,5 +1,5 @@ #include "llvm/Analysis/Passes.h" -#include "llvm/Support/StandardPasses.h" +#include "llvm/Support/PassManagerBuilder.h" #include "llvm/PassManager.h" #include "llvm-c/Core.h" #include @@ -8,22 +8,29 @@ using namespace llvm; extern "C" void LLVMAddStandardFunctionPasses(LLVMPassManagerRef PM, unsigned int OptimizationLevel) { - createStandardFunctionPasses(unwrap(PM), OptimizationLevel); + PassManagerBuilder PMBuilder; + PMBuilder.OptLevel = OptimizationLevel; + FunctionPassManager *FPM = (FunctionPassManager*) unwrap(PM); + PMBuilder.populateFunctionPassManager(*FPM); } extern "C" void LLVMAddStandardModulePasses(LLVMPassManagerRef PM, unsigned int OptimizationLevel, LLVMBool OptimizeSize, LLVMBool UnitAtATime, LLVMBool UnrollLoops, LLVMBool SimplifyLibCalls, - LLVMBool HaveExceptions, unsigned int InliningThreshold) { - Pass *InliningPass; + unsigned int InliningThreshold) { + + PassManagerBuilder PMBuilder; + PMBuilder.OptLevel = OptimizationLevel; + PMBuilder.SizeLevel = OptimizeSize; + PMBuilder.DisableUnitAtATime = !UnitAtATime; + PMBuilder.DisableUnrollLoops = !UnrollLoops; + + PMBuilder.DisableSimplifyLibCalls = !SimplifyLibCalls; + if (InliningThreshold) - InliningPass = createFunctionInliningPass(InliningThreshold); - else - InliningPass = NULL; + PMBuilder.Inliner = createFunctionInliningPass(InliningThreshold); - createStandardModulePasses(unwrap(PM), OptimizationLevel, OptimizeSize, - UnitAtATime, UnrollLoops, SimplifyLibCalls, - HaveExceptions, InliningPass); + PassManager *MPM = (PassManager*) unwrap(PM); + PMBuilder.populateModulePassManager(*MPM); } - diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 2c50a6ccfa732..eb06398c48e64 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -47,7 +47,7 @@ extern "C" const char *LLVMRustGetLastError(void) { extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM); extern "C" void LLVMAddStandardModulePasses(LLVMPassManagerRef PM, unsigned int OptimizationLevel, bool OptimizeSize, bool UnitAtATime, - bool UnrollLoops, bool SimplifyLibCalls, bool HaveExceptions, + bool UnrollLoops, bool SimplifyLibCalls, unsigned int InliningThreshold); int *RustHackToFetchPassesO = (int*)LLVMAddBasicAliasAnalysisPass; @@ -80,7 +80,6 @@ extern "C" void LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, LLVMCodeGenFileType FileType) { // Set compilation options. - llvm::UnwindTablesMandatory = true; llvm::NoFramePointerElim = true; InitializeAllTargets(); diff --git a/src/snapshots.txt b/src/snapshots.txt index ab954d630f7dc..e1199383ea6a5 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,18 @@ +S 2011-06-08 f54f279 + linux-i386 4a13693dc548c764e3b662a90d52e57359e3bc91 + macos-i386 e0bd0fd650a194c361881cf62c4af33c78276939 + winnt-i386 5c3c2a634ad2fed5b3987fb0e9de7fd75c510bd4 + +S 2011-06-07 a4ca75e + linux-i386 3de95184c59f5b0554df3da995090aaba26a190f + macos-i386 1537f2e01c746dc6ca2a9bfb4b2e81256bb01e96 + winnt-i386 538765c5c4c31dfe8d6e998ef7503beb5cfa1525 + +S 2011-06-03 f29d046 + linux-i386 76e4ee5b9148aae30ebfaabb12791bfee4fa8727 + macos-i386 e146fa18f4b0f22fe4fd7fd104242837569d7702 + winnt-i386 d1d4560c449d675c22601a1377b3c12389272e5d + S 2011-06-01 a6ca9c2 linux-i386 64569e47e1693a6e100d62fd31258c1d6ba3ea17 macos-i386 e36a8d3d8365bc353ed2477d5c52656c1e8541df diff --git a/src/test/compile-fail/arg-count-mismatch.rs b/src/test/compile-fail/arg-count-mismatch.rs index 18f4104e33cae..103335380b21b 100644 --- a/src/test/compile-fail/arg-count-mismatch.rs +++ b/src/test/compile-fail/arg-count-mismatch.rs @@ -1,4 +1,4 @@ -// error-pattern: mismatched types +// error-pattern: parameters were supplied fn f(int x) { } diff --git a/src/test/compile-fail/ext-nonexistent.rs b/src/test/compile-fail/ext-nonexistent.rs new file mode 100644 index 0000000000000..9a7591ab7cebd --- /dev/null +++ b/src/test/compile-fail/ext-nonexistent.rs @@ -0,0 +1,4 @@ +// error-pattern:unknown syntax expander +fn main() { + #iamnotanextensionthatexists(""); +} diff --git a/src/test/compile-fail/extenv-no-args.rs b/src/test/compile-fail/extenv-no-args.rs new file mode 100644 index 0000000000000..2503a631c048a --- /dev/null +++ b/src/test/compile-fail/extenv-no-args.rs @@ -0,0 +1,5 @@ +// error-pattern:malformed #env call + +fn main() { + #env(); +} diff --git a/src/test/compile-fail/extenv-not-string-literal.rs b/src/test/compile-fail/extenv-not-string-literal.rs new file mode 100644 index 0000000000000..885924c83781e --- /dev/null +++ b/src/test/compile-fail/extenv-not-string-literal.rs @@ -0,0 +1,5 @@ +// error-pattern:malformed #env call + +fn main() { + #env(10); +} diff --git a/src/test/compile-fail/extenv-too-many-args.rs b/src/test/compile-fail/extenv-too-many-args.rs new file mode 100644 index 0000000000000..e71d0ec3c724e --- /dev/null +++ b/src/test/compile-fail/extenv-too-many-args.rs @@ -0,0 +1,5 @@ +// error-pattern:malformed #env call + +fn main() { + #env("one", "two"); +} diff --git a/src/test/compile-fail/extfmt-missing-type.rs b/src/test/compile-fail/extfmt-missing-type.rs new file mode 100644 index 0000000000000..8f82e3317e19e --- /dev/null +++ b/src/test/compile-fail/extfmt-missing-type.rs @@ -0,0 +1,5 @@ +// error-pattern:missing type + +fn main() { + #fmt("%+"); +} diff --git a/src/test/compile-fail/extfmt-no-args.rs b/src/test/compile-fail/extfmt-no-args.rs new file mode 100644 index 0000000000000..d31939ead1b25 --- /dev/null +++ b/src/test/compile-fail/extfmt-no-args.rs @@ -0,0 +1,6 @@ +// xfail-stage0 +// error-pattern:format string + +fn main() { + #fmt(); +} diff --git a/src/test/compile-fail/extfmt-non-literal2.rs b/src/test/compile-fail/extfmt-non-literal2.rs new file mode 100644 index 0000000000000..218263973d6b2 --- /dev/null +++ b/src/test/compile-fail/extfmt-non-literal2.rs @@ -0,0 +1,9 @@ +// xfail-stage0 +// error-pattern: literal + +fn main() { + // #fmt's first argument must be a literal. Hopefully this + // restriction can be eased eventually to just require a + // compile-time constant. + auto x = #fmt(20); +} diff --git a/src/test/compile-fail/extfmt-not-enough-args.rs b/src/test/compile-fail/extfmt-not-enough-args.rs new file mode 100644 index 0000000000000..80aad7bc03c5a --- /dev/null +++ b/src/test/compile-fail/extfmt-not-enough-args.rs @@ -0,0 +1,8 @@ +// xfail-stage0 +// error-pattern:not enough arguments + +use std; + +fn main() { + auto s = #fmt("%s%s%s", "test", "test"); +} diff --git a/src/test/compile-fail/extfmt-unknown-type.rs b/src/test/compile-fail/extfmt-unknown-type.rs new file mode 100644 index 0000000000000..08d5da0a496a6 --- /dev/null +++ b/src/test/compile-fail/extfmt-unknown-type.rs @@ -0,0 +1,5 @@ +// error-pattern:unknown type + +fn main() { + #fmt("%w"); +} diff --git a/src/test/compile-fail/extfmt-unsigned-plus.rs b/src/test/compile-fail/extfmt-unsigned-plus.rs new file mode 100644 index 0000000000000..a74f4dbfca0b1 --- /dev/null +++ b/src/test/compile-fail/extfmt-unsigned-plus.rs @@ -0,0 +1,7 @@ +// xfail-stage0 +// error-pattern:only valid in signed #fmt conversion + +fn main() { + // Can't use a sign on unsigned conversions + #fmt("%+u", 10u); +} diff --git a/src/test/compile-fail/extfmt-unsigned-space.rs b/src/test/compile-fail/extfmt-unsigned-space.rs new file mode 100644 index 0000000000000..bd1b6c97968e0 --- /dev/null +++ b/src/test/compile-fail/extfmt-unsigned-space.rs @@ -0,0 +1,7 @@ +// xfail-stage0 +// error-pattern:only valid in signed #fmt conversion + +fn main() { + // Can't use a space on unsigned conversions + #fmt("% u", 10u); +} diff --git a/src/test/compile-fail/extfmt-unterminated-conv.rs b/src/test/compile-fail/extfmt-unterminated-conv.rs new file mode 100644 index 0000000000000..8c75c75f9fda4 --- /dev/null +++ b/src/test/compile-fail/extfmt-unterminated-conv.rs @@ -0,0 +1,5 @@ +// error-pattern:unterminated conversion + +fn main() { + #fmt("%"); +} diff --git a/src/test/compile-fail/pattern-tyvar.rs b/src/test/compile-fail/pattern-tyvar.rs index cb94ee5c173e6..70da34713c7f5 100644 --- a/src/test/compile-fail/pattern-tyvar.rs +++ b/src/test/compile-fail/pattern-tyvar.rs @@ -1,3 +1,6 @@ +// xfail-stage0 +// xfail-stage1 +// xfail-stage2 // -*- rust -*- use std; import std::option; diff --git a/src/test/compile-fail/unsafe-alias-2.rs b/src/test/compile-fail/unsafe-alias-2.rs new file mode 100644 index 0000000000000..4a9551a9130f1 --- /dev/null +++ b/src/test/compile-fail/unsafe-alias-2.rs @@ -0,0 +1,15 @@ +// error-pattern:invalidate alias x + +fn whoknows(@mutable int x) { + *x = 10; +} + +fn main() { + auto box = @mutable 1; + alt (*box) { + case (?x) { + whoknows(box); + log_err x; + } + } +} diff --git a/src/test/compile-fail/unsafe-alias.rs b/src/test/compile-fail/unsafe-alias.rs new file mode 100644 index 0000000000000..a81b490266d84 --- /dev/null +++ b/src/test/compile-fail/unsafe-alias.rs @@ -0,0 +1,14 @@ +// error-pattern:may alias with argument + +fn foo(&int x, fn() f) { + log x; +} + +fn whoknows(@mutable int x) { + *x = 10; +} + +fn main() { + auto box = @mutable 1; + foo(*box, bind whoknows(box)); +} diff --git a/src/test/compile-fail/unsafe-alt.rs b/src/test/compile-fail/unsafe-alt.rs new file mode 100644 index 0000000000000..4144e3751db0b --- /dev/null +++ b/src/test/compile-fail/unsafe-alt.rs @@ -0,0 +1,17 @@ +// error-pattern:invalidate alias i + +tag foo { + left(int); + right(bool); +} + +fn main() { + auto x = left(10); + alt (x) { + case (left(?i)) { + x = right(false); + log i; + } + case (_) {} + } +} diff --git a/src/test/compile-fail/unsafe-for.rs b/src/test/compile-fail/unsafe-for.rs new file mode 100644 index 0000000000000..bc050173bc0df --- /dev/null +++ b/src/test/compile-fail/unsafe-for.rs @@ -0,0 +1,9 @@ +// error-pattern:invalidate alias x + +fn main() { + let vec[mutable int] v = [mutable 1, 2, 3]; + for (int x in v) { + v.(0) = 10; + log x; + } +} diff --git a/src/test/compile-fail/vector-no-ann.rs b/src/test/compile-fail/vector-no-ann.rs index 912fb0a388ace..b492f103c2034 100644 --- a/src/test/compile-fail/vector-no-ann.rs +++ b/src/test/compile-fail/vector-no-ann.rs @@ -1,6 +1,6 @@ // xfail-stage0 -// error-pattern:Ambiguous type +// error-pattern:cannot determine a type fn main() -> () { auto foo = []; } diff --git a/src/test/run-fail/explicit-fail-msg.rs b/src/test/run-fail/explicit-fail-msg.rs new file mode 100644 index 0000000000000..e37cf5d58f516 --- /dev/null +++ b/src/test/run-fail/explicit-fail-msg.rs @@ -0,0 +1,5 @@ +// error-pattern:woooo + +fn main() { + fail "woooo"; +} diff --git a/src/test/run-pass/ret-none.rs b/src/test/run-pass/ret-none.rs new file mode 100644 index 0000000000000..cc9f3020f4dcb --- /dev/null +++ b/src/test/run-pass/ret-none.rs @@ -0,0 +1,6 @@ +tag option[T] { none; some(T); } + +fn f[T]() -> option[T] { ret none; } + +fn main() { f[int](); } + diff --git a/src/test/run-pass/str-multiline.rs b/src/test/run-pass/str-multiline.rs new file mode 100644 index 0000000000000..c5ad5b15119cf --- /dev/null +++ b/src/test/run-pass/str-multiline.rs @@ -0,0 +1,15 @@ +// -*- rust -*- + +use std; +import std::str; + +fn main() { + let str a = "this \ +is a test"; + let str b = "this \ + is \ + another \ + test"; + assert (str::eq(a, "this is a test")); + assert (str::eq(b, "this is another test")); +} \ No newline at end of file diff --git a/src/test/run-pass/type-ptr.rs b/src/test/run-pass/type-ptr.rs new file mode 100644 index 0000000000000..3743fb115e884 --- /dev/null +++ b/src/test/run-pass/type-ptr.rs @@ -0,0 +1,12 @@ +fn f(*int a) -> *int { + ret a; +} + +fn g(*int a) -> *int { + auto b = f(a); + ret b; +} + +fn main(vec[str] args) { + ret; +}