From df9cf0be9b898bc3432d444826ff05d6d0e22f97 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 7 Jun 2011 04:53:47 -0400 Subject: [PATCH 1/8] Add multiline, whitespace-eating strings. --- src/comp/front/lexer.rs | 3 +++ src/test/run-pass/str-multiline.rs | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/run-pass/str-multiline.rs diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs index b6f5ab9e9c3..08409bea14c 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/test/run-pass/str-multiline.rs b/src/test/run-pass/str-multiline.rs new file mode 100644 index 00000000000..c5ad5b15119 --- /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 From b1d6f12a050ea0c99f13a1eb58c06577559cc76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Tue, 7 Jun 2011 16:41:19 -0400 Subject: [PATCH 2/8] Don't put a copy of main (the C one) in each binary we produce. This is a step in getting a driver that works on all linux systems. Sorry for the linker hacks, I will remove them after snapshotting a new compiler. --- Makefile.in | 6 +-- mk/clean.mk | 2 + mk/rt.mk | 12 ++++++ mk/stage1.mk | 2 +- mk/stage2.mk | 2 +- mk/stage3.mk | 4 +- mk/tests.mk | 6 +-- src/comp/middle/trans.rs | 85 ++++++++++++++-------------------------- src/rt/main.ll.in | 24 ++++++++++++ 9 files changed, 77 insertions(+), 66 deletions(-) create mode 100644 src/rt/main.ll.in diff --git a/Makefile.in b/Makefile.in index ecff84dc4c0..362b97ea036 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.a stage1/glue.o stage1/$(CFG_STDLIB) +SREQ1 := stage1/rustc$(X) $(LREQ) rt/main.a stage2/glue.o stage2/$(CFG_STDLIB) +SREQ2 := stage2/rustc$(X) $(LREQ) rt/main.a stage3/glue.o stage3/$(CFG_STDLIB) ###################################################################### diff --git a/mk/clean.mk b/mk/clean.mk index 3f19953929e..305b06b5e0a 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -28,6 +28,8 @@ 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 -f rt/main.a $(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 8139f9e4e79..1cc6dfb57f4 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -76,6 +76,18 @@ 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/main.a: rt/main.o + rm -f $@ + ar crs $@ $^ + 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 f2ca6321d94..c98882e41a8 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.a -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 e084a19a8d3..0d87400c1e2 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.a -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 dc2792446e2..77d09440883 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.a -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 5e30b352dfa..db7a3dd4d33 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.a -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.a -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.a -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/middle/trans.rs b/src/comp/middle/trans.rs index 4230032f7ee..a65b1403b38 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -338,6 +338,9 @@ fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { fn mangle(&vec[str] ss) -> str { + if (vec::len(ss) > 0u && str::eq(vec::top(ss), "main")) { + ret "_rust_main"; + } // Follow C++ namespace-mangling style auto n = "_ZN"; // Begin name-sequence. @@ -369,7 +372,7 @@ fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, ret mangle(path + [ccx.names.next(flav)]); } -fn mangle_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str { +fn mangle_name_by_path(&vec[str] path) -> str { ret mangle(path); } @@ -7095,7 +7098,7 @@ fn create_vtbl(@local_ctxt cx, let @local_ctxt mcx = @rec(path = cx.path + ["method", m.node.ident] with *cx); - let str s = mangle_name_by_path(mcx.ccx, mcx.path); + let str s = mangle_name_by_path(mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(m.node.id, llfn); @@ -7107,7 +7110,7 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_path(cx.ccx, cx.path + ["vtbl"]); + auto vtbl_name = mangle_name_by_path(cx.path + ["vtbl"]); auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name)); llvm::LLVMSetInitializer(gvar, vtbl); @@ -7124,7 +7127,7 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let str s = mangle_name_by_path(cx.ccx, cx.path + ["drop"]); + let str s = mangle_name_by_path(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); @@ -7518,7 +7521,7 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } // Declare the function itself. - let str s = mangle_name_by_path(ccx, path); + let str s = mangle_name_by_path(path); let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty); // Declare the global constant pair that points to it. @@ -7532,6 +7535,8 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, ccx.sess.span_err(sp, "multiple 'main' functions"); } log #fmt("registering %s as main function for crate", ps); + llvm::LLVMSetLinkage(llfn, lib::llvm::LLVMExternalLinkage + as llvm::Linkage); ccx.main_fn = some(llfn); } } @@ -7593,7 +7598,7 @@ 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_path(ccx, path); + let str s = mangle_name_by_path(path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type); @@ -7996,51 +8001,6 @@ fn create_typedefs(&@crate_ctxt cx) { llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn)); } -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 = alt (cx.ccx.main_fn) { - case (none) { - cx.ccx.sess.err("missing 'main' function"); - // FIXME: shouldn't sess.err's ! result unify with f? - C_nil() - } - case (some(?f)) { f } - }; - - // - // 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()), @@ -8211,8 +8171,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)]); @@ -8245,7 +8203,14 @@ 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 cname = crate_name(ccx, "__none__"); + auto mapname; + if (ccx.sess.get_opts().shared) { + mapname = cname; + } 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)); @@ -8322,9 +8287,17 @@ 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); - } + auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, T_ptr(T_int()), + str::buf("_rust_fetch_this_object_hack")); + + auto gvar2 = llvm::LLVMAddGlobal(cx.ccx.llmod, T_ptr(T_ptr(T_int())), + str::buf("_rust_fetch_this_object_hack2")); + llvm::LLVMSetInitializer(gvar2, gvar); + llvm::LLVMSetGlobalConstant(gvar, True); + llvm::LLVMSetGlobalConstant(gvar2, True); + } emit_tydescs(ccx); diff --git a/src/rt/main.ll.in b/src/rt/main.ll.in new file mode 100644 index 00000000000..d956fb86817 --- /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 +} From ab69c4a98f630c9f82d5cb21e336ff3620b76d45 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 7 Jun 2011 13:50:30 -0700 Subject: [PATCH 3/8] Removing dead code and redundant fails; changing fails to sess.bug calls (issue #444). --- src/comp/middle/trans.rs | 32 +++--- src/comp/middle/tstate/auxiliary.rs | 2 +- src/comp/middle/ty.rs | 146 ++++++++-------------------- src/comp/middle/typeck.rs | 69 ++++++------- src/comp/pretty/pprust.rs | 2 +- 5 files changed, 93 insertions(+), 158 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a65b1403b38..7333375b902 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3687,13 +3687,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 { @@ -3704,13 +3702,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, @@ -3876,7 +3872,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); @@ -4260,7 +4256,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"); @@ -4298,7 +4294,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, @@ -4359,7 +4355,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; @@ -4408,7 +4404,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); @@ -4473,8 +4469,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; @@ -5361,7 +5357,7 @@ 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, @@ -6910,7 +6906,7 @@ 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; } @@ -6927,7 +6923,7 @@ fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { 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) { diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 4aa178d6c5c..b801954b933 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/ty.rs b/src/comp/middle/ty.rs index 9095f9e9c52..206eb24501c 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -921,9 +921,7 @@ fn sequence_element_type(&ctxt cx, &t ty) -> t { // NB: This is not exhaustive. } - // FIXME: add sess.err or sess.span_err explaining failure (issue - // #444) - fail; + cx.sess.bug("sequence_element_type called on non-sequence value"); } fn type_is_tup_like(&ctxt cx, &t ty) -> bool { @@ -949,8 +947,8 @@ fn get_element_type(&ctxt cx, &t ty, uint i) -> t { // tag. } - // FIXME: add sess.err or sess.span_err explaining failure (issue #444) - 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 { @@ -1544,24 +1542,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(&ty_ctxt tcx, &ast::ann ann) + -> ty_param_substs_opt_and_ty { + + // Pull out the node type table. + alt ({tcx.node_types.(ann.id)}) { case (none) { - log_err "ann_to_ty_param_substs_opt_and_ty() called on an " + - "untyped node"; - fail; + tcx.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(&ty_ctxt tcx, &ast::ann ann) -> t { + ret ann_to_ty_param_substs_opt_and_ty(tcx, 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(&ty_ctxt tcx, &ast::ann ann) -> vec[t] { + alt (ann_to_ty_param_substs_opt_and_ty(tcx, ann)._0) { case (none) { let vec[t] result = []; ret result; @@ -1570,8 +1569,8 @@ 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(&ty_ctxt tcx, &ast::ann ann) -> bool { + auto tpt = ann_to_ty_param_substs_opt_and_ty(tcx, ann); ret !option::is_none[vec[t]](tpt._0); } @@ -1579,7 +1578,7 @@ fn ann_has_type_params(&node_type_table ntt, &ast::ann ann) -> bool { // 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); + auto tpot = ann_to_ty_param_substs_opt_and_ty(cx, a); alt (tpot._0) { case (none) { ret tpot._1; } case (some(?tps)) { @@ -1638,21 +1637,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 { @@ -1660,7 +1659,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 { @@ -1674,66 +1673,8 @@ fn is_fn_ty(&ctxt cx, &t fty) -> bool { // 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); - } - } - 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); - } - } -} - 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 @@ -1820,18 +1761,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(&ty_ctxt tcx, &@ast::expr expr) -> bool { + ret ann_has_type_params(tcx, 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"); @@ -2281,8 +2222,9 @@ mod unify { 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; + // TODO: bound param unifying with local + cx.tcx.sess.unimpl("TODO: bound param unifying with " + + "local"); } case (_) { @@ -2686,18 +2628,15 @@ mod unify { } fn unify_sets[T](&ty_ctxt tcx, &@bindings[T] bindings) -> set_result { - obj handler() { + obj handler(ty_ctxt tcx) { fn resolve_local(ast::def_id id) -> option::t[t] { - log_err "resolve_local in unify_sets"; - fail; + tcx.sess.bug("resolve_local in unify_sets"); } fn record_local(ast::def_id id, t ty) { - log_err "record_local in unify_sets"; - fail; + tcx.sess.bug("record_local in unify_sets"); } fn record_param(uint index, t binding) -> unify::result { - log_err "record_param in unify_sets"; - fail; + tcx.sess.bug("record_param in unify_sets"); } } @@ -2718,8 +2657,8 @@ mod unify { // FIXME: Is this right? auto bindings = mk_bindings[int](int::hash, int::eq_alias); - alt (unify(expected, actual, handler(), bindings, - tcx)) { + alt (unify(expected, actual, handler(tcx), + bindings, tcx)) { case (ures_ok(?result_ty)) { results.(i) = some[t](result_ty); } @@ -2840,9 +2779,8 @@ fn bind_params_in_type(&ctxt cx, &t typ) -> t { fn binder(&ctxt cx, 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; + cx.sess.bug("bind_params_in_type() called on type that " + + "already has bound params in it"); } case (ty_param(?index)) { ret mk_bound_param(cx, index); } case (_) { ret typ; } @@ -2924,9 +2862,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 @@ -2954,13 +2892,13 @@ fn ret_ty_of_fn_ty(ty_ctxt tcx, t a_ty) -> t { ret ret_ty; } case (_) { - fail; + tcx.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)); + ret ret_ty_of_fn_ty(tcx, ann_to_type(tcx, ann)); } // Local Variables: diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 11fbab4ddde..c07e76f8332 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1116,7 +1116,7 @@ mod pushdown { // TODO: enforce mutability auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_vec(?mt)) { for (@ast::expr e_0 in es_0) { @@ -1132,7 +1132,7 @@ mod pushdown { } 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)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_tup(?mts)) { auto i = 0u; @@ -1151,7 +1151,7 @@ mod pushdown { 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)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_rec(?field_mts)) { alt (base_0) { @@ -1192,7 +1192,7 @@ mod pushdown { } 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)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_call(?sube, ?es, ?ann)) { @@ -1201,24 +1201,24 @@ mod pushdown { // 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); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); /* The following is a bit special-cased, but takes care of @@ -1248,17 +1248,17 @@ mod pushdown { } case (ast::expr_lit(?lit, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0); pushdown_block(scx, expected, then_0); @@ -1274,65 +1274,65 @@ mod pushdown { } 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)); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, 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); + ann_to_type(scx.fcx.ccx.tcx, 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); + ty::ann_to_type_params(scx.fcx.ccx.tcx, ann); + auto t_0 = ann_to_type(scx.fcx.ccx.tcx, ann); auto result_0 = demand::full(scx, e.span, expected, t_0, tp_substs_0, adk); @@ -1341,8 +1341,9 @@ mod pushdown { // 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) { + (scx.fcx.ccx.tcx, ann)._0) { case (none) { ty_params_opt = none[vec[ty::t]]; } @@ -1355,7 +1356,7 @@ mod pushdown { } 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); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } /* FIXME: should this check the type annotations? */ @@ -1371,13 +1372,13 @@ mod pushdown { case (ast::expr_port(?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, 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)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_chan(?subty)) { auto pt = ty::mk_port(scx.fcx.ccx.tcx, subty); @@ -1419,7 +1420,7 @@ mod pushdown { // 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); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } @@ -1427,7 +1428,7 @@ mod pushdown { // 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); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } @@ -1450,7 +1451,7 @@ mod pushdown { } } demand::simple(scx, bloc.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, bloc.node.a)); + ann_to_type(scx.fcx.ccx.tcx, bloc.node.a)); } } @@ -1488,7 +1489,7 @@ mod writeback { } auto tpot = - ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx.node_types, + ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, ann); auto tt = tpot._1; if (!ty::type_contains_locals(fcx.ccx.tcx, tt)) { ret; } @@ -1553,7 +1554,7 @@ fn replace_expr_type(&@stmt_ctxt scx, &@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(scx.fcx.ccx.tcx, expr)) { new_tps = some[vec[ty::t]](new_tyt._0); } else { new_tps = none[vec[ty::t]]; @@ -2722,7 +2723,7 @@ 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); + auto rty = ann_to_type(ccx.tcx, ann); let @fn_ctxt fcx = @rec(ret_ty = rty, purity = ast::pure_fn, locals = @common::new_def_hash[ty::t](), @@ -2742,7 +2743,7 @@ fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, 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); + auto field_ty = ty::ann_to_type(ccx.tcx, f.ann); local_ty_table.insert(f.id, field_ty); } } diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index be492d03a1a..2c7e65dcb22 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -945,7 +945,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 */ } From a4ca75e6afb93386c4ccb5f0aa7121bfa9fedb58 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 7 Jun 2011 15:07:27 -0700 Subject: [PATCH 4/8] For consistency, use ctxt instead of ty_ctxt outside of unify. --- src/comp/middle/ty.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 206eb24501c..0200cdd30f8 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1542,25 +1542,25 @@ fn eq_ty(&t a, &t b) -> bool { ret a == b; } // Type lookups -fn ann_to_ty_param_substs_opt_and_ty(&ty_ctxt tcx, &ast::ann ann) +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 ({tcx.node_types.(ann.id)}) { + alt ({cx.node_types.(ann.id)}) { case (none) { - tcx.sess.bug("ann_to_ty_param_substs_opt_and_ty() called on an " + - "untyped node"); + 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(&ty_ctxt tcx, &ast::ann ann) -> t { - ret ann_to_ty_param_substs_opt_and_ty(tcx, 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(&ty_ctxt tcx, &ast::ann ann) -> vec[t] { - alt (ann_to_ty_param_substs_opt_and_ty(tcx, 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; @@ -1569,8 +1569,8 @@ fn ann_to_type_params(&ty_ctxt tcx, &ast::ann ann) -> vec[t] { } } -fn ann_has_type_params(&ty_ctxt tcx, &ast::ann ann) -> bool { - auto tpt = ann_to_ty_param_substs_opt_and_ty(tcx, 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); } @@ -1765,8 +1765,8 @@ fn expr_ty_params_and_ty(&ctxt cx, &@ast::expr expr) ann_to_type(cx, a)); } -fn expr_has_ty_params(&ty_ctxt tcx, &@ast::expr expr) -> bool { - ret ann_has_type_params(tcx, 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 { @@ -2886,19 +2886,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 (_) { - tcx.sess.bug("ret_ty_of_fn_ty() called on non-function type"); + 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, 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: From 7034a28241763df5fbb6c5ae748f2455b46975f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Tue, 7 Jun 2011 20:40:31 -0400 Subject: [PATCH 5/8] Update the snapshot. --- src/snapshots.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index d64be8bffe1..5b41fb5a158 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,8 @@ +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 From 721c5bbee870a08e16d5303837fae4184a5ad377 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 7 Jun 2011 17:54:22 -0700 Subject: [PATCH 6/8] More work on proper linkage name-mangling. Almost right, aside from version numbers. --- src/comp/back/link.rs | 246 ++++++++++++++++++++++++++++++++++++- src/comp/driver/session.rs | 43 ++++--- src/comp/front/ast.rs | 7 +- src/comp/front/eval.rs | 9 +- src/comp/front/parser.rs | 6 +- src/comp/middle/trans.rs | 189 +++++++++++----------------- src/comp/middle/walk.rs | 2 +- src/lib/fs.rs | 14 +++ src/lib/std.rc | 8 +- 9 files changed, 381 insertions(+), 143 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 2ae7b6a6fab..6469bbd3ced 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; @@ -218,3 +228,235 @@ 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) { + 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/session.rs b/src/comp/driver/session.rs index 9f025849402..e0080ca2651 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 92f12c3dc1b..f670c2760a7 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -71,6 +71,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 +85,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); } diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs index d5a76372846..a8e881ee036 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/parser.rs b/src/comp/front/parser.rs index 62ba7325f99..b84a740a917 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -2362,10 +2362,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/middle/trans.rs b/src/comp/middle/trans.rs index 7333375b902..1687a62fa57 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; @@ -119,6 +129,9 @@ state type crate_ctxt = rec(session::session sess, @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, @@ -166,14 +179,14 @@ type fn_ctxt = rec( 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 @@ -313,73 +326,6 @@ fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { ret @rec(path = cx.path + [name] with *cx); } -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); - // Prefix with _ so that it never blends into adjacent digits - hash = "_" + hash; - ccx.type_sha1s.insert(t, hash); - } - } - ret hash; -} - -fn mangle(&vec[str] ss) -> str { - - if (vec::len(ss) > 0u && str::eq(vec::top(ss), "main")) { - ret "_rust_main"; - } - // 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 mangle_name_by_type(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str { - auto hash = get_type_sha1(ccx, t); - ret mangle(path + [hash]); -} - -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 mangle([name, s, hash]); -} - -fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, - &str flav) -> str { - ret mangle(path + [ccx.names.next(flav)]); -} - -fn mangle_name_by_path(&vec[str] path) -> str { - ret mangle(path); -} - -fn mangle_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { - ret ccx.names.next(flav); -} - fn res(@block_ctxt bcx, ValueRef val) -> result { ret rec(bcx = bcx, val = val); @@ -1917,10 +1863,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, "tydesc"); + name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); } auto gvar = llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), @@ -1951,10 +1897,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, "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); @@ -4106,7 +4054,8 @@ fn trans_for_each(&@block_ctxt cx, // Step 2: Declare foreach body function. - let str s = mangle_name_by_path_and_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 @@ -4805,7 +4754,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_path_and_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, @@ -5823,13 +5773,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 @@ -6225,8 +6179,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); @@ -6239,9 +6193,9 @@ fn mk_spawn_wrapper(&@block_ctxt cx, // TODO: construct a name based on tname let str wrap_name = - mangle_name_by_path_and_seq(cx.fcx.lcx.ccx, - cx.fcx.lcx.path, - "spawn_wrapper"); + 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); @@ -6252,7 +6206,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)]; @@ -6271,19 +6225,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. @@ -6719,7 +6673,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); @@ -7094,7 +7048,7 @@ fn create_vtbl(@local_ctxt cx, let @local_ctxt mcx = @rec(path = cx.path + ["method", m.node.ident] with *cx); - let str s = mangle_name_by_path(mcx.path); + 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); @@ -7106,7 +7060,8 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_path(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); @@ -7123,7 +7078,7 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let str s = mangle_name_by_path(cx.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); @@ -7516,25 +7471,29 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } } + 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_path(path); + 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 (str::eq(vec::top(path), "main") && - !ccx.sess.get_opts().shared) { + if (is_main) { if (ccx.main_fn != none[ValueRef]) { ccx.sess.span_err(sp, "multiple 'main' functions"); } - log #fmt("registering %s as main function for crate", ps); 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, @@ -7565,7 +7524,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?!"); + "actually a fn"); } case (ast::native_item_fn(_, _, _, ?tps, _, _)) { count = vec::len[ast::ty_param](tps); @@ -7594,13 +7553,13 @@ 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_path(path); + 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); @@ -7938,7 +7897,7 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { auto discrim_val = C_int(i as int); auto p = wcx.path + [ident, variant.node.name, "discrim"]; - auto s = mangle_name_by_type(ccx, p, ty::mk_int(ccx.tcx)); + auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); auto discrim_gvar = llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s)); @@ -7957,8 +7916,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); } @@ -8178,15 +8137,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 = []; @@ -8199,10 +8149,9 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { i += 1; } vec::push[ValueRef](subcrates, C_int(0)); - auto cname = crate_name(ccx, "__none__"); auto mapname; if (ccx.sess.get_opts().shared) { - mapname = cname; + mapname = ccx.crate_meta_name; } else { mapname = "toplevel"; } @@ -8240,7 +8189,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, @@ -8252,6 +8201,10 @@ fn trans_crate(&session::session sess, &@ast::crate crate, 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](), @@ -8263,7 +8216,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, diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 426f72d9bed..1ecafe1f02f 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(_, _)) {} } diff --git a/src/lib/fs.rs b/src/lib/fs.rs index d051d574fd2..92e90e62cbf 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/std.rc b/src/lib/std.rc index 3619ede40f8..b35b150528d 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -1,8 +1,10 @@ meta (name = "std", - desc = "Rust standard library", + vers = "0.1", uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", - url = "http://rust-lang.org/src/std", - ver = "0.0.1"); + url = "http://rust-lang.org/src/std"); + +meta (comment = "Rust standard library", + license = "BSD"); // Built-in types support modules. From ddec6b5f472088e26ec81cc829c0b377fef477ac Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 20 May 2011 18:36:35 -0700 Subject: [PATCH 7/8] rustc: Use a set-based approach to unification; remove ty_bound_param and ty_local. Sorry, big perf regression; will fix soon. --- src/comp/driver/rustc.rs | 2 +- src/comp/middle/metadata.rs | 11 - src/comp/middle/trans.rs | 24 +- src/comp/middle/ty.rs | 691 ++++------ src/comp/middle/typeck.rs | 1552 +++++++++++----------- src/lib/smallintmap.rs | 4 + src/lib/ufind.rs | 15 +- src/lib/uint.rs | 5 + src/lib/vec.rs | 10 +- src/test/compile-fail/ext-nonexistent.rs | 3 +- 10 files changed, 1119 insertions(+), 1198 deletions(-) diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index e33a2e1c35d..a33416c8638 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -125,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/middle/metadata.rs b/src/comp/middle/metadata.rs index e2e60b80075..59f3cf56387 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -230,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/trans.rs b/src/comp/middle/trans.rs index 1687a62fa57..01192deb8da 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -904,10 +904,6 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { case (ty::ty_param(_)) { llty = T_i8(); } - case (ty::ty_bound_param(_)) { - cx.tcx.sess.span_err(sp, - "trans::type_of called on ty_bound_param"); - } case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); } } @@ -1299,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. @@ -1373,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]; } @@ -1553,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; @@ -2745,10 +2737,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, @@ -5308,6 +5298,7 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, } 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, @@ -7552,6 +7543,7 @@ 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_internal_name_by_path(ccx, path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 0200cdd30f8..53b3c8fce07 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; @@ -88,9 +89,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; @@ -118,10 +117,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 @@ -129,12 +126,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; @@ -259,132 +250,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) { @@ -485,18 +445,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; } @@ -594,12 +546,12 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { ret mstr + ty_to_str(cx, m.ty); } - alt (cname(cx, typ)) { + /*alt (cname(cx, typ)) { case (some(?cs)) { ret cs; } case (_) { } - } + }*/ auto s = ""; @@ -664,20 +616,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); } @@ -753,9 +695,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); @@ -853,9 +793,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); @@ -1018,7 +956,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; } } @@ -1228,13 +1165,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_ptr(?mt)) { ret hash_subty(35u, mt.ty); } + 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); } } } @@ -1470,24 +1405,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; } @@ -1575,16 +1498,21 @@ fn ann_has_type_params(&ctxt cx, &ast::ann ann) -> bool { } +// 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); } + } +} + // 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); - alt (tpot._0) { - case (none) { ret tpot._1; } - case (some(?tps)) { - ret substitute_type_params(cx, tps, tpot._1); - } - } + ret ty_param_substs_opt_and_ty_to_monotype(cx, tpot); } @@ -1618,18 +1546,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] { @@ -1670,6 +1590,13 @@ fn is_fn_ty(&ctxt cx, &t fty) -> bool { } } +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; } + } +} + // Type accessors for AST nodes @@ -1882,54 +1809,87 @@ 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); - - 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); + tag fixup_result { + fix_ok(t); // fixup succeeded + fix_err(int); // fixup failed because a type variable was unresolved } - fn record_binding[T](&@ctxt cx, &@bindings[T] bindings, &T key, t typ) - -> result { - auto n = get_or_create_set[T](bindings, key); + type var_bindings = rec(ufind::ufind sets, + smallintmap::smallintmap[t] types); - 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; - } - case (?res) { ret res; } + type ctxt = rec(@var_bindings vb, ty_ctxt tcx); + + fn mk_var_bindings() -> @var_bindings { + ret @rec(sets=ufind::make(), types=smallintmap::mk[t]()); + } + + // 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 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 (none) { /* fall through */ } } } - - vec::grow_set[option::t[t]](bindings.types, n, none[t], - some[t](result_type)); - - ret ures_ok(typ); } - type ctxt = rec(@bindings[int] bindings, - unify_handler handler, - ty_ctxt tcx); + 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); + } // Wraps the given type in an appropriate cname. // @@ -1944,7 +1904,7 @@ mod unify { ret ures_ok(expected); } - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } // Unifies two mutability flags. @@ -1976,8 +1936,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. @@ -1995,8 +1954,7 @@ mod unify { result_mode = expected_input.mode; } else 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; } @@ -2040,7 +1998,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 @@ -2055,8 +2013,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); } } } @@ -2084,9 +2041,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, @@ -2113,16 +2068,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, @@ -2151,16 +2103,42 @@ 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 { + fn folder(ty_ctxt tcx, @var_bindings vb, @bool success, 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)) { + *success = false; 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, success, _), + typ2); + } + case (none[t]) { *success = false; ret typ; } + } + log ""; // fixes ambiguity + *success = false; ret typ; + } + + case (_) { ret typ; } } - case (some(?n)) { set_num = n; } } - ret set_num; + + auto success = @true; + auto rty = fold_ty(tcx, bind folder(tcx, vb, success, _), typ); + /*if (*success) { ret rty; } + log_err "*** failed! type " + ty::ty_to_str(tcx, typ) + " => " + + ty::ty_to_str(tcx, rty); + ret typ;*/ + ret rty; } fn unify_step(&@ctxt cx, &t expected, &t actual) -> result { @@ -2173,72 +2151,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); + ret ures_ok(mk_var(cx.tcx, actual_id)); } - 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); - } - case (ty::ty_bound_param(?actual_id)) { - alt (struct(cx.tcx, expected)) { - case (ty::ty_local(_)) { - // TODO: bound param unifying with local - cx.tcx.sess.unimpl("TODO: bound param unifying with " - + "local"); - } - - 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 (_) { /* 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); } @@ -2255,7 +2218,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 @@ -2288,7 +2251,7 @@ mod unify { case (_) { /* fall through */ } } - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } case (ty::ty_box(?expected_mt)) { @@ -2296,10 +2259,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; } } @@ -2317,9 +2277,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2328,10 +2286,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; } } @@ -2349,9 +2304,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2371,9 +2324,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2393,9 +2344,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2407,7 +2356,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 @@ -2423,7 +2372,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; } } @@ -2447,9 +2396,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); } } } @@ -2461,7 +2408,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 @@ -2476,8 +2423,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; } } @@ -2487,7 +2433,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, @@ -2511,9 +2457,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); } } } @@ -2529,9 +2473,7 @@ mod unify { expected_cf, actual_cf); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2545,9 +2487,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); } } } @@ -2557,147 +2497,82 @@ 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); - } - - 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; } - } - } - } - - 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); - } } } - // 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; - } + 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); + } - fn substituter(ty_ctxt tcx, - @bindings[int] bindings, - vec[t] types, - t typ) -> t { + 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); + } + } + + log_err #fmt("set %u:%s%s", i, typespec, sets); + i += 1u; + } + } + + // Fixups and substitutions + + fn fixup_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> fixup_result { + fn subst_vars(ty_ctxt tcx, @var_bindings vb, 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 (ty::ty_var(?vid)) { + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { + log_err "unresolved type variable"; + fail; + } + case (some[t](?rt)) { + ret fold_ty(tcx, bind subst_vars(tcx, vb, _), rt); } - case (none) { ret typ; } } } case (_) { ret typ; } } } - auto f = bind substituter(tcx, bindings, set_types, _); - ret fold_ty(tcx, f, typ); + // FIXME: Report errors better. + ret fix_ok(fold_ty(tcx, bind subst_vars(tcx, vb, _), typ)); } - fn unify_sets[T](&ty_ctxt tcx, &@bindings[T] bindings) -> set_result { - obj handler(ty_ctxt tcx) { - fn resolve_local(ast::def_id id) -> option::t[t] { - tcx.sess.bug("resolve_local in unify_sets"); - } - fn record_local(ast::def_id id, t ty) { - tcx.sess.bug("record_local in unify_sets"); - } - fn record_param(uint index, t binding) -> unify::result { - tcx.sess.bug("record_param in unify_sets"); - } - } - - 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(tcx), - 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); - } - } - } + fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) -> t { + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { ret mk_var(tcx, vid); } + case (some[t](?rt)) { + alt (fixup_vars(tcx, vb, rt)) { + case (fix_ok(?rty)) { ret rty; } + case (fix_err(_)) { + // TODO: antisocial + log_err "failed to resolve type var"; + fail; } } } - 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)]; - } - - ret usr_ok(real_results); - } - - 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 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); } } } } @@ -2752,46 +2627,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)) { - cx.sess.bug("bind_params_in_type() called on type that " - + "already has bound params in it"); - } - 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; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index c07e76f8332..d604ad9a390 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -31,9 +31,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; @@ -62,76 +66,41 @@ type crate_ctxt = rec(mutable vec[obj_info] obj_infos, 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)"); - } - - 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); @@ -146,8 +115,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); @@ -172,12 +144,18 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) // 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); @@ -185,16 +163,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 { @@ -202,13 +184,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 { @@ -245,7 +227,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; } @@ -254,12 +235,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; @@ -398,11 +381,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]; } } @@ -413,8 +396,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. @@ -835,105 +818,32 @@ mod collect { // Type unification 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)) { + /*auto cache_key = tup(expected, actual, param_substs); + alt (fcx.ccx.unify_cache.find(cache_key)) { case (some(?r)) { - scx.fcx.ccx.cache_hits += 1u; + fcx.ccx.cache_hits += 1u; ret r; } case (none) { - scx.fcx.ccx.cache_misses += 1u; + fcx.ccx.cache_misses += 1u; } + }*/ + + auto result = ty::unify::unify(expected, actual, fcx.var_bindings, + fcx.ccx.tcx); + + //fcx.ccx.unify_cache.insert(cache_key, result); + + // FIXME: Shouldn't be necessary, but is until we remove pushdown. + alt (result) { + case (ures_ok(?typ)) { + ret ures_ok(ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, typ)); + } + case (_) { ret result; } } - - 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; } } @@ -983,22 +893,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 { @@ -1007,35 +917,41 @@ 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.ccx.tcx, expected_1); + actual_1 = strip_boxes(fcx.ccx.tcx, actual_1); + implicit_boxes = count_boxes(fcx.ccx.tcx, 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 @@ -1047,10 +963,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; } } } @@ -1066,9 +982,8 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, 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]; } } @@ -1105,22 +1020,22 @@ mod pushdown { // TODO: enforce this via a predicate. // TODO: This function is incomplete. - fn pushdown_expr(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e) { - be pushdown_expr_full(scx, expected, e, NO_AUTODEREF); + fn pushdown_expr(&@fn_ctxt fcx, &ty::t expected, &@ast::expr e) { + be pushdown_expr_full(fcx, expected, e, NO_AUTODEREF); } - fn pushdown_expr_full(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e, + fn pushdown_expr_full(&@fn_ctxt fcx, &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, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_vec(?mt)) { for (@ast::expr e_0 in es_0) { - pushdown_expr(scx, mt.ty, e_0); + pushdown_expr(fcx, mt.ty, e_0); } } case (_) { @@ -1128,16 +1043,16 @@ mod pushdown { fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, 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, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(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); + pushdown_expr(fcx, mts.(i).ty, elt_0.expr); i += 1u; } } @@ -1146,13 +1061,13 @@ mod pushdown { fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, 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, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_rec(?field_mts)) { alt (base_0) { case (none) { @@ -1160,7 +1075,7 @@ mod pushdown { for (ast::field field_0 in fields_0) { assert (str::eq(field_0.node.ident, field_mts.(i).ident)); - pushdown_expr(scx, + pushdown_expr(fcx, field_mts.(i).mt.ty, field_0.node.expr); i += 1u; @@ -1175,7 +1090,7 @@ mod pushdown { for (ty::field ft in field_mts) { if (str::eq(field_0.node.ident, ft.ident)) { - pushdown_expr(scx, ft.mt.ty, + pushdown_expr(fcx, ft.mt.ty, field_0.node.expr); } } @@ -1188,162 +1103,163 @@ mod pushdown { fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, 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)) { + alt (struct(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"); + fcx.ccx.tcx.sess.span_err(e.span, + "Expecting an application of box " + + "to have a box type; it had type " + + ty::ty_to_str(fcx.ccx.tcx, t)); } } } case (ast::deref) { - inner_ty = ty::mk_box(scx.fcx.ccx.tcx, + inner_ty = ty::mk_box(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); } + case (_) { inner_ty = strip_boxes(fcx.ccx.tcx, t); } } - pushdown_expr(scx, inner_ty, sube); + pushdown_expr(fcx, inner_ty, sube); } case (ast::expr_lit(?lit, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann), adk); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); - auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0); - pushdown_block(scx, expected, then_0); + auto then_t = ty::block_ty(fcx.ccx.tcx, then_0); + pushdown_block(fcx, 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); + auto else_t = ty::expr_ty(fcx.ccx.tcx, e_0); + pushdown_expr(fcx, expected, e_0); } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_block(?bloc, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - pushdown_block(scx, t, bloc); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); + pushdown_block(fcx, 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, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + pushdown_expr(fcx, expected, lhs_0); + pushdown_expr(fcx, expected, rhs_0); + write::ty_only_fixup(fcx, 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, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + pushdown_expr(fcx, expected, lhs_0); + pushdown_expr(fcx, expected, rhs_0); + write::ty_only_fixup(fcx, 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, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + pushdown_expr(fcx, expected, lhs_0); + pushdown_expr(fcx, expected, rhs_0); + write::ty_only_fixup(fcx, 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_path(?pth, ?ann)) { auto tp_substs_0 = - ty::ann_to_type_params(scx.fcx.ccx.tcx, ann); - auto t_0 = ann_to_type(scx.fcx.ccx.tcx, ann); + ty::ann_to_type_params(fcx.ccx.tcx, ann); + auto t_0 = ty::ann_to_monotype(fcx.ccx.tcx, ann); - auto result_0 = demand::full(scx, e.span, expected, t_0, + auto result_0 = demand::full(fcx, e.span, expected, t_0, tp_substs_0, adk); - auto t = result_0._1; + auto t = ann_to_type(fcx.ccx.tcx, ann); // 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, ann)._0) { + alt (ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, + ann)._0) { case (none) { ty_params_opt = none[vec[ty::t]]; } @@ -1352,12 +1268,12 @@ mod pushdown { } } - write::ty_fixup(scx, ann.id, tup(ty_params_opt, t)); + write::ty_fixup(fcx, 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } /* FIXME: should this check the type annotations? */ case (ast::expr_fail(_)) { /* no-op */ } @@ -1371,47 +1287,47 @@ mod pushdown { 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, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_chan(?es, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_chan(?subty)) { - auto pt = ty::mk_port(scx.fcx.ccx.tcx, subty); - pushdown_expr(scx, pt, es); + auto pt = ty::mk_port(fcx.ccx.tcx, subty); + pushdown_expr(fcx, pt, es); } case (_) { log "chan expr doesn't have a chan type!"; fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, 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); + pushdown_block(fcx, expected, arm_0.block); + auto bty = block_ty(fcx.ccx.tcx, arm_0.block); + t = demand::simple(fcx, e.span, t, bty); } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, 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); + pushdown_expr(fcx, next_ty_var(fcx), lval); + auto t = expr_ty(fcx.ccx.tcx, lval); + write::ty_only_fixup(fcx, 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); + pushdown_expr(fcx, next_ty_var(fcx), expr); + auto t = expr_ty(fcx.ccx.tcx, expr); + pushdown_expr(fcx, ty::mk_chan(fcx.ccx.tcx, t), lval); } case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) { @@ -1419,21 +1335,21 @@ mod pushdown { // 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, 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, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (_) { - scx.fcx.ccx.tcx.sess.span_unimpl(e.span, + fcx.ccx.tcx.sess.span_unimpl(e.span, #fmt("type unification for expression variant: %s", pretty::pprust::expr_to_str(e))); } @@ -1441,89 +1357,94 @@ mod pushdown { } // Push-down over typed blocks. - fn pushdown_block(&@stmt_ctxt scx, &ty::t expected, &ast::block bloc) { + fn pushdown_block(&@fn_ctxt fcx, &ty::t expected, &ast::block bloc) { alt (bloc.node.expr) { case (some(?e_0)) { - pushdown_expr(scx, expected, e_0); + pushdown_expr(fcx, expected, e_0); } case (none) { /* empty */ } } - demand::simple(scx, bloc.span, expected, - ann_to_type(scx.fcx.ccx.tcx, bloc.node.a)); + demand::simple(fcx, bloc.span, expected, ann_to_type(fcx.ccx.tcx, + 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. +// 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: inefficient since not all types have vars in them. It would be better +// to maintain a list of fixups. 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); - } - case (some(?lt)) { - local_ty = lt; - } - } + 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; } - 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.)"); + alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) { + case (fix_ok(?new_type)) { ret new_type; } + case (fix_err(?vid)) { + // TODO: We should try to do a variable ID -> local lookup if + // we can and display this in terms of the local that had an + // incomplete type. + fcx.ccx.tcx.sess.span_err(sp, #fmt( + "cannot determine type of variable ID `%d`", vid)); + } } - 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; } + 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); + + 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)]; + } + new_substs_opt = some[vec[ty::t]](new_substs); } } - auto tpot = - ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, - 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)) { + // FIXME: Report errors better. + auto var_id = fcx.locals.get(l.id); + auto lty = ty::unify::resolve_type_var(fcx.ccx.tcx, + fcx.var_bindings, var_id); + write::ty_only(fcx.ccx.tcx, l.ann.id, lty); + } + 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) { @@ -1540,7 +1461,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); @@ -1548,19 +1469,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, 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)); } @@ -1582,50 +1635,53 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t { // Pattern checking is top-down rather than bottom-up so that bindings get // their types immediately. -fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { +fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) { alt (pat.node) { case (ast::pat_wild(?ann)) { - write::ty_only_fixup(scx, ann.id, expected); + write::ty_only_fixup(fcx, ann.id, expected); } case (ast::pat_lit(?lt, ?ann)) { - auto typ = check_lit(scx.fcx.ccx, lt); - typ = demand::simple(scx, pat.span, expected, typ); - write::ty_only_fixup(scx, ann.id, typ); + 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)) { - scx.fcx.locals.insert(def_id, expected); - write::ty_only_fixup(scx, ann.id, expected); + 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 = scx.fcx.ccx.tcx.def_map.get(ann.id); + 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(scx.fcx.ccx.tcx, + auto tag_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids._0); - auto path_tpot = instantiate_path(scx, path, tag_tpt, pat.span); + auto path_tpot = instantiate_path(fcx, path, tag_tpt, pat.span); // Take the tag type params out of `expected`. auto expected_tps; - alt (struct(scx.fcx.ccx.tcx, expected)) { + alt (struct(fcx.ccx.tcx, expected)) { case (ty::ty_tag(_, ?tps)) { expected_tps = tps; } case (_) { // FIXME: Switch expected and actual in this message? I // can never tell. - scx.fcx.ccx.tcx.sess.span_err(pat.span, + fcx.ccx.tcx.sess.span_err(pat.span, #fmt("mismatched types: expected tag but found %s", - ty::ty_to_str(scx.fcx.ccx.tcx, expected))); + ty::ty_to_str(fcx.ccx.tcx, expected))); } } // Unify with the expected tag type. - auto path_tpt = demand::full(scx, pat.span, expected, - path_tpot._1, expected_tps, - NO_AUTODEREF); + 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(scx.fcx.ccx, pat.span, + auto arg_types = variant_arg_types(fcx.ccx, pat.span, v_def_ids._1, expected_tps); auto subpats_len = vec::len[@ast::pat](subpats); @@ -1637,7 +1693,7 @@ fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { // TODO: note definition of tag variant // TODO (issue #448): Wrap a #fmt string over multiple // lines... - scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt( + 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" }, @@ -1648,20 +1704,20 @@ fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { // TODO: vec::iter2 auto i = 0u; for (@ast::pat subpat in subpats) { - check_pat(scx, subpat, arg_types.(i)); + 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... - scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt( + 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(scx, ann.id, path_tpot); + write::ty_fixup(fcx, ann.id, path_tpot); } } } @@ -1728,16 +1784,16 @@ 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, &@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 = []; @@ -1745,223 +1801,225 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { 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); + check_expr(fcx, a); + auto typ = expr_ty(fcx.ccx.tcx, a); vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); } case (none) { - auto typ = next_ty_var(scx); + auto typ = next_ty_var(fcx); vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); } } } - auto rt_0 = next_ty_var(scx); + auto rt_0 = next_ty_var(fcx); auto t_0; - alt (struct(scx.fcx.ccx.tcx, expr_ty(scx.fcx.ccx.tcx, f))) { + alt (struct(fcx.ccx.tcx, expr_ty(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); + t_0 = ty::mk_fn(fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf); } case (ty::ty_native_fn(?abi, _, _)) { - t_0 = ty::mk_native_fn(scx.fcx.ccx.tcx, abi, arg_tys_0, rt_0); + t_0 = ty::mk_native_fn(fcx.ccx.tcx, abi, arg_tys_0, rt_0); } case (?u) { - scx.fcx.ccx.tcx.sess.span_err(f.span, + 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))); + ty_to_str(fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, f))); } } // 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, + auto f_ty = ty::expr_ty(fcx.ccx.tcx, f); + auto f_tps = ty::expr_ty_params_and_ty(fcx.ccx.tcx, f)._0; + auto tpt_1 = demand::full(fcx, f.span, f_ty, t_0, f_tps, NO_AUTODEREF); - replace_expr_type(scx, f, tpt_1); + //replace_expr_type(fcx, f, tpt_1); } // A generic function for checking assignment expressions - fn check_assignment(&@stmt_ctxt scx, &@ast::expr lhs, &@ast::expr rhs, + fn check_assignment(&@fn_ctxt fcx, &@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); + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto lhs_t0 = expr_ty(fcx.ccx.tcx, lhs); + auto rhs_t0 = expr_ty(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); + pushdown::pushdown_expr(fcx, rhs_t0, lhs); + auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); + pushdown::pushdown_expr(fcx, lhs_t1, rhs); + auto rhs_t1 = expr_ty(fcx.ccx.tcx, rhs); - write::ty_only_fixup(scx, a.id, rhs_t1); + write::ty_only_fixup(fcx, a.id, rhs_t1); } // 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, &@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, 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); + auto lhs_t0 = expr_ty(fcx.ccx.tcx, lhs); + auto rhs_t0 = expr_ty(fcx.ccx.tcx, 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); + pushdown::pushdown_expr_full(fcx, rhs_t0, lhs, AUTODEREF_OK); + auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); + pushdown::pushdown_expr_full(fcx, lhs_t1, rhs, AUTODEREF_OK); - auto t = strip_boxes(scx.fcx.ccx.tcx, lhs_t0); + auto t = strip_boxes(fcx.ccx.tcx, lhs_t0); 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 (struct(fcx.ccx.tcx, 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.ccx.tcx, 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"); } - 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); + 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); + check_expr(fcx, e); - write::bot_ty(scx.fcx.ccx.tcx, a.id); + pushdown::pushdown_expr(fcx, fcx.ret_ty, 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); + check_expr(fcx, e); + pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } } } @@ -1970,21 +2028,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); + pushdown::pushdown_expr(fcx, fcx.ret_ty, 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) { @@ -1992,237 +2050,237 @@ 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, 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, 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, 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(scx, lhs); - check_expr(scx, rhs); - auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); - auto chan_t = ty::mk_chan(scx.fcx.ccx.tcx, rhs_t); - pushdown::pushdown_expr(scx, chan_t, lhs); + auto chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t); + pushdown::pushdown_expr(fcx, 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 (struct(fcx.ccx.tcx, lhs_t)) { case (ty::ty_chan(?it)) { item_t = it; } case (_) { fail; } } - pushdown::pushdown_expr(scx, item_t, rhs); + pushdown::pushdown_expr(fcx, 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 lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); - auto port_t = ty::mk_port(scx.fcx.ccx.tcx, lhs_t1); - pushdown::pushdown_expr(scx, port_t, rhs); + auto port_t = ty::mk_port(fcx.ccx.tcx, lhs_t1); + pushdown::pushdown_expr(fcx, port_t, rhs); auto item_t; - auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs); - alt (struct(scx.fcx.ccx.tcx, rhs_t)) { + auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); + alt (struct(fcx.ccx.tcx, rhs_t)) { case (ty::ty_port(?it)) { item_t = it; } case (_) { fail; } } - pushdown::pushdown_expr(scx, item_t, lhs); + pushdown::pushdown_expr(fcx, item_t, lhs); - 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), + check_expr(fcx, cond); + pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); - check_block(scx, thn); + 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(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)) { + auto thn_t = block_ty(fcx.ccx.tcx, thn); + auto elsopt_t = expr_ty(fcx.ccx.tcx, els); + 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 (struct (fcx.ccx.tcx, + 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); + pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); + check_block(fcx, body); - 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); + pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), 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 = 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); + check_pat(fcx, arm.pat, pattern_ty); pats += [arm.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_block(fcx, result_ty, bloc); } - pushdown::pushdown_expr(scx, pattern_ty, expr); + pushdown::pushdown_expr(fcx, 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, 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 (struct(fcx.ccx.tcx, fty)) { case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) { proto_1 = proto; rt_1 = rt; @@ -2239,7 +2297,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 (_) { @@ -2247,7 +2305,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)) { @@ -2255,14 +2313,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, 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 (struct(fcx.ccx.tcx, fty)) { case (ty::ty_fn(_,_,?rt,_)) { rt_1 = rt; } case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; } case (_) { @@ -2271,14 +2329,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. @@ -2286,7 +2344,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; } @@ -2294,11 +2352,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 (struct(fcx.ccx.tcx, 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); } } @@ -2306,86 +2364,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, 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, @@ -2394,38 +2452,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 (struct(fcx.ccx.tcx, 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); @@ -2436,106 +2494,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.ccx.tcx, base_t); + base_t = ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, base_t); + alt (struct(fcx.ccx.tcx, 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.ccx.tcx, 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 (struct(fcx.ccx.tcx, 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 (struct(fcx.ccx.tcx, 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)); } } } @@ -2552,7 +2612,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. @@ -2563,16 +2623,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 @@ -2600,46 +2660,50 @@ 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); + pushdown::pushdown_expr(fcx, lty, init.expr); } case (ast::init_move) { - pushdown::pushdown_expr(scx, lty, init.expr); + pushdown::pushdown_expr(fcx, lty, 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); + pushdown::pushdown_expr(fcx, port_ty, init.expr); } } } @@ -2647,41 +2711,27 @@ 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_and_pushdown_expr(&@fn_ctxt fcx, &@ast::expr expr) { + check_expr(fcx, expr); + auto ety = expr_ty(fcx.ccx.tcx, expr); + pushdown::pushdown_expr(fcx, ety, expr); } fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { @@ -2696,25 +2746,25 @@ 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_and_pushdown_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); + 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); + pushdown::pushdown_expr(fcx, ety, e); + write::ty_only_fixup(fcx, block.node.a.id, ety); } } @@ -2724,45 +2774,35 @@ 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, ann); - let @fn_ctxt fcx = @rec(ret_ty = rty, - purity = ast::pure_fn, - locals = @common::new_def_hash[ty::t](), - ccx = ccx); + 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); - with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, e)); + check_and_pushdown_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](); + &ast::block body, &ast::ann ann) { + auto gather_result = gather_locals(ccx, decl, body, ann); - // 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, 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); - } - - 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) { @@ -2776,12 +2816,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) { @@ -2789,8 +2829,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. diff --git a/src/lib/smallintmap.rs b/src/lib/smallintmap.rs index ca586eb6f05..49e9efa20f4 100644 --- a/src/lib/smallintmap.rs +++ b/src/lib/smallintmap.rs @@ -38,3 +38,7 @@ 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/ufind.rs b/src/lib/ufind.rs index 7dfa861c6ed..275efd813e4 100644 --- a/src/lib/ufind.rs +++ b/src/lib/ufind.rs @@ -20,6 +20,12 @@ fn make_set(&ufind ufnd) -> 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; } @@ -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 044eeff4fc4..c5aeb49d80b 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 374b55ed9be..2f82f330446 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -210,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; @@ -218,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); @@ -393,6 +393,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/test/compile-fail/ext-nonexistent.rs b/src/test/compile-fail/ext-nonexistent.rs index e068bb3c4a4..9a7591ab7ce 100644 --- a/src/test/compile-fail/ext-nonexistent.rs +++ b/src/test/compile-fail/ext-nonexistent.rs @@ -1,5 +1,4 @@ - // error-pattern:unknown syntax expander fn main() { #iamnotanextensionthatexists(""); -} \ No newline at end of file +} From 0857d22c046c90c3e6ee3adebcee360b2d298341 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 7 Jun 2011 23:03:41 -0700 Subject: [PATCH 8/8] rustc: Print out a real error message on unresolved types. Puts out burning tinderbox. --- src/comp/middle/ty.rs | 41 +++++++++++++++----------- src/comp/middle/typeck.rs | 21 ++++++++----- src/test/compile-fail/vector-no-ann.rs | 2 +- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 53b3c8fce07..3d0c612a085 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -2537,17 +2537,24 @@ mod unify { // Fixups and substitutions fn fixup_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> fixup_result { - fn subst_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> t { + fn subst_vars(ty_ctxt tcx, @var_bindings vb, + @mutable option::t[int] unresolved, t typ) -> t { alt (struct(tcx, typ)) { case (ty::ty_var(?vid)) { + if ((vid as uint) >= ufind::set_count(vb.sets)) { + *unresolved = some[int](vid); + ret typ; + } + auto root_id = ufind::find(vb.sets, vid as uint); alt (smallintmap::find[t](vb.types, root_id)) { case (none[t]) { - log_err "unresolved type variable"; - fail; + *unresolved = some[int](vid); + ret typ; } case (some[t](?rt)) { - ret fold_ty(tcx, bind subst_vars(tcx, vb, _), rt); + ret fold_ty(tcx, + bind subst_vars(tcx, vb, unresolved, _), rt); } } } @@ -2555,24 +2562,22 @@ mod unify { } } - // FIXME: Report errors better. - ret fix_ok(fold_ty(tcx, bind subst_vars(tcx, vb, _), typ)); + auto unresolved = @mutable none[int]; + auto rty = fold_ty(tcx, bind subst_vars(tcx, vb, unresolved, _), typ); + + auto ur = *unresolved; + alt (ur) { + case (none[int]) { ret fix_ok(rty); } + case (some[int](?var_id)) { ret fix_err(var_id); } + } } - fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) -> t { + fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) + -> fixup_result { auto root_id = ufind::find(vb.sets, vid as uint); alt (smallintmap::find[t](vb.types, root_id)) { - case (none[t]) { ret mk_var(tcx, vid); } - case (some[t](?rt)) { - alt (fixup_vars(tcx, vb, rt)) { - case (fix_ok(?rty)) { ret rty; } - case (fix_err(_)) { - // TODO: antisocial - log_err "failed to resolve type var"; - fail; - } - } - } + case (none[t]) { ret fix_ok(mk_var(tcx, vid)); } + case (some[t](?rt)) { ret fixup_vars(tcx, vb, rt); } } } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index d604ad9a390..db3f3ede0c7 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1387,11 +1387,8 @@ mod writeback { alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) { case (fix_ok(?new_type)) { ret new_type; } case (fix_err(?vid)) { - // TODO: We should try to do a variable ID -> local lookup if - // we can and display this in terms of the local that had an - // incomplete type. - fcx.ccx.tcx.sess.span_err(sp, #fmt( - "cannot determine type of variable ID `%d`", vid)); + fcx.ccx.tcx.sess.span_err(sp, + "cannot determine a type for this expression"); } } } @@ -1434,11 +1431,19 @@ mod writeback { fn visit_decl_pre(@fn_ctxt fcx, &@ast::decl d) { alt (d.node) { case (ast::decl_local(?l)) { - // FIXME: Report errors better. auto var_id = fcx.locals.get(l.id); - auto lty = ty::unify::resolve_type_var(fcx.ccx.tcx, + auto fix_rslt = ty::unify::resolve_type_var(fcx.ccx.tcx, fcx.var_bindings, var_id); - write::ty_only(fcx.ccx.tcx, l.ann.id, lty); + 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 */ } } diff --git a/src/test/compile-fail/vector-no-ann.rs b/src/test/compile-fail/vector-no-ann.rs index 912fb0a388a..b492f103c20 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 = []; }