diff options
Diffstat (limited to 'src/comp')
91 files changed, 0 insertions, 54922 deletions
diff --git a/src/comp/README.txt b/src/comp/README.txt deleted file mode 100644 index 9ee501c4c3b..00000000000 --- a/src/comp/README.txt +++ /dev/null @@ -1,77 +0,0 @@ -An informal guide to reading and working on the rustc compiler. -================================================================== - -If you wish to expand on this document, or have one of the -slightly-more-familiar authors add anything else to it, please get in -touch or file a bug. Your concerns are probably the same as someone -else's. - - -High-level concepts -=================== - -Rustc consists of the following subdirectories: - -syntax/ - pure syntax concerns: lexer, parser, AST. -front/ - front-end: attributes, conditional compilation -middle/ - middle-end: resolving, typechecking, translating -back/ - back-end: linking and ABI -driver/ - command-line processing, main() entrypoint -util/ - ubiquitous types and helper functions -lib/ - bindings to LLVM -pretty/ - pretty-printing - -The entry-point for the compiler is main() in driver/rustc.rs, and -this file sequences the various parts together. - - -The 3 central data structures: ------------------------------- - -#1: syntax/ast.rs defines the AST. The AST is treated as immutable - after parsing despite containing some mutable types (hashtables - and such). There are three interesting details to know about this - structure: - - - Many -- though not all -- nodes within this data structure are - wrapped in the type spanned<T>, meaning that the front-end has - marked the input coordinates of that node. The member .node is - the data itself, the member .span is the input location (file, - line, column; both low and high). - - - Many other nodes within this data structure carry a - def_id. These nodes represent the 'target' of some name - reference elsewhere in the tree. When the AST is resolved, by - middle/resolve.rs, all names wind up acquiring a def that they - point to. So anything that can be pointed-to by a name winds - up with a def_id. - -#2: middle/ty.rs defines the datatype sty. This is the type that - represents types after they have been resolved and normalized by - the middle-end. The typeck phase converts every ast type to a - ty::sty, and the latter is used to drive later phases of - compilation. Most variants in the ast::ty tag have a - corresponding variant in the ty::sty tag. - -#3: lib/llvm.rs defines the exported types ValueRef, TypeRef, - BasicBlockRef, and several others. Each of these is an opaque - pointer to an LLVM type, manipulated through the lib.llvm - interface. - - -Control and information flow within the compiler: -------------------------------------------------- - -- main() in driver/rustc.rs assumes control on startup. Options are - parsed, platform is detected, etc. - -- front/parser.rs is driven over the input files. - -- Multiple middle-end passes (middle/resolve.rs, middle/typeck.rs) are - run over the resulting AST. Each pass generates new information - about the AST which is stored in various side data structures. - -- Finally middle/trans.rs is applied to the AST, which performs a - type-directed translation to LLVM-ese. When it's finished - synthesizing LLVM values, rustc asks LLVM to write them out in some - form (.bc, .o) and possibly run the system linker. diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs deleted file mode 100644 index c02960deb00..00000000000 --- a/src/comp/back/abi.rs +++ /dev/null @@ -1,93 +0,0 @@ - - - -// FIXME: Most of these should be uints. -const rc_base_field_refcnt: int = 0; - -const task_field_refcnt: int = 0; - -const task_field_stk: int = 2; - -const task_field_runtime_sp: int = 3; - -const task_field_rust_sp: int = 4; - -const task_field_gc_alloc_chain: int = 5; - -const task_field_dom: int = 6; - -const n_visible_task_fields: int = 7; - -const dom_field_interrupt_flag: int = 1; - -const frame_glue_fns_field_mark: int = 0; - -const frame_glue_fns_field_drop: int = 1; - -const frame_glue_fns_field_reloc: int = 2; - -const box_field_refcnt: int = 0; -const box_field_tydesc: int = 1; -const box_field_prev: int = 2; -const box_field_next: int = 3; -const box_field_body: int = 4; - -const general_code_alignment: int = 16; - -const tydesc_field_first_param: int = 0; -const tydesc_field_size: int = 1; -const tydesc_field_align: int = 2; -const tydesc_field_take_glue: int = 3; -const tydesc_field_drop_glue: int = 4; -const tydesc_field_free_glue: int = 5; -const tydesc_field_unused: int = 6; -const tydesc_field_sever_glue: int = 7; -const tydesc_field_mark_glue: int = 8; -const tydesc_field_unused2: int = 9; -const tydesc_field_unused_2: int = 10; -const tydesc_field_shape: int = 11; -const tydesc_field_shape_tables: int = 12; -const tydesc_field_n_params: int = 13; -const tydesc_field_obj_params: int = 14; // FIXME unused -const n_tydesc_fields: int = 15; - -const cmp_glue_op_eq: uint = 0u; - -const cmp_glue_op_lt: uint = 1u; - -const cmp_glue_op_le: uint = 2u; - -// The two halves of a closure: code and environment. -const fn_field_code: int = 0; -const fn_field_box: int = 1; - -// closures, see trans_closure.rs -const closure_body_ty_params: int = 0; -const closure_body_bindings: int = 1; - -const vec_elt_fill: int = 0; - -const vec_elt_alloc: int = 1; - -const vec_elt_elems: int = 2; - -const worst_case_glue_call_args: int = 7; - -const abi_version: uint = 1u; - -fn memcpy_glue_name() -> str { ret "rust_memcpy_glue"; } - -fn bzero_glue_name() -> str { ret "rust_bzero_glue"; } - -fn yield_glue_name() -> str { ret "rust_yield_glue"; } - -fn no_op_type_glue_name() -> str { ret "rust_no_op_type_glue"; } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs deleted file mode 100644 index c2cc106b3e2..00000000000 --- a/src/comp/back/link.rs +++ /dev/null @@ -1,718 +0,0 @@ -import ctypes::{c_int, c_uint}; -import driver::session; -import session::session; -import lib::llvm::llvm; -import front::attr; -import middle::ty; -import metadata::{encoder, cstore}; -import middle::trans::common::crate_ctxt; -import std::fs; -import std::run; -import std::sha1::sha1; -import syntax::ast; -import syntax::print::pprust; -import lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data, True, False}; -import util::filesearch; -import middle::ast_map::{path, path_mod, path_name}; - -enum output_type { - output_type_none, - output_type_bitcode, - output_type_assembly, - output_type_llvm_assembly, - output_type_object, - output_type_exe, -} - -fn llvm_err(sess: session, msg: str) unsafe { - let buf = llvm::LLVMRustGetLastError(); - if buf == ptr::null() { - sess.fatal(msg); - } else { sess.fatal(msg + ": " + str::from_cstr(buf)); } -} - -fn load_intrinsics_bc(sess: session) -> option<ModuleRef> { - let path = alt filesearch::search( - sess.filesearch, - bind filesearch::pick_file("intrinsics.bc", _)) { - option::some(path) { path } - option::none { - sess.warn("couldn't find intrinsics.bc"); - ret option::none; - } - }; - let membuf = str::as_buf(path, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if membuf as uint == 0u { - llvm_err(sess, "installation problem: couldn't open " + path); - fail; - } - let llintrinsicsmod = llvm::LLVMRustParseBitcode(membuf); - llvm::LLVMDisposeMemoryBuffer(membuf); - if llintrinsicsmod as uint == 0u { - sess.warn("couldn't parse intrinsics.bc"); - ret option::none; - } - - ret option::some(llintrinsicsmod); -} - -fn load_intrinsics_ll(sess: session) -> ModuleRef { - let path = alt filesearch::search( - sess.filesearch, - bind filesearch::pick_file("intrinsics.ll", _)) { - option::some(path) { path } - option::none { sess.fatal("couldn't find intrinsics.ll") } - }; - let llintrinsicsmod = str::as_buf(path, { |buf| - llvm::LLVMRustParseAssemblyFile(buf) - }); - if llintrinsicsmod as uint == 0u { - llvm_err(sess, "couldn't parse intrinsics.ll"); - fail; - } - ret llintrinsicsmod; -} - -fn link_intrinsics(sess: session, llmod: ModuleRef) { - let llintrinsicsmod = { - alt load_intrinsics_bc(sess) { - option::some(m) { m } - option::none { - // When the bitcode format changes we can't parse a .bc - // file produced with a newer LLVM (as happens when stage0 - // is trying to build against a new LLVM revision), in - // that case we'll try to parse the assembly. - sess.warn("couldn't parse intrinsics.bc, trying intrinsics.ll"); - load_intrinsics_ll(sess) - } - } - }; - let linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod); - llvm::LLVMDisposeModule(llintrinsicsmod); - if linkres == False { - llvm_err(sess, "couldn't link the module with the intrinsics"); - fail; - } -} - -mod write { - fn is_object_or_assembly_or_exe(ot: output_type) -> bool { - if ot == output_type_assembly || ot == output_type_object || - ot == output_type_exe { - ret true; - } - ret false; - } - - // Decides what to call an intermediate file, given the name of the output - // and the extension to use. - fn mk_intermediate_name(output_path: str, extension: str) -> str unsafe { - let stem = alt str::find_char(output_path, '.') { - some(dot_pos) { str::slice(output_path, 0u, dot_pos) } - none { output_path } - }; - ret stem + "." + extension; - } - - fn run_passes(sess: session, llmod: ModuleRef, output: str) { - let opts = sess.opts; - if opts.time_llvm_passes { llvm::LLVMRustEnableTimePasses(); } - link_intrinsics(sess, llmod); - let pm = mk_pass_manager(); - let td = mk_target_data( - sess.targ_cfg.target_strs.data_layout); - llvm::LLVMAddTargetData(td.lltd, pm.llpm); - // TODO: run the linter here also, once there are llvm-c bindings for - // it. - - // Generate a pre-optimization intermediate file if -save-temps was - // specified. - - if opts.save_temps { - alt opts.output_type { - output_type_bitcode { - if opts.optimize != 0u { - let filename = mk_intermediate_name(output, "no-opt.bc"); - str::as_buf(filename, - {|buf| - llvm::LLVMWriteBitcodeToFile(llmod, buf) - }); - } - } - _ { - let filename = mk_intermediate_name(output, "bc"); - str::as_buf(filename, - {|buf| - llvm::LLVMWriteBitcodeToFile(llmod, buf) - }); - } - } - } - if opts.verify { llvm::LLVMAddVerifierPass(pm.llpm); } - // FIXME: This is mostly a copy of the bits of opt's -O2 that are - // available in the C api. - // FIXME2: We might want to add optimization levels like -O1, -O2, - // -Os, etc - // FIXME3: Should we expose and use the pass lists used by the opt - // tool? - - if opts.optimize != 0u { - let fpm = mk_pass_manager(); - llvm::LLVMAddTargetData(td.lltd, fpm.llpm); - - let FPMB = llvm::LLVMPassManagerBuilderCreate(); - llvm::LLVMPassManagerBuilderSetOptLevel(FPMB, 2u as c_uint); - llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(FPMB, - fpm.llpm); - llvm::LLVMPassManagerBuilderDispose(FPMB); - - llvm::LLVMRunPassManager(fpm.llpm, llmod); - let threshold = 225u; - if opts.optimize == 3u { threshold = 275u; } - - let MPMB = llvm::LLVMPassManagerBuilderCreate(); - llvm::LLVMPassManagerBuilderSetOptLevel(MPMB, - opts.optimize as c_uint); - llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False); - llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB, False); - llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB, False); - llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB, - False); - - if threshold != 0u { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold - (MPMB, threshold as c_uint); - } - llvm::LLVMPassManagerBuilderPopulateModulePassManager(MPMB, - pm.llpm); - - llvm::LLVMPassManagerBuilderDispose(MPMB); - } - if opts.verify { llvm::LLVMAddVerifierPass(pm.llpm); } - if is_object_or_assembly_or_exe(opts.output_type) { - let LLVMAssemblyFile = 0 as c_int; - let LLVMObjectFile = 1 as c_int; - let LLVMOptNone = 0 as c_int; // -O0 - let LLVMOptLess = 1 as c_int; // -O1 - let LLVMOptDefault = 2 as c_int; // -O2, -Os - let LLVMOptAggressive = 3 as c_int; // -O3 - - let CodeGenOptLevel; - alt check opts.optimize { - 0u { CodeGenOptLevel = LLVMOptNone; } - 1u { CodeGenOptLevel = LLVMOptLess; } - 2u { CodeGenOptLevel = LLVMOptDefault; } - 3u { CodeGenOptLevel = LLVMOptAggressive; } - } - - let FileType; - if opts.output_type == output_type_object || - opts.output_type == output_type_exe { - FileType = LLVMObjectFile; - } else { FileType = LLVMAssemblyFile; } - // Write optimized bitcode if --save-temps was on. - - if opts.save_temps { - // Always output the bitcode file with --save-temps - - let filename = mk_intermediate_name(output, "opt.bc"); - llvm::LLVMRunPassManager(pm.llpm, llmod); - str::as_buf(filename, - {|buf| - llvm::LLVMWriteBitcodeToFile(llmod, buf) - }); - pm = mk_pass_manager(); - // Save the assembly file if -S is used - - if opts.output_type == output_type_assembly { - let _: () = str::as_buf( - sess.targ_cfg.target_strs.target_triple, - {|buf_t| - str::as_buf(output, {|buf_o| - llvm::LLVMRustWriteOutputFile( - pm.llpm, - llmod, - buf_t, - buf_o, - LLVMAssemblyFile, - CodeGenOptLevel, - true)})}); - } - - - // Save the object file for -c or --save-temps alone - // This .o is needed when an exe is built - if opts.output_type == output_type_object || - opts.output_type == output_type_exe { - let _: () = - str::as_buf( - sess.targ_cfg.target_strs.target_triple, - {|buf_t| - str::as_buf(output, {|buf_o| - llvm::LLVMRustWriteOutputFile( - pm.llpm, - llmod, - buf_t, - buf_o, - LLVMObjectFile, - CodeGenOptLevel, - true)})}); - } - } else { - // If we aren't saving temps then just output the file - // type corresponding to the '-c' or '-S' flag used - - let _: () = - str::as_buf( - sess.targ_cfg.target_strs.target_triple, - {|buf_t| - str::as_buf(output, {|buf_o| - llvm::LLVMRustWriteOutputFile( - pm.llpm, - llmod, - buf_t, - buf_o, - FileType, - CodeGenOptLevel, - true)})}); - } - // Clean up and return - - llvm::LLVMDisposeModule(llmod); - if opts.time_llvm_passes { llvm::LLVMRustPrintPassTimings(); } - ret; - } - - if opts.output_type == output_type_llvm_assembly { - // Given options "-S --emit-llvm": output LLVM assembly - str::as_buf(output, {|buf_o| - llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)}); - } else { - // If only a bitcode file is asked for by using the '--emit-llvm' - // flag, then output it here - llvm::LLVMRunPassManager(pm.llpm, llmod); - str::as_buf(output, - {|buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) }); - } - - llvm::LLVMDisposeModule(llmod); - if opts.time_llvm_passes { llvm::LLVMRustPrintPassTimings(); } - } -} - - -/* - * 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 different 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 mandatory): name and vers. - * Every crate gets them; if it doesn't name them explicitly we infer them - * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS. - * - * - Define CMETA as all the non-name, non-vers exported meta tags in the - * crate (in sorted order). - * - * - Define CMH as hash(CMETA + hashes of dependent crates). - * - * - 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. - * - */ - -type link_meta = {name: str, vers: str, extras_hash: str}; - -fn build_link_meta(sess: session, c: ast::crate, output: str, - sha: sha1) -> link_meta { - - type provided_metas = - {name: option<str>, - vers: option<str>, - cmh_items: [@ast::meta_item]}; - - fn provided_link_metas(sess: session, c: ast::crate) -> - provided_metas { - let name: option<str> = none; - let vers: option<str> = none; - let cmh_items: [@ast::meta_item] = []; - let linkage_metas = attr::find_linkage_metas(c.node.attrs); - attr::require_unique_names(sess, linkage_metas); - for meta: @ast::meta_item in linkage_metas { - if attr::get_meta_item_name(meta) == "name" { - alt attr::get_meta_item_value_str(meta) { - some(v) { name = some(v); } - none { cmh_items += [meta]; } - } - } else if attr::get_meta_item_name(meta) == "vers" { - alt attr::get_meta_item_value_str(meta) { - some(v) { vers = some(v); } - none { cmh_items += [meta]; } - } - } else { cmh_items += [meta]; } - } - ret {name: name, vers: vers, cmh_items: cmh_items}; - } - - // This calculates CMH as defined above - fn crate_meta_extras_hash(sha: sha1, _crate: ast::crate, - metas: provided_metas, - dep_hashes: [str]) -> str { - fn len_and_str(s: str) -> str { - ret #fmt["%u_%s", str::len(s), s]; - } - - fn len_and_str_lit(l: ast::lit) -> str { - ret len_and_str(pprust::lit_to_str(@l)); - } - - let cmh_items = attr::sort_meta_items(metas.cmh_items); - - sha.reset(); - for m_: @ast::meta_item in cmh_items { - let m = m_; - alt m.node { - ast::meta_name_value(key, value) { - sha.input_str(len_and_str(key)); - sha.input_str(len_and_str_lit(value)); - } - ast::meta_word(name) { sha.input_str(len_and_str(name)); } - ast::meta_list(_, _) { - // FIXME (#607): Implement this - fail "unimplemented meta_item variant"; - } - } - } - - for dh in dep_hashes { - sha.input_str(len_and_str(dh)); - } - - ret truncated_sha1_result(sha); - } - - fn warn_missing(sess: session, name: str, default: str) { - if !sess.building_library { ret; } - sess.warn(#fmt["missing crate link meta '%s', using '%s' as default", - name, default]); - } - - fn crate_meta_name(sess: session, _crate: ast::crate, - output: str, metas: provided_metas) -> str { - ret alt metas.name { - some(v) { v } - none { - let name = - { - let os = str::split_char(fs::basename(output), '.'); - if (vec::len(os) < 2u) { - sess.fatal(#fmt("Output file name %s doesn't\ - appear to have an extension", output)); - } - vec::pop(os); - str::connect(os, ".") - }; - warn_missing(sess, "name", name); - name - } - }; - } - - fn crate_meta_vers(sess: session, _crate: ast::crate, - metas: provided_metas) -> str { - ret alt metas.vers { - some(v) { v } - none { - let vers = "0.0"; - warn_missing(sess, "vers", vers); - vers - } - }; - } - - let provided_metas = provided_link_metas(sess, c); - let name = crate_meta_name(sess, c, output, provided_metas); - let vers = crate_meta_vers(sess, c, provided_metas); - let dep_hashes = cstore::get_dep_hashes(sess.cstore); - let extras_hash = - crate_meta_extras_hash(sha, c, provided_metas, dep_hashes); - - ret {name: name, vers: vers, extras_hash: extras_hash}; -} - -fn truncated_sha1_result(sha: sha1) -> str unsafe { - ret str::slice(sha.result_str(), 0u, 16u); -} - - -// This calculates STH for a symbol, as defined above -fn symbol_hash(tcx: ty::ctxt, sha: sha1, t: ty::t, link_meta: link_meta) -> - str { - // NB: do *not* use abbrevs here as we want the symbol names - // to be independent of one another in the crate. - - sha.reset(); - sha.input_str(link_meta.name); - sha.input_str("-"); - // FIXME: This wants to be link_meta.meta_hash - sha.input_str(link_meta.name); - sha.input_str("-"); - sha.input_str(encoder::encoded_ty(tcx, t)); - let hash = truncated_sha1_result(sha); - // Prefix with _ so that it never blends into adjacent digits - - ret "_" + hash; -} - -fn get_symbol_hash(ccx: crate_ctxt, t: ty::t) -> str { - let hash = ""; - alt ccx.type_sha1s.find(t) { - some(h) { hash = h; } - none { - hash = symbol_hash(ccx.tcx, ccx.sha, t, ccx.link_meta); - ccx.type_sha1s.insert(t, hash); - } - } - ret hash; -} - -fn mangle(ss: path) -> str { - // Follow C++ namespace-mangling style - - let n = "_ZN"; // Begin name-sequence. - - for s in ss { - alt s { path_name(s) | path_mod(s) { - n += #fmt["%u%s", str::len(s), s]; - } } - } - n += "E"; // End name-sequence. - n -} - -fn exported_name(path: path, hash: str, _vers: str) -> str { - // FIXME: versioning isn't working yet - ret mangle(path + [path_name(hash)]); // + "@" + vers; - -} - -fn mangle_exported_name(ccx: crate_ctxt, path: path, t: ty::t) -> str { - let hash = get_symbol_hash(ccx, t); - ret exported_name(path, hash, ccx.link_meta.vers); -} - -fn mangle_internal_name_by_type_only(ccx: crate_ctxt, t: ty::t, name: str) -> - str { - let s = util::ppaux::ty_to_short_str(ccx.tcx, t); - let hash = get_symbol_hash(ccx, t); - ret mangle([path_name(name), path_name(s), path_name(hash)]); -} - -fn mangle_internal_name_by_path_and_seq(ccx: crate_ctxt, path: path, - flav: str) -> str { - ret mangle(path + [path_name(ccx.names(flav))]); -} - -fn mangle_internal_name_by_path(_ccx: crate_ctxt, path: path) -> str { - ret mangle(path); -} - -fn mangle_internal_name_by_seq(ccx: crate_ctxt, flav: str) -> str { - ret ccx.names(flav); -} - -// If the user wants an exe generated we need to invoke -// cc to link the object file with some libs -fn link_binary(sess: session, - obj_filename: str, - out_filename: str, - lm: link_meta) { - // Converts a library file name into a cc -l argument - fn unlib(config: @session::config, filename: str) -> str unsafe { - let rmlib = fn@(filename: str) -> str { - let found = str::find_str(filename, "lib"); - if config.os == session::os_macos || - (config.os == session::os_linux || - config.os == session::os_freebsd) && - option::is_some(found) && option::get(found) == 0u { - ret str::slice(filename, 3u, str::len(filename)); - } else { ret filename; } - }; - fn rmext(filename: str) -> str { - let parts = str::split_char(filename, '.'); - vec::pop(parts); - ret str::connect(parts, "."); - } - ret alt config.os { - session::os_macos { rmext(rmlib(filename)) } - session::os_linux { rmext(rmlib(filename)) } - session::os_freebsd { rmext(rmlib(filename)) } - _ { rmext(filename) } - }; - } - - let output = if sess.building_library { - let long_libname = - std::os::dylib_filename(#fmt("%s-%s-%s", - lm.name, lm.extras_hash, lm.vers)); - #debug("link_meta.name: %s", lm.name); - #debug("long_libname: %s", long_libname); - #debug("out_filename: %s", out_filename); - #debug("dirname(out_filename): %s", fs::dirname(out_filename)); - - fs::connect(fs::dirname(out_filename), long_libname) - } else { out_filename }; - - log(debug, "output: " + output); - - // The default library location, we need this to find the runtime. - // The location of crates will be determined as needed. - let stage: str = "-L" + sess.filesearch.get_target_lib_path(); - - // In the future, FreeBSD will use clang as default compiler. - // It would be flexible to use cc (system's default C compiler) - // instead of hard-coded gcc. - // For win32, there is no cc command, - // so we add a condition to make it use gcc. - let cc_prog: str = - if sess.targ_cfg.os == session::os_win32 { "gcc" } else { "cc" }; - // The invocations of cc share some flags across platforms - - let cc_args = - [stage] + sess.targ_cfg.target_strs.cc_args + - ["-o", output, obj_filename]; - - let lib_cmd; - let os = sess.targ_cfg.os; - if os == session::os_macos { - lib_cmd = "-dynamiclib"; - } else { lib_cmd = "-shared"; } - - let cstore = sess.cstore; - for cratepath: str in cstore::get_used_crate_files(cstore) { - if str::ends_with(cratepath, ".rlib") { - cc_args += [cratepath]; - cont; - } - let cratepath = cratepath; - let dir = fs::dirname(cratepath); - if dir != "" { cc_args += ["-L" + dir]; } - let libarg = unlib(sess.targ_cfg, fs::basename(cratepath)); - cc_args += ["-l" + libarg]; - } - - let ula = cstore::get_used_link_args(cstore); - for arg: str in ula { cc_args += [arg]; } - - let used_libs = cstore::get_used_libraries(cstore); - for l: str in used_libs { cc_args += ["-l" + l]; } - - if sess.building_library { - cc_args += [lib_cmd]; - - // On mac we need to tell the linker to let this library - // be rpathed - if sess.targ_cfg.os == session::os_macos { - cc_args += ["-Wl,-install_name,@rpath/" - + fs::basename(output)]; - } - } else { - // FIXME: why do we hardcode -lm? - cc_args += ["-lm"]; - } - - // Always want the runtime linked in - cc_args += ["-lrustrt"]; - - // On linux librt and libdl are an indirect dependencies via rustrt, - // and binutils 2.22+ won't add them automatically - if sess.targ_cfg.os == session::os_linux { - cc_args += ["-lrt", "-ldl"]; - } - - if sess.targ_cfg.os == session::os_freebsd { - cc_args += ["-lrt", "-L/usr/local/lib", "-lexecinfo", - "-L/usr/local/lib/gcc46", - "-L/usr/local/lib/gcc44", "-lstdc++", - "-Wl,-z,origin", - "-Wl,-rpath,/usr/local/lib/gcc46", - "-Wl,-rpath,/usr/local/lib/gcc44"]; - } - - // OS X 10.6 introduced 'compact unwind info', which is produced by the - // linker from the dwarf unwind info. Unfortunately, it does not seem to - // understand how to unwind our __morestack frame, so we have to turn it - // off. This has impacted some other projects like GHC. - if sess.targ_cfg.os == session::os_macos { - cc_args += ["-Wl,-no_compact_unwind"]; - } - - // Stack growth requires statically linking a __morestack function - cc_args += ["-lmorestack"]; - - cc_args += rpath::get_rpath_flags(sess, output); - - #debug("%s link args: %s", cc_prog, str::connect(cc_args, " ")); - // We run 'cc' here - let prog = run::program_output(cc_prog, cc_args); - if 0 != prog.status { - sess.err(#fmt["linking with %s failed with code %d", - cc_prog, prog.status]); - sess.note(#fmt["%s arguments: %s", - cc_prog, str::connect(cc_args, " ")]); - sess.note(prog.err + prog.out); - sess.abort_if_errors(); - } - - // Clean up on Darwin - if sess.targ_cfg.os == session::os_macos { - run::run_program("dsymutil", [output]); - } - - // Remove the temporary object file if we aren't saving temps - if !sess.opts.save_temps { - run::run_program("rm", [obj_filename]); - } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/back/rpath.rs b/src/comp/back/rpath.rs deleted file mode 100644 index cc74efa82cf..00000000000 --- a/src/comp/back/rpath.rs +++ /dev/null @@ -1,345 +0,0 @@ -import std::{os, fs, os_fs, map}; -import metadata::cstore; -import driver::session; -import util::filesearch; - -export get_rpath_flags; - -pure fn not_win32(os: session::os) -> bool { - alt os { - session::os_win32 { false } - _ { true } - } -} - -fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] { - let os = sess.targ_cfg.os; - - // No rpath on windows - if os == session::os_win32 { - ret []; - } - - #debug("preparing the RPATH!"); - - let cwd = os::getcwd(); - let sysroot = sess.filesearch.sysroot(); - let output = out_filename; - let libs = cstore::get_used_crate_files(sess.cstore); - // We don't currently rpath native libraries, but we know - // where rustrt is and we know every rust program needs it - let libs = libs + [get_sysroot_absolute_rt_lib(sess)]; - - let target_triple = sess.opts.target_triple; - let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple); - rpaths_to_flags(rpaths) -} - -fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path { - let path = [sess.filesearch.sysroot()] - + filesearch::relative_target_lib_path( - sess.opts.target_triple) - + [os::dylib_filename("rustrt")]; - fs::connect_many(path) -} - -fn rpaths_to_flags(rpaths: [str]) -> [str] { - vec::map(rpaths, { |rpath| #fmt("-Wl,-rpath,%s",rpath)}) -} - -fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path, - output: fs::path, libs: [fs::path], - target_triple: str) -> [str] { - #debug("cwd: %s", cwd); - #debug("sysroot: %s", sysroot); - #debug("output: %s", output); - #debug("libs:"); - for libpath in libs { - #debug(" %s", libpath); - } - #debug("target_triple: %s", target_triple); - - // Use relative paths to the libraries. Binaries can be moved - // as long as they maintain the relative relationship to the - // crates they depend on. - let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs); - - // Make backup absolute paths to the libraries. Binaries can - // be moved as long as the crates they link against don't move. - let abs_rpaths = get_absolute_rpaths(cwd, libs); - - // And a final backup rpath to the global library location. - let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)]; - - fn log_rpaths(desc: str, rpaths: [str]) { - #debug("%s rpaths:", desc); - for rpath in rpaths { - #debug(" %s", rpath); - } - } - - log_rpaths("relative", rel_rpaths); - log_rpaths("absolute", abs_rpaths); - log_rpaths("fallback", fallback_rpaths); - - let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths; - - // Remove duplicates - let rpaths = minimize_rpaths(rpaths); - ret rpaths; -} - -fn get_rpaths_relative_to_output(os: session::os, - cwd: fs::path, - output: fs::path, - libs: [fs::path]) -> [str] { - vec::map(libs, bind get_rpath_relative_to_output(os, cwd, output, _)) -} - -fn get_rpath_relative_to_output(os: session::os, - cwd: fs::path, - output: fs::path, - &&lib: fs::path) : not_win32(os) -> str { - // Mac doesn't appear to support $ORIGIN - let prefix = alt os { - session::os_linux { "$ORIGIN" + fs::path_sep() } - session::os_freebsd { "$ORIGIN" + fs::path_sep() } - session::os_macos { "@executable_path" + fs::path_sep() } - session::os_win32 { std::util::unreachable(); } - }; - - prefix + get_relative_to( - get_absolute(cwd, output), - get_absolute(cwd, lib)) -} - -// Find the relative path from one file to another -fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path { - assert fs::path_is_absolute(abs1); - assert fs::path_is_absolute(abs2); - #debug("finding relative path from %s to %s", - abs1, abs2); - let normal1 = fs::normalize(abs1); - let normal2 = fs::normalize(abs2); - let split1 = str::split_char(normal1, os_fs::path_sep); - let split2 = str::split_char(normal2, os_fs::path_sep); - let len1 = vec::len(split1); - let len2 = vec::len(split2); - assert len1 > 0u; - assert len2 > 0u; - - let max_common_path = math::min(len1, len2) - 1u; - let start_idx = 0u; - while start_idx < max_common_path - && split1[start_idx] == split2[start_idx] { - start_idx += 1u; - } - - let path = []; - - uint::range(start_idx, len1 - 1u) {|_i| path += [".."]; }; - - path += vec::slice(split2, start_idx, len2 - 1u); - - if check vec::is_not_empty(path) { - ret fs::connect_many(path); - } else { - ret "."; - } -} - -fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] { - vec::map(libs, bind get_absolute_rpath(cwd, _)) -} - -fn get_absolute_rpath(cwd: fs::path, &&lib: fs::path) -> str { - fs::dirname(get_absolute(cwd, lib)) -} - -fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path { - if fs::path_is_absolute(lib) { - lib - } else { - fs::connect(cwd, lib) - } -} - -fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str { - let install_prefix = #env("CFG_PREFIX"); - - if install_prefix == "" { - fail "rustc compiled without CFG_PREFIX environment variable"; - } - - let path = [install_prefix] - + filesearch::relative_target_lib_path(target_triple); - get_absolute(cwd, fs::connect_many(path)) -} - -fn minimize_rpaths(rpaths: [str]) -> [str] { - let set = map::new_str_hash::<()>(); - let minimized = []; - for rpath in rpaths { - if !set.contains_key(rpath) { - minimized += [rpath]; - set.insert(rpath, ()); - } - } - ret minimized; -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -#[cfg(target_os = "freebsd")] -mod test { - #[test] - fn test_rpaths_to_flags() { - let flags = rpaths_to_flags(["path1", "path2"]); - assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]; - } - - #[test] - fn test_get_absolute1() { - let cwd = "/dir"; - let lib = "some/path/lib"; - let res = get_absolute(cwd, lib); - assert res == "/dir/some/path/lib"; - } - - #[test] - fn test_get_absolute2() { - let cwd = "/dir"; - let lib = "/some/path/lib"; - let res = get_absolute(cwd, lib); - assert res == "/some/path/lib"; - } - - #[test] - fn test_prefix_rpath() { - let res = get_install_prefix_rpath("/usr/lib", "triple"); - let d = fs::connect(#env("CFG_PREFIX"), "/lib/rustc/triple/lib"); - assert str::ends_with(res, d); - } - - #[test] - fn test_prefix_rpath_abs() { - let res = get_install_prefix_rpath("/usr/lib", "triple"); - assert fs::path_is_absolute(res); - } - - #[test] - fn test_minimize1() { - let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]); - assert res == ["rpath1", "rpath2"]; - } - - #[test] - fn test_minimize2() { - let res = minimize_rpaths(["1a", "2", "2", "1a", "4a", - "1a", "2", "3", "4a", "3"]); - assert res == ["1a", "2", "4a", "3"]; - } - - #[test] - fn test_relative_to1() { - let p1 = "/usr/bin/rustc"; - let p2 = "/usr/lib/mylib"; - let res = get_relative_to(p1, p2); - assert res == "../lib"; - } - - #[test] - fn test_relative_to2() { - let p1 = "/usr/bin/rustc"; - let p2 = "/usr/bin/../lib/mylib"; - let res = get_relative_to(p1, p2); - assert res == "../lib"; - } - - #[test] - fn test_relative_to3() { - let p1 = "/usr/bin/whatever/rustc"; - let p2 = "/usr/lib/whatever/mylib"; - let res = get_relative_to(p1, p2); - assert res == "../../lib/whatever"; - } - - #[test] - fn test_relative_to4() { - let p1 = "/usr/bin/whatever/../rustc"; - let p2 = "/usr/lib/whatever/mylib"; - let res = get_relative_to(p1, p2); - assert res == "../lib/whatever"; - } - - #[test] - fn test_relative_to5() { - let p1 = "/usr/bin/whatever/../rustc"; - let p2 = "/usr/lib/whatever/../mylib"; - let res = get_relative_to(p1, p2); - assert res == "../lib"; - } - - #[test] - fn test_relative_to6() { - let p1 = "/1"; - let p2 = "/2/3"; - let res = get_relative_to(p1, p2); - assert res == "2"; - } - - #[test] - fn test_relative_to7() { - let p1 = "/1/2"; - let p2 = "/3"; - let res = get_relative_to(p1, p2); - assert res == ".."; - } - - #[test] - fn test_relative_to8() { - let p1 = "/home/brian/Dev/rust/build/" - + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"; - let p2 = "/home/brian/Dev/rust/build/stage2/bin/.." - + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"; - let res = get_relative_to(p1, p2); - assert res == "."; - } - - #[test] - #[cfg(target_os = "linux")] - fn test_rpath_relative() { - let o = session::os_linux; - check not_win32(o); - let res = get_rpath_relative_to_output(o, - "/usr", "bin/rustc", "lib/libstd.so"); - assert res == "$ORIGIN/../lib"; - } - - #[test] - #[cfg(target_os = "freebsd")] - fn test_rpath_relative() { - let o = session::os_freebsd; - check not_win32(o); - let res = get_rpath_relative_to_output(o, - "/usr", "bin/rustc", "lib/libstd.so"); - assert res == "$ORIGIN/../lib"; - } - - #[test] - #[cfg(target_os = "macos")] - fn test_rpath_relative() { - // this is why refinements would be nice - let o = session::os_macos; - check not_win32(o); - let res = get_rpath_relative_to_output(o, "/usr", "bin/rustc", - "lib/libstd.so"); - assert res == "@executable_path/../lib"; - } - - #[test] - fn test_get_absolute_rpath() { - let res = get_absolute_rpath("/usr", "lib/libstd.so"); - assert res == "/usr/lib"; - } -} diff --git a/src/comp/back/target_strs.rs b/src/comp/back/target_strs.rs deleted file mode 100644 index cc40746b71c..00000000000 --- a/src/comp/back/target_strs.rs +++ /dev/null @@ -1,7 +0,0 @@ -type t = { - module_asm: str, - meta_sect_name: str, - data_layout: str, - target_triple: str, - cc_args: [str] -}; diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs deleted file mode 100644 index 31ee139c524..00000000000 --- a/src/comp/back/upcall.rs +++ /dev/null @@ -1,130 +0,0 @@ - -import driver::session; -import middle::trans::base; -import middle::trans::common::{T_fn, T_i1, T_i8, T_i32, - T_int, T_nil, T_dict, - T_opaque_vec, T_ptr, - T_size_t, T_void}; -import lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef}; - -type upcalls = - {_fail: ValueRef, - malloc: ValueRef, - free: ValueRef, - validate_box: ValueRef, - shared_malloc: ValueRef, - shared_free: ValueRef, - shared_realloc: ValueRef, - mark: ValueRef, - create_shared_type_desc: ValueRef, - free_shared_type_desc: ValueRef, - get_type_desc: ValueRef, - intern_dict: ValueRef, - vec_grow: ValueRef, - vec_push: ValueRef, - cmp_type: ValueRef, - log_type: ValueRef, - dynastack_mark: ValueRef, - dynastack_alloc: ValueRef, - dynastack_free: ValueRef, - alloc_c_stack: ValueRef, - call_shim_on_c_stack: ValueRef, - call_shim_on_rust_stack: ValueRef, - rust_personality: ValueRef, - reset_stack_limit: ValueRef}; - -fn declare_upcalls(targ_cfg: @session::config, - _tn: type_names, - tydesc_type: TypeRef, - llmod: ModuleRef) -> @upcalls { - fn decl(llmod: ModuleRef, prefix: str, name: str, - tys: [TypeRef], rv: TypeRef) -> - ValueRef { - let arg_tys: [TypeRef] = []; - for t: TypeRef in tys { arg_tys += [t]; } - let fn_ty = T_fn(arg_tys, rv); - ret base::decl_cdecl_fn(llmod, prefix + name, fn_ty); - } - let d = bind decl(llmod, "upcall_", _, _, _); - let dv = bind decl(llmod, "upcall_", _, _, T_void()); - let dvi = bind decl(llmod, "upcall_intrinsic_", _, _, T_void()); - - let int_t = T_int(targ_cfg); - let size_t = T_size_t(targ_cfg); - let opaque_vec_t = T_opaque_vec(targ_cfg); - - ret @{_fail: dv("fail", [T_ptr(T_i8()), - T_ptr(T_i8()), - size_t]), - malloc: - d("malloc", [T_ptr(tydesc_type)], T_ptr(T_i8())), - free: - dv("free", [T_ptr(T_i8())]), - validate_box: - dv("validate_box", [T_ptr(T_i8())]), - shared_malloc: - d("shared_malloc", [size_t], T_ptr(T_i8())), - shared_free: - dv("shared_free", [T_ptr(T_i8())]), - shared_realloc: - d("shared_realloc", [T_ptr(T_i8()), size_t], T_ptr(T_i8())), - mark: - d("mark", [T_ptr(T_i8())], int_t), - create_shared_type_desc: - d("create_shared_type_desc", [T_ptr(tydesc_type)], - T_ptr(tydesc_type)), - free_shared_type_desc: - dv("free_shared_type_desc", [T_ptr(tydesc_type)]), - get_type_desc: - d("get_type_desc", - [T_ptr(T_nil()), size_t, - size_t, size_t, - T_ptr(T_ptr(tydesc_type)), int_t], - T_ptr(tydesc_type)), - intern_dict: - d("intern_dict", [size_t, T_ptr(T_dict())], T_ptr(T_dict())), - vec_grow: - dv("vec_grow", [T_ptr(T_ptr(opaque_vec_t)), int_t]), - vec_push: - dvi("vec_push", - [T_ptr(T_ptr(opaque_vec_t)), T_ptr(tydesc_type), - T_ptr(T_i8())]), - cmp_type: - dv("cmp_type", - [T_ptr(T_i1()), T_ptr(tydesc_type), - T_ptr(T_ptr(tydesc_type)), T_ptr(T_i8()), T_ptr(T_i8()), - T_i8()]), - log_type: - dv("log_type", [T_ptr(tydesc_type), T_ptr(T_i8()), T_i32()]), - dynastack_mark: - d("dynastack_mark", [], T_ptr(T_i8())), - dynastack_alloc: - d("dynastack_alloc_2", [size_t, T_ptr(tydesc_type)], - T_ptr(T_i8())), - dynastack_free: - dv("dynastack_free", [T_ptr(T_i8())]), - alloc_c_stack: - d("alloc_c_stack", [size_t], T_ptr(T_i8())), - call_shim_on_c_stack: - d("call_shim_on_c_stack", - // arguments: void *args, void *fn_ptr - [T_ptr(T_i8()), T_ptr(T_i8())], - int_t), - call_shim_on_rust_stack: - d("call_shim_on_rust_stack", - [T_ptr(T_i8()), T_ptr(T_i8())], int_t), - rust_personality: - d("rust_personality", [], T_i32()), - reset_stack_limit: - dv("reset_stack_limit", []) - }; -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/back/x86.rs b/src/comp/back/x86.rs deleted file mode 100644 index 3db3d1db50a..00000000000 --- a/src/comp/back/x86.rs +++ /dev/null @@ -1,53 +0,0 @@ -import driver::session; - -fn get_target_strs(target_os: session::os) -> target_strs::t { - ret { - module_asm: "", - - meta_sect_name: alt target_os { - session::os_macos { "__DATA,__note.rustc" } - session::os_win32 { ".note.rustc" } - session::os_linux { ".note.rustc" } - session::os_freebsd { ".note.rustc" } - }, - - data_layout: alt target_os { - session::os_macos { - "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16" + "-i32:32:32-i64:32:64" + - "-f32:32:32-f64:32:64-v64:64:64" + - "-v128:128:128-a0:0:64-f80:128:128" + "-n8:16:32" - } - - session::os_win32 { - "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32" - } - - session::os_linux { - "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32" - } - - session::os_freebsd { - "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32" - } - }, - - target_triple: alt target_os { - session::os_macos { "i686-apple-darwin" } - session::os_win32 { "i686-pc-mingw32" } - session::os_linux { "i686-unknown-linux-gnu" } - session::os_freebsd { "i686-unknown-freebsd" } - }, - - cc_args: ["-m32"] - }; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/back/x86_64.rs b/src/comp/back/x86_64.rs deleted file mode 100644 index 284152c23c6..00000000000 --- a/src/comp/back/x86_64.rs +++ /dev/null @@ -1,60 +0,0 @@ -import driver::session; - -fn get_target_strs(target_os: session::os) -> target_strs::t { - ret { - module_asm: "", - - meta_sect_name: alt target_os { - session::os_macos { "__DATA,__note.rustc" } - session::os_win32 { ".note.rustc" } - session::os_linux { ".note.rustc" } - session::os_freebsd { ".note.rustc" } - }, - - data_layout: alt target_os { - session::os_macos { - "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ - "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ - "s0:64:64-f80:128:128-n8:16:32:64" - } - - session::os_win32 { - // FIXME: Test this. Copied from linux - "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ - "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ - "s0:64:64-f80:128:128-n8:16:32:64-S128" - } - - session::os_linux { - "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ - "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ - "s0:64:64-f80:128:128-n8:16:32:64-S128" - } - - session::os_freebsd { - "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ - "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ - "s0:64:64-f80:128:128-n8:16:32:64-S128" - } - }, - - target_triple: alt target_os { - session::os_macos { "x86_64-apple-darwin" } - session::os_win32 { "x86_64-pc-mingw32" } - session::os_linux { "x86_64-unknown-linux-gnu" } - session::os_freebsd { "x86_64-unknown-freebsd" } - }, - - cc_args: ["-m64"] - }; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/driver/diagnostic.rs b/src/comp/driver/diagnostic.rs deleted file mode 100644 index 8f0570a4349..00000000000 --- a/src/comp/driver/diagnostic.rs +++ /dev/null @@ -1,256 +0,0 @@ -import std::{io, term}; -import io::writer_util; -import syntax::codemap; -import codemap::span; - -export emitter, emit; -export level, fatal, error, warning, note; -export span_handler, handler, mk_span_handler, mk_handler; -export codemap_span_handler, codemap_handler; -export ice_msg; - -type emitter = fn@(cmsp: option<(codemap::codemap, span)>, - msg: str, lvl: level); - - -iface span_handler { - fn span_fatal(sp: span, msg: str) -> !; - fn span_err(sp: span, msg: str); - fn span_warn(sp: span, msg: str); - fn span_note(sp: span, msg: str); - fn span_bug(sp: span, msg: str) -> !; - fn span_unimpl(sp: span, msg: str) -> !; - fn handler() -> handler; -} - -iface handler { - fn fatal(msg: str) -> !; - fn err(msg: str); - fn bump_err_count(); - fn has_errors() -> bool; - fn abort_if_errors(); - fn warn(msg: str); - fn note(msg: str); - fn bug(msg: str) -> !; - fn unimpl(msg: str) -> !; - fn emit(cmsp: option<(codemap::codemap, span)>, msg: str, lvl: level); -} - -type handler_t = @{ - mutable err_count: uint, - _emit: emitter -}; - -type codemap_t = @{ - handler: handler, - cm: codemap::codemap -}; - -impl codemap_span_handler of span_handler for codemap_t { - fn span_fatal(sp: span, msg: str) -> ! { - self.handler.emit(some((self.cm, sp)), msg, fatal); - fail; - } - fn span_err(sp: span, msg: str) { - self.handler.emit(some((self.cm, sp)), msg, error); - self.handler.bump_err_count(); - } - fn span_warn(sp: span, msg: str) { - self.handler.emit(some((self.cm, sp)), msg, warning); - } - fn span_note(sp: span, msg: str) { - self.handler.emit(some((self.cm, sp)), msg, note); - } - fn span_bug(sp: span, msg: str) -> ! { - self.span_fatal(sp, ice_msg(msg)); - } - fn span_unimpl(sp: span, msg: str) -> ! { - self.span_bug(sp, "unimplemented " + msg); - } - fn handler() -> handler { - self.handler - } -} - -impl codemap_handler of handler for handler_t { - fn fatal(msg: str) -> ! { - self._emit(none, msg, fatal); - fail; - } - fn err(msg: str) { - self._emit(none, msg, error); - self.bump_err_count(); - } - fn bump_err_count() { - self.err_count += 1u; - } - fn has_errors() -> bool { self.err_count > 0u } - fn abort_if_errors() { - if self.err_count > 0u { - self.fatal("aborting due to previous errors"); - } - } - fn warn(msg: str) { - self._emit(none, msg, warning); - } - fn note(msg: str) { - self._emit(none, msg, note); - } - fn bug(msg: str) -> ! { - self.fatal(ice_msg(msg)); - } - fn unimpl(msg: str) -> ! { self.bug("unimplemented " + msg); } - fn emit(cmsp: option<(codemap::codemap, span)>, msg: str, lvl: level) { - self._emit(cmsp, msg, lvl); - } -} - -fn ice_msg(msg: str) -> str { - #fmt["internal compiler error %s", msg] -} - -fn mk_span_handler(handler: handler, cm: codemap::codemap) -> span_handler { - @{ handler: handler, cm: cm } as span_handler -} - -fn mk_handler(emitter: option<emitter>) -> handler { - - let emit = alt emitter { - some(e) { e } - none { - let f = fn@(cmsp: option<(codemap::codemap, span)>, - msg: str, t: level) { - emit(cmsp, msg, t); - }; - f - } - }; - - @{ - mutable err_count: 0u, - _emit: emit - } as handler -} - -enum level { - fatal, - error, - warning, - note, -} - -fn diagnosticstr(lvl: level) -> str { - alt lvl { - fatal { "error" } - error { "error" } - warning { "warning" } - note { "note" } - } -} - -fn diagnosticcolor(lvl: level) -> u8 { - alt lvl { - fatal { term::color_bright_red } - error { term::color_bright_red } - warning { term::color_bright_yellow } - note { term::color_bright_green } - } -} - -fn print_diagnostic(topic: str, lvl: level, msg: str) { - if str::is_not_empty(topic) { - io::stderr().write_str(#fmt["%s ", topic]); - } - if term::color_supported() { - term::fg(io::stderr(), diagnosticcolor(lvl)); - } - io::stderr().write_str(#fmt["%s:", diagnosticstr(lvl)]); - if term::color_supported() { - term::reset(io::stderr()); - } - io::stderr().write_str(#fmt[" %s\n", msg]); -} - -fn emit(cmsp: option<(codemap::codemap, span)>, - msg: str, lvl: level) { - alt cmsp { - some((cm, sp)) { - let sp = codemap::adjust_span(cm,sp); - let ss = codemap::span_to_str(sp, cm); - let lines = codemap::span_to_lines(sp, cm); - print_diagnostic(ss, lvl, msg); - highlight_lines(cm, sp, lines); - print_macro_backtrace(cm, sp); - } - none { - print_diagnostic("", lvl, msg); - } - } -} - -fn highlight_lines(cm: codemap::codemap, sp: span, - lines: @codemap::file_lines) { - - let fm = lines.file; - - // arbitrarily only print up to six lines of the error - let max_lines = 6u; - let elided = false; - let display_lines = lines.lines; - if vec::len(display_lines) > max_lines { - display_lines = vec::slice(display_lines, 0u, max_lines); - elided = true; - } - // Print the offending lines - for line: uint in display_lines { - io::stderr().write_str(#fmt["%s:%u ", fm.name, line + 1u]); - let s = codemap::get_line(fm, line as int) + "\n"; - io::stderr().write_str(s); - } - if elided { - let last_line = display_lines[vec::len(display_lines) - 1u]; - let s = #fmt["%s:%u ", fm.name, last_line + 1u]; - let indent = str::len(s); - let out = ""; - while indent > 0u { out += " "; indent -= 1u; } - out += "...\n"; - io::stderr().write_str(out); - } - - - // If there's one line at fault we can easily point to the problem - if vec::len(lines.lines) == 1u { - let lo = codemap::lookup_char_pos(cm, sp.lo); - let digits = 0u; - let num = (lines.lines[0] + 1u) / 10u; - - // how many digits must be indent past? - while num > 0u { num /= 10u; digits += 1u; } - - // indent past |name:## | and the 0-offset column location - let left = str::len(fm.name) + digits + lo.col + 3u; - let s = ""; - while left > 0u { str::push_char(s, ' '); left -= 1u; } - - s += "^"; - let hi = codemap::lookup_char_pos(cm, sp.hi); - if hi.col != lo.col { - // the ^ already takes up one space - let width = hi.col - lo.col - 1u; - while width > 0u { str::push_char(s, '~'); width -= 1u; } - } - io::stderr().write_str(s + "\n"); - } -} - -fn print_macro_backtrace(cm: codemap::codemap, sp: span) { - option::may (sp.expn_info) {|ei| - let ss = option::maybe("", ei.callie.span, - bind codemap::span_to_str(_, cm)); - print_diagnostic(ss, note, - #fmt("in expansion of #%s", ei.callie.name)); - let ss = codemap::span_to_str(ei.call_site, cm); - print_diagnostic(ss, note, "expansion site"); - print_macro_backtrace(cm, ei.call_site); - } -} diff --git a/src/comp/driver/driver.rs b/src/comp/driver/driver.rs deleted file mode 100644 index 4aaabc667ba..00000000000 --- a/src/comp/driver/driver.rs +++ /dev/null @@ -1,667 +0,0 @@ - -// -*- rust -*- -import metadata::{creader, cstore}; -import session::session; -import syntax::parse::{parser}; -import syntax::{ast, codemap}; -import front::attr; -import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage, - last_use, lint, inline}; -import syntax::print::{pp, pprust}; -import util::{ppaux, filesearch}; -import back::link; -import result::{ok, err}; -import std::{fs, io, getopts}; -import io::{reader_util, writer_util}; -import getopts::{optopt, optmulti, optflag, optflagopt, opt_present}; -import back::{x86, x86_64}; - -enum pp_mode { ppm_normal, ppm_expanded, ppm_typed, ppm_identified, } - -fn default_configuration(sess: session, argv0: str, input: str) -> - ast::crate_cfg { - let libc = alt sess.targ_cfg.os { - session::os_win32 { "msvcrt.dll" } - session::os_macos { "libc.dylib" } - session::os_linux { "libc.so.6" } - session::os_freebsd { "libc.so.7" } - _ { "libc.so" } - }; - - let mk = attr::mk_name_value_item_str; - - let arch = alt sess.targ_cfg.arch { - session::arch_x86 { "x86" } - session::arch_x86_64 { "x86_64" } - session::arch_arm { "arm" } - }; - - ret [ // Target bindings. - mk("target_os", std::os::target_os()), - mk("target_arch", arch), - mk("target_libc", libc), - // Build bindings. - mk("build_compiler", argv0), - mk("build_input", input)]; -} - -fn build_configuration(sess: session, argv0: str, input: str) -> - ast::crate_cfg { - // Combine the configuration requested by the session (command line) with - // some default and generated configuration items - let default_cfg = default_configuration(sess, argv0, input); - let user_cfg = sess.opts.cfg; - // If the user wants a test runner, then add the test cfg - let gen_cfg = - { - if sess.opts.test && !attr::contains_name(user_cfg, "test") - { - [attr::mk_word_item("test")] - } else { [] } - }; - ret user_cfg + gen_cfg + default_cfg; -} - -// Convert strings provided as --cfg [cfgspec] into a crate_cfg -fn parse_cfgspecs(cfgspecs: [str]) -> ast::crate_cfg { - // FIXME: It would be nice to use the parser to parse all varieties of - // meta_item here. At the moment we just support the meta_word variant. - let words = []; - for s: str in cfgspecs { words += [attr::mk_word_item(s)]; } - ret words; -} - -fn input_is_stdin(filename: str) -> bool { filename == "-" } - -fn parse_input(sess: session, cfg: ast::crate_cfg, input: str) - -> @ast::crate { - if !input_is_stdin(input) { - parser::parse_crate_from_file(input, cfg, sess.parse_sess) - } else { - let src = @str::from_bytes(io::stdin().read_whole_stream()); - parser::parse_crate_from_source_str(input, src, cfg, sess.parse_sess) - } -} - -fn time<T>(do_it: bool, what: str, thunk: fn@() -> T) -> T { - if !do_it { ret thunk(); } - let start = std::time::precise_time_s(); - let rv = thunk(); - let end = std::time::precise_time_s(); - io::stdout().write_str(#fmt("time: %3.3f s\t%s\n", - end - start, what)); - ret rv; -} - -enum compile_upto { - cu_parse, - cu_expand, - cu_typeck, - cu_no_trans, - cu_everything, -} - -fn compile_upto(sess: session, cfg: ast::crate_cfg, - input: str, upto: compile_upto, - outputs: option<output_filenames>) - -> {crate: @ast::crate, tcx: option<ty::ctxt>} { - let time_passes = sess.opts.time_passes; - let crate = time(time_passes, "parsing", - bind parse_input(sess, cfg, input)); - if upto == cu_parse { ret {crate: crate, tcx: none}; } - - sess.building_library = session::building_library( - sess.opts.crate_type, crate, sess.opts.test); - - crate = - time(time_passes, "configuration", - bind front::config::strip_unconfigured_items(crate)); - crate = - time(time_passes, "maybe building test harness", - bind front::test::modify_for_testing(sess, crate)); - crate = - time(time_passes, "expansion", - bind syntax::ext::expand::expand_crate(sess, crate)); - - if upto == cu_expand { ret {crate: crate, tcx: none}; } - - crate = - time(time_passes, "core injection", - bind front::core_inject::maybe_inject_libcore_ref(sess, crate)); - - let ast_map = - time(time_passes, "ast indexing", - bind middle::ast_map::map_crate(*crate)); - time(time_passes, "external crate/lib resolution", - bind creader::read_crates(sess, *crate)); - let {def_map, exp_map, impl_map} = - time(time_passes, "resolution", - bind resolve::resolve_crate(sess, ast_map, crate)); - let freevars = - time(time_passes, "freevar finding", - bind freevars::annotate_freevars(def_map, crate)); - let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars); - let (method_map, dict_map) = - time(time_passes, "typechecking", - bind typeck::check_crate(ty_cx, impl_map, crate)); - time(time_passes, "const checking", - bind middle::check_const::check_crate(sess, crate, method_map)); - - if upto == cu_typeck { ret {crate: crate, tcx: some(ty_cx)}; } - - time(time_passes, "block-use checking", - bind middle::block_use::check_crate(ty_cx, crate)); - time(time_passes, "function usage", - bind fn_usage::check_crate_fn_usage(ty_cx, crate)); - time(time_passes, "alt checking", - bind middle::check_alt::check_crate(ty_cx, crate)); - time(time_passes, "typestate checking", - bind middle::tstate::ck::check_crate(ty_cx, crate)); - let mutbl_map = - time(time_passes, "mutability checking", - bind middle::mutbl::check_crate(ty_cx, crate)); - let (copy_map, ref_map) = - time(time_passes, "alias checking", - bind middle::alias::check_crate(ty_cx, crate)); - let last_uses = time(time_passes, "last use finding", - bind last_use::find_last_uses(crate, def_map, ref_map, ty_cx)); - time(time_passes, "kind checking", - bind kind::check_crate(ty_cx, method_map, last_uses, crate)); - - lint::check_crate(ty_cx, crate, sess.opts.lint_opts, time_passes); - - if upto == cu_no_trans { ret {crate: crate, tcx: some(ty_cx)}; } - let outputs = option::get(outputs); - - let maps = {mutbl_map: mutbl_map, copy_map: copy_map, - last_uses: last_uses, impl_map: impl_map, - method_map: method_map, dict_map: dict_map}; - - let ienbld = sess.opts.inline; - let inline_map = - time(time_passes, "inline", - bind inline::instantiate_inlines(ienbld, ty_cx, maps, crate)); - - let (llmod, link_meta) = - time(time_passes, "translation", - bind trans::base::trans_crate( - sess, crate, ty_cx, outputs.obj_filename, - exp_map, maps, inline_map)); - time(time_passes, "LLVM passes", - bind link::write::run_passes(sess, llmod, outputs.obj_filename)); - - let stop_after_codegen = - sess.opts.output_type != link::output_type_exe || - sess.opts.static && sess.building_library; - - if stop_after_codegen { ret {crate: crate, tcx: some(ty_cx)}; } - - time(time_passes, "Linking", - bind link::link_binary(sess, outputs.obj_filename, - outputs.out_filename, link_meta)); - ret {crate: crate, tcx: some(ty_cx)}; -} - -fn compile_input(sess: session, cfg: ast::crate_cfg, input: str, - outdir: option<str>, output: option<str>) { - - let upto = if sess.opts.parse_only { cu_parse } - else if sess.opts.no_trans { cu_no_trans } - else { cu_everything }; - let outputs = build_output_filenames(input, outdir, output, sess); - compile_upto(sess, cfg, input, upto, some(outputs)); -} - -fn pretty_print_input(sess: session, cfg: ast::crate_cfg, input: str, - ppm: pp_mode) { - fn ann_paren_for_expr(node: pprust::ann_node) { - alt node { pprust::node_expr(s, expr) { pprust::popen(s); } _ { } } - } - fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) { - alt node { - pprust::node_expr(s, expr) { - pp::space(s.s); - pp::word(s.s, "as"); - pp::space(s.s); - pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))); - pprust::pclose(s); - } - _ { } - } - } - fn ann_identified_post(node: pprust::ann_node) { - alt node { - pprust::node_item(s, item) { - pp::space(s.s); - pprust::synth_comment(s, int::to_str(item.id, 10u)); - } - pprust::node_block(s, blk) { - pp::space(s.s); - pprust::synth_comment(s, - "block " + int::to_str(blk.node.id, 10u)); - } - pprust::node_expr(s, expr) { - pp::space(s.s); - pprust::synth_comment(s, int::to_str(expr.id, 10u)); - pprust::pclose(s); - } - _ { } - } - } - - // Because the pretty printer needs to make a pass over the source - // to collect comments and literals, and we need to support reading - // from stdin, we're going to just suck the source into a string - // so both the parser and pretty-printer can use it. - let upto = alt ppm { - ppm_expanded { cu_expand } - ppm_typed { cu_typeck } - _ { cu_parse } - }; - let {crate, tcx} = compile_upto(sess, cfg, input, upto, none); - - let ann: pprust::pp_ann = pprust::no_ann(); - alt ppm { - ppm_typed { - ann = {pre: ann_paren_for_expr, - post: bind ann_typed_post(option::get(tcx), _)}; - } - ppm_identified { - ann = {pre: ann_paren_for_expr, post: ann_identified_post}; - } - ppm_expanded | ppm_normal {} - } - let src = codemap::get_filemap(sess.codemap, input).src; - pprust::print_crate(sess.codemap, sess.span_diagnostic, crate, input, - io::string_reader(*src), io::stdout(), ann); -} - -fn get_os(triple: str) -> option<session::os> { - ret if str::contains(triple, "win32") || - str::contains(triple, "mingw32") { - some(session::os_win32) - } else if str::contains(triple, "darwin") { - some(session::os_macos) - } else if str::contains(triple, "linux") { - some(session::os_linux) - } else if str::contains(triple, "freebsd") { - some(session::os_freebsd) - } else { none }; -} - -fn get_arch(triple: str) -> option<session::arch> { - ret if str::contains(triple, "i386") || str::contains(triple, "i486") || - str::contains(triple, "i586") || - str::contains(triple, "i686") || - str::contains(triple, "i786") { - some(session::arch_x86) - } else if str::contains(triple, "x86_64") { - some(session::arch_x86_64) - } else if str::contains(triple, "arm") || - str::contains(triple, "xscale") { - some(session::arch_arm) - } else { none }; -} - -fn build_target_config(sopts: @session::options, - demitter: diagnostic::emitter) -> @session::config { - let os = alt get_os(sopts.target_triple) { - some(os) { os } - none { early_error(demitter, "Unknown operating system!") } - }; - let arch = alt get_arch(sopts.target_triple) { - some(arch) { arch } - none { early_error(demitter, - "Unknown architecture! " + sopts.target_triple) } - }; - let (int_type, uint_type, float_type) = alt arch { - session::arch_x86 {(ast::ty_i32, ast::ty_u32, ast::ty_f64)} - session::arch_x86_64 {(ast::ty_i64, ast::ty_u64, ast::ty_f64)} - session::arch_arm {(ast::ty_i32, ast::ty_u32, ast::ty_f64)} - }; - let target_strs = alt arch { - session::arch_x86 {x86::get_target_strs(os)} - session::arch_x86_64 {x86_64::get_target_strs(os)} - session::arch_arm {x86::get_target_strs(os)} - }; - let target_cfg: @session::config = - @{os: os, arch: arch, target_strs: target_strs, int_type: int_type, - uint_type: uint_type, float_type: float_type}; - ret target_cfg; -} - -fn host_triple() -> str { - // Get the host triple out of the build environment. This ensures that our - // idea of the host triple is the same as for the set of libraries we've - // actually built. We can't just take LLVM's host triple because they - // normalize all ix86 architectures to i386. - // FIXME: Instead of grabbing the host triple we really should be - // grabbing (at compile time) the target triple that this rustc is - // built with and calling that (at runtime) the host triple. - let ht = #env("CFG_HOST_TRIPLE"); - ret if ht != "" { - ht - } else { - fail "rustc built without CFG_HOST_TRIPLE" - }; -} - -fn build_session_options(match: getopts::match, - demitter: diagnostic::emitter) -> @session::options { - let crate_type = if opt_present(match, "lib") { - session::lib_crate - } else if opt_present(match, "bin") { - session::bin_crate - } else { - session::unknown_crate - }; - let static = opt_present(match, "static"); - - let parse_only = opt_present(match, "parse-only"); - let no_trans = opt_present(match, "no-trans"); - let lint_opts = []; - if opt_present(match, "no-lint-ctypes") { - lint_opts += [(lint::ctypes, false)]; - } - let monomorphize = opt_present(match, "monomorphize"); - let inline = opt_present(match, "inline"); - - let output_type = - if parse_only || no_trans { - link::output_type_none - } else if opt_present(match, "S") && opt_present(match, "emit-llvm") { - link::output_type_llvm_assembly - } else if opt_present(match, "S") { - link::output_type_assembly - } else if opt_present(match, "c") { - link::output_type_object - } else if opt_present(match, "emit-llvm") { - link::output_type_bitcode - } else { link::output_type_exe }; - let verify = !opt_present(match, "no-verify"); - let save_temps = opt_present(match, "save-temps"); - let extra_debuginfo = opt_present(match, "xg"); - let debuginfo = opt_present(match, "g") || extra_debuginfo; - let stats = opt_present(match, "stats"); - let time_passes = opt_present(match, "time-passes"); - let time_llvm_passes = opt_present(match, "time-llvm-passes"); - let sysroot_opt = getopts::opt_maybe_str(match, "sysroot"); - let target_opt = getopts::opt_maybe_str(match, "target"); - let no_asm_comments = getopts::opt_present(match, "no-asm-comments"); - alt output_type { - // unless we're emitting huamn-readable assembly, omit comments. - link::output_type_llvm_assembly | link::output_type_assembly {} - _ { no_asm_comments = true; } - } - let opt_level: uint = - if opt_present(match, "O") { - if opt_present(match, "opt-level") { - early_error(demitter, "-O and --opt-level both provided"); - } - 2u - } else if opt_present(match, "opt-level") { - alt getopts::opt_str(match, "opt-level") { - "0" { 0u } - "1" { 1u } - "2" { 2u } - "3" { 3u } - _ { - early_error(demitter, "optimization level needs " + - "to be between 0-3") - } - } - } else { 0u }; - let target = - alt target_opt { - none { host_triple() } - some(s) { s } - }; - - let addl_lib_search_paths = getopts::opt_strs(match, "L"); - let cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg")); - let test = opt_present(match, "test"); - let warn_unused_imports = opt_present(match, "warn-unused-imports"); - let enforce_mut_vars = opt_present(match, "enforce-mut-vars"); - let sopts: @session::options = - @{crate_type: crate_type, - static: static, - optimize: opt_level, - debuginfo: debuginfo, - extra_debuginfo: extra_debuginfo, - verify: verify, - lint_opts: lint_opts, - save_temps: save_temps, - stats: stats, - time_passes: time_passes, - time_llvm_passes: time_llvm_passes, - output_type: output_type, - addl_lib_search_paths: addl_lib_search_paths, - maybe_sysroot: sysroot_opt, - target_triple: target, - cfg: cfg, - test: test, - parse_only: parse_only, - no_trans: no_trans, - no_asm_comments: no_asm_comments, - monomorphize: monomorphize, - inline: inline, - warn_unused_imports: warn_unused_imports, - enforce_mut_vars: enforce_mut_vars}; - ret sopts; -} - -fn build_session(sopts: @session::options, input: str, - demitter: diagnostic::emitter) -> session { - let codemap = codemap::new_codemap(); - let diagnostic_handler = - diagnostic::mk_handler(some(demitter)); - let span_diagnostic_handler = - diagnostic::mk_span_handler(diagnostic_handler, codemap); - build_session_(sopts, input, codemap, demitter, - span_diagnostic_handler) -} - -fn build_session_( - sopts: @session::options, input: str, - codemap: codemap::codemap, - demitter: diagnostic::emitter, - span_diagnostic_handler: diagnostic::span_handler -) -> session { - let target_cfg = build_target_config(sopts, demitter); - let cstore = cstore::mk_cstore(); - let filesearch = filesearch::mk_filesearch( - sopts.maybe_sysroot, - sopts.target_triple, - sopts.addl_lib_search_paths); - @{targ_cfg: target_cfg, - opts: sopts, - cstore: cstore, - parse_sess: @{ - cm: codemap, - mutable next_id: 1, - span_diagnostic: span_diagnostic_handler, - mutable chpos: 0u, - mutable byte_pos: 0u - }, - codemap: codemap, - // For a library crate, this is always none - mutable main_fn: none, - span_diagnostic: span_diagnostic_handler, - filesearch: filesearch, - mutable building_library: false, - working_dir: fs::dirname(input)} -} - -fn parse_pretty(sess: session, &&name: str) -> pp_mode { - if str::eq(name, "normal") { - ret ppm_normal; - } else if str::eq(name, "expanded") { - ret ppm_expanded; - } else if str::eq(name, "typed") { - ret ppm_typed; - } else if str::eq(name, "identified") { ret ppm_identified; } - sess.fatal("argument to `pretty` must be one of `normal`, `typed`, or " + - "`identified`"); -} - -fn opts() -> [getopts::opt] { - ret [optflag("h"), optflag("help"), optflag("v"), optflag("version"), - optflag("emit-llvm"), optflagopt("pretty"), - optflag("ls"), optflag("parse-only"), optflag("no-trans"), - optflag("O"), optopt("opt-level"), optmulti("L"), optflag("S"), - optopt("o"), optopt("out-dir"), optflag("xg"), - optflag("c"), optflag("g"), optflag("save-temps"), - optopt("sysroot"), optopt("target"), optflag("stats"), - optflag("time-passes"), optflag("time-llvm-passes"), - optflag("no-verify"), - optflag("no-lint-ctypes"), - optflag("monomorphize"), - optflag("inline"), - optmulti("cfg"), optflag("test"), - optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"), - optflag("no-asm-comments"), - optflag("warn-unused-imports"), - optflag("enforce-mut-vars")]; -} - -type output_filenames = @{out_filename: str, obj_filename:str}; - -fn build_output_filenames(ifile: str, - odir: option<str>, - ofile: option<str>, - sess: session) - -> output_filenames { - let obj_path = ""; - let out_path: str = ""; - let sopts = sess.opts; - let stop_after_codegen = - sopts.output_type != link::output_type_exe || - sopts.static && sess.building_library; - - - let obj_suffix = - alt sopts.output_type { - link::output_type_none { "none" } - link::output_type_bitcode { "bc" } - link::output_type_assembly { "s" } - link::output_type_llvm_assembly { "ll" } - // Object and exe output both use the '.o' extension here - link::output_type_object | link::output_type_exe { - "o" - } - }; - - alt ofile { - none { - // "-" as input file will cause the parser to read from stdin so we - // have to make up a name - // We want to toss everything after the final '.' - let dirname = alt odir { - some(d) { d } - none { - if input_is_stdin(ifile) { - std::os::getcwd() - } else { - fs::dirname(ifile) - } - } - }; - - let base_filename = if !input_is_stdin(ifile) { - let (path, _) = fs::splitext(ifile); - fs::basename(path) - } else { - "rust_out" - }; - let base_path = fs::connect(dirname, base_filename); - - - if sess.building_library { - let basename = fs::basename(base_path); - let dylibname = std::os::dylib_filename(basename); - out_path = fs::connect(dirname, dylibname); - obj_path = fs::connect(dirname, basename + "." + obj_suffix); - } else { - out_path = base_path; - obj_path = base_path + "." + obj_suffix; - } - } - - some(out_file) { - out_path = out_file; - obj_path = if stop_after_codegen { - out_file - } else { - let (base, _) = fs::splitext(out_file); - let modified = base + "." + obj_suffix; - modified - }; - - if sess.building_library { - // FIXME: We might want to warn here; we're actually not going to - // respect the user's choice of library name when it comes time to - // link, we'll be linking to lib<basename>-<hash>-<version>.so no - // matter what. - } - - if odir != none { - sess.warn("Ignoring --out-dir flag due to -o flag."); - } - } - } - ret @{out_filename: out_path, - obj_filename: obj_path}; -} - -fn early_error(emitter: diagnostic::emitter, msg: str) -> ! { - emitter(none, msg, diagnostic::fatal); - fail; -} - -fn list_metadata(sess: session, path: str, out: io::writer) { - metadata::creader::list_file_metadata(sess, path, out); -} - -#[cfg(test)] -mod test { - - // When the user supplies --test we should implicitly supply --cfg test - #[test] - fn test_switch_implies_cfg_test() { - let match = - alt getopts::getopts(["--test"], opts()) { - ok(m) { m } - err(f) { fail "test_switch_implies_cfg_test: " + - getopts::fail_str(f); } - }; - let sessopts = build_session_options(match, diagnostic::emit); - let sess = build_session(sessopts, "", diagnostic::emit); - let cfg = build_configuration(sess, "whatever", "whatever"); - assert (attr::contains_name(cfg, "test")); - } - - // When the user supplies --test and --cfg test, don't implicitly add - // another --cfg test - #[test] - fn test_switch_implies_cfg_test_unless_cfg_test() { - let match = - alt getopts::getopts(["--test", "--cfg=test"], opts()) { - ok(m) { m } - err(f) { fail "test_switch_implies_cfg_test_unless_cfg_test: " + - getopts::fail_str(f); } - }; - let sessopts = build_session_options(match, diagnostic::emit); - let sess = build_session(sessopts, "", diagnostic::emit); - let cfg = build_configuration(sess, "whatever", "whatever"); - let test_items = attr::find_meta_items_by_name(cfg, "test"); - assert (vec::len(test_items) == 1u); - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs deleted file mode 100644 index 8d0b8549062..00000000000 --- a/src/comp/driver/rustc.rs +++ /dev/null @@ -1,197 +0,0 @@ -use std; -use rustc; - -// -*- rust -*- -import result::{ok, err}; -import std::{io, getopts}; -import io::writer_util; -import getopts::{opt_present}; -import rustc::driver::driver::*; -import rustc::syntax::codemap; -import rustc::driver::diagnostic; - -fn version(argv0: str) { - let vers = "unknown version"; - let env_vers = #env["CFG_VERSION"]; - if str::len(env_vers) != 0u { vers = env_vers; } - io::stdout().write_str(#fmt["%s %s\n", argv0, vers]); - io::stdout().write_str(#fmt["host: %s\n", host_triple()]); -} - -fn usage(argv0: str) { - io::stdout().write_str(#fmt["Usage: %s [options] <input>\n", argv0] + - " -Options: - - --bin Compile an executable crate (default) - -c Compile and assemble, but do not link - --cfg <cfgspec> Configure the compilation environment - --emit-llvm Produce an LLVM bitcode file - -g Produce debug info - --gc Garbage collect shared data (experimental/temporary) - -h --help Display this message - -L <path> Add a directory to the library search path - --lib Compile a library crate - --ls List the symbols defined by a compiled library crate - --no-asm-comments Do not add comments into the assembly source - --no-lint-ctypes Suppress warnings for possibly incorrect ctype usage - --no-trans Run all passes except translation; no output - --no-verify Suppress LLVM verification step (slight speedup) - (see http://llvm.org/docs/Passes.html for detail) - -O Equivalent to --opt-level=2 - -o <filename> Write output to <filename> - --opt-level <lvl> Optimize with possible levels 0-3 - --out-dir <dir> Write output to compiler-chosen filename in <dir> - --parse-only Parse only; do not compile, assemble, or link - --pretty [type] Pretty-print the input instead of compiling; - valid types are: normal (un-annotated source), - expanded (crates expanded), typed (crates expanded, - with type annotations), or identified (fully - parenthesized, AST nodes and blocks with IDs) - -S Compile only; do not assemble or link - --save-temps Write intermediate files (.bc, .opt.bc, .o) - in addition to normal output - --static Use or produce static libraries or binaries - --stats Print compilation statistics - --sysroot <path> Override the system root - --test Build a test harness - --target <triple> Target cpu-manufacturer-kernel[-os] to compile for - (default: host triple) - (see http://sources.redhat.com/autobook/autobook/ - autobook_17.html for detail) - - --time-passes Time the individual phases of the compiler - --time-llvm-passes Time the individual phases of the LLVM backend - -v --version Print version info and exit - --warn-unused-imports - Warn about unnecessary imports - -"); -} - -fn run_compiler(args: [str], demitter: diagnostic::emitter) { - // Don't display log spew by default. Can override with RUST_LOG. - logging::console_off(); - - let args = args, binary = vec::shift(args); - - if vec::len(args) == 0u { usage(binary); ret; } - - let match = - alt getopts::getopts(args, opts()) { - ok(m) { m } - err(f) { - early_error(demitter, getopts::fail_str(f)) - } - }; - if opt_present(match, "h") || opt_present(match, "help") { - usage(binary); - ret; - } - if opt_present(match, "v") || opt_present(match, "version") { - version(binary); - ret; - } - let ifile = alt vec::len(match.free) { - 0u { early_error(demitter, "No input filename given.") } - 1u { match.free[0] } - _ { early_error(demitter, "Multiple input filenames provided.") } - }; - - let sopts = build_session_options(match, demitter); - let sess = build_session(sopts, ifile, demitter); - let odir = getopts::opt_maybe_str(match, "out-dir"); - let ofile = getopts::opt_maybe_str(match, "o"); - let cfg = build_configuration(sess, binary, ifile); - let pretty = - option::map(getopts::opt_default(match, "pretty", - "normal"), - bind parse_pretty(sess, _)); - alt pretty { - some::<pp_mode>(ppm) { pretty_print_input(sess, cfg, ifile, ppm); ret; } - none::<pp_mode> {/* continue */ } - } - let ls = opt_present(match, "ls"); - if ls { - list_metadata(sess, ifile, io::stdout()); - ret; - } - - compile_input(sess, cfg, ifile, odir, ofile); -} - -/* -This is a sanity check that any failure of the compiler is performed -through the diagnostic module and reported properly - we shouldn't be calling -plain-old-fail on any execution path that might be taken. Since we have -console logging off by default, hitting a plain fail statement would make the -compiler silently exit, which would be terrible. - -This method wraps the compiler in a subtask and injects a function into the -diagnostic emitter which records when we hit a fatal error. If the task -fails without recording a fatal error then we've encountered a compiler -bug and need to present an error. -*/ -fn monitor(f: fn~(diagnostic::emitter)) { - enum monitor_msg { - fatal, - done, - }; - - let p = comm::port(); - let ch = comm::chan(p); - - alt task::try {|| - - // The 'diagnostics emitter'. Every error, warning, etc. should - // go through this function. - let demitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>, - msg: str, lvl: diagnostic::level) { - if lvl == diagnostic::fatal { - comm::send(ch, fatal); - } - diagnostic::emit(cmsp, msg, lvl); - }; - - resource finally(ch: comm::chan<monitor_msg>) { - comm::send(ch, done); - } - - let _finally = finally(ch); - - f(demitter) - } { - result::ok(_) { /* fallthrough */ } - result::err(_) { - // Task failed without emitting a fatal diagnostic - if comm::recv(p) == done { - diagnostic::emit( - none, - diagnostic::ice_msg("unexpected failure"), - diagnostic::error); - let note = "The compiler hit an unexpected failure path. \ - This is a bug. Try running with \ - RUST_LOG=rustc=0,::rt::backtrace \ - to get further details and report the results \ - to github.com/mozilla/rust/issues"; - diagnostic::emit(none, note, diagnostic::note); - } - // Fail so the process returns a failure code - fail; - } - } -} - -fn main(args: [str]) { - monitor {|demitter| - run_compiler(args, demitter); - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs deleted file mode 100644 index ec2182d2929..00000000000 --- a/src/comp/driver/session.rs +++ /dev/null @@ -1,210 +0,0 @@ - -import syntax::{ast, codemap}; -import syntax::ast::node_id; -import codemap::span; -import syntax::ast::{int_ty, uint_ty, float_ty}; -import syntax::parse::parser::parse_sess; -import util::filesearch; -import back::target_strs; -import middle::lint; - -enum os { os_win32, os_macos, os_linux, os_freebsd, } - -enum arch { arch_x86, arch_x86_64, arch_arm, } - -enum crate_type { bin_crate, lib_crate, unknown_crate, } - -type config = - {os: os, - arch: arch, - target_strs: target_strs::t, - int_type: int_ty, - uint_type: uint_ty, - float_type: float_ty}; - -type options = - // The crate config requested for the session, which may be combined - // with additional crate configurations during the compile process - {crate_type: crate_type, - static: bool, - optimize: uint, - debuginfo: bool, - extra_debuginfo: bool, - verify: bool, - lint_opts: [(lint::option, bool)], - save_temps: bool, - stats: bool, - time_passes: bool, - time_llvm_passes: bool, - output_type: back::link::output_type, - addl_lib_search_paths: [str], - maybe_sysroot: option<str>, - target_triple: str, - cfg: ast::crate_cfg, - test: bool, - parse_only: bool, - no_trans: bool, - no_asm_comments: bool, - monomorphize: bool, - inline: bool, - warn_unused_imports: bool, - enforce_mut_vars: bool}; - -type crate_metadata = {name: str, data: [u8]}; - -type session = @{targ_cfg: @config, - opts: @options, - cstore: metadata::cstore::cstore, - parse_sess: parse_sess, - codemap: codemap::codemap, - // For a library crate, this is always none - mutable main_fn: option<(node_id, codemap::span)>, - span_diagnostic: diagnostic::span_handler, - filesearch: filesearch::filesearch, - mutable building_library: bool, - working_dir: str}; - -impl session for session { - fn span_fatal(sp: span, msg: str) -> ! { - self.span_diagnostic.span_fatal(sp, msg) - } - fn fatal(msg: str) -> ! { - self.span_diagnostic.handler().fatal(msg) - } - fn span_err(sp: span, msg: str) { - self.span_diagnostic.span_err(sp, msg) - } - fn err(msg: str) { - self.span_diagnostic.handler().err(msg) - } - fn has_errors() -> bool { - self.span_diagnostic.handler().has_errors() - } - fn abort_if_errors() { - self.span_diagnostic.handler().abort_if_errors() - } - fn span_warn(sp: span, msg: str) { - self.span_diagnostic.span_warn(sp, msg) - } - fn warn(msg: str) { - self.span_diagnostic.handler().warn(msg) - } - fn span_note(sp: span, msg: str) { - self.span_diagnostic.span_note(sp, msg) - } - fn note(msg: str) { - self.span_diagnostic.handler().note(msg) - } - fn span_bug(sp: span, msg: str) -> ! { - self.span_diagnostic.span_bug(sp, msg) - } - fn bug(msg: str) -> ! { - self.span_diagnostic.handler().bug(msg) - } - fn span_unimpl(sp: span, msg: str) -> ! { - self.span_diagnostic.span_unimpl(sp, msg) - } - fn unimpl(msg: str) -> ! { - self.span_diagnostic.handler().unimpl(msg) - } - fn next_node_id() -> ast::node_id { - ret syntax::parse::parser::next_node_id(self.parse_sess); - } -} - -fn building_library(req_crate_type: crate_type, crate: @ast::crate, - testing: bool) -> bool { - alt req_crate_type { - bin_crate { false } - lib_crate { true } - unknown_crate { - if testing { - false - } else { - alt front::attr::get_meta_item_value_str_by_name( - crate.node.attrs, - "crate_type") { - option::some("lib") { true } - _ { false } - } - } - } - } -} - -#[cfg(test)] -mod test { - import syntax::ast_util; - - fn make_crate_type_attr(t: str) -> ast::attribute { - ast_util::respan(ast_util::dummy_sp(), { - style: ast::attr_outer, - value: ast_util::respan(ast_util::dummy_sp(), - ast::meta_name_value( - "crate_type", - ast_util::respan(ast_util::dummy_sp(), - ast::lit_str(t)))) - }) - } - - fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate { - let attrs = []; - if with_bin { attrs += [make_crate_type_attr("bin")]; } - if with_lib { attrs += [make_crate_type_attr("lib")]; } - @ast_util::respan(ast_util::dummy_sp(), { - directives: [], - module: {view_items: [], items: []}, - attrs: attrs, - config: [] - }) - } - - #[test] - fn bin_crate_type_attr_results_in_bin_output() { - let crate = make_crate(true, false); - assert !building_library(unknown_crate, crate, false); - } - - #[test] - fn lib_crate_type_attr_results_in_lib_output() { - let crate = make_crate(false, true); - assert building_library(unknown_crate, crate, false); - } - - #[test] - fn bin_option_overrides_lib_crate_type() { - let crate = make_crate(false, true); - assert !building_library(bin_crate, crate, false); - } - - #[test] - fn lib_option_overrides_bin_crate_type() { - let crate = make_crate(true, false); - assert building_library(lib_crate, crate, false); - } - - #[test] - fn bin_crate_type_is_default() { - let crate = make_crate(false, false); - assert !building_library(unknown_crate, crate, false); - } - - #[test] - fn test_option_overrides_lib_crate_type() { - let crate = make_crate(false, true); - assert !building_library(unknown_crate, crate, true); - } - - #[test] - fn test_option_does_not_override_requested_lib_type() { - let crate = make_crate(false, false); - assert building_library(lib_crate, crate, true); - } -} - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/front/attr.rs b/src/comp/front/attr.rs deleted file mode 100644 index 9a2aea62570..00000000000 --- a/src/comp/front/attr.rs +++ /dev/null @@ -1,308 +0,0 @@ -// Functions dealing with attributes and meta_items - -import std::map; -import syntax::{ast, ast_util}; -import driver::session::session; - -export attr_meta; -export attr_metas; -export find_linkage_metas; -export find_attrs_by_name; -export attrs_contains_name; -export find_meta_items_by_name; -export contains; -export contains_name; -export sort_meta_items; -export remove_meta_items_by_name; -export require_unique_names; -export get_attr_name; -export get_meta_item_name; -export get_meta_item_value_str; -export get_meta_item_value_str_by_name; -export get_meta_item_list; -export meta_item_value_from_list; -export meta_item_list_from_list; -export name_value_str_pair; -export mk_name_value_item_str; -export mk_name_value_item; -export mk_list_item; -export mk_word_item; -export mk_attr; -export native_abi; - -// From a list of crate attributes get only the meta_items that impact crate -// linkage -fn find_linkage_metas(attrs: [ast::attribute]) -> [@ast::meta_item] { - let metas: [@ast::meta_item] = []; - for attr: ast::attribute in find_attrs_by_name(attrs, "link") { - alt attr.node.value.node { - ast::meta_list(_, items) { metas += items; } - _ { #debug("ignoring link attribute that has incorrect type"); } - } - } - ret metas; -} - -// Search a list of attributes and return only those with a specific name -fn find_attrs_by_name(attrs: [ast::attribute], name: ast::ident) -> - [ast::attribute] { - let filter = ( - fn@(a: ast::attribute) -> option<ast::attribute> { - if get_attr_name(a) == name { - option::some(a) - } else { option::none } - } - ); - ret vec::filter_map(attrs, filter); -} - -fn attrs_contains_name(attrs: [ast::attribute], name: ast::ident) -> bool { - vec::is_not_empty(find_attrs_by_name(attrs, name)) -} - -fn get_attr_name(attr: ast::attribute) -> ast::ident { - get_meta_item_name(@attr.node.value) -} - -fn find_meta_items_by_name(metas: [@ast::meta_item], name: ast::ident) -> - [@ast::meta_item] { - let filter = fn@(&&m: @ast::meta_item) -> option<@ast::meta_item> { - if get_meta_item_name(m) == name { - option::some(m) - } else { option::none } - }; - ret vec::filter_map(metas, filter); -} - -fn get_meta_item_name(meta: @ast::meta_item) -> ast::ident { - alt meta.node { - ast::meta_word(n) { n } - ast::meta_name_value(n, _) { n } - ast::meta_list(n, _) { n } - } -} - -// Gets the string value if the meta_item is a meta_name_value variant -// containing a string, otherwise none -fn get_meta_item_value_str(meta: @ast::meta_item) -> option<str> { - alt meta.node { - ast::meta_name_value(_, v) { - alt v.node { ast::lit_str(s) { option::some(s) } _ { option::none } } - } - _ { option::none } - } -} - -fn get_meta_item_value_str_by_name(attrs: [ast::attribute], name: ast::ident) - -> option<str> { - let mattrs = find_attrs_by_name(attrs, name); - if vec::len(mattrs) > 0u { - ret get_meta_item_value_str(attr_meta(mattrs[0])); - } - ret option::none; -} - -fn get_meta_item_list(meta: @ast::meta_item) -> option<[@ast::meta_item]> { - alt meta.node { - ast::meta_list(_, l) { option::some(l) } - _ { option::none } - } -} - -fn attr_meta(attr: ast::attribute) -> @ast::meta_item { @attr.node.value } - -// Get the meta_items from inside a vector of attributes -fn attr_metas(attrs: [ast::attribute]) -> [@ast::meta_item] { - let mitems = []; - for a: ast::attribute in attrs { mitems += [attr_meta(a)]; } - ret mitems; -} - -fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool { - ret alt a.node { - ast::meta_word(na) { - alt b.node { ast::meta_word(nb) { na == nb } _ { false } } - } - ast::meta_name_value(na, va) { - alt b.node { - ast::meta_name_value(nb, vb) { na == nb && va.node == vb.node } - _ { false } - } - } - ast::meta_list(na, la) { - - // FIXME (#607): Needs implementing - // This involves probably sorting the list by name and - // meta_item variant - fail "unimplemented meta_item variant" - } - } -} - -fn contains(haystack: [@ast::meta_item], needle: @ast::meta_item) -> bool { - #debug("looking for %s", - syntax::print::pprust::meta_item_to_str(*needle)); - for item: @ast::meta_item in haystack { - #debug("looking in %s", - syntax::print::pprust::meta_item_to_str(*item)); - if eq(item, needle) { #debug("found it!"); ret true; } - } - #debug("found it not :("); - ret false; -} - -fn contains_name(metas: [@ast::meta_item], name: ast::ident) -> bool { - let matches = find_meta_items_by_name(metas, name); - ret vec::len(matches) > 0u; -} - -// FIXME: This needs to sort by meta_item variant in addition to the item name -fn sort_meta_items(items: [@ast::meta_item]) -> [@ast::meta_item] { - fn lteq(&&ma: @ast::meta_item, &&mb: @ast::meta_item) -> bool { - fn key(m: @ast::meta_item) -> ast::ident { - alt m.node { - ast::meta_word(name) { name } - ast::meta_name_value(name, _) { name } - ast::meta_list(name, _) { name } - } - } - ret key(ma) <= key(mb); - } - - // This is sort of stupid here, converting to a vec of mutables and back - let v: [mutable @ast::meta_item] = [mutable]; - for mi: @ast::meta_item in items { v += [mutable mi]; } - - std::sort::quick_sort(lteq, v); - - let v2: [@ast::meta_item] = []; - for mi: @ast::meta_item in v { v2 += [mi]; } - ret v2; -} - -fn remove_meta_items_by_name(items: [@ast::meta_item], name: str) -> - [@ast::meta_item] { - - let filter = fn@(&&item: @ast::meta_item) -> option<@ast::meta_item> { - if get_meta_item_name(item) != name { - option::some(item) - } else { option::none } - }; - - ret vec::filter_map(items, filter); -} - -fn require_unique_names(sess: session, metas: [@ast::meta_item]) { - let map = map::new_str_hash(); - for meta: @ast::meta_item in metas { - let name = get_meta_item_name(meta); - if map.contains_key(name) { - sess.span_fatal(meta.span, - #fmt["duplicate meta item `%s`", name]); - } - map.insert(name, ()); - } -} - -fn native_abi(attrs: [ast::attribute]) -> either::t<str, ast::native_abi> { - ret alt attr::get_meta_item_value_str_by_name(attrs, "abi") { - option::none { - either::right(ast::native_abi_cdecl) - } - option::some("rust-intrinsic") { - either::right(ast::native_abi_rust_intrinsic) - } - option::some("cdecl") { - either::right(ast::native_abi_cdecl) - } - option::some("stdcall") { - either::right(ast::native_abi_stdcall) - } - option::some(t) { - either::left("unsupported abi: " + t) - } - }; -} - -fn meta_item_from_list( - items: [@ast::meta_item], - name: str -) -> option<@ast::meta_item> { - let items = attr::find_meta_items_by_name(items, name); - vec::last(items) -} - -fn meta_item_value_from_list( - items: [@ast::meta_item], - name: str -) -> option<str> { - alt meta_item_from_list(items, name) { - some(item) { - alt attr::get_meta_item_value_str(item) { - some(value) { some(value) } - none { none } - } - } - none { none } - } -} - -fn meta_item_list_from_list( - items: [@ast::meta_item], - name: str -) -> option<[@ast::meta_item]> { - alt meta_item_from_list(items, name) { - some(item) { - attr::get_meta_item_list(item) - } - none { none } - } -} - -fn name_value_str_pair( - item: @ast::meta_item -) -> option<(str, str)> { - alt attr::get_meta_item_value_str(item) { - some(value) { - let name = attr::get_meta_item_name(item); - some((name, value)) - } - none { none } - } -} - -fn span<T: copy>(item: T) -> ast::spanned<T> { - ret {node: item, span: ast_util::dummy_sp()}; -} - -fn mk_name_value_item_str(name: ast::ident, value: str) -> @ast::meta_item { - let value_lit = span(ast::lit_str(value)); - ret mk_name_value_item(name, value_lit); -} - -fn mk_name_value_item(name: ast::ident, value: ast::lit) -> @ast::meta_item { - ret @span(ast::meta_name_value(name, value)); -} - -fn mk_list_item(name: ast::ident, items: [@ast::meta_item]) -> - @ast::meta_item { - ret @span(ast::meta_list(name, items)); -} - -fn mk_word_item(name: ast::ident) -> @ast::meta_item { - ret @span(ast::meta_word(name)); -} - -fn mk_attr(item: @ast::meta_item) -> ast::attribute { - ret span({style: ast::attr_inner, value: *item}); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/front/config.rs b/src/comp/front/config.rs deleted file mode 100644 index 44c88739069..00000000000 --- a/src/comp/front/config.rs +++ /dev/null @@ -1,134 +0,0 @@ -import syntax::{ast, fold}; - -export strip_unconfigured_items; -export metas_in_cfg; -export strip_items; - -type in_cfg_pred = fn@([ast::attribute]) -> bool; - -type ctxt = @{ - in_cfg: in_cfg_pred -}; - -// Support conditional compilation by transforming the AST, stripping out -// any items that do not belong in the current configuration -fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate { - strip_items(crate) {|attrs| - in_cfg(crate.node.config, attrs) - } -} - -fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred) - -> @ast::crate { - - let ctxt = @{in_cfg: in_cfg}; - - let precursor = - {fold_mod: bind fold_mod(ctxt, _, _), - fold_block: fold::wrap(bind fold_block(ctxt, _, _)), - fold_native_mod: bind fold_native_mod(ctxt, _, _) - with *fold::default_ast_fold()}; - - let fold = fold::make_fold(precursor); - let res = @fold.fold_crate(*crate); - ret res; -} - -fn filter_item(cx: ctxt, &&item: @ast::item) -> - option<@ast::item> { - if item_in_cfg(cx, item) { option::some(item) } else { option::none } -} - -fn fold_mod(cx: ctxt, m: ast::_mod, fld: fold::ast_fold) -> - ast::_mod { - let filter = bind filter_item(cx, _); - let filtered_items = vec::filter_map(m.items, filter); - ret {view_items: vec::map(m.view_items, fld.fold_view_item), - items: vec::map(filtered_items, fld.fold_item)}; -} - -fn filter_native_item(cx: ctxt, &&item: @ast::native_item) -> - option<@ast::native_item> { - if native_item_in_cfg(cx, item) { - option::some(item) - } else { option::none } -} - -fn fold_native_mod(cx: ctxt, nm: ast::native_mod, - fld: fold::ast_fold) -> ast::native_mod { - let filter = bind filter_native_item(cx, _); - let filtered_items = vec::filter_map(nm.items, filter); - ret {view_items: vec::map(nm.view_items, fld.fold_view_item), - items: filtered_items}; -} - -fn filter_stmt(cx: ctxt, &&stmt: @ast::stmt) -> - option<@ast::stmt> { - alt stmt.node { - ast::stmt_decl(decl, _) { - alt decl.node { - ast::decl_item(item) { - if item_in_cfg(cx, item) { - option::some(stmt) - } else { option::none } - } - _ { option::some(stmt) } - } - } - _ { option::some(stmt) } - } -} - -fn fold_block(cx: ctxt, b: ast::blk_, fld: fold::ast_fold) -> - ast::blk_ { - let filter = bind filter_stmt(cx, _); - let filtered_stmts = vec::filter_map(b.stmts, filter); - ret {view_items: b.view_items, - stmts: vec::map(filtered_stmts, fld.fold_stmt), - expr: option::map(b.expr, fld.fold_expr), - id: b.id, - rules: b.rules}; -} - -fn item_in_cfg(cx: ctxt, item: @ast::item) -> bool { - ret cx.in_cfg(item.attrs); -} - -fn native_item_in_cfg(cx: ctxt, item: @ast::native_item) -> bool { - ret cx.in_cfg(item.attrs); -} - -// Determine if an item should be translated in the current crate -// configuration based on the item's attributes -fn in_cfg(cfg: ast::crate_cfg, attrs: [ast::attribute]) -> bool { - metas_in_cfg(cfg, attr::attr_metas(attrs)) -} - -fn metas_in_cfg(cfg: ast::crate_cfg, metas: [@ast::meta_item]) -> bool { - - // The "cfg" attributes on the item - let cfg_metas = attr::find_meta_items_by_name(metas, "cfg"); - - // Pull the inner meta_items from the #[cfg(meta_item, ...)] attributes, - // so we can match against them. This is the list of configurations for - // which the item is valid - let cfg_metas = vec::concat(vec::filter_map(cfg_metas, - {|&&i| attr::get_meta_item_list(i)})); - - let has_cfg_metas = vec::len(cfg_metas) > 0u; - if !has_cfg_metas { ret true; } - - for cfg_mi: @ast::meta_item in cfg_metas { - if attr::contains(cfg, cfg_mi) { ret true; } - } - - ret false; -} - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/front/core_inject.rs b/src/comp/front/core_inject.rs deleted file mode 100644 index b21967721c5..00000000000 --- a/src/comp/front/core_inject.rs +++ /dev/null @@ -1,41 +0,0 @@ -import driver::session::session; -import syntax::codemap; -import syntax::ast; -import front::attr; - -export maybe_inject_libcore_ref; - -fn maybe_inject_libcore_ref(sess: session, - crate: @ast::crate) -> @ast::crate { - if use_core(crate) { - inject_libcore_ref(sess, crate) - } else { - crate - } -} - -fn use_core(crate: @ast::crate) -> bool { - !attr::attrs_contains_name(crate.node.attrs, "no_core") -} - -fn inject_libcore_ref(sess: session, - crate: @ast::crate) -> @ast::crate { - - fn spanned<T: copy>(x: T) -> @ast::spanned<T> { - ret @{node: x, - span: {lo: 0u, hi: 0u, - expn_info: option::none}}; - } - - let n1 = sess.next_node_id(); - let n2 = sess.next_node_id(); - - let vi1 = spanned(ast::view_item_use("core", [], n1)); - let vp = spanned(ast::view_path_glob(@["core"], n2)); - let vi2 = spanned(ast::view_item_import([vp])); - - let vis = [vi1, vi2] + crate.node.module.view_items; - - ret @{node: {module: { view_items: vis with crate.node.module } - with crate.node} with *crate } -} diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs deleted file mode 100644 index 47cd3328755..00000000000 --- a/src/comp/front/test.rs +++ /dev/null @@ -1,470 +0,0 @@ -// Code that generates a test runner to run all the tests in a crate - -import syntax::{ast, ast_util}; -import syntax::ast_util::*; -//import syntax::ast_util::dummy_sp; -import syntax::fold; -import syntax::print::pprust; -import syntax::codemap::span; -import driver::session; -import session::session; -import front::attr; - -export modify_for_testing; - -type node_id_gen = fn@() -> ast::node_id; - -type test = {span: span, path: [ast::ident], ignore: bool, should_fail: bool}; - -type test_ctxt = - @{sess: session::session, - crate: @ast::crate, - mutable path: [ast::ident], - mutable testfns: [test]}; - -// Traverse the crate, collecting all the test functions, eliding any -// existing main functions, and synthesizing a main test harness -fn modify_for_testing(sess: session::session, - crate: @ast::crate) -> @ast::crate { - - if sess.opts.test { - generate_test_harness(sess, crate) - } else { - strip_test_functions(crate) - } -} - -fn generate_test_harness(sess: session::session, - crate: @ast::crate) -> @ast::crate { - let cx: test_ctxt = - @{sess: sess, - crate: crate, - mutable path: [], - mutable testfns: []}; - - let precursor = - {fold_crate: fold::wrap(bind fold_crate(cx, _, _)), - fold_item: bind fold_item(cx, _, _), - fold_mod: bind fold_mod(cx, _, _) with *fold::default_ast_fold()}; - - let fold = fold::make_fold(precursor); - let res = @fold.fold_crate(*crate); - ret res; -} - -fn strip_test_functions(crate: @ast::crate) -> @ast::crate { - // When not compiling with --test we should not compile the - // #[test] functions - config::strip_items(crate) {|attrs| - !attr::contains_name(attr::attr_metas(attrs), "test") - } -} - -fn fold_mod(_cx: test_ctxt, m: ast::_mod, fld: fold::ast_fold) -> ast::_mod { - - // Remove any defined main function from the AST so it doesn't clash with - // the one we're going to add. FIXME: This is sloppy. Instead we should - // have some mechanism to indicate to the translation pass which function - // we want to be main. - fn nomain(&&item: @ast::item) -> option<@ast::item> { - alt item.node { - ast::item_fn(_, _, _) { - if item.ident == "main" { - option::none - } else { option::some(item) } - } - _ { option::some(item) } - } - } - - let mod_nomain = - {view_items: m.view_items, items: vec::filter_map(m.items, nomain)}; - ret fold::noop_fold_mod(mod_nomain, fld); -} - -fn fold_crate(cx: test_ctxt, c: ast::crate_, fld: fold::ast_fold) -> - ast::crate_ { - let folded = fold::noop_fold_crate(c, fld); - - // Add a special __test module to the crate that will contain code - // generated for the test harness - ret {module: add_test_module(cx, folded.module) with folded}; -} - - -fn fold_item(cx: test_ctxt, &&i: @ast::item, fld: fold::ast_fold) -> - @ast::item { - - cx.path += [i.ident]; - #debug("current path: %s", ast_util::path_name_i(cx.path)); - - if is_test_fn(i) { - alt i.node { - ast::item_fn(decl, _, _) if decl.purity == ast::unsafe_fn { - cx.sess.span_fatal( - i.span, - "unsafe functions cannot be used for tests"); - } - _ { - #debug("this is a test function"); - let test = {span: i.span, - path: cx.path, ignore: is_ignored(cx, i), - should_fail: should_fail(i)}; - cx.testfns += [test]; - #debug("have %u test functions", vec::len(cx.testfns)); - } - } - } - - let res = fold::noop_fold_item(i, fld); - vec::pop(cx.path); - ret res; -} - -fn is_test_fn(i: @ast::item) -> bool { - let has_test_attr = - vec::len(attr::find_attrs_by_name(i.attrs, "test")) > 0u; - - fn has_test_signature(i: @ast::item) -> bool { - alt i.node { - ast::item_fn(decl, tps, _) { - let input_cnt = vec::len(decl.inputs); - let no_output = decl.output.node == ast::ty_nil; - let tparm_cnt = vec::len(tps); - input_cnt == 0u && no_output && tparm_cnt == 0u - } - _ { false } - } - } - - ret has_test_attr && has_test_signature(i); -} - -fn is_ignored(cx: test_ctxt, i: @ast::item) -> bool { - let ignoreattrs = attr::find_attrs_by_name(i.attrs, "ignore"); - let ignoreitems = attr::attr_metas(ignoreattrs); - let cfg_metas = vec::concat(vec::filter_map(ignoreitems, - {|&&i| attr::get_meta_item_list(i)})); - ret if vec::is_not_empty(ignoreitems) { - config::metas_in_cfg(cx.crate.node.config, cfg_metas) - } else { - false - } -} - -fn should_fail(i: @ast::item) -> bool { - vec::len(attr::find_attrs_by_name(i.attrs, "should_fail")) > 0u -} - -fn add_test_module(cx: test_ctxt, m: ast::_mod) -> ast::_mod { - let testmod = mk_test_module(cx); - ret {items: m.items + [testmod] with m}; -} - -/* - -We're going to be building a module that looks more or less like: - -mod __test { - - fn main(args: [str]) -> int { - std::test::test_main(args, tests()) - } - - fn tests() -> [std::test::test_desc] { - ... the list of tests in the crate ... - } -} - -*/ - -fn mk_test_module(cx: test_ctxt) -> @ast::item { - // A function that generates a vector of test descriptors to feed to the - // test runner - let testsfn = mk_tests(cx); - // The synthesized main function which will call the console test runner - // with our list of tests - let mainfn = mk_main(cx); - let testmod: ast::_mod = {view_items: [], items: [mainfn, testsfn]}; - let item_ = ast::item_mod(testmod); - // This attribute tells resolve to let us call unexported functions - let resolve_unexported_attr = - attr::mk_attr(attr::mk_word_item("!resolve_unexported")); - let item: ast::item = - {ident: "__test", - attrs: [resolve_unexported_attr], - id: cx.sess.next_node_id(), - node: item_, - span: dummy_sp()}; - - #debug("Synthetic test module:\n%s\n", pprust::item_to_str(@item)); - - ret @item; -} - -fn nospan<T: copy>(t: T) -> ast::spanned<T> { - ret {node: t, span: dummy_sp()}; -} - -fn mk_tests(cx: test_ctxt) -> @ast::item { - let ret_ty = mk_test_desc_vec_ty(cx); - - let decl: ast::fn_decl = - {inputs: [], - output: ret_ty, - purity: ast::impure_fn, - cf: ast::return_val, - constraints: []}; - - // The vector of test_descs for this crate - let test_descs = mk_test_desc_vec(cx); - - let body_: ast::blk_ = - default_block([], option::some(test_descs), cx.sess.next_node_id()); - let body = nospan(body_); - - let item_ = ast::item_fn(decl, [], body); - let item: ast::item = - {ident: "tests", - attrs: [], - id: cx.sess.next_node_id(), - node: item_, - span: dummy_sp()}; - ret @item; -} - -fn mk_path(cx: test_ctxt, path: [ast::ident]) -> [ast::ident] { - // For tests that are inside of std we don't want to prefix - // the paths with std:: - let is_std = { - let items = attr::find_linkage_metas(cx.crate.node.attrs); - alt attr::meta_item_value_from_list(items, "name") { - some("std") { true } - _ { false } - } - }; - (if is_std { [] } else { ["std"] }) + path -} - -// The ast::ty of [std::test::test_desc] -fn mk_test_desc_vec_ty(cx: test_ctxt) -> @ast::ty { - let test_desc_ty_path = - @nospan({global: false, - idents: mk_path(cx, ["test", "test_desc"]), - types: []}); - - let test_desc_ty: ast::ty = - nospan(ast::ty_path(test_desc_ty_path, cx.sess.next_node_id())); - - let vec_mt: ast::mt = {ty: @test_desc_ty, mutbl: ast::m_imm}; - - ret @nospan(ast::ty_vec(vec_mt)); -} - -fn mk_test_desc_vec(cx: test_ctxt) -> @ast::expr { - #debug("building test vector from %u tests", vec::len(cx.testfns)); - let descs = []; - for test: test in cx.testfns { - let test_ = test; // Satisfy alias analysis - descs += [mk_test_desc_rec(cx, test_)]; - } - - ret @{id: cx.sess.next_node_id(), - node: ast::expr_vec(descs, ast::m_imm), - span: dummy_sp()}; -} - -fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr { - let span = test.span; - let path = test.path; - - #debug("encoding %s", ast_util::path_name_i(path)); - - let name_lit: ast::lit = - nospan(ast::lit_str(ast_util::path_name_i(path))); - let name_expr: ast::expr = - {id: cx.sess.next_node_id(), - node: ast::expr_lit(@name_lit), - span: span}; - - let name_field: ast::field = - nospan({mutbl: ast::m_imm, ident: "name", expr: @name_expr}); - - let fn_path = @nospan({global: false, idents: path, types: []}); - - let fn_expr: ast::expr = - {id: cx.sess.next_node_id(), - node: ast::expr_path(fn_path), - span: span}; - - let fn_wrapper_expr = mk_test_wrapper(cx, fn_expr, span); - - let fn_field: ast::field = - nospan({mutbl: ast::m_imm, ident: "fn", expr: fn_wrapper_expr}); - - let ignore_lit: ast::lit = nospan(ast::lit_bool(test.ignore)); - - let ignore_expr: ast::expr = - {id: cx.sess.next_node_id(), - node: ast::expr_lit(@ignore_lit), - span: span}; - - let ignore_field: ast::field = - nospan({mutbl: ast::m_imm, ident: "ignore", expr: @ignore_expr}); - - let fail_lit: ast::lit = nospan(ast::lit_bool(test.should_fail)); - - let fail_expr: ast::expr = - {id: cx.sess.next_node_id(), - node: ast::expr_lit(@fail_lit), - span: span}; - - let fail_field: ast::field = - nospan({mutbl: ast::m_imm, ident: "should_fail", expr: @fail_expr}); - - let desc_rec_: ast::expr_ = - ast::expr_rec([name_field, fn_field, ignore_field, fail_field], - option::none); - let desc_rec: ast::expr = - {id: cx.sess.next_node_id(), node: desc_rec_, span: span}; - ret @desc_rec; -} - -// Produces a bare function that wraps the test function -// FIXME: This can go away once fn is the type of bare function -fn mk_test_wrapper(cx: test_ctxt, - fn_path_expr: ast::expr, - span: span) -> @ast::expr { - let call_expr: ast::expr = { - id: cx.sess.next_node_id(), - node: ast::expr_call(@fn_path_expr, [], false), - span: span - }; - - let call_stmt: ast::stmt = nospan( - ast::stmt_semi(@call_expr, cx.sess.next_node_id())); - - let wrapper_decl: ast::fn_decl = { - inputs: [], - output: @nospan(ast::ty_nil), - purity: ast::impure_fn, - cf: ast::return_val, - constraints: [] - }; - - let wrapper_body: ast::blk = nospan({ - view_items: [], - stmts: [@call_stmt], - expr: option::none, - id: cx.sess.next_node_id(), - rules: ast::default_blk - }); - - let wrapper_capture: @ast::capture_clause = @{ - copies: [], - moves: [] - }; - - let wrapper_expr: ast::expr = { - id: cx.sess.next_node_id(), - node: ast::expr_fn(ast::proto_bare, wrapper_decl, - wrapper_body, wrapper_capture), - span: span - }; - - ret @wrapper_expr; -} - -fn mk_main(cx: test_ctxt) -> @ast::item { - let str_pt = @nospan({global: false, idents: ["str"], types: []}); - let str_ty = @nospan(ast::ty_path(str_pt, cx.sess.next_node_id())); - let args_mt: ast::mt = {ty: str_ty, mutbl: ast::m_imm}; - let args_ty: ast::ty = nospan(ast::ty_vec(args_mt)); - - let args_arg: ast::arg = - {mode: ast::expl(ast::by_val), - ty: @args_ty, - ident: "args", - id: cx.sess.next_node_id()}; - - let ret_ty = nospan(ast::ty_nil); - - let decl: ast::fn_decl = - {inputs: [args_arg], - output: @ret_ty, - purity: ast::impure_fn, - cf: ast::return_val, - constraints: []}; - - let test_main_call_expr = mk_test_main_call(cx); - - let body_: ast::blk_ = - default_block([], option::some(test_main_call_expr), - cx.sess.next_node_id()); - let body = {node: body_, span: dummy_sp()}; - - let item_ = ast::item_fn(decl, [], body); - let item: ast::item = - {ident: "main", - attrs: [], - id: cx.sess.next_node_id(), - node: item_, - span: dummy_sp()}; - ret @item; -} - -fn mk_test_main_call(cx: test_ctxt) -> @ast::expr { - - // Get the args passed to main so we can pass the to test_main - let args_path = - @nospan({global: false, idents: ["args"], types: []}); - - let args_path_expr_: ast::expr_ = ast::expr_path(args_path); - - let args_path_expr: ast::expr = - {id: cx.sess.next_node_id(), node: args_path_expr_, span: dummy_sp()}; - - // Call __test::test to generate the vector of test_descs - let test_path = - @nospan({global: false, idents: ["tests"], types: []}); - - let test_path_expr_: ast::expr_ = ast::expr_path(test_path); - - let test_path_expr: ast::expr = - {id: cx.sess.next_node_id(), node: test_path_expr_, span: dummy_sp()}; - - let test_call_expr_ = ast::expr_call(@test_path_expr, [], false); - - let test_call_expr: ast::expr = - {id: cx.sess.next_node_id(), node: test_call_expr_, span: dummy_sp()}; - - // Call std::test::test_main - let test_main_path = - @nospan({global: false, - idents: mk_path(cx, ["test", "test_main"]), - types: []}); - - let test_main_path_expr_: ast::expr_ = ast::expr_path(test_main_path); - - let test_main_path_expr: ast::expr = - {id: cx.sess.next_node_id(), node: test_main_path_expr_, - span: dummy_sp()}; - - let test_main_call_expr_: ast::expr_ = - ast::expr_call(@test_main_path_expr, - [@args_path_expr, @test_call_expr], false); - - let test_main_call_expr: ast::expr = - {id: cx.sess.next_node_id(), node: test_main_call_expr_, - span: dummy_sp()}; - - ret @test_main_call_expr; -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs deleted file mode 100644 index 2dc2945d8de..00000000000 --- a/src/comp/lib/llvm.rs +++ /dev/null @@ -1,1113 +0,0 @@ -import str::sbuf; - -import ctypes::{c_int, c_uint, unsigned, longlong, ulonglong}; - -type Opcode = u32; -type Bool = unsigned; -const True: Bool = 1u32; -const False: Bool = 0u32; - -// Consts for the LLVM CallConv type, pre-cast to uint. - -enum CallConv { - CCallConv = 0, - FastCallConv = 8, - ColdCallConv = 9, - X86StdcallCallConv = 64, - X86FastcallCallConv = 65, -} - -enum Visibility { - LLVMDefaultVisibility = 0, - HiddenVisibility = 1, - ProtectedVisibility = 2, -} - -enum Linkage { - ExternalLinkage = 0, - AvailableExternallyLinkage = 1, - LinkOnceAnyLinkage = 2, - LinkOnceODRLinkage = 3, - WeakAnyLinkage = 4, - WeakODRLinkage = 5, - AppendingLinkage = 6, - InternalLinkage = 7, - PrivateLinkage = 8, - DLLImportLinkage = 9, - DLLExportLinkage = 10, - ExternalWeakLinkage = 11, - GhostLinkage = 12, - CommonLinkage = 13, - LinkerPrivateLinkage = 14, - LinkerPrivateWeakLinkage = 15, - LinkerPrivateWeakDefAutoLinkage = 16, -} - -enum Attribute { - ZExtAttribute = 1, - SExtAttribute = 2, - NoReturnAttribute = 4, - InRegAttribute = 8, - StructRetAttribute = 16, - NoUnwindAttribute = 32, - NoAliasAttribute = 64, - ByValAttribute = 128, - NestAttribute = 256, - ReadNoneAttribute = 512, - ReadOnlyAttribute = 1024, - NoInlineAttribute = 2048, - AlwaysInlineAttribute = 4096, - OptimizeForSizeAttribute = 8192, - StackProtectAttribute = 16384, - StackProtectReqAttribute = 32768, - // 31 << 16 - AlignmentAttribute = 2031616, - NoCaptureAttribute = 2097152, - NoRedZoneAttribute = 4194304, - NoImplicitFloatAttribute = 8388608, - NakedAttribute = 16777216, - InlineHintAttribute = 33554432, - // 7 << 26 - StackAttribute = 469762048, - ReturnsTwiceAttribute = 536870912, - // 1 << 30 - UWTableAttribute = 1073741824, - NonLazyBindAttribute = 2147483648, -} - -// Consts for the LLVM IntPredicate type, pre-cast to uint. -// FIXME: as above. - -enum IntPredicate { - IntEQ = 32, - IntNE = 33, - IntUGT = 34, - IntUGE = 35, - IntULT = 36, - IntULE = 37, - IntSGT = 38, - IntSGE = 39, - IntSLT = 40, - IntSLE = 41, -} - -// Consts for the LLVM RealPredicate type, pre-case to uint. -// FIXME: as above. - -enum RealPredicate { - RealOEQ = 1, - RealOGT = 2, - RealOGE = 3, - RealOLT = 4, - RealOLE = 5, - RealONE = 6, - RealORD = 7, - RealUNO = 8, - RealUEQ = 9, - RealUGT = 10, - RealUGE = 11, - RealULT = 12, - RealULE = 13, - RealUNE = 14, -} - -// Opaque pointer types -enum Module_opaque {} -type ModuleRef = *Module_opaque; -enum Context_opaque {} -type ContextRef = *Context_opaque; -enum Type_opaque {} -type TypeRef = *Type_opaque; -enum Value_opaque {} -type ValueRef = *Value_opaque; -enum BasicBlock_opaque {} -type BasicBlockRef = *BasicBlock_opaque; -enum Builder_opaque {} -type BuilderRef = *Builder_opaque; -enum MemoryBuffer_opaque {} -type MemoryBufferRef = *MemoryBuffer_opaque; -enum PassManager_opaque {} -type PassManagerRef = *PassManager_opaque; -enum PassManagerBuilder_opaque {} -type PassManagerBuilderRef = *PassManagerBuilder_opaque; -enum Use_opaque {} -type UseRef = *Use_opaque; -enum TargetData_opaque {} -type TargetDataRef = *TargetData_opaque; -enum ObjectFile_opaque {} -type ObjectFileRef = *ObjectFile_opaque; -enum SectionIterator_opaque {} -type SectionIteratorRef = *SectionIterator_opaque; - -#[link_args = "-Lrustllvm"] -#[link_name = "rustllvm"] -#[abi = "cdecl"] -native mod llvm { - /* Create and destroy contexts. */ - fn LLVMContextCreate() -> ContextRef; - fn LLVMGetGlobalContext() -> ContextRef; - fn LLVMContextDispose(C: ContextRef); - fn LLVMGetMDKindIDInContext(C: ContextRef, Name: sbuf, SLen: unsigned) -> - unsigned; - fn LLVMGetMDKindID(Name: sbuf, SLen: unsigned) -> unsigned; - - /* Create and destroy modules. */ - fn LLVMModuleCreateWithNameInContext(ModuleID: sbuf, C: ContextRef) -> - ModuleRef; - fn LLVMDisposeModule(M: ModuleRef); - - /** Data layout. See Module::getDataLayout. */ - fn LLVMGetDataLayout(M: ModuleRef) -> sbuf; - fn LLVMSetDataLayout(M: ModuleRef, Triple: sbuf); - - /** Target triple. See Module::getTargetTriple. */ - fn LLVMGetTarget(M: ModuleRef) -> sbuf; - fn LLVMSetTarget(M: ModuleRef, Triple: sbuf); - - /** See Module::dump. */ - fn LLVMDumpModule(M: ModuleRef); - - /** See Module::setModuleInlineAsm. */ - fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: sbuf); - - /** See llvm::LLVMTypeKind::getTypeID. */ - - // FIXME: returning int rather than TypeKind because - // we directly inspect the values, and casting from - // a native doesn't work yet (only *to* a native). - - fn LLVMGetTypeKind(Ty: TypeRef) -> c_int; - - /** See llvm::LLVMType::getContext. */ - fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; - - /* Operations on integer types */ - fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMIntTypeInContext(C: ContextRef, NumBits: unsigned) -> TypeRef; - - fn LLVMInt1Type() -> TypeRef; - fn LLVMInt8Type() -> TypeRef; - fn LLVMInt16Type() -> TypeRef; - fn LLVMInt32Type() -> TypeRef; - fn LLVMInt64Type() -> TypeRef; - fn LLVMIntType(NumBits: unsigned) -> TypeRef; - fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> unsigned; - - /* Operations on real types */ - fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef; - fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef; - fn LLVMX86FP80TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMFP128TypeInContext(C: ContextRef) -> TypeRef; - fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef; - - fn LLVMFloatType() -> TypeRef; - fn LLVMDoubleType() -> TypeRef; - fn LLVMX86FP80Type() -> TypeRef; - fn LLVMFP128Type() -> TypeRef; - fn LLVMPPCFP128Type() -> TypeRef; - - /* Operations on function types */ - fn LLVMFunctionType(ReturnType: TypeRef, ParamTypes: *TypeRef, - ParamCount: unsigned, IsVarArg: Bool) -> TypeRef; - fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; - fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; - fn LLVMCountParamTypes(FunctionTy: TypeRef) -> unsigned; - fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *TypeRef); - - /* Operations on struct types */ - fn LLVMStructTypeInContext(C: ContextRef, ElementTypes: *TypeRef, - ElementCount: unsigned, - Packed: Bool) -> TypeRef; - fn LLVMStructType(ElementTypes: *TypeRef, ElementCount: unsigned, - Packed: Bool) -> TypeRef; - fn LLVMCountStructElementTypes(StructTy: TypeRef) -> unsigned; - fn LLVMGetStructElementTypes(StructTy: TypeRef, Dest: *TypeRef); - fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool; - - /* Operations on array, pointer, and vector types (sequence types) */ - fn LLVMArrayType(ElementType: TypeRef, - ElementCount: unsigned) -> TypeRef; - fn LLVMPointerType(ElementType: TypeRef, - AddressSpace: unsigned) -> TypeRef; - fn LLVMVectorType(ElementType: TypeRef, - ElementCount: unsigned) -> TypeRef; - - fn LLVMGetElementType(Ty: TypeRef) -> TypeRef; - fn LLVMGetArrayLength(ArrayTy: TypeRef) -> unsigned; - fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> unsigned; - fn LLVMGetVectorSize(VectorTy: TypeRef) -> unsigned; - - /* Operations on other types */ - fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; - fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; - fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef; - - fn LLVMVoidType() -> TypeRef; - fn LLVMLabelType() -> TypeRef; - fn LLVMMetadataType() -> TypeRef; - - /* Operations on all values */ - fn LLVMTypeOf(Val: ValueRef) -> TypeRef; - fn LLVMGetValueName(Val: ValueRef) -> sbuf; - fn LLVMSetValueName(Val: ValueRef, Name: sbuf); - fn LLVMDumpValue(Val: ValueRef); - fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); - fn LLVMHasMetadata(Val: ValueRef) -> c_int; - fn LLVMGetMetadata(Val: ValueRef, KindID: unsigned) -> ValueRef; - fn LLVMSetMetadata(Val: ValueRef, KindID: unsigned, Node: ValueRef); - - /* Operations on Uses */ - fn LLVMGetFirstUse(Val: ValueRef) -> UseRef; - fn LLVMGetNextUse(U: UseRef) -> UseRef; - fn LLVMGetUser(U: UseRef) -> ValueRef; - fn LLVMGetUsedValue(U: UseRef) -> ValueRef; - - /* Operations on Users */ - fn LLVMGetOperand(Val: ValueRef, Index: unsigned) -> ValueRef; - fn LLVMSetOperand(Val: ValueRef, Index: unsigned, Op: ValueRef); - - /* Operations on constants of any type */ - fn LLVMConstNull(Ty: TypeRef) -> ValueRef; - /* all zeroes */ - fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; - /* only for int/vector */ - fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; - fn LLVMIsConstant(Val: ValueRef) -> Bool; - fn LLVMIsNull(Val: ValueRef) -> Bool; - fn LLVMIsUndef(Val: ValueRef) -> Bool; - fn LLVMConstPointerNull(Ty: TypeRef) -> ValueRef; - - /* Operations on metadata */ - fn LLVMMDStringInContext(C: ContextRef, Str: sbuf, SLen: unsigned) -> - ValueRef; - fn LLVMMDString(Str: sbuf, SLen: unsigned) -> ValueRef; - fn LLVMMDNodeInContext(C: ContextRef, Vals: *ValueRef, Count: unsigned) -> - ValueRef; - fn LLVMMDNode(Vals: *ValueRef, Count: unsigned) -> ValueRef; - fn LLVMAddNamedMetadataOperand(M: ModuleRef, Str: sbuf, - Val: ValueRef); - - /* Operations on scalar constants */ - fn LLVMConstInt(IntTy: TypeRef, N: ulonglong, SignExtend: Bool) -> - ValueRef; - // FIXME: radix is actually u8, but our native layer can't handle this - // yet. lucky for us we're little-endian. Small miracles. - fn LLVMConstIntOfString(IntTy: TypeRef, Text: sbuf, Radix: c_int) -> - ValueRef; - fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, Text: sbuf, SLen: unsigned, - Radix: u8) -> ValueRef; - fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; - fn LLVMConstRealOfString(RealTy: TypeRef, Text: sbuf) -> ValueRef; - fn LLVMConstRealOfStringAndSize(RealTy: TypeRef, Text: sbuf, - SLen: unsigned) -> ValueRef; - fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> ulonglong; - fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> longlong; - - - /* Operations on composite constants */ - fn LLVMConstStringInContext(C: ContextRef, Str: sbuf, Length: unsigned, - DontNullTerminate: Bool) -> ValueRef; - fn LLVMConstStructInContext(C: ContextRef, ConstantVals: *ValueRef, - Count: unsigned, Packed: Bool) -> ValueRef; - - fn LLVMConstString(Str: sbuf, Length: unsigned, - DontNullTerminate: Bool) -> ValueRef; - fn LLVMConstArray(ElementTy: TypeRef, ConstantVals: *ValueRef, - Length: unsigned) -> ValueRef; - fn LLVMConstStruct(ConstantVals: *ValueRef, - Count: unsigned, Packed: Bool) -> ValueRef; - fn LLVMConstVector(ScalarConstantVals: *ValueRef, - Size: unsigned) -> ValueRef; - - /* Constant expressions */ - fn LLVMAlignOf(Ty: TypeRef) -> ValueRef; - fn LLVMSizeOf(Ty: TypeRef) -> ValueRef; - fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef; - fn LLVMConstNSWNeg(ConstantVal: ValueRef) -> ValueRef; - fn LLVMConstNUWNeg(ConstantVal: ValueRef) -> ValueRef; - fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef; - fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef; - fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstExactSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; - fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> - ValueRef; - fn LLVMConstGEP(ConstantVal: ValueRef, ConstantIndices: *uint, - NumIndices: unsigned) -> ValueRef; - fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: *uint, - NumIndices: unsigned) -> ValueRef; - fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> - ValueRef; - fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> - ValueRef; - fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> - ValueRef; - fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) -> - ValueRef; - fn LLVMConstIntCast(ConstantVal: ValueRef, ToType: TypeRef, - isSigned: Bool) -> ValueRef; - fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; - fn LLVMConstSelect(ConstantCondition: ValueRef, ConstantIfTrue: ValueRef, - ConstantIfFalse: ValueRef) -> ValueRef; - fn LLVMConstExtractElement(VectorConstant: ValueRef, - IndexConstant: ValueRef) -> ValueRef; - fn LLVMConstInsertElement(VectorConstant: ValueRef, - ElementValueConstant: ValueRef, - IndexConstant: ValueRef) -> ValueRef; - fn LLVMConstShuffleVector(VectorAConstant: ValueRef, - VectorBConstant: ValueRef, - MaskConstant: ValueRef) -> ValueRef; - fn LLVMConstExtractValue(AggConstant: ValueRef, IdxList: *uint, - NumIdx: unsigned) -> ValueRef; - fn LLVMConstInsertValue(AggConstant: ValueRef, - ElementValueConstant: ValueRef, IdxList: *uint, - NumIdx: unsigned) -> ValueRef; - fn LLVMConstInlineAsm(Ty: TypeRef, AsmString: sbuf, Constraints: sbuf, - HasSideEffects: Bool, IsAlignStack: Bool) -> - ValueRef; - fn LLVMBlockAddress(F: ValueRef, BB: BasicBlockRef) -> ValueRef; - - - - /* Operations on global variables, functions, and aliases (globals) */ - fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; - fn LLVMIsDeclaration(Global: ValueRef) -> Bool; - fn LLVMGetLinkage(Global: ValueRef) -> unsigned; - fn LLVMSetLinkage(Global: ValueRef, Link: unsigned); - fn LLVMGetSection(Global: ValueRef) -> sbuf; - fn LLVMSetSection(Global: ValueRef, Section: sbuf); - fn LLVMGetVisibility(Global: ValueRef) -> unsigned; - fn LLVMSetVisibility(Global: ValueRef, Viz: unsigned); - fn LLVMGetAlignment(Global: ValueRef) -> unsigned; - fn LLVMSetAlignment(Global: ValueRef, Bytes: unsigned); - - - /* Operations on global variables */ - fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: sbuf) -> ValueRef; - fn LLVMAddGlobalInAddressSpace(M: ModuleRef, Ty: TypeRef, Name: sbuf, - AddressSpace: unsigned) -> ValueRef; - fn LLVMGetNamedGlobal(M: ModuleRef, Name: sbuf) -> ValueRef; - fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; - fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; - fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; - fn LLVMGetPreviousGlobal(GlobalVar: ValueRef) -> ValueRef; - fn LLVMDeleteGlobal(GlobalVar: ValueRef); - fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; - fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef); - fn LLVMIsThreadLocal(GlobalVar: ValueRef) -> Bool; - fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); - fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; - fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); - - /* Operations on aliases */ - fn LLVMAddAlias(M: ModuleRef, Ty: TypeRef, Aliasee: ValueRef, Name: sbuf) - -> ValueRef; - - /* Operations on functions */ - fn LLVMAddFunction(M: ModuleRef, Name: sbuf, FunctionTy: TypeRef) -> - ValueRef; - fn LLVMGetNamedFunction(M: ModuleRef, Name: sbuf) -> ValueRef; - fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef; - fn LLVMGetLastFunction(M: ModuleRef) -> ValueRef; - fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; - fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; - fn LLVMDeleteFunction(Fn: ValueRef); - fn LLVMGetOrInsertFunction(M: ModuleRef, Name: sbuf, FunctionTy: TypeRef) - -> ValueRef; - fn LLVMGetIntrinsicID(Fn: ValueRef) -> unsigned; - fn LLVMGetFunctionCallConv(Fn: ValueRef) -> unsigned; - fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: unsigned); - fn LLVMGetGC(Fn: ValueRef) -> sbuf; - fn LLVMSetGC(Fn: ValueRef, Name: sbuf); - fn LLVMAddFunctionAttr(Fn: ValueRef, PA: unsigned, HighPA: unsigned); - fn LLVMGetFunctionAttr(Fn: ValueRef) -> unsigned; - fn LLVMRemoveFunctionAttr(Fn: ValueRef, PA: unsigned, HighPA: unsigned); - - /* Operations on parameters */ - fn LLVMCountParams(Fn: ValueRef) -> unsigned; - fn LLVMGetParams(Fn: ValueRef, Params: *ValueRef); - fn LLVMGetParam(Fn: ValueRef, Index: unsigned) -> ValueRef; - fn LLVMGetParamParent(Inst: ValueRef) -> ValueRef; - fn LLVMGetFirstParam(Fn: ValueRef) -> ValueRef; - fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; - fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; - fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; - fn LLVMAddAttribute(Arg: ValueRef, PA: unsigned); - fn LLVMRemoveAttribute(Arg: ValueRef, PA: unsigned); - fn LLVMGetAttribute(Arg: ValueRef) -> unsigned; - fn LLVMSetParamAlignment(Arg: ValueRef, align: unsigned); - - /* Operations on basic blocks */ - fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef; - fn LLVMValueIsBasicBlock(Val: ValueRef) -> Bool; - fn LLVMValueAsBasicBlock(Val: ValueRef) -> BasicBlockRef; - fn LLVMGetBasicBlockParent(BB: BasicBlockRef) -> ValueRef; - fn LLVMCountBasicBlocks(Fn: ValueRef) -> unsigned; - fn LLVMGetBasicBlocks(Fn: ValueRef, BasicBlocks: *ValueRef); - fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef; - fn LLVMGetLastBasicBlock(Fn: ValueRef) -> BasicBlockRef; - fn LLVMGetNextBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; - fn LLVMGetPreviousBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; - fn LLVMGetEntryBasicBlock(Fn: ValueRef) -> BasicBlockRef; - - fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: sbuf) - -> BasicBlockRef; - fn LLVMInsertBasicBlockInContext(C: ContextRef, BB: BasicBlockRef, - Name: sbuf) -> BasicBlockRef; - - fn LLVMAppendBasicBlock(Fn: ValueRef, Name: sbuf) -> BasicBlockRef; - fn LLVMInsertBasicBlock(InsertBeforeBB: BasicBlockRef, Name: sbuf) -> - BasicBlockRef; - fn LLVMDeleteBasicBlock(BB: BasicBlockRef); - - /* Operations on instructions */ - fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef; - fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef; - fn LLVMGetLastInstruction(BB: BasicBlockRef) -> ValueRef; - fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef; - fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; - - /* Operations on call sites */ - fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: unsigned); - fn LLVMGetInstructionCallConv(Instr: ValueRef) -> unsigned; - fn LLVMAddInstrAttribute(Instr: ValueRef, index: unsigned, IA: unsigned); - fn LLVMRemoveInstrAttribute(Instr: ValueRef, index: unsigned, - IA: unsigned); - fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: unsigned, - align: unsigned); - - /* Operations on call instructions (only) */ - fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; - fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); - - /* Operations on phi nodes */ - fn LLVMAddIncoming(PhiNode: ValueRef, IncomingValues: *ValueRef, - IncomingBlocks: *BasicBlockRef, Count: unsigned); - fn LLVMCountIncoming(PhiNode: ValueRef) -> unsigned; - fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: unsigned) -> ValueRef; - fn LLVMGetIncomingBlock(PhiNode: ValueRef, - Index: unsigned) -> BasicBlockRef; - - /* Instruction builders */ - fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef; - fn LLVMCreateBuilder() -> BuilderRef; - fn LLVMPositionBuilder(Builder: BuilderRef, Block: BasicBlockRef, - Instr: ValueRef); - fn LLVMPositionBuilderBefore(Builder: BuilderRef, Instr: ValueRef); - fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef); - fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef; - fn LLVMClearInsertionPosition(Builder: BuilderRef); - fn LLVMInsertIntoBuilder(Builder: BuilderRef, Instr: ValueRef); - fn LLVMInsertIntoBuilderWithName(Builder: BuilderRef, Instr: ValueRef, - Name: sbuf); - fn LLVMDisposeBuilder(Builder: BuilderRef); - - /* Metadata */ - fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); - fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; - fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef); - - /* Terminators */ - fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef; - fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef; - fn LLVMBuildAggregateRet(B: BuilderRef, RetVals: *ValueRef, - N: unsigned) -> ValueRef; - fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef; - fn LLVMBuildCondBr(B: BuilderRef, If: ValueRef, Then: BasicBlockRef, - Else: BasicBlockRef) -> ValueRef; - fn LLVMBuildSwitch(B: BuilderRef, V: ValueRef, Else: BasicBlockRef, - NumCases: unsigned) -> ValueRef; - fn LLVMBuildIndirectBr(B: BuilderRef, Addr: ValueRef, - NumDests: unsigned) -> ValueRef; - fn LLVMBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *ValueRef, - NumArgs: unsigned, Then: BasicBlockRef, - Catch: BasicBlockRef, Name: sbuf) -> ValueRef; - fn LLVMBuildLandingPad(B: BuilderRef, Ty: TypeRef, PersFn: ValueRef, - NumClauses: unsigned, Name: sbuf) -> ValueRef; - fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef; - fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef; - - /* Add a case to the switch instruction */ - fn LLVMAddCase(Switch: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef); - - /* Add a destination to the indirectbr instruction */ - fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); - - /* Add a clause to the landing pad instruction */ - fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); - - /* Set the cleanup on a landing pad instruction */ - fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); - - /* Arithmetic */ - fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildNSWAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildNUWAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildSub(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildNSWSub(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildNUWSub(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFSub(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildMul(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildNSWMul(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildNUWMul(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFMul(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildUDiv(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildSDiv(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildExactSDiv(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFDiv(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildURem(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildSRem(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildFRem(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildShl(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildLShr(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildAShr(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildAnd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildOr(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) -> - ValueRef; - fn LLVMBuildXor(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildBinOp(B: BuilderRef, Op: Opcode, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: sbuf) -> ValueRef; - - /* Memory */ - fn LLVMBuildMalloc(B: BuilderRef, Ty: TypeRef, Name: sbuf) -> ValueRef; - fn LLVMBuildArrayMalloc(B: BuilderRef, Ty: TypeRef, Val: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: sbuf) -> ValueRef; - fn LLVMBuildArrayAlloca(B: BuilderRef, Ty: TypeRef, Val: ValueRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef; - fn LLVMBuildLoad(B: BuilderRef, PointerVal: ValueRef, Name: sbuf) -> - ValueRef; - fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) -> - ValueRef; - fn LLVMBuildGEP(B: BuilderRef, Pointer: ValueRef, Indices: *ValueRef, - NumIndices: unsigned, Name: sbuf) -> ValueRef; - fn LLVMBuildInBoundsGEP(B: BuilderRef, Pointer: ValueRef, - Indices: *ValueRef, NumIndices: unsigned, - Name: sbuf) - -> ValueRef; - fn LLVMBuildStructGEP(B: BuilderRef, Pointer: ValueRef, Idx: unsigned, - Name: sbuf) -> ValueRef; - fn LLVMBuildGlobalString(B: BuilderRef, Str: sbuf, Name: sbuf) -> - ValueRef; - fn LLVMBuildGlobalStringPtr(B: BuilderRef, Str: sbuf, Name: sbuf) -> - ValueRef; - - /* Casts */ - fn LLVMBuildTrunc(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildZExt(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildSExt(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFPToUI(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFPToSI(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildUIToFP(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildSIToFP(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFPTrunc(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFPExt(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildPtrToInt(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildIntToPtr(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildBitCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildZExtOrBitCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildSExtOrBitCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildTruncOrBitCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildCast(B: BuilderRef, Op: Opcode, Val: ValueRef, - DestTy: TypeRef, Name: sbuf) -> ValueRef; - fn LLVMBuildPointerCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildIntCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - fn LLVMBuildFPCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, - Name: sbuf) -> ValueRef; - - /* Comparisons */ - fn LLVMBuildICmp(B: BuilderRef, Op: unsigned, LHS: ValueRef, - RHS: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildFCmp(B: BuilderRef, Op: unsigned, LHS: ValueRef, - RHS: ValueRef, Name: sbuf) -> ValueRef; - - /* Miscellaneous instructions */ - fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: sbuf) -> ValueRef; - fn LLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: *ValueRef, - NumArgs: unsigned, Name: sbuf) -> ValueRef; - fn LLVMBuildSelect(B: BuilderRef, If: ValueRef, Then: ValueRef, - Else: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildVAArg(B: BuilderRef, list: ValueRef, Ty: TypeRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildExtractElement(B: BuilderRef, VecVal: ValueRef, - Index: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildInsertElement(B: BuilderRef, VecVal: ValueRef, - EltVal: ValueRef, Index: ValueRef, Name: sbuf) - -> ValueRef; - fn LLVMBuildShuffleVector(B: BuilderRef, V1: ValueRef, V2: ValueRef, - Mask: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildExtractValue(B: BuilderRef, AggVal: ValueRef, Index: unsigned, - Name: sbuf) -> ValueRef; - fn LLVMBuildInsertValue(B: BuilderRef, AggVal: ValueRef, EltVal: ValueRef, - Index: unsigned, Name: sbuf) -> ValueRef; - - fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: sbuf) -> ValueRef; - fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: sbuf) -> - ValueRef; - fn LLVMBuildPtrDiff(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, - Name: sbuf) -> ValueRef; - - /* Selected entries from the downcasts. */ - fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; - - /** Writes a module to the specified path. Returns 0 on success. */ - fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: sbuf) -> c_int; - - /** Creates target data from a target layout string. */ - fn LLVMCreateTargetData(StringRep: sbuf) -> TargetDataRef; - /** Adds the target data to the given pass manager. The pass manager - references the target data only weakly. */ - fn LLVMAddTargetData(TD: TargetDataRef, PM: PassManagerRef); - /** Returns the size of a type. FIXME: rv is actually a ULongLong! */ - fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) -> unsigned; - /** Returns the alignment of a type. */ - fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, - Ty: TypeRef) -> unsigned; - /** Disposes target data. */ - fn LLVMDisposeTargetData(TD: TargetDataRef); - - /** Creates a pass manager. */ - fn LLVMCreatePassManager() -> PassManagerRef; - /** Disposes a pass manager. */ - fn LLVMDisposePassManager(PM: PassManagerRef); - /** Runs a pass manager on a module. */ - fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool; - - /** Adds a verification pass. */ - fn LLVMAddVerifierPass(PM: PassManagerRef); - - fn LLVMAddGlobalOptimizerPass(PM: PassManagerRef); - fn LLVMAddIPSCCPPass(PM: PassManagerRef); - fn LLVMAddDeadArgEliminationPass(PM: PassManagerRef); - fn LLVMAddInstructionCombiningPass(PM: PassManagerRef); - fn LLVMAddCFGSimplificationPass(PM: PassManagerRef); - fn LLVMAddFunctionInliningPass(PM: PassManagerRef); - fn LLVMAddFunctionAttrsPass(PM: PassManagerRef); - fn LLVMAddScalarReplAggregatesPass(PM: PassManagerRef); - fn LLVMAddScalarReplAggregatesPassSSA(PM: PassManagerRef); - fn LLVMAddJumpThreadingPass(PM: PassManagerRef); - fn LLVMAddConstantPropagationPass(PM: PassManagerRef); - fn LLVMAddReassociatePass(PM: PassManagerRef); - fn LLVMAddLoopRotatePass(PM: PassManagerRef); - fn LLVMAddLICMPass(PM: PassManagerRef); - fn LLVMAddLoopUnswitchPass(PM: PassManagerRef); - fn LLVMAddLoopDeletionPass(PM: PassManagerRef); - fn LLVMAddLoopUnrollPass(PM: PassManagerRef); - fn LLVMAddGVNPass(PM: PassManagerRef); - fn LLVMAddMemCpyOptPass(PM: PassManagerRef); - fn LLVMAddSCCPPass(PM: PassManagerRef); - fn LLVMAddDeadStoreEliminationPass(PM: PassManagerRef); - fn LLVMAddStripDeadPrototypesPass(PM: PassManagerRef); - fn LLVMAddConstantMergePass(PM: PassManagerRef); - fn LLVMAddArgumentPromotionPass(PM: PassManagerRef); - fn LLVMAddTailCallEliminationPass(PM: PassManagerRef); - fn LLVMAddIndVarSimplifyPass(PM: PassManagerRef); - fn LLVMAddAggressiveDCEPass(PM: PassManagerRef); - fn LLVMAddGlobalDCEPass(PM: PassManagerRef); - fn LLVMAddCorrelatedValuePropagationPass(PM: PassManagerRef); - fn LLVMAddPruneEHPass(PM: PassManagerRef); - fn LLVMAddSimplifyLibCallsPass(PM: PassManagerRef); - fn LLVMAddLoopIdiomPass(PM: PassManagerRef); - fn LLVMAddEarlyCSEPass(PM: PassManagerRef); - fn LLVMAddTypeBasedAliasAnalysisPass(PM: PassManagerRef); - fn LLVMAddBasicAliasAnalysisPass(PM: PassManagerRef); - - fn LLVMPassManagerBuilderCreate() -> PassManagerBuilderRef; - fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef); - fn LLVMPassManagerBuilderSetOptLevel(PMB: PassManagerBuilderRef, - OptimizationLevel: unsigned); - fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, - Value: Bool); - fn LLVMPassManagerBuilderSetDisableUnitAtATime(PMB: PassManagerBuilderRef, - Value: Bool); - fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: PassManagerBuilderRef, - Value: Bool); - fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls - (PMB: PassManagerBuilderRef, Value: Bool); - fn LLVMPassManagerBuilderUseInlinerWithThreshold - (PMB: PassManagerBuilderRef, threshold: unsigned); - fn LLVMPassManagerBuilderPopulateModulePassManager - (PMB: PassManagerBuilderRef, PM: PassManagerRef); - - fn LLVMPassManagerBuilderPopulateFunctionPassManager - (PMB: PassManagerBuilderRef, PM: PassManagerRef); - - /** Destroys a memory buffer. */ - fn LLVMDisposeMemoryBuffer(MemBuf: MemoryBufferRef); - - - /* Stuff that's in rustllvm/ because it's not upstream yet. */ - - /** Opens an object file. */ - fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; - /** Closes an object file. */ - fn LLVMDisposeObjectFile(ObjectFile: ObjectFileRef); - - /** Enumerates the sections in an object file. */ - fn LLVMGetSections(ObjectFile: ObjectFileRef) -> SectionIteratorRef; - /** Destroys a section iterator. */ - fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); - /** Returns true if the section iterator is at the end of the section - list: */ - fn LLVMIsSectionIteratorAtEnd(ObjectFile: ObjectFileRef, - SI: SectionIteratorRef) -> Bool; - /** Moves the section iterator to point to the next section. */ - fn LLVMMoveToNextSection(SI: SectionIteratorRef); - /** Returns the current section name. */ - fn LLVMGetSectionName(SI: SectionIteratorRef) -> sbuf; - /** Returns the current section size. */ - fn LLVMGetSectionSize(SI: SectionIteratorRef) -> ulonglong; - /** Returns the current section contents as a string buffer. */ - fn LLVMGetSectionContents(SI: SectionIteratorRef) -> sbuf; - - /** Reads the given file and returns it as a memory buffer. Use - LLVMDisposeMemoryBuffer() to get rid of it. */ - fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: sbuf) -> - MemoryBufferRef; - - /* FIXME: The FileType is an enum.*/ - fn LLVMRustWriteOutputFile(PM: PassManagerRef, M: ModuleRef, Triple: sbuf, - Output: sbuf, FileType: c_int, OptLevel: c_int, - EnableSegmentedStacks: bool); - - /** Returns a string describing the last error caused by an LLVMRust* - call. */ - fn LLVMRustGetLastError() -> sbuf; - - /** Parses the bitcode in the given memory buffer. */ - fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef; - - /** Parses LLVM asm in the given file */ - fn LLVMRustParseAssemblyFile(Filename: sbuf) -> ModuleRef; - - /** FiXME: Hacky adaptor for lack of ULongLong in FFI: */ - fn LLVMRustConstInt(IntTy: TypeRef, N_hi: unsigned, N_lo: unsigned, - SignExtend: Bool) -> ValueRef; - - fn LLVMRustAddPrintModulePass(PM: PassManagerRef, M: ModuleRef, - Output: sbuf); - - /** Turn on LLVM pass-timing. */ - fn LLVMRustEnableTimePasses(); - - /** Print the pass timings since static dtors aren't picking them up. */ - fn LLVMRustPrintPassTimings(); - - fn LLVMStructCreateNamed(C: ContextRef, Name: sbuf) -> TypeRef; - - fn LLVMStructSetBody(StructTy: TypeRef, ElementTypes: *TypeRef, - ElementCount: unsigned, Packed: Bool); - - fn LLVMConstNamedStruct(S: TypeRef, ConstantVals: *ValueRef, - Count: unsigned) -> ValueRef; - - /** Links LLVM modules together. `Src` is destroyed by this call and - must never be referenced again. */ - fn LLVMLinkModules(Dest: ModuleRef, Src: ModuleRef) -> Bool; -} - -fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) { - llvm::LLVMSetInstructionCallConv(Instr, CC as unsigned); -} -fn SetFunctionCallConv(Fn: ValueRef, CC: CallConv) { - llvm::LLVMSetFunctionCallConv(Fn, CC as unsigned); -} -fn SetLinkage(Global: ValueRef, Link: Linkage) { - llvm::LLVMSetLinkage(Global, Link as unsigned); -} - -/* Memory-managed object interface to type handles. */ - -type type_names = @{type_names: std::map::hashmap<TypeRef, str>, - named_types: std::map::hashmap<str, TypeRef>}; - -fn associate_type(tn: type_names, s: str, t: TypeRef) { - assert tn.type_names.insert(t, s); - assert tn.named_types.insert(s, t); -} - -fn type_has_name(tn: type_names, t: TypeRef) -> option<str> { - ret tn.type_names.find(t); -} - -fn name_has_type(tn: type_names, s: str) -> option<TypeRef> { - ret tn.named_types.find(s); -} - -fn mk_type_names() -> type_names { - fn hash(&&t: TypeRef) -> uint { ret t as uint; } - fn eq(&&a: TypeRef, &&b: TypeRef) -> bool { ret a as uint == b as uint; } - @{type_names: std::map::mk_hashmap(hash, eq), - named_types: std::map::new_str_hash()} -} - -fn type_to_str(names: type_names, ty: TypeRef) -> str { - ret type_to_str_inner(names, [], ty); -} - -fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) -> - str { - alt type_has_name(names, ty) { - option::some(n) { ret n; } - _ {} - } - - let outer = outer0 + [ty]; - - let kind: int = llvm::LLVMGetTypeKind(ty) as int; - - fn tys_str(names: type_names, outer: [TypeRef], tys: [TypeRef]) -> str { - let s: str = ""; - let first: bool = true; - for t: TypeRef in tys { - if first { first = false; } else { s += ", "; } - s += type_to_str_inner(names, outer, t); - } - ret s; - } - - alt kind { - // FIXME: more enum-as-int constants determined from Core::h; - // horrible, horrible. Complete as needed. - 0 { ret "Void"; } - 1 { ret "Half"; } - 2 { ret "Float"; } - 3 { ret "Double"; } - 4 { ret "X86_FP80"; } - 5 { ret "FP128"; } - 6 { ret "PPC_FP128"; } - 7 { ret "Label"; } - 8 { - ret "i" + int::str(llvm::LLVMGetIntTypeWidth(ty) as int); - } - 9 { - let s = "fn("; - let out_ty: TypeRef = llvm::LLVMGetReturnType(ty); - let n_args = llvm::LLVMCountParamTypes(ty) as uint; - let args: [TypeRef] = vec::init_elt::<TypeRef>(n_args, 0 as TypeRef); - unsafe { - llvm::LLVMGetParamTypes(ty, vec::unsafe::to_ptr(args)); - } - s += tys_str(names, outer, args); - s += ") -> "; - s += type_to_str_inner(names, outer, out_ty); - ret s; - } - 10 { - let s: str = "{"; - let n_elts = llvm::LLVMCountStructElementTypes(ty) as uint; - let elts: [TypeRef] = vec::init_elt::<TypeRef>(n_elts, 0 as TypeRef); - unsafe { - llvm::LLVMGetStructElementTypes(ty, vec::unsafe::to_ptr(elts)); - } - s += tys_str(names, outer, elts); - s += "}"; - ret s; - } - 11 { - let el_ty = llvm::LLVMGetElementType(ty); - ret "[" + type_to_str_inner(names, outer, el_ty) + " x " + - uint::str(llvm::LLVMGetArrayLength(ty) as uint) + "]"; - } - 12 { - let i: uint = 0u; - for tout: TypeRef in outer0 { - i += 1u; - if tout as int == ty as int { - let n: uint = vec::len::<TypeRef>(outer0) - i; - ret "*\\" + int::str(n as int); - } - } - ret "*" + - type_to_str_inner(names, outer, llvm::LLVMGetElementType(ty)); - } - 13 { ret "Vector"; } - 14 { ret "Metadata"; } - 15 { ret "X86_MMAX"; } - _ { #error("unknown TypeKind %d", kind as int); fail; } - } -} - -fn float_width(llt: TypeRef) -> uint { - ret alt llvm::LLVMGetTypeKind(llt) as int { - 1 { 32u } - 2 { 64u } - 3 { 80u } - 4 | 5 { 128u } - _ { fail "llvm_float_width called on a non-float type" } - }; -} - -fn fn_ty_param_tys(fn_ty: TypeRef) -> [TypeRef] unsafe { - let args = vec::init_elt(llvm::LLVMCountParamTypes(fn_ty) as uint, - 0 as TypeRef); - llvm::LLVMGetParamTypes(fn_ty, vec::unsafe::to_ptr(args)); - ret args; -} - - -/* Memory-managed interface to target data. */ - -resource target_data_res(TD: TargetDataRef) { - llvm::LLVMDisposeTargetData(TD); -} - -type target_data = {lltd: TargetDataRef, dtor: @target_data_res}; - -fn mk_target_data(string_rep: str) -> target_data { - let lltd = - str::as_buf(string_rep, {|buf| llvm::LLVMCreateTargetData(buf) }); - ret {lltd: lltd, dtor: @target_data_res(lltd)}; -} - -/* Memory-managed interface to pass managers. */ - -resource pass_manager_res(PM: PassManagerRef) { - llvm::LLVMDisposePassManager(PM); -} - -type pass_manager = {llpm: PassManagerRef, dtor: @pass_manager_res}; - -fn mk_pass_manager() -> pass_manager { - let llpm = llvm::LLVMCreatePassManager(); - ret {llpm: llpm, dtor: @pass_manager_res(llpm)}; -} - -/* Memory-managed interface to object files. */ - -resource object_file_res(ObjectFile: ObjectFileRef) { - llvm::LLVMDisposeObjectFile(ObjectFile); -} - -type object_file = {llof: ObjectFileRef, dtor: @object_file_res}; - -fn mk_object_file(llmb: MemoryBufferRef) -> option<object_file> { - let llof = llvm::LLVMCreateObjectFile(llmb); - if llof as int == 0 { ret option::none::<object_file>; } - ret option::some({llof: llof, dtor: @object_file_res(llof)}); -} - -/* Memory-managed interface to section iterators. */ - -resource section_iter_res(SI: SectionIteratorRef) { - llvm::LLVMDisposeSectionIterator(SI); -} - -type section_iter = {llsi: SectionIteratorRef, dtor: @section_iter_res}; - -fn mk_section_iter(llof: ObjectFileRef) -> section_iter { - let llsi = llvm::LLVMGetSections(llof); - ret {llsi: llsi, dtor: @section_iter_res(llsi)}; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/metadata/astencode.rs b/src/comp/metadata/astencode.rs deleted file mode 100644 index bd1309c7c86..00000000000 --- a/src/comp/metadata/astencode.rs +++ /dev/null @@ -1,925 +0,0 @@ -import syntax::ast; -import syntax::fold; -import syntax::visit; -import syntax::ast_util; -import syntax::ast_util::inlined_item_methods; -import syntax::codemap::span; -import std::map::map; -import std::smallintmap::map; -import std::ebml; -import std::ebml::writer; -import std::serialization; -import std::serialization::serializer; -import std::serialization::deserializer; -import std::serialization::serializer_helpers; -import std::serialization::deserializer_helpers; -import middle::trans::common::maps; -import middle::{ty, typeck, last_use, ast_map}; -import middle::typeck::method_origin; -import middle::typeck::dict_res; -import middle::typeck::dict_origin; -import driver::session::session; -import middle::freevars::freevar_entry; -import c = common; -import e = encoder; - -// used in testing: -import std::io; -import driver::diagnostic; -import syntax::codemap; -import syntax::parse::parser; -import syntax::print::pprust; - -export encode_inlined_item; -export decode_inlined_item; - -type decode_ctxt = @{ - cdata: cstore::crate_metadata, - tcx: ty::ctxt, - maps: maps -}; - -type extended_decode_ctxt = @{ - dcx: decode_ctxt, - from_id_range: id_range, - to_id_range: id_range -}; - -iface tr { - fn tr(xcx: extended_decode_ctxt) -> self; -} - -// ______________________________________________________________________ -// Top-level methods. - -fn encode_inlined_item(ecx: @e::encode_ctxt, - ebml_w: ebml::writer, - path: ast_map::path, - ii: ast::inlined_item) { - #debug["> Encoding inlined item: %s::%s (%u)", - ast_map::path_to_str(path), ii.ident(), - ebml_w.writer.tell()]; - - let id_range = compute_id_range(ii); - ebml_w.wr_tag(c::tag_ast as uint) {|| - encode_id_range(ebml_w, id_range); - encode_ast(ebml_w, ii); - encode_side_tables_for_ii(ecx, ebml_w, ii); - } - - #debug["< Encoded inlined fn: %s::%s (%u)", - ast_map::path_to_str(path), ii.ident(), - ebml_w.writer.tell()]; -} - -fn decode_inlined_item(cdata: cstore::crate_metadata, - tcx: ty::ctxt, - maps: maps, - path: ast_map::path, - par_doc: ebml::doc) -> option<ast::inlined_item> { - let dcx = @{cdata: cdata, tcx: tcx, maps: maps}; - alt par_doc.opt_child(c::tag_ast) { - none { none } - some(ast_doc) { - #debug["> Decoding inlined fn: %s::?", ast_map::path_to_str(path)]; - let from_id_range = decode_id_range(ast_doc); - let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range); - let xcx = @{dcx: dcx, - from_id_range: from_id_range, - to_id_range: to_id_range}; - let raw_ii = decode_ast(ast_doc); - let ii = renumber_ast(xcx, raw_ii); - ast_map::map_decoded_item(dcx.tcx.items, path, ii); - #debug["Fn named: %s", ii.ident()]; - decode_side_tables(xcx, ast_doc); - #debug["< Decoded inlined fn: %s::%s", - ast_map::path_to_str(path), ii.ident()]; - some(ii) - } - } -} - -// ______________________________________________________________________ -// Enumerating the IDs which appear in an AST - -type id_range = {min: ast::node_id, max: ast::node_id}; - -fn empty(range: id_range) -> bool { - range.min >= range.max -} - -fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) { - let visitor = visit::mk_simple_visitor(@{ - visit_mod: fn@(_m: ast::_mod, _sp: span, id: ast::node_id) { - vfn(id) - }, - - visit_view_item: fn@(vi: @ast::view_item) { - alt vi.node { - ast::view_item_use(_, _, id) { vfn(id) } - ast::view_item_import(vps) | ast::view_item_export(vps) { - vec::iter(vps) {|vp| - alt vp.node { - ast::view_path_simple(_, _, id) { vfn(id) } - ast::view_path_glob(_, id) { vfn(id) } - ast::view_path_list(_, _, id) { vfn(id) } - } - } - } - } - }, - - visit_native_item: fn@(ni: @ast::native_item) { - vfn(ni.id) - }, - - visit_item: fn@(i: @ast::item) { - vfn(i.id); - }, - - visit_local: fn@(l: @ast::local) { - vfn(l.node.id); - }, - - visit_block: fn@(b: ast::blk) { - vfn(b.node.id); - }, - - visit_stmt: fn@(s: @ast::stmt) { - vfn(ast_util::stmt_id(*s)); - }, - - visit_arm: fn@(_a: ast::arm) { }, - - visit_pat: fn@(p: @ast::pat) { - vfn(p.id) - }, - - visit_decl: fn@(_d: @ast::decl) { - }, - - visit_expr: fn@(e: @ast::expr) { - vfn(e.id); - alt e.node { - ast::expr_unary(_, _) | ast::expr_binary(_, _, _) { - vfn(ast_util::op_expr_callee_id(e)); - } - _ { /* fallthrough */ } - } - }, - - visit_ty: fn@(t: @ast::ty) { - alt t.node { - ast::ty_path(_, id) { - vfn(id) - } - _ { /* fall through */ } - } - }, - - visit_ty_params: fn@(ps: [ast::ty_param]) { - vec::iter(ps) {|p| vfn(p.id) } - }, - - visit_constr: fn@(_p: @ast::path, _sp: span, id: ast::node_id) { - vfn(id); - }, - - visit_fn: fn@(fk: visit::fn_kind, d: ast::fn_decl, - _b: ast::blk, _sp: span, id: ast::node_id) { - vfn(id); - - alt fk { - visit::fk_item_fn(_, tps) | - visit::fk_method(_, tps) | - visit::fk_res(_, tps) { - vec::iter(tps) {|tp| vfn(tp.id)} - } - visit::fk_anon(_) | - visit::fk_fn_block { - } - } - - vec::iter(d.inputs) {|arg| - vfn(arg.id) - } - }, - - visit_class_item: fn@(_s: span, _p: ast::privacy, - c: ast::class_member) { - alt c { - ast::instance_var(_, _, _, id) { - vfn(id) - } - ast::class_method(_) { - } - } - } - }); - - item.accept((), visitor) -} - -fn compute_id_range(item: ast::inlined_item) -> id_range { - let min = @mutable int::max_value; - let max = @mutable int::min_value; - visit_ids(item) {|id| - *min = int::min(*min, id); - *max = int::max(*max, id + 1); - } - ret {min:*min, max:*max}; -} - -fn encode_id_range(ebml_w: ebml::writer, id_range: id_range) { - ebml_w.wr_tag(c::tag_id_range as uint) {|| - ebml_w.emit_tup(2u) {|| - ebml_w.emit_tup_elt(0u) {|| ebml_w.emit_int(id_range.min) } - ebml_w.emit_tup_elt(1u) {|| ebml_w.emit_int(id_range.max) } - } - } -} - -fn decode_id_range(par_doc: ebml::doc) -> id_range { - let range_doc = par_doc[c::tag_id_range]; - let dsr = serialization::mk_ebml_deserializer(range_doc); - dsr.read_tup(2u) {|| - {min: dsr.read_tup_elt(0u) {|| dsr.read_int() }, - max: dsr.read_tup_elt(1u) {|| dsr.read_int() }} - } -} - -fn reserve_id_range(sess: session, - from_id_range: id_range) -> id_range { - // Handle the case of an empty range: - if empty(from_id_range) { ret from_id_range; } - let cnt = from_id_range.max - from_id_range.min; - let to_id_min = sess.parse_sess.next_id; - let to_id_max = sess.parse_sess.next_id + cnt; - sess.parse_sess.next_id = to_id_max; - ret {min: to_id_min, max: to_id_min}; -} - -impl translation_routines for extended_decode_ctxt { - fn tr_id(id: ast::node_id) -> ast::node_id { - // from_id_range should be non-empty - assert !empty(self.from_id_range); - (id - self.from_id_range.min + self.to_id_range.min) - } - fn tr_def_id(did: ast::def_id) -> ast::def_id { - decoder::translate_def_id(self.dcx.cdata, did) - } - fn tr_intern_def_id(did: ast::def_id) -> ast::def_id { - assert did.crate == ast::local_crate; - {crate: ast::local_crate, node: self.tr_id(did.node)} - } - fn tr_span(_span: span) -> span { - ast_util::dummy_sp() // TODO... - } -} - -impl of tr for ast::def_id { - fn tr(xcx: extended_decode_ctxt) -> ast::def_id { - xcx.tr_def_id(self) - } - fn tr_intern(xcx: extended_decode_ctxt) -> ast::def_id { - xcx.tr_intern_def_id(self) - } -} - -impl of tr for span { - fn tr(xcx: extended_decode_ctxt) -> span { - xcx.tr_span(self) - } -} - -impl serializer_helpers<S: serialization::serializer> for S { - fn emit_def_id(did: ast::def_id) { - astencode_gen::serialize_syntax_ast_def_id(self, did) - } -} - -impl deserializer_helpers<D: serialization::deserializer> for D { - fn read_def_id(xcx: extended_decode_ctxt) -> ast::def_id { - let did = astencode_gen::deserialize_syntax_ast_def_id(self); - did.tr(xcx) - } -} - -// ______________________________________________________________________ -// Encoding and decoding the AST itself -// -// The hard work is done by an autogenerated module astencode_gen. To -// regenerate astencode_gen, run src/etc/gen-astencode. It will -// replace astencode_gen with a dummy file and regenerate its -// contents. If you get compile errors, the dummy file -// remains---resolve the errors and then rerun astencode_gen. -// Annoying, I know, but hopefully only temporary. -// -// When decoding, we have to renumber the AST so that the node ids that -// appear within are disjoint from the node ids in our existing ASTs. -// We also have to adjust the spans: for now we just insert a dummy span, -// but eventually we should add entries to the local codemap as required. - -fn encode_ast(ebml_w: ebml::writer, item: ast::inlined_item) { - ebml_w.wr_tag(c::tag_tree as uint) {|| - astencode_gen::serialize_syntax_ast_inlined_item(ebml_w, item) - } -} - -fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item { - let chi_doc = par_doc[c::tag_tree]; - let d = serialization::mk_ebml_deserializer(chi_doc); - astencode_gen::deserialize_syntax_ast_inlined_item(d) -} - -fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item) - -> ast::inlined_item { - let fld = fold::make_fold({ - new_id: xcx.tr_id(_), - new_span: xcx.tr_span(_) - with *fold::default_ast_fold() - }); - - alt ii { - ast::ii_item(i) { - ast::ii_item(fld.fold_item(i)) - } - ast::ii_method(d, m) { - ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m)) - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding of ast::def - -fn encode_def(ebml_w: ebml::writer, def: ast::def) { - astencode_gen::serialize_syntax_ast_def(ebml_w, def) -} - -fn decode_def(xcx: extended_decode_ctxt, doc: ebml::doc) -> ast::def { - let dsr = serialization::mk_ebml_deserializer(doc); - let def = astencode_gen::deserialize_syntax_ast_def(dsr); - def.tr(xcx) -} - -impl of tr for ast::def { - fn tr(xcx: extended_decode_ctxt) -> ast::def { - alt self { - ast::def_fn(did, p) { ast::def_fn(did.tr(xcx), p) } - ast::def_self(nid) { ast::def_self(xcx.tr_id(nid)) } - ast::def_mod(did) { ast::def_mod(did.tr(xcx)) } - ast::def_native_mod(did) { ast::def_native_mod(did.tr(xcx)) } - ast::def_const(did) { ast::def_const(did.tr(xcx)) } - ast::def_arg(nid, m) { ast::def_arg(xcx.tr_id(nid), m) } - ast::def_local(nid, b) { ast::def_local(xcx.tr_id(nid), b) } - ast::def_variant(e_did, v_did) { - ast::def_variant(e_did.tr(xcx), v_did.tr(xcx)) - } - ast::def_ty(did) { ast::def_ty(did.tr(xcx)) } - ast::def_prim_ty(p) { ast::def_prim_ty(p) } - ast::def_ty_param(did, v) { ast::def_ty_param(did.tr(xcx), v) } - ast::def_binding(nid) { ast::def_binding(xcx.tr_id(nid)) } - ast::def_use(did) { ast::def_use(did.tr(xcx)) } - ast::def_upvar(nid1, def, nid2) { - ast::def_upvar(xcx.tr_id(nid1), @(*def).tr(xcx), xcx.tr_id(nid2)) - } - ast::def_class(did) { - ast::def_class(did.tr(xcx)) - } - ast::def_class_field(did0, did1) { - ast::def_class_field(did0.tr(xcx), did1.tr(xcx)) - } - ast::def_class_method(did0, did1) { - ast::def_class_method(did0.tr(xcx), did1.tr(xcx)) - } - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding of freevar information - -fn encode_freevar_entry(ebml_w: ebml::writer, fv: freevar_entry) { - astencode_gen::serialize_middle_freevars_freevar_entry(ebml_w, fv) -} - -impl helper for serialization::ebml_deserializer { - fn read_freevar_entry(xcx: extended_decode_ctxt) -> freevar_entry { - let fv = - astencode_gen::deserialize_middle_freevars_freevar_entry(self); - fv.tr(xcx) - } -} - -impl of tr for freevar_entry { - fn tr(xcx: extended_decode_ctxt) -> freevar_entry { - {def: self.def.tr(xcx), span: self.span.tr(xcx)} - } -} - -// ______________________________________________________________________ -// Encoding and decoding of method_origin - -fn encode_method_origin(ebml_w: ebml::writer, mo: method_origin) { - astencode_gen::serialize_middle_typeck_method_origin(ebml_w, mo) -} - -impl helper for serialization::ebml_deserializer { - fn read_method_origin(xcx: extended_decode_ctxt) -> method_origin { - let fv = astencode_gen::deserialize_middle_typeck_method_origin(self); - fv.tr(xcx) - } -} - -impl of tr for method_origin { - fn tr(xcx: extended_decode_ctxt) -> method_origin { - alt self { - typeck::method_static(did) { - typeck::method_static(did.tr(xcx)) - } - typeck::method_param(did, m, p, b) { - typeck::method_param(did.tr(xcx), m, p, b) - } - typeck::method_iface(did, m) { - typeck::method_iface(did.tr(xcx), m) - } - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding dict_res - -fn encode_dict_res(ecx: @e::encode_ctxt, - ebml_w: ebml::writer, - dr: typeck::dict_res) { - // can't autogenerate this code because automatic serialization of - // ty::t doesn't work, and there is no way (atm) to have - // hand-written serialization routines combine with auto-generated - // ones. perhaps we should fix this. - ebml_w.emit_from_vec(*dr) {|dict_origin| - encode_dict_origin(ecx, ebml_w, dict_origin) - } -} - -fn encode_dict_origin(ecx: @e::encode_ctxt, - ebml_w: ebml::writer, - dict_origin: typeck::dict_origin) { - ebml_w.emit_enum("dict_origin") {|| - alt dict_origin { - typeck::dict_static(def_id, tys, dict_res) { - ebml_w.emit_enum_variant("dict_static", 0u, 3u) {|| - ebml_w.emit_enum_variant_arg(0u) {|| - ebml_w.emit_def_id(def_id) - } - ebml_w.emit_enum_variant_arg(1u) {|| - ebml_w.emit_tys(ecx, tys); - } - ebml_w.emit_enum_variant_arg(2u) {|| - encode_dict_res(ecx, ebml_w, dict_res); - } - } - } - typeck::dict_param(pn, bn) { - ebml_w.emit_enum_variant("dict_param", 1u, 2u) {|| - ebml_w.emit_enum_variant_arg(0u) {|| - ebml_w.emit_uint(pn); - } - ebml_w.emit_enum_variant_arg(1u) {|| - ebml_w.emit_uint(bn); - } - } - } - typeck::dict_iface(def_id) { - ebml_w.emit_enum_variant("dict_iface", 1u, 3u) {|| - ebml_w.emit_enum_variant_arg(0u) {|| - ebml_w.emit_def_id(def_id) - } - } - } - } - } - -} - -impl helpers for serialization::ebml_deserializer { - fn read_dict_res(xcx: extended_decode_ctxt) -> typeck::dict_res { - @self.read_to_vec {|| self.read_dict_origin(xcx) } - } - - fn read_dict_origin(xcx: extended_decode_ctxt) -> typeck::dict_origin { - self.read_enum("dict_origin") {|| - self.read_enum_variant {|i| - alt check i { - 0u { - typeck::dict_static( - self.read_enum_variant_arg(0u) {|| - self.read_def_id(xcx) - }, - self.read_enum_variant_arg(1u) {|| - self.read_tys(xcx) - }, - self.read_enum_variant_arg(2u) {|| - self.read_dict_res(xcx) - } - ) - } - 1u { - typeck::dict_param( - self.read_enum_variant_arg(0u) {|| - self.read_uint() - }, - self.read_enum_variant_arg(1u) {|| - self.read_uint() - } - ) - } - 2u { - typeck::dict_iface( - self.read_enum_variant_arg(0u) {|| - self.read_def_id(xcx) - } - ) - } - } - } - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding the side tables - -impl helpers for @e::encode_ctxt { - fn ty_str_ctxt() -> @tyencode::ctxt { - @{ds: e::def_to_str, - tcx: self.ccx.tcx, - abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs)} - } -} - -impl helpers for ebml::writer { - fn emit_ty(ecx: @e::encode_ctxt, ty: ty::t) { - e::write_type(ecx, self, ty) - } - - fn emit_tys(ecx: @e::encode_ctxt, tys: [ty::t]) { - self.emit_from_vec(tys) {|ty| - e::write_type(ecx, self, ty) - } - } - - fn emit_bounds(ecx: @e::encode_ctxt, bs: ty::param_bounds) { - tyencode::enc_bounds(self.writer, ecx.ty_str_ctxt(), bs) - } - - fn emit_tpbt(ecx: @e::encode_ctxt, tpbt: ty::ty_param_bounds_and_ty) { - self.emit_rec {|| - self.emit_rec_field("bounds", 0u) {|| - self.emit_from_vec(*tpbt.bounds) {|bs| - self.emit_bounds(ecx, bs) - } - } - self.emit_rec_field("ty", 0u) {|| - self.emit_ty(ecx, tpbt.ty); - } - } - } -} - -impl writer for ebml::writer { - fn tag(tag_id: c::astencode_tag, f: fn()) { - self.wr_tag(tag_id as uint) {|| f() } - } - - fn id(id: ast::node_id) { - self.wr_tagged_u64(c::tag_table_id as uint, id as u64) - } -} - -fn encode_side_tables_for_ii(ecx: @e::encode_ctxt, - ebml_w: ebml::writer, - ii: ast::inlined_item) { - ebml_w.wr_tag(c::tag_table as uint) {|| - visit_ids(ii, fn@(id: ast::node_id) { - // Note: this will cause a copy of ebml_w, which is bad as - // it has mutable fields. But I believe it's harmless since - // we generate balanced EBML. - encode_side_tables_for_id(ecx, ebml_w, id) - }); - } -} - -fn encode_side_tables_for_id(ecx: @e::encode_ctxt, - ebml_w: ebml::writer, - id: ast::node_id) { - - let ccx = ecx.ccx; - let tcx = ccx.tcx; - - #debug["Encoding side tables for id %d", id]; - - option::may(tcx.def_map.find(id)) {|def| - ebml_w.tag(c::tag_table_def) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - astencode_gen::serialize_syntax_ast_def(ebml_w, def) - } - } - } - option::may((*tcx.node_types).find(id as uint)) {|ty| - ebml_w.tag(c::tag_table_node_type) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - e::write_type(ecx, ebml_w, ty) - } - } - } - - option::may(tcx.node_type_substs.find(id)) {|tys| - ebml_w.tag(c::tag_table_node_type_subst) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - ebml_w.emit_tys(ecx, tys) - } - } - } - - option::may(tcx.freevars.find(id)) {|fv| - ebml_w.tag(c::tag_table_freevars) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - ebml_w.emit_from_vec(*fv) {|fv_entry| - encode_freevar_entry(ebml_w, *fv_entry) - } - } - } - } - - let lid = {crate: ast::local_crate, node: id}; - option::may(tcx.tcache.find(lid)) {|tpbt| - ebml_w.tag(c::tag_table_tcache) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - ebml_w.emit_tpbt(ecx, tpbt); - } - } - } - - option::may(tcx.ty_param_bounds.find(id)) {|pbs| - ebml_w.tag(c::tag_table_param_bounds) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - ebml_w.emit_bounds(ecx, pbs) - } - } - } - - // I believe it is not necessary to encode this information. The - // ids will appear in the AST but in the *type* information, which - // is what we actually use in trans, all modes will have been - // resolved. - // - //option::may(tcx.inferred_modes.find(id)) {|m| - // ebml_w.tag(c::tag_table_inferred_modes) {|| - // ebml_w.id(id); - // ebml_w.tag(c::tag_table_val) {|| - // tyencode::enc_mode(ebml_w.writer, ty_str_ctxt(), m); - // } - // } - //} - - option::may(ccx.maps.mutbl_map.find(id)) {|_m| - ebml_w.tag(c::tag_table_mutbl) {|| - ebml_w.id(id); - } - } - - option::may(ccx.maps.copy_map.find(id)) {|_m| - ebml_w.tag(c::tag_table_copy) {|| - ebml_w.id(id); - } - } - - option::may(ccx.maps.last_uses.find(id)) {|_m| - ebml_w.tag(c::tag_table_last_use) {|| - ebml_w.id(id); - } - } - - // impl_map is not used except when emitting metadata, - // don't need to keep it. - - option::may(ccx.maps.method_map.find(id)) {|mo| - ebml_w.tag(c::tag_table_method_map) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - astencode_gen:: - serialize_middle_typeck_method_origin(ebml_w, mo) - } - } - } - - option::may(ccx.maps.dict_map.find(id)) {|dr| - ebml_w.tag(c::tag_table_dict_map) {|| - ebml_w.id(id); - ebml_w.tag(c::tag_table_val) {|| - encode_dict_res(ecx, ebml_w, dr); - } - } - } -} - -impl decoder for ebml::doc { - fn as_int() -> int { ebml::doc_as_u64(self) as int } - fn [](tag: c::astencode_tag) -> ebml::doc { - ebml::get_doc(self, tag as uint) - } - fn opt_child(tag: c::astencode_tag) -> option<ebml::doc> { - ebml::maybe_get_doc(self, tag as uint) - } -} - -impl decoder for serialization::ebml_deserializer { - fn read_ty(xcx: extended_decode_ctxt) -> ty::t { - tydecode::parse_ty_data( - self.parent.data, xcx.dcx.cdata.cnum, self.pos, xcx.dcx.tcx, - xcx.tr_def_id(_)) - } - - fn read_tys(xcx: extended_decode_ctxt) -> [ty::t] { - self.read_to_vec {|| self.read_ty(xcx) } - } - - fn read_bounds(xcx: extended_decode_ctxt) -> @[ty::param_bound] { - tydecode::parse_bounds_data( - self.parent.data, self.pos, xcx.dcx.cdata.cnum, xcx.dcx.tcx, - xcx.tr_def_id(_)) - } - - fn read_ty_param_bounds_and_ty(xcx: extended_decode_ctxt) - -> ty::ty_param_bounds_and_ty { - self.read_rec {|| - { - bounds: self.read_rec_field("bounds", 0u) {|| - @self.read_to_vec {|| self.read_bounds(xcx) } - }, - ty: self.read_rec_field("ty", 1u) {|| - self.read_ty(xcx) - } - } - } - } -} - -fn decode_side_tables(xcx: extended_decode_ctxt, - ast_doc: ebml::doc) { - let dcx = xcx.dcx; - let tbl_doc = ast_doc[c::tag_table]; - ebml::docs(tbl_doc) {|tag, entry_doc| - let id0 = entry_doc[c::tag_table_id].as_int(); - let id = xcx.tr_id(id0); - - #debug[">> Side table document with tag 0x%x \ - found for id %d (orig %d)", - tag, id, id0]; - - if tag == (c::tag_table_mutbl as uint) { - dcx.maps.mutbl_map.insert(id, ()); - } else if tag == (c::tag_table_copy as uint) { - dcx.maps.copy_map.insert(id, ()); - } else if tag == (c::tag_table_last_use as uint) { - dcx.maps.last_uses.insert(id, last_use::is_last_use); - } else { - let val_doc = entry_doc[c::tag_table_val]; - let val_dsr = serialization::mk_ebml_deserializer(val_doc); - if tag == (c::tag_table_def as uint) { - let def = decode_def(xcx, val_doc); - dcx.tcx.def_map.insert(id, def); - } else if tag == (c::tag_table_node_type as uint) { - let ty = val_dsr.read_ty(xcx); - (*dcx.tcx.node_types).insert(id as uint, ty); - } else if tag == (c::tag_table_node_type_subst as uint) { - let tys = val_dsr.read_tys(xcx); - dcx.tcx.node_type_substs.insert(id, tys); - } else if tag == (c::tag_table_freevars as uint) { - let fv_info = @val_dsr.read_to_vec {|| - @val_dsr.read_freevar_entry(xcx) - }; - dcx.tcx.freevars.insert(id, fv_info); - } else if tag == (c::tag_table_tcache as uint) { - let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); - let lid = {crate: ast::local_crate, node: id}; - dcx.tcx.tcache.insert(lid, tpbt); - } else if tag == (c::tag_table_param_bounds as uint) { - let bounds = val_dsr.read_bounds(xcx); - dcx.tcx.ty_param_bounds.insert(id, bounds); - } else if tag == (c::tag_table_method_map as uint) { - dcx.maps.method_map.insert(id, - val_dsr.read_method_origin(xcx)); - } else if tag == (c::tag_table_dict_map as uint) { - dcx.maps.dict_map.insert(id, - val_dsr.read_dict_res(xcx)); - } else { - xcx.dcx.tcx.sess.bug( - #fmt["Unknown tag found in side tables: %x", tag]); - } - } - - #debug[">< Side table doc loaded"]; - } -} - -// ______________________________________________________________________ -// Testing of astencode_gen - -#[cfg(test)] -fn encode_item_ast(ebml_w: ebml::writer, item: @ast::item) { - ebml_w.wr_tag(c::tag_tree as uint) {|| - astencode_gen::serialize_syntax_ast_item(ebml_w, *item); - } -} - -#[cfg(test)] -fn decode_item_ast(par_doc: ebml::doc) -> @ast::item { - let chi_doc = par_doc[c::tag_tree]; - let d = serialization::mk_ebml_deserializer(chi_doc); - @astencode_gen::deserialize_syntax_ast_item(d) -} - -#[cfg(test)] -fn new_parse_sess() -> parser::parse_sess { - let cm = codemap::new_codemap(); - let handler = diagnostic::mk_handler(option::none); - let sess = @{ - cm: cm, - mutable next_id: 1, - span_diagnostic: diagnostic::mk_span_handler(handler, cm), - mutable chpos: 0u, - mutable byte_pos: 0u - }; - ret sess; -} - -#[cfg(test)] -iface fake_ext_ctxt { - fn session() -> fake_session; -} - -#[cfg(test)] -type fake_options = {cfg: ast::crate_cfg}; - -#[cfg(test)] -type fake_session = {opts: @fake_options, - parse_sess: parser::parse_sess}; - -#[cfg(test)] -impl of fake_ext_ctxt for fake_session { - fn session() -> fake_session {self} -} - -#[cfg(test)] -fn mk_ctxt() -> fake_ext_ctxt { - let opts : fake_options = {cfg: []}; - {opts: @opts, parse_sess: new_parse_sess()} as fake_ext_ctxt -} - -#[cfg(test)] -fn roundtrip(in_item: @ast::item) { - #debug["in_item = %s", pprust::item_to_str(in_item)]; - let mbuf = io::mk_mem_buffer(); - let ebml_w = ebml::mk_writer(io::mem_buffer_writer(mbuf)); - encode_item_ast(ebml_w, in_item); - let ebml_doc = ebml::new_doc(@io::mem_buffer_buf(mbuf)); - let out_item = decode_item_ast(ebml_doc); - #debug["out_item = %s", pprust::item_to_str(out_item)]; - assert in_item == out_item; -} - -#[test] -fn test_basic() { - let ext_cx = mk_ctxt(); - roundtrip(#ast(item){ - fn foo() {} - }); -} - -#[test] -fn test_smalltalk() { - let ext_cx = mk_ctxt(); - roundtrip(#ast(item){ - fn foo() -> int { 3 + 4 } // first smalltalk program ever executed. - }); -} - -#[test] -fn test_more() { - let ext_cx = mk_ctxt(); - roundtrip(#ast(item){ - fn foo(x: uint, y: uint) -> uint { - let z = x + y; - ret z; - } - }); -} \ No newline at end of file diff --git a/src/comp/metadata/astencode_gen.rs b/src/comp/metadata/astencode_gen.rs deleted file mode 100644 index 1c413de261c..00000000000 --- a/src/comp/metadata/astencode_gen.rs +++ /dev/null @@ -1,8831 +0,0 @@ -/*syntax::ast::ident*/ -fn serialize_1<S: std::serialization::serializer>(s: S, - v: syntax::ast::ident) { - - s.emit_str(v); -} -/*syntax::ast::attr_style*/ -fn serialize_5<S: std::serialization::serializer>(s: S, - v: - syntax::ast::attr_style) { - s.emit_enum("syntax::ast::attr_style", - - {|| - alt v { - syntax::ast::attr_outer { - s.emit_enum_variant("syntax::ast::attr_outer", 0u, 0u, - {|| }) - } - syntax::ast::attr_inner { - s.emit_enum_variant("syntax::ast::attr_inner", 1u, 0u, - {|| }) - } - } - }); -} -/*@syntax::ast::meta_item*/ -fn serialize_9<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::meta_item) { - s.emit_box(/*syntax::ast::meta_item*/{|| serialize_6(s, *v) }); -} -/*[@syntax::ast::meta_item]*/ -fn serialize_8<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::meta_item]) { - s.emit_vec(vec::len(v), /*@syntax::ast::meta_item*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_9(s, e) }) - }) - }); -} -/*str*/ -fn serialize_12<S: std::serialization::serializer>(s: S, v: str) { - - s.emit_str(v); -} -/*i64*/ -fn serialize_13<S: std::serialization::serializer>(s: S, v: i64) { - - s.emit_i64(v); -} -/*syntax::ast::int_ty*/ -fn serialize_14<S: std::serialization::serializer>(s: S, - v: syntax::ast::int_ty) { - - s.emit_enum("syntax::ast::int_ty", - - - - - - {|| - alt v { - syntax::ast::ty_i { - s.emit_enum_variant("syntax::ast::ty_i", 0u, 0u, - {|| }) - } - syntax::ast::ty_char { - s.emit_enum_variant("syntax::ast::ty_char", 1u, 0u, - {|| }) - } - syntax::ast::ty_i8 { - s.emit_enum_variant("syntax::ast::ty_i8", 2u, 0u, - {|| }) - } - syntax::ast::ty_i16 { - s.emit_enum_variant("syntax::ast::ty_i16", 3u, 0u, - {|| }) - } - syntax::ast::ty_i32 { - s.emit_enum_variant("syntax::ast::ty_i32", 4u, 0u, - {|| }) - } - syntax::ast::ty_i64 { - s.emit_enum_variant("syntax::ast::ty_i64", 5u, 0u, - {|| }) - } - } - }); -} -/*u64*/ -fn serialize_15<S: std::serialization::serializer>(s: S, v: u64) { - - s.emit_u64(v); -} -/*syntax::ast::uint_ty*/ -fn serialize_16<S: std::serialization::serializer>(s: S, - v: syntax::ast::uint_ty) { - - s.emit_enum("syntax::ast::uint_ty", - - - - - {|| - alt v { - syntax::ast::ty_u { - s.emit_enum_variant("syntax::ast::ty_u", 0u, 0u, - {|| }) - } - syntax::ast::ty_u8 { - s.emit_enum_variant("syntax::ast::ty_u8", 1u, 0u, - {|| }) - } - syntax::ast::ty_u16 { - s.emit_enum_variant("syntax::ast::ty_u16", 2u, 0u, - {|| }) - } - syntax::ast::ty_u32 { - s.emit_enum_variant("syntax::ast::ty_u32", 3u, 0u, - {|| }) - } - syntax::ast::ty_u64 { - s.emit_enum_variant("syntax::ast::ty_u64", 4u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::float_ty*/ -fn serialize_17<S: std::serialization::serializer>(s: S, - v: syntax::ast::float_ty) { - - s.emit_enum("syntax::ast::float_ty", - - - {|| - alt v { - syntax::ast::ty_f { - s.emit_enum_variant("syntax::ast::ty_f", 0u, 0u, - {|| }) - } - syntax::ast::ty_f32 { - s.emit_enum_variant("syntax::ast::ty_f32", 1u, 0u, - {|| }) - } - syntax::ast::ty_f64 { - s.emit_enum_variant("syntax::ast::ty_f64", 2u, 0u, - {|| }) - } - } - }); -} -/*bool*/ -fn serialize_18<S: std::serialization::serializer>(s: S, v: bool) { - - s.emit_bool(v); -} -/*syntax::ast::lit_*/ -fn serialize_11<S: std::serialization::serializer>(s: S, - v: syntax::ast::lit_) { - - s.emit_enum("syntax::ast::lit_", - /*str*/ - /*i64*//*syntax::ast::int_ty*/ - /*u64*//*syntax::ast::uint_ty*/ - /*str*//*syntax::ast::float_ty*/ - - /*bool*/ - {|| - alt v { - syntax::ast::lit_str(v0) { - s.emit_enum_variant("syntax::ast::lit_str", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_12(s, - v0) - }) - } - }) - } - syntax::ast::lit_int(v0, v1) { - s.emit_enum_variant("syntax::ast::lit_int", 1u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_13(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_14(s, - v1) - }) - } - }) - } - syntax::ast::lit_uint(v0, v1) { - s.emit_enum_variant("syntax::ast::lit_uint", 2u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_15(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_16(s, - v1) - }) - } - }) - } - syntax::ast::lit_float(v0, v1) { - s.emit_enum_variant("syntax::ast::lit_float", 3u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_12(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_17(s, - v1) - }) - } - }) - } - syntax::ast::lit_nil { - s.emit_enum_variant("syntax::ast::lit_nil", 4u, 0u, - {|| }) - } - syntax::ast::lit_bool(v0) { - s.emit_enum_variant("syntax::ast::lit_bool", 5u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_18(s, - v0) - }) - } - }) - } - } - }); -} -/*uint*/ -fn serialize_20<S: std::serialization::serializer>(s: S, v: uint) { - - s.emit_uint(v); -} -/*core::option::t<syntax::codemap::span>*/ -fn serialize_26<S: std::serialization::serializer>(s: S, - v: - core::option::t<syntax::codemap::span>) { - s.emit_enum("core::option::t", - - /*syntax::codemap::span*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_19(s, - v0) - }) - } - }) - } - } - }); -} -/*{name: str,span: core::option::t<syntax::codemap::span>}*/ -fn serialize_25<S: std::serialization::serializer>(s: S, - v: - {name: str, - span: - core::option::t<syntax::codemap::span>,}) { - s.emit_rec(/*str*//*core::option::t<syntax::codemap::span>*/ - {|| - { - s.emit_rec_field("name", 0u, - {|| serialize_12(s, v.name) }); - s.emit_rec_field("span", 1u, - {|| serialize_26(s, v.span) }) - } - }); -} - -/*{call_site: syntax::codemap::span,callie: {name: str,span: core::option::t<syntax::codemap::span>}}*/ -fn serialize_24<S: std::serialization::serializer>(s: S, - v: - {call_site: - syntax::codemap::span, - callie: - {name: str, - span: - core::option::t<syntax::codemap::span>,},}) { - s.emit_rec(/*syntax::codemap::span*/ - /*{name: str,span: core::option::t<syntax::codemap::span>}*/ - {|| - { - s.emit_rec_field("call_site", 0u, - {|| serialize_19(s, v.call_site) }); - s.emit_rec_field("callie", 1u, - {|| serialize_25(s, v.callie) }) - } - }); -} -/*syntax::codemap::expn_info_*/ -fn serialize_23<S: std::serialization::serializer>(s: S, - v: - syntax::codemap::expn_info_) { - s.emit_enum("syntax::codemap::expn_info_", - - /*{call_site: syntax::codemap::span,callie: {name: str,span: core::option::t<syntax::codemap::span>}}*/ - {|| - alt v { - syntax::codemap::expanded_from(v0) { - s.emit_enum_variant("syntax::codemap::expanded_from", - 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_24(s, - v0) - }) - } - }) - } - } - }); -} -/*@syntax::codemap::expn_info_*/ -fn serialize_22<S: std::serialization::serializer>(s: S, - v: - @syntax::codemap::expn_info_) { - s.emit_box(/*syntax::codemap::expn_info_*/{|| serialize_23(s, *v) }); -} -/*syntax::codemap::expn_info<@syntax::codemap::expn_info_>*/ -fn serialize_21<S: std::serialization::serializer>(s: S, - v: - syntax::codemap::expn_info<@syntax::codemap::expn_info_>) { - s.emit_enum("core::option::t", - - /*@syntax::codemap::expn_info_*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_22(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::codemap::span*/ -fn serialize_19<S: std::serialization::serializer>(s: S, - v: syntax::codemap::span) { - - s.emit_rec(/*uint*//*uint*/ - /*syntax::codemap::expn_info<@syntax::codemap::expn_info_>*/ - {|| - { - s.emit_rec_field("lo", 0u, - {|| serialize_20(s, v.lo) }); - s.emit_rec_field("hi", 1u, - {|| serialize_20(s, v.hi) }); - s.emit_rec_field("expn_info", 2u, - {|| serialize_21(s, v.expn_info) }) - } - }); -} -/*syntax::ast::lit*/ -fn serialize_10<S: std::serialization::serializer>(s: S, - v: syntax::ast::lit) { - - s.emit_rec(/*syntax::ast::lit_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_11(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*syntax::ast::meta_item_*/ -fn serialize_7<S: std::serialization::serializer>(s: S, - v: - syntax::ast::meta_item_) { - s.emit_enum("syntax::ast::meta_item_", - /*syntax::ast::ident*/ - /*syntax::ast::ident*//*[@syntax::ast::meta_item]*/ - /*syntax::ast::ident*//*syntax::ast::lit*/ - {|| - alt v { - syntax::ast::meta_word(v0) { - s.emit_enum_variant("syntax::ast::meta_word", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_1(s, - v0) - }) - } - }) - } - syntax::ast::meta_list(v0, v1) { - s.emit_enum_variant("syntax::ast::meta_list", 1u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_1(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_8(s, - v1) - }) - } - }) - } - syntax::ast::meta_name_value(v0, v1) { - s.emit_enum_variant("syntax::ast::meta_name_value", - 2u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_1(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_10(s, - v1) - }) - } - }) - } - } - }); -} -/*syntax::ast::meta_item*/ -fn serialize_6<S: std::serialization::serializer>(s: S, - v: syntax::ast::meta_item) { - - s.emit_rec(/*syntax::ast::meta_item_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_7(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*syntax::ast::attribute_*/ -fn serialize_4<S: std::serialization::serializer>(s: S, - v: - syntax::ast::attribute_) { - s.emit_rec(/*syntax::ast::attr_style*//*syntax::ast::meta_item*/ - {|| - { - s.emit_rec_field("style", 0u, - {|| serialize_5(s, v.style) }); - s.emit_rec_field("value", 1u, - {|| serialize_6(s, v.value) }) - } - }); -} -/*syntax::ast::attribute*/ -fn serialize_3<S: std::serialization::serializer>(s: S, - v: syntax::ast::attribute) { - - s.emit_rec(/*syntax::ast::attribute_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_4(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*[syntax::ast::attribute]*/ -fn serialize_2<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::attribute]) { - s.emit_vec(vec::len(v), /*syntax::ast::attribute*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_3(s, e) }) - }) - }); -} -/*syntax::ast::node_id*/ -fn serialize_27<S: std::serialization::serializer>(s: S, - v: syntax::ast::node_id) { - - s.emit_int(v); -} -/*syntax::ast::mutability*/ -fn serialize_33<S: std::serialization::serializer>(s: S, - v: - syntax::ast::mutability) { - s.emit_enum("syntax::ast::mutability", - - - {|| - alt v { - syntax::ast::m_mutbl { - s.emit_enum_variant("syntax::ast::m_mutbl", 0u, 0u, - {|| }) - } - syntax::ast::m_imm { - s.emit_enum_variant("syntax::ast::m_imm", 1u, 0u, - {|| }) - } - syntax::ast::m_const { - s.emit_enum_variant("syntax::ast::m_const", 2u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::mt*/ -fn serialize_32<S: std::serialization::serializer>(s: S, v: syntax::ast::mt) { - - s.emit_rec(/*@syntax::ast::ty*//*syntax::ast::mutability*/ - {|| - { - s.emit_rec_field("ty", 0u, - {|| serialize_29(s, v.ty) }); - s.emit_rec_field("mutbl", 1u, - {|| serialize_33(s, v.mutbl) }) - } - }); -} -/*syntax::ast::ty_field_*/ -fn serialize_36<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ty_field_) { - s.emit_rec(/*syntax::ast::ident*//*syntax::ast::mt*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("mt", 1u, {|| serialize_32(s, v.mt) }) - } - }); -} -/*syntax::ast::ty_field*/ -fn serialize_35<S: std::serialization::serializer>(s: S, - v: syntax::ast::ty_field) { - - s.emit_rec(/*syntax::ast::ty_field_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_36(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*[syntax::ast::ty_field]*/ -fn serialize_34<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::ty_field]) { - s.emit_vec(vec::len(v), /*syntax::ast::ty_field*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_35(s, e) }) - }) - }); -} -/*syntax::ast::proto*/ -fn serialize_37<S: std::serialization::serializer>(s: S, - v: syntax::ast::proto) { - - s.emit_enum("syntax::ast::proto", - - - - - {|| - alt v { - syntax::ast::proto_bare { - s.emit_enum_variant("syntax::ast::proto_bare", 0u, 0u, - {|| }) - } - syntax::ast::proto_any { - s.emit_enum_variant("syntax::ast::proto_any", 1u, 0u, - {|| }) - } - syntax::ast::proto_uniq { - s.emit_enum_variant("syntax::ast::proto_uniq", 2u, 0u, - {|| }) - } - syntax::ast::proto_box { - s.emit_enum_variant("syntax::ast::proto_box", 3u, 0u, - {|| }) - } - syntax::ast::proto_block { - s.emit_enum_variant("syntax::ast::proto_block", 4u, - 0u, {|| }) - } - } - }); -} -/*syntax::ast::rmode*/ -fn serialize_42<S: std::serialization::serializer>(s: S, - v: syntax::ast::rmode) { - - s.emit_enum("syntax::ast::rmode", - - - - - {|| - alt v { - syntax::ast::by_ref { - s.emit_enum_variant("syntax::ast::by_ref", 0u, 0u, - {|| }) - } - syntax::ast::by_val { - s.emit_enum_variant("syntax::ast::by_val", 1u, 0u, - {|| }) - } - syntax::ast::by_mutbl_ref { - s.emit_enum_variant("syntax::ast::by_mutbl_ref", 2u, - 0u, {|| }) - } - syntax::ast::by_move { - s.emit_enum_variant("syntax::ast::by_move", 3u, 0u, - {|| }) - } - syntax::ast::by_copy { - s.emit_enum_variant("syntax::ast::by_copy", 4u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::mode<syntax::ast::rmode>*/ -fn serialize_41<S: std::serialization::serializer>(s: S, - v: - syntax::ast::mode<syntax::ast::rmode>) { - s.emit_enum("syntax::ast::inferable", - /*syntax::ast::rmode*/ - /*syntax::ast::node_id*/ - {|| - alt v { - syntax::ast::expl(v0) { - s.emit_enum_variant("syntax::ast::expl", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_42(s, - v0) - }) - } - }) - } - syntax::ast::infer(v0) { - s.emit_enum_variant("syntax::ast::infer", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_27(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::arg*/ -fn serialize_40<S: std::serialization::serializer>(s: S, - v: syntax::ast::arg) { - - s.emit_rec(/*syntax::ast::mode<syntax::ast::rmode>*//*@syntax::ast::ty*/ - /*syntax::ast::ident*//*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("mode", 0u, - {|| serialize_41(s, v.mode) }); - s.emit_rec_field("ty", 1u, - {|| serialize_29(s, v.ty) }); - s.emit_rec_field("ident", 2u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("id", 3u, {|| serialize_27(s, v.id) }) - } - }); -} -/*[syntax::ast::arg]*/ -fn serialize_39<S: std::serialization::serializer>(s: S, - v: [syntax::ast::arg]) { - - s.emit_vec(vec::len(v), /*syntax::ast::arg*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_40(s, e) }) - }) - }); -} -/*syntax::ast::purity*/ -fn serialize_43<S: std::serialization::serializer>(s: S, - v: syntax::ast::purity) { - - s.emit_enum("syntax::ast::purity", - - - - {|| - alt v { - syntax::ast::pure_fn { - s.emit_enum_variant("syntax::ast::pure_fn", 0u, 0u, - {|| }) - } - syntax::ast::unsafe_fn { - s.emit_enum_variant("syntax::ast::unsafe_fn", 1u, 0u, - {|| }) - } - syntax::ast::impure_fn { - s.emit_enum_variant("syntax::ast::impure_fn", 2u, 0u, - {|| }) - } - syntax::ast::crust_fn { - s.emit_enum_variant("syntax::ast::crust_fn", 3u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::ret_style*/ -fn serialize_44<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ret_style) { - s.emit_enum("syntax::ast::ret_style", - - {|| - alt v { - syntax::ast::noreturn { - s.emit_enum_variant("syntax::ast::noreturn", 0u, 0u, - {|| }) - } - syntax::ast::return_val { - s.emit_enum_variant("syntax::ast::return_val", 1u, 0u, - {|| }) - } - } - }); -} -/*[syntax::ast::ident]*/ -fn serialize_52<S: std::serialization::serializer>(s: S, - v: [syntax::ast::ident]) { - - s.emit_vec(vec::len(v), /*syntax::ast::ident*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_1(s, e) }) - }) - }); -} -/*[@syntax::ast::ty]*/ -fn serialize_53<S: std::serialization::serializer>(s: S, - v: [@syntax::ast::ty]) { - - s.emit_vec(vec::len(v), /*@syntax::ast::ty*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_29(s, e) }) - }) - }); -} -/*syntax::ast::path_*/ -fn serialize_51<S: std::serialization::serializer>(s: S, - v: syntax::ast::path_) { - - s.emit_rec(/*bool*//*[syntax::ast::ident]*//*[@syntax::ast::ty]*/ - {|| - { - s.emit_rec_field("global", 0u, - {|| serialize_18(s, v.global) }); - s.emit_rec_field("idents", 1u, - {|| serialize_52(s, v.idents) }); - s.emit_rec_field("types", 2u, - {|| serialize_53(s, v.types) }) - } - }); -} -/*syntax::ast::path*/ -fn serialize_50<S: std::serialization::serializer>(s: S, - v: syntax::ast::path) { - - s.emit_rec(/*syntax::ast::path_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_51(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::path*/ -fn serialize_49<S: std::serialization::serializer>(s: S, - v: @syntax::ast::path) { - - s.emit_box(/*syntax::ast::path*/{|| serialize_50(s, *v) }); -} -/*@syntax::ast::lit*/ -fn serialize_58<S: std::serialization::serializer>(s: S, - v: @syntax::ast::lit) { - - s.emit_box(/*syntax::ast::lit*/{|| serialize_10(s, *v) }); -} -/*syntax::ast::constr_arg_general_<uint>*/ -fn serialize_57<S: std::serialization::serializer>(s: S, - v: - syntax::ast::constr_arg_general_<uint>) { - s.emit_enum("syntax::ast::constr_arg_general_", - - /*uint*/ - /*@syntax::ast::lit*/ - {|| - alt v { - syntax::ast::carg_base { - s.emit_enum_variant("syntax::ast::carg_base", 0u, 0u, - {|| }) - } - syntax::ast::carg_ident(v0) { - s.emit_enum_variant("syntax::ast::carg_ident", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_20(s, - v0) - }) - } - }) - } - syntax::ast::carg_lit(v0) { - s.emit_enum_variant("syntax::ast::carg_lit", 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_58(s, - v0) - }) - } - }) - } - } - }); -} -/*{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ -fn serialize_56<S: std::serialization::serializer>(s: S, - v: - {node: - syntax::ast::constr_arg_general_<uint>, - span: - syntax::codemap::span,}) { - s.emit_rec(/*syntax::ast::constr_arg_general_<uint>*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_57(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} - -/*@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ -fn serialize_55<S: std::serialization::serializer>(s: S, - v: - @{node: - syntax::ast::constr_arg_general_<uint>, - span: - syntax::codemap::span,}) { - s.emit_box( - /*{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ - {|| serialize_56(s, *v) }); -} - -/*[@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}]*/ -fn serialize_54<S: std::serialization::serializer>(s: S, - v: - [@{node: - syntax::ast::constr_arg_general_<uint>, - span: - syntax::codemap::span,}]) { - s.emit_vec(vec::len(v), - /*@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_55(s, e) }) - }) - }); -} - -/*{path: @syntax::ast::path,args: [@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}],id: syntax::ast::node_id}*/ -fn serialize_48<S: std::serialization::serializer>(s: S, - v: - {path: - @syntax::ast::path, - args: - [@{node: - syntax::ast::constr_arg_general_<uint>, - span: - syntax::codemap::span,}], - id: - syntax::ast::node_id,}) { - s.emit_rec(/*@syntax::ast::path*/ - /*[@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}]*/ - /*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("path", 0u, - {|| serialize_49(s, v.path) }); - s.emit_rec_field("args", 1u, - {|| serialize_54(s, v.args) }); - s.emit_rec_field("id", 2u, {|| serialize_27(s, v.id) }) - } - }); -} -/*syntax::ast::constr*/ -fn serialize_47<S: std::serialization::serializer>(s: S, - v: syntax::ast::constr) { - - s.emit_rec( - /*{path: @syntax::ast::path,args: [@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}],id: syntax::ast::node_id}*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_48(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::constr*/ -fn serialize_46<S: std::serialization::serializer>(s: S, - v: @syntax::ast::constr) { - - s.emit_box(/*syntax::ast::constr*/{|| serialize_47(s, *v) }); -} -/*[@syntax::ast::constr]*/ -fn serialize_45<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::constr]) { - s.emit_vec(vec::len(v), /*@syntax::ast::constr*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_46(s, e) }) - }) - }); -} -/*syntax::ast::fn_decl*/ -fn serialize_38<S: std::serialization::serializer>(s: S, - v: syntax::ast::fn_decl) { - - s.emit_rec(/*[syntax::ast::arg]*//*@syntax::ast::ty*/ - /*syntax::ast::purity*//*syntax::ast::ret_style*/ - /*[@syntax::ast::constr]*/ - {|| - { - s.emit_rec_field("inputs", 0u, - {|| serialize_39(s, v.inputs) }); - s.emit_rec_field("output", 1u, - {|| serialize_29(s, v.output) }); - s.emit_rec_field("purity", 2u, - {|| serialize_43(s, v.purity) }); - s.emit_rec_field("cf", 3u, - {|| serialize_44(s, v.cf) }); - s.emit_rec_field("constraints", 4u, - {|| serialize_45(s, v.constraints) }) - } - }); -} -/*syntax::ast::constr_arg_general_<@syntax::ast::path>*/ -fn serialize_66<S: std::serialization::serializer>(s: S, - v: - syntax::ast::constr_arg_general_<@syntax::ast::path>) { - s.emit_enum("syntax::ast::constr_arg_general_", - - /*@syntax::ast::path*/ - /*@syntax::ast::lit*/ - {|| - alt v { - syntax::ast::carg_base { - s.emit_enum_variant("syntax::ast::carg_base", 0u, 0u, - {|| }) - } - syntax::ast::carg_ident(v0) { - s.emit_enum_variant("syntax::ast::carg_ident", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_49(s, - v0) - }) - } - }) - } - syntax::ast::carg_lit(v0) { - s.emit_enum_variant("syntax::ast::carg_lit", 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_58(s, - v0) - }) - } - }) - } - } - }); -} - -/*{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ -fn serialize_65<S: std::serialization::serializer>(s: S, - v: - {node: - syntax::ast::constr_arg_general_<@syntax::ast::path>, - span: - syntax::codemap::span,}) { - s.emit_rec(/*syntax::ast::constr_arg_general_<@syntax::ast::path>*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_66(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} - -/*@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ -fn serialize_64<S: std::serialization::serializer>(s: S, - v: - @{node: - syntax::ast::constr_arg_general_<@syntax::ast::path>, - span: - syntax::codemap::span,}) { - s.emit_box( - /*{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ - {|| serialize_65(s, *v) }); -} - -/*[@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}]*/ -fn serialize_63<S: std::serialization::serializer>(s: S, - v: - [@{node: - syntax::ast::constr_arg_general_<@syntax::ast::path>, - span: - syntax::codemap::span,}]) { - s.emit_vec(vec::len(v), - /*@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_64(s, e) }) - }) - }); -} -/*syntax::ast::ty_constr_*/ -fn serialize_62<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ty_constr_) { - s.emit_rec(/*@syntax::ast::path*/ - /*[@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}]*/ - /*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("path", 0u, - {|| serialize_49(s, v.path) }); - s.emit_rec_field("args", 1u, - {|| serialize_63(s, v.args) }); - s.emit_rec_field("id", 2u, {|| serialize_27(s, v.id) }) - } - }); -} -/*syntax::ast::ty_constr*/ -fn serialize_61<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ty_constr) { - s.emit_rec(/*syntax::ast::ty_constr_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_62(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::ty_constr*/ -fn serialize_60<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::ty_constr) { - s.emit_box(/*syntax::ast::ty_constr*/{|| serialize_61(s, *v) }); -} -/*[@syntax::ast::ty_constr]*/ -fn serialize_59<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::ty_constr]) { - s.emit_vec(vec::len(v), /*@syntax::ast::ty_constr*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_60(s, e) }) - }) - }); -} -/*[@syntax::ast::expr]*/ -fn serialize_73<S: std::serialization::serializer>(s: S, - v: [@syntax::ast::expr]) { - - s.emit_vec(vec::len(v), /*@syntax::ast::expr*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_70(s, e) }) - }) - }); -} -/*syntax::ast::field_*/ -fn serialize_76<S: std::serialization::serializer>(s: S, - v: syntax::ast::field_) { - - s.emit_rec(/*syntax::ast::mutability*//*syntax::ast::ident*/ - /*@syntax::ast::expr*/ - {|| - { - s.emit_rec_field("mutbl", 0u, - {|| serialize_33(s, v.mutbl) }); - s.emit_rec_field("ident", 1u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("expr", 2u, - {|| serialize_70(s, v.expr) }) - } - }); -} -/*syntax::ast::field*/ -fn serialize_75<S: std::serialization::serializer>(s: S, - v: syntax::ast::field) { - - s.emit_rec(/*syntax::ast::field_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_76(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*[syntax::ast::field]*/ -fn serialize_74<S: std::serialization::serializer>(s: S, - v: [syntax::ast::field]) { - - s.emit_vec(vec::len(v), /*syntax::ast::field*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_75(s, e) }) - }) - }); -} -/*core::option::t<@syntax::ast::expr>*/ -fn serialize_77<S: std::serialization::serializer>(s: S, - v: - core::option::t<@syntax::ast::expr>) { - s.emit_enum("core::option::t", - - /*@syntax::ast::expr*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }) - } - }) - } - } - }); -} -/*[core::option::t<@syntax::ast::expr>]*/ -fn serialize_78<S: std::serialization::serializer>(s: S, - v: - [core::option::t<@syntax::ast::expr>]) { - s.emit_vec(vec::len(v), /*core::option::t<@syntax::ast::expr>*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_77(s, e) }) - }) - }); -} -/*syntax::ast::binop*/ -fn serialize_79<S: std::serialization::serializer>(s: S, - v: syntax::ast::binop) { - - s.emit_enum("syntax::ast::binop", - - - - - - - - - - - - - - - - - - - {|| - alt v { - syntax::ast::add { - s.emit_enum_variant("syntax::ast::add", 0u, 0u, {|| }) - } - syntax::ast::subtract { - s.emit_enum_variant("syntax::ast::subtract", 1u, 0u, - {|| }) - } - syntax::ast::mul { - s.emit_enum_variant("syntax::ast::mul", 2u, 0u, {|| }) - } - syntax::ast::div { - s.emit_enum_variant("syntax::ast::div", 3u, 0u, {|| }) - } - syntax::ast::rem { - s.emit_enum_variant("syntax::ast::rem", 4u, 0u, {|| }) - } - syntax::ast::and { - s.emit_enum_variant("syntax::ast::and", 5u, 0u, {|| }) - } - syntax::ast::or { - s.emit_enum_variant("syntax::ast::or", 6u, 0u, {|| }) - } - syntax::ast::bitxor { - s.emit_enum_variant("syntax::ast::bitxor", 7u, 0u, - {|| }) - } - syntax::ast::bitand { - s.emit_enum_variant("syntax::ast::bitand", 8u, 0u, - {|| }) - } - syntax::ast::bitor { - s.emit_enum_variant("syntax::ast::bitor", 9u, 0u, - {|| }) - } - syntax::ast::lsl { - s.emit_enum_variant("syntax::ast::lsl", 10u, 0u, - {|| }) - } - syntax::ast::lsr { - s.emit_enum_variant("syntax::ast::lsr", 11u, 0u, - {|| }) - } - syntax::ast::asr { - s.emit_enum_variant("syntax::ast::asr", 12u, 0u, - {|| }) - } - syntax::ast::eq { - s.emit_enum_variant("syntax::ast::eq", 13u, 0u, {|| }) - } - syntax::ast::lt { - s.emit_enum_variant("syntax::ast::lt", 14u, 0u, {|| }) - } - syntax::ast::le { - s.emit_enum_variant("syntax::ast::le", 15u, 0u, {|| }) - } - syntax::ast::ne { - s.emit_enum_variant("syntax::ast::ne", 16u, 0u, {|| }) - } - syntax::ast::ge { - s.emit_enum_variant("syntax::ast::ge", 17u, 0u, {|| }) - } - syntax::ast::gt { - s.emit_enum_variant("syntax::ast::gt", 18u, 0u, {|| }) - } - } - }); -} -/*syntax::ast::unop*/ -fn serialize_80<S: std::serialization::serializer>(s: S, - v: syntax::ast::unop) { - - s.emit_enum("syntax::ast::unop", - /*syntax::ast::mutability*/ - /*syntax::ast::mutability*/ - - - {|| - alt v { - syntax::ast::box(v0) { - s.emit_enum_variant("syntax::ast::box", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_33(s, - v0) - }) - } - }) - } - syntax::ast::uniq(v0) { - s.emit_enum_variant("syntax::ast::uniq", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_33(s, - v0) - }) - } - }) - } - syntax::ast::deref { - s.emit_enum_variant("syntax::ast::deref", 2u, 0u, - {|| }) - } - syntax::ast::not { - s.emit_enum_variant("syntax::ast::not", 3u, 0u, {|| }) - } - syntax::ast::neg { - s.emit_enum_variant("syntax::ast::neg", 4u, 0u, {|| }) - } - } - }); -} -/*syntax::ast::simple_path*/ -fn serialize_92<S: std::serialization::serializer>(s: S, - v: - syntax::ast::simple_path) { - s.emit_vec(vec::len(v), /*syntax::ast::ident*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_1(s, e) }) - }) - }); -} -/*@syntax::ast::simple_path*/ -fn serialize_91<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::simple_path) { - s.emit_box(/*syntax::ast::simple_path*/{|| serialize_92(s, *v) }); -} -/*syntax::ast::path_list_ident_*/ -fn serialize_95<S: std::serialization::serializer>(s: S, - v: - syntax::ast::path_list_ident_) { - s.emit_rec(/*syntax::ast::ident*//*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("name", 0u, - {|| serialize_1(s, v.name) }); - s.emit_rec_field("id", 1u, {|| serialize_27(s, v.id) }) - } - }); -} -/*syntax::ast::path_list_ident*/ -fn serialize_94<S: std::serialization::serializer>(s: S, - v: - syntax::ast::path_list_ident) { - s.emit_rec(/*syntax::ast::path_list_ident_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_95(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*[syntax::ast::path_list_ident]*/ -fn serialize_93<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::path_list_ident]) { - s.emit_vec(vec::len(v), /*syntax::ast::path_list_ident*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_94(s, e) }) - }) - }); -} -/*syntax::ast::view_path_*/ -fn serialize_90<S: std::serialization::serializer>(s: S, - v: - syntax::ast::view_path_) { - s.emit_enum("syntax::ast::view_path_", - /*syntax::ast::ident*//*@syntax::ast::simple_path*/ - /*syntax::ast::node_id*/ - /*@syntax::ast::simple_path*//*syntax::ast::node_id*/ - /*@syntax::ast::simple_path*/ - /*[syntax::ast::path_list_ident]*//*syntax::ast::node_id*/ - {|| - alt v { - syntax::ast::view_path_simple(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::view_path_simple", - 0u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_1(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_91(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_27(s, - v2) - }) - } - }) - } - syntax::ast::view_path_glob(v0, v1) { - s.emit_enum_variant("syntax::ast::view_path_glob", 1u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_91(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_27(s, - v1) - }) - } - }) - } - syntax::ast::view_path_list(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::view_path_list", 2u, - 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_91(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_93(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_27(s, - v2) - }) - } - }) - } - } - }); -} -/*syntax::ast::view_path*/ -fn serialize_89<S: std::serialization::serializer>(s: S, - v: - syntax::ast::view_path) { - s.emit_rec(/*syntax::ast::view_path_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_90(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::view_path*/ -fn serialize_88<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::view_path) { - s.emit_box(/*syntax::ast::view_path*/{|| serialize_89(s, *v) }); -} -/*[@syntax::ast::view_path]*/ -fn serialize_87<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::view_path]) { - s.emit_vec(vec::len(v), /*@syntax::ast::view_path*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_88(s, e) }) - }) - }); -} -/*syntax::ast::view_item_*/ -fn serialize_86<S: std::serialization::serializer>(s: S, - v: - syntax::ast::view_item_) { - s.emit_enum("syntax::ast::view_item_", - /*syntax::ast::ident*//*[@syntax::ast::meta_item]*/ - /*syntax::ast::node_id*/ - /*[@syntax::ast::view_path]*/ - /*[@syntax::ast::view_path]*/ - {|| - alt v { - syntax::ast::view_item_use(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::view_item_use", 0u, - 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_1(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_8(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_27(s, - v2) - }) - } - }) - } - syntax::ast::view_item_import(v0) { - s.emit_enum_variant("syntax::ast::view_item_import", - 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_87(s, - v0) - }) - } - }) - } - syntax::ast::view_item_export(v0) { - s.emit_enum_variant("syntax::ast::view_item_export", - 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_87(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::view_item*/ -fn serialize_85<S: std::serialization::serializer>(s: S, - v: - syntax::ast::view_item) { - s.emit_rec(/*syntax::ast::view_item_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_86(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::view_item*/ -fn serialize_84<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::view_item) { - s.emit_box(/*syntax::ast::view_item*/{|| serialize_85(s, *v) }); -} -/*[@syntax::ast::view_item]*/ -fn serialize_83<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::view_item]) { - s.emit_vec(vec::len(v), /*@syntax::ast::view_item*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_84(s, e) }) - }) - }); -} -/*core::option::t<@syntax::ast::pat>*/ -fn serialize_110<S: std::serialization::serializer>(s: S, - v: - core::option::t<@syntax::ast::pat>) { - s.emit_enum("core::option::t", - - /*@syntax::ast::pat*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_107(s, - v0) - }) - } - }) - } - } - }); -} -/*[@syntax::ast::pat]*/ -fn serialize_111<S: std::serialization::serializer>(s: S, - v: [@syntax::ast::pat]) { - - s.emit_vec(vec::len(v), /*@syntax::ast::pat*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_107(s, e) }) - }) - }); -} -/*syntax::ast::field_pat*/ -fn serialize_113<S: std::serialization::serializer>(s: S, - v: - syntax::ast::field_pat) { - s.emit_rec(/*syntax::ast::ident*//*@syntax::ast::pat*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("pat", 1u, - {|| serialize_107(s, v.pat) }) - } - }); -} -/*[syntax::ast::field_pat]*/ -fn serialize_112<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::field_pat]) { - s.emit_vec(vec::len(v), /*syntax::ast::field_pat*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_113(s, e) }) - }) - }); -} -/*syntax::ast::pat_*/ -fn serialize_109<S: std::serialization::serializer>(s: S, - v: syntax::ast::pat_) { - - s.emit_enum("syntax::ast::pat_", - - /*@syntax::ast::path*//*core::option::t<@syntax::ast::pat>*/ - /*@syntax::ast::path*//*[@syntax::ast::pat]*/ - /*[syntax::ast::field_pat]*//*bool*/ - /*[@syntax::ast::pat]*/ - /*@syntax::ast::pat*/ - /*@syntax::ast::pat*/ - /*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - {|| - alt v { - syntax::ast::pat_wild { - s.emit_enum_variant("syntax::ast::pat_wild", 0u, 0u, - {|| }) - } - syntax::ast::pat_ident(v0, v1) { - s.emit_enum_variant("syntax::ast::pat_ident", 1u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_49(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_110(s, - v1) - }) - } - }) - } - syntax::ast::pat_enum(v0, v1) { - s.emit_enum_variant("syntax::ast::pat_enum", 2u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_49(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_111(s, - v1) - }) - } - }) - } - syntax::ast::pat_rec(v0, v1) { - s.emit_enum_variant("syntax::ast::pat_rec", 3u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_112(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_18(s, - v1) - }) - } - }) - } - syntax::ast::pat_tup(v0) { - s.emit_enum_variant("syntax::ast::pat_tup", 4u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_111(s, - v0) - }) - } - }) - } - syntax::ast::pat_box(v0) { - s.emit_enum_variant("syntax::ast::pat_box", 5u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_107(s, - v0) - }) - } - }) - } - syntax::ast::pat_uniq(v0) { - s.emit_enum_variant("syntax::ast::pat_uniq", 6u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_107(s, - v0) - }) - } - }) - } - syntax::ast::pat_lit(v0) { - s.emit_enum_variant("syntax::ast::pat_lit", 7u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }) - } - }) - } - syntax::ast::pat_range(v0, v1) { - s.emit_enum_variant("syntax::ast::pat_range", 8u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - } - }); -} -/*syntax::ast::pat*/ -fn serialize_108<S: std::serialization::serializer>(s: S, - v: syntax::ast::pat) { - - s.emit_rec(/*syntax::ast::node_id*//*syntax::ast::pat_*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("id", 0u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("node", 1u, - {|| serialize_109(s, v.node) }); - s.emit_rec_field("span", 2u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::pat*/ -fn serialize_107<S: std::serialization::serializer>(s: S, - v: @syntax::ast::pat) { - - s.emit_box(/*syntax::ast::pat*/{|| serialize_108(s, *v) }); -} -/*syntax::ast::init_op*/ -fn serialize_116<S: std::serialization::serializer>(s: S, - v: syntax::ast::init_op) { - - s.emit_enum("syntax::ast::init_op", - - {|| - alt v { - syntax::ast::init_assign { - s.emit_enum_variant("syntax::ast::init_assign", 0u, - 0u, {|| }) - } - syntax::ast::init_move { - s.emit_enum_variant("syntax::ast::init_move", 1u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::initializer*/ -fn serialize_115<S: std::serialization::serializer>(s: S, - v: - syntax::ast::initializer) { - s.emit_rec(/*syntax::ast::init_op*//*@syntax::ast::expr*/ - {|| - { - s.emit_rec_field("op", 0u, - {|| serialize_116(s, v.op) }); - s.emit_rec_field("expr", 1u, - {|| serialize_70(s, v.expr) }) - } - }); -} -/*core::option::t<syntax::ast::initializer>*/ -fn serialize_114<S: std::serialization::serializer>(s: S, - v: - core::option::t<syntax::ast::initializer>) { - s.emit_enum("core::option::t", - - /*syntax::ast::initializer*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_115(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::local_*/ -fn serialize_106<S: std::serialization::serializer>(s: S, - v: syntax::ast::local_) { - - s.emit_rec(/*bool*//*@syntax::ast::ty*//*@syntax::ast::pat*/ - /*core::option::t<syntax::ast::initializer>*/ - /*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("is_mutbl", 0u, - {|| serialize_18(s, v.is_mutbl) }); - s.emit_rec_field("ty", 1u, - {|| serialize_29(s, v.ty) }); - s.emit_rec_field("pat", 2u, - {|| serialize_107(s, v.pat) }); - s.emit_rec_field("init", 3u, - {|| serialize_114(s, v.init) }); - s.emit_rec_field("id", 4u, {|| serialize_27(s, v.id) }) - } - }); -} -/*syntax::ast::local*/ -fn serialize_105<S: std::serialization::serializer>(s: S, - v: syntax::ast::local) { - - s.emit_rec(/*syntax::ast::local_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_106(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::local*/ -fn serialize_104<S: std::serialization::serializer>(s: S, - v: @syntax::ast::local) { - - s.emit_box(/*syntax::ast::local*/{|| serialize_105(s, *v) }); -} -/*[@syntax::ast::local]*/ -fn serialize_103<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::local]) { - s.emit_vec(vec::len(v), /*@syntax::ast::local*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_104(s, e) }) - }) - }); -} -/*@syntax::ast::item*/ -fn serialize_117<S: std::serialization::serializer>(s: S, - v: @syntax::ast::item) { - - s.emit_box(/*syntax::ast::item*/{|| serialize_0(s, *v) }); -} -/*syntax::ast::decl_*/ -fn serialize_102<S: std::serialization::serializer>(s: S, - v: syntax::ast::decl_) { - - s.emit_enum("syntax::ast::decl_", - /*[@syntax::ast::local]*/ - /*@syntax::ast::item*/ - {|| - alt v { - syntax::ast::decl_local(v0) { - s.emit_enum_variant("syntax::ast::decl_local", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_103(s, - v0) - }) - } - }) - } - syntax::ast::decl_item(v0) { - s.emit_enum_variant("syntax::ast::decl_item", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_117(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::decl*/ -fn serialize_101<S: std::serialization::serializer>(s: S, - v: syntax::ast::decl) { - - s.emit_rec(/*syntax::ast::decl_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_102(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::decl*/ -fn serialize_100<S: std::serialization::serializer>(s: S, - v: @syntax::ast::decl) { - - s.emit_box(/*syntax::ast::decl*/{|| serialize_101(s, *v) }); -} -/*syntax::ast::stmt_*/ -fn serialize_99<S: std::serialization::serializer>(s: S, - v: syntax::ast::stmt_) { - - s.emit_enum("syntax::ast::stmt_", - /*@syntax::ast::decl*//*syntax::ast::node_id*/ - /*@syntax::ast::expr*//*syntax::ast::node_id*/ - /*@syntax::ast::expr*//*syntax::ast::node_id*/ - {|| - alt v { - syntax::ast::stmt_decl(v0, v1) { - s.emit_enum_variant("syntax::ast::stmt_decl", 0u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_100(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_27(s, - v1) - }) - } - }) - } - syntax::ast::stmt_expr(v0, v1) { - s.emit_enum_variant("syntax::ast::stmt_expr", 1u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_27(s, - v1) - }) - } - }) - } - syntax::ast::stmt_semi(v0, v1) { - s.emit_enum_variant("syntax::ast::stmt_semi", 2u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_27(s, - v1) - }) - } - }) - } - } - }); -} -/*syntax::ast::stmt*/ -fn serialize_98<S: std::serialization::serializer>(s: S, - v: syntax::ast::stmt) { - - s.emit_rec(/*syntax::ast::stmt_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_99(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::stmt*/ -fn serialize_97<S: std::serialization::serializer>(s: S, - v: @syntax::ast::stmt) { - - s.emit_box(/*syntax::ast::stmt*/{|| serialize_98(s, *v) }); -} -/*[@syntax::ast::stmt]*/ -fn serialize_96<S: std::serialization::serializer>(s: S, - v: [@syntax::ast::stmt]) { - - s.emit_vec(vec::len(v), /*@syntax::ast::stmt*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_97(s, e) }) - }) - }); -} -/*syntax::ast::blk_check_mode*/ -fn serialize_118<S: std::serialization::serializer>(s: S, - v: - syntax::ast::blk_check_mode) { - s.emit_enum("syntax::ast::blk_check_mode", - - - {|| - alt v { - syntax::ast::default_blk { - s.emit_enum_variant("syntax::ast::default_blk", 0u, - 0u, {|| }) - } - syntax::ast::unchecked_blk { - s.emit_enum_variant("syntax::ast::unchecked_blk", 1u, - 0u, {|| }) - } - syntax::ast::unsafe_blk { - s.emit_enum_variant("syntax::ast::unsafe_blk", 2u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::blk_*/ -fn serialize_82<S: std::serialization::serializer>(s: S, - v: syntax::ast::blk_) { - - s.emit_rec(/*[@syntax::ast::view_item]*//*[@syntax::ast::stmt]*/ - /*core::option::t<@syntax::ast::expr>*//*syntax::ast::node_id*/ - /*syntax::ast::blk_check_mode*/ - {|| - { - s.emit_rec_field("view_items", 0u, - {|| serialize_83(s, v.view_items) }); - s.emit_rec_field("stmts", 1u, - {|| serialize_96(s, v.stmts) }); - s.emit_rec_field("expr", 2u, - {|| serialize_77(s, v.expr) }); - s.emit_rec_field("id", 3u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("rules", 4u, - {|| serialize_118(s, v.rules) }) - } - }); -} -/*syntax::ast::blk*/ -fn serialize_81<S: std::serialization::serializer>(s: S, - v: syntax::ast::blk) { - - s.emit_rec(/*syntax::ast::blk_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_82(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*syntax::ast::arm*/ -fn serialize_120<S: std::serialization::serializer>(s: S, - v: syntax::ast::arm) { - - s.emit_rec(/*[@syntax::ast::pat]*//*core::option::t<@syntax::ast::expr>*/ - /*syntax::ast::blk*/ - {|| - { - s.emit_rec_field("pats", 0u, - {|| serialize_111(s, v.pats) }); - s.emit_rec_field("guard", 1u, - {|| serialize_77(s, v.guard) }); - s.emit_rec_field("body", 2u, - {|| serialize_81(s, v.body) }) - } - }); -} -/*[syntax::ast::arm]*/ -fn serialize_119<S: std::serialization::serializer>(s: S, - v: [syntax::ast::arm]) { - - s.emit_vec(vec::len(v), /*syntax::ast::arm*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_120(s, e) }) - }) - }); -} -/*syntax::ast::alt_mode*/ -fn serialize_121<S: std::serialization::serializer>(s: S, - v: - syntax::ast::alt_mode) { - s.emit_enum("syntax::ast::alt_mode", - - {|| - alt v { - syntax::ast::alt_check { - s.emit_enum_variant("syntax::ast::alt_check", 0u, 0u, - {|| }) - } - syntax::ast::alt_exhaustive { - s.emit_enum_variant("syntax::ast::alt_exhaustive", 1u, - 0u, {|| }) - } - } - }); -} -/*int*/ -fn serialize_127<S: std::serialization::serializer>(s: S, v: int) { - - s.emit_int(v); -} -/*syntax::ast::capture_item*/ -fn serialize_126<S: std::serialization::serializer>(s: S, - v: - syntax::ast::capture_item) { - s.emit_rec(/*int*//*syntax::ast::ident*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("id", 0u, - {|| serialize_127(s, v.id) }); - s.emit_rec_field("name", 1u, - {|| serialize_1(s, v.name) }); - s.emit_rec_field("span", 2u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::capture_item*/ -fn serialize_125<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::capture_item) { - s.emit_box(/*syntax::ast::capture_item*/{|| serialize_126(s, *v) }); -} -/*[@syntax::ast::capture_item]*/ -fn serialize_124<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::capture_item]) { - s.emit_vec(vec::len(v), /*@syntax::ast::capture_item*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_125(s, e) }) - }) - }); -} -/*syntax::ast::capture_clause*/ -fn serialize_123<S: std::serialization::serializer>(s: S, - v: - syntax::ast::capture_clause) { - s.emit_rec(/*[@syntax::ast::capture_item]*/ - /*[@syntax::ast::capture_item]*/ - {|| - { - s.emit_rec_field("copies", 0u, - {|| serialize_124(s, v.copies) }); - s.emit_rec_field("moves", 1u, - {|| serialize_124(s, v.moves) }) - } - }); -} -/*@syntax::ast::capture_clause*/ -fn serialize_122<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::capture_clause) { - s.emit_box(/*syntax::ast::capture_clause*/{|| serialize_123(s, *v) }); -} -/*syntax::ast::expr_check_mode*/ -fn serialize_128<S: std::serialization::serializer>(s: S, - v: - syntax::ast::expr_check_mode) { - s.emit_enum("syntax::ast::expr_check_mode", - - {|| - alt v { - syntax::ast::claimed_expr { - s.emit_enum_variant("syntax::ast::claimed_expr", 0u, - 0u, {|| }) - } - syntax::ast::checked_expr { - s.emit_enum_variant("syntax::ast::checked_expr", 1u, - 0u, {|| }) - } - } - }); -} -/*syntax::ast::expr_*/ -fn serialize_72<S: std::serialization::serializer>(s: S, - v: syntax::ast::expr_) { - - s.emit_enum("syntax::ast::expr_", - /*[@syntax::ast::expr]*//*syntax::ast::mutability*/ - /*[syntax::ast::field]*/ - /*core::option::t<@syntax::ast::expr>*/ - /*@syntax::ast::expr*//*[@syntax::ast::expr]*//*bool*/ - /*[@syntax::ast::expr]*/ - /*@syntax::ast::expr*/ - /*[core::option::t<@syntax::ast::expr>]*/ - /*syntax::ast::binop*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*/ - /*syntax::ast::unop*//*@syntax::ast::expr*/ - /*@syntax::ast::lit*/ - /*@syntax::ast::expr*//*@syntax::ast::ty*/ - /*@syntax::ast::expr*//*syntax::ast::blk*/ - /*core::option::t<@syntax::ast::expr>*/ - /*@syntax::ast::expr*//*syntax::ast::blk*/ - /*@syntax::ast::local*//*@syntax::ast::expr*/ - /*syntax::ast::blk*/ - /*syntax::ast::blk*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*[syntax::ast::arm]*/ - /*syntax::ast::alt_mode*/ - /*syntax::ast::proto*//*syntax::ast::fn_decl*/ - /*syntax::ast::blk*//*@syntax::ast::capture_clause*/ - /*syntax::ast::fn_decl*//*syntax::ast::blk*/ - /*syntax::ast::blk*/ - /*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - /*syntax::ast::binop*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*syntax::ast::ident*/ - /*[@syntax::ast::ty]*/ - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - /*@syntax::ast::path*/ - /*core::option::t<@syntax::ast::expr>*/ - - - /*core::option::t<@syntax::ast::expr>*/ - /*@syntax::ast::expr*/ - /*int*//*@syntax::ast::expr*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*/ - /*syntax::ast::expr_check_mode*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*//*syntax::ast::blk*/ - /*core::option::t<@syntax::ast::expr>*/ - /*syntax::ast::mac*/ - {|| - alt v { - syntax::ast::expr_vec(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_vec", 0u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_73(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_33(s, - v1) - }) - } - }) - } - syntax::ast::expr_rec(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_rec", 1u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_74(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_77(s, - v1) - }) - } - }) - } - syntax::ast::expr_call(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_call", 2u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_73(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_18(s, - v2) - }) - } - }) - } - syntax::ast::expr_tup(v0) { - s.emit_enum_variant("syntax::ast::expr_tup", 3u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_73(s, - v0) - }) - } - }) - } - syntax::ast::expr_bind(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_bind", 4u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_78(s, - v1) - }) - } - }) - } - syntax::ast::expr_binary(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_binary", 5u, - 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_79(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_70(s, - v2) - }) - } - }) - } - syntax::ast::expr_unary(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_unary", 6u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_80(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_lit(v0) { - s.emit_enum_variant("syntax::ast::expr_lit", 7u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_58(s, - v0) - }) - } - }) - } - syntax::ast::expr_cast(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_cast", 8u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_29(s, - v1) - }) - } - }) - } - syntax::ast::expr_if(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_if", 9u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_81(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_77(s, - v2) - }) - } - }) - } - syntax::ast::expr_while(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_while", 10u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_81(s, - v1) - }) - } - }) - } - syntax::ast::expr_for(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_for", 11u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_104(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_81(s, - v2) - }) - } - }) - } - syntax::ast::expr_do_while(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_do_while", 12u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_81(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_alt(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_alt", 13u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_119(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_121(s, - v2) - }) - } - }) - } - syntax::ast::expr_fn(v0, v1, v2, v3) { - s.emit_enum_variant("syntax::ast::expr_fn", 14u, 4u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_37(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_38(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_81(s, - v2) - }); - s.emit_enum_variant_arg(3u, - {|| - serialize_122(s, - v3) - }) - } - }) - } - syntax::ast::expr_fn_block(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_fn_block", 15u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_38(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_81(s, - v1) - }) - } - }) - } - syntax::ast::expr_block(v0) { - s.emit_enum_variant("syntax::ast::expr_block", 16u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_81(s, - v0) - }) - } - }) - } - syntax::ast::expr_copy(v0) { - s.emit_enum_variant("syntax::ast::expr_copy", 17u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }) - } - }) - } - syntax::ast::expr_move(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_move", 18u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_assign(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_assign", 19u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_swap(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_swap", 20u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_assign_op(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_assign_op", - 21u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_79(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_70(s, - v2) - }) - } - }) - } - syntax::ast::expr_field(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_field", 22u, - 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_1(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_53(s, - v2) - }) - } - }) - } - syntax::ast::expr_index(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_index", 23u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_path(v0) { - s.emit_enum_variant("syntax::ast::expr_path", 24u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_49(s, - v0) - }) - } - }) - } - syntax::ast::expr_fail(v0) { - s.emit_enum_variant("syntax::ast::expr_fail", 25u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_77(s, - v0) - }) - } - }) - } - syntax::ast::expr_break { - s.emit_enum_variant("syntax::ast::expr_break", 26u, - 0u, {|| }) - } - syntax::ast::expr_cont { - s.emit_enum_variant("syntax::ast::expr_cont", 27u, 0u, - {|| }) - } - syntax::ast::expr_ret(v0) { - s.emit_enum_variant("syntax::ast::expr_ret", 28u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_77(s, - v0) - }) - } - }) - } - syntax::ast::expr_be(v0) { - s.emit_enum_variant("syntax::ast::expr_be", 29u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }) - } - }) - } - syntax::ast::expr_log(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_log", 30u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_127(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_70(s, - v2) - }) - } - }) - } - syntax::ast::expr_assert(v0) { - s.emit_enum_variant("syntax::ast::expr_assert", 31u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }) - } - }) - } - syntax::ast::expr_check(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_check", 32u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_128(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::expr_if_check(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_if_check", 33u, - 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_81(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_77(s, - v2) - }) - } - }) - } - syntax::ast::expr_mac(v0) { - s.emit_enum_variant("syntax::ast::expr_mac", 34u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_67(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::expr*/ -fn serialize_71<S: std::serialization::serializer>(s: S, - v: syntax::ast::expr) { - - s.emit_rec(/*syntax::ast::node_id*//*syntax::ast::expr_*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("id", 0u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("node", 1u, - {|| serialize_72(s, v.node) }); - s.emit_rec_field("span", 2u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::expr*/ -fn serialize_70<S: std::serialization::serializer>(s: S, - v: @syntax::ast::expr) { - - s.emit_box(/*syntax::ast::expr*/{|| serialize_71(s, *v) }); -} -/*syntax::ast::mac_arg<@syntax::ast::expr>*/ -fn serialize_69<S: std::serialization::serializer>(s: S, - v: - syntax::ast::mac_arg<@syntax::ast::expr>) { - s.emit_enum("core::option::t", - - /*@syntax::ast::expr*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_70(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::mac_body_*/ -fn serialize_130<S: std::serialization::serializer>(s: S, - v: - syntax::ast::mac_body_) { - s.emit_rec(/*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("span", 0u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*syntax::ast::mac_body<syntax::ast::mac_body_>*/ -fn serialize_129<S: std::serialization::serializer>(s: S, - v: - syntax::ast::mac_body<syntax::ast::mac_body_>) { - s.emit_enum("core::option::t", - - /*syntax::ast::mac_body_*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_130(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::mac_*/ -fn serialize_68<S: std::serialization::serializer>(s: S, - v: syntax::ast::mac_) { - - s.emit_enum("syntax::ast::mac_", - /*@syntax::ast::path*/ - /*syntax::ast::mac_arg<@syntax::ast::expr>*/ - /*syntax::ast::mac_body<syntax::ast::mac_body_>*/ - /*@syntax::ast::ty*/ - /*syntax::ast::blk*/ - - /*syntax::codemap::span*//*@syntax::ast::expr*/ - /*uint*/ - {|| - alt v { - syntax::ast::mac_invoc(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::mac_invoc", 0u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_49(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_69(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_129(s, - v2) - }) - } - }) - } - syntax::ast::mac_embed_type(v0) { - s.emit_enum_variant("syntax::ast::mac_embed_type", 1u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_29(s, - v0) - }) - } - }) - } - syntax::ast::mac_embed_block(v0) { - s.emit_enum_variant("syntax::ast::mac_embed_block", - 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_81(s, - v0) - }) - } - }) - } - syntax::ast::mac_ellipsis { - s.emit_enum_variant("syntax::ast::mac_ellipsis", 3u, - 0u, {|| }) - } - syntax::ast::mac_aq(v0, v1) { - s.emit_enum_variant("syntax::ast::mac_aq", 4u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_19(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::mac_var(v0) { - s.emit_enum_variant("syntax::ast::mac_var", 5u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_20(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::mac*/ -fn serialize_67<S: std::serialization::serializer>(s: S, - v: syntax::ast::mac) { - - s.emit_rec(/*syntax::ast::mac_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_68(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*syntax::ast::ty_*/ -fn serialize_31<S: std::serialization::serializer>(s: S, - v: syntax::ast::ty_) { - - s.emit_enum("syntax::ast::ty_", - - - /*syntax::ast::mt*/ - /*syntax::ast::mt*/ - /*syntax::ast::mt*/ - /*syntax::ast::mt*/ - /*[syntax::ast::ty_field]*/ - /*syntax::ast::proto*//*syntax::ast::fn_decl*/ - /*[@syntax::ast::ty]*/ - /*@syntax::ast::path*//*syntax::ast::node_id*/ - /*@syntax::ast::ty*//*[@syntax::ast::ty_constr]*/ - /*syntax::ast::mac*/ - {|| - alt v { - syntax::ast::ty_nil { - s.emit_enum_variant("syntax::ast::ty_nil", 0u, 0u, - {|| }) - } - syntax::ast::ty_bot { - s.emit_enum_variant("syntax::ast::ty_bot", 1u, 0u, - {|| }) - } - syntax::ast::ty_box(v0) { - s.emit_enum_variant("syntax::ast::ty_box", 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_32(s, - v0) - }) - } - }) - } - syntax::ast::ty_uniq(v0) { - s.emit_enum_variant("syntax::ast::ty_uniq", 3u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_32(s, - v0) - }) - } - }) - } - syntax::ast::ty_vec(v0) { - s.emit_enum_variant("syntax::ast::ty_vec", 4u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_32(s, - v0) - }) - } - }) - } - syntax::ast::ty_ptr(v0) { - s.emit_enum_variant("syntax::ast::ty_ptr", 5u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_32(s, - v0) - }) - } - }) - } - syntax::ast::ty_rec(v0) { - s.emit_enum_variant("syntax::ast::ty_rec", 6u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_34(s, - v0) - }) - } - }) - } - syntax::ast::ty_fn(v0, v1) { - s.emit_enum_variant("syntax::ast::ty_fn", 7u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_37(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_38(s, - v1) - }) - } - }) - } - syntax::ast::ty_tup(v0) { - s.emit_enum_variant("syntax::ast::ty_tup", 8u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_53(s, - v0) - }) - } - }) - } - syntax::ast::ty_path(v0, v1) { - s.emit_enum_variant("syntax::ast::ty_path", 9u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_49(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_27(s, - v1) - }) - } - }) - } - syntax::ast::ty_constr(v0, v1) { - s.emit_enum_variant("syntax::ast::ty_constr", 10u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_29(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_59(s, - v1) - }) - } - }) - } - syntax::ast::ty_mac(v0) { - s.emit_enum_variant("syntax::ast::ty_mac", 11u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_67(s, - v0) - }) - } - }) - } - syntax::ast::ty_infer { - s.emit_enum_variant("syntax::ast::ty_infer", 12u, 0u, - {|| }) - } - } - }); -} -/*syntax::ast::ty*/ -fn serialize_30<S: std::serialization::serializer>(s: S, v: syntax::ast::ty) { - - s.emit_rec(/*syntax::ast::ty_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_31(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::ty*/ -fn serialize_29<S: std::serialization::serializer>(s: S, - v: @syntax::ast::ty) { - - s.emit_box(/*syntax::ast::ty*/{|| serialize_30(s, *v) }); -} -/*syntax::ast::ty_param_bound*/ -fn serialize_135<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ty_param_bound) { - s.emit_enum("syntax::ast::ty_param_bound", - - - /*@syntax::ast::ty*/ - {|| - alt v { - syntax::ast::bound_copy { - s.emit_enum_variant("syntax::ast::bound_copy", 0u, 0u, - {|| }) - } - syntax::ast::bound_send { - s.emit_enum_variant("syntax::ast::bound_send", 1u, 0u, - {|| }) - } - syntax::ast::bound_iface(v0) { - s.emit_enum_variant("syntax::ast::bound_iface", 2u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_29(s, - v0) - }) - } - }) - } - } - }); -} -/*[syntax::ast::ty_param_bound]*/ -fn serialize_134<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::ty_param_bound]) { - s.emit_vec(vec::len(v), /*syntax::ast::ty_param_bound*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_135(s, e) }) - }) - }); -} -/*@[syntax::ast::ty_param_bound]*/ -fn serialize_133<S: std::serialization::serializer>(s: S, - v: - @[syntax::ast::ty_param_bound]) { - s.emit_box(/*[syntax::ast::ty_param_bound]*/{|| serialize_134(s, *v) }); -} -/*syntax::ast::ty_param*/ -fn serialize_132<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ty_param) { - s.emit_rec(/*syntax::ast::ident*//*syntax::ast::node_id*/ - /*@[syntax::ast::ty_param_bound]*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("id", 1u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("bounds", 2u, - {|| serialize_133(s, v.bounds) }) - } - }); -} -/*[syntax::ast::ty_param]*/ -fn serialize_131<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::ty_param]) { - s.emit_vec(vec::len(v), /*syntax::ast::ty_param*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_132(s, e) }) - }) - }); -} -/*[@syntax::ast::item]*/ -fn serialize_137<S: std::serialization::serializer>(s: S, - v: [@syntax::ast::item]) { - - s.emit_vec(vec::len(v), /*@syntax::ast::item*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_117(s, e) }) - }) - }); -} -/*syntax::ast::_mod*/ -fn serialize_136<S: std::serialization::serializer>(s: S, - v: syntax::ast::_mod) { - - s.emit_rec(/*[@syntax::ast::view_item]*//*[@syntax::ast::item]*/ - {|| - { - s.emit_rec_field("view_items", 0u, - {|| serialize_83(s, v.view_items) }); - s.emit_rec_field("items", 1u, - {|| serialize_137(s, v.items) }) - } - }); -} -/*syntax::ast::native_item_*/ -fn serialize_142<S: std::serialization::serializer>(s: S, - v: - syntax::ast::native_item_) { - s.emit_enum("syntax::ast::native_item_", - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - {|| - alt v { - syntax::ast::native_item_fn(v0, v1) { - s.emit_enum_variant("syntax::ast::native_item_fn", 0u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_38(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_131(s, - v1) - }) - } - }) - } - } - }); -} -/*syntax::ast::native_item*/ -fn serialize_141<S: std::serialization::serializer>(s: S, - v: - syntax::ast::native_item) { - s.emit_rec(/*syntax::ast::ident*//*[syntax::ast::attribute]*/ - /*syntax::ast::native_item_*//*syntax::ast::node_id*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("attrs", 1u, - {|| serialize_2(s, v.attrs) }); - s.emit_rec_field("node", 2u, - {|| serialize_142(s, v.node) }); - s.emit_rec_field("id", 3u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("span", 4u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::native_item*/ -fn serialize_140<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::native_item) { - s.emit_box(/*syntax::ast::native_item*/{|| serialize_141(s, *v) }); -} -/*[@syntax::ast::native_item]*/ -fn serialize_139<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::native_item]) { - s.emit_vec(vec::len(v), /*@syntax::ast::native_item*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_140(s, e) }) - }) - }); -} -/*syntax::ast::native_mod*/ -fn serialize_138<S: std::serialization::serializer>(s: S, - v: - syntax::ast::native_mod) { - s.emit_rec(/*[@syntax::ast::view_item]*//*[@syntax::ast::native_item]*/ - {|| - { - s.emit_rec_field("view_items", 0u, - {|| serialize_83(s, v.view_items) }); - s.emit_rec_field("items", 1u, - {|| serialize_139(s, v.items) }) - } - }); -} -/*syntax::ast::variant_arg*/ -fn serialize_147<S: std::serialization::serializer>(s: S, - v: - syntax::ast::variant_arg) { - s.emit_rec(/*@syntax::ast::ty*//*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("ty", 0u, - {|| serialize_29(s, v.ty) }); - s.emit_rec_field("id", 1u, {|| serialize_27(s, v.id) }) - } - }); -} -/*[syntax::ast::variant_arg]*/ -fn serialize_146<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::variant_arg]) { - s.emit_vec(vec::len(v), /*syntax::ast::variant_arg*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_147(s, e) }) - }) - }); -} -/*syntax::ast::variant_*/ -fn serialize_145<S: std::serialization::serializer>(s: S, - v: - syntax::ast::variant_) { - s.emit_rec(/*syntax::ast::ident*//*[syntax::ast::attribute]*/ - /*[syntax::ast::variant_arg]*//*syntax::ast::node_id*/ - /*core::option::t<@syntax::ast::expr>*/ - {|| - { - s.emit_rec_field("name", 0u, - {|| serialize_1(s, v.name) }); - s.emit_rec_field("attrs", 1u, - {|| serialize_2(s, v.attrs) }); - s.emit_rec_field("args", 2u, - {|| serialize_146(s, v.args) }); - s.emit_rec_field("id", 3u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("disr_expr", 4u, - {|| serialize_77(s, v.disr_expr) }) - } - }); -} -/*syntax::ast::variant*/ -fn serialize_144<S: std::serialization::serializer>(s: S, - v: syntax::ast::variant) { - - s.emit_rec(/*syntax::ast::variant_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_145(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*[syntax::ast::variant]*/ -fn serialize_143<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::variant]) { - s.emit_vec(vec::len(v), /*syntax::ast::variant*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_144(s, e) }) - }) - }); -} -/*syntax::ast::privacy*/ -fn serialize_152<S: std::serialization::serializer>(s: S, - v: syntax::ast::privacy) { - - s.emit_enum("syntax::ast::privacy", - - {|| - alt v { - syntax::ast::priv { - s.emit_enum_variant("syntax::ast::priv", 0u, 0u, - {|| }) - } - syntax::ast::pub { - s.emit_enum_variant("syntax::ast::pub", 1u, 0u, {|| }) - } - } - }); -} -/*syntax::ast::class_mutability*/ -fn serialize_154<S: std::serialization::serializer>(s: S, - v: - syntax::ast::class_mutability) { - s.emit_enum("syntax::ast::class_mutability", - - {|| - alt v { - syntax::ast::class_mutable { - s.emit_enum_variant("syntax::ast::class_mutable", 0u, - 0u, {|| }) - } - syntax::ast::class_immutable { - s.emit_enum_variant("syntax::ast::class_immutable", - 1u, 0u, {|| }) - } - } - }); -} -/*syntax::ast::class_member*/ -fn serialize_153<S: std::serialization::serializer>(s: S, - v: - syntax::ast::class_member) { - s.emit_enum("syntax::ast::class_member", - /*syntax::ast::ident*//*@syntax::ast::ty*/ - /*syntax::ast::class_mutability*//*syntax::ast::node_id*/ - /*@syntax::ast::item*/ - {|| - alt v { - syntax::ast::instance_var(v0, v1, v2, v3) { - s.emit_enum_variant("syntax::ast::instance_var", 0u, - 4u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_1(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_29(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_154(s, - v2) - }); - s.emit_enum_variant_arg(3u, - {|| - serialize_27(s, - v3) - }) - } - }) - } - syntax::ast::class_method(v0) { - s.emit_enum_variant("syntax::ast::class_method", 1u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_117(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::class_item_*/ -fn serialize_151<S: std::serialization::serializer>(s: S, - v: - syntax::ast::class_item_) { - s.emit_rec(/*syntax::ast::privacy*//*syntax::ast::class_member*/ - {|| - { - s.emit_rec_field("privacy", 0u, - {|| serialize_152(s, v.privacy) }); - s.emit_rec_field("decl", 1u, - {|| serialize_153(s, v.decl) }) - } - }); -} -/*syntax::ast::class_item*/ -fn serialize_150<S: std::serialization::serializer>(s: S, - v: - syntax::ast::class_item) { - s.emit_rec(/*syntax::ast::class_item_*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("node", 0u, - {|| serialize_151(s, v.node) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::class_item*/ -fn serialize_149<S: std::serialization::serializer>(s: S, - v: - @syntax::ast::class_item) { - s.emit_box(/*syntax::ast::class_item*/{|| serialize_150(s, *v) }); -} -/*[@syntax::ast::class_item]*/ -fn serialize_148<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::class_item]) { - s.emit_vec(vec::len(v), /*@syntax::ast::class_item*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_149(s, e) }) - }) - }); -} -/*syntax::ast::ty_method*/ -fn serialize_156<S: std::serialization::serializer>(s: S, - v: - syntax::ast::ty_method) { - s.emit_rec(/*syntax::ast::ident*//*[syntax::ast::attribute]*/ - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("attrs", 1u, - {|| serialize_2(s, v.attrs) }); - s.emit_rec_field("decl", 2u, - {|| serialize_38(s, v.decl) }); - s.emit_rec_field("tps", 3u, - {|| serialize_131(s, v.tps) }); - s.emit_rec_field("span", 4u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*[syntax::ast::ty_method]*/ -fn serialize_155<S: std::serialization::serializer>(s: S, - v: - [syntax::ast::ty_method]) { - s.emit_vec(vec::len(v), /*syntax::ast::ty_method*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_156(s, e) }) - }) - }); -} -/*core::option::t<@syntax::ast::ty>*/ -fn serialize_157<S: std::serialization::serializer>(s: S, - v: - core::option::t<@syntax::ast::ty>) { - s.emit_enum("core::option::t", - - /*@syntax::ast::ty*/ - {|| - alt v { - core::option::none { - s.emit_enum_variant("core::option::none", 0u, 0u, - {|| }) - } - core::option::some(v0) { - s.emit_enum_variant("core::option::some", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_29(s, - v0) - }) - } - }) - } - } - }); -} -/*syntax::ast::method*/ -fn serialize_160<S: std::serialization::serializer>(s: S, - v: syntax::ast::method) { - - s.emit_rec(/*syntax::ast::ident*//*[syntax::ast::attribute]*/ - /*[syntax::ast::ty_param]*//*syntax::ast::fn_decl*/ - /*syntax::ast::blk*//*syntax::ast::node_id*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("attrs", 1u, - {|| serialize_2(s, v.attrs) }); - s.emit_rec_field("tps", 2u, - {|| serialize_131(s, v.tps) }); - s.emit_rec_field("decl", 3u, - {|| serialize_38(s, v.decl) }); - s.emit_rec_field("body", 4u, - {|| serialize_81(s, v.body) }); - s.emit_rec_field("id", 5u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("span", 6u, - {|| serialize_19(s, v.span) }) - } - }); -} -/*@syntax::ast::method*/ -fn serialize_159<S: std::serialization::serializer>(s: S, - v: @syntax::ast::method) { - - s.emit_box(/*syntax::ast::method*/{|| serialize_160(s, *v) }); -} -/*[@syntax::ast::method]*/ -fn serialize_158<S: std::serialization::serializer>(s: S, - v: - [@syntax::ast::method]) { - s.emit_vec(vec::len(v), /*@syntax::ast::method*/ - {|| - vec::iteri(v, - {|i, e| - s.emit_vec_elt(i, {|| serialize_159(s, e) }) - }) - }); -} -/*syntax::ast::item_*/ -fn serialize_28<S: std::serialization::serializer>(s: S, - v: syntax::ast::item_) { - - s.emit_enum("syntax::ast::item_", - /*@syntax::ast::ty*//*@syntax::ast::expr*/ - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - /*syntax::ast::blk*/ - /*syntax::ast::_mod*/ - /*syntax::ast::native_mod*/ - /*@syntax::ast::ty*//*[syntax::ast::ty_param]*/ - /*[syntax::ast::variant]*//*[syntax::ast::ty_param]*/ - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - /*syntax::ast::blk*//*syntax::ast::node_id*/ - /*syntax::ast::node_id*/ - /*[syntax::ast::ty_param]*//*[@syntax::ast::class_item]*/ - /*syntax::ast::node_id*//*syntax::ast::fn_decl*/ - /*syntax::ast::blk*/ - /*[syntax::ast::ty_param]*//*[syntax::ast::ty_method]*/ - /*[syntax::ast::ty_param]*/ - /*core::option::t<@syntax::ast::ty>*//*@syntax::ast::ty*/ - /*[@syntax::ast::method]*/ - {|| - alt v { - syntax::ast::item_const(v0, v1) { - s.emit_enum_variant("syntax::ast::item_const", 0u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_29(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_70(s, - v1) - }) - } - }) - } - syntax::ast::item_fn(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::item_fn", 1u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_38(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_131(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_81(s, - v2) - }) - } - }) - } - syntax::ast::item_mod(v0) { - s.emit_enum_variant("syntax::ast::item_mod", 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_136(s, - v0) - }) - } - }) - } - syntax::ast::item_native_mod(v0) { - s.emit_enum_variant("syntax::ast::item_native_mod", - 3u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_138(s, - v0) - }) - } - }) - } - syntax::ast::item_ty(v0, v1) { - s.emit_enum_variant("syntax::ast::item_ty", 4u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_29(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_131(s, - v1) - }) - } - }) - } - syntax::ast::item_enum(v0, v1) { - s.emit_enum_variant("syntax::ast::item_enum", 5u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_143(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_131(s, - v1) - }) - } - }) - } - syntax::ast::item_res(v0, v1, v2, v3, v4) { - s.emit_enum_variant("syntax::ast::item_res", 6u, 5u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_38(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_131(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_81(s, - v2) - }); - s.emit_enum_variant_arg(3u, - {|| - serialize_27(s, - v3) - }); - s.emit_enum_variant_arg(4u, - {|| - serialize_27(s, - v4) - }) - } - }) - } - syntax::ast::item_class(v0, v1, v2, v3, v4) { - s.emit_enum_variant("syntax::ast::item_class", 7u, 5u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_131(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_148(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_27(s, - v2) - }); - s.emit_enum_variant_arg(3u, - {|| - serialize_38(s, - v3) - }); - s.emit_enum_variant_arg(4u, - {|| - serialize_81(s, - v4) - }) - } - }) - } - syntax::ast::item_iface(v0, v1) { - s.emit_enum_variant("syntax::ast::item_iface", 8u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_131(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_155(s, - v1) - }) - } - }) - } - syntax::ast::item_impl(v0, v1, v2, v3) { - s.emit_enum_variant("syntax::ast::item_impl", 9u, 4u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_131(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_157(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_29(s, - v2) - }); - s.emit_enum_variant_arg(3u, - {|| - serialize_158(s, - v3) - }) - } - }) - } - } - }); -} -/*syntax::ast::item*/ -fn serialize_0<S: std::serialization::serializer>(s: S, - v: syntax::ast::item) { - - s.emit_rec(/*syntax::ast::ident*//*[syntax::ast::attribute]*/ - /*syntax::ast::node_id*//*syntax::ast::item_*/ - /*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("ident", 0u, - {|| serialize_1(s, v.ident) }); - s.emit_rec_field("attrs", 1u, - {|| serialize_2(s, v.attrs) }); - s.emit_rec_field("id", 2u, - {|| serialize_27(s, v.id) }); - s.emit_rec_field("node", 3u, - {|| serialize_28(s, v.node) }); - s.emit_rec_field("span", 4u, - {|| serialize_19(s, v.span) }) - } - }); -} -fn serialize_syntax_ast_item<S: std::serialization::serializer>(s: S, - v: - syntax::ast::item) { - serialize_0(s, v); -} -/*syntax::ast::ident*/ -fn deserialize_1<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ident { - s.read_str() -} -/*syntax::ast::attr_style*/ -fn deserialize_5<S: std::serialization::deserializer>(s: S) -> - syntax::ast::attr_style { - s.read_enum("syntax::ast::attr_style", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::attr_outer } - 1u { syntax::ast::attr_inner } - } - }) - }) -} -/*@syntax::ast::meta_item*/ -fn deserialize_9<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::meta_item { - - s.read_box(/*syntax::ast::meta_item*/{|| @deserialize_6(s) }) - -} -/*[@syntax::ast::meta_item]*/ -fn deserialize_8<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::meta_item] { - s.read_vec( - - /*@syntax::ast::meta_item*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_9(s) }) - }) - }) -} -/*str*/ -fn deserialize_12<S: std::serialization::deserializer>(s: S) -> str { - s.read_str() -} -/*i64*/ -fn deserialize_13<S: std::serialization::deserializer>(s: S) -> i64 { - s.read_i64() -} -/*syntax::ast::int_ty*/ -fn deserialize_14<S: std::serialization::deserializer>(s: S) -> - syntax::ast::int_ty { - s.read_enum("syntax::ast::int_ty", - - - - - - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::ty_i } - 1u { syntax::ast::ty_char } - 2u { syntax::ast::ty_i8 } - 3u { syntax::ast::ty_i16 } - 4u { syntax::ast::ty_i32 } - 5u { syntax::ast::ty_i64 } - } - }) - }) -} -/*u64*/ -fn deserialize_15<S: std::serialization::deserializer>(s: S) -> u64 { - s.read_u64() -} -/*syntax::ast::uint_ty*/ -fn deserialize_16<S: std::serialization::deserializer>(s: S) -> - syntax::ast::uint_ty { - s.read_enum("syntax::ast::uint_ty", - - - - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::ty_u } - 1u { syntax::ast::ty_u8 } - 2u { syntax::ast::ty_u16 } - 3u { syntax::ast::ty_u32 } - 4u { syntax::ast::ty_u64 } - } - }) - }) -} -/*syntax::ast::float_ty*/ -fn deserialize_17<S: std::serialization::deserializer>(s: S) -> - syntax::ast::float_ty { - s.read_enum("syntax::ast::float_ty", - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::ty_f } - 1u { syntax::ast::ty_f32 } - 2u { syntax::ast::ty_f64 } - } - }) - }) -} -/*bool*/ -fn deserialize_18<S: std::serialization::deserializer>(s: S) -> bool { - s.read_bool() -} -/*syntax::ast::lit_*/ -fn deserialize_11<S: std::serialization::deserializer>(s: S) -> - syntax::ast::lit_ { - s.read_enum("syntax::ast::lit_", - /*str*/ - - /*i64*//*syntax::ast::int_ty*/ - - /*u64*//*syntax::ast::uint_ty*/ - - /*str*//*syntax::ast::float_ty*/ - - - - /*bool*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::lit_str(s.read_enum_variant_arg(0u, - {|| - deserialize_12(s) - })) - } - 1u { - syntax::ast::lit_int(s.read_enum_variant_arg(0u, - {|| - deserialize_13(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_14(s) - })) - } - 2u { - syntax::ast::lit_uint(s.read_enum_variant_arg(0u, - {|| - deserialize_15(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_16(s) - })) - } - 3u { - syntax::ast::lit_float(s.read_enum_variant_arg(0u, - {|| - deserialize_12(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_17(s) - })) - } - 4u { syntax::ast::lit_nil } - 5u { - syntax::ast::lit_bool(s.read_enum_variant_arg(0u, - {|| - deserialize_18(s) - })) - } - } - }) - }) -} -/*uint*/ -fn deserialize_20<S: std::serialization::deserializer>(s: S) -> uint { - s.read_uint() -} -/*core::option::t<syntax::codemap::span>*/ -fn deserialize_26<S: std::serialization::deserializer>(s: S) -> - core::option::t<syntax::codemap::span> { - s.read_enum("core::option::t", - - - /*syntax::codemap::span*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_19(s) - })) - } - } - }) - }) -} -/*{name: str,span: core::option::t<syntax::codemap::span>}*/ -fn deserialize_25<S: std::serialization::deserializer>(s: S) -> - {name: str, span: core::option::t<syntax::codemap::span>,} { - - s.read_rec( - - - /*str*/ - - /*core::option::t<syntax::codemap::span>*/ - - {|| - {name: - s.read_rec_field("name", 0u, {|| deserialize_12(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_26(s) }),} - }) - -} -/*{call_site: syntax::codemap::span,callie: {name: str,span: core::option::t<syntax::codemap::span>}}*/ -fn deserialize_24<S: std::serialization::deserializer>(s: S) -> - {call_site: syntax::codemap::span, - callie: {name: str, span: core::option::t<syntax::codemap::span>,},} { - - s.read_rec( - - - /*syntax::codemap::span*/ - - /*{name: str,span: core::option::t<syntax::codemap::span>}*/ - - {|| - {call_site: - s.read_rec_field("call_site", 0u, - {|| deserialize_19(s) }), - callie: - s.read_rec_field("callie", 1u, - {|| deserialize_25(s) }),} - }) - -} -/*syntax::codemap::expn_info_*/ -fn deserialize_23<S: std::serialization::deserializer>(s: S) -> - syntax::codemap::expn_info_ { - s.read_enum("syntax::codemap::expn_info_", - - /*{call_site: syntax::codemap::span,callie: {name: str,span: core::option::t<syntax::codemap::span>}}*/ - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::codemap::expanded_from(s.read_enum_variant_arg(0u, - {|| - deserialize_24(s) - })) - } - } - }) - }) -} -/*@syntax::codemap::expn_info_*/ -fn deserialize_22<S: std::serialization::deserializer>(s: S) -> - @syntax::codemap::expn_info_ { - - s.read_box(/*syntax::codemap::expn_info_*/{|| @deserialize_23(s) }) - -} -/*syntax::codemap::expn_info<@syntax::codemap::expn_info_>*/ -fn deserialize_21<S: std::serialization::deserializer>(s: S) -> - syntax::codemap::expn_info<@syntax::codemap::expn_info_> { - s.read_enum("core::option::t", - - - /*@syntax::codemap::expn_info_*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_22(s) - })) - } - } - }) - }) -} -/*syntax::codemap::span*/ -fn deserialize_19<S: std::serialization::deserializer>(s: S) -> - syntax::codemap::span { - - s.read_rec( - - - /*uint*/ - - /*uint*/ - - /*syntax::codemap::expn_info<@syntax::codemap::expn_info_>*/ - - {|| - {lo: s.read_rec_field("lo", 0u, {|| deserialize_20(s) }), - hi: s.read_rec_field("hi", 1u, {|| deserialize_20(s) }), - expn_info: - s.read_rec_field("expn_info", 2u, - {|| deserialize_21(s) }),} - }) - -} -/*syntax::ast::lit*/ -fn deserialize_10<S: std::serialization::deserializer>(s: S) -> - syntax::ast::lit { - - s.read_rec( - - - /*syntax::ast::lit_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_11(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*syntax::ast::meta_item_*/ -fn deserialize_7<S: std::serialization::deserializer>(s: S) -> - syntax::ast::meta_item_ { - s.read_enum("syntax::ast::meta_item_", - /*syntax::ast::ident*/ - - /*syntax::ast::ident*//*[@syntax::ast::meta_item]*/ - - /*syntax::ast::ident*//*syntax::ast::lit*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::meta_word(s.read_enum_variant_arg(0u, - {|| - deserialize_1(s) - })) - } - 1u { - syntax::ast::meta_list(s.read_enum_variant_arg(0u, - {|| - deserialize_1(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_8(s) - })) - } - 2u { - syntax::ast::meta_name_value(s.read_enum_variant_arg(0u, - {|| - deserialize_1(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_10(s) - })) - } - } - }) - }) -} -/*syntax::ast::meta_item*/ -fn deserialize_6<S: std::serialization::deserializer>(s: S) -> - syntax::ast::meta_item { - - s.read_rec( - - - /*syntax::ast::meta_item_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_7(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*syntax::ast::attribute_*/ -fn deserialize_4<S: std::serialization::deserializer>(s: S) -> - syntax::ast::attribute_ { - - s.read_rec( - - - /*syntax::ast::attr_style*/ - - /*syntax::ast::meta_item*/ - - {|| - {style: - s.read_rec_field("style", 0u, {|| deserialize_5(s) }), - value: - s.read_rec_field("value", 1u, - {|| deserialize_6(s) }),} - }) - -} -/*syntax::ast::attribute*/ -fn deserialize_3<S: std::serialization::deserializer>(s: S) -> - syntax::ast::attribute { - - s.read_rec( - - - /*syntax::ast::attribute_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_4(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*[syntax::ast::attribute]*/ -fn deserialize_2<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::attribute] { - s.read_vec( - - /*syntax::ast::attribute*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_3(s) }) - }) - }) -} -/*syntax::ast::node_id*/ -fn deserialize_27<S: std::serialization::deserializer>(s: S) -> - syntax::ast::node_id { - s.read_int() -} -/*syntax::ast::mutability*/ -fn deserialize_33<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mutability { - s.read_enum("syntax::ast::mutability", - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::m_mutbl } - 1u { syntax::ast::m_imm } - 2u { syntax::ast::m_const } - } - }) - }) -} -/*syntax::ast::mt*/ -fn deserialize_32<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mt { - - s.read_rec( - - - /*@syntax::ast::ty*/ - - /*syntax::ast::mutability*/ - - {|| - {ty: s.read_rec_field("ty", 0u, {|| deserialize_29(s) }), - mutbl: - s.read_rec_field("mutbl", 1u, - {|| deserialize_33(s) }),} - }) - -} -/*syntax::ast::ty_field_*/ -fn deserialize_36<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_field_ { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*syntax::ast::mt*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - mt: s.read_rec_field("mt", 1u, {|| deserialize_32(s) }),} - }) -} -/*syntax::ast::ty_field*/ -fn deserialize_35<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_field { - - s.read_rec( - - - /*syntax::ast::ty_field_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_36(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*[syntax::ast::ty_field]*/ -fn deserialize_34<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::ty_field] { - s.read_vec( - - /*syntax::ast::ty_field*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_35(s) }) - }) - }) -} -/*syntax::ast::proto*/ -fn deserialize_37<S: std::serialization::deserializer>(s: S) -> - syntax::ast::proto { - s.read_enum("syntax::ast::proto", - - - - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::proto_bare } - 1u { syntax::ast::proto_any } - 2u { syntax::ast::proto_uniq } - 3u { syntax::ast::proto_box } - 4u { syntax::ast::proto_block } - } - }) - }) -} -/*syntax::ast::rmode*/ -fn deserialize_42<S: std::serialization::deserializer>(s: S) -> - syntax::ast::rmode { - s.read_enum("syntax::ast::rmode", - - - - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::by_ref } - 1u { syntax::ast::by_val } - 2u { syntax::ast::by_mutbl_ref } - 3u { syntax::ast::by_move } - 4u { syntax::ast::by_copy } - } - }) - }) -} -/*syntax::ast::mode<syntax::ast::rmode>*/ -fn deserialize_41<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mode<syntax::ast::rmode> { - s.read_enum("syntax::ast::inferable", - /*syntax::ast::rmode*/ - - /*syntax::ast::node_id*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::expl(s.read_enum_variant_arg(0u, - {|| - deserialize_42(s) - })) - } - 1u { - syntax::ast::infer(s.read_enum_variant_arg(0u, - {|| - deserialize_27(s) - })) - } - } - }) - }) -} -/*syntax::ast::arg*/ -fn deserialize_40<S: std::serialization::deserializer>(s: S) -> - syntax::ast::arg { - - s.read_rec( - - - /*syntax::ast::mode<syntax::ast::rmode>*/ - - /*@syntax::ast::ty*/ - - /*syntax::ast::ident*/ - - /*syntax::ast::node_id*/ - - {|| - {mode: - s.read_rec_field("mode", 0u, {|| deserialize_41(s) }), - ty: s.read_rec_field("ty", 1u, {|| deserialize_29(s) }), - ident: - s.read_rec_field("ident", 2u, {|| deserialize_1(s) }), - id: s.read_rec_field("id", 3u, {|| deserialize_27(s) }),} - }) -} -/*[syntax::ast::arg]*/ -fn deserialize_39<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::arg] { - s.read_vec( - - /*syntax::ast::arg*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_40(s) }) - }) - }) -} -/*syntax::ast::purity*/ -fn deserialize_43<S: std::serialization::deserializer>(s: S) -> - syntax::ast::purity { - s.read_enum("syntax::ast::purity", - - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::pure_fn } - 1u { syntax::ast::unsafe_fn } - 2u { syntax::ast::impure_fn } - 3u { syntax::ast::crust_fn } - } - }) - }) -} -/*syntax::ast::ret_style*/ -fn deserialize_44<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ret_style { - s.read_enum("syntax::ast::ret_style", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::noreturn } - 1u { syntax::ast::return_val } - } - }) - }) -} -/*[syntax::ast::ident]*/ -fn deserialize_52<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::ident] { - s.read_vec( - - /*syntax::ast::ident*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_1(s) }) - }) - }) -} -/*[@syntax::ast::ty]*/ -fn deserialize_53<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::ty] { - s.read_vec( - - /*@syntax::ast::ty*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_29(s) }) - }) - }) -} -/*syntax::ast::path_*/ -fn deserialize_51<S: std::serialization::deserializer>(s: S) -> - syntax::ast::path_ { - - s.read_rec( - - - /*bool*/ - - /*[syntax::ast::ident]*/ - - /*[@syntax::ast::ty]*/ - - {|| - {global: - s.read_rec_field("global", 0u, - {|| deserialize_18(s) }), - idents: - s.read_rec_field("idents", 1u, - {|| deserialize_52(s) }), - types: - s.read_rec_field("types", 2u, - {|| deserialize_53(s) }),} - }) - -} -/*syntax::ast::path*/ -fn deserialize_50<S: std::serialization::deserializer>(s: S) -> - syntax::ast::path { - - s.read_rec( - - - /*syntax::ast::path_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_51(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::path*/ -fn deserialize_49<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::path { - - s.read_box(/*syntax::ast::path*/{|| @deserialize_50(s) }) - -} -/*@syntax::ast::lit*/ -fn deserialize_58<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::lit { - - s.read_box(/*syntax::ast::lit*/{|| @deserialize_10(s) }) - -} -/*syntax::ast::constr_arg_general_<uint>*/ -fn deserialize_57<S: std::serialization::deserializer>(s: S) -> - syntax::ast::constr_arg_general_<uint> { - s.read_enum("syntax::ast::constr_arg_general_", - - - /*uint*/ - - /*@syntax::ast::lit*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::carg_base } - 1u { - syntax::ast::carg_ident(s.read_enum_variant_arg(0u, - {|| - deserialize_20(s) - })) - } - 2u { - syntax::ast::carg_lit(s.read_enum_variant_arg(0u, - {|| - deserialize_58(s) - })) - } - } - }) - }) -} -/*{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ -fn deserialize_56<S: std::serialization::deserializer>(s: S) -> - {node: syntax::ast::constr_arg_general_<uint>, - span: syntax::codemap::span,} { - - s.read_rec( - - - /*syntax::ast::constr_arg_general_<uint>*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_57(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ -fn deserialize_55<S: std::serialization::deserializer>(s: S) -> - @{node: syntax::ast::constr_arg_general_<uint>, - span: syntax::codemap::span,} { - - s.read_box( - /*{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ - {|| @deserialize_56(s) }) - -} -/*[@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}]*/ -fn deserialize_54<S: std::serialization::deserializer>(s: S) -> - [@{node: syntax::ast::constr_arg_general_<uint>, - span: syntax::codemap::span,}] { - s.read_vec( - - - /*@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}*/ - - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_55(s) }) - }) - }) -} -/*{path: @syntax::ast::path,args: [@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}],id: syntax::ast::node_id}*/ -fn deserialize_48<S: std::serialization::deserializer>(s: S) -> - {path: @syntax::ast::path, - args: - [@{node: syntax::ast::constr_arg_general_<uint>, - span: syntax::codemap::span,}], - id: syntax::ast::node_id,} { - - s.read_rec( - - - /*@syntax::ast::path*/ - - - /*[@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}]*/ - - - /*syntax::ast::node_id*/ - - {|| - {path: - s.read_rec_field("path", 0u, {|| deserialize_49(s) }), - args: - s.read_rec_field("args", 1u, {|| deserialize_54(s) }), - id: s.read_rec_field("id", 2u, {|| deserialize_27(s) }),} - }) -} -/*syntax::ast::constr*/ -fn deserialize_47<S: std::serialization::deserializer>(s: S) -> - syntax::ast::constr { - - s.read_rec( - - - - /*{path: @syntax::ast::path,args: [@{node: syntax::ast::constr_arg_general_<uint>,span: syntax::codemap::span}],id: syntax::ast::node_id}*/ - - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_48(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::constr*/ -fn deserialize_46<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::constr { - - s.read_box(/*syntax::ast::constr*/{|| @deserialize_47(s) }) - -} -/*[@syntax::ast::constr]*/ -fn deserialize_45<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::constr] { - s.read_vec( - - /*@syntax::ast::constr*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_46(s) }) - }) - }) -} -/*syntax::ast::fn_decl*/ -fn deserialize_38<S: std::serialization::deserializer>(s: S) -> - syntax::ast::fn_decl { - - s.read_rec( - - - /*[syntax::ast::arg]*/ - - /*@syntax::ast::ty*/ - - /*syntax::ast::purity*/ - - /*syntax::ast::ret_style*/ - - /*[@syntax::ast::constr]*/ - - {|| - {inputs: - s.read_rec_field("inputs", 0u, - {|| deserialize_39(s) }), - output: - s.read_rec_field("output", 1u, - {|| deserialize_29(s) }), - purity: - s.read_rec_field("purity", 2u, - {|| deserialize_43(s) }), - cf: s.read_rec_field("cf", 3u, {|| deserialize_44(s) }), - constraints: - s.read_rec_field("constraints", 4u, - {|| deserialize_45(s) }),} - }) - -} -/*syntax::ast::constr_arg_general_<@syntax::ast::path>*/ -fn deserialize_66<S: std::serialization::deserializer>(s: S) -> - syntax::ast::constr_arg_general_<@syntax::ast::path> { - s.read_enum("syntax::ast::constr_arg_general_", - - - /*@syntax::ast::path*/ - - /*@syntax::ast::lit*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::carg_base } - 1u { - syntax::ast::carg_ident(s.read_enum_variant_arg(0u, - {|| - deserialize_49(s) - })) - } - 2u { - syntax::ast::carg_lit(s.read_enum_variant_arg(0u, - {|| - deserialize_58(s) - })) - } - } - }) - }) -} -/*{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ -fn deserialize_65<S: std::serialization::deserializer>(s: S) -> - {node: syntax::ast::constr_arg_general_<@syntax::ast::path>, - span: syntax::codemap::span,} { - - s.read_rec( - - - /*syntax::ast::constr_arg_general_<@syntax::ast::path>*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_66(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ -fn deserialize_64<S: std::serialization::deserializer>(s: S) -> - @{node: syntax::ast::constr_arg_general_<@syntax::ast::path>, - span: syntax::codemap::span,} { - - s.read_box( - /*{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ - {|| @deserialize_65(s) }) - -} -/*[@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}]*/ -fn deserialize_63<S: std::serialization::deserializer>(s: S) -> - [@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>, - span: syntax::codemap::span,}] { - s.read_vec( - - - /*@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}*/ - - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_64(s) }) - }) - }) -} -/*syntax::ast::ty_constr_*/ -fn deserialize_62<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_constr_ { - - s.read_rec( - - - /*@syntax::ast::path*/ - - - /*[@{node: syntax::ast::constr_arg_general_<@syntax::ast::path>,span: syntax::codemap::span}]*/ - - - /*syntax::ast::node_id*/ - - {|| - {path: - s.read_rec_field("path", 0u, {|| deserialize_49(s) }), - args: - s.read_rec_field("args", 1u, {|| deserialize_63(s) }), - id: s.read_rec_field("id", 2u, {|| deserialize_27(s) }),} - }) -} -/*syntax::ast::ty_constr*/ -fn deserialize_61<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_constr { - - s.read_rec( - - - /*syntax::ast::ty_constr_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_62(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::ty_constr*/ -fn deserialize_60<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::ty_constr { - - s.read_box(/*syntax::ast::ty_constr*/{|| @deserialize_61(s) }) - -} -/*[@syntax::ast::ty_constr]*/ -fn deserialize_59<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::ty_constr] { - s.read_vec( - - /*@syntax::ast::ty_constr*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_60(s) }) - }) - }) -} -/*[@syntax::ast::expr]*/ -fn deserialize_73<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::expr] { - s.read_vec( - - /*@syntax::ast::expr*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_70(s) }) - }) - }) -} -/*syntax::ast::field_*/ -fn deserialize_76<S: std::serialization::deserializer>(s: S) -> - syntax::ast::field_ { - - s.read_rec( - - - /*syntax::ast::mutability*/ - - /*syntax::ast::ident*/ - - /*@syntax::ast::expr*/ - - {|| - {mutbl: - s.read_rec_field("mutbl", 0u, - {|| deserialize_33(s) }), - ident: - s.read_rec_field("ident", 1u, {|| deserialize_1(s) }), - expr: - s.read_rec_field("expr", 2u, - {|| deserialize_70(s) }),} - }) - -} -/*syntax::ast::field*/ -fn deserialize_75<S: std::serialization::deserializer>(s: S) -> - syntax::ast::field { - - s.read_rec( - - - /*syntax::ast::field_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_76(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*[syntax::ast::field]*/ -fn deserialize_74<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::field] { - s.read_vec( - - /*syntax::ast::field*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_75(s) }) - }) - }) -} -/*core::option::t<@syntax::ast::expr>*/ -fn deserialize_77<S: std::serialization::deserializer>(s: S) -> - core::option::t<@syntax::ast::expr> { - s.read_enum("core::option::t", - - - /*@syntax::ast::expr*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - })) - } - } - }) - }) -} -/*[core::option::t<@syntax::ast::expr>]*/ -fn deserialize_78<S: std::serialization::deserializer>(s: S) -> - [core::option::t<@syntax::ast::expr>] { - s.read_vec( - - /*core::option::t<@syntax::ast::expr>*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_77(s) }) - }) - }) -} -/*syntax::ast::binop*/ -fn deserialize_79<S: std::serialization::deserializer>(s: S) -> - syntax::ast::binop { - s.read_enum("syntax::ast::binop", - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::add } - 1u { syntax::ast::subtract } - 2u { syntax::ast::mul } - 3u { syntax::ast::div } - 4u { syntax::ast::rem } - 5u { syntax::ast::and } - 6u { syntax::ast::or } - 7u { syntax::ast::bitxor } - 8u { syntax::ast::bitand } - 9u { syntax::ast::bitor } - 10u { syntax::ast::lsl } - 11u { syntax::ast::lsr } - 12u { syntax::ast::asr } - 13u { syntax::ast::eq } - 14u { syntax::ast::lt } - 15u { syntax::ast::le } - 16u { syntax::ast::ne } - 17u { syntax::ast::ge } - 18u { syntax::ast::gt } - } - }) - }) -} -/*syntax::ast::unop*/ -fn deserialize_80<S: std::serialization::deserializer>(s: S) -> - syntax::ast::unop { - s.read_enum("syntax::ast::unop", - /*syntax::ast::mutability*/ - - /*syntax::ast::mutability*/ - - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::box(s.read_enum_variant_arg(0u, - {|| - deserialize_33(s) - })) - } - 1u { - syntax::ast::uniq(s.read_enum_variant_arg(0u, - {|| - deserialize_33(s) - })) - } - 2u { syntax::ast::deref } - 3u { syntax::ast::not } - 4u { syntax::ast::neg } - } - }) - }) -} -/*syntax::ast::simple_path*/ -fn deserialize_92<S: std::serialization::deserializer>(s: S) -> - syntax::ast::simple_path { - s.read_vec( - - /*syntax::ast::ident*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_1(s) }) - }) - }) -} -/*@syntax::ast::simple_path*/ -fn deserialize_91<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::simple_path { - - s.read_box(/*syntax::ast::simple_path*/{|| @deserialize_92(s) }) - -} -/*syntax::ast::path_list_ident_*/ -fn deserialize_95<S: std::serialization::deserializer>(s: S) -> - syntax::ast::path_list_ident_ { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*syntax::ast::node_id*/ - - {|| - {name: - s.read_rec_field("name", 0u, {|| deserialize_1(s) }), - id: s.read_rec_field("id", 1u, {|| deserialize_27(s) }),} - }) -} -/*syntax::ast::path_list_ident*/ -fn deserialize_94<S: std::serialization::deserializer>(s: S) -> - syntax::ast::path_list_ident { - - s.read_rec( - - - /*syntax::ast::path_list_ident_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_95(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*[syntax::ast::path_list_ident]*/ -fn deserialize_93<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::path_list_ident] { - s.read_vec( - - /*syntax::ast::path_list_ident*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_94(s) }) - }) - }) -} -/*syntax::ast::view_path_*/ -fn deserialize_90<S: std::serialization::deserializer>(s: S) -> - syntax::ast::view_path_ { - s.read_enum("syntax::ast::view_path_", - /*syntax::ast::ident*//*@syntax::ast::simple_path*/ - /*syntax::ast::node_id*/ - - /*@syntax::ast::simple_path*//*syntax::ast::node_id*/ - - /*@syntax::ast::simple_path*/ - /*[syntax::ast::path_list_ident]*//*syntax::ast::node_id*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::view_path_simple(s.read_enum_variant_arg(0u, - {|| - deserialize_1(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_91(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_27(s) - })) - } - 1u { - syntax::ast::view_path_glob(s.read_enum_variant_arg(0u, - {|| - deserialize_91(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_27(s) - })) - } - 2u { - syntax::ast::view_path_list(s.read_enum_variant_arg(0u, - {|| - deserialize_91(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_93(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_27(s) - })) - } - } - }) - }) -} -/*syntax::ast::view_path*/ -fn deserialize_89<S: std::serialization::deserializer>(s: S) -> - syntax::ast::view_path { - - s.read_rec( - - - /*syntax::ast::view_path_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_90(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::view_path*/ -fn deserialize_88<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::view_path { - - s.read_box(/*syntax::ast::view_path*/{|| @deserialize_89(s) }) - -} -/*[@syntax::ast::view_path]*/ -fn deserialize_87<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::view_path] { - s.read_vec( - - /*@syntax::ast::view_path*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_88(s) }) - }) - }) -} -/*syntax::ast::view_item_*/ -fn deserialize_86<S: std::serialization::deserializer>(s: S) -> - syntax::ast::view_item_ { - s.read_enum("syntax::ast::view_item_", - /*syntax::ast::ident*//*[@syntax::ast::meta_item]*/ - /*syntax::ast::node_id*/ - - /*[@syntax::ast::view_path]*/ - - /*[@syntax::ast::view_path]*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::view_item_use(s.read_enum_variant_arg(0u, - {|| - deserialize_1(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_8(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_27(s) - })) - } - 1u { - syntax::ast::view_item_import(s.read_enum_variant_arg(0u, - {|| - deserialize_87(s) - })) - } - 2u { - syntax::ast::view_item_export(s.read_enum_variant_arg(0u, - {|| - deserialize_87(s) - })) - } - } - }) - }) -} -/*syntax::ast::view_item*/ -fn deserialize_85<S: std::serialization::deserializer>(s: S) -> - syntax::ast::view_item { - - s.read_rec( - - - /*syntax::ast::view_item_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_86(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::view_item*/ -fn deserialize_84<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::view_item { - - s.read_box(/*syntax::ast::view_item*/{|| @deserialize_85(s) }) - -} -/*[@syntax::ast::view_item]*/ -fn deserialize_83<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::view_item] { - s.read_vec( - - /*@syntax::ast::view_item*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_84(s) }) - }) - }) -} -/*core::option::t<@syntax::ast::pat>*/ -fn deserialize_110<S: std::serialization::deserializer>(s: S) -> - core::option::t<@syntax::ast::pat> { - s.read_enum("core::option::t", - - - /*@syntax::ast::pat*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_107(s) - })) - } - } - }) - }) -} -/*[@syntax::ast::pat]*/ -fn deserialize_111<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::pat] { - s.read_vec( - - /*@syntax::ast::pat*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_107(s) }) - }) - }) -} -/*syntax::ast::field_pat*/ -fn deserialize_113<S: std::serialization::deserializer>(s: S) -> - syntax::ast::field_pat { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*@syntax::ast::pat*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - pat: - s.read_rec_field("pat", 1u, - {|| deserialize_107(s) }),} - }) - -} -/*[syntax::ast::field_pat]*/ -fn deserialize_112<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::field_pat] { - s.read_vec( - - /*syntax::ast::field_pat*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_113(s) }) - }) - }) -} -/*syntax::ast::pat_*/ -fn deserialize_109<S: std::serialization::deserializer>(s: S) -> - syntax::ast::pat_ { - s.read_enum("syntax::ast::pat_", - - - /*@syntax::ast::path*//*core::option::t<@syntax::ast::pat>*/ - - /*@syntax::ast::path*//*[@syntax::ast::pat]*/ - - /*[syntax::ast::field_pat]*//*bool*/ - - /*[@syntax::ast::pat]*/ - - /*@syntax::ast::pat*/ - - /*@syntax::ast::pat*/ - - /*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::pat_wild } - 1u { - syntax::ast::pat_ident(s.read_enum_variant_arg(0u, - {|| - deserialize_49(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_110(s) - })) - } - 2u { - syntax::ast::pat_enum(s.read_enum_variant_arg(0u, - {|| - deserialize_49(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_111(s) - })) - } - 3u { - syntax::ast::pat_rec(s.read_enum_variant_arg(0u, - {|| - deserialize_112(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_18(s) - })) - } - 4u { - syntax::ast::pat_tup(s.read_enum_variant_arg(0u, - {|| - deserialize_111(s) - })) - } - 5u { - syntax::ast::pat_box(s.read_enum_variant_arg(0u, - {|| - deserialize_107(s) - })) - } - 6u { - syntax::ast::pat_uniq(s.read_enum_variant_arg(0u, - {|| - deserialize_107(s) - })) - } - 7u { - syntax::ast::pat_lit(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - })) - } - 8u { - syntax::ast::pat_range(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - } - }) - }) -} -/*syntax::ast::pat*/ -fn deserialize_108<S: std::serialization::deserializer>(s: S) -> - syntax::ast::pat { - - s.read_rec( - - - /*syntax::ast::node_id*/ - - /*syntax::ast::pat_*/ - - /*syntax::codemap::span*/ - - {|| - {id: s.read_rec_field("id", 0u, {|| deserialize_27(s) }), - node: - s.read_rec_field("node", 1u, - {|| deserialize_109(s) }), - span: - s.read_rec_field("span", 2u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::pat*/ -fn deserialize_107<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::pat { - - s.read_box(/*syntax::ast::pat*/{|| @deserialize_108(s) }) - -} -/*syntax::ast::init_op*/ -fn deserialize_116<S: std::serialization::deserializer>(s: S) -> - syntax::ast::init_op { - s.read_enum("syntax::ast::init_op", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::init_assign } - 1u { syntax::ast::init_move } - } - }) - }) -} -/*syntax::ast::initializer*/ -fn deserialize_115<S: std::serialization::deserializer>(s: S) -> - syntax::ast::initializer { - - s.read_rec( - - - /*syntax::ast::init_op*/ - - /*@syntax::ast::expr*/ - - {|| - {op: s.read_rec_field("op", 0u, {|| deserialize_116(s) }), - expr: - s.read_rec_field("expr", 1u, - {|| deserialize_70(s) }),} - }) - -} -/*core::option::t<syntax::ast::initializer>*/ -fn deserialize_114<S: std::serialization::deserializer>(s: S) -> - core::option::t<syntax::ast::initializer> { - s.read_enum("core::option::t", - - - /*syntax::ast::initializer*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_115(s) - })) - } - } - }) - }) -} -/*syntax::ast::local_*/ -fn deserialize_106<S: std::serialization::deserializer>(s: S) -> - syntax::ast::local_ { - - s.read_rec( - - - /*bool*/ - - /*@syntax::ast::ty*/ - - /*@syntax::ast::pat*/ - - /*core::option::t<syntax::ast::initializer>*/ - - /*syntax::ast::node_id*/ - - {|| - {is_mutbl: - s.read_rec_field("is_mutbl", 0u, - {|| deserialize_18(s) }), - ty: s.read_rec_field("ty", 1u, {|| deserialize_29(s) }), - pat: - s.read_rec_field("pat", 2u, {|| deserialize_107(s) }), - init: - s.read_rec_field("init", 3u, - {|| deserialize_114(s) }), - id: s.read_rec_field("id", 4u, {|| deserialize_27(s) }),} - }) -} -/*syntax::ast::local*/ -fn deserialize_105<S: std::serialization::deserializer>(s: S) -> - syntax::ast::local { - - s.read_rec( - - - /*syntax::ast::local_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, - {|| deserialize_106(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::local*/ -fn deserialize_104<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::local { - - s.read_box(/*syntax::ast::local*/{|| @deserialize_105(s) }) - -} -/*[@syntax::ast::local]*/ -fn deserialize_103<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::local] { - s.read_vec( - - /*@syntax::ast::local*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_104(s) }) - }) - }) -} -/*@syntax::ast::item*/ -fn deserialize_117<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::item { - - s.read_box(/*syntax::ast::item*/{|| @deserialize_0(s) }) - -} -/*syntax::ast::decl_*/ -fn deserialize_102<S: std::serialization::deserializer>(s: S) -> - syntax::ast::decl_ { - s.read_enum("syntax::ast::decl_", - /*[@syntax::ast::local]*/ - - /*@syntax::ast::item*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::decl_local(s.read_enum_variant_arg(0u, - {|| - deserialize_103(s) - })) - } - 1u { - syntax::ast::decl_item(s.read_enum_variant_arg(0u, - {|| - deserialize_117(s) - })) - } - } - }) - }) -} -/*syntax::ast::decl*/ -fn deserialize_101<S: std::serialization::deserializer>(s: S) -> - syntax::ast::decl { - - s.read_rec( - - - /*syntax::ast::decl_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, - {|| deserialize_102(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::decl*/ -fn deserialize_100<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::decl { - - s.read_box(/*syntax::ast::decl*/{|| @deserialize_101(s) }) - -} -/*syntax::ast::stmt_*/ -fn deserialize_99<S: std::serialization::deserializer>(s: S) -> - syntax::ast::stmt_ { - s.read_enum("syntax::ast::stmt_", - /*@syntax::ast::decl*//*syntax::ast::node_id*/ - - /*@syntax::ast::expr*//*syntax::ast::node_id*/ - - /*@syntax::ast::expr*//*syntax::ast::node_id*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::stmt_decl(s.read_enum_variant_arg(0u, - {|| - deserialize_100(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_27(s) - })) - } - 1u { - syntax::ast::stmt_expr(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_27(s) - })) - } - 2u { - syntax::ast::stmt_semi(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_27(s) - })) - } - } - }) - }) -} -/*syntax::ast::stmt*/ -fn deserialize_98<S: std::serialization::deserializer>(s: S) -> - syntax::ast::stmt { - - s.read_rec( - - - /*syntax::ast::stmt_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_99(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::stmt*/ -fn deserialize_97<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::stmt { - - s.read_box(/*syntax::ast::stmt*/{|| @deserialize_98(s) }) - -} -/*[@syntax::ast::stmt]*/ -fn deserialize_96<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::stmt] { - s.read_vec( - - /*@syntax::ast::stmt*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, {|| deserialize_97(s) }) - }) - }) -} -/*syntax::ast::blk_check_mode*/ -fn deserialize_118<S: std::serialization::deserializer>(s: S) -> - syntax::ast::blk_check_mode { - s.read_enum("syntax::ast::blk_check_mode", - - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::default_blk } - 1u { - syntax::ast::unchecked_blk - } - 2u { syntax::ast::unsafe_blk } - } - }) - }) -} -/*syntax::ast::blk_*/ -fn deserialize_82<S: std::serialization::deserializer>(s: S) -> - syntax::ast::blk_ { - - s.read_rec( - - - /*[@syntax::ast::view_item]*/ - - /*[@syntax::ast::stmt]*/ - - /*core::option::t<@syntax::ast::expr>*/ - - /*syntax::ast::node_id*/ - - /*syntax::ast::blk_check_mode*/ - - {|| - {view_items: - s.read_rec_field("view_items", 0u, - {|| deserialize_83(s) }), - stmts: - s.read_rec_field("stmts", 1u, - {|| deserialize_96(s) }), - expr: - s.read_rec_field("expr", 2u, {|| deserialize_77(s) }), - id: s.read_rec_field("id", 3u, {|| deserialize_27(s) }), - rules: - s.read_rec_field("rules", 4u, - {|| deserialize_118(s) }),} - }) - -} -/*syntax::ast::blk*/ -fn deserialize_81<S: std::serialization::deserializer>(s: S) -> - syntax::ast::blk { - - s.read_rec( - - - /*syntax::ast::blk_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_82(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*syntax::ast::arm*/ -fn deserialize_120<S: std::serialization::deserializer>(s: S) -> - syntax::ast::arm { - - s.read_rec( - - - /*[@syntax::ast::pat]*/ - - /*core::option::t<@syntax::ast::expr>*/ - - /*syntax::ast::blk*/ - - {|| - {pats: - s.read_rec_field("pats", 0u, - {|| deserialize_111(s) }), - guard: - s.read_rec_field("guard", 1u, - {|| deserialize_77(s) }), - body: - s.read_rec_field("body", 2u, - {|| deserialize_81(s) }),} - }) - -} -/*[syntax::ast::arm]*/ -fn deserialize_119<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::arm] { - s.read_vec( - - /*syntax::ast::arm*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_120(s) }) - }) - }) -} -/*syntax::ast::alt_mode*/ -fn deserialize_121<S: std::serialization::deserializer>(s: S) -> - syntax::ast::alt_mode { - s.read_enum("syntax::ast::alt_mode", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::alt_check } - 1u { - syntax::ast::alt_exhaustive - } - } - }) - }) -} -/*int*/ -fn deserialize_127<S: std::serialization::deserializer>(s: S) -> int { - s.read_int() -} -/*syntax::ast::capture_item*/ -fn deserialize_126<S: std::serialization::deserializer>(s: S) -> - syntax::ast::capture_item { - - s.read_rec( - - - /*int*/ - - /*syntax::ast::ident*/ - - /*syntax::codemap::span*/ - - {|| - {id: s.read_rec_field("id", 0u, {|| deserialize_127(s) }), - name: - s.read_rec_field("name", 1u, {|| deserialize_1(s) }), - span: - s.read_rec_field("span", 2u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::capture_item*/ -fn deserialize_125<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::capture_item { - - s.read_box(/*syntax::ast::capture_item*/{|| @deserialize_126(s) }) - -} -/*[@syntax::ast::capture_item]*/ -fn deserialize_124<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::capture_item] { - s.read_vec( - - /*@syntax::ast::capture_item*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_125(s) }) - }) - }) -} -/*syntax::ast::capture_clause*/ -fn deserialize_123<S: std::serialization::deserializer>(s: S) -> - syntax::ast::capture_clause { - - s.read_rec( - - - /*[@syntax::ast::capture_item]*/ - - /*[@syntax::ast::capture_item]*/ - - {|| - {copies: - s.read_rec_field("copies", 0u, - {|| deserialize_124(s) }), - moves: - s.read_rec_field("moves", 1u, - {|| deserialize_124(s) }),} - }) - -} -/*@syntax::ast::capture_clause*/ -fn deserialize_122<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::capture_clause { - - s.read_box(/*syntax::ast::capture_clause*/{|| @deserialize_123(s) }) - -} -/*syntax::ast::expr_check_mode*/ -fn deserialize_128<S: std::serialization::deserializer>(s: S) -> - syntax::ast::expr_check_mode { - s.read_enum("syntax::ast::expr_check_mode", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::claimed_expr } - 1u { syntax::ast::checked_expr } - } - }) - }) -} -/*syntax::ast::expr_*/ -fn deserialize_72<S: std::serialization::deserializer>(s: S) -> - syntax::ast::expr_ { - s.read_enum("syntax::ast::expr_", - /*[@syntax::ast::expr]*//*syntax::ast::mutability*/ - - /*[syntax::ast::field]*/ - /*core::option::t<@syntax::ast::expr>*/ - - /*@syntax::ast::expr*//*[@syntax::ast::expr]*//*bool*/ - - /*[@syntax::ast::expr]*/ - - /*@syntax::ast::expr*/ - /*[core::option::t<@syntax::ast::expr>]*/ - - /*syntax::ast::binop*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*/ - - /*syntax::ast::unop*//*@syntax::ast::expr*/ - - /*@syntax::ast::lit*/ - - /*@syntax::ast::expr*//*@syntax::ast::ty*/ - - /*@syntax::ast::expr*//*syntax::ast::blk*/ - /*core::option::t<@syntax::ast::expr>*/ - - /*@syntax::ast::expr*//*syntax::ast::blk*/ - - /*@syntax::ast::local*//*@syntax::ast::expr*/ - /*syntax::ast::blk*/ - - /*syntax::ast::blk*//*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*[syntax::ast::arm]*/ - /*syntax::ast::alt_mode*/ - - /*syntax::ast::proto*//*syntax::ast::fn_decl*/ - /*syntax::ast::blk*//*@syntax::ast::capture_clause*/ - - /*syntax::ast::fn_decl*//*syntax::ast::blk*/ - - /*syntax::ast::blk*/ - - /*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - - /*syntax::ast::binop*//*@syntax::ast::expr*/ - /*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*syntax::ast::ident*/ - /*[@syntax::ast::ty]*/ - - /*@syntax::ast::expr*//*@syntax::ast::expr*/ - - /*@syntax::ast::path*/ - - /*core::option::t<@syntax::ast::expr>*/ - - - - - - /*core::option::t<@syntax::ast::expr>*/ - - /*@syntax::ast::expr*/ - - /*int*//*@syntax::ast::expr*//*@syntax::ast::expr*/ - - /*@syntax::ast::expr*/ - - /*syntax::ast::expr_check_mode*//*@syntax::ast::expr*/ - - /*@syntax::ast::expr*//*syntax::ast::blk*/ - /*core::option::t<@syntax::ast::expr>*/ - - /*syntax::ast::mac*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::expr_vec(s.read_enum_variant_arg(0u, - {|| - deserialize_73(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_33(s) - })) - } - 1u { - syntax::ast::expr_rec(s.read_enum_variant_arg(0u, - {|| - deserialize_74(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_77(s) - })) - } - 2u { - syntax::ast::expr_call(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_73(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_18(s) - })) - } - 3u { - syntax::ast::expr_tup(s.read_enum_variant_arg(0u, - {|| - deserialize_73(s) - })) - } - 4u { - syntax::ast::expr_bind(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_78(s) - })) - } - 5u { - syntax::ast::expr_binary(s.read_enum_variant_arg(0u, - {|| - deserialize_79(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_70(s) - })) - } - 6u { - syntax::ast::expr_unary(s.read_enum_variant_arg(0u, - {|| - deserialize_80(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 7u { - syntax::ast::expr_lit(s.read_enum_variant_arg(0u, - {|| - deserialize_58(s) - })) - } - 8u { - syntax::ast::expr_cast(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_29(s) - })) - } - 9u { - syntax::ast::expr_if(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_81(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_77(s) - })) - } - 10u { - syntax::ast::expr_while(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_81(s) - })) - } - 11u { - syntax::ast::expr_for(s.read_enum_variant_arg(0u, - {|| - deserialize_104(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_81(s) - })) - } - 12u { - syntax::ast::expr_do_while(s.read_enum_variant_arg(0u, - {|| - deserialize_81(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 13u { - syntax::ast::expr_alt(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_119(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_121(s) - })) - } - 14u { - syntax::ast::expr_fn(s.read_enum_variant_arg(0u, - {|| - deserialize_37(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_38(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_81(s) - }), - s.read_enum_variant_arg(3u, - {|| - deserialize_122(s) - })) - } - 15u { - syntax::ast::expr_fn_block(s.read_enum_variant_arg(0u, - {|| - deserialize_38(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_81(s) - })) - } - 16u { - syntax::ast::expr_block(s.read_enum_variant_arg(0u, - {|| - deserialize_81(s) - })) - } - 17u { - syntax::ast::expr_copy(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - })) - } - 18u { - syntax::ast::expr_move(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 19u { - syntax::ast::expr_assign(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 20u { - syntax::ast::expr_swap(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 21u { - syntax::ast::expr_assign_op(s.read_enum_variant_arg(0u, - {|| - deserialize_79(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_70(s) - })) - } - 22u { - syntax::ast::expr_field(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_1(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_53(s) - })) - } - 23u { - syntax::ast::expr_index(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 24u { - syntax::ast::expr_path(s.read_enum_variant_arg(0u, - {|| - deserialize_49(s) - })) - } - 25u { - syntax::ast::expr_fail(s.read_enum_variant_arg(0u, - {|| - deserialize_77(s) - })) - } - 26u { syntax::ast::expr_break } - 27u { syntax::ast::expr_cont } - 28u { - syntax::ast::expr_ret(s.read_enum_variant_arg(0u, - {|| - deserialize_77(s) - })) - } - 29u { - syntax::ast::expr_be(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - })) - } - 30u { - syntax::ast::expr_log(s.read_enum_variant_arg(0u, - {|| - deserialize_127(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_70(s) - })) - } - 31u { - syntax::ast::expr_assert(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - })) - } - 32u { - syntax::ast::expr_check(s.read_enum_variant_arg(0u, - {|| - deserialize_128(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 33u { - syntax::ast::expr_if_check(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_81(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_77(s) - })) - } - 34u { - syntax::ast::expr_mac(s.read_enum_variant_arg(0u, - {|| - deserialize_67(s) - })) - } - } - }) - }) -} -/*syntax::ast::expr*/ -fn deserialize_71<S: std::serialization::deserializer>(s: S) -> - syntax::ast::expr { - - s.read_rec( - - - /*syntax::ast::node_id*/ - - /*syntax::ast::expr_*/ - - /*syntax::codemap::span*/ - - {|| - {id: s.read_rec_field("id", 0u, {|| deserialize_27(s) }), - node: - s.read_rec_field("node", 1u, {|| deserialize_72(s) }), - span: - s.read_rec_field("span", 2u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::expr*/ -fn deserialize_70<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::expr { - - s.read_box(/*syntax::ast::expr*/{|| @deserialize_71(s) }) - -} -/*syntax::ast::mac_arg<@syntax::ast::expr>*/ -fn deserialize_69<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mac_arg<@syntax::ast::expr> { - s.read_enum("core::option::t", - - - /*@syntax::ast::expr*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_70(s) - })) - } - } - }) - }) -} -/*syntax::ast::mac_body_*/ -fn deserialize_130<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mac_body_ { - - s.read_rec( - - - /*syntax::codemap::span*/ - - {|| - {span: - s.read_rec_field("span", 0u, - {|| deserialize_19(s) }),} - }) - -} -/*syntax::ast::mac_body<syntax::ast::mac_body_>*/ -fn deserialize_129<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mac_body<syntax::ast::mac_body_> { - s.read_enum("core::option::t", - - - /*syntax::ast::mac_body_*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_130(s) - })) - } - } - }) - }) -} -/*syntax::ast::mac_*/ -fn deserialize_68<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mac_ { - s.read_enum("syntax::ast::mac_", - /*@syntax::ast::path*/ - /*syntax::ast::mac_arg<@syntax::ast::expr>*/ - /*syntax::ast::mac_body<syntax::ast::mac_body_>*/ - - /*@syntax::ast::ty*/ - - /*syntax::ast::blk*/ - - - - /*syntax::codemap::span*//*@syntax::ast::expr*/ - - /*uint*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::mac_invoc(s.read_enum_variant_arg(0u, - {|| - deserialize_49(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_69(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_129(s) - })) - } - 1u { - syntax::ast::mac_embed_type(s.read_enum_variant_arg(0u, - {|| - deserialize_29(s) - })) - } - 2u { - syntax::ast::mac_embed_block(s.read_enum_variant_arg(0u, - {|| - deserialize_81(s) - })) - } - 3u { syntax::ast::mac_ellipsis } - 4u { - syntax::ast::mac_aq(s.read_enum_variant_arg(0u, - {|| - deserialize_19(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 5u { - syntax::ast::mac_var(s.read_enum_variant_arg(0u, - {|| - deserialize_20(s) - })) - } - } - }) - }) -} -/*syntax::ast::mac*/ -fn deserialize_67<S: std::serialization::deserializer>(s: S) -> - syntax::ast::mac { - - s.read_rec( - - - /*syntax::ast::mac_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_68(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*syntax::ast::ty_*/ -fn deserialize_31<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_ { - s.read_enum("syntax::ast::ty_", - - - - - /*syntax::ast::mt*/ - - /*syntax::ast::mt*/ - - /*syntax::ast::mt*/ - - /*syntax::ast::mt*/ - - /*[syntax::ast::ty_field]*/ - - /*syntax::ast::proto*//*syntax::ast::fn_decl*/ - - /*[@syntax::ast::ty]*/ - - /*@syntax::ast::path*//*syntax::ast::node_id*/ - - /*@syntax::ast::ty*//*[@syntax::ast::ty_constr]*/ - - /*syntax::ast::mac*/ - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::ty_nil } - 1u { syntax::ast::ty_bot } - 2u { - syntax::ast::ty_box(s.read_enum_variant_arg(0u, - {|| - deserialize_32(s) - })) - } - 3u { - syntax::ast::ty_uniq(s.read_enum_variant_arg(0u, - {|| - deserialize_32(s) - })) - } - 4u { - syntax::ast::ty_vec(s.read_enum_variant_arg(0u, - {|| - deserialize_32(s) - })) - } - 5u { - syntax::ast::ty_ptr(s.read_enum_variant_arg(0u, - {|| - deserialize_32(s) - })) - } - 6u { - syntax::ast::ty_rec(s.read_enum_variant_arg(0u, - {|| - deserialize_34(s) - })) - } - 7u { - syntax::ast::ty_fn(s.read_enum_variant_arg(0u, - {|| - deserialize_37(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_38(s) - })) - } - 8u { - syntax::ast::ty_tup(s.read_enum_variant_arg(0u, - {|| - deserialize_53(s) - })) - } - 9u { - syntax::ast::ty_path(s.read_enum_variant_arg(0u, - {|| - deserialize_49(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_27(s) - })) - } - 10u { - syntax::ast::ty_constr(s.read_enum_variant_arg(0u, - {|| - deserialize_29(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_59(s) - })) - } - 11u { - syntax::ast::ty_mac(s.read_enum_variant_arg(0u, - {|| - deserialize_67(s) - })) - } - 12u { syntax::ast::ty_infer } - } - }) - }) -} -/*syntax::ast::ty*/ -fn deserialize_30<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty { - - s.read_rec( - - - /*syntax::ast::ty_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, {|| deserialize_31(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::ty*/ -fn deserialize_29<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::ty { - - s.read_box(/*syntax::ast::ty*/{|| @deserialize_30(s) }) - -} -/*syntax::ast::ty_param_bound*/ -fn deserialize_135<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_param_bound { - s.read_enum("syntax::ast::ty_param_bound", - - - - - /*@syntax::ast::ty*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::bound_copy } - 1u { syntax::ast::bound_send } - 2u { - syntax::ast::bound_iface(s.read_enum_variant_arg(0u, - {|| - deserialize_29(s) - })) - } - } - }) - }) -} -/*[syntax::ast::ty_param_bound]*/ -fn deserialize_134<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::ty_param_bound] { - s.read_vec( - - /*syntax::ast::ty_param_bound*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_135(s) }) - }) - }) -} -/*@[syntax::ast::ty_param_bound]*/ -fn deserialize_133<S: std::serialization::deserializer>(s: S) -> - @[syntax::ast::ty_param_bound] { - - s.read_box(/*[syntax::ast::ty_param_bound]*/{|| @deserialize_134(s) }) - -} -/*syntax::ast::ty_param*/ -fn deserialize_132<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_param { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*syntax::ast::node_id*/ - - /*@[syntax::ast::ty_param_bound]*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - id: s.read_rec_field("id", 1u, {|| deserialize_27(s) }), - bounds: - s.read_rec_field("bounds", 2u, - {|| deserialize_133(s) }),} - }) - -} -/*[syntax::ast::ty_param]*/ -fn deserialize_131<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::ty_param] { - s.read_vec( - - /*syntax::ast::ty_param*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_132(s) }) - }) - }) -} -/*[@syntax::ast::item]*/ -fn deserialize_137<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::item] { - s.read_vec( - - /*@syntax::ast::item*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_117(s) }) - }) - }) -} -/*syntax::ast::_mod*/ -fn deserialize_136<S: std::serialization::deserializer>(s: S) -> - syntax::ast::_mod { - - s.read_rec( - - - /*[@syntax::ast::view_item]*/ - - /*[@syntax::ast::item]*/ - - {|| - {view_items: - s.read_rec_field("view_items", 0u, - {|| deserialize_83(s) }), - items: - s.read_rec_field("items", 1u, - {|| deserialize_137(s) }),} - }) - -} -/*syntax::ast::native_item_*/ -fn deserialize_142<S: std::serialization::deserializer>(s: S) -> - syntax::ast::native_item_ { - s.read_enum("syntax::ast::native_item_", - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::native_item_fn(s.read_enum_variant_arg(0u, - {|| - deserialize_38(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_131(s) - })) - } - } - }) - }) -} -/*syntax::ast::native_item*/ -fn deserialize_141<S: std::serialization::deserializer>(s: S) -> - syntax::ast::native_item { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*[syntax::ast::attribute]*/ - - /*syntax::ast::native_item_*/ - - /*syntax::ast::node_id*/ - - /*syntax::codemap::span*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - attrs: - s.read_rec_field("attrs", 1u, {|| deserialize_2(s) }), - node: - s.read_rec_field("node", 2u, - {|| deserialize_142(s) }), - id: s.read_rec_field("id", 3u, {|| deserialize_27(s) }), - span: - s.read_rec_field("span", 4u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::native_item*/ -fn deserialize_140<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::native_item { - - s.read_box(/*syntax::ast::native_item*/{|| @deserialize_141(s) }) - -} -/*[@syntax::ast::native_item]*/ -fn deserialize_139<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::native_item] { - s.read_vec( - - /*@syntax::ast::native_item*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_140(s) }) - }) - }) -} -/*syntax::ast::native_mod*/ -fn deserialize_138<S: std::serialization::deserializer>(s: S) -> - syntax::ast::native_mod { - - s.read_rec( - - - /*[@syntax::ast::view_item]*/ - - /*[@syntax::ast::native_item]*/ - - {|| - {view_items: - s.read_rec_field("view_items", 0u, - {|| deserialize_83(s) }), - items: - s.read_rec_field("items", 1u, - {|| deserialize_139(s) }),} - }) - -} -/*syntax::ast::variant_arg*/ -fn deserialize_147<S: std::serialization::deserializer>(s: S) -> - syntax::ast::variant_arg { - - s.read_rec( - - - /*@syntax::ast::ty*/ - - /*syntax::ast::node_id*/ - - {|| - {ty: s.read_rec_field("ty", 0u, {|| deserialize_29(s) }), - id: s.read_rec_field("id", 1u, {|| deserialize_27(s) }),} - }) -} -/*[syntax::ast::variant_arg]*/ -fn deserialize_146<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::variant_arg] { - s.read_vec( - - /*syntax::ast::variant_arg*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_147(s) }) - }) - }) -} -/*syntax::ast::variant_*/ -fn deserialize_145<S: std::serialization::deserializer>(s: S) -> - syntax::ast::variant_ { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*[syntax::ast::attribute]*/ - - /*[syntax::ast::variant_arg]*/ - - /*syntax::ast::node_id*/ - - /*core::option::t<@syntax::ast::expr>*/ - - {|| - {name: - s.read_rec_field("name", 0u, {|| deserialize_1(s) }), - attrs: - s.read_rec_field("attrs", 1u, {|| deserialize_2(s) }), - args: - s.read_rec_field("args", 2u, - {|| deserialize_146(s) }), - id: s.read_rec_field("id", 3u, {|| deserialize_27(s) }), - disr_expr: - s.read_rec_field("disr_expr", 4u, - {|| deserialize_77(s) }),} - }) - -} -/*syntax::ast::variant*/ -fn deserialize_144<S: std::serialization::deserializer>(s: S) -> - syntax::ast::variant { - - s.read_rec( - - - /*syntax::ast::variant_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, - {|| deserialize_145(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*[syntax::ast::variant]*/ -fn deserialize_143<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::variant] { - s.read_vec( - - /*syntax::ast::variant*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_144(s) }) - }) - }) -} -/*syntax::ast::privacy*/ -fn deserialize_152<S: std::serialization::deserializer>(s: S) -> - syntax::ast::privacy { - s.read_enum("syntax::ast::privacy", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { syntax::ast::priv } - 1u { syntax::ast::pub } - } - }) - }) -} -/*syntax::ast::class_mutability*/ -fn deserialize_154<S: std::serialization::deserializer>(s: S) -> - syntax::ast::class_mutability { - s.read_enum("syntax::ast::class_mutability", - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::class_mutable - } - 1u { - syntax::ast::class_immutable - } - } - }) - }) -} -/*syntax::ast::class_member*/ -fn deserialize_153<S: std::serialization::deserializer>(s: S) -> - syntax::ast::class_member { - s.read_enum("syntax::ast::class_member", - /*syntax::ast::ident*//*@syntax::ast::ty*/ - /*syntax::ast::class_mutability*//*syntax::ast::node_id*/ - - /*@syntax::ast::item*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::instance_var(s.read_enum_variant_arg(0u, - {|| - deserialize_1(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_29(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_154(s) - }), - s.read_enum_variant_arg(3u, - {|| - deserialize_27(s) - })) - } - 1u { - syntax::ast::class_method(s.read_enum_variant_arg(0u, - {|| - deserialize_117(s) - })) - } - } - }) - }) -} -/*syntax::ast::class_item_*/ -fn deserialize_151<S: std::serialization::deserializer>(s: S) -> - syntax::ast::class_item_ { - - s.read_rec( - - - /*syntax::ast::privacy*/ - - /*syntax::ast::class_member*/ - - {|| - {privacy: - s.read_rec_field("privacy", 0u, - {|| deserialize_152(s) }), - decl: - s.read_rec_field("decl", 1u, - {|| deserialize_153(s) }),} - }) - -} -/*syntax::ast::class_item*/ -fn deserialize_150<S: std::serialization::deserializer>(s: S) -> - syntax::ast::class_item { - - s.read_rec( - - - /*syntax::ast::class_item_*/ - - /*syntax::codemap::span*/ - - {|| - {node: - s.read_rec_field("node", 0u, - {|| deserialize_151(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::class_item*/ -fn deserialize_149<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::class_item { - - s.read_box(/*syntax::ast::class_item*/{|| @deserialize_150(s) }) - -} -/*[@syntax::ast::class_item]*/ -fn deserialize_148<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::class_item] { - s.read_vec( - - /*@syntax::ast::class_item*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_149(s) }) - }) - }) -} -/*syntax::ast::ty_method*/ -fn deserialize_156<S: std::serialization::deserializer>(s: S) -> - syntax::ast::ty_method { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*[syntax::ast::attribute]*/ - - /*syntax::ast::fn_decl*/ - - /*[syntax::ast::ty_param]*/ - - /*syntax::codemap::span*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - attrs: - s.read_rec_field("attrs", 1u, {|| deserialize_2(s) }), - decl: - s.read_rec_field("decl", 2u, {|| deserialize_38(s) }), - tps: - s.read_rec_field("tps", 3u, {|| deserialize_131(s) }), - span: - s.read_rec_field("span", 4u, - {|| deserialize_19(s) }),} - }) - -} -/*[syntax::ast::ty_method]*/ -fn deserialize_155<S: std::serialization::deserializer>(s: S) -> - [syntax::ast::ty_method] { - s.read_vec( - - /*syntax::ast::ty_method*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_156(s) }) - }) - }) -} -/*core::option::t<@syntax::ast::ty>*/ -fn deserialize_157<S: std::serialization::deserializer>(s: S) -> - core::option::t<@syntax::ast::ty> { - s.read_enum("core::option::t", - - - /*@syntax::ast::ty*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { core::option::none } - 1u { - core::option::some(s.read_enum_variant_arg(0u, - {|| - deserialize_29(s) - })) - } - } - }) - }) -} -/*syntax::ast::method*/ -fn deserialize_160<S: std::serialization::deserializer>(s: S) -> - syntax::ast::method { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*[syntax::ast::attribute]*/ - - /*[syntax::ast::ty_param]*/ - - /*syntax::ast::fn_decl*/ - - /*syntax::ast::blk*/ - - /*syntax::ast::node_id*/ - - /*syntax::codemap::span*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - attrs: - s.read_rec_field("attrs", 1u, {|| deserialize_2(s) }), - tps: - s.read_rec_field("tps", 2u, {|| deserialize_131(s) }), - decl: - s.read_rec_field("decl", 3u, {|| deserialize_38(s) }), - body: - s.read_rec_field("body", 4u, {|| deserialize_81(s) }), - id: s.read_rec_field("id", 5u, {|| deserialize_27(s) }), - span: - s.read_rec_field("span", 6u, - {|| deserialize_19(s) }),} - }) - -} -/*@syntax::ast::method*/ -fn deserialize_159<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::method { - - s.read_box(/*syntax::ast::method*/{|| @deserialize_160(s) }) - -} -/*[@syntax::ast::method]*/ -fn deserialize_158<S: std::serialization::deserializer>(s: S) -> - [@syntax::ast::method] { - s.read_vec( - - /*@syntax::ast::method*/ - {|len| - vec::init_fn(len, - {|i| - s.read_vec_elt(i, - {|| deserialize_159(s) }) - }) - }) -} -/*syntax::ast::item_*/ -fn deserialize_28<S: std::serialization::deserializer>(s: S) -> - syntax::ast::item_ { - s.read_enum("syntax::ast::item_", - /*@syntax::ast::ty*//*@syntax::ast::expr*/ - - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - /*syntax::ast::blk*/ - - /*syntax::ast::_mod*/ - - /*syntax::ast::native_mod*/ - - /*@syntax::ast::ty*//*[syntax::ast::ty_param]*/ - - /*[syntax::ast::variant]*//*[syntax::ast::ty_param]*/ - - /*syntax::ast::fn_decl*//*[syntax::ast::ty_param]*/ - /*syntax::ast::blk*//*syntax::ast::node_id*/ - /*syntax::ast::node_id*/ - - /*[syntax::ast::ty_param]*//*[@syntax::ast::class_item]*/ - /*syntax::ast::node_id*//*syntax::ast::fn_decl*/ - /*syntax::ast::blk*/ - - /*[syntax::ast::ty_param]*//*[syntax::ast::ty_method]*/ - - /*[syntax::ast::ty_param]*/ - /*core::option::t<@syntax::ast::ty>*//*@syntax::ast::ty*/ - /*[@syntax::ast::method]*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::item_const(s.read_enum_variant_arg(0u, - {|| - deserialize_29(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_70(s) - })) - } - 1u { - syntax::ast::item_fn(s.read_enum_variant_arg(0u, - {|| - deserialize_38(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_131(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_81(s) - })) - } - 2u { - syntax::ast::item_mod(s.read_enum_variant_arg(0u, - {|| - deserialize_136(s) - })) - } - 3u { - syntax::ast::item_native_mod(s.read_enum_variant_arg(0u, - {|| - deserialize_138(s) - })) - } - 4u { - syntax::ast::item_ty(s.read_enum_variant_arg(0u, - {|| - deserialize_29(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_131(s) - })) - } - 5u { - syntax::ast::item_enum(s.read_enum_variant_arg(0u, - {|| - deserialize_143(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_131(s) - })) - } - 6u { - syntax::ast::item_res(s.read_enum_variant_arg(0u, - {|| - deserialize_38(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_131(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_81(s) - }), - s.read_enum_variant_arg(3u, - {|| - deserialize_27(s) - }), - s.read_enum_variant_arg(4u, - {|| - deserialize_27(s) - })) - } - 7u { - syntax::ast::item_class(s.read_enum_variant_arg(0u, - {|| - deserialize_131(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_148(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_27(s) - }), - s.read_enum_variant_arg(3u, - {|| - deserialize_38(s) - }), - s.read_enum_variant_arg(4u, - {|| - deserialize_81(s) - })) - } - 8u { - syntax::ast::item_iface(s.read_enum_variant_arg(0u, - {|| - deserialize_131(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_155(s) - })) - } - 9u { - syntax::ast::item_impl(s.read_enum_variant_arg(0u, - {|| - deserialize_131(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_157(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_29(s) - }), - s.read_enum_variant_arg(3u, - {|| - deserialize_158(s) - })) - } - } - }) - }) -} -/*syntax::ast::item*/ -fn deserialize_0<S: std::serialization::deserializer>(s: S) -> - syntax::ast::item { - - s.read_rec( - - - /*syntax::ast::ident*/ - - /*[syntax::ast::attribute]*/ - - /*syntax::ast::node_id*/ - - /*syntax::ast::item_*/ - - /*syntax::codemap::span*/ - - {|| - {ident: - s.read_rec_field("ident", 0u, {|| deserialize_1(s) }), - attrs: - s.read_rec_field("attrs", 1u, {|| deserialize_2(s) }), - id: s.read_rec_field("id", 2u, {|| deserialize_27(s) }), - node: - s.read_rec_field("node", 3u, {|| deserialize_28(s) }), - span: - s.read_rec_field("span", 4u, - {|| deserialize_19(s) }),} - }) - -} -fn deserialize_syntax_ast_item<S: std::serialization::deserializer>(s: S) -> - syntax::ast::item { - deserialize_0(s) -} -/*syntax::ast::crate_num*/ -fn serialize_163<S: std::serialization::serializer>(s: S, - v: - syntax::ast::crate_num) { - s.emit_int(v); -} -/*syntax::ast::def_id*/ -fn serialize_162<S: std::serialization::serializer>(s: S, - v: syntax::ast::def_id) { - - s.emit_rec(/*syntax::ast::crate_num*//*syntax::ast::node_id*/ - {|| - { - s.emit_rec_field("crate", 0u, - {|| serialize_163(s, v.crate) }); - s.emit_rec_field("node", 1u, - {|| serialize_27(s, v.node) }) - } - }); -} -/*syntax::ast::prim_ty*/ -fn serialize_164<S: std::serialization::serializer>(s: S, - v: syntax::ast::prim_ty) { - - s.emit_enum("syntax::ast::prim_ty", - /*syntax::ast::int_ty*/ - /*syntax::ast::uint_ty*/ - /*syntax::ast::float_ty*/ - - {|| - alt v { - syntax::ast::ty_int(v0) { - s.emit_enum_variant("syntax::ast::ty_int", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_14(s, - v0) - }) - } - }) - } - syntax::ast::ty_uint(v0) { - s.emit_enum_variant("syntax::ast::ty_uint", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_16(s, - v0) - }) - } - }) - } - syntax::ast::ty_float(v0) { - s.emit_enum_variant("syntax::ast::ty_float", 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_17(s, - v0) - }) - } - }) - } - syntax::ast::ty_str { - s.emit_enum_variant("syntax::ast::ty_str", 3u, 0u, - {|| }) - } - syntax::ast::ty_bool { - s.emit_enum_variant("syntax::ast::ty_bool", 4u, 0u, - {|| }) - } - } - }); -} -/*@syntax::ast::def*/ -fn serialize_165<S: std::serialization::serializer>(s: S, - v: @syntax::ast::def) { - - s.emit_box(/*syntax::ast::def*/{|| serialize_161(s, *v) }); -} -/*syntax::ast::def*/ -fn serialize_161<S: std::serialization::serializer>(s: S, - v: syntax::ast::def) { - - s.emit_enum("syntax::ast::def", - /*syntax::ast::def_id*//*syntax::ast::purity*/ - /*syntax::ast::node_id*/ - /*syntax::ast::def_id*/ - /*syntax::ast::def_id*/ - /*syntax::ast::def_id*/ - /*syntax::ast::node_id*/ - /*syntax::ast::mode<syntax::ast::rmode>*/ - /*syntax::ast::node_id*//*bool*/ - /*syntax::ast::def_id*//*syntax::ast::def_id*/ - /*syntax::ast::def_id*/ - /*syntax::ast::prim_ty*/ - /*syntax::ast::def_id*//*uint*/ - /*syntax::ast::node_id*/ - /*syntax::ast::def_id*/ - /*syntax::ast::node_id*//*@syntax::ast::def*/ - /*syntax::ast::node_id*/ - /*syntax::ast::def_id*/ - /*syntax::ast::def_id*//*syntax::ast::def_id*/ - /*syntax::ast::def_id*//*syntax::ast::def_id*/ - {|| - alt v { - syntax::ast::def_fn(v0, v1) { - s.emit_enum_variant("syntax::ast::def_fn", 0u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_43(s, - v1) - }) - } - }) - } - syntax::ast::def_self(v0) { - s.emit_enum_variant("syntax::ast::def_self", 1u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_27(s, - v0) - }) - } - }) - } - syntax::ast::def_mod(v0) { - s.emit_enum_variant("syntax::ast::def_mod", 2u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - syntax::ast::def_native_mod(v0) { - s.emit_enum_variant("syntax::ast::def_native_mod", 3u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - syntax::ast::def_const(v0) { - s.emit_enum_variant("syntax::ast::def_const", 4u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - syntax::ast::def_arg(v0, v1) { - s.emit_enum_variant("syntax::ast::def_arg", 5u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_27(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_41(s, - v1) - }) - } - }) - } - syntax::ast::def_local(v0, v1) { - s.emit_enum_variant("syntax::ast::def_local", 6u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_27(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_18(s, - v1) - }) - } - }) - } - syntax::ast::def_variant(v0, v1) { - s.emit_enum_variant("syntax::ast::def_variant", 7u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_162(s, - v1) - }) - } - }) - } - syntax::ast::def_ty(v0) { - s.emit_enum_variant("syntax::ast::def_ty", 8u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - syntax::ast::def_prim_ty(v0) { - s.emit_enum_variant("syntax::ast::def_prim_ty", 9u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_164(s, - v0) - }) - } - }) - } - syntax::ast::def_ty_param(v0, v1) { - s.emit_enum_variant("syntax::ast::def_ty_param", 10u, - 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_20(s, - v1) - }) - } - }) - } - syntax::ast::def_binding(v0) { - s.emit_enum_variant("syntax::ast::def_binding", 11u, - 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_27(s, - v0) - }) - } - }) - } - syntax::ast::def_use(v0) { - s.emit_enum_variant("syntax::ast::def_use", 12u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - syntax::ast::def_upvar(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::def_upvar", 13u, 3u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_27(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_165(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_27(s, - v2) - }) - } - }) - } - syntax::ast::def_class(v0) { - s.emit_enum_variant("syntax::ast::def_class", 14u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - syntax::ast::def_class_field(v0, v1) { - s.emit_enum_variant("syntax::ast::def_class_field", - 15u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_162(s, - v1) - }) - } - }) - } - syntax::ast::def_class_method(v0, v1) { - s.emit_enum_variant("syntax::ast::def_class_method", - 16u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_162(s, - v1) - }) - } - }) - } - } - }); -} -fn serialize_syntax_ast_def<S: std::serialization::serializer>(s: S, - v: - syntax::ast::def) { - serialize_161(s, v); -} -/*syntax::ast::crate_num*/ -fn deserialize_163<S: std::serialization::deserializer>(s: S) -> - syntax::ast::crate_num { - s.read_int() -} -/*syntax::ast::def_id*/ -fn deserialize_162<S: std::serialization::deserializer>(s: S) -> - syntax::ast::def_id { - - s.read_rec( - - - /*syntax::ast::crate_num*/ - - /*syntax::ast::node_id*/ - - {|| - {crate: - s.read_rec_field("crate", 0u, - {|| deserialize_163(s) }), - node: - s.read_rec_field("node", 1u, - {|| deserialize_27(s) }),} - }) - -} -/*syntax::ast::prim_ty*/ -fn deserialize_164<S: std::serialization::deserializer>(s: S) -> - syntax::ast::prim_ty { - s.read_enum("syntax::ast::prim_ty", - /*syntax::ast::int_ty*/ - - /*syntax::ast::uint_ty*/ - - /*syntax::ast::float_ty*/ - - - - - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::ty_int(s.read_enum_variant_arg(0u, - {|| - deserialize_14(s) - })) - } - 1u { - syntax::ast::ty_uint(s.read_enum_variant_arg(0u, - {|| - deserialize_16(s) - })) - } - 2u { - syntax::ast::ty_float(s.read_enum_variant_arg(0u, - {|| - deserialize_17(s) - })) - } - 3u { syntax::ast::ty_str } - 4u { syntax::ast::ty_bool } - } - }) - }) -} -/*@syntax::ast::def*/ -fn deserialize_165<S: std::serialization::deserializer>(s: S) -> - @syntax::ast::def { - - s.read_box(/*syntax::ast::def*/{|| @deserialize_161(s) }) - -} -/*syntax::ast::def*/ -fn deserialize_161<S: std::serialization::deserializer>(s: S) -> - syntax::ast::def { - s.read_enum("syntax::ast::def", - /*syntax::ast::def_id*//*syntax::ast::purity*/ - - /*syntax::ast::node_id*/ - - /*syntax::ast::def_id*/ - - /*syntax::ast::def_id*/ - - /*syntax::ast::def_id*/ - - /*syntax::ast::node_id*/ - /*syntax::ast::mode<syntax::ast::rmode>*/ - - /*syntax::ast::node_id*//*bool*/ - - /*syntax::ast::def_id*//*syntax::ast::def_id*/ - - /*syntax::ast::def_id*/ - - /*syntax::ast::prim_ty*/ - - /*syntax::ast::def_id*//*uint*/ - - /*syntax::ast::node_id*/ - - /*syntax::ast::def_id*/ - - /*syntax::ast::node_id*//*@syntax::ast::def*/ - /*syntax::ast::node_id*/ - - /*syntax::ast::def_id*/ - - /*syntax::ast::def_id*//*syntax::ast::def_id*/ - - /*syntax::ast::def_id*//*syntax::ast::def_id*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::def_fn(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_43(s) - })) - } - 1u { - syntax::ast::def_self(s.read_enum_variant_arg(0u, - {|| - deserialize_27(s) - })) - } - 2u { - syntax::ast::def_mod(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 3u { - syntax::ast::def_native_mod(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 4u { - syntax::ast::def_const(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 5u { - syntax::ast::def_arg(s.read_enum_variant_arg(0u, - {|| - deserialize_27(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_41(s) - })) - } - 6u { - syntax::ast::def_local(s.read_enum_variant_arg(0u, - {|| - deserialize_27(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_18(s) - })) - } - 7u { - syntax::ast::def_variant(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_162(s) - })) - } - 8u { - syntax::ast::def_ty(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 9u { - syntax::ast::def_prim_ty(s.read_enum_variant_arg(0u, - {|| - deserialize_164(s) - })) - } - 10u { - syntax::ast::def_ty_param(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_20(s) - })) - } - 11u { - syntax::ast::def_binding(s.read_enum_variant_arg(0u, - {|| - deserialize_27(s) - })) - } - 12u { - syntax::ast::def_use(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 13u { - syntax::ast::def_upvar(s.read_enum_variant_arg(0u, - {|| - deserialize_27(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_165(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_27(s) - })) - } - 14u { - syntax::ast::def_class(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 15u { - syntax::ast::def_class_field(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_162(s) - })) - } - 16u { - syntax::ast::def_class_method(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_162(s) - })) - } - } - }) - }) -} -fn deserialize_syntax_ast_def<S: std::serialization::deserializer>(s: S) -> - syntax::ast::def { - deserialize_161(s) -} -/*middle::typeck::method_origin*/ -fn serialize_166<S: std::serialization::serializer>(s: S, - v: - middle::typeck::method_origin) { - s.emit_enum("middle::typeck::method_origin", - /*syntax::ast::def_id*/ - /*syntax::ast::def_id*//*uint*//*uint*//*uint*/ - /*syntax::ast::def_id*//*uint*/ - {|| - alt v { - middle::typeck::method_static(v0) { - s.emit_enum_variant("middle::typeck::method_static", - 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }) - } - }) - } - middle::typeck::method_param(v0, v1, v2, v3) { - s.emit_enum_variant("middle::typeck::method_param", - 1u, 4u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_20(s, - v1) - }); - s.emit_enum_variant_arg(2u, - {|| - serialize_20(s, - v2) - }); - s.emit_enum_variant_arg(3u, - {|| - serialize_20(s, - v3) - }) - } - }) - } - middle::typeck::method_iface(v0, v1) { - s.emit_enum_variant("middle::typeck::method_iface", - 2u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_20(s, - v1) - }) - } - }) - } - } - }); -} -fn serialize_middle_typeck_method_origin<S: std::serialization::serializer>(s: - S, - v: - middle::typeck::method_origin) { - serialize_166(s, v); -} -/*middle::typeck::method_origin*/ -fn deserialize_166<S: std::serialization::deserializer>(s: S) -> - middle::typeck::method_origin { - s.read_enum("middle::typeck::method_origin", - /*syntax::ast::def_id*/ - - /*syntax::ast::def_id*//*uint*//*uint*//*uint*/ - - /*syntax::ast::def_id*//*uint*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - middle::typeck::method_static(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - })) - } - 1u { - middle::typeck::method_param(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_20(s) - }), - s.read_enum_variant_arg(2u, - {|| - deserialize_20(s) - }), - s.read_enum_variant_arg(3u, - {|| - deserialize_20(s) - })) - } - 2u { - middle::typeck::method_iface(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_20(s) - })) - } - } - }) - }) -} -fn deserialize_middle_typeck_method_origin<S: std::serialization::deserializer>(s: - S) - -> middle::typeck::method_origin { - deserialize_166(s) -} -/*middle::freevars::freevar_entry*/ -fn serialize_167<S: std::serialization::serializer>(s: S, - v: - middle::freevars::freevar_entry) { - s.emit_rec(/*syntax::ast::def*//*syntax::codemap::span*/ - {|| - { - s.emit_rec_field("def", 0u, - {|| serialize_161(s, v.def) }); - s.emit_rec_field("span", 1u, - {|| serialize_19(s, v.span) }) - } - }); -} -fn serialize_middle_freevars_freevar_entry<S: std::serialization::serializer>(s: - S, - v: - middle::freevars::freevar_entry) { - serialize_167(s, v); -} -/*middle::freevars::freevar_entry*/ -fn deserialize_167<S: std::serialization::deserializer>(s: S) -> - middle::freevars::freevar_entry { - - s.read_rec( - - - /*syntax::ast::def*/ - - /*syntax::codemap::span*/ - - {|| - {def: - s.read_rec_field("def", 0u, {|| deserialize_161(s) }), - span: - s.read_rec_field("span", 1u, - {|| deserialize_19(s) }),} - }) - -} -fn deserialize_middle_freevars_freevar_entry<S: std::serialization::deserializer>(s: - S) - -> middle::freevars::freevar_entry { - deserialize_167(s) -} -fn serialize_syntax_ast_def_id<S: std::serialization::serializer>(s: S, - v: - syntax::ast::def_id) { - serialize_162(s, v); -} -fn deserialize_syntax_ast_def_id<S: std::serialization::deserializer>(s: S) -> - syntax::ast::def_id { - deserialize_162(s) -} -/*syntax::ast::inlined_item*/ -fn serialize_168<S: std::serialization::serializer>(s: S, - v: - syntax::ast::inlined_item) { - s.emit_enum("syntax::ast::inlined_item", - /*@syntax::ast::item*/ - /*syntax::ast::def_id*//*@syntax::ast::method*/ - {|| - alt v { - syntax::ast::ii_item(v0) { - s.emit_enum_variant("syntax::ast::ii_item", 0u, 1u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_117(s, - v0) - }) - } - }) - } - syntax::ast::ii_method(v0, v1) { - s.emit_enum_variant("syntax::ast::ii_method", 1u, 2u, - {|| - { - s.emit_enum_variant_arg(0u, - {|| - serialize_162(s, - v0) - }); - s.emit_enum_variant_arg(1u, - {|| - serialize_159(s, - v1) - }) - } - }) - } - } - }); -} -fn serialize_syntax_ast_inlined_item<S: std::serialization::serializer>(s: S, - v: - syntax::ast::inlined_item) { - serialize_168(s, v); -} -/*syntax::ast::inlined_item*/ -fn deserialize_168<S: std::serialization::deserializer>(s: S) -> - syntax::ast::inlined_item { - s.read_enum("syntax::ast::inlined_item", - /*@syntax::ast::item*/ - - /*syntax::ast::def_id*//*@syntax::ast::method*/ - {|| - s.read_enum_variant({|v_id| - alt check v_id { - 0u { - syntax::ast::ii_item(s.read_enum_variant_arg(0u, - {|| - deserialize_117(s) - })) - } - 1u { - syntax::ast::ii_method(s.read_enum_variant_arg(0u, - {|| - deserialize_162(s) - }), - s.read_enum_variant_arg(1u, - {|| - deserialize_159(s) - })) - } - } - }) - }) -} -fn deserialize_syntax_ast_inlined_item<S: std::serialization::deserializer>(s: - S) - -> syntax::ast::inlined_item { - deserialize_168(s) -} diff --git a/src/comp/metadata/common.rs b/src/comp/metadata/common.rs deleted file mode 100644 index 4ccb3405560..00000000000 --- a/src/comp/metadata/common.rs +++ /dev/null @@ -1,112 +0,0 @@ -// EBML enum definitions and utils shared by the encoder and decoder - -const tag_paths: uint = 0x01u; - -const tag_items: uint = 0x02u; - -const tag_paths_data: uint = 0x03u; - -const tag_paths_data_name: uint = 0x04u; - -const tag_paths_data_item: uint = 0x05u; - -const tag_paths_data_mod: uint = 0x06u; - -const tag_def_id: uint = 0x07u; - -const tag_items_data: uint = 0x08u; - -const tag_items_data_item: uint = 0x09u; - -const tag_items_data_item_family: uint = 0x0au; - -const tag_items_data_item_ty_param_bounds: uint = 0x0bu; - -const tag_items_data_item_type: uint = 0x0cu; - -const tag_items_data_item_symbol: uint = 0x0du; - -const tag_items_data_item_variant: uint = 0x0eu; - -const tag_items_data_item_enum_id: uint = 0x0fu; - -const tag_index: uint = 0x11u; - -const tag_index_buckets: uint = 0x12u; - -const tag_index_buckets_bucket: uint = 0x13u; - -const tag_index_buckets_bucket_elt: uint = 0x14u; - -const tag_index_table: uint = 0x15u; - -const tag_meta_item_name_value: uint = 0x18u; - -const tag_meta_item_name: uint = 0x19u; - -const tag_meta_item_value: uint = 0x20u; - -const tag_attributes: uint = 0x21u; - -const tag_attribute: uint = 0x22u; - -const tag_meta_item_word: uint = 0x23u; - -const tag_meta_item_list: uint = 0x24u; - -// The list of crates that this crate depends on -const tag_crate_deps: uint = 0x25u; - -// A single crate dependency -const tag_crate_dep: uint = 0x26u; - -const tag_crate_hash: uint = 0x28u; - -const tag_mod_impl: uint = 0x30u; - -const tag_item_method: uint = 0x31u; -const tag_impl_iface: uint = 0x32u; - -// discriminator value for variants -const tag_disr_val: uint = 0x34u; - -// used to encode ast_map::path and ast_map::path_elt -const tag_path: uint = 0x40u; -const tag_path_len: uint = 0x41u; -const tag_path_elt_mod: uint = 0x42u; -const tag_path_elt_name: uint = 0x43u; - -// used to encode crate_ctxt side tables -enum astencode_tag { // Reserves 0x50 -- 0x6f - tag_ast = 0x50, - - tag_tree = 0x51, - - tag_id_range = 0x52, - - tag_table = 0x53, - tag_table_id = 0x54, - tag_table_val = 0x55, - tag_table_def = 0x56, - tag_table_node_type = 0x57, - tag_table_node_type_subst = 0x58, - tag_table_freevars = 0x59, - tag_table_tcache, - tag_table_param_bounds, - tag_table_inferred_modes, - tag_table_mutbl, - tag_table_copy, - tag_table_last_use, - tag_table_method_map, - tag_table_dict_map -} - -// djb's cdb hashes. -fn hash_node_id(&&node_id: int) -> uint { ret 177573u ^ (node_id as uint); } - -fn hash_path(&&s: str) -> uint { - let h = 5381u; - for ch: u8 in str::bytes(s) { h = (h << 5u) + h ^ (ch as uint); } - ret h; -} - diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs deleted file mode 100644 index 6222fc91e2c..00000000000 --- a/src/comp/metadata/creader.rs +++ /dev/null @@ -1,307 +0,0 @@ -// Extracting metadata from crate files - -import driver::session; -import session::session; -import syntax::{ast, ast_util}; -import lib::llvm::{False, llvm, mk_object_file, mk_section_iter}; -import front::attr; -import syntax::visit; -import syntax::codemap::span; -import util::{filesearch}; -import std::{io, fs}; -import io::writer_util; -import std::map::{hashmap, new_int_hash}; -import syntax::print::pprust; -import common::*; - -export read_crates; -export list_file_metadata; - -// Traverses an AST, reading all the information about use'd crates and native -// libraries necessary for later resolving, typechecking, linking, etc. -fn read_crates(sess: session::session, crate: ast::crate) { - let e = @{sess: sess, - crate_cache: std::map::new_str_hash::<int>(), - mutable next_crate_num: 1}; - let v = - visit::mk_simple_visitor(@{visit_view_item: - bind visit_view_item(e, _), - visit_item: bind visit_item(e, _) - with *visit::default_simple_visitor()}); - visit::visit_crate(crate, (), v); -} - -type env = @{sess: session::session, - crate_cache: hashmap<str, int>, - mutable next_crate_num: ast::crate_num}; - -fn visit_view_item(e: env, i: @ast::view_item) { - alt i.node { - ast::view_item_use(ident, meta_items, id) { - let cnum = resolve_crate(e, ident, meta_items, i.span); - cstore::add_use_stmt_cnum(e.sess.cstore, id, cnum); - } - _ { } - } -} - -fn visit_item(e: env, i: @ast::item) { - alt i.node { - ast::item_native_mod(m) { - alt attr::native_abi(i.attrs) { - either::right(abi) { - if abi != ast::native_abi_cdecl && - abi != ast::native_abi_stdcall { ret; } - } - either::left(msg) { e.sess.span_fatal(i.span, msg); } - } - - let cstore = e.sess.cstore; - let native_name = - alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") { - some(nn) { - if nn == "" { - e.sess.span_fatal( - i.span, - "empty #[link_name] not allowed; use #[nolink]."); - } - nn - } - none { i.ident } - }; - let already_added = false; - if vec::len(attr::find_attrs_by_name(i.attrs, "nolink")) == 0u { - already_added = !cstore::add_used_library(cstore, native_name); - } - let link_args = attr::find_attrs_by_name(i.attrs, "link_args"); - if vec::len(link_args) > 0u && already_added { - e.sess.span_fatal(i.span, "library '" + native_name + - "' already added: can't specify link_args."); - } - for a: ast::attribute in link_args { - alt attr::get_meta_item_value_str(attr::attr_meta(a)) { - some(linkarg) { - cstore::add_used_link_args(cstore, linkarg); - } - none {/* fallthrough */ } - } - } - } - _ { } - } -} - -// A diagnostic function for dumping crate metadata to an output stream -fn list_file_metadata(sess: session::session, path: str, out: io::writer) { - alt get_metadata_section(sess, path) { - option::some(bytes) { decoder::list_crate_metadata(bytes, out); } - option::none { - out.write_str("Could not find metadata in " + path + ".\n"); - } - } -} - -fn metadata_matches(crate_data: @[u8], metas: [@ast::meta_item]) -> bool { - let attrs = decoder::get_crate_attributes(crate_data); - let linkage_metas = attr::find_linkage_metas(attrs); - - #debug("matching %u metadata requirements against %u items", - vec::len(metas), vec::len(linkage_metas)); - - #debug("crate metadata:"); - for have: @ast::meta_item in linkage_metas { - #debug(" %s", pprust::meta_item_to_str(*have)); - } - - for needed: @ast::meta_item in metas { - #debug("looking for %s", pprust::meta_item_to_str(*needed)); - if !attr::contains(linkage_metas, needed) { - #debug("missing %s", pprust::meta_item_to_str(*needed)); - ret false; - } - } - ret true; -} - -fn default_native_lib_naming(sess: session::session, static: bool) -> - {prefix: str, suffix: str} { - if static { ret {prefix: "lib", suffix: ".rlib"}; } - alt sess.targ_cfg.os { - session::os_win32 { ret {prefix: "", suffix: ".dll"}; } - session::os_macos { ret {prefix: "lib", suffix: ".dylib"}; } - session::os_linux { ret {prefix: "lib", suffix: ".so"}; } - session::os_freebsd { ret {prefix: "lib", suffix: ".so"}; } - } -} - -fn find_library_crate(sess: session::session, ident: ast::ident, - metas: [@ast::meta_item]) - -> option<{ident: str, data: @[u8]}> { - - attr::require_unique_names(sess, metas); - let metas = metas; - - let crate_name = - { - let name_items = attr::find_meta_items_by_name(metas, "name"); - alt vec::last(name_items) { - some(i) { - alt attr::get_meta_item_value_str(i) { - some(n) { n } - // FIXME: Probably want a warning here since the user - // is using the wrong type of meta item - _ { ident } - } - } - none { ident } - } - }; - - let nn = default_native_lib_naming(sess, sess.opts.static); - let x = - find_library_crate_aux(sess, nn, crate_name, - metas, sess.filesearch); - if x != none || sess.opts.static { ret x; } - let nn2 = default_native_lib_naming(sess, true); - ret find_library_crate_aux(sess, nn2, crate_name, metas, - sess.filesearch); -} - -fn find_library_crate_aux(sess: session::session, - nn: {prefix: str, suffix: str}, - crate_name: str, - metas: [@ast::meta_item], - filesearch: filesearch::filesearch) -> - option<{ident: str, data: @[u8]}> { - let prefix: str = nn.prefix + crate_name + "-"; - let suffix: str = nn.suffix; - - ret filesearch::search(filesearch, { |path| - #debug("inspecting file %s", path); - let f: str = fs::basename(path); - if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) { - #debug("skipping %s, doesn't look like %s*%s", path, prefix, - suffix); - option::none - } else { - #debug("%s is a candidate", path); - alt get_metadata_section(sess, path) { - option::some(cvec) { - if !metadata_matches(cvec, metas) { - #debug("skipping %s, metadata doesn't match", path); - option::none - } else { - #debug("found %s with matching metadata", path); - option::some({ident: path, data: cvec}) - } - } - _ { - #debug("could not load metadata for %s", path); - option::none - } - } - } - }); -} - -fn get_metadata_section(sess: session::session, - filename: str) -> option<@[u8]> unsafe { - let mb = str::as_buf(filename, {|buf| - llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf) - }); - if mb as int == 0 { ret option::none::<@[u8]>; } - let of = alt mk_object_file(mb) { - option::some(of) { of } - _ { ret option::none::<@[u8]>; } - }; - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let name_buf = llvm::LLVMGetSectionName(si.llsi); - let name = unsafe { str::from_cstr(name_buf) }; - if str::eq(name, sess.targ_cfg.target_strs.meta_sect_name) { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; - unsafe { - let cvbuf: *u8 = unsafe::reinterpret_cast(cbuf); - ret option::some::<@[u8]>(@vec::unsafe::from_buf(cvbuf, csz)); - } - } - llvm::LLVMMoveToNextSection(si.llsi); - } - ret option::none::<@[u8]>; -} - -fn load_library_crate(sess: session::session, span: span, ident: ast::ident, - metas: [@ast::meta_item]) - -> {ident: str, data: @[u8]} { - - - alt find_library_crate(sess, ident, metas) { - some(t) { ret t; } - none { - sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]); - } - } -} - -fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item], - span: span) -> ast::crate_num { - if !e.crate_cache.contains_key(ident) { - let cinfo = - load_library_crate(e.sess, span, ident, metas); - - let cfilename = cinfo.ident; - let cdata = cinfo.data; - - // Claim this crate number and cache it - let cnum = e.next_crate_num; - e.crate_cache.insert(ident, cnum); - e.next_crate_num += 1; - - // Now resolve the crates referenced by this crate - let cnum_map = resolve_crate_deps(e, cdata); - - let cmeta = @{name: ident, data: cdata, - cnum_map: cnum_map, cnum: cnum}; - - let cstore = e.sess.cstore; - cstore::set_crate_data(cstore, cnum, cmeta); - cstore::add_used_crate_file(cstore, cfilename); - ret cnum; - } else { ret e.crate_cache.get(ident); } -} - -// Go through the crate metadata and load any crates that it references -fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map { - #debug("resolving deps of external crate"); - // The map from crate numbers in the crate we're resolving to local crate - // numbers - let cnum_map = new_int_hash::<ast::crate_num>(); - for dep: decoder::crate_dep in decoder::get_crate_deps(cdata) { - let extrn_cnum = dep.cnum; - let cname = dep.ident; - #debug("resolving dep %s", cname); - if e.crate_cache.contains_key(cname) { - #debug("already have it"); - // We've already seen this crate - let local_cnum = e.crate_cache.get(cname); - cnum_map.insert(extrn_cnum, local_cnum); - } else { - #debug("need to load it"); - // This is a new one so we've got to load it - // FIXME: Need better error reporting than just a bogus span - let fake_span = ast_util::dummy_sp(); - let local_cnum = resolve_crate(e, cname, [], fake_span); - cnum_map.insert(extrn_cnum, local_cnum); - } - } - ret cnum_map; -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/metadata/csearch.rs b/src/comp/metadata/csearch.rs deleted file mode 100644 index 7dbf8dde75a..00000000000 --- a/src/comp/metadata/csearch.rs +++ /dev/null @@ -1,126 +0,0 @@ -// Searching for information from the cstore - -import syntax::ast; -import syntax::ast_util; -import middle::{ty, ast_map}; -import option::{some, none}; -import driver::session; -import middle::trans::common::maps; - -export get_symbol; -export get_type_param_count; -export lookup_defs; -export lookup_method_purity; -export get_enum_variants; -export get_impls_for_mod; -export get_iface_methods; -export get_type; -export get_impl_iface; -export get_item_path; -export maybe_get_item_ast; - -fn get_symbol(cstore: cstore::cstore, def: ast::def_id) -> str { - let cdata = cstore::get_crate_data(cstore, def.crate).data; - ret decoder::get_symbol(cdata, def.node); -} - -fn get_type_param_count(cstore: cstore::cstore, def: ast::def_id) -> uint { - let cdata = cstore::get_crate_data(cstore, def.crate).data; - ret decoder::get_type_param_count(cdata, def.node); -} - -fn lookup_defs(cstore: cstore::cstore, cnum: ast::crate_num, - path: [ast::ident]) -> [ast::def] { - let result = []; - for (c, data, def) in resolve_path(cstore, cnum, path) { - result += [decoder::lookup_def(c, data, def)]; - } - ret result; -} - -fn lookup_method_purity(cstore: cstore::cstore, did: ast::def_id) - -> ast::purity { - let cdata = cstore::get_crate_data(cstore, did.crate).data; - alt check decoder::lookup_def(did.crate, cdata, did) { - ast::def_fn(_, p) { p } - } -} - -fn resolve_path(cstore: cstore::cstore, cnum: ast::crate_num, - path: [ast::ident]) -> - [(ast::crate_num, @[u8], ast::def_id)] { - let cm = cstore::get_crate_data(cstore, cnum); - #debug("resolve_path %s in crates[%d]:%s", - str::connect(path, "::"), cnum, cm.name); - let result = []; - for def in decoder::resolve_path(path, cm.data) { - if def.crate == ast::local_crate { - result += [(cnum, cm.data, def)]; - } else { - if cm.cnum_map.contains_key(def.crate) { - // This reexport is itself a reexport from anther crate - let next_cnum = cm.cnum_map.get(def.crate); - let next_cm_data = cstore::get_crate_data(cstore, next_cnum); - result += [(next_cnum, next_cm_data.data, def)]; - } - } - } - ret result; -} - -fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path { - let cstore = tcx.sess.cstore; - let cdata = cstore::get_crate_data(cstore, def.crate); - let path = decoder::get_item_path(cdata, def.node); - [ast_map::path_mod(cdata.name)] + path -} - -// Finds the AST for this item in the crate metadata, if any. If the item was -// not marked for inlining, then the AST will not be present and hence none -// will be returned. -fn maybe_get_item_ast(tcx: ty::ctxt, maps: maps, def: ast::def_id) - -> option<ast::inlined_item> { - let cstore = tcx.sess.cstore; - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::maybe_get_item_ast(cdata, tcx, maps, def.node) -} - -fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id) -> [ty::variant_info] { - let cstore = tcx.sess.cstore; - let cdata = cstore::get_crate_data(cstore, def.crate); - ret decoder::get_enum_variants(cdata, def.node, tcx) -} - -fn get_impls_for_mod(cstore: cstore::cstore, def: ast::def_id, - name: option<ast::ident>) - -> @[@middle::resolve::_impl] { - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_impls_for_mod(cdata, def.node, name) -} - -fn get_iface_methods(tcx: ty::ctxt, def: ast::def_id) -> @[ty::method] { - let cstore = tcx.sess.cstore; - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_iface_methods(cdata, def.node, tcx) -} - -fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_bounds_and_ty { - let cstore = tcx.sess.cstore; - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_type(cdata, def.node, tcx) -} - -fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id) - -> option<ty::t> { - let cstore = tcx.sess.cstore; - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_impl_iface(cdata, def.node, tcx) -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/metadata/cstore.rs b/src/comp/metadata/cstore.rs deleted file mode 100644 index e9dd1a010c5..00000000000 --- a/src/comp/metadata/cstore.rs +++ /dev/null @@ -1,175 +0,0 @@ -// The crate store - a central repo for information collected about external -// crates and libraries - -import std::map; -import syntax::ast; -import util::common::*; - -export cstore::{}; -export cnum_map; -export crate_metadata; -export mk_cstore; -export get_crate_data; -export set_crate_data; -export have_crate_data; -export iter_crate_data; -export add_used_crate_file; -export get_used_crate_files; -export add_used_library; -export get_used_libraries; -export add_used_link_args; -export get_used_link_args; -export add_use_stmt_cnum; -export find_use_stmt_cnum; -export get_dep_hashes; -export get_path; - - -// A map from external crate numbers (as decoded from some crate file) to -// local crate numbers (as generated during this session). Each external -// crate may refer to types in other external crates, and each has their -// own crate numbers. -type cnum_map = map::hashmap<ast::crate_num, ast::crate_num>; - -// Multiple items may have the same def_id in crate metadata. They may be -// renamed imports or reexports. This map keeps the "real" module path -// and def_id. -type mod_path_map = map::hashmap<ast::def_id, str>; - -type crate_metadata = @{name: str, - data: @[u8], - cnum_map: cnum_map, - cnum: ast::crate_num}; - -// This is a bit of an experiment at encapsulating the data in cstore. By -// keeping all the data in a non-exported enum variant, it's impossible for -// other modules to access the cstore's private data. This could also be -// achieved with an obj, but at the expense of a vtable. Not sure if this is a -// good pattern or not. -enum cstore { private(cstore_private), } - -type cstore_private = - @{metas: map::hashmap<ast::crate_num, crate_metadata>, - use_crate_map: use_crate_map, - mod_path_map: mod_path_map, - mutable used_crate_files: [str], - mutable used_libraries: [str], - mutable used_link_args: [str]}; - -// Map from node_id's of local use statements to crate numbers -type use_crate_map = map::hashmap<ast::node_id, ast::crate_num>; - -// Internal method to retrieve the data from the cstore -fn p(cstore: cstore) -> cstore_private { alt cstore { private(p) { p } } } - -fn mk_cstore() -> cstore { - let meta_cache = map::new_int_hash::<crate_metadata>(); - let crate_map = map::new_int_hash::<ast::crate_num>(); - let mod_path_map = new_def_hash(); - ret private(@{metas: meta_cache, - use_crate_map: crate_map, - mod_path_map: mod_path_map, - mutable used_crate_files: [], - mutable used_libraries: [], - mutable used_link_args: []}); -} - -fn get_crate_data(cstore: cstore, cnum: ast::crate_num) -> crate_metadata { - ret p(cstore).metas.get(cnum); -} - -fn set_crate_data(cstore: cstore, cnum: ast::crate_num, - data: crate_metadata) { - p(cstore).metas.insert(cnum, data); - vec::iter(decoder::get_crate_module_paths(data.data)) {|dp| - let (did, path) = dp; - let d = {crate: cnum, node: did.node}; - p(cstore).mod_path_map.insert(d, path); - } -} - -fn have_crate_data(cstore: cstore, cnum: ast::crate_num) -> bool { - ret p(cstore).metas.contains_key(cnum); -} - -fn iter_crate_data(cstore: cstore, i: fn(ast::crate_num, crate_metadata)) { - p(cstore).metas.items {|k,v| i(k, v);}; -} - -fn add_used_crate_file(cstore: cstore, lib: str) { - if !vec::contains(p(cstore).used_crate_files, lib) { - p(cstore).used_crate_files += [lib]; - } -} - -fn get_used_crate_files(cstore: cstore) -> [str] { - ret p(cstore).used_crate_files; -} - -fn add_used_library(cstore: cstore, lib: str) -> bool { - assert lib != ""; - - if vec::contains(p(cstore).used_libraries, lib) { ret false; } - p(cstore).used_libraries += [lib]; - ret true; -} - -fn get_used_libraries(cstore: cstore) -> [str] { - ret p(cstore).used_libraries; -} - -fn add_used_link_args(cstore: cstore, args: str) { - p(cstore).used_link_args += str::split_char(args, ' '); -} - -fn get_used_link_args(cstore: cstore) -> [str] { - ret p(cstore).used_link_args; -} - -fn add_use_stmt_cnum(cstore: cstore, use_id: ast::node_id, - cnum: ast::crate_num) { - p(cstore).use_crate_map.insert(use_id, cnum); -} - -fn find_use_stmt_cnum(cstore: cstore, - use_id: ast::node_id) -> option<ast::crate_num> { - p(cstore).use_crate_map.find(use_id) -} - -// returns hashes of crates directly used by this crate. Hashes are -// sorted by crate name. -fn get_dep_hashes(cstore: cstore) -> [str] { - type crate_hash = {name: str, hash: str}; - let result = []; - - p(cstore).use_crate_map.values {|cnum| - let cdata = cstore::get_crate_data(cstore, cnum); - let hash = decoder::get_crate_hash(cdata.data); - #debug("Add hash[%s]: %s", cdata.name, hash); - result += [{name: cdata.name, hash: hash}]; - }; - fn lteq(a: crate_hash, b: crate_hash) -> bool { - ret a.name <= b.name; - } - let sorted = std::sort::merge_sort(lteq, result); - #debug("sorted:"); - for x in sorted { - #debug(" hash[%s]: %s", x.name, x.hash); - } - fn mapper(ch: crate_hash) -> str { ret ch.hash; } - ret vec::map(sorted, mapper); -} - -fn get_path(cstore: cstore, d: ast::def_id) -> [str] { - alt p(cstore).mod_path_map.find(d) { - option::some(ds) { str::split_str(ds, "::") } - option::none { [] } - } -} -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs deleted file mode 100644 index 196789ee58c..00000000000 --- a/src/comp/metadata/decoder.rs +++ /dev/null @@ -1,577 +0,0 @@ -// Decoding metadata from a single crate's metadata - -import std::{ebml, map, io}; -import io::writer_util; -import syntax::{ast, ast_util}; -import driver::session::session; -import front::attr; -import middle::ty; -import middle::ast_map; -import common::*; -import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data}; -import syntax::print::pprust; -import cmd=cstore::crate_metadata; -import middle::trans::common::maps; - -export get_symbol; -export get_enum_variants; -export get_type; -export get_type_param_count; -export get_impl_iface; -export lookup_def; -export lookup_item_name; -export get_impl_iface; -export resolve_path; -export get_crate_attributes; -export list_crate_metadata; -export crate_dep; -export get_crate_deps; -export get_crate_hash; -export get_impls_for_mod; -export get_iface_methods; -export get_crate_module_paths; -export get_item_path; -export maybe_get_item_ast; - -// Used internally by astencode: -export translate_def_id; - -// A function that takes a def_id relative to the crate being searched and -// returns a def_id relative to the compilation environment, i.e. if we hit a -// def_id for an item defined in another crate, somebody needs to figure out -// what crate that's in and give us a def_id that makes sense for the current -// build. - -fn lookup_hash(d: ebml::doc, eq_fn: fn@([u8]) -> bool, hash: uint) -> - [ebml::doc] { - let index = ebml::get_doc(d, tag_index); - let table = ebml::get_doc(index, tag_index_table); - let hash_pos = table.start + hash % 256u * 4u; - let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4u) as uint; - let {tag:_, doc:bucket} = ebml::doc_at(d.data, pos); - // Awkward logic because we can't ret from foreach yet - - let result: [ebml::doc] = []; - let belt = tag_index_buckets_bucket_elt; - ebml::tagged_docs(bucket, belt) {|elt| - let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4u) as uint; - if eq_fn(vec::slice::<u8>(*elt.data, elt.start + 4u, elt.end)) { - result += [ebml::doc_at(d.data, pos).doc]; - } - }; - ret result; -} - -fn maybe_find_item(item_id: int, items: ebml::doc) -> option<ebml::doc> { - fn eq_item(bytes: [u8], item_id: int) -> bool { - ret io::u64_from_be_bytes(bytes, 0u, 4u) as int == item_id; - } - let eqer = bind eq_item(_, item_id); - let found = lookup_hash(items, eqer, hash_node_id(item_id)); - if vec::len(found) == 0u { - ret option::none::<ebml::doc>; - } else { ret option::some::<ebml::doc>(found[0]); } -} - -fn find_item(item_id: int, items: ebml::doc) -> ebml::doc { - ret option::get(maybe_find_item(item_id, items)); -} - -// Looks up an item in the given metadata and returns an ebml doc pointing -// to the item data. -fn lookup_item(item_id: int, data: @[u8]) -> ebml::doc { - let items = ebml::get_doc(ebml::new_doc(data), tag_items); - ret find_item(item_id, items); -} - -fn item_family(item: ebml::doc) -> char { - let fam = ebml::get_doc(item, tag_items_data_item_family); - ebml::doc_as_u8(fam) as char -} - -fn item_symbol(item: ebml::doc) -> str { - let sym = ebml::get_doc(item, tag_items_data_item_symbol); - ret str::from_bytes(ebml::doc_data(sym)); -} - -fn variant_enum_id(d: ebml::doc) -> ast::def_id { - let tagdoc = ebml::get_doc(d, tag_items_data_item_enum_id); - ret parse_def_id(ebml::doc_data(tagdoc)); -} - -fn variant_disr_val(d: ebml::doc) -> option<int> { - option::chain(ebml::maybe_get_doc(d, tag_disr_val)) {|val_doc| - int::parse_buf(ebml::doc_data(val_doc), 10u) - } -} - -fn doc_type(doc: ebml::doc, tcx: ty::ctxt, cdata: cmd) -> ty::t { - let tp = ebml::get_doc(doc, tag_items_data_item_type); - parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, {|did| - translate_def_id(cdata, did) - }) -} - -fn item_type(item_id: ast::def_id, item: ebml::doc, - tcx: ty::ctxt, cdata: cmd) -> ty::t { - let t = doc_type(item, tcx, cdata); - if family_names_type(item_family(item)) { - ty::mk_with_id(tcx, t, item_id) - } else { t } -} - -fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd) - -> option<ty::t> { - let result = none; - ebml::tagged_docs(item, tag_impl_iface) {|ity| - let t = parse_ty_data(ity.data, cdata.cnum, ity.start, tcx, {|did| - translate_def_id(cdata, did) - }); - result = some(t); - } - result -} - -fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd) - -> @[ty::param_bounds] { - let bounds = []; - ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p| - let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, {|did| - translate_def_id(cdata, did) - }); - bounds += [bd]; - } - @bounds -} - -fn item_ty_param_count(item: ebml::doc) -> uint { - let n = 0u; - ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds, - {|_p| n += 1u; }); - n -} - -fn enum_variant_ids(item: ebml::doc, cdata: cmd) -> [ast::def_id] { - let ids: [ast::def_id] = []; - let v = tag_items_data_item_variant; - ebml::tagged_docs(item, v) {|p| - let ext = parse_def_id(ebml::doc_data(p)); - ids += [{crate: cdata.cnum, node: ext.node}]; - }; - ret ids; -} - -// Given a path and serialized crate metadata, returns the ID of the -// definition the path refers to. -fn resolve_path(path: [ast::ident], data: @[u8]) -> [ast::def_id] { - fn eq_item(data: [u8], s: str) -> bool { - ret str::eq(str::from_bytes(data), s); - } - let s = str::connect(path, "::"); - let md = ebml::new_doc(data); - let paths = ebml::get_doc(md, tag_paths); - let eqer = bind eq_item(_, s); - let result: [ast::def_id] = []; - for doc: ebml::doc in lookup_hash(paths, eqer, hash_path(s)) { - let did_doc = ebml::get_doc(doc, tag_def_id); - result += [parse_def_id(ebml::doc_data(did_doc))]; - } - ret result; -} - -fn item_path(item_doc: ebml::doc) -> ast_map::path { - let path_doc = ebml::get_doc(item_doc, tag_path); - - let len_doc = ebml::get_doc(path_doc, tag_path_len); - let len = ebml::doc_as_u32(len_doc) as uint; - - let result = []; - vec::reserve(result, len); - - ebml::docs(path_doc) {|tag, elt_doc| - if tag == tag_path_elt_mod { - let str = ebml::doc_as_str(elt_doc); - result += [ast_map::path_mod(str)]; - } else if tag == tag_path_elt_name { - let str = ebml::doc_as_str(elt_doc); - result += [ast_map::path_name(str)]; - } else { - // ignore tag_path_len element - } - } - - ret result; -} - -fn item_name(item: ebml::doc) -> ast::ident { - let name = ebml::get_doc(item, tag_paths_data_name); - str::from_bytes(ebml::doc_data(name)) -} - -fn lookup_item_name(data: @[u8], id: ast::node_id) -> ast::ident { - item_name(lookup_item(id, data)) -} - -fn lookup_def(cnum: ast::crate_num, data: @[u8], did_: ast::def_id) -> - ast::def { - let item = lookup_item(did_.node, data); - let fam_ch = item_family(item); - let did = {crate: cnum, node: did_.node}; - // We treat references to enums as references to types. - alt check fam_ch { - 'c' { ast::def_const(did) } - 'u' { ast::def_fn(did, ast::unsafe_fn) } - 'f' { ast::def_fn(did, ast::impure_fn) } - 'p' { ast::def_fn(did, ast::pure_fn) } - 'y' { ast::def_ty(did) } - 't' { ast::def_ty(did) } - 'm' { ast::def_mod(did) } - 'n' { ast::def_native_mod(did) } - 'v' { - let tid = variant_enum_id(item); - tid = {crate: cnum, node: tid.node}; - ast::def_variant(tid, did) - } - 'I' { ast::def_ty(did) } - } -} - -fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> ty::ty_param_bounds_and_ty { - let item = lookup_item(id, cdata.data); - let t = item_type({crate: cdata.cnum, node: id}, item, tcx, cdata); - let tp_bounds = if family_has_type_params(item_family(item)) { - item_ty_param_bounds(item, tcx, cdata) - } else { @[] }; - ret {bounds: tp_bounds, ty: t}; -} - -fn get_type_param_count(data: @[u8], id: ast::node_id) -> uint { - item_ty_param_count(lookup_item(id, data)) -} - -fn get_impl_iface(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> option<ty::t> { - item_impl_iface(lookup_item(id, cdata.data), tcx, cdata) -} - -fn get_symbol(data: @[u8], id: ast::node_id) -> str { - ret item_symbol(lookup_item(id, data)); -} - -fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path { - item_path(lookup_item(id, cdata.data)) -} - -fn maybe_get_item_ast(cdata: cmd, tcx: ty::ctxt, maps: maps, - id: ast::node_id) -> option<ast::inlined_item> { - let item_doc = lookup_item(id, cdata.data); - let path = vec::init(item_path(item_doc)); - astencode::decode_inlined_item(cdata, tcx, maps, path, item_doc) -} - -fn get_enum_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> [ty::variant_info] { - let data = cdata.data; - let items = ebml::get_doc(ebml::new_doc(data), tag_items); - let item = find_item(id, items); - let infos: [ty::variant_info] = []; - let variant_ids = enum_variant_ids(item, cdata); - let disr_val = 0; - for did: ast::def_id in variant_ids { - let item = find_item(did.node, items); - let ctor_ty = item_type({crate: cdata.cnum, node: id}, item, - tcx, cdata); - let name = item_name(item); - let arg_tys: [ty::t] = []; - alt ty::get(ctor_ty).struct { - ty::ty_fn(f) { - for a: ty::arg in f.inputs { arg_tys += [a.ty]; } - } - _ { /* Nullary enum variant. */ } - } - alt variant_disr_val(item) { - some(val) { disr_val = val; } - _ { /* empty */ } - } - infos += [@{args: arg_tys, ctor_ty: ctor_ty, name: name, - id: did, disr_val: disr_val}]; - disr_val += 1; - } - ret infos; -} - -fn item_impl_methods(cdata: cmd, item: ebml::doc, base_tps: uint) - -> [@middle::resolve::method_info] { - let rslt = []; - ebml::tagged_docs(item, tag_item_method) {|doc| - let m_did = parse_def_id(ebml::doc_data(doc)); - let mth_item = lookup_item(m_did.node, cdata.data); - rslt += [@{did: translate_def_id(cdata, m_did), - n_tps: item_ty_param_count(mth_item) - base_tps, - ident: item_name(mth_item)}]; - } - rslt -} - -fn get_impls_for_mod(cdata: cmd, m_id: ast::node_id, - name: option<ast::ident>) - -> @[@middle::resolve::_impl] { - let data = cdata.data; - let mod_item = lookup_item(m_id, data), result = []; - ebml::tagged_docs(mod_item, tag_mod_impl) {|doc| - let did = translate_def_id(cdata, parse_def_id(ebml::doc_data(doc))); - let item = lookup_item(did.node, data), nm = item_name(item); - if alt name { some(n) { n == nm } none { true } } { - let base_tps = item_ty_param_count(item); - result += [@{did: did, ident: nm, - methods: item_impl_methods(cdata, item, base_tps)}]; - } - } - @result -} - -fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> @[ty::method] { - let data = cdata.data; - let item = lookup_item(id, data), result = []; - ebml::tagged_docs(item, tag_item_method) {|mth| - let bounds = item_ty_param_bounds(mth, tcx, cdata); - let name = item_name(mth); - let ty = doc_type(mth, tcx, cdata); - let fty = alt ty::get(ty).struct { ty::ty_fn(f) { f } - _ { tcx.sess.bug("get_iface_methods: id has non-function type"); - } }; - result += [{ident: name, tps: bounds, fty: fty, - purity: alt check item_family(mth) { - 'u' { ast::unsafe_fn } - 'f' { ast::impure_fn } - 'p' { ast::pure_fn } - }}]; - } - @result -} - -fn family_has_type_params(fam_ch: char) -> bool { - alt check fam_ch { - 'c' | 'T' | 'm' | 'n' { false } - 'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' { true } - } -} - -fn family_names_type(fam_ch: char) -> bool { - alt fam_ch { 'y' | 't' | 'I' { true } _ { false } } -} - -fn read_path(d: ebml::doc) -> {path: str, pos: uint} { - let desc = ebml::doc_data(d); - let pos = io::u64_from_be_bytes(desc, 0u, 4u) as uint; - let pathbytes = vec::slice::<u8>(desc, 4u, vec::len::<u8>(desc)); - let path = str::from_bytes(pathbytes); - ret {path: path, pos: pos}; -} - -fn describe_def(items: ebml::doc, id: ast::def_id) -> str { - if id.crate != ast::local_crate { ret "external"; } - ret item_family_to_str(item_family(find_item(id.node, items))); -} - -fn item_family_to_str(fam: char) -> str { - alt check fam { - 'c' { ret "const"; } - 'f' { ret "fn"; } - 'u' { ret "unsafe fn"; } - 'p' { ret "pure fn"; } - 'F' { ret "native fn"; } - 'U' { ret "unsafe native fn"; } - 'P' { ret "pure native fn"; } - 'y' { ret "type"; } - 'T' { ret "native type"; } - 't' { ret "type"; } - 'm' { ret "mod"; } - 'n' { ret "native mod"; } - 'v' { ret "enum"; } - 'i' { ret "impl"; } - 'I' { ret "iface"; } - } -} - -fn get_meta_items(md: ebml::doc) -> [@ast::meta_item] { - let items: [@ast::meta_item] = []; - ebml::tagged_docs(md, tag_meta_item_word) {|meta_item_doc| - let nd = ebml::get_doc(meta_item_doc, tag_meta_item_name); - let n = str::from_bytes(ebml::doc_data(nd)); - items += [attr::mk_word_item(n)]; - }; - ebml::tagged_docs(md, tag_meta_item_name_value) {|meta_item_doc| - let nd = ebml::get_doc(meta_item_doc, tag_meta_item_name); - let vd = ebml::get_doc(meta_item_doc, tag_meta_item_value); - let n = str::from_bytes(ebml::doc_data(nd)); - let v = str::from_bytes(ebml::doc_data(vd)); - // FIXME (#611): Should be able to decode meta_name_value variants, - // but currently they can't be encoded - items += [attr::mk_name_value_item_str(n, v)]; - }; - ebml::tagged_docs(md, tag_meta_item_list) {|meta_item_doc| - let nd = ebml::get_doc(meta_item_doc, tag_meta_item_name); - let n = str::from_bytes(ebml::doc_data(nd)); - let subitems = get_meta_items(meta_item_doc); - items += [attr::mk_list_item(n, subitems)]; - }; - ret items; -} - -fn get_attributes(md: ebml::doc) -> [ast::attribute] { - let attrs: [ast::attribute] = []; - alt ebml::maybe_get_doc(md, tag_attributes) { - option::some(attrs_d) { - ebml::tagged_docs(attrs_d, tag_attribute) {|attr_doc| - let meta_items = get_meta_items(attr_doc); - // Currently it's only possible to have a single meta item on - // an attribute - assert (vec::len(meta_items) == 1u); - let meta_item = meta_items[0]; - attrs += - [{node: {style: ast::attr_outer, value: *meta_item}, - span: ast_util::dummy_sp()}]; - }; - } - option::none { } - } - ret attrs; -} - -fn list_meta_items(meta_items: ebml::doc, out: io::writer) { - for mi: @ast::meta_item in get_meta_items(meta_items) { - out.write_str(#fmt["%s\n", pprust::meta_item_to_str(*mi)]); - } -} - -fn list_crate_attributes(md: ebml::doc, hash: str, out: io::writer) { - out.write_str(#fmt("=Crate Attributes (%s)=\n", hash)); - - for attr: ast::attribute in get_attributes(md) { - out.write_str(#fmt["%s\n", pprust::attribute_to_str(attr)]); - } - - out.write_str("\n\n"); -} - -fn get_crate_attributes(data: @[u8]) -> [ast::attribute] { - ret get_attributes(ebml::new_doc(data)); -} - -type crate_dep = {cnum: ast::crate_num, ident: str}; - -fn get_crate_deps(data: @[u8]) -> [crate_dep] { - let deps: [crate_dep] = []; - let cratedoc = ebml::new_doc(data); - let depsdoc = ebml::get_doc(cratedoc, tag_crate_deps); - let crate_num = 1; - ebml::tagged_docs(depsdoc, tag_crate_dep) {|depdoc| - let depname = str::from_bytes(ebml::doc_data(depdoc)); - deps += [{cnum: crate_num, ident: depname}]; - crate_num += 1; - }; - ret deps; -} - -fn list_crate_deps(data: @[u8], out: io::writer) { - out.write_str("=External Dependencies=\n"); - - for dep: crate_dep in get_crate_deps(data) { - out.write_str(#fmt["%d %s\n", dep.cnum, dep.ident]); - } - - out.write_str("\n"); -} - -fn get_crate_hash(data: @[u8]) -> str { - let cratedoc = ebml::new_doc(data); - let hashdoc = ebml::get_doc(cratedoc, tag_crate_hash); - ret str::from_bytes(ebml::doc_data(hashdoc)); -} - -fn list_crate_items(bytes: @[u8], md: ebml::doc, out: io::writer) { - out.write_str("=Items=\n"); - let items = ebml::get_doc(md, tag_items); - iter_crate_items(bytes) {|path, did| - out.write_str(#fmt["%s (%s)\n", path, describe_def(items, did)]); - } - out.write_str("\n"); -} - -fn iter_crate_items(bytes: @[u8], proc: fn(str, ast::def_id)) { - let md = ebml::new_doc(bytes); - let paths = ebml::get_doc(md, tag_paths); - let index = ebml::get_doc(paths, tag_index); - let bs = ebml::get_doc(index, tag_index_buckets); - ebml::tagged_docs(bs, tag_index_buckets_bucket) {|bucket| - let et = tag_index_buckets_bucket_elt; - ebml::tagged_docs(bucket, et) {|elt| - let data = read_path(elt); - let {tag:_, doc:def} = ebml::doc_at(bytes, data.pos); - let did_doc = ebml::get_doc(def, tag_def_id); - let did = parse_def_id(ebml::doc_data(did_doc)); - proc(data.path, did); - }; - }; -} - -fn get_crate_module_paths(bytes: @[u8]) -> [(ast::def_id, str)] { - fn mod_of_path(p: str) -> str { - str::connect(vec::init(str::split_str(p, "::")), "::") - } - - // find all module (path, def_ids), which are not - // fowarded path due to renamed import or reexport - let res = []; - let mods = map::new_str_hash(); - iter_crate_items(bytes) {|path, did| - let m = mod_of_path(path); - if str::is_not_empty(m) { - // if m has a sub-item, it must be a module - mods.insert(m, true); - } - // Collect everything by now. There might be multiple - // paths pointing to the same did. Those will be - // unified later by using the mods map - res += [(did, path)]; - } - ret vec::filter(res) {|x| - let (_, xp) = x; - mods.contains_key(xp) - } -} - -fn list_crate_metadata(bytes: @[u8], out: io::writer) { - let hash = get_crate_hash(bytes); - let md = ebml::new_doc(bytes); - list_crate_attributes(md, hash, out); - list_crate_deps(bytes, out); - list_crate_items(bytes, md, out); -} - -// Translates a def_id from an external crate to a def_id for the current -// compilation environment. We use this when trying to load types from -// external crates - if those types further refer to types in other crates -// then we must translate the crate number from that encoded in the external -// crate to the correct local crate number. -fn translate_def_id(cdata: cmd, did: ast::def_id) -> ast::def_id { - if did.crate == ast::local_crate { - ret {crate: cdata.cnum, node: did.node}; - } - - alt cdata.cnum_map.find(did.crate) { - option::some(n) { ret {crate: n, node: did.node}; } - option::none { fail "didn't find a crate in the cnum_map"; } - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs deleted file mode 100644 index 2da07511628..00000000000 --- a/src/comp/metadata/encoder.rs +++ /dev/null @@ -1,766 +0,0 @@ -// Metadata encoding - -import std::{io, ebml, map, list}; -import io::writer_util; -import ebml::writer; -import syntax::ast::*; -import syntax::print::pprust; -import syntax::ast_util; -import syntax::ast_util::local_def; -import common::*; -import middle::trans::common::crate_ctxt; -import middle::ty; -import middle::ty::node_id_to_type; -import middle::ast_map; -import front::attr; -import driver::session::session; -import std::serialization::serializer; - -export encode_metadata; -export encoded_ty; - -// used by astencode: -export def_to_str; -export encode_ctxt; -export write_type; -export encode_def_id; - -type abbrev_map = map::hashmap<ty::t, tyencode::ty_abbrev>; - -type encode_ctxt = {ccx: crate_ctxt, type_abbrevs: abbrev_map}; - -fn should_inline(_path: ast_map::path, attrs: [attribute]) -> bool { - attr::attrs_contains_name(attrs, "inline") -} - -// Path table encoding -fn encode_name(ebml_w: ebml::writer, name: str) { - ebml_w.wr_tagged_str(tag_paths_data_name, name); -} - -fn encode_def_id(ebml_w: ebml::writer, id: def_id) { - ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); -} - -fn encode_named_def_id(ebml_w: ebml::writer, name: str, id: def_id) { - ebml_w.wr_tag(tag_paths_data_item) {|| - encode_name(ebml_w, name); - encode_def_id(ebml_w, id); - } -} - -type entry<T> = {val: T, pos: uint}; - -fn encode_enum_variant_paths(ebml_w: ebml::writer, variants: [variant], - path: [str], &index: [entry<str>]) { - for variant: variant in variants { - add_to_index(ebml_w, path, index, variant.node.name); - ebml_w.wr_tag(tag_paths_data_item) {|| - encode_name(ebml_w, variant.node.name); - encode_def_id(ebml_w, local_def(variant.node.id)); - } - } -} - -fn add_to_index(ebml_w: ebml::writer, path: [str], &index: [entry<str>], - name: str) { - let full_path = path + [name]; - index += - [{val: str::connect(full_path, "::"), pos: ebml_w.writer.tell()}]; -} - -fn encode_native_module_item_paths(ebml_w: ebml::writer, nmod: native_mod, - path: [str], &index: [entry<str>]) { - for nitem: @native_item in nmod.items { - add_to_index(ebml_w, path, index, nitem.ident); - encode_named_def_id(ebml_w, nitem.ident, local_def(nitem.id)); - } -} - -fn encode_module_item_paths(ebml_w: ebml::writer, module: _mod, path: [str], - &index: [entry<str>]) { - // FIXME factor out add_to_index/start/encode_name/encode_def_id/end ops - for it: @item in module.items { - if !ast_util::is_exported(it.ident, module) { cont; } - alt it.node { - item_const(_, _) { - add_to_index(ebml_w, path, index, it.ident); - encode_named_def_id(ebml_w, it.ident, local_def(it.id)); - } - item_fn(_, tps, _) { - add_to_index(ebml_w, path, index, it.ident); - encode_named_def_id(ebml_w, it.ident, local_def(it.id)); - } - item_mod(_mod) { - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_mod); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(it.id)); - encode_module_item_paths(ebml_w, _mod, path + [it.ident], index); - ebml_w.end_tag(); - } - item_native_mod(nmod) { - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_mod); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(it.id)); - encode_native_module_item_paths(ebml_w, nmod, path + [it.ident], - index); - ebml_w.end_tag(); - } - item_ty(_, tps) { - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_item); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(it.id)); - ebml_w.end_tag(); - } - item_res(_, tps, _, _, ctor_id) { - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_item); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(ctor_id)); - ebml_w.end_tag(); - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_item); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(it.id)); - ebml_w.end_tag(); - } - item_class(_,_,_,_,_) { - fail "encode: implement item_class"; - } - item_enum(variants, tps) { - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_item); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(it.id)); - ebml_w.end_tag(); - encode_enum_variant_paths(ebml_w, variants, path, index); - } - item_iface(_, _) { - add_to_index(ebml_w, path, index, it.ident); - ebml_w.start_tag(tag_paths_data_item); - encode_name(ebml_w, it.ident); - encode_def_id(ebml_w, local_def(it.id)); - ebml_w.end_tag(); - } - item_impl(_, _, _, _) {} - } - } -} - -fn encode_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, crate: @crate) - -> [entry<str>] { - let index: [entry<str>] = []; - let path: [str] = []; - ebml_w.start_tag(tag_paths); - encode_module_item_paths(ebml_w, crate.node.module, path, index); - encode_reexport_paths(ebml_w, ecx, index); - ebml_w.end_tag(); - ret index; -} - -fn encode_reexport_paths(ebml_w: ebml::writer, - ecx: @encode_ctxt, &index: [entry<str>]) { - ecx.ccx.exp_map.items {|path, defs| - for def in *defs { - index += [{val: path, pos: ebml_w.writer.tell()}]; - ebml_w.start_tag(tag_paths_data_item); - encode_name(ebml_w, path); - encode_def_id(ebml_w, ast_util::def_id_of_def(def)); - ebml_w.end_tag(); - } - } -} - - -// Item info table encoding -fn encode_family(ebml_w: ebml::writer, c: char) { - ebml_w.start_tag(tag_items_data_item_family); - ebml_w.writer.write([c as u8]); - ebml_w.end_tag(); -} - -fn def_to_str(did: def_id) -> str { ret #fmt["%d:%d", did.crate, did.node]; } - -fn encode_type_param_bounds(ebml_w: ebml::writer, ecx: @encode_ctxt, - params: [ty_param]) { - let ty_str_ctxt = @{ds: def_to_str, - tcx: ecx.ccx.tcx, - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - for param in params { - ebml_w.start_tag(tag_items_data_item_ty_param_bounds); - let bs = ecx.ccx.tcx.ty_param_bounds.get(param.id); - tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, bs); - ebml_w.end_tag(); - } -} - -fn encode_variant_id(ebml_w: ebml::writer, vid: def_id) { - ebml_w.start_tag(tag_items_data_item_variant); - ebml_w.writer.write(str::bytes(def_to_str(vid))); - ebml_w.end_tag(); -} - -fn write_type(ecx: @encode_ctxt, ebml_w: ebml::writer, typ: ty::t) { - let ty_str_ctxt = - @{ds: def_to_str, - tcx: ecx.ccx.tcx, - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); -} - -fn encode_type(ecx: @encode_ctxt, ebml_w: ebml::writer, typ: ty::t) { - ebml_w.start_tag(tag_items_data_item_type); - write_type(ecx, ebml_w, typ); - ebml_w.end_tag(); -} - -fn encode_symbol(ecx: @encode_ctxt, ebml_w: ebml::writer, id: node_id) { - ebml_w.start_tag(tag_items_data_item_symbol); - ebml_w.writer.write(str::bytes(ecx.ccx.item_symbols.get(id))); - ebml_w.end_tag(); -} - -fn encode_discriminant(ecx: @encode_ctxt, ebml_w: ebml::writer, id: node_id) { - ebml_w.start_tag(tag_items_data_item_symbol); - ebml_w.writer.write(str::bytes(ecx.ccx.discrim_symbols.get(id))); - ebml_w.end_tag(); -} - -fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: ebml::writer, disr_val: int) { - ebml_w.start_tag(tag_disr_val); - ebml_w.writer.write(str::bytes(int::to_str(disr_val,10u))); - ebml_w.end_tag(); -} - -fn encode_enum_id(ebml_w: ebml::writer, id: def_id) { - ebml_w.start_tag(tag_items_data_item_enum_id); - ebml_w.writer.write(str::bytes(def_to_str(id))); - ebml_w.end_tag(); -} - -fn encode_enum_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer, - id: node_id, variants: [variant], - path: ast_map::path, &index: [entry<int>], - ty_params: [ty_param]) { - let disr_val = 0; - let i = 0; - let vi = ty::enum_variants(ecx.ccx.tcx, {crate: local_crate, node: id}); - for variant: variant in variants { - index += [{val: variant.node.id, pos: ebml_w.writer.tell()}]; - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(variant.node.id)); - encode_family(ebml_w, 'v'); - encode_name(ebml_w, variant.node.name); - encode_enum_id(ebml_w, local_def(id)); - encode_type(ecx, ebml_w, - node_id_to_type(ecx.ccx.tcx, variant.node.id)); - if vec::len::<variant_arg>(variant.node.args) > 0u { - encode_symbol(ecx, ebml_w, variant.node.id); - } - encode_discriminant(ecx, ebml_w, variant.node.id); - if vi[i].disr_val != disr_val { - encode_disr_val(ecx, ebml_w, vi[i].disr_val); - disr_val = vi[i].disr_val; - } - encode_type_param_bounds(ebml_w, ecx, ty_params); - encode_path(ebml_w, path, ast_map::path_name(variant.node.name)); - ebml_w.end_tag(); - disr_val += 1; - i += 1; - } -} - -fn encode_path(ebml_w: ebml::writer, - path: ast_map::path, - name: ast_map::path_elt) { - fn encode_path_elt(ebml_w: ebml::writer, elt: ast_map::path_elt) { - let (tag, name) = alt elt { - ast_map::path_mod(name) { (tag_path_elt_mod, name) } - ast_map::path_name(name) { (tag_path_elt_name, name) } - }; - - ebml_w.wr_tagged_str(tag, name); - } - - ebml_w.wr_tag(tag_path) {|| - ebml_w.wr_tagged_u32(tag_path_len, (vec::len(path) + 1u) as u32); - vec::iter(path) {|pe| encode_path_elt(ebml_w, pe); } - encode_path_elt(ebml_w, name); - } -} - -fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod, - id: node_id, path: ast_map::path, name: ident) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(id)); - encode_family(ebml_w, 'm'); - encode_name(ebml_w, name); - alt ecx.ccx.maps.impl_map.get(id) { - list::cons(impls, @list::nil) { - for i in *impls { - if ast_util::is_exported(i.ident, md) { - ebml_w.wr_tagged_str(tag_mod_impl, def_to_str(i.did)); - } - } - } - _ { ecx.ccx.tcx.sess.bug("encode_info_for_mod: \ - undocumented invariant"); } - } - encode_path(ebml_w, path, ast_map::path_mod(name)); - ebml_w.end_tag(); -} - -fn purity_fn_family(p: purity) -> char { - alt p { - unsafe_fn { 'u' } - pure_fn { 'p' } - impure_fn { 'f' } - crust_fn { 'c' } - } -} - -fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, - &index: [entry<int>], path: ast_map::path) { - let tcx = ecx.ccx.tcx; - alt item.node { - item_const(_, _) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'c'); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_symbol(ecx, ebml_w, item.id); - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - } - item_fn(decl, tps, _) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, purity_fn_family(decl.purity)); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_symbol(ecx, ebml_w, item.id); - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - if should_inline(path, item.attrs) { - astencode::encode_inlined_item(ecx, ebml_w, path, ii_item(item)); - } - ebml_w.end_tag(); - } - item_mod(m) { - encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); - } - item_native_mod(_) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'n'); - encode_name(ebml_w, item.ident); - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - } - item_ty(_, tps) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'y'); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ebml_w, item.ident); - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - } - item_enum(variants, tps) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 't'); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ebml_w, item.ident); - for v: variant in variants { - encode_variant_id(ebml_w, local_def(v.node.id)); - } - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - encode_enum_variant_info(ecx, ebml_w, item.id, variants, - path, index, tps); - } - item_class(_,_,_,_,_) { - fail "encode: implement item_class"; - } - item_res(_, tps, _, _, ctor_id) { - let fn_ty = node_id_to_type(tcx, ctor_id); - - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(ctor_id)); - encode_family(ebml_w, 'y'); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, ty::ty_fn_ret(fn_ty)); - encode_name(ebml_w, item.ident); - encode_symbol(ecx, ebml_w, item.id); - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - - index += [{val: ctor_id, pos: ebml_w.writer.tell()}]; - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(ctor_id)); - encode_family(ebml_w, 'f'); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, fn_ty); - encode_symbol(ecx, ebml_w, ctor_id); - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - } - item_impl(tps, ifce, _, methods) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'i'); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ebml_w, item.ident); - for m in methods { - ebml_w.start_tag(tag_item_method); - ebml_w.writer.write(str::bytes(def_to_str(local_def(m.id)))); - ebml_w.end_tag(); - } - alt ifce { - some(_) { - encode_symbol(ecx, ebml_w, item.id); - let i_ty = ty::lookup_item_type(tcx, local_def(item.id)).ty; - ebml_w.start_tag(tag_impl_iface); - write_type(ecx, ebml_w, i_ty); - ebml_w.end_tag(); - } - _ {} - } - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - - let impl_path = path + [ast_map::path_name(item.ident)]; - for m in methods { - index += [{val: m.id, pos: ebml_w.writer.tell()}]; - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(m.id)); - encode_family(ebml_w, purity_fn_family(m.decl.purity)); - encode_type_param_bounds(ebml_w, ecx, tps + m.tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id)); - encode_name(ebml_w, m.ident); - encode_symbol(ecx, ebml_w, m.id); - encode_path(ebml_w, impl_path, ast_map::path_name(m.ident)); - if should_inline(path, m.attrs) { - astencode::encode_inlined_item( - ecx, ebml_w, impl_path, - ii_method(local_def(item.id), m)); - } - ebml_w.end_tag(); - } - } - item_iface(tps, ms) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'I'); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ebml_w, item.ident); - let i = 0u; - for mty in *ty::iface_methods(tcx, local_def(item.id)) { - ebml_w.start_tag(tag_item_method); - encode_name(ebml_w, mty.ident); - encode_type_param_bounds(ebml_w, ecx, ms[i].tps); - encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty)); - encode_family(ebml_w, purity_fn_family(mty.purity)); - ebml_w.end_tag(); - i += 1u; - } - encode_path(ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - } - } -} - -fn encode_info_for_native_item(ecx: @encode_ctxt, ebml_w: ebml::writer, - nitem: @native_item, path: ast_map::path) { - ebml_w.start_tag(tag_items_data_item); - alt nitem.node { - native_item_fn(fn_decl, tps) { - encode_def_id(ebml_w, local_def(nitem.id)); - encode_family(ebml_w, purity_fn_family(fn_decl.purity)); - encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(ecx.ccx.tcx, nitem.id)); - encode_symbol(ecx, ebml_w, nitem.id); - encode_path(ebml_w, path, ast_map::path_name(nitem.ident)); - } - } - ebml_w.end_tag(); -} - -fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer, - crate_mod: _mod) -> [entry<int>] { - let index: [entry<int>] = []; - ebml_w.start_tag(tag_items_data); - index += [{val: crate_node_id, pos: ebml_w.writer.tell()}]; - encode_info_for_mod(ecx, ebml_w, crate_mod, crate_node_id, [], ""); - ecx.ccx.tcx.items.items {|key, val| - alt val { - middle::ast_map::node_item(i, path) { - index += [{val: key, pos: ebml_w.writer.tell()}]; - encode_info_for_item(ecx, ebml_w, i, index, *path); - } - middle::ast_map::node_native_item(i, path) { - index += [{val: key, pos: ebml_w.writer.tell()}]; - encode_info_for_native_item(ecx, ebml_w, i, *path); - } - _ { } - } - }; - ebml_w.end_tag(); - ret index; -} - - -// Path and definition ID indexing - -fn create_index<T: copy>(index: [entry<T>], hash_fn: fn@(T) -> uint) -> - [@[entry<T>]] { - let buckets: [@mutable [entry<T>]] = []; - uint::range(0u, 256u) {|_i| buckets += [@mutable []]; }; - for elt: entry<T> in index { - let h = hash_fn(elt.val); - *buckets[h % 256u] += [elt]; - } - - let buckets_frozen = []; - for bucket: @mutable [entry<T>] in buckets { - buckets_frozen += [@*bucket]; - } - ret buckets_frozen; -} - -fn encode_index<T>(ebml_w: ebml::writer, buckets: [@[entry<T>]], - write_fn: fn(io::writer, T)) { - let writer = ebml_w.writer; - ebml_w.start_tag(tag_index); - let bucket_locs: [uint] = []; - ebml_w.start_tag(tag_index_buckets); - for bucket: @[entry<T>] in buckets { - bucket_locs += [ebml_w.writer.tell()]; - ebml_w.start_tag(tag_index_buckets_bucket); - for elt: entry<T> in *bucket { - ebml_w.start_tag(tag_index_buckets_bucket_elt); - writer.write_be_uint(elt.pos, 4u); - write_fn(writer, elt.val); - ebml_w.end_tag(); - } - ebml_w.end_tag(); - } - ebml_w.end_tag(); - ebml_w.start_tag(tag_index_table); - for pos: uint in bucket_locs { writer.write_be_uint(pos, 4u); } - ebml_w.end_tag(); - ebml_w.end_tag(); -} - -fn write_str(writer: io::writer, &&s: str) { writer.write_str(s); } - -fn write_int(writer: io::writer, &&n: int) { - writer.write_be_uint(n as uint, 4u); -} - -fn encode_meta_item(ebml_w: ebml::writer, mi: meta_item) { - alt mi.node { - meta_word(name) { - ebml_w.start_tag(tag_meta_item_word); - ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(str::bytes(name)); - ebml_w.end_tag(); - ebml_w.end_tag(); - } - meta_name_value(name, value) { - alt value.node { - lit_str(value) { - ebml_w.start_tag(tag_meta_item_name_value); - ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(str::bytes(name)); - ebml_w.end_tag(); - ebml_w.start_tag(tag_meta_item_value); - ebml_w.writer.write(str::bytes(value)); - ebml_w.end_tag(); - ebml_w.end_tag(); - } - _ {/* FIXME (#611) */ } - } - } - meta_list(name, items) { - ebml_w.start_tag(tag_meta_item_list); - ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(str::bytes(name)); - ebml_w.end_tag(); - for inner_item: @meta_item in items { - encode_meta_item(ebml_w, *inner_item); - } - ebml_w.end_tag(); - } - } -} - -fn encode_attributes(ebml_w: ebml::writer, attrs: [attribute]) { - ebml_w.start_tag(tag_attributes); - for attr: attribute in attrs { - ebml_w.start_tag(tag_attribute); - encode_meta_item(ebml_w, attr.node.value); - ebml_w.end_tag(); - } - ebml_w.end_tag(); -} - -// So there's a special crate attribute called 'link' which defines the -// metadata that Rust cares about for linking crates. This attribute requires -// 'name' and 'vers' items, so if the user didn't provide them we will throw -// them in anyway with default values. -fn synthesize_crate_attrs(ecx: @encode_ctxt, crate: @crate) -> [attribute] { - - fn synthesize_link_attr(ecx: @encode_ctxt, items: [@meta_item]) -> - attribute { - - assert (ecx.ccx.link_meta.name != ""); - assert (ecx.ccx.link_meta.vers != ""); - - let name_item = - attr::mk_name_value_item_str("name", ecx.ccx.link_meta.name); - let vers_item = - attr::mk_name_value_item_str("vers", ecx.ccx.link_meta.vers); - - let other_items = - { - let tmp = attr::remove_meta_items_by_name(items, "name"); - attr::remove_meta_items_by_name(tmp, "vers") - }; - - let meta_items = [name_item, vers_item] + other_items; - let link_item = attr::mk_list_item("link", meta_items); - - ret attr::mk_attr(link_item); - } - - let attrs: [attribute] = []; - let found_link_attr = false; - for attr: attribute in crate.node.attrs { - attrs += - if attr::get_attr_name(attr) != "link" { - [attr] - } else { - alt attr.node.value.node { - meta_list(n, l) { - found_link_attr = true;; - [synthesize_link_attr(ecx, l)] - } - _ { [attr] } - } - }; - } - - if !found_link_attr { attrs += [synthesize_link_attr(ecx, [])]; } - - ret attrs; -} - -fn encode_crate_deps(ebml_w: ebml::writer, cstore: cstore::cstore) { - - fn get_ordered_names(cstore: cstore::cstore) -> [str] { - type hashkv = @{key: crate_num, val: cstore::crate_metadata}; - type numname = {crate: crate_num, ident: str}; - - // Pull the cnums and names out of cstore - let pairs: [mutable numname] = [mutable]; - cstore::iter_crate_data(cstore) {|key, val| - pairs += [mutable {crate: key, ident: val.name}]; - }; - - // Sort by cnum - fn lteq(kv1: numname, kv2: numname) -> bool { kv1.crate <= kv2.crate } - std::sort::quick_sort(lteq, pairs); - - // Sanity-check the crate numbers - let expected_cnum = 1; - for n: numname in pairs { - assert (n.crate == expected_cnum); - expected_cnum += 1; - } - - // Return just the names - fn name(kv: numname) -> str { kv.ident } - // mutable -> immutable hack for vec::map - let immpairs = vec::slice(pairs, 0u, vec::len(pairs)); - ret vec::map(immpairs, name); - } - - // We're just going to write a list of crate names, with the assumption - // that they are numbered 1 to n. - // FIXME: This is not nearly enough to support correct versioning - // but is enough to get transitive crate dependencies working. - ebml_w.start_tag(tag_crate_deps); - for cname: str in get_ordered_names(cstore) { - ebml_w.start_tag(tag_crate_dep); - ebml_w.writer.write(str::bytes(cname)); - ebml_w.end_tag(); - } - ebml_w.end_tag(); -} - -fn encode_hash(ebml_w: ebml::writer, hash: str) { - ebml_w.start_tag(tag_crate_hash); - ebml_w.writer.write(str::bytes(hash)); - ebml_w.end_tag(); -} - -fn encode_metadata(cx: crate_ctxt, crate: @crate) -> [u8] { - - let abbrevs = ty::new_ty_hash(); - let ecx = @{ccx: cx, type_abbrevs: abbrevs}; - - let buf = io::mk_mem_buffer(); - let buf_w = io::mem_buffer_writer(buf); - let ebml_w = ebml::mk_writer(buf_w); - - encode_hash(ebml_w, cx.link_meta.extras_hash); - - let crate_attrs = synthesize_crate_attrs(ecx, crate); - encode_attributes(ebml_w, crate_attrs); - - encode_crate_deps(ebml_w, cx.sess.cstore); - - // Encode and index the paths. - ebml_w.start_tag(tag_paths); - let paths_index = encode_item_paths(ebml_w, ecx, crate); - let paths_buckets = create_index(paths_index, hash_path); - encode_index(ebml_w, paths_buckets, write_str); - ebml_w.end_tag(); - - // Encode and index the items. - ebml_w.start_tag(tag_items); - let items_index = encode_info_for_items(ecx, ebml_w, crate.node.module); - let items_buckets = create_index(items_index, hash_node_id); - encode_index(ebml_w, items_buckets, write_int); - ebml_w.end_tag(); - - // Pad this, since something (LLVM, presumably) is cutting off the - // remaining % 4 bytes. - buf_w.write([0u8, 0u8, 0u8, 0u8]); - io::mem_buffer_buf(buf) -} - -// Get the encoded string for a type -fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> str { - let cx = @{ds: def_to_str, tcx: tcx, abbrevs: tyencode::ac_no_abbrevs}; - let buf = io::mk_mem_buffer(); - tyencode::enc_ty(io::mem_buffer_writer(buf), cx, t); - ret io::mem_buffer_str(buf); -} - - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs deleted file mode 100644 index 5d97777c0fb..00000000000 --- a/src/comp/metadata/tydecode.rs +++ /dev/null @@ -1,426 +0,0 @@ -// Type decoding - -import syntax::ast; -import syntax::ast::*; -import syntax::ast_util; -import syntax::ast_util::respan; -import middle::ty; - -export parse_ty_data, parse_def_id; -export parse_bounds_data; - -// Compact string representation for ty::t values. API ty_str & -// parse_from_str. Extra parameters are for converting to/from def_ids in the -// data buffer. Whatever format you choose should not contain pipe characters. - -// Callback to translate defs to strs or back: -type conv_did = fn(ast::def_id) -> ast::def_id; - -type pstate = {data: @[u8], crate: int, mutable pos: uint, tcx: ty::ctxt}; - -fn peek(st: @pstate) -> char { - st.data[st.pos] as char -} - -fn next(st: @pstate) -> char { - let ch = st.data[st.pos] as char; - st.pos = st.pos + 1u; - ret ch; -} - -fn next_byte(st: @pstate) -> u8 { - let b = st.data[st.pos]; - st.pos = st.pos + 1u; - ret b; -} - -fn parse_ident(st: @pstate, last: char) -> ast::ident { - fn is_last(b: char, c: char) -> bool { ret c == b; } - ret parse_ident_(st, bind is_last(last, _)); -} - -fn parse_ident_(st: @pstate, is_last: fn@(char) -> bool) -> - ast::ident { - let rslt = ""; - while !is_last(peek(st)) { - rslt += str::from_byte(next_byte(st)); - } - ret rslt; -} - - -fn parse_ty_data(data: @[u8], crate_num: int, pos: uint, tcx: ty::ctxt, - conv: conv_did) -> ty::t { - let st = @{data: data, crate: crate_num, mutable pos: pos, tcx: tcx}; - parse_ty(st, conv) -} - -fn parse_ret_ty(st: @pstate, conv: conv_did) -> (ast::ret_style, ty::t) { - alt peek(st) { - '!' { next(st); (ast::noreturn, ty::mk_bot(st.tcx)) } - _ { (ast::return_val, parse_ty(st, conv)) } - } -} - -fn parse_constrs(st: @pstate, conv: conv_did) -> [@ty::constr] { - let rslt: [@ty::constr] = []; - alt peek(st) { - ':' { - do { - next(st); - rslt += [parse_constr(st, conv, parse_constr_arg)]; - } while peek(st) == ';' - } - _ { } - } - ret rslt; -} - -// FIXME less copy-and-paste -fn parse_ty_constrs(st: @pstate, conv: conv_did) -> [@ty::type_constr] { - let rslt: [@ty::type_constr] = []; - alt peek(st) { - ':' { - do { - next(st); - rslt += [parse_constr(st, conv, parse_ty_constr_arg)]; - } while peek(st) == ';' - } - _ { } - } - ret rslt; -} - -fn parse_path(st: @pstate) -> @ast::path { - let idents: [ast::ident] = []; - fn is_last(c: char) -> bool { ret c == '(' || c == ':'; } - idents += [parse_ident_(st, is_last)]; - while true { - alt peek(st) { - ':' { next(st); next(st); } - c { - if c == '(' { - ret @respan(ast_util::dummy_sp(), - {global: false, idents: idents, types: []}); - } else { idents += [parse_ident_(st, is_last)]; } - } - } - } - fail "parse_path: ill-formed path"; -} - -fn parse_constr_arg(st: @pstate) -> ast::fn_constr_arg { - alt peek(st) { - '*' { st.pos += 1u; ret ast::carg_base; } - c { - - /* how will we disambiguate between - an arg index and a lit argument? */ - if c >= '0' && c <= '9' { - next(st); - // FIXME - ret ast::carg_ident((c as uint) - 48u); - } else { - #error("Lit args are unimplemented"); - fail; // FIXME - } - /* - else { - auto lit = parse_lit(st, conv, ','); - args += [respan(st.span, ast::carg_lit(lit))]; - } - */ - } - } -} - -fn parse_ty_constr_arg(st: @pstate) -> ast::constr_arg_general_<@path> { - alt peek(st) { - '*' { st.pos += 1u; ret ast::carg_base; } - c { ret ast::carg_ident(parse_path(st)); } - } -} - -fn parse_constr<T: copy>(st: @pstate, conv: conv_did, - pser: fn(@pstate) -> ast::constr_arg_general_<T>) - -> @ty::constr_general<T> { - let sp = ast_util::dummy_sp(); // FIXME: use a real span - let args: [@sp_constr_arg<T>] = []; - let pth = parse_path(st); - let ignore: char = next(st); - assert (ignore == '('); - let def = parse_def(st, conv); - let an_arg: constr_arg_general_<T>; - do { - an_arg = pser(st); - // FIXME use a real span - args += [@respan(sp, an_arg)]; - ignore = next(st); - } while ignore == ';' - assert (ignore == ')'); - ret @respan(sp, {path: pth, args: args, id: def}); -} - -fn parse_ty_rust_fn(st: @pstate, conv: conv_did, p: ast::proto) -> ty::t { - ret ty::mk_fn(st.tcx, {proto: p with parse_ty_fn(st, conv)}); -} - -fn parse_proto(c: char) -> ast::proto { - alt c { - '~' { ast::proto_uniq } - '@' { ast::proto_box } - '*' { ast::proto_any } - '&' { ast::proto_block } - 'n' { ast::proto_bare } - _ { fail "illegal fn type kind " + str::from_char(c); } - } -} - -fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { - alt check next(st) { - 'n' { ret ty::mk_nil(st.tcx); } - 'z' { ret ty::mk_bot(st.tcx); } - 'b' { ret ty::mk_bool(st.tcx); } - 'i' { ret ty::mk_int(st.tcx); } - 'u' { ret ty::mk_uint(st.tcx); } - 'l' { ret ty::mk_float(st.tcx); } - 'M' { - alt check next(st) { - 'b' { ret ty::mk_mach_uint(st.tcx, ast::ty_u8); } - 'w' { ret ty::mk_mach_uint(st.tcx, ast::ty_u16); } - 'l' { ret ty::mk_mach_uint(st.tcx, ast::ty_u32); } - 'd' { ret ty::mk_mach_uint(st.tcx, ast::ty_u64); } - 'B' { ret ty::mk_mach_int(st.tcx, ast::ty_i8); } - 'W' { ret ty::mk_mach_int(st.tcx, ast::ty_i16); } - 'L' { ret ty::mk_mach_int(st.tcx, ast::ty_i32); } - 'D' { ret ty::mk_mach_int(st.tcx, ast::ty_i64); } - 'f' { ret ty::mk_mach_float(st.tcx, ast::ty_f32); } - 'F' { ret ty::mk_mach_float(st.tcx, ast::ty_f64); } - } - } - 'c' { ret ty::mk_char(st.tcx); } - 'S' { ret ty::mk_str(st.tcx); } - 't' { - assert (next(st) == '['); - let def = parse_def(st, conv); - let params: [ty::t] = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos = st.pos + 1u; - ret ty::mk_enum(st.tcx, def, params); - } - 'x' { - assert (next(st) == '['); - let def = parse_def(st, conv); - let params: [ty::t] = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos = st.pos + 1u; - ret ty::mk_iface(st.tcx, def, params); - } - 'p' { - let did = parse_def(st, conv); - ret ty::mk_param(st.tcx, parse_int(st) as uint, did); - } - 's' { - assert next(st) == '['; - let params = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos += 1u; - ret ty::mk_self(st.tcx, params); - } - '@' { ret ty::mk_box(st.tcx, parse_mt(st, conv)); } - '~' { ret ty::mk_uniq(st.tcx, parse_mt(st, conv)); } - '*' { ret ty::mk_ptr(st.tcx, parse_mt(st, conv)); } - 'I' { ret ty::mk_vec(st.tcx, parse_mt(st, conv)); } - 'R' { - assert (next(st) == '['); - let fields: [ty::field] = []; - while peek(st) != ']' { - let name = ""; - while peek(st) != '=' { - name += str::from_byte(next_byte(st)); - } - st.pos = st.pos + 1u; - fields += [{ident: name, mt: parse_mt(st, conv)}]; - } - st.pos = st.pos + 1u; - ret ty::mk_rec(st.tcx, fields); - } - 'T' { - assert (next(st) == '['); - let params = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos = st.pos + 1u; - ret ty::mk_tup(st.tcx, params); - } - 'f' { - let proto = parse_proto(next(st)); - parse_ty_rust_fn(st, conv, proto) - } - 'r' { - assert (next(st) == '['); - let def = parse_def(st, conv); - let inner = parse_ty(st, conv); - let params: [ty::t] = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos = st.pos + 1u; - ret ty::mk_res(st.tcx, def, inner, params); - } - 'X' { ret ty::mk_var(st.tcx, parse_int(st)); } - 'Y' { ret ty::mk_type(st.tcx); } - 'y' { ret ty::mk_send_type(st.tcx); } - 'C' { - let ck = alt check next(st) { - '&' { ty::ck_block } - '@' { ty::ck_box } - '~' { ty::ck_uniq } - }; - ret ty::mk_opaque_closure_ptr(st.tcx, ck); - } - '#' { - let pos = parse_hex(st); - assert (next(st) == ':'); - let len = parse_hex(st); - assert (next(st) == '#'); - alt st.tcx.rcache.find({cnum: st.crate, pos: pos, len: len}) { - some(tt) { ret tt; } - none { - let ps = @{pos: pos with *st}; - let tt = parse_ty(ps, conv); - st.tcx.rcache.insert({cnum: st.crate, pos: pos, len: len}, tt); - ret tt; - } - } - } - 'A' { - assert (next(st) == '['); - let tt = parse_ty(st, conv); - let tcs = parse_ty_constrs(st, conv); - assert (next(st) == ']'); - ret ty::mk_constr(st.tcx, tt, tcs); - } - '"' { - let def = parse_def(st, conv); - let inner = parse_ty(st, conv); - ty::mk_with_id(st.tcx, inner, def) - } - 'B' { ty::mk_opaque_box(st.tcx) } - c { #error("unexpected char in type string: %c", c); fail;} - } -} - -fn parse_mt(st: @pstate, conv: conv_did) -> ty::mt { - let m; - alt peek(st) { - 'm' { next(st); m = ast::m_mutbl; } - '?' { next(st); m = ast::m_const; } - _ { m = ast::m_imm; } - } - ret {ty: parse_ty(st, conv), mutbl: m}; -} - -fn parse_def(st: @pstate, conv: conv_did) -> ast::def_id { - let def = []; - while peek(st) != '|' { def += [next_byte(st)]; } - st.pos = st.pos + 1u; - ret conv(parse_def_id(def)); -} - -fn parse_int(st: @pstate) -> int { - let n = 0; - while true { - let cur = peek(st); - if cur < '0' || cur > '9' { break; } - st.pos = st.pos + 1u; - n *= 10; - n += (cur as int) - ('0' as int); - } - ret n; -} - -fn parse_hex(st: @pstate) -> uint { - let n = 0u; - while true { - let cur = peek(st); - if (cur < '0' || cur > '9') && (cur < 'a' || cur > 'f') { break; } - st.pos = st.pos + 1u; - n *= 16u; - if '0' <= cur && cur <= '9' { - n += (cur as uint) - ('0' as uint); - } else { n += 10u + (cur as uint) - ('a' as uint); } - } - ret n; -} - -fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty { - assert (next(st) == '['); - let inputs: [ty::arg] = []; - while peek(st) != ']' { - let mode = alt check peek(st) { - '&' { ast::by_mutbl_ref } - '-' { ast::by_move } - '+' { ast::by_copy } - '=' { ast::by_ref } - '#' { ast::by_val } - }; - st.pos += 1u; - inputs += [{mode: ast::expl(mode), ty: parse_ty(st, conv)}]; - } - st.pos += 1u; // eat the ']' - let cs = parse_constrs(st, conv); - let (ret_style, ret_ty) = parse_ret_ty(st, conv); - ret {proto: ast::proto_bare, inputs: inputs, output: ret_ty, - ret_style: ret_style, constraints: cs}; -} - - -// Rust metadata parsing -fn parse_def_id(buf: [u8]) -> ast::def_id { - let colon_idx = 0u; - let len = vec::len(buf); - while colon_idx < len && buf[colon_idx] != ':' as u8 { colon_idx += 1u; } - if colon_idx == len { - #error("didn't find ':' when parsing def id"); - fail; - } - let crate_part = vec::slice::<u8>(buf, 0u, colon_idx); - let def_part = vec::slice::<u8>(buf, colon_idx + 1u, len); - - let crate_part_vec = []; - let def_part_vec = []; - for b: u8 in crate_part { crate_part_vec += [b]; } - for b: u8 in def_part { def_part_vec += [b]; } - - let crate_num = option::get(uint::parse_buf(crate_part_vec, 10u)) as int; - let def_num = option::get(uint::parse_buf(def_part_vec, 10u)) as int; - ret {crate: crate_num, node: def_num}; -} - -fn parse_bounds_data(data: @[u8], start: uint, - crate_num: int, tcx: ty::ctxt, conv: conv_did) - -> @[ty::param_bound] { - let st = @{data: data, crate: crate_num, mutable pos: start, tcx: tcx}; - parse_bounds(st, conv) -} - -fn parse_bounds(st: @pstate, conv: conv_did) -> @[ty::param_bound] { - let bounds = []; - while true { - bounds += [alt check next(st) { - 'S' { ty::bound_send } - 'C' { ty::bound_copy } - 'I' { ty::bound_iface(parse_ty(st, conv)) } - '.' { break; } - }]; - } - @bounds -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs deleted file mode 100644 index aa08e313dd7..00000000000 --- a/src/comp/metadata/tyencode.rs +++ /dev/null @@ -1,303 +0,0 @@ -// Type encoding - -import std::io; -import io::writer_util; -import std::map::hashmap; -import syntax::ast::*; -import driver::session::session; -import middle::ty; -import syntax::print::pprust::*; - -export ctxt; -export ty_abbrev; -export ac_no_abbrevs; -export ac_use_abbrevs; -export enc_ty; -export enc_bounds; -export enc_mode; - -type ctxt = - // Def -> str Callback: - // The type context. - {ds: fn@(def_id) -> str, tcx: ty::ctxt, abbrevs: abbrev_ctxt}; - -// Compact string representation for ty.t values. API ty_str & parse_from_str. -// Extra parameters are for converting to/from def_ids in the string rep. -// Whatever format you choose should not contain pipe characters. -type ty_abbrev = {pos: uint, len: uint, s: @str}; - -enum abbrev_ctxt { ac_no_abbrevs, ac_use_abbrevs(hashmap<ty::t, ty_abbrev>), } - -fn cx_uses_abbrevs(cx: @ctxt) -> bool { - alt cx.abbrevs { - ac_no_abbrevs { ret false; } - ac_use_abbrevs(_) { ret true; } - } -} - -fn enc_ty(w: io::writer, cx: @ctxt, t: ty::t) { - alt cx.abbrevs { - ac_no_abbrevs { - let result_str = alt cx.tcx.short_names_cache.find(t) { - some(s) { *s } - none { - let buf = io::mk_mem_buffer(); - enc_sty(io::mem_buffer_writer(buf), cx, ty::get(t).struct); - cx.tcx.short_names_cache.insert(t, @io::mem_buffer_str(buf)); - io::mem_buffer_str(buf) - } - }; - w.write_str(result_str); - } - ac_use_abbrevs(abbrevs) { - alt abbrevs.find(t) { - some(a) { w.write_str(*a.s); ret; } - none { - let pos = w.tell(); - alt ty::type_def_id(t) { - some(def_id) { - w.write_char('"'); - w.write_str(cx.ds(def_id)); - w.write_char('|'); - } - _ {} - } - enc_sty(w, cx, ty::get(t).struct); - let end = w.tell(); - let len = end - pos; - fn estimate_sz(u: uint) -> uint { - let n = u; - let len = 0u; - while n != 0u { len += 1u; n = n >> 4u; } - ret len; - } - let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); - if abbrev_len < len { - // I.e. it's actually an abbreviation. - let s = "#" + uint::to_str(pos, 16u) + ":" + - uint::to_str(len, 16u) + "#"; - let a = {pos: pos, len: len, s: @s}; - abbrevs.insert(t, a); - } - ret; - } - } - } - } -} -fn enc_mt(w: io::writer, cx: @ctxt, mt: ty::mt) { - alt mt.mutbl { - m_imm { } - m_mutbl { w.write_char('m'); } - m_const { w.write_char('?'); } - } - enc_ty(w, cx, mt.ty); -} -fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { - alt st { - ty::ty_nil { w.write_char('n'); } - ty::ty_bot { w.write_char('z'); } - ty::ty_bool { w.write_char('b'); } - ty::ty_int(t) { - alt t { - ty_i { w.write_char('i'); } - ty_char { w.write_char('c'); } - ty_i8 { w.write_str("MB"); } - ty_i16 { w.write_str("MW"); } - ty_i32 { w.write_str("ML"); } - ty_i64 { w.write_str("MD"); } - } - } - ty::ty_uint(t) { - alt t { - ty_u { w.write_char('u'); } - ty_u8 { w.write_str("Mb"); } - ty_u16 { w.write_str("Mw"); } - ty_u32 { w.write_str("Ml"); } - ty_u64 { w.write_str("Md"); } - } - } - ty::ty_float(t) { - alt t { - ty_f { w.write_char('l'); } - ty_f32 { w.write_str("Mf"); } - ty_f64 { w.write_str("MF"); } - } - } - ty::ty_str { w.write_char('S'); } - ty::ty_enum(def, tys) { - w.write_str("t["); - w.write_str(cx.ds(def)); - w.write_char('|'); - for t: ty::t in tys { enc_ty(w, cx, t); } - w.write_char(']'); - } - ty::ty_iface(def, tys) { - w.write_str("x["); - w.write_str(cx.ds(def)); - w.write_char('|'); - for t: ty::t in tys { enc_ty(w, cx, t); } - w.write_char(']'); - } - ty::ty_tup(ts) { - w.write_str("T["); - for t in ts { enc_ty(w, cx, t); } - w.write_char(']'); - } - ty::ty_box(mt) { w.write_char('@'); enc_mt(w, cx, mt); } - ty::ty_uniq(mt) { w.write_char('~'); enc_mt(w, cx, mt); } - ty::ty_ptr(mt) { w.write_char('*'); enc_mt(w, cx, mt); } - ty::ty_vec(mt) { w.write_char('I'); enc_mt(w, cx, mt); } - ty::ty_rec(fields) { - w.write_str("R["); - for field: ty::field in fields { - w.write_str(field.ident); - w.write_char('='); - enc_mt(w, cx, field.mt); - } - w.write_char(']'); - } - ty::ty_fn(f) { - enc_proto(w, f.proto); - enc_ty_fn(w, cx, f); - } - ty::ty_res(def, ty, tps) { - w.write_str("r["); - w.write_str(cx.ds(def)); - w.write_char('|'); - enc_ty(w, cx, ty); - for t: ty::t in tps { enc_ty(w, cx, t); } - w.write_char(']'); - } - ty::ty_var(id) { w.write_char('X'); w.write_str(int::str(id)); } - ty::ty_param(id, did) { - w.write_char('p'); - w.write_str(cx.ds(did)); - w.write_char('|'); - w.write_str(uint::str(id)); - } - ty::ty_self(tps) { - w.write_str("s["); - for t in tps { enc_ty(w, cx, t); } - w.write_char(']'); - } - ty::ty_type { w.write_char('Y'); } - ty::ty_send_type { w.write_char('y'); } - ty::ty_opaque_closure_ptr(ty::ck_block) { w.write_str("C&"); } - ty::ty_opaque_closure_ptr(ty::ck_box) { w.write_str("C@"); } - ty::ty_opaque_closure_ptr(ty::ck_uniq) { w.write_str("C~"); } - ty::ty_constr(ty, cs) { - w.write_str("A["); - enc_ty(w, cx, ty); - for tc: @ty::type_constr in cs { enc_ty_constr(w, cx, tc); } - w.write_char(']'); - } - ty::ty_opaque_box { w.write_char('B'); } - ty::ty_class(def, tys) { - w.write_str("c["); - w.write_str(cx.ds(def)); - w.write_char('|'); - for t: ty::t in tys { enc_ty(w, cx, t); } - w.write_char(']'); - } - } -} -fn enc_proto(w: io::writer, proto: proto) { - alt proto { - proto_uniq { w.write_str("f~"); } - proto_box { w.write_str("f@"); } - proto_block { w.write_str("f&"); } - proto_any { w.write_str("f*"); } - proto_bare { w.write_str("fn"); } - } -} - -fn enc_mode(w: io::writer, cx: @ctxt, m: mode) { - alt ty::resolved_mode(cx.tcx, m) { - by_mutbl_ref { w.write_char('&'); } - by_move { w.write_char('-'); } - by_copy { w.write_char('+'); } - by_ref { w.write_char('='); } - by_val { w.write_char('#'); } - } -} - -fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) { - w.write_char('['); - for arg: ty::arg in ft.inputs { - enc_mode(w, cx, arg.mode); - enc_ty(w, cx, arg.ty); - } - w.write_char(']'); - let colon = true; - for c: @ty::constr in ft.constraints { - if colon { - w.write_char(':'); - colon = false; - } else { w.write_char(';'); } - enc_constr(w, cx, c); - } - alt ft.ret_style { - noreturn { w.write_char('!'); } - _ { enc_ty(w, cx, ft.output); } - } -} - -// FIXME less copy-and-paste -fn enc_constr(w: io::writer, cx: @ctxt, c: @ty::constr) { - w.write_str(path_to_str(c.node.path)); - w.write_char('('); - w.write_str(cx.ds(c.node.id)); - w.write_char('|'); - let semi = false; - for a: @constr_arg in c.node.args { - if semi { w.write_char(';'); } else { semi = true; } - alt a.node { - carg_base { w.write_char('*'); } - carg_ident(i) { w.write_uint(i); } - carg_lit(l) { w.write_str(lit_to_str(l)); } - } - } - w.write_char(')'); -} - -fn enc_ty_constr(w: io::writer, cx: @ctxt, c: @ty::type_constr) { - w.write_str(path_to_str(c.node.path)); - w.write_char('('); - w.write_str(cx.ds(c.node.id)); - w.write_char('|'); - let semi = false; - for a: @ty::ty_constr_arg in c.node.args { - if semi { w.write_char(';'); } else { semi = true; } - alt a.node { - carg_base { w.write_char('*'); } - carg_ident(p) { w.write_str(path_to_str(p)); } - carg_lit(l) { w.write_str(lit_to_str(l)); } - } - } - w.write_char(')'); -} - -fn enc_bounds(w: io::writer, cx: @ctxt, bs: @[ty::param_bound]) { - for bound in *bs { - alt bound { - ty::bound_send { w.write_char('S'); } - ty::bound_copy { w.write_char('C'); } - ty::bound_iface(tp) { - w.write_char('I'); - enc_ty(w, cx, tp); - } - } - } - w.write_char('.'); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs deleted file mode 100644 index cb0785b4df1..00000000000 --- a/src/comp/middle/alias.rs +++ /dev/null @@ -1,715 +0,0 @@ - -import syntax::{ast, ast_util}; -import ast::{ident, fn_ident, node_id}; -import syntax::codemap::span; -import syntax::visit; -import visit::vt; -import std::list; -import std::util::unreachable; -import option::is_none; -import list::list; -import driver::session::session; -import pat_util::*; -import util::ppaux::ty_to_str; - -// This is not an alias-analyser (though it would merit from becoming one, or -// getting input from one, to be more precise). It is a pass that checks -// whether aliases are used in a safe way. - -enum copied { not_allowed, copied, not_copied, } -enum invalid_reason { overwritten, val_taken, } -type invalid = {reason: invalid_reason, - node_id: node_id, - sp: span, path: @ast::path}; - -enum unsafe_ty { contains(ty::t), mutbl_contains(ty::t), } - -type binding = @{node_id: node_id, - span: span, - root_var: option<node_id>, - local_id: uint, - unsafe_tys: [unsafe_ty], - mutable copied: copied}; - -// FIXME it may be worthwhile to use a linked list of bindings instead -type scope = {bs: [binding], - invalid: @mutable list<@invalid>}; - -fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option<node_id>, - unsafe_tys: [unsafe_ty]) -> binding { - alt root_var { - some(r_id) { cx.ref_map.insert(id, r_id); } - _ {} - } - ret @{node_id: id, span: span, root_var: root_var, - local_id: local_id_of_node(cx, id), - unsafe_tys: unsafe_tys, - mutable copied: not_copied}; -} - -enum local_info { local(uint), } - -type copy_map = std::map::hashmap<node_id, ()>; -type ref_map = std::map::hashmap<node_id, node_id>; - -type ctx = {tcx: ty::ctxt, - copy_map: copy_map, - ref_map: ref_map, - mutable silent: bool}; - -fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> (copy_map, ref_map) { - // Stores information about function arguments that's otherwise not easily - // available. - let cx = @{tcx: tcx, - copy_map: std::map::new_int_hash(), - ref_map: std::map::new_int_hash(), - mutable silent: false}; - let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _), - visit_expr: bind visit_expr(cx, _, _, _), - visit_block: bind visit_block(cx, _, _, _) - with *visit::default_visitor::<scope>()}; - let sc = {bs: [], invalid: @mutable list::nil}; - visit::visit_crate(*crate, sc, visit::mk_vt(v)); - tcx.sess.abort_if_errors(); - ret (cx.copy_map, cx.ref_map); -} - -fn visit_fn(cx: @ctx, _fk: visit::fn_kind, decl: ast::fn_decl, - body: ast::blk, sp: span, - id: ast::node_id, sc: scope, v: vt<scope>) { - visit::visit_fn_decl(decl, sc, v); - let fty = ty::node_id_to_type(cx.tcx, id); - let args = ty::ty_fn_args(fty); - for arg in args { - alt ty::resolved_mode(cx.tcx, arg.mode) { - ast::by_val if ty::type_has_dynamic_size(cx.tcx, arg.ty) { - err(*cx, sp, "can not pass a dynamically-sized type by value"); - } - _ { /* fallthrough */ } - } - } - - // Blocks need to obey any restrictions from the enclosing scope, and may - // be called multiple times. - let proto = ty::ty_fn_proto(fty); - alt proto { - ast::proto_block | ast::proto_any { - check_loop(*cx, sc) {|| v.visit_block(body, sc, v);} - } - ast::proto_box | ast::proto_uniq | ast::proto_bare { - let sc = {bs: [], invalid: @mutable list::nil}; - v.visit_block(body, sc, v); - } - } -} - -fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) { - let handled = true; - alt ex.node { - ast::expr_call(f, args, _) { - check_call(*cx, sc, f, args); - handled = false; - } - ast::expr_alt(input, arms, _) { check_alt(*cx, input, arms, sc, v); } - ast::expr_for(decl, seq, blk) { - visit_expr(cx, seq, sc, v); - check_loop(*cx, sc) {|| check_for(*cx, decl, seq, blk, sc, v); } - } - ast::expr_path(pt) { - check_var(*cx, ex, pt, ex.id, false, sc); - handled = false; - } - ast::expr_swap(lhs, rhs) { - check_lval(cx, lhs, sc, v); - check_lval(cx, rhs, sc, v); - handled = false; - } - ast::expr_move(dest, src) { - visit_expr(cx, src, sc, v); - check_lval(cx, dest, sc, v); - check_lval(cx, src, sc, v); - } - ast::expr_assign(dest, src) | ast::expr_assign_op(_, dest, src) { - visit_expr(cx, src, sc, v); - check_lval(cx, dest, sc, v); - } - ast::expr_if(c, then, els) { check_if(c, then, els, sc, v); } - ast::expr_while(_, _) | ast::expr_do_while(_, _) { - check_loop(*cx, sc) {|| visit::visit_expr(ex, sc, v); } - } - _ { handled = false; } - } - if !handled { visit::visit_expr(ex, sc, v); } -} - -fn visit_block(cx: @ctx, b: ast::blk, sc: scope, v: vt<scope>) { - let sc = sc; - for stmt in b.node.stmts { - alt stmt.node { - ast::stmt_decl(@{node: ast::decl_item(it), _}, _) { - v.visit_item(it, sc, v); - } - ast::stmt_decl(@{node: ast::decl_local(locs), _}, _) { - for loc in locs { - alt loc.node.init { - some(init) { - if init.op == ast::init_move { - check_lval(cx, init.expr, sc, v); - } else { - visit_expr(cx, init.expr, sc, v); - } - } - none { } - } - } - } - ast::stmt_expr(ex, _) | ast::stmt_semi(ex, _) { - v.visit_expr(ex, sc, v); - } - } - } - visit::visit_expr_opt(b.node.expr, sc, v); -} - -fn add_bindings_for_let(cx: ctx, &bs: [binding], loc: @ast::local) { - alt loc.node.init { - some(init) { - if init.op == ast::init_move { - err(cx, loc.span, "can not move into a by-reference binding"); - } - let root = expr_root(cx, init.expr, false); - let root_var = path_def_id(cx, root.ex); - if is_none(root_var) { - err(cx, loc.span, "a reference binding can't be \ - rooted in a temporary"); - } - for proot in pattern_roots(cx.tcx, root.mutbl, loc.node.pat) { - let bnd = mk_binding(cx, proot.id, proot.span, root_var, - unsafe_set(proot.mutbl)); - // Don't implicitly copy explicit references - bnd.copied = not_allowed; - bs += [bnd]; - } - } - _ { - err(cx, loc.span, "by-reference bindings must be initialized"); - } - } -} - - -fn cant_copy(cx: ctx, b: binding) -> bool { - alt b.copied { - not_allowed { ret true; } - copied { ret false; } - not_copied {} - } - let ty = ty::node_id_to_type(cx.tcx, b.node_id); - if ty::type_allows_implicit_copy(cx.tcx, ty) { - b.copied = copied; - cx.copy_map.insert(b.node_id, ()); - if copy_is_expensive(cx.tcx, ty) { - cx.tcx.sess.span_warn(b.span, - "inserting an implicit copy for type " + - util::ppaux::ty_to_str(cx.tcx, ty)); - } - ret false; - } else { ret true; } -} - -fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr]) - -> [binding] { - let fty = ty::expr_ty(cx.tcx, f); - let arg_ts = ty::ty_fn_args(fty); - let mut_roots: [{arg: uint, node: node_id}] = []; - let bindings = []; - let i = 0u; - for arg_t: ty::arg in arg_ts { - let arg = args[i]; - let root = expr_root(cx, arg, false); - alt ty::resolved_mode(cx.tcx, arg_t.mode) { - ast::by_mutbl_ref { - alt path_def(cx, arg) { - some(def) { - let dnum = ast_util::def_id_of_def(def).node; - mut_roots += [{arg: i, node: dnum}]; - } - _ { } - } - } - ast::by_ref | ast::by_val | ast::by_move | ast::by_copy { } - } - let root_var = path_def_id(cx, root.ex); - let arg_copied = alt ty::resolved_mode(cx.tcx, arg_t.mode) { - ast::by_move | ast::by_copy { copied } - ast::by_mutbl_ref { not_allowed } - ast::by_ref | ast::by_val { not_copied } - }; - bindings += [@{node_id: arg.id, - span: arg.span, - root_var: root_var, - local_id: 0u, - unsafe_tys: unsafe_set(root.mutbl), - mutable copied: arg_copied}]; - i += 1u; - } - let f_may_close = - alt f.node { - ast::expr_path(_) { def_is_local_or_self(cx.tcx.def_map.get(f.id)) } - _ { true } - }; - if f_may_close { - let i = 0u; - for b in bindings { - let unsfe = vec::len(b.unsafe_tys) > 0u; - alt b.root_var { - some(rid) { - for o in sc.bs { - if o.node_id == rid && vec::len(o.unsafe_tys) > 0u { - unsfe = true; break; - } - } - } - _ {} - } - if unsfe && cant_copy(cx, b) { - err(cx, f.span, #fmt["function may alias with argument \ - %u, which is not immutably rooted", i]); - } - i += 1u; - } - } - let j = 0u; - for b in bindings { - for unsafe_ty in b.unsafe_tys { - let i = 0u; - for arg_t: ty::arg in arg_ts { - let mut_alias = - (ast::by_mutbl_ref == ty::arg_mode(cx.tcx, arg_t)); - if i != j && - ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty, - mut_alias) && - cant_copy(cx, b) { - err(cx, args[i].span, - #fmt["argument %u may alias with argument %u, \ - which is not immutably rooted", i, j]); - } - i += 1u; - } - } - j += 1u; - } - // Ensure we're not passing a root by mutable alias. - - for {node: node, arg: arg} in mut_roots { - let i = 0u; - for b in bindings { - if i != arg { - alt b.root_var { - some(root) { - if node == root && cant_copy(cx, b) { - err(cx, args[arg].span, - "passing a mutable reference to a \ - variable that roots another reference"); - break; - } - } - none { } - } - } - i += 1u; - } - } - ret bindings; -} - -fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope, - v: vt<scope>) { - v.visit_expr(input, sc, v); - let orig_invalid = *sc.invalid; - let all_invalid = orig_invalid; - let root = expr_root(cx, input, true); - for a: ast::arm in arms { - let new_bs = sc.bs; - let root_var = path_def_id(cx, root.ex); - let pat_id_map = pat_util::pat_id_map(cx.tcx.def_map, a.pats[0]); - type info = { - id: node_id, - mutable unsafe_tys: [unsafe_ty], - span: span}; - let binding_info: [info] = []; - for pat in a.pats { - for proot in pattern_roots(cx.tcx, root.mutbl, pat) { - let canon_id = pat_id_map.get(proot.name); - alt vec::find(binding_info, {|x| x.id == canon_id}) { - some(s) { s.unsafe_tys += unsafe_set(proot.mutbl); } - none { - binding_info += [ - {id: canon_id, - mutable unsafe_tys: unsafe_set(proot.mutbl), - span: proot.span}]; - } - } - } - } - for info in binding_info { - new_bs += [mk_binding(cx, info.id, info.span, root_var, - copy info.unsafe_tys)]; - } - *sc.invalid = orig_invalid; - visit::visit_arm(a, {bs: new_bs with sc}, v); - all_invalid = join_invalid(all_invalid, *sc.invalid); - } - *sc.invalid = all_invalid; -} - -fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk, - sc: scope, v: vt<scope>) { - let root = expr_root(cx, seq, false); - - // If this is a mutable vector, don't allow it to be touched. - let seq_t = ty::expr_ty(cx.tcx, seq); - let cur_mutbl = root.mutbl; - alt ty::get(seq_t).struct { - ty::ty_vec(mt) { - if mt.mutbl != ast::m_imm { - cur_mutbl = some(contains(seq_t)); - } - } - _ {} - } - let root_var = path_def_id(cx, root.ex); - let new_bs = sc.bs; - for proot in pattern_roots(cx.tcx, cur_mutbl, local.node.pat) { - new_bs += [mk_binding(cx, proot.id, proot.span, root_var, - unsafe_set(proot.mutbl))]; - } - visit::visit_block(blk, {bs: new_bs with sc}, v); -} - -fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id, - assign: bool, sc: scope) { - let def = cx.tcx.def_map.get(id); - if !def_is_local_or_self(def) { ret; } - let my_defnum = ast_util::def_id_of_def(def).node; - let my_local_id = local_id_of_node(cx, my_defnum); - let var_t = ty::expr_ty(cx.tcx, ex); - for b in sc.bs { - // excludes variables introduced since the alias was made - if my_local_id < b.local_id { - for unsafe_ty in b.unsafe_tys { - if ty_can_unsafely_include(cx, unsafe_ty, var_t, assign) { - let inv = @{reason: val_taken, node_id: b.node_id, - sp: ex.span, path: p}; - *sc.invalid = list::cons(inv, @*sc.invalid); - } - } - } else if b.node_id == my_defnum { - test_scope(cx, sc, b, p); - } - } -} - -fn check_lval(cx: @ctx, dest: @ast::expr, sc: scope, v: vt<scope>) { - alt dest.node { - ast::expr_path(p) { - let def = cx.tcx.def_map.get(dest.id); - let dnum = ast_util::def_id_of_def(def).node; - for b in sc.bs { - if b.root_var == some(dnum) { - let inv = @{reason: overwritten, node_id: b.node_id, - sp: dest.span, path: p}; - *sc.invalid = list::cons(inv, @*sc.invalid); - } - } - } - _ { visit_expr(cx, dest, sc, v); } - } -} - -fn check_if(c: @ast::expr, then: ast::blk, els: option<@ast::expr>, - sc: scope, v: vt<scope>) { - v.visit_expr(c, sc, v); - let orig_invalid = *sc.invalid; - v.visit_block(then, sc, v); - let then_invalid = *sc.invalid; - *sc.invalid = orig_invalid; - visit::visit_expr_opt(els, sc, v); - *sc.invalid = join_invalid(*sc.invalid, then_invalid); -} - -fn check_loop(cx: ctx, sc: scope, checker: fn()) { - let orig_invalid = filter_invalid(*sc.invalid, sc.bs); - checker(); - let new_invalid = filter_invalid(*sc.invalid, sc.bs); - // Have to check contents of loop again if it invalidated an alias - if list::len(orig_invalid) < list::len(new_invalid) { - let old_silent = cx.silent; - cx.silent = true; - checker(); - cx.silent = old_silent; - } - *sc.invalid = new_invalid; -} - -fn test_scope(cx: ctx, sc: scope, b: binding, p: @ast::path) { - let prob = find_invalid(b.node_id, *sc.invalid); - alt b.root_var { - some(dn) { - for other in sc.bs { - if !is_none(prob) { break; } - if other.node_id == dn { - prob = find_invalid(other.node_id, *sc.invalid); - } - } - } - _ {} - } - if !is_none(prob) && cant_copy(cx, b) { - let i = option::get(prob); - let msg = alt i.reason { - overwritten { "overwriting " + ast_util::path_name(i.path) } - val_taken { "taking the value of " + ast_util::path_name(i.path) } - }; - err(cx, i.sp, msg + " will invalidate reference " + - ast_util::path_name(p) + ", which is still used"); - } -} - -fn path_def(cx: ctx, ex: @ast::expr) -> option<ast::def> { - ret alt ex.node { - ast::expr_path(_) { some(cx.tcx.def_map.get(ex.id)) } - _ { none } - } -} - -fn path_def_id(cx: ctx, ex: @ast::expr) -> option<ast::node_id> { - alt ex.node { - ast::expr_path(_) { - ret some(ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)).node); - } - _ { ret none; } - } -} - -fn ty_can_unsafely_include(cx: ctx, needle: unsafe_ty, haystack: ty::t, - mutbl: bool) -> bool { - fn get_mutbl(cur: bool, mt: ty::mt) -> bool { - ret cur || mt.mutbl != ast::m_imm; - } - fn helper(tcx: ty::ctxt, needle: unsafe_ty, haystack: ty::t, mutbl: bool) - -> bool { - if alt needle { - contains(ty) { ty == haystack } - mutbl_contains(ty) { mutbl && ty == haystack } - } { ret true; } - alt ty::get(haystack).struct { - ty::ty_enum(_, ts) { - for t: ty::t in ts { - if helper(tcx, needle, t, mutbl) { ret true; } - } - ret false; - } - ty::ty_box(mt) | ty::ty_ptr(mt) | ty::ty_uniq(mt) { - ret helper(tcx, needle, mt.ty, get_mutbl(mutbl, mt)); - } - ty::ty_rec(fields) { - for f: ty::field in fields { - if helper(tcx, needle, f.mt.ty, get_mutbl(mutbl, f.mt)) { - ret true; - } - } - ret false; - } - ty::ty_tup(ts) { - for t in ts { if helper(tcx, needle, t, mutbl) { ret true; } } - ret false; - } - ty::ty_fn({proto: ast::proto_bare, _}) { ret false; } - // These may contain anything. - ty::ty_fn(_) | ty::ty_iface(_, _) { ret true; } - // A type param may include everything, but can only be - // treated as opaque downstream, and is thus safe unless we - // saw mutable fields, in which case the whole thing can be - // overwritten. - ty::ty_param(_, _) { ret mutbl; } - _ { ret false; } - } - } - ret helper(cx.tcx, needle, haystack, mutbl); -} - -fn def_is_local_or_self(d: ast::def) -> bool { - alt d { - ast::def_local(_, _) | ast::def_arg(_, _) | ast::def_binding(_) | - ast::def_upvar(_, _, _) | ast::def_self(_) { true } - _ { false } - } -} - -fn local_id_of_node(cx: ctx, id: node_id) -> uint { - alt cx.tcx.items.find(id) { - some(ast_map::node_arg(_, id)) | some(ast_map::node_local(id)) { id } - _ { 0u } - } -} - -// Heuristic, somewhat random way to decide whether to warn when inserting an -// implicit copy. -fn copy_is_expensive(tcx: ty::ctxt, ty: ty::t) -> bool { - fn score_ty(tcx: ty::ctxt, ty: ty::t) -> uint { - ret alt ty::get(ty).struct { - ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) | - ty::ty_uint(_) | ty::ty_float(_) | ty::ty_type | - ty::ty_ptr(_) { 1u } - ty::ty_box(_) | ty::ty_iface(_, _) { 3u } - ty::ty_constr(t, _) | ty::ty_res(_, t, _) { score_ty(tcx, t) } - ty::ty_fn(_) { 4u } - ty::ty_str | ty::ty_vec(_) | ty::ty_param(_, _) { 50u } - ty::ty_uniq(mt) { 1u + score_ty(tcx, mt.ty) } - ty::ty_enum(_, ts) | ty::ty_tup(ts) { - let sum = 0u; - for t in ts { sum += score_ty(tcx, t); } - sum - } - ty::ty_rec(fs) { - let sum = 0u; - for f in fs { sum += score_ty(tcx, f.mt.ty); } - sum - } - _ { - tcx.sess.warn(#fmt("score_ty: unexpected type %s", - ty_to_str(tcx, ty))); - 1u // ??? - } - }; - } - ret score_ty(tcx, ty) > 8u; -} - -type pattern_root = {id: node_id, - name: ident, - mutbl: option<unsafe_ty>, - span: span}; - -fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat) - -> [pattern_root] { - fn walk(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat, - &set: [pattern_root]) { - alt pat.node { - ast::pat_ident(nm, sub) - if !pat_util::pat_is_variant(tcx.def_map, pat) { - set += [{id: pat.id, name: path_to_ident(nm), mutbl: mutbl, - span: pat.span}]; - alt sub { some(p) { walk(tcx, mutbl, p, set); } _ {} } - } - ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) | - ast::pat_ident(_, _) {} - ast::pat_enum(_, ps) | ast::pat_tup(ps) { - for p in ps { walk(tcx, mutbl, p, set); } - } - ast::pat_rec(fs, _) { - let ty = ty::node_id_to_type(tcx, pat.id); - for f in fs { - let m = ty::get_field(ty, f.ident).mt.mutbl != ast::m_imm, - c = if m { some(contains(ty)) } else { mutbl }; - walk(tcx, c, f.pat, set); - } - } - ast::pat_box(p) { - let ty = ty::node_id_to_type(tcx, pat.id); - let m = alt ty::get(ty).struct { - ty::ty_box(mt) { mt.mutbl != ast::m_imm } - _ { tcx.sess.span_bug(pat.span, "box pat has non-box type"); } - }, - c = if m {some(contains(ty)) } else { mutbl }; - walk(tcx, c, p, set); - } - ast::pat_uniq(p) { - let ty = ty::node_id_to_type(tcx, pat.id); - let m = alt ty::get(ty).struct { - ty::ty_uniq(mt) { mt.mutbl != ast::m_imm } - _ { tcx.sess.span_bug(pat.span, "uniq pat has non-uniq type"); } - }, - c = if m { some(contains(ty)) } else { mutbl }; - walk(tcx, c, p, set); - } - } - } - let set = []; - walk(tcx, mutbl, pat, set); - ret set; -} - -// Wraps the expr_root in mutbl.rs to also handle roots that exist through -// return-by-reference -fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) - -> {ex: @ast::expr, mutbl: option<unsafe_ty>} { - let base_root = mutbl::expr_root(cx.tcx, ex, autoderef); - let unsafe_ty = none; - for d in *base_root.ds { - if d.mutbl { unsafe_ty = some(contains(d.outer_t)); break; } - } - ret {ex: base_root.ex, mutbl: unsafe_ty}; -} - -fn unsafe_set(from: option<unsafe_ty>) -> [unsafe_ty] { - alt from { some(t) { [t] } _ { [] } } -} - -fn find_invalid(id: node_id, lst: list<@invalid>) - -> option<@invalid> { - let cur = lst; - while true { - alt cur { - list::nil { break; } - list::cons(head, tail) { - if head.node_id == id { ret some(head); } - cur = *tail; - } - } - } - ret none; -} - -fn join_invalid(a: list<@invalid>, b: list<@invalid>) -> list<@invalid> { - let result = a; - list::iter(b) {|elt| - let found = false; - list::iter(a) {|e| if e == elt { found = true; } } - if !found { result = list::cons(elt, @result); } - } - result -} - -fn filter_invalid(src: list<@invalid>, bs: [binding]) -> list<@invalid> { - let out = list::nil, cur = src; - while cur != list::nil { - alt cur { - list::cons(head, tail) { - let p = vec::position(bs, {|b| b.node_id == head.node_id}); - if !is_none(p) { out = list::cons(head, @out); } - cur = *tail; - } - list::nil { - // typestate would help... - unreachable(); - } - } - } - ret out; -} - -fn err(cx: ctx, sp: span, err: str) { - if !cx.silent || !cx.tcx.sess.has_errors() { - cx.tcx.sess.span_err(sp, err); - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs deleted file mode 100644 index 673b3649191..00000000000 --- a/src/comp/middle/ast_map.rs +++ /dev/null @@ -1,152 +0,0 @@ -import std::map; -import syntax::ast::*; -import syntax::ast_util; -import syntax::ast_util::inlined_item_methods; -import syntax::{visit, codemap}; - -enum path_elt { path_mod(str), path_name(str) } -type path = [path_elt]; - -fn path_to_str_with_sep(p: path, sep: str) -> str { - let strs = vec::map(p) {|e| - alt e { - path_mod(s) { s } - path_name(s) { s } - } - }; - str::connect(strs, sep) -} - -fn path_to_str(p: path) -> str { - path_to_str_with_sep(p, "::") -} - -enum ast_node { - node_item(@item, @path), - node_native_item(@native_item, @path), - node_method(@method, def_id, @path), - node_variant(variant, def_id, @path), - node_expr(@expr), - // Locals are numbered, because the alias analysis needs to know in which - // order they are introduced. - node_arg(arg, uint), - node_local(uint), - node_res_ctor(@item), -} - -type map = std::map::map<node_id, ast_node>; -type ctx = {map: map, mutable path: path, mutable local_id: uint}; -type vt = visit::vt<ctx>; - -fn mk_ast_map_visitor() -> vt { - ret visit::mk_vt(@{ - visit_item: map_item, - visit_native_item: map_native_item, - visit_expr: map_expr, - visit_fn: map_fn, - visit_local: map_local, - visit_arm: map_arm - with *visit::default_visitor() - }); -} - -fn map_crate(c: crate) -> map { - let cx = {map: std::map::new_int_hash(), - mutable path: [], - mutable local_id: 0u}; - visit::visit_crate(c, cx, mk_ast_map_visitor()); - ret cx.map; -} - -// Used for items loaded from external crate that are being inlined into this -// crate: -fn map_decoded_item(map: map, path: path, ii: inlined_item) { - // I believe it is ok for the local IDs of inlined items from other crates - // to overlap with the local ids from this crate, so just generate the ids - // starting from 0. (In particular, I think these ids are only used in - // alias analysis, which we will not be running on the inlined items, and - // even if we did I think it only needs an ordering between local - // variables that are simultaneously in scope). - let cx = {map: map, - mutable path: path, - mutable local_id: 0u}; - let v = mk_ast_map_visitor(); - ii.accept(cx, v); -} - -fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, - sp: codemap::span, id: node_id, cx: ctx, v: vt) { - for a in decl.inputs { - cx.map.insert(a.id, node_arg(a, cx.local_id)); - cx.local_id += 1u; - } - visit::visit_fn(fk, decl, body, sp, id, cx, v); -} - -fn number_pat(cx: ctx, pat: @pat) { - pat_util::walk_pat(pat) {|p| - alt p.node { - pat_ident(_, _) { - cx.map.insert(p.id, node_local(cx.local_id)); - cx.local_id += 1u; - } - _ {} - } - }; -} - -fn map_local(loc: @local, cx: ctx, v: vt) { - number_pat(cx, loc.node.pat); - visit::visit_local(loc, cx, v); -} - -fn map_arm(arm: arm, cx: ctx, v: vt) { - number_pat(cx, arm.pats[0]); - visit::visit_arm(arm, cx, v); -} - -fn map_item(i: @item, cx: ctx, v: vt) { - cx.map.insert(i.id, node_item(i, @cx.path)); - alt i.node { - item_impl(_, _, _, ms) { - let implid = ast_util::local_def(i.id); - for m in ms { cx.map.insert(m.id, node_method(m, implid, @cx.path)); } - } - item_res(_, _, _, dtor_id, ctor_id) { - cx.map.insert(ctor_id, node_res_ctor(i)); - cx.map.insert(dtor_id, node_item(i, @cx.path)); - } - item_enum(vs, _) { - for v in vs { - cx.map.insert(v.node.id, node_variant( - v, ast_util::local_def(i.id), - @(cx.path + [path_name(i.ident)]))); - } - } - _ { } - } - alt i.node { - item_mod(_) | item_native_mod(_) { cx.path += [path_mod(i.ident)]; } - _ { cx.path += [path_name(i.ident)]; } - } - visit::visit_item(i, cx, v); - vec::pop(cx.path); -} - -fn map_native_item(i: @native_item, cx: ctx, v: vt) { - cx.map.insert(i.id, node_native_item(i, @cx.path)); - visit::visit_native_item(i, cx, v); -} - -fn map_expr(ex: @expr, cx: ctx, v: vt) { - cx.map.insert(ex.id, node_expr(ex)); - visit::visit_expr(ex, cx, v); -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/block_use.rs b/src/comp/middle/block_use.rs deleted file mode 100644 index f21dcd5cc40..00000000000 --- a/src/comp/middle/block_use.rs +++ /dev/null @@ -1,42 +0,0 @@ -import syntax::visit; -import syntax::ast::*; -import driver::session::session; - -type ctx = {tcx: ty::ctxt, mutable allow_block: bool}; - -fn check_crate(tcx: ty::ctxt, crate: @crate) { - let cx = {tcx: tcx, mutable allow_block: false}; - let v = visit::mk_vt(@{visit_expr: visit_expr - with *visit::default_visitor()}); - visit::visit_crate(*crate, cx, v); -} - -fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) { - if !cx.allow_block { - alt ty::get(ty::expr_ty(cx.tcx, ex)).struct { - ty::ty_fn({proto: p, _}) if is_blockish(p) { - cx.tcx.sess.span_err(ex.span, "expressions with block type \ - can only appear in callee or (by-ref) argument position"); - } - _ {} - } - } - let outer = cx.allow_block; - alt ex.node { - expr_call(f, args, _) { - cx.allow_block = true; - v.visit_expr(f, cx, v); - let i = 0u; - for arg_t in ty::ty_fn_args(ty::expr_ty(cx.tcx, f)) { - cx.allow_block = (ty::arg_mode(cx.tcx, arg_t) == by_ref); - v.visit_expr(args[i], cx, v); - i += 1u; - } - } - _ { - cx.allow_block = false; - visit::visit_expr(ex, cx, v); - } - } - cx.allow_block = outer; -} diff --git a/src/comp/middle/capture.rs b/src/comp/middle/capture.rs deleted file mode 100644 index c32623b30b1..00000000000 --- a/src/comp/middle/capture.rs +++ /dev/null @@ -1,133 +0,0 @@ -import syntax::{ast, ast_util}; -import driver::session::session; -import std::map; - -export capture_mode; -export capture_var; -export capture_map; -export check_capture_clause; -export compute_capture_vars; -export cap_copy; -export cap_move; -export cap_drop; -export cap_ref; - -enum capture_mode { - cap_copy, //< Copy the value into the closure. - cap_move, //< Move the value into the closure. - cap_drop, //< Drop value after creating closure. - cap_ref, //< Reference directly from parent stack frame (block fn). -} - -type capture_var = { - def: ast::def, //< The variable being accessed free. - mode: capture_mode //< How is the variable being accessed. -}; - -type capture_map = map::hashmap<ast::def_id, capture_var>; - -// checks the capture clause for a fn_expr() and issues warnings or -// errors for any irregularities which we identify. -fn check_capture_clause(tcx: ty::ctxt, - fn_expr_id: ast::node_id, - fn_proto: ast::proto, - cap_clause: ast::capture_clause) { - let freevars = freevars::get_freevars(tcx, fn_expr_id); - let seen_defs = map::new_int_hash(); - - let check_capture_item = fn@(&&cap_item: @ast::capture_item) { - let cap_def = tcx.def_map.get(cap_item.id); - if !vec::any(*freevars, {|fv| fv.def == cap_def}) { - tcx.sess.span_warn( - cap_item.span, - #fmt("Captured variable '%s' not used in closure", - cap_item.name)); - } - - let cap_def_id = ast_util::def_id_of_def(cap_def).node; - if !seen_defs.insert(cap_def_id, ()) { - tcx.sess.span_err( - cap_item.span, - #fmt("Variable '%s' captured more than once", - cap_item.name)); - } - }; - - let check_not_upvar = fn@(&&cap_item: @ast::capture_item) { - alt tcx.def_map.get(cap_item.id) { - ast::def_upvar(_, _, _) { - tcx.sess.span_err( - cap_item.span, - #fmt("Upvars (like '%s') cannot be moved into a closure", - cap_item.name)); - } - _ {} - } - }; - - let check_block_captures = fn@(v: [@ast::capture_item]) { - if check vec::is_not_empty(v) { - let cap_item0 = vec::head(v); - tcx.sess.span_err( - cap_item0.span, - "Cannot capture values explicitly with a block closure"); - } - }; - - alt fn_proto { - ast::proto_any | ast::proto_block { - check_block_captures(cap_clause.copies); - check_block_captures(cap_clause.moves); - } - ast::proto_bare | ast::proto_box | ast::proto_uniq { - vec::iter(cap_clause.copies, check_capture_item); - vec::iter(cap_clause.moves, check_capture_item); - vec::iter(cap_clause.moves, check_not_upvar); - } - } -} - -fn compute_capture_vars(tcx: ty::ctxt, - fn_expr_id: ast::node_id, - fn_proto: ast::proto, - cap_clause: ast::capture_clause) -> [capture_var] { - let freevars = freevars::get_freevars(tcx, fn_expr_id); - let cap_map = map::new_int_hash(); - - vec::iter(cap_clause.copies) { |cap_item| - let cap_def = tcx.def_map.get(cap_item.id); - let cap_def_id = ast_util::def_id_of_def(cap_def).node; - if vec::any(*freevars, {|fv| fv.def == cap_def}) { - cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy }); - } - } - - vec::iter(cap_clause.moves) { |cap_item| - let cap_def = tcx.def_map.get(cap_item.id); - let cap_def_id = ast_util::def_id_of_def(cap_def).node; - if vec::any(*freevars, {|fv| fv.def == cap_def}) { - cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move }); - } else { - cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop }); - } - } - - let implicit_mode = alt fn_proto { - ast::proto_any | ast::proto_block { cap_ref } - ast::proto_bare | ast::proto_box | ast::proto_uniq { cap_copy } - }; - - vec::iter(*freevars) { |fvar| - let fvar_def_id = ast_util::def_id_of_def(fvar.def).node; - alt cap_map.find(fvar_def_id) { - option::some(_) { /* was explicitly named, do nothing */ } - option::none { - cap_map.insert(fvar_def_id, {def:fvar.def, mode:implicit_mode}); - } - } - } - - let result = []; - cap_map.values { |cap_var| result += [cap_var]; } - ret result; -} diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs deleted file mode 100644 index 6d55aed095e..00000000000 --- a/src/comp/middle/check_alt.rs +++ /dev/null @@ -1,325 +0,0 @@ - -import syntax::ast::*; -import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs, - lit_expr_eq, unguarded_pat}; -import syntax::codemap::span; -import pat_util::*; -import syntax::visit; -import driver::session::session; -import middle::ty; -import middle::ty::*; - -fn check_crate(tcx: ty::ctxt, crate: @crate) { - visit::visit_crate(*crate, (), visit::mk_vt(@{ - visit_expr: bind check_expr(tcx, _, _, _), - visit_local: bind check_local(tcx, _, _, _) - with *visit::default_visitor::<()>() - })); - tcx.sess.abort_if_errors(); -} - -fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) { - visit::visit_expr(ex, s, v); - alt ex.node { - expr_alt(scrut, arms, mode) { - check_arms(tcx, arms); - /* Check for exhaustiveness */ - if mode == alt_exhaustive { - let arms = vec::concat(vec::filter_map(arms, unguarded_pat)); - check_exhaustive(tcx, ex.span, arms); - } - } - _ { } - } -} - -fn check_arms(tcx: ty::ctxt, arms: [arm]) { - let i = 0; - /* Check for unreachable patterns */ - for arm: arm in arms { - for arm_pat: @pat in arm.pats { - let reachable = true; - let j = 0; - while j < i { - if option::is_none(arms[j].guard) { - for prev_pat: @pat in arms[j].pats { - if pattern_supersedes(tcx, prev_pat, arm_pat) { - reachable = false; - } - } - } - j += 1; - } - if !reachable { - tcx.sess.span_err(arm_pat.span, "unreachable pattern"); - } - } - i += 1; - } -} - -fn raw_pat(p: @pat) -> @pat { - alt p.node { - pat_ident(_, some(s)) { raw_pat(s) } - _ { p } - } -} - -fn check_exhaustive(tcx: ty::ctxt, sp: span, pats: [@pat]) { - if pats.len() == 0u { - tcx.sess.span_err(sp, "non-exhaustive patterns"); - ret; - } - // If there a non-refutable pattern in the set, we're okay. - for pat in pats { if !is_refutable(tcx, pat) { ret; } } - - alt ty::get(ty::node_id_to_type(tcx, pats[0].id)).struct { - ty::ty_enum(id, _) { - check_exhaustive_enum(tcx, id, sp, pats); - } - ty::ty_box(_) { - check_exhaustive(tcx, sp, vec::filter_map(pats, {|p| - alt raw_pat(p).node { pat_box(sub) { some(sub) } _ { none } } - })); - } - ty::ty_uniq(_) { - check_exhaustive(tcx, sp, vec::filter_map(pats, {|p| - alt raw_pat(p).node { pat_uniq(sub) { some(sub) } _ { none } } - })); - } - ty::ty_tup(ts) { - let cols = vec::to_mut(vec::init_elt(ts.len(), [])); - for p in pats { - alt raw_pat(p).node { - pat_tup(sub) { - vec::iteri(sub) {|i, sp| cols[i] += [sp];} - } - _ {} - } - } - vec::iter(cols) {|col| check_exhaustive(tcx, sp, col); } - } - ty::ty_rec(fs) { - let cols = vec::init_elt(fs.len(), {mutable wild: false, - mutable pats: []}); - for p in pats { - alt raw_pat(p).node { - pat_rec(sub, _) { - vec::iteri(fs) {|i, field| - alt vec::find(sub, {|pf| pf.ident == field.ident }) { - some(pf) { cols[i].pats += [pf.pat]; } - none { cols[i].wild = true; } - } - } - } - _ {} - } - } - vec::iter(cols) {|col| - if !col.wild { check_exhaustive(tcx, sp, copy col.pats); } - } - } - ty::ty_bool { - let saw_true = false, saw_false = false; - for p in pats { - alt raw_pat(p).node { - pat_lit(@{node: expr_lit(@{node: lit_bool(b), _}), _}) { - if b { saw_true = true; } - else { saw_false = true; } - } - _ {} - } - } - if !saw_true { tcx.sess.span_err( - sp, "non-exhaustive bool patterns: true not covered"); } - if !saw_false { tcx.sess.span_err( - sp, "non-exhaustive bool patterns: false not covered"); } - } - ty::ty_nil { - let seen = vec::any(pats, {|p| - alt raw_pat(p).node { - pat_lit(@{node: expr_lit(@{node: lit_nil, _}), _}) { true } - _ { false } - } - }); - if !seen { tcx.sess.span_err(sp, "non-exhaustive patterns"); } - } - // Literal patterns are always considered non-exhaustive - _ { - tcx.sess.span_err(sp, "non-exhaustive literal patterns"); - } - } -} - -fn check_exhaustive_enum(tcx: ty::ctxt, enum_id: def_id, sp: span, - pats: [@pat]) { - let variants = enum_variants(tcx, enum_id); - let columns_by_variant = vec::map(*variants, {|v| - {mutable seen: false, - cols: vec::to_mut(vec::init_elt(v.args.len(), []))} - }); - - for pat in pats { - let pat = raw_pat(pat); - alt tcx.def_map.get(pat.id) { - def_variant(_, id) { - let variant_idx = - option::get(vec::position(*variants, {|v| v.id == id})); - columns_by_variant[variant_idx].seen = true; - alt pat.node { - pat_enum(_, args) { - vec::iteri(args) {|i, p| - columns_by_variant[variant_idx].cols[i] += [p]; - } - } - _ {} - } - } - _ {} - } - } - - vec::iteri(columns_by_variant) {|i, cv| - if !cv.seen { - tcx.sess.span_err(sp, "non-exhaustive patterns: variant `" + - variants[i].name + "` not covered"); - } else { - vec::iter(cv.cols) {|col| check_exhaustive(tcx, sp, col); } - } - } -} - -fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { - fn patterns_supersede(tcx: ty::ctxt, as: [@pat], bs: [@pat]) -> bool { - let i = 0; - for a: @pat in as { - if !pattern_supersedes(tcx, a, bs[i]) { ret false; } - i += 1; - } - ret true; - } - fn field_patterns_supersede(tcx: ty::ctxt, fas: [field_pat], - fbs: [field_pat]) -> bool { - let wild = @{id: 0, node: pat_wild, span: dummy_sp()}; - for fa: field_pat in fas { - let pb = wild; - for fb: field_pat in fbs { - if fa.ident == fb.ident { pb = fb.pat; } - } - if !pattern_supersedes(tcx, fa.pat, pb) { ret false; } - } - ret true; - } - - alt a.node { - pat_ident(_, some(p)) { pattern_supersedes(tcx, p, b) } - pat_wild { true } - pat_ident(_, none) { - let opt_def_a = tcx.def_map.find(a.id); - alt opt_def_a { - some(def_variant(_, _)) { opt_def_a == tcx.def_map.find(b.id) } - // This is a binding - _ { true } - } - } - pat_enum(va, suba) { - alt b.node { - pat_enum(vb, subb) { - tcx.def_map.get(a.id) == tcx.def_map.get(b.id) && - patterns_supersede(tcx, suba, subb) - } - _ { false } - } - } - pat_rec(suba, _) { - alt b.node { - pat_rec(subb, _) { field_patterns_supersede(tcx, suba, subb) } - _ { false } - } - } - pat_tup(suba) { - alt b.node { - pat_tup(subb) { patterns_supersede(tcx, suba, subb) } - _ { false } - } - } - pat_box(suba) { - alt b.node { - pat_box(subb) { pattern_supersedes(tcx, suba, subb) } - _ { pattern_supersedes(tcx, suba, b) } - } - } - pat_uniq(suba) { - alt b.node { - pat_uniq(subb) { pattern_supersedes(tcx, suba, subb) } - _ { pattern_supersedes(tcx, suba, b) } - } - } - pat_lit(la) { - alt b.node { - pat_lit(lb) { lit_expr_eq(la, lb) } - _ { false } - } - } - pat_range(begina, enda) { - alt b.node { - pat_lit(lb) { - compare_lit_exprs(begina, lb) <= 0 && - compare_lit_exprs(enda, lb) >= 0 - } - pat_range(beginb, endb) { - compare_lit_exprs(begina, beginb) <= 0 && - compare_lit_exprs(enda, endb) >= 0 - } - _ { false } - } - } - } -} - -fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) { - visit::visit_local(loc, s, v); - if is_refutable(tcx, loc.node.pat) { - tcx.sess.span_err(loc.node.pat.span, - "refutable pattern in local binding"); - } -} - -fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool { - alt tcx.def_map.find(pat.id) { - some(def_variant(enum_id, var_id)) { - if vec::len(*ty::enum_variants(tcx, enum_id)) != 1u { ret true; } - } - _ {} - } - - alt pat.node { - pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) { - is_refutable(tcx, sub) - } - pat_wild | pat_ident(_, none) { false } - pat_lit(_) | pat_range(_, _) { true } - pat_rec(fields, _) { - for it: field_pat in fields { - if is_refutable(tcx, it.pat) { ret true; } - } - false - } - pat_tup(elts) { - for elt in elts { if is_refutable(tcx, elt) { ret true; } } - false - } - pat_enum(_, args) { - for p: @pat in args { if is_refutable(tcx, p) { ret true; } } - false - } - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/check_const.rs b/src/comp/middle/check_const.rs deleted file mode 100644 index d04abffb320..00000000000 --- a/src/comp/middle/check_const.rs +++ /dev/null @@ -1,98 +0,0 @@ -import syntax::ast::*; -import syntax::{visit, ast_util}; -import driver::session::session; - -fn check_crate(sess: session, crate: @crate, method_map: typeck::method_map) { - visit::visit_crate(*crate, false, visit::mk_vt(@{ - visit_item: check_item, - visit_pat: check_pat, - visit_expr: bind check_expr(sess, method_map, _, _, _) - with *visit::default_visitor() - })); - sess.abort_if_errors(); -} - -fn check_item(it: @item, &&_is_const: bool, v: visit::vt<bool>) { - alt it.node { - item_const(_, ex) { v.visit_expr(ex, true, v); } - item_enum(vs, _) { - for var in vs { - option::may(var.node.disr_expr) {|ex| - v.visit_expr(ex, true, v); - } - } - } - _ { visit::visit_item(it, false, v); } - } -} - -fn check_pat(p: @pat, &&_is_const: bool, v: visit::vt<bool>) { - fn is_str(e: @expr) -> bool { - alt e.node { expr_lit(@{node: lit_str(_), _}) { true } _ { false } } - } - alt p.node { - // Let through plain string literals here - pat_lit(a) { if !is_str(a) { v.visit_expr(a, true, v); } } - pat_range(a, b) { - if !is_str(a) { v.visit_expr(a, true, v); } - if !is_str(b) { v.visit_expr(b, true, v); } - } - _ { visit::visit_pat(p, false, v); } - } -} - -fn check_expr(sess: session, method_map: typeck::method_map, e: @expr, - &&is_const: bool, v: visit::vt<bool>) { - if is_const { - alt e.node { - expr_unary(box(_), _) | expr_unary(uniq(_), _) | - expr_unary(deref, _){ - sess.span_err(e.span, - "disallowed operator in constant expression"); - ret; - } - expr_lit(@{node: lit_str(_), _}) { - sess.span_err(e.span, - "string constants are not supported"); - } - expr_binary(_, _, _) | expr_unary(_, _) { - if method_map.contains_key(e.id) { - sess.span_err(e.span, "user-defined operators are not \ - allowed in constant expressions"); - } - } - expr_lit(_) {} - _ { - sess.span_err(e.span, - "constant contains unimplemented expression type"); - ret; - } - } - } - alt e.node { - expr_lit(@{node: lit_int(v, t), _}) { - if t != ty_char { - if (v as u64) > ast_util::int_ty_max( - if t == ty_i { sess.targ_cfg.int_type } else { t }) { - sess.span_err(e.span, "literal out of range for its type"); - } - } - } - expr_lit(@{node: lit_uint(v, t), _}) { - if v > ast_util::uint_ty_max( - if t == ty_u { sess.targ_cfg.uint_type } else { t }) { - sess.span_err(e.span, "literal out of range for its type"); - } - } - _ {} - } - visit::visit_expr(e, is_const, v); -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/fn_usage.rs b/src/comp/middle/fn_usage.rs deleted file mode 100644 index c415f5deb05..00000000000 --- a/src/comp/middle/fn_usage.rs +++ /dev/null @@ -1,94 +0,0 @@ -import syntax::ast; -import syntax::visit; -import syntax::print::pprust::expr_to_str; -import driver::session::session; - -export check_crate_fn_usage; - -type fn_usage_ctx = { - tcx: ty::ctxt, - unsafe_fn_legal: bool, - generic_bare_fn_legal: bool -}; - -fn fn_usage_expr(expr: @ast::expr, - ctx: fn_usage_ctx, - v: visit::vt<fn_usage_ctx>) { - alt expr.node { - ast::expr_path(path) { - if !ctx.unsafe_fn_legal { - alt ctx.tcx.def_map.find(expr.id) { - some(ast::def_fn(_, ast::unsafe_fn)) { - log(error, ("expr=", expr_to_str(expr))); - ctx.tcx.sess.span_fatal( - expr.span, - "unsafe functions can only be called"); - } - - _ {} - } - } - if !ctx.generic_bare_fn_legal - && ty::expr_has_ty_params(ctx.tcx, expr) { - alt ty::get(ty::expr_ty(ctx.tcx, expr)).struct { - ty::ty_fn({proto: ast::proto_bare, _}) { - ctx.tcx.sess.span_fatal( - expr.span, - "generic bare functions can only be called or bound"); - } - _ { } - } - } - } - - ast::expr_call(f, args, _) { - let f_ctx = {unsafe_fn_legal: true, - generic_bare_fn_legal: true with ctx}; - v.visit_expr(f, f_ctx, v); - - let args_ctx = {unsafe_fn_legal: false, - generic_bare_fn_legal: false with ctx}; - visit::visit_exprs(args, args_ctx, v); - } - - ast::expr_bind(f, args) { - let f_ctx = {unsafe_fn_legal: false, - generic_bare_fn_legal: true with ctx}; - v.visit_expr(f, f_ctx, v); - - let args_ctx = {unsafe_fn_legal: false, - generic_bare_fn_legal: false with ctx}; - for arg in args { - visit::visit_expr_opt(arg, args_ctx, v); - } - } - - _ { - let subctx = {unsafe_fn_legal: false, - generic_bare_fn_legal: false with ctx}; - visit::visit_expr(expr, subctx, v); - } - } -} - -fn check_crate_fn_usage(tcx: ty::ctxt, crate: @ast::crate) { - let visit = - visit::mk_vt( - @{visit_expr: fn_usage_expr - with *visit::default_visitor()}); - let ctx = { - tcx: tcx, - unsafe_fn_legal: false, - generic_bare_fn_legal: false - }; - visit::visit_crate(*crate, ctx, visit); -} - - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs deleted file mode 100644 index 65a4ae627ea..00000000000 --- a/src/comp/middle/freevars.rs +++ /dev/null @@ -1,121 +0,0 @@ -// A pass that annotates for each loops and functions with the free -// variables that they contain. - -import syntax::print::pprust::path_to_str; -import std::map::*; -import option::*; -import syntax::{ast, ast_util, visit}; -import middle::resolve; -import syntax::codemap::span; - -export annotate_freevars; -export freevar_map; -export freevar_info; -export freevar_entry; -export get_freevars; -export has_freevars; - -// A vector of defs representing the free variables referred to in a function. -// (The def_upvar will already have been stripped). -type freevar_entry = { - def: ast::def, //< The variable being accessed free. - span: span //< First span where it is accessed (there can be multiple) -}; -type freevar_info = @[@freevar_entry]; -type freevar_map = hashmap<ast::node_id, freevar_info>; - -// Searches through part of the AST for all references to locals or -// upvars in this frame and returns the list of definition IDs thus found. -// Since we want to be able to collect upvars in some arbitrary piece -// of the AST, we take a walker function that we invoke with a visitor -// in order to start the search. -fn collect_freevars(def_map: resolve::def_map, blk: ast::blk) - -> freevar_info { - let seen = new_int_hash(); - let refs = @mutable []; - - fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { } - - let walk_expr = fn@(expr: @ast::expr, &&depth: int, v: visit::vt<int>) { - alt expr.node { - ast::expr_fn(proto, decl, _, captures) { - if proto != ast::proto_bare { - visit::visit_expr(expr, depth + 1, v); - } - } - ast::expr_fn_block(_, _) { - visit::visit_expr(expr, depth + 1, v); - } - ast::expr_path(path) { - let i = 0; - alt def_map.find(expr.id) { - none { fail ("Not found: " + path_to_str(path)) } - some(df) { - let def = df; - while i < depth { - alt copy def { - ast::def_upvar(_, inner, _) { def = *inner; } - _ { break; } - } - i += 1; - } - if i == depth { // Made it to end of loop - let dnum = ast_util::def_id_of_def(def).node; - if !seen.contains_key(dnum) { - *refs += [@{def:def, span:expr.span}]; - seen.insert(dnum, ()); - } - } - } - } - } - _ { visit::visit_expr(expr, depth, v); } - } - }; - - let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr - with *visit::default_visitor()}); - v.visit_block(blk, 1, v); - ret @*refs; -} - -// Build a map from every function and for-each body to a set of the -// freevars contained in it. The implementation is not particularly -// efficient as it fully recomputes the free variables at every -// node of interest rather than building up the free variables in -// one pass. This could be improved upon if it turns out to matter. -fn annotate_freevars(def_map: resolve::def_map, crate: @ast::crate) -> - freevar_map { - let freevars = new_int_hash(); - - let walk_fn = fn@(_fk: visit::fn_kind, _decl: ast::fn_decl, - blk: ast::blk, _sp: span, nid: ast::node_id) { - let vars = collect_freevars(def_map, blk); - freevars.insert(nid, vars); - }; - - let visitor = - visit::mk_simple_visitor(@{visit_fn: walk_fn - with *visit::default_simple_visitor()}); - visit::visit_crate(*crate, (), visitor); - - ret freevars; -} - -fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info { - alt tcx.freevars.find(fid) { - none { fail "get_freevars: " + int::str(fid) + " has no freevars"; } - some(d) { ret d; } - } -} -fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool { - ret vec::len(*get_freevars(tcx, fid)) != 0u; -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/inline.rs b/src/comp/middle/inline.rs deleted file mode 100644 index 91d69168faf..00000000000 --- a/src/comp/middle/inline.rs +++ /dev/null @@ -1,100 +0,0 @@ -import std::map::hashmap; -import syntax::ast; -import syntax::ast_util; -import syntax::ast_util::inlined_item_methods; -import syntax::visit; -import middle::typeck::method_map; -import middle::trans::common::maps; -import metadata::csearch; - -export inline_map; -export instantiate_inlines; - -type inline_map = hashmap<ast::def_id, ast::inlined_item>; - -enum ctxt = { - tcx: ty::ctxt, - maps: maps, - inline_map: inline_map, - mut to_process: [ast::inlined_item] -}; - -fn instantiate_inlines(enabled: bool, - tcx: ty::ctxt, - maps: maps, - crate: @ast::crate) -> inline_map { - let vt = visit::mk_vt(@{ - visit_expr: fn@(e: @ast::expr, cx: ctxt, vt: visit::vt<ctxt>) { - visit::visit_expr(e, cx, vt); - cx.visit_expr(e); - } - with *visit::default_visitor::<ctxt>() - }); - let inline_map = ast_util::new_def_id_hash(); - let cx = ctxt({tcx: tcx, maps: maps, - inline_map: inline_map, mutable to_process: []}); - if enabled { visit::visit_crate(*crate, cx, vt); } - while !vec::is_empty(cx.to_process) { - let to_process = []; - to_process <-> cx.to_process; - #debug["Recursively looking at inlined items"]; - vec::iter(to_process) {|ii| - ii.accept(cx, vt); - } - } - ret inline_map; -} - -impl methods for ctxt { - fn visit_expr(e: @ast::expr) { - - // Look for fn items or methods that are referenced which - // ought to be inlined. - - alt e.node { - ast::expr_path(_) { - alt self.tcx.def_map.get(e.id) { - ast::def_fn(did, _) { - self.maybe_enqueue_fn(did); - } - _ { /* not a fn item, fallthrough */ } - } - } - ast::expr_field(_, _, _) { - alt self.maps.method_map.find(e.id) { - some(origin) { - self.maybe_enqueue_impl_method(origin); - } - _ { /* not an impl method, fallthrough */ } - } - } - _ { /* fallthrough */ } - } - } - - fn maybe_enqueue_fn(did: ast::def_id) { - if did.crate == ast::local_crate { ret; } - if self.inline_map.contains_key(did) { ret; } - alt csearch::maybe_get_item_ast(self.tcx, self.maps, did) { - none { - /* no AST attached, do not inline */ - #debug["No AST attached to def %s", - ty::item_path_str(self.tcx, did)]; - } - some(ii) { /* Found an AST, add to table: */ - #debug["Inlining def %s", ty::item_path_str(self.tcx, did)]; - self.to_process += [ii]; - self.inline_map.insert(did, ii); - } - } - } - - fn maybe_enqueue_impl_method(method_origin: typeck::method_origin) { - alt method_origin { - typeck::method_static(did) { self.maybe_enqueue_fn(did); } - typeck::method_param(_, _, _, _) | typeck::method_iface(_, _) { - /* fallthrough */ - } - } - } -} diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs deleted file mode 100644 index ffe2873a3b7..00000000000 --- a/src/comp/middle/kind.rs +++ /dev/null @@ -1,282 +0,0 @@ -import syntax::{visit, ast_util}; -import syntax::ast::*; -import syntax::codemap::span; -import ty::{kind, kind_copyable, kind_sendable, kind_noncopyable}; -import driver::session::session; - -// Kind analysis pass. There are three kinds: -// -// sendable: scalar types, and unique types containing only sendable types -// copyable: boxes, closures, and uniques containing copyable types -// noncopyable: resources, or unique types containing resources -// -// This pass ensures that type parameters are only instantiated with types -// whose kinds are equal or less general than the way the type parameter was -// annotated (with the `send` or `copy` keyword). -// -// It also verifies that noncopyable kinds are not copied. Sendability is not -// applied, since none of our language primitives send. Instead, the sending -// primitives in the stdlib are explicitly annotated to only take sendable -// types. - -fn kind_to_str(k: kind) -> str { - alt k { - kind_sendable { "sendable" } - kind_copyable { "copyable" } - kind_noncopyable { "noncopyable" } - } -} - -type rval_map = std::map::hashmap<node_id, ()>; - -type ctx = {tcx: ty::ctxt, - rval_map: rval_map, - method_map: typeck::method_map, - last_uses: last_use::last_uses}; - -fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - last_uses: last_use::last_uses, crate: @crate) - -> rval_map { - let ctx = {tcx: tcx, - rval_map: std::map::new_int_hash(), - method_map: method_map, - last_uses: last_uses}; - let visit = visit::mk_vt(@{ - visit_expr: check_expr, - visit_stmt: check_stmt, - visit_block: check_block, - visit_fn: check_fn - with *visit::default_visitor() - }); - visit::visit_crate(*crate, ctx, visit); - tcx.sess.abort_if_errors(); - ret ctx.rval_map; -} - -// Yields the appropriate function to check the kind of closed over -// variables. `id` is the node_id for some expression that creates the -// closure. -fn with_appropriate_checker(cx: ctx, id: node_id, - b: fn(fn@(ctx, ty::t, sp: span))) { - let fty = ty::node_id_to_type(cx.tcx, id); - alt ty::ty_fn_proto(fty) { - proto_uniq { b(check_send); } - proto_box { b(check_copy); } - proto_bare { b(check_none); } - proto_any | proto_block { /* no check needed */ } - } -} - -// Check that the free variables used in a shared/sendable closure conform -// to the copy/move kind bounds. Then recursively check the function body. -fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span, - fn_id: node_id, cx: ctx, v: visit::vt<ctx>) { - - // n.b.: This could be the body of either a fn decl or a fn expr. In the - // former case, the prototype will be proto_bare and no check occurs. In - // the latter case, we do not check the variables that in the capture - // clause (as we don't have access to that here) but just those that - // appear free. The capture clauses are checked below, in check_expr(). - // - // We could do this check also in check_expr(), but it seems more - // "future-proof" to do it this way, as check_fn_body() is supposed to be - // the common flow point for all functions that appear in the AST. - - with_appropriate_checker(cx, fn_id) { |checker| - for @{def, span} in *freevars::get_freevars(cx.tcx, fn_id) { - let id = ast_util::def_id_of_def(def).node; - if checker == check_copy { - let last_uses = alt check cx.last_uses.find(fn_id) { - some(last_use::closes_over(vars)) { vars } - none { [] } - }; - if option::is_some(vec::position_elt(last_uses, id)) { cont; } - } - let ty = ty::node_id_to_type(cx.tcx, id); - checker(cx, ty, span); - } - } - - visit::visit_fn(fk, decl, body, sp, fn_id, cx, v); -} - -fn check_fn_cap_clause(cx: ctx, - id: node_id, - cap_clause: capture_clause) { - // Check that the variables named in the clause which are not free vars - // (if any) are also legal. freevars are checked above in check_fn(). - // This is kind of a degenerate case, as captured variables will generally - // appear free in the body. - let freevars = freevars::get_freevars(cx.tcx, id); - let freevar_ids = vec::map(*freevars, { |freevar| - ast_util::def_id_of_def(freevar.def).node - }); - //log("freevar_ids", freevar_ids); - with_appropriate_checker(cx, id) { |checker| - let check_var = fn@(&&cap_item: @capture_item) { - let cap_def = cx.tcx.def_map.get(cap_item.id); - let cap_def_id = ast_util::def_id_of_def(cap_def).node; - if !vec::contains(freevar_ids, cap_def_id) { - let ty = ty::node_id_to_type(cx.tcx, cap_def_id); - checker(cx, ty, cap_item.span); - } - }; - vec::iter(cap_clause.copies, check_var); - vec::iter(cap_clause.moves, check_var); - } -} - -fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) { - alt b.node.expr { - some(ex) { maybe_copy(cx, ex); } - _ {} - } - visit::visit_block(b, cx, v); -} - -fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) { - alt e.node { - expr_assign(_, ex) | expr_assign_op(_, _, ex) | - expr_unary(box(_), ex) | expr_unary(uniq(_), ex) | - expr_ret(some(ex)) { maybe_copy(cx, ex); } - expr_copy(expr) { check_copy_ex(cx, expr, false); } - // Vector add copies. - expr_binary(add, ls, rs) { maybe_copy(cx, ls); maybe_copy(cx, rs); } - expr_rec(fields, def) { - for field in fields { maybe_copy(cx, field.node.expr); } - alt def { - some(ex) { - // All noncopyable fields must be overridden - let t = ty::expr_ty(cx.tcx, ex); - let ty_fields = alt ty::get(t).struct { - ty::ty_rec(f) { f } - _ { cx.tcx.sess.span_bug(ex.span, "Bad expr type in record"); } - }; - for tf in ty_fields { - if !vec::any(fields, {|f| f.node.ident == tf.ident}) && - !ty::kind_can_be_copied(ty::type_kind(cx.tcx, tf.mt.ty)) { - cx.tcx.sess.span_err(ex.span, - "copying a noncopyable value"); - } - } - } - _ {} - } - } - expr_tup(exprs) | expr_vec(exprs, _) { - for expr in exprs { maybe_copy(cx, expr); } - } - expr_bind(_, args) { - for a in args { alt a { some(ex) { maybe_copy(cx, ex); } _ {} } } - } - expr_call(f, args, _) { - let i = 0u; - for arg_t in ty::ty_fn_args(ty::expr_ty(cx.tcx, f)) { - alt ty::arg_mode(cx.tcx, arg_t) { - by_copy { maybe_copy(cx, args[i]); } - by_ref | by_val | by_mutbl_ref | by_move { } - } - i += 1u; - } - } - expr_path(_) { - alt cx.tcx.node_type_substs.find(e.id) { - some(ts) { - let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id)); - let bounds = ty::lookup_item_type(cx.tcx, did).bounds; - let i = 0u; - for ty in ts { - let kind = ty::type_kind(cx.tcx, ty); - let p_kind = ty::param_bounds_to_kind(bounds[i]); - if !ty::kind_lteq(p_kind, kind) { - cx.tcx.sess.span_err(e.span, "instantiating a " + - kind_to_str(p_kind) + - " type parameter with a " - + kind_to_str(kind) + " type"); - } - i += 1u; - } - } - none {} - } - } - expr_fn(_, _, _, cap_clause) { - check_fn_cap_clause(cx, e.id, *cap_clause); - } - _ { } - } - visit::visit_expr(e, cx, v); -} - -fn check_stmt(stmt: @stmt, cx: ctx, v: visit::vt<ctx>) { - alt stmt.node { - stmt_decl(@{node: decl_local(locals), _}, _) { - for local in locals { - alt local.node.init { - some({op: init_assign, expr}) { maybe_copy(cx, expr); } - _ {} - } - } - } - _ {} - } - visit::visit_stmt(stmt, cx, v); -} - -fn maybe_copy(cx: ctx, ex: @expr) { - check_copy_ex(cx, ex, true); -} - -fn is_nullary_variant(cx: ctx, ex: @expr) -> bool { - alt ex.node { - expr_path(_) { - alt cx.tcx.def_map.get(ex.id) { - def_variant(edid, vdid) { - vec::len(ty::enum_variant_with_id(cx.tcx, edid, vdid).args) == 0u - } - _ { false } - } - } - _ { false } - } -} - -fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) { - if ty::expr_is_lval(cx.method_map, ex) && - !cx.last_uses.contains_key(ex.id) && - !is_nullary_variant(cx, ex) { - let ty = ty::expr_ty(cx.tcx, ex); - check_copy(cx, ty, ex.span); - // FIXME turn this on again once vector types are no longer unique. - // Right now, it is too annoying to be useful. - /* if warn && ty::type_is_unique(ty) { - cx.tcx.sess.span_warn(ex.span, "copying a unique value"); - }*/ - } -} - -fn check_copy(cx: ctx, ty: ty::t, sp: span) { - if !ty::kind_can_be_copied(ty::type_kind(cx.tcx, ty)) { - cx.tcx.sess.span_err(sp, "copying a noncopyable value"); - } -} - -fn check_send(cx: ctx, ty: ty::t, sp: span) { - if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) { - cx.tcx.sess.span_err(sp, "not a sendable value"); - } -} - -fn check_none(cx: ctx, _ty: ty::t, sp: span) { - cx.tcx.sess.span_err(sp, "attempted dynamic environment capture"); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs deleted file mode 100644 index 12ffdfccb41..00000000000 --- a/src/comp/middle/last_use.rs +++ /dev/null @@ -1,373 +0,0 @@ -import syntax::{visit, ast_util}; -import syntax::ast::*; -import syntax::codemap::span; -import std::list::{is_not_empty, list, nil, cons, tail}; -import std::util::unreachable; -import std::list; - -// Last use analysis pass. -// -// Finds the last read of each value stored in a local variable or -// callee-owned argument (arguments with by-move or by-copy passing -// style). This is a limited form of liveness analysis, peformed -// (perhaps foolishly) directly on the AST. -// -// The algorithm walks the AST, keeping a set of (def, last_use) -// pairs. When the function is exited, or the local is overwritten, -// the current set of last uses is marked with 'true' in a table. -// Other branches may later overwrite them with 'false' again, since -// they may find a use coming after them. (Marking an expression as a -// last use is only done if it has not already been marked with -// 'false'.) -// -// Some complexity is added to deal with joining control flow branches -// (by `break` or conditionals), and for handling loops. - -// Marks expr_paths that are last uses. -enum is_last_use { - is_last_use, - has_last_use, - closes_over([node_id]), -} -type last_uses = std::map::hashmap<node_id, is_last_use>; - -enum seen { unset, seen(node_id), } -enum block_type { func, loop, } - -enum use { var_use(node_id), close_over(node_id), } -type set = [{def: node_id, uses: list<use>}]; -type bl = @{type: block_type, mutable second: bool, mutable exits: [set]}; - -enum use_id { path(node_id), close(node_id, node_id) } -fn hash_use_id(id: use_id) -> uint { - (alt id { path(i) { i } close(i, j) { (i << 10) + j } }) as uint -} - -type ctx = {last_uses: std::map::hashmap<use_id, bool>, - def_map: resolve::def_map, - ref_map: alias::ref_map, - tcx: ty::ctxt, - // The current set of local last uses - mutable current: set, - mutable blocks: list<bl>}; - -fn find_last_uses(c: @crate, def_map: resolve::def_map, - ref_map: alias::ref_map, tcx: ty::ctxt) -> last_uses { - let v = visit::mk_vt(@{visit_expr: visit_expr, - visit_stmt: visit_stmt, - visit_fn: visit_fn - with *visit::default_visitor()}); - let cx = {last_uses: std::map::mk_hashmap(hash_use_id, {|a, b| a == b}), - def_map: def_map, - ref_map: ref_map, - tcx: tcx, - mutable current: [], - mutable blocks: nil}; - visit::visit_crate(*c, cx, v); - let mini_table = std::map::new_int_hash(); - cx.last_uses.items {|key, val| - if !val { ret; } - alt key { - path(id) { - mini_table.insert(id, is_last_use); - let def_node = ast_util::def_id_of_def(def_map.get(id)).node; - mini_table.insert(def_node, has_last_use); - } - close(fn_id, local_id) { - mini_table.insert(local_id, has_last_use); - let known = alt check mini_table.find(fn_id) { - some(closes_over(ids)) { ids } - none { [] } - }; - mini_table.insert(fn_id, closes_over(known + [local_id])); - } - } - } - ret mini_table; -} - -fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) { - alt ex.node { - expr_ret(oexpr) { - visit::visit_expr_opt(oexpr, cx, v); - if !add_block_exit(cx, func) { leave_fn(cx); } - } - expr_fail(oexpr) { - visit::visit_expr_opt(oexpr, cx, v); - leave_fn(cx); - } - expr_break { add_block_exit(cx, loop); } - expr_while(_, _) | expr_do_while(_, _) { - visit_block(loop, cx) {|| visit::visit_expr(ex, cx, v);} - } - expr_for(_, coll, blk) { - v.visit_expr(coll, cx, v); - visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);} - } - expr_alt(input, arms, _) { - v.visit_expr(input, cx, v); - let before = cx.current, sets = []; - for arm in arms { - cx.current = before; - v.visit_arm(arm, cx, v); - sets += [cx.current]; - } - cx.current = join_branches(sets); - } - expr_if(cond, then, els) { - v.visit_expr(cond, cx, v); - let cur = cx.current; - visit::visit_block(then, cx, v); - cx.current <-> cur; - visit::visit_expr_opt(els, cx, v); - cx.current = join_branches([cur, cx.current]); - } - expr_path(_) { - let my_def = cx.def_map.get(ex.id); - let my_def_id = ast_util::def_id_of_def(my_def).node; - alt cx.ref_map.find(my_def_id) { - option::some(root_id) { - clear_in_current(cx, root_id, false); - } - _ { - option::may(def_is_owned_local(cx, my_def)) {|nid| - clear_in_current(cx, nid, false); - cx.current += [{def: nid, - uses: cons(var_use(ex.id), @nil)}]; - } - } - } - } - expr_swap(lhs, rhs) { - clear_if_path(cx, lhs, v, false); - clear_if_path(cx, rhs, v, false); - } - expr_move(dest, src) | expr_assign(dest, src) { - v.visit_expr(src, cx, v); - clear_if_path(cx, dest, v, true); - } - expr_assign_op(_, dest, src) { - v.visit_expr(src, cx, v); - v.visit_expr(dest, cx, v); - clear_if_path(cx, dest, v, true); - } - expr_fn(_, _, _, cap_clause) { - // n.b.: safe to ignore copies, as if they are unused - // then they are ignored, otherwise they will show up - // as freevars in the body. - vec::iter(cap_clause.moves) {|ci| - clear_def_if_local(cx, cx.def_map.get(ci.id), false); - } - visit::visit_expr(ex, cx, v); - } - expr_call(f, args, _) { - v.visit_expr(f, cx, v); - let i = 0u, fns = []; - let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f)); - for arg in args { - alt arg.node { - expr_fn(_, _, _, _) | expr_fn_block(_, _) - if is_blockish(ty::ty_fn_proto(arg_ts[i].ty)) { - fns += [arg]; - } - _ { - alt ty::arg_mode(cx.tcx, arg_ts[i]) { - by_mutbl_ref { clear_if_path(cx, arg, v, false); } - _ { v.visit_expr(arg, cx, v); } - } - } - } - i += 1u; - } - for f in fns { v.visit_expr(f, cx, v); } - } - _ { visit::visit_expr(ex, cx, v); } - } -} - -fn visit_stmt(s: @stmt, cx: ctx, v: visit::vt<ctx>) { - alt s.node { - stmt_decl(@{node: decl_local(ls), _}, _) { - shadow_in_current(cx, {|id| - for local in ls { - let found = false; - pat_util::pat_bindings(cx.tcx.def_map, local.node.pat, - {|pid, _a, _b| - if pid == id { found = true; } - }); - if found { ret true; } - } - false - }); - } - _ {} - } - visit::visit_stmt(s, cx, v); -} - -fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, - sp: span, id: node_id, - cx: ctx, v: visit::vt<ctx>) { - let fty = ty::node_id_to_type(cx.tcx, id); - let proto = ty::ty_fn_proto(fty); - alt proto { - proto_any | proto_block { - visit_block(func, cx, {|| - shadow_in_current(cx, {|id| - for arg in decl.inputs { if arg.id == id { ret true; } } - false - }); - visit::visit_fn(fk, decl, body, sp, id, cx, v); - }); - } - proto_box | proto_uniq | proto_bare { - alt cx.tcx.freevars.find(id) { - some(vars) { - for v in *vars { - option::may(def_is_owned_local(cx, v.def)) {|nid| - clear_in_current(cx, nid, false); - cx.current += [{def: nid, - uses: cons(close_over(id), @nil)}]; - } - } - } - _ {} - } - let old_cur = [], old_blocks = nil; - cx.blocks <-> old_blocks; - cx.current <-> old_cur; - visit::visit_fn(fk, decl, body, sp, id, cx, v); - cx.blocks <-> old_blocks; - leave_fn(cx); - cx.current <-> old_cur; - } - } -} - -fn visit_block(tp: block_type, cx: ctx, visit: fn()) { - let local = @{type: tp, mutable second: false, mutable exits: []}; - cx.blocks = cons(local, @cx.blocks); - visit(); - local.second = true; - local.exits = []; - visit(); - let cx_blocks = cx.blocks; - cx.blocks = tail(cx_blocks); - local.exits += [cx.current]; - cx.current = join_branches(local.exits); -} - -fn add_block_exit(cx: ctx, tp: block_type) -> bool { - let cur = cx.blocks; - while cur != nil { - alt cur { - cons(b, tail) { - if (b.type == tp) { - if !b.second { b.exits += [cx.current]; } - ret true; - } - cur = *tail; - } - nil { - // typestate can't use the while loop condition -- - // *sigh* - unreachable(); - } - } - } - ret false; -} - -fn join_branches(branches: [set]) -> set { - let found: set = [], i = 0u, l = vec::len(branches); - for set in branches { - i += 1u; - for {def, uses} in set { - if !vec::any(found, {|v| v.def == def}) { - let j = i, nne = uses; - while j < l { - for {def: d2, uses} in branches[j] { - if d2 == def { - list::iter(uses) {|e| - if !list::has(nne, e) { nne = cons(e, @nne); } - } - } - } - j += 1u; - } - found += [{def: def, uses: nne}]; - } - } - } - ret found; -} - -fn leave_fn(cx: ctx) { - for {def, uses} in cx.current { - list::iter(uses) {|use| - let key = alt use { - var_use(pth_id) { path(pth_id) } - close_over(fn_id) { close(fn_id, def) } - }; - if !cx.last_uses.contains_key(key) { - cx.last_uses.insert(key, true); - } - } - } -} - -fn shadow_in_current(cx: ctx, p: fn(node_id) -> bool) { - let out = []; - cx.current <-> out; - for e in out { if !p(e.def) { cx.current += [e]; } } -} - -fn clear_in_current(cx: ctx, my_def: node_id, to: bool) { - for {def, uses} in cx.current { - if def == my_def { - list::iter(uses) {|use| - let key = alt use { - var_use(pth_id) { path(pth_id) } - close_over(fn_id) { close(fn_id, def) } - }; - if !to || !cx.last_uses.contains_key(key) { - cx.last_uses.insert(key, to); - } - } - cx.current = vec::filter(copy cx.current, {|x| x.def != my_def}); - break; - } - } -} - -fn def_is_owned_local(cx: ctx, d: def) -> option<node_id> { - alt d { - def_local(id, _) { some(id) } - def_arg(id, m) { - alt ty::resolved_mode(cx.tcx, m) { - by_copy | by_move { some(id) } - by_ref | by_val | by_mutbl_ref { none } - } - } - def_upvar(_, d, fn_id) { - if is_blockish(ty::ty_fn_proto(ty::node_id_to_type(cx.tcx, fn_id))) { - def_is_owned_local(cx, *d) - } else { none } - } - _ { none } - } -} - -fn clear_def_if_local(cx: ctx, d: def, to: bool) { - alt def_is_owned_local(cx, d) { - some(nid) { clear_in_current(cx, nid, to); } - _ {} - } -} - -fn clear_if_path(cx: ctx, ex: @expr, v: visit::vt<ctx>, to: bool) { - alt ex.node { - expr_path(_) { clear_def_if_local(cx, cx.def_map.get(ex.id), to); } - _ { v.visit_expr(ex, cx, v); } - } -} diff --git a/src/comp/middle/lint.rs b/src/comp/middle/lint.rs deleted file mode 100644 index f46a50ea4a1..00000000000 --- a/src/comp/middle/lint.rs +++ /dev/null @@ -1,164 +0,0 @@ -import driver::session::session; -import middle::ty::ctxt; -import syntax::{ast, visit}; -import front::attr; -import std::io; -import io::writer_util; - -enum option { - ctypes, -} - -impl opt_ for option { - fn desc() -> str { - "lint: " + alt self { - ctypes { "ctypes usage checking" } - } - } - fn run(tcx: ty::ctxt, crate: @ast::crate, time_pass: bool) { - let checker = alt self { - ctypes { - bind check_ctypes(tcx, crate) - } - }; - time(time_pass, self.desc(), checker); - } -} - -// FIXME: Copied from driver.rs, to work around a bug(#1566) -fn time(do_it: bool, what: str, thunk: fn()) { - if !do_it{ ret thunk(); } - let start = std::time::precise_time_s(); - thunk(); - let end = std::time::precise_time_s(); - io::stdout().write_str(#fmt("time: %3.3f s\t%s\n", - end - start, what)); -} - -// Merge lint options specified by crate attributes and rustc command -// line. Precedence: cmdline > attribute > default -fn merge_opts(attrs: [ast::attribute], cmd_opts: [(option, bool)]) -> - [(option, bool)] { - fn str_to_option(name: str) -> (option, bool) { - ret alt check name { - "ctypes" { (ctypes, true) } - "no_ctypes" { (ctypes, false) } - } - } - - fn meta_to_option(meta: @ast::meta_item) -> (option, bool) { - ret alt meta.node { - ast::meta_word(name) { - str_to_option(name) - } - _ { fail "meta_to_option: meta_list contains a non-meta-word"; } - }; - } - - fn default() -> [(option, bool)] { - [(ctypes, true)] - } - - fn contains(xs: [(option, bool)], x: option) -> bool { - for (o, _) in xs { - if o == x { ret true; } - } - ret false; - } - - let result = cmd_opts; - - let lint_metas = - attr::attr_metas(attr::find_attrs_by_name(attrs, "lint")); - - vec::iter(lint_metas) {|mi| - alt mi.node { - ast::meta_list(_, list) { - vec::iter(list) {|e| - let (o, v) = meta_to_option(e); - if !contains(cmd_opts, o) { - result += [(o, v)]; - } - } - } - _ { } - } - }; - - for (o, v) in default() { - if !contains(result, o) { - result += [(o, v)]; - } - } - - ret result; -} - -fn check_ctypes(tcx: ty::ctxt, crate: @ast::crate) { - fn check_native_fn(tcx: ty::ctxt, decl: ast::fn_decl) { - let tys = vec::map(decl.inputs) {|a| a.ty }; - for ty in (tys + [decl.output]) { - alt ty.node { - ast::ty_path(_, id) { - alt tcx.def_map.get(id) { - ast::def_prim_ty(ast::ty_int(ast::ty_i)) { - tcx.sess.span_warn( - ty.span, - "found rust type `int` in native module, while \ - ctypes::c_int or ctypes::long should be used"); - } - ast::def_prim_ty(ast::ty_uint(ast::ty_u)) { - tcx.sess.span_warn( - ty.span, - "found rust type `uint` in native module, while \ - ctypes::c_uint or ctypes::ulong should be used"); - } - _ { } - } - } - _ { } - } - } - } - - fn check_item(tcx: ty::ctxt, it: @ast::item) { - alt it.node { - ast::item_native_mod(nmod) { - for ni in nmod.items { - alt ni.node { - ast::native_item_fn(decl, tps) { - check_native_fn(tcx, decl); - } - _ { } - } - } - } - _ {/* nothing to do */ } - } - } - - let visit = visit::mk_simple_visitor(@{ - visit_item: bind check_item(tcx, _) - with *visit::default_simple_visitor() - }); - visit::visit_crate(*crate, (), visit); -} - -fn check_crate(tcx: ty::ctxt, crate: @ast::crate, - opts: [(option, bool)], time: bool) { - let lint_opts = lint::merge_opts(crate.node.attrs, opts); - for (lopt, switch) in lint_opts { - if switch == true { - lopt.run(tcx, crate, time); - } - } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/mutbl.rs b/src/comp/middle/mutbl.rs deleted file mode 100644 index 836b2631427..00000000000 --- a/src/comp/middle/mutbl.rs +++ /dev/null @@ -1,321 +0,0 @@ -import syntax::ast::*; -import syntax::visit; -import syntax::ast_util; -import driver::session::session; - -enum deref_t { unbox(bool), field, index, } - -type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t}; - -// Finds the root (the thing that is dereferenced) for the given expr, and a -// vec of dereferences that were used on this root. Note that, in this vec, -// the inner derefs come in front, so foo.bar[1] becomes rec(ex=foo, -// ds=[index,field]) -fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) -> - {ex: @expr, ds: @[deref]} { - fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} { - let ds = [], t = t; - while true { - alt ty::get(t).struct { - ty::ty_box(mt) { - ds += [@{mutbl: mt.mutbl == m_mutbl, - kind: unbox(false), - outer_t: t}]; - t = mt.ty; - } - ty::ty_uniq(mt) { - ds += [@{mutbl: mt.mutbl == m_mutbl, - kind: unbox(false), - outer_t: t}]; - t = mt.ty; - } - ty::ty_res(_, inner, tps) { - ds += [@{mutbl: false, kind: unbox(false), outer_t: t}]; - t = ty::substitute_type_params(tcx, tps, inner); - } - ty::ty_enum(did, tps) { - let variants = ty::enum_variants(tcx, did); - if vec::len(*variants) != 1u || - vec::len(variants[0].args) != 1u { - break; - } - ds += [@{mutbl: false, kind: unbox(false), outer_t: t}]; - t = ty::substitute_type_params(tcx, tps, variants[0].args[0]); - } - _ { break; } - } - } - ret {t: t, ds: ds}; - } - let ds: [deref] = [], ex = ex; - while true { - alt copy ex.node { - expr_field(base, ident, _) { - let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base)); - let is_mutbl = false; - alt ty::get(auto_unbox.t).struct { - ty::ty_rec(fields) { - for fld: ty::field in fields { - if str::eq(ident, fld.ident) { - is_mutbl = fld.mt.mutbl == m_mutbl; - break; - } - } - } - _ {} - } - ds += [@{mutbl: is_mutbl, kind: field, outer_t: auto_unbox.t}]; - ds += auto_unbox.ds; - ex = base; - } - expr_index(base, _) { - let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base)); - alt ty::get(auto_unbox.t).struct { - ty::ty_vec(mt) { - ds += - [@{mutbl: mt.mutbl == m_mutbl, - kind: index, - outer_t: auto_unbox.t}]; - } - ty::ty_str { - ds += [@{mutbl: false, kind: index, outer_t: auto_unbox.t}]; - } - _ { break; } - } - ds += auto_unbox.ds; - ex = base; - } - expr_unary(op, base) { - if op == deref { - let base_t = ty::expr_ty(tcx, base); - let is_mutbl = false, ptr = false; - alt ty::get(base_t).struct { - ty::ty_box(mt) { is_mutbl = mt.mutbl == m_mutbl; } - ty::ty_uniq(mt) { is_mutbl = mt.mutbl == m_mutbl; } - ty::ty_res(_, _, _) { } - ty::ty_enum(_, _) { } - ty::ty_ptr(mt) { - is_mutbl = mt.mutbl == m_mutbl; - ptr = true; - } - _ { tcx.sess.span_bug(base.span, "Ill-typed base \ - expression in deref"); } - } - ds += [@{mutbl: is_mutbl, kind: unbox(ptr && is_mutbl), - outer_t: base_t}]; - ex = base; - } else { break; } - } - _ { break; } - } - } - if autoderef { - let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, ex)); - ds += auto_unbox.ds; - } - ret {ex: ex, ds: @ds}; -} - -// Actual mutbl-checking pass - -type mutbl_map = std::map::hashmap<node_id, ()>; -type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map}; - -fn check_crate(tcx: ty::ctxt, crate: @crate) -> mutbl_map { - let cx = @{tcx: tcx, mutbl_map: std::map::new_int_hash()}; - let v = @{visit_expr: bind visit_expr(cx, _, _, _), - visit_decl: bind visit_decl(cx, _, _, _) - with *visit::default_visitor()}; - visit::visit_crate(*crate, (), visit::mk_vt(v)); - ret cx.mutbl_map; -} - -enum msg { msg_assign, msg_move_out, msg_mutbl_ref, } - -fn mk_err(cx: @ctx, span: syntax::codemap::span, msg: msg, name: str) { - cx.tcx.sess.span_err(span, alt msg { - msg_assign { "assigning to " + name } - msg_move_out { "moving out of " + name } - msg_mutbl_ref { "passing " + name + " by mutable reference" } - }); -} - -fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) { - visit::visit_decl(d, e, v); - alt d.node { - decl_local(locs) { - for loc in locs { - alt loc.node.init { - some(init) { - if init.op == init_move { check_move_rhs(cx, init.expr); } - } - none { } - } - } - } - _ { } - } -} - -fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) { - alt ex.node { - expr_call(f, args, _) { check_call(cx, f, args); } - expr_bind(f, args) { check_bind(cx, f, args); } - expr_swap(lhs, rhs) { - check_lval(cx, lhs, msg_assign); - check_lval(cx, rhs, msg_assign); - } - expr_move(dest, src) { - check_lval(cx, dest, msg_assign); - check_move_rhs(cx, src); - } - expr_assign(dest, src) | expr_assign_op(_, dest, src) { - check_lval(cx, dest, msg_assign); - } - expr_fn(_, _, _, cap) { - for moved in cap.moves { - let def = cx.tcx.def_map.get(moved.id); - alt is_immutable_def(cx, def) { - some(name) { mk_err(cx, moved.span, msg_move_out, moved.name); } - _ { } - } - cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ()); - } - } - _ { } - } - visit::visit_expr(ex, e, v); -} - -fn check_lval(cx: @ctx, dest: @expr, msg: msg) { - alt dest.node { - expr_path(p) { - let def = cx.tcx.def_map.get(dest.id); - alt is_immutable_def(cx, def) { - some(name) { mk_err(cx, dest.span, msg, name); } - _ { } - } - cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ()); - } - _ { - let root = expr_root(cx.tcx, dest, false); - if vec::len(*root.ds) == 0u { - if msg != msg_move_out { - mk_err(cx, dest.span, msg, "non-lvalue"); - } - } else if !root.ds[0].mutbl { - let name = - alt root.ds[0].kind { - mutbl::unbox(_) { "immutable box" } - mutbl::field { "immutable field" } - mutbl::index { "immutable vec content" } - }; - mk_err(cx, dest.span, msg, name); - } - } - } -} - -fn check_move_rhs(cx: @ctx, src: @expr) { - alt src.node { - expr_path(p) { - alt cx.tcx.def_map.get(src.id) { - def_self(_) { - mk_err(cx, src.span, msg_move_out, "method self"); - } - _ { } - } - check_lval(cx, src, msg_move_out); - } - _ { - let root = expr_root(cx.tcx, src, false); - - // Not a path and no-derefs means this is a temporary. - if vec::len(*root.ds) != 0u && - root.ds[vec::len(*root.ds) - 1u].kind != unbox(true) { - cx.tcx.sess.span_err(src.span, "moving out of a data structure"); - } - } - } -} - -fn check_call(cx: @ctx, f: @expr, args: [@expr]) { - let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f)); - let i = 0u; - for arg_t: ty::arg in arg_ts { - alt ty::resolved_mode(cx.tcx, arg_t.mode) { - by_mutbl_ref { check_lval(cx, args[i], msg_mutbl_ref); } - by_move { check_lval(cx, args[i], msg_move_out); } - by_ref | by_val | by_copy { } - } - i += 1u; - } -} - -fn check_bind(cx: @ctx, f: @expr, args: [option<@expr>]) { - let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f)); - let i = 0u; - for arg in args { - alt arg { - some(expr) { - let o_msg = alt ty::resolved_mode(cx.tcx, arg_ts[i].mode) { - by_mutbl_ref { some("by mutable reference") } - by_move { some("by move") } - _ { none } - }; - alt o_msg { - some(name) { - cx.tcx.sess.span_err( - expr.span, "can not bind an argument passed " + name); - } - none {} - } - } - _ {} - } - i += 1u; - } -} - -fn is_immutable_def(cx: @ctx, def: def) -> option<str> { - alt def { - def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) | - def_use(_) { - some("static item") - } - def_arg(_, m) { - alt ty::resolved_mode(cx.tcx, m) { - by_ref | by_val { some("argument") } - by_mutbl_ref | by_move | by_copy { none } - } - } - def_self(_) { some("self argument") } - def_upvar(_, inner, node_id) { - let ty = ty::node_id_to_type(cx.tcx, node_id); - let proto = ty::ty_fn_proto(ty); - ret alt proto { - proto_any | proto_block { is_immutable_def(cx, *inner) } - _ { some("upvar") } - }; - } - - // Note: we should *always* allow all local variables to be assigned - // here and then guarantee in the typestate pass that immutable local - // variables are assigned at most once. But this requires a new kind of - // propagation (def. not assigned), so I didn't do that. - def_local(_, false) if cx.tcx.sess.opts.enforce_mut_vars { - some("immutable local variable") - } - - def_binding(_) { some("binding") } - _ { none } - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/pat_util.rs b/src/comp/middle/pat_util.rs deleted file mode 100644 index 1a6856e36bf..00000000000 --- a/src/comp/middle/pat_util.rs +++ /dev/null @@ -1,70 +0,0 @@ -import syntax::ast::*; -import syntax::ast_util; -import syntax::ast_util::respan; -import syntax::fold; -import syntax::fold::*; -import syntax::codemap::span; - -export walk_pat; -export pat_binding_ids, pat_bindings, pat_id_map; -export pat_is_variant; -export path_to_ident; - -type pat_id_map = std::map::hashmap<str, node_id>; - -// This is used because same-named variables in alternative patterns need to -// use the node_id of their namesake in the first pattern. -fn pat_id_map(dm: resolve::def_map, pat: @pat) -> pat_id_map { - let map = std::map::new_str_hash(); - pat_bindings(dm, pat) {|p_id, _s, n| - map.insert(path_to_ident(n), p_id); - }; - ret map; -} - -fn pat_is_variant(dm: resolve::def_map, pat: @pat) -> bool { - alt pat.node { - pat_enum(_, _) { true } - pat_ident(_, none) { - alt dm.find(pat.id) { - some(def_variant(_, _)) { true } - _ { false } - } - } - _ { false } - } -} - -// This does *not* normalize. The pattern should be already normalized -// if you want to get a normalized pattern out of it. -// Could return a constrained type in order to express that (future work) -fn pat_bindings(dm: resolve::def_map, pat: @pat, - it: fn(node_id, span, @path)) { - walk_pat(pat) {|p| - alt p.node { - pat_ident(pth, _) if !pat_is_variant(dm, p) { - it(p.id, p.span, pth); - } - _ {} - } - } -} - -fn walk_pat(pat: @pat, it: fn(@pat)) { - it(pat); - alt pat.node { - pat_ident(pth, some(p)) { walk_pat(p, it); } - pat_rec(fields, _) { for f in fields { walk_pat(f.pat, it); } } - pat_enum(_, s) | pat_tup(s) { for p in s { walk_pat(p, it); } } - pat_box(s) | pat_uniq(s) { walk_pat(s, it); } - pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, none) {} - } -} - -fn pat_binding_ids(dm: resolve::def_map, pat: @pat) -> [node_id] { - let found = []; - pat_bindings(dm, pat) {|b_id, _sp, _pt| found += [b_id]; }; - ret found; -} - -fn path_to_ident(p: @path) -> ident { vec::last_total(p.node.idents) } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs deleted file mode 100644 index 117641c9fe8..00000000000 --- a/src/comp/middle/resolve.rs +++ /dev/null @@ -1,2381 +0,0 @@ -import syntax::{ast, ast_util, codemap}; -import syntax::ast::*; -import ast::{ident, fn_ident, def, def_id, node_id}; -import syntax::ast_util::{local_def, def_id_of_def, class_item_ident}; -import pat_util::*; - -import front::attr; -import metadata::{csearch, cstore}; -import driver::session::session; -import util::common::*; -import std::map::{new_int_hash, new_str_hash}; -import syntax::codemap::span; -import syntax::visit; -import visit::vt; -import std::{list, deque}; -import std::map::hashmap; -import std::list::{list, nil, cons}; -import option::{is_none, is_some}; -import syntax::print::pprust::*; - -export resolve_crate, resolve_crate_reexports; -export def_map, ext_map, exp_map, impl_map; -export _impl, iscopes, method_info; - -// Resolving happens in two passes. The first pass collects defids of all -// (internal) imports and modules, so that they can be looked up when needed, -// and then uses this information to resolve the imports. The second pass -// locates all names (in expressions, types, and alt patterns) and resolves -// them, storing the resulting def in the AST nodes. - -enum scope { - scope_toplevel, - scope_crate, - scope_item(@ast::item), - scope_bare_fn(ast::fn_decl, node_id, [ast::ty_param]), - scope_fn_expr(ast::fn_decl, node_id, [ast::ty_param]), - scope_native_item(@ast::native_item), - scope_loop(@ast::local), // there's only 1 decl per loop. - scope_block(ast::blk, @mutable uint, @mutable uint), - scope_arm(ast::arm), - scope_method(ast::node_id, [ast::ty_param]), -} - -type scopes = list<scope>; - -fn top_scope() -> scopes { - cons(scope_crate, @cons(scope_toplevel, @nil)) -} - -enum import_state { - todo(ast::node_id, ast::ident, @[ast::ident], span, scopes), - is_glob(@[ast::ident], scopes, span), - resolving(span), - resolved(option<def>, /* value */ - option<def>, /* type */ - option<def>, /* module */ - @[@_impl], /* impls */ - /* used for reporting unused import warning */ - ast::ident, span), -} - -enum glob_import_state { - glob_resolving(span), - glob_resolved(option<def>, /* value */ - option<def>, /* type */ - option<def>), /* module */ -} - -type ext_hash = hashmap<{did: def_id, ident: str, ns: namespace}, def>; - -fn new_ext_hash() -> ext_hash { - type key = {did: def_id, ident: str, ns: namespace}; - fn hash(v: key) -> uint { - ret str::hash(v.ident) + util::common::hash_def(v.did) + - alt v.ns { - ns_val(_) { 1u } - ns_type { 2u } - ns_module { 3u } - }; - } - fn eq(v1: key, v2: key) -> bool { - ret util::common::def_eq(v1.did, v2.did) && - str::eq(v1.ident, v2.ident) && v1.ns == v2.ns; - } - ret std::map::mk_hashmap::<key, def>(hash, eq); -} - -enum mod_index_entry { - mie_view_item(ident, node_id, span), - mie_import_ident(node_id, span), - mie_item(@ast::item), - mie_class_item(node_id, /* parent class name */ - @ast::class_item), /* class member */ - mie_native_item(@ast::native_item), - mie_enum_variant(/* variant index */uint, - /*parts of enum item*/ [variant], - node_id, span), -} - -type mod_index = hashmap<ident, list<mod_index_entry>>; - -// A tuple of an imported def and the view_path from its originating import -type glob_imp_def = {def: def, path: @ast::view_path}; - -type indexed_mod = { - m: option<ast::_mod>, - index: mod_index, - mutable glob_imports: [glob_imp_def], - mutable globbed_exports: [ident], - glob_imported_names: hashmap<str, glob_import_state>, - path: str -}; - -/* native modules can't contain enums, and we don't store their ASTs because - we only need to look at them to determine exports, which they can't - control.*/ - -type def_map = hashmap<node_id, def>; -type ext_map = hashmap<def_id, [ident]>; -type exp_map = hashmap<str, @mutable [def]>; -type impl_map = hashmap<node_id, iscopes>; -type impl_cache = hashmap<def_id, option<@[@_impl]>>; - -type env = - {cstore: cstore::cstore, - def_map: def_map, - ast_map: ast_map::map, - imports: hashmap<ast::node_id, import_state>, - exp_map: exp_map, - mod_map: hashmap<ast::node_id, @indexed_mod>, - block_map: hashmap<ast::node_id, [glob_imp_def]>, - ext_map: ext_map, - impl_map: impl_map, - impl_cache: impl_cache, - ext_cache: ext_hash, - used_imports: {mutable track: bool, - mutable data: [ast::node_id]}, - mutable reported: [{ident: str, sc: scope}], - mutable ignored_imports: [node_id], - mutable current_tp: option<uint>, - mutable resolve_unexported: bool, - sess: session}; - - -// Used to distinguish between lookups from outside and from inside modules, -// since export restrictions should only be applied for the former. -enum dir { inside, outside, } - -// There are two types of ns_value enum: "definitely a enum"; and "enum or -// other value". This is so that lookup can behave differently when looking up -// a variable name that's not yet in scope to check if it's already bound to a -// enum. -enum namespace { ns_val(enumness), ns_type, ns_module, } -enum enumness { - definite_enum, - value_or_enum -} - -fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) -> - {def_map: def_map, exp_map: exp_map, impl_map: impl_map} { - let e = create_env(sess, amap); - map_crate(e, crate); - resolve_imports(*e); - check_exports(e); - resolve_names(e, crate); - resolve_impls(e, crate); - // check_for_collisions must happen after resolve_names so we - // don't complain if a pattern uses the same nullary enum twice - check_for_collisions(e, *crate); - if sess.opts.warn_unused_imports { - check_unused_imports(e); - } - ret {def_map: e.def_map, exp_map: e.exp_map, impl_map: e.impl_map}; -} - -// Used by rustdoc -fn resolve_crate_reexports(sess: session, amap: ast_map::map, - crate: @ast::crate) -> exp_map { - let e = create_env(sess, amap); - map_crate(e, crate); - resolve_imports(*e); - check_exports(e); - ret e.exp_map; -} - -fn create_env(sess: session, amap: ast_map::map) -> @env { - @{cstore: sess.cstore, - def_map: new_int_hash(), - ast_map: amap, - imports: new_int_hash(), - exp_map: new_str_hash(), - mod_map: new_int_hash(), - block_map: new_int_hash(), - ext_map: new_def_hash(), - impl_map: new_int_hash(), - impl_cache: new_def_hash(), - ext_cache: new_ext_hash(), - used_imports: {mutable track: false, mutable data: []}, - mutable reported: [], - mutable ignored_imports: [], - mutable current_tp: none, - mutable resolve_unexported: false, - sess: sess} -} - -fn iter_export_paths(vi: ast::view_item, f: fn(vp: @ast::view_path)) { - alt vi.node { - ast::view_item_export(vps) { - for vp in vps { - f(vp); - } - } - _ {} - } -} - -fn iter_import_paths(vi: ast::view_item, f: fn(vp: @ast::view_path)) { - alt vi.node { - ast::view_item_import(vps) { - for vp in vps { - f(vp); - } - } - _ {} - } -} - -fn iter_effective_import_paths(vi: ast::view_item, - f: fn(vp: @ast::view_path)) { - iter_import_paths(vi, f); - iter_export_paths(vi) {|vp| - alt vp.node { - ast::view_path_simple(_, _, _) { } - // FIXME: support uniform ident-list exports eventually; - // at the moment they have half a meaning as reaching into - // tags. - ast::view_path_list(_, _, _) {} - ast::view_path_glob(_,_) { - f(vp); - } - } - } -} - -// Locate all modules and imports and index them, so that the next passes can -// resolve through them. -fn map_crate(e: @env, c: @ast::crate) { - - fn index_vi(e: @env, i: @ast::view_item, sc: scopes, _v: vt<scopes>) { - iter_effective_import_paths(*i) { |vp| - alt vp.node { - ast::view_path_simple(name, path, id) { - e.imports.insert(id, todo(id, name, path, vp.span, sc)); - } - ast::view_path_glob(path, id) { - e.imports.insert(id, is_glob(path, sc, vp.span)); - } - ast::view_path_list(mod_path, idents, _) { - for ident in idents { - let t = todo(ident.node.id, ident.node.name, - @(*mod_path + [ident.node.name]), - ident.span, sc); - e.imports.insert(ident.node.id, t); - } - } - } - } - } - - fn path_from_scope(sc: scopes, n: str) -> str { - let path = n + "::"; - list::iter(sc) {|s| - alt s { - scope_item(i) { path = i.ident + "::" + path; } - _ {} - } - } - path - } - - fn index_i(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) { - visit_item_with_scope(e, i, sc, v); - alt i.node { - ast::item_mod(md) { - e.mod_map.insert(i.id, - @{m: some(md), - index: index_mod(md), - mutable glob_imports: [], - mutable globbed_exports: [], - glob_imported_names: new_str_hash(), - path: path_from_scope(sc, i.ident)}); - } - ast::item_native_mod(nmd) { - e.mod_map.insert(i.id, - @{m: none::<ast::_mod>, - index: index_nmod(nmd), - mutable glob_imports: [], - mutable globbed_exports: [], - glob_imported_names: new_str_hash(), - path: path_from_scope(sc, i.ident)}); - } - _ { } - } - } - - // Note: a glob export works as an implict import, along with a - // re-export of anything that was exported at the glob-target location. - // So we wind up reusing the glob-import machinery when looking at - // glob exports. They just do re-exporting in a later step. - fn link_glob(e: @env, vi: @ast::view_item, sc: scopes, _v: vt<scopes>) { - iter_effective_import_paths(*vi) { |vp| - alt vp.node { - ast::view_path_glob(path, _) { - alt follow_import(*e, sc, *path, vp.span) { - some(imp) { - let glob = {def: imp, path: vp}; - alt list::head(sc) { - scope_item(i) { - e.mod_map.get(i.id).glob_imports += [glob]; - } - scope_block(b, _, _) { - let globs = alt e.block_map.find(b.node.id) { - some(globs) { globs + [glob] } - none { [glob] } - }; - e.block_map.insert(b.node.id, globs); - } - scope_crate { - e.mod_map.get(ast::crate_node_id).glob_imports - += [glob]; - } - _ { e.sess.span_bug(vi.span, "Unexpected scope in a \ - glob import"); } - } - } - _ { } - } - } - _ { } - } - } - } - - // First, find all the modules, and index the names that they contain - let v_map_mod = - @{visit_view_item: bind index_vi(e, _, _, _), - visit_item: bind index_i(e, _, _, _), - visit_block: visit_block_with_scope - with *visit::default_visitor::<scopes>()}; - visit::visit_crate(*c, top_scope(), visit::mk_vt(v_map_mod)); - - // Register the top-level mod - e.mod_map.insert(ast::crate_node_id, - @{m: some(c.node.module), - index: index_mod(c.node.module), - mutable glob_imports: [], - mutable globbed_exports: [], - glob_imported_names: new_str_hash(), - path: ""}); - - // Next, assemble the links for globbed imports and exports. - let v_link_glob = - @{visit_view_item: bind link_glob(e, _, _, _), - visit_block: visit_block_with_scope, - visit_item: bind visit_item_with_scope(e, _, _, _) - with *visit::default_visitor::<scopes>()}; - visit::visit_crate(*c, top_scope(), visit::mk_vt(v_link_glob)); - -} - -fn resolve_imports(e: env) { - e.used_imports.track = true; - e.imports.values {|v| - alt v { - todo(node_id, name, path, span, scopes) { - resolve_import(e, local_def(node_id), name, *path, span, scopes); - } - resolved(_, _, _, _, _, _) | is_glob(_, _, _) { } - _ { e.sess.bug("Shouldn't see a resolving in resolve_imports"); } - } - }; - e.used_imports.track = false; - e.sess.abort_if_errors(); -} - -fn check_unused_imports(e: @env) { - e.imports.items {|k, v| - alt v { - resolved(_, _, _, _, name, sp) { - if !vec::contains(e.used_imports.data, k) { - e.sess.span_warn(sp, "unused import " + name); - } - } - _ { } - } - }; -} - -fn resolve_capture_item(e: @env, sc: scopes, &&cap_item: @ast::capture_item) { - let dcur = lookup_in_scope_strict( - *e, sc, cap_item.span, cap_item.name, ns_val(value_or_enum)); - maybe_insert(e, cap_item.id, dcur); -} - -fn maybe_insert(e: @env, id: node_id, def: option<def>) { - alt def { - some(df) { e.def_map.insert(id, df); } - _ {} - } -} - -fn resolve_names(e: @env, c: @ast::crate) { - e.used_imports.track = true; - let v = - @{visit_native_item: visit_native_item_with_scope, - visit_item: bind visit_item_with_scope(e, _, _, _), - visit_block: visit_block_with_scope, - visit_decl: visit_decl_with_scope, - visit_arm: visit_arm_with_scope, - visit_local: bind visit_local_with_scope(e, _, _, _), - visit_pat: bind walk_pat(e, _, _, _), - visit_expr: bind walk_expr(e, _, _, _), - visit_ty: bind walk_ty(e, _, _, _), - visit_ty_params: bind walk_tps(e, _, _, _), - visit_constr: bind walk_constr(e, _, _, _, _, _), - visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _) - with *visit::default_visitor()}; - visit::visit_crate(*c, top_scope(), visit::mk_vt(v)); - e.used_imports.track = false; - e.sess.abort_if_errors(); - - fn walk_expr(e: @env, exp: @ast::expr, sc: scopes, v: vt<scopes>) { - visit_expr_with_scope(exp, sc, v); - alt exp.node { - ast::expr_path(p) { - maybe_insert(e, exp.id, - lookup_path_strict(*e, sc, exp.span, p.node, - ns_val(value_or_enum))); - } - ast::expr_fn(_, _, _, cap_clause) { - let rci = bind resolve_capture_item(e, sc, _); - vec::iter(cap_clause.copies, rci); - vec::iter(cap_clause.moves, rci); - } - _ { } - } - } - fn walk_ty(e: @env, t: @ast::ty, sc: scopes, v: vt<scopes>) { - visit::visit_ty(t, sc, v); - alt t.node { - ast::ty_path(p, id) { - maybe_insert(e, id, - lookup_path_strict(*e, sc, t.span, p.node, ns_type)); - } - _ { } - } - } - fn walk_tps(e: @env, tps: [ast::ty_param], sc: scopes, v: vt<scopes>) { - let outer_current_tp = e.current_tp, current = 0u; - for tp in tps { - e.current_tp = some(current); - for bound in *tp.bounds { - alt bound { - bound_iface(t) { v.visit_ty(t, sc, v); } - _ {} - } - } - current += 1u; - } - e.current_tp = outer_current_tp; - } - fn walk_constr(e: @env, p: @ast::path, sp: span, id: node_id, sc: scopes, - _v: vt<scopes>) { - maybe_insert(e, id, lookup_path_strict(*e, sc, - sp, p.node, ns_val(value_or_enum))); - } - fn walk_pat(e: @env, pat: @ast::pat, sc: scopes, v: vt<scopes>) { - visit::visit_pat(pat, sc, v); - alt pat.node { - ast::pat_enum(p, _) { - alt lookup_path_strict(*e, sc, p.span, p.node, - ns_val(value_or_enum)) { - some(fnd@ast::def_variant(_,_)) { - e.def_map.insert(pat.id, fnd); - } - _ { - e.sess.span_err(p.span, - "not a enum variant: " + - ast_util::path_name(p)); - } - } - } - /* Here we determine whether a given pat_ident binds a new - variable a refers to a nullary enum. */ - ast::pat_ident(p, none) { - alt lookup_in_scope(*e, sc, p.span, path_to_ident(p), - ns_val(definite_enum)) { - some(fnd@ast::def_variant(_,_)) { - e.def_map.insert(pat.id, fnd); - } - _ { - // Binds a var -- nothing needs to be done - } - } - } - _ { } - } - } -} - - -// Visit helper functions -fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) { - // Some magic here. Items with the !resolve_unexported attribute - // cause us to consider every name to be exported when resolving their - // contents. This is used to allow the test runner to run unexported - // tests. - let old_resolve_unexported = e.resolve_unexported; - e.resolve_unexported |= - attr::contains_name(attr::attr_metas(i.attrs), - "!resolve_unexported"); - - let sc = cons(scope_item(i), @sc); - alt i.node { - ast::item_impl(tps, ifce, sty, methods) { - visit::visit_ty_params(tps, sc, v); - alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} } - v.visit_ty(sty, sc, v); - for m in methods { - v.visit_ty_params(m.tps, sc, v); - let msc = cons(scope_method(i.id, tps + m.tps), @sc); - v.visit_fn(visit::fk_method(m.ident, []), - m.decl, m.body, m.span, m.id, msc, v); - } - } - ast::item_iface(tps, methods) { - visit::visit_ty_params(tps, sc, v); - for m in methods { - let msc = cons(scope_method(i.id, tps + m.tps), @sc); - for a in m.decl.inputs { v.visit_ty(a.ty, msc, v); } - v.visit_ty(m.decl.output, msc, v); - } - } - ast::item_class(tps, members, ctor_id, ctor_decl, ctor_block) { - visit::visit_ty_params(tps, sc, v); - let class_scope = cons(scope_item(i), @sc); - /* visit the constructor... */ - visit_fn_with_scope(e, visit::fk_item_fn(i.ident, tps), ctor_decl, - ctor_block, ctor_block.span, ctor_id, - class_scope, v); - /* visit the items */ - for cm in members { - alt cm.node.decl { - class_method(i) { visit_item_with_scope(e, i, class_scope, v); } - instance_var(_,t,_,_) { v.visit_ty(t, class_scope, v); } - } - } - } - _ { visit::visit_item(i, sc, v); } - } - - e.resolve_unexported = old_resolve_unexported; -} - -fn visit_native_item_with_scope(ni: @ast::native_item, sc: scopes, - v: vt<scopes>) { - visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v); -} - -fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl, - body: ast::blk, sp: span, - id: node_id, sc: scopes, v: vt<scopes>) { - // is this a main fn declaration? - alt fk { - visit::fk_item_fn(nm, _) { - if is_main_name([ast_map::path_name(nm)]) && - !e.sess.building_library { - // This is a main function -- set it in the session - // as the main ID - e.sess.main_fn = some((id, sp)); - } - } - _ { /* fallthrough */ } - } - - // here's where we need to set up the mapping - // for f's constrs in the table. - for c: @ast::constr in decl.constraints { resolve_constr(e, c, sc, v); } - let scope = alt fk { - visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) | - visit::fk_method(_, tps) { scope_bare_fn(decl, id, tps) } - visit::fk_anon(ast::proto_bare) { scope_bare_fn(decl, id, []) } - visit::fk_anon(_) | visit::fk_fn_block { scope_fn_expr(decl, id, []) } - }; - - visit::visit_fn(fk, decl, body, sp, id, cons(scope, @sc), v); -} - -fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) { - let pos = @mutable 0u, loc = @mutable 0u; - let block_sc = cons(scope_block(b, pos, loc), @sc); - for vi in b.node.view_items { v.visit_view_item(vi, block_sc, v); } - for stmt in b.node.stmts { - v.visit_stmt(stmt, block_sc, v);; - *pos += 1u;; - *loc = 0u; - } - visit::visit_expr_opt(b.node.expr, block_sc, v); -} - -fn visit_decl_with_scope(d: @decl, sc: scopes, v: vt<scopes>) { - let loc_pos = alt list::head(sc) { - scope_block(_, _, pos) { pos } - _ { @mutable 0u } - }; - alt d.node { - decl_local(locs) { - for loc in locs { v.visit_local(loc, sc, v);; *loc_pos += 1u; } - } - decl_item(it) { v.visit_item(it, sc, v); } - } -} - -fn visit_arm_with_scope(a: ast::arm, sc: scopes, v: vt<scopes>) { - for p: @pat in a.pats { v.visit_pat(p, sc, v); } - let sc_inner = cons(scope_arm(a), @sc); - visit::visit_expr_opt(a.guard, sc_inner, v); - v.visit_block(a.body, sc_inner, v); -} - -fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) { - alt x.node { - ast::expr_for(decl, coll, blk) { - let new_sc = cons(scope_loop(decl), @sc); - v.visit_expr(coll, sc, v); - v.visit_local(decl, new_sc, v); - v.visit_block(blk, new_sc, v); - } - _ { visit::visit_expr(x, sc, v); } - } -} - -// This is only for irrefutable patterns (e.g. ones that appear in a let) -// So if x occurs, and x is already known to be a enum, that's always an error -fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt<scopes>) { - // Check whether the given local has the same name as a enum that's - // in scope - // We disallow this, in order to make alt patterns consisting of - // a single identifier unambiguous (does the pattern "foo" refer - // to enum foo, or is it binding a new name foo?) - alt loc.node.pat.node { - pat_ident(an_ident,_) { - // Be sure to pass definite_enum to lookup_in_scope so that - // if this is a name that's being shadowed, we don't die - alt lookup_in_scope(*e, sc, loc.span, - path_to_ident(an_ident), ns_val(definite_enum)) { - some(ast::def_variant(enum_id,variant_id)) { - // Declaration shadows a enum that's in scope. - // That's an error. - e.sess.span_err(loc.span, - #fmt("Declaration of %s shadows a enum that's in scope", - path_to_ident(an_ident))); - } - _ {} - } - } - _ {} - } - visit::visit_local(loc, sc, v); -} - - -fn follow_import(e: env, sc: scopes, path: [ident], sp: span) -> - option<def> { - let path_len = vec::len(path); - let dcur = lookup_in_scope_strict(e, sc, sp, path[0], ns_module); - let i = 1u; - while true { - alt dcur { - some(dcur_def) { - if i == path_len { break; } - dcur = - lookup_in_mod_strict(e, dcur_def, sp, path[i], - ns_module, outside); - i += 1u; - } - _ { break; } - } - } - if i == path_len { - alt dcur { - some(ast::def_mod(_)) | some(ast::def_native_mod(_)) { ret dcur; } - _ { - e.sess.span_err(sp, str::connect(path, "::") + - " does not name a module."); - ret none; - } - } - } else { ret none; } -} - -fn resolve_constr(e: @env, c: @ast::constr, sc: scopes, _v: vt<scopes>) { - alt lookup_path_strict(*e, sc, c.span, c.node.path.node, - ns_val(value_or_enum)) { - some(d@ast::def_fn(_,ast::pure_fn)) { - e.def_map.insert(c.node.id, d); - } - _ { - let s = path_to_str(c.node.path); - e.sess.span_err(c.span, #fmt("%s is not declared pure. Try \ - `pure fn %s` instead of `fn %s`.", s, s, s)); - } - } -} - -// Import resolution -fn resolve_import(e: env, defid: ast::def_id, name: ast::ident, - ids: [ast::ident], sp: codemap::span, sc: scopes) { - fn register(e: env, id: node_id, cx: ctxt, sp: codemap::span, - name: ast::ident, lookup: fn(namespace) -> option<def>, - impls: [@_impl]) { - let val = lookup(ns_val(value_or_enum)), typ = lookup(ns_type), - md = lookup(ns_module); - if is_none(val) && is_none(typ) && is_none(md) && - vec::len(impls) == 0u { - unresolved_err(e, cx, sp, name, "import"); - } else { - e.imports.insert(id, resolved(val, typ, md, @impls, name, sp)); - } - } - // Temporarily disable this import and the imports coming after during - // resolution of this import. - fn find_imports_after(e: env, id: node_id, sc: scopes) -> [node_id] { - fn lst(my_id: node_id, vis: [@view_item]) -> [node_id] { - let imports = [], found = false; - for vi in vis { - iter_effective_import_paths(*vi) {|vp| - alt vp.node { - view_path_simple(_, _, id) - | view_path_glob(_, id) { - if id == my_id { found = true; } - if found { imports += [id]; } - } - view_path_list(_, ids, _) { - for id in ids { - if id.node.id == my_id { found = true; } - if found { imports += [id.node.id]; } - } - } - } - } - } - imports - } - alt sc { - cons(scope_item(@{node: item_mod(m), _}), _) { - lst(id, m.view_items) - } - cons(scope_item(@{node: item_native_mod(m), _}), _) { - lst(id, m.view_items) - } - cons(scope_block(b, _, _), _) { - lst(id, b.node.view_items) - } - cons(scope_crate, _) { - lst(id, - option::get(e.mod_map.get(ast::crate_node_id).m).view_items) - } - _ { - e.sess.bug("find_imports_after: nil or unexpected scope"); - } - } - } - // This function has cleanup code at the end. Do not return without going - // through that. - e.imports.insert(defid.node, resolving(sp)); - let ignored = find_imports_after(e, defid.node, sc); - e.ignored_imports <-> ignored; - let n_idents = vec::len(ids); - let end_id = ids[n_idents - 1u]; - if n_idents == 1u { - register(e, defid.node, in_scope(sc), sp, name, - {|ns| lookup_in_scope(e, sc, sp, end_id, ns) }, []); - } else { - alt lookup_in_scope(e, sc, sp, ids[0], ns_module) { - none { - unresolved_err(e, in_scope(sc), sp, ids[0], ns_name(ns_module)); - } - some(dcur_) { - let dcur = dcur_, i = 1u; - while true { - if i == n_idents - 1u { - let impls = []; - find_impls_in_mod(e, dcur, impls, some(end_id)); - register(e, defid.node, in_mod(dcur), sp, name, {|ns| - lookup_in_mod(e, dcur, sp, end_id, ns, outside) - }, impls); - break; - } else { - dcur = alt lookup_in_mod(e, dcur, sp, ids[i], ns_module, - outside) { - some(dcur) { dcur } - none { - unresolved_err(e, in_mod(dcur), sp, ids[i], - ns_name(ns_module)); - break; - } - }; - i += 1u; - } - } - } - } - } - e.ignored_imports <-> ignored; - // If we couldn't resolve the import, don't leave it in a partially - // resolved state, to avoid having it reported later as a cyclic - // import - alt e.imports.find(defid.node) { - some(resolving(sp)) { - e.imports.insert(defid.node, resolved(none, none, none, @[], "", sp)); - } - _ { } - } -} - - -// Utilities -fn ns_name(ns: namespace) -> str { - alt ns { - ns_type { "typename" } - ns_val(v) { - alt (v) { - value_or_enum { "name" } - definite_enum { "enum" } - } - } - ns_module { "modulename" } - } -} - -enum ctxt { in_mod(def), in_scope(scopes), } - -fn unresolved_err(e: env, cx: ctxt, sp: span, name: ident, kind: str) { - fn find_fn_or_mod_scope(sc: scopes) -> option<scope> { - let sc = sc; - while true { - alt sc { - cons(cur, rest) { - alt cur { - scope_crate | scope_bare_fn(_, _, _) | - scope_fn_expr(_, _, _) | - scope_item(@{node: ast::item_mod(_), _}) { - ret some(cur); - } - _ { sc = *rest; } - } - } - _ { ret none; } - } - } - fail; - } - let path = name; - alt cx { - in_scope(sc) { - alt find_fn_or_mod_scope(sc) { - some(err_scope) { - for rs: {ident: str, sc: scope} in e.reported { - if str::eq(rs.ident, name) && err_scope == rs.sc { ret; } - } - e.reported += [{ident: name, sc: err_scope}]; - } - _ {} - } - } - in_mod(def) { - let did = def_id_of_def(def); - if did.crate == ast::local_crate { - path = e.mod_map.get(did.node).path + path; - } else if did.node != ast::crate_node_id { - let paths = e.ext_map.get(did); - if vec::len(paths) > 0u { - path = str::connect(paths, "::") + "::" + path; - } - } - } - } - e.sess.span_err(sp, mk_unresolved_msg(path, kind)); -} - -fn unresolved_fatal(e: env, sp: span, id: ident, kind: str) -> ! { - e.sess.span_fatal(sp, mk_unresolved_msg(id, kind)); -} - -fn mk_unresolved_msg(id: ident, kind: str) -> str { - ret #fmt["unresolved %s: %s", kind, id]; -} - -// Lookup helpers -fn lookup_path_strict(e: env, sc: scopes, sp: span, pth: ast::path_, - ns: namespace) -> option<def> { - let n_idents = vec::len(pth.idents); - let headns = if n_idents == 1u { ns } else { ns_module }; - - let first_scope = if pth.global { top_scope() } else { sc }; - - let dcur_ = - lookup_in_scope_strict(e, first_scope, sp, pth.idents[0], headns); - - alt dcur_ { - none { ret none; } - some(dcur__) { - let i = 1u; - let dcur = dcur__; - while i < n_idents { - let curns = if n_idents == i + 1u { ns } else { ns_module }; - alt lookup_in_mod_strict(e, dcur, sp, pth.idents[i], - curns, outside) { - none { break; } - some(thing) { dcur = thing; } - } - i += 1u; - } - ret some(dcur); - } - } -} - -fn lookup_in_scope_strict(e: env, sc: scopes, sp: span, name: ident, - ns: namespace) -> option<def> { - alt lookup_in_scope(e, sc, sp, name, ns) { - none { - unresolved_err(e, in_scope(sc), sp, name, ns_name(ns)); - ret none; - } - some(d) { ret some(d); } - } -} - -fn scope_is_fn(sc: scope) -> bool { - ret alt sc { - scope_bare_fn(_, _, _) | scope_native_item(_) { true } - _ { false } - }; -} - -// Returns: -// none - does not close -// some(node_id) - closes via the expr w/ node_id -fn scope_closes(sc: scope) -> option<node_id> { - alt sc { - scope_fn_expr(_, node_id, _) { some(node_id) } - _ { none } - } -} - -fn def_is_local(d: def) -> bool { - alt d { - ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_binding(_) | - ast::def_upvar(_, _, _) { true } - _ { false } - } -} - -fn def_is_self(d: def) -> bool { - alt d { - ast::def_self(_) { true } - _ { false } - } -} - -fn def_is_ty_arg(d: def) -> bool { - ret alt d { ast::def_ty_param(_, _) { true } _ { false } }; -} - -fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace) - -> option<def> { - - fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) -> - option<def> { - alt s { - scope_toplevel { - if ns == ns_type { - ret some(ast::def_prim_ty(alt name { - "bool" { ast::ty_bool } - "int" { ast::ty_int(ast::ty_i) } - "uint" { ast::ty_uint(ast::ty_u) } - "float" { ast::ty_float(ast::ty_f) } - "str" { ast::ty_str } - "char" { ast::ty_int(ast::ty_char) } - "i8" { ast::ty_int(ast::ty_i8) } - "i16" { ast::ty_int(ast::ty_i16) } - "i32" { ast::ty_int(ast::ty_i32) } - "i64" { ast::ty_int(ast::ty_i64) } - "u8" { ast::ty_uint(ast::ty_u8) } - "u16" { ast::ty_uint(ast::ty_u16) } - "u32" { ast::ty_uint(ast::ty_u32) } - "u64" { ast::ty_uint(ast::ty_u64) } - "f32" { ast::ty_float(ast::ty_f32) } - "f64" { ast::ty_float(ast::ty_f64) } - _ { ret none; } - })); - } - } - scope_crate { - ret lookup_in_local_mod(e, ast::crate_node_id, sp, - name, ns, inside); - } - scope_item(it) { - alt it.node { - ast::item_impl(tps, _, _, _) { - if ns == ns_type { ret lookup_in_ty_params(e, name, tps); } - } - ast::item_enum(_, tps) | ast::item_ty(_, tps) { - if ns == ns_type { ret lookup_in_ty_params(e, name, tps); } - } - ast::item_iface(tps, _) { - if ns == ns_type { - if name == "self" { - ret some(def_self(it.id)); - } - ret lookup_in_ty_params(e, name, tps); - } - } - ast::item_mod(_) { - ret lookup_in_local_mod(e, it.id, sp, name, ns, inside); - } - ast::item_native_mod(m) { - ret lookup_in_local_native_mod(e, it.id, sp, name, ns); - } - ast::item_class(tps, members, ctor_id, _, _) { - if ns == ns_type { - ret lookup_in_ty_params(e, name, tps); - } - if ns == ns_val(value_or_enum) && name == it.ident { - ret some(ast::def_fn(local_def(ctor_id), - ast::impure_fn)); - } - if ns == ns_val(value_or_enum) { - ret lookup_in_class(local_def(it.id), - members, name); - } - // FIXME: AST allows other items to appear in a class, - // but that might not be wise - } - _ { } - } - } - scope_method(id, tps) { - if (name == "self" && ns == ns_val(value_or_enum)) { - ret some(ast::def_self(id)); - } else if ns == ns_type { - ret lookup_in_ty_params(e, name, tps); - } - } - scope_native_item(it) { - alt it.node { - ast::native_item_fn(decl, ty_params) { - ret lookup_in_fn(e, name, decl, ty_params, ns); - } - _ { - e.sess.span_bug(it.span, "lookup_in_scope: \ - scope_native_item doesn't refer to a native item"); - } - } - } - scope_bare_fn(decl, _, ty_params) | - scope_fn_expr(decl, _, ty_params) { - ret lookup_in_fn(e, name, decl, ty_params, ns); - } - scope_loop(local) { - if ns == ns_val(value_or_enum) { - alt lookup_in_pat(e, name, local.node.pat) { - some(nid) { ret some(ast::def_binding(nid)); } - _ { } - } - } - } - scope_block(b, pos, loc) { - ret lookup_in_block(e, name, sp, b.node, *pos, *loc, ns); - } - scope_arm(a) { - if ns == ns_val(value_or_enum) { - alt lookup_in_pat(e, name, a.pats[0]) { - some(nid) { ret some(ast::def_binding(nid)); } - _ { ret none; } - } - } - } - } - ret none; - } - let left_fn = false; - let closing = []; - // Used to determine whether self is in scope - let left_fn_level2 = false; - let sc = sc; - while true { - alt copy sc { - nil { ret none; } - cons(hd, tl) { - alt in_scope(e, sp, name, hd, ns) { - some(df_) { - let df = df_; - let local = def_is_local(df), self_scope = def_is_self(df); - if left_fn && local || left_fn_level2 && self_scope - || scope_is_fn(hd) && left_fn && def_is_ty_arg(df) { - let msg = alt ns { - ns_type { - "attempt to use a type argument out of scope" - } - ns_val(v) { - alt(v) { - /* If we were looking for a enum, at this point - we know it's bound to a non-enum value, and - we can return none instead of failing */ - definite_enum { ret none; } - _ { "attempted dynamic environment-capture" } - } - } - _ { "attempted dynamic environment-capture" } - }; - e.sess.span_fatal(sp, msg); - } else if local || self_scope { - let i = vec::len(closing); - while i > 0u { - i -= 1u; - #debug["name=%s df=%?", name, df]; - assert def_is_local(df) || def_is_self(df); - let df_id = def_id_of_def(df).node; - df = ast::def_upvar(df_id, @df, closing[i]); - } - } - ret some(df); - } - _ {} - } - if left_fn { - left_fn_level2 = true; - } else if ns != ns_module { - left_fn = scope_is_fn(hd); - alt scope_closes(hd) { - some(node_id) { closing += [node_id]; } - _ { } - } - } - sc = *tl; - } - } - } - e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh -} - -fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param]) - -> option<def> { - let n = 0u; - for tp: ast::ty_param in ty_params { - if str::eq(tp.ident, name) && alt e.current_tp { - some(cur) { n < cur } none { true } - } { ret some(ast::def_ty_param(local_def(tp.id), n)); } - n += 1u; - } - ret none; -} - -fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option<node_id> { - let found = none; - - pat_util::pat_bindings(e.def_map, pat) {|p_id, _sp, n| - if str::eq(path_to_ident(n), name) - { found = some(p_id); } - }; - ret found; -} - -fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl, - ty_params: [ast::ty_param], - ns: namespace) -> option<def> { - alt ns { - ns_val(value_or_enum) { - for a: ast::arg in decl.inputs { - if str::eq(a.ident, name) { - ret some(ast::def_arg(a.id, a.mode)); - } - } - ret none; - } - ns_type { ret lookup_in_ty_params(e, name, ty_params); } - _ { ret none; } - } -} - -/* - FIXME: not sure about this code. maybe this should be handled - using the mod_index stuff - */ -fn lookup_in_class(parent_id: def_id, - members: [@class_item], name: ident) - -> option<def> { - for m in members { - alt m.node.decl { - instance_var(v_name,_,_,id) { - if v_name == name { - ret some(def_class_field(parent_id, local_def(id))); - } - } - class_method(i) { - if i.ident == name { - ret some(def_class_method(parent_id, local_def(i.id))); - } - } - } - } - ret none; -} - -fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint, - loc_pos: uint, ns: namespace) -> option<def> { - - let i = vec::len(b.stmts); - while i > 0u { - i -= 1u; - let st = b.stmts[i]; - alt st.node { - ast::stmt_decl(d, _) { - alt d.node { - ast::decl_local(locs) { - if i <= pos { - let j = vec::len(locs); - while j > 0u { - j -= 1u; - let loc = locs[j]; - if ns == ns_val(value_or_enum) - && (i < pos || j < loc_pos) { - alt lookup_in_pat(e, name, loc.node.pat) { - some(nid) { - ret some(ast::def_local(nid, - loc.node.is_mutbl)); - } - _ { } - } - } - } - } - } - ast::decl_item(it) { - alt it.node { - ast::item_enum(variants, _) { - if ns == ns_type { - if str::eq(it.ident, name) { - ret some(ast::def_ty(local_def(it.id))); - } - } else { - alt ns { - ns_val(_) { - for v: ast::variant in variants { - if str::eq(v.node.name, name) { - let i = v.node.id; - ret some(ast::def_variant - (local_def(it.id), local_def(i))); - } - } - } - _ {} - } - } - } - _ { - if str::eq(it.ident, name) { - let found = found_def_item(it, ns); - if !is_none(found) { - ret found; - } - } - } - } - } - } - } - _ { } - } - } - for vi in b.view_items { - - let is_import = false; - alt vi.node { - ast::view_item_import(_) { is_import = true; } - _ {} - } - - alt vi.node { - - ast::view_item_import(vps) | ast::view_item_export(vps) { - for vp in vps { - alt vp.node { - ast::view_path_simple(ident, _, id) { - if is_import && name == ident { - ret lookup_import(e, local_def(id), ns); - } - } - - ast::view_path_list(path, idents, _) { - for ident in idents { - if name == ident.node.name { - let def = local_def(ident.node.id); - ret lookup_import(e, def, ns); - } - } - } - - ast::view_path_glob(_, _) { - alt e.block_map.find(b.id) { - some(globs) { - let found = lookup_in_globs(e, globs, sp, name, - ns, inside); - if found != none { - ret found; - } - } - _ {} - } - } - } - } - } - _ { e.sess.span_bug(vi.span, "Unexpected view_item in block"); } - } - } - ret none; -} - -fn found_def_item(i: @ast::item, ns: namespace) -> option<def> { - alt i.node { - ast::item_const(_, _) { - if ns == ns_val(value_or_enum) { - ret some(ast::def_const(local_def(i.id))); } - } - ast::item_fn(decl, _, _) { - if ns == ns_val(value_or_enum) { - ret some(ast::def_fn(local_def(i.id), decl.purity)); - } - } - ast::item_mod(_) { - if ns == ns_module { ret some(ast::def_mod(local_def(i.id))); } - } - ast::item_native_mod(_) { - if ns == ns_module { ret some(ast::def_native_mod(local_def(i.id))); } - } - ast::item_ty(_, _) | item_iface(_, _) | item_enum(_, _) { - if ns == ns_type { ret some(ast::def_ty(local_def(i.id))); } - } - ast::item_res(_, _, _, _, ctor_id) { - alt ns { - ns_val(value_or_enum) { - ret some(ast::def_fn(local_def(ctor_id), ast::impure_fn)); - } - ns_type { ret some(ast::def_ty(local_def(i.id))); } - _ { } - } - } - ast::item_class(_, _, _, _, _) { - if ns == ns_type { - ret some(ast::def_class(local_def(i.id))); - } - } - ast::item_impl(_,_,_,_) { /* ??? */ } - } - ret none; -} - -fn lookup_in_mod_strict(e: env, m: def, sp: span, name: ident, - ns: namespace, dr: dir) -> option<def> { - alt lookup_in_mod(e, m, sp, name, ns, dr) { - none { - unresolved_err(e, in_mod(m), sp, name, ns_name(ns)); - ret none; - } - some(d) { ret some(d); } - } -} - -fn lookup_in_mod(e: env, m: def, sp: span, name: ident, ns: namespace, - dr: dir) -> option<def> { - let defid = def_id_of_def(m); - if defid.crate != ast::local_crate { - // examining a module in an external crate - let cached = e.ext_cache.find({did: defid, ident: name, ns: ns}); - if !is_none(cached) { ret cached; } - let path = [name]; - if defid.node != ast::crate_node_id { - path = cstore::get_path(e.cstore, defid) + path; - } - alt lookup_external(e, defid.crate, path, ns) { - some(df) { - e.ext_cache.insert({did: defid, ident: name, ns: ns}, df); - ret some(df); - } - _ { ret none; } - } - } - alt m { - ast::def_mod(defid) { - ret lookup_in_local_mod(e, defid.node, sp, name, ns, dr); - } - ast::def_native_mod(defid) { - ret lookup_in_local_native_mod(e, defid.node, sp, name, ns); - } - _ { - // Precondition - e.sess.span_bug(sp, "lookup_in_mod was passed a non-mod def"); - } - } -} - -fn found_view_item(e: env, id: node_id) -> option<def> { - alt cstore::find_use_stmt_cnum(e.cstore, id) { - some(cnum) { - some(ast::def_mod({crate: cnum, node: ast::crate_node_id})) - } - none { - // This can happen if we didn't load external crate info. - // Rustdoc depends on this. - none - } - } -} - -fn lookup_import(e: env, defid: def_id, ns: namespace) -> option<def> { - // Imports are simply ignored when resolving themselves. - if vec::contains(e.ignored_imports, defid.node) { ret none; } - alt e.imports.get(defid.node) { - todo(node_id, name, path, span, scopes) { - resolve_import(e, local_def(node_id), name, *path, span, scopes); - ret lookup_import(e, defid, ns); - } - resolving(sp) { - e.sess.span_err(sp, "cyclic import"); - ret none; - } - resolved(val, typ, md, _, _, _) { - if e.used_imports.track { - e.used_imports.data += [defid.node]; - } - ret alt ns { ns_val(_) { val } ns_type { typ } - ns_module { md } }; - } - is_glob(_,_,_) { - e.sess.bug("lookup_import: can't handle is_glob"); - } - } -} - -fn lookup_in_local_native_mod(e: env, node_id: node_id, sp: span, id: ident, - ns: namespace) -> option<def> { - ret lookup_in_local_mod(e, node_id, sp, id, ns, inside); -} - -fn is_exported(e: env, i: ident, m: @indexed_mod) -> bool { - - alt m.m { - some(_m) { - if ast_util::is_exported(i, _m) { ret true; } - } - _ {} - } - - ret vec::contains(m.globbed_exports, i) - || e.resolve_unexported; -} - -fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident, - ns: namespace, dr: dir) -> option<def> { - let info = e.mod_map.get(node_id); - if dr == outside && !is_exported(e, id, info) { - // if we're in a native mod, then dr==inside, so info.m is some _mod - ret none; // name is not visible - } - alt info.index.find(id) { - none { } - some(lst) { - let found = list::find(lst, bind lookup_in_mie(e, _, ns)); - if !is_none(found) { - ret found; - } - } - } - // not local or explicitly imported; try globs: - ret lookup_glob_in_mod(e, info, sp, id, ns, outside); -} - -fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident, - ns: namespace, dr: dir) -> option<def> { - fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident, - ns: namespace, dr: dir) -> option<glob_imp_def> { - alt def.path.node { - - ast::view_path_glob(_, id) { - if vec::contains(e.ignored_imports, id) { ret none; } - } - - _ { - e.sess.span_bug(sp, "lookup_in_globs: not a glob"); - } - } - alt lookup_in_mod(e, def.def, sp, name, ns, dr) { - some(d) { option::some({def: d, path: def.path}) } - none { none } - } - } - let matches = vec::filter_map(copy globs, - bind lookup_in_mod_(e, _, sp, id, ns, dr)); - if vec::len(matches) == 0u { - ret none; - } - else if vec::len(matches) == 1u || ns == ns_val(definite_enum) { - ret some(matches[0].def); - } else { - for match: glob_imp_def in matches { - let sp = match.path.span; - e.sess.span_note(sp, #fmt["'%s' is imported here", id]); - } - e.sess.span_fatal(sp, "'" + id + "' is glob-imported from" + - " multiple different modules."); - } -} - -fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident, - wanted_ns: namespace, dr: dir) -> option<def> { - // since we don't know what names we have in advance, - // absence takes the place of todo() - if !info.glob_imported_names.contains_key(id) { - info.glob_imported_names.insert(id, glob_resolving(sp)); - // kludge - let val_ns = if wanted_ns == ns_val(definite_enum) { - ns_val(definite_enum) - } else { - ns_val(value_or_enum) - }; - let globs = info.glob_imports; - let val = lookup_in_globs(e, globs, sp, id, val_ns, dr); - let typ = lookup_in_globs(e, globs, sp, id, ns_type, dr); - let md = lookup_in_globs(e, globs, sp, id, ns_module, dr); - info.glob_imported_names.insert(id, glob_resolved(val, typ, md)); - } - alt info.glob_imported_names.get(id) { - glob_resolving(sp) { - ret none; - } - glob_resolved(val, typ, md) { - ret alt wanted_ns { - ns_val(_) { val } - ns_type { typ } - ns_module { md } - }; - } - } -} - -fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) -> - option<def> { - alt mie { - mie_view_item(_, id, _) { - if ns == ns_module { ret found_view_item(e, id); } - } - mie_import_ident(id, _) { ret lookup_import(e, local_def(id), ns); } - mie_item(item) { ret found_def_item(item, ns); } - mie_enum_variant(variant_idx, variants, parent_id, parent_span) { - alt ns { - ns_val(_) { - let vid = variants[variant_idx].node.id; - ret some(ast::def_variant(local_def(parent_id), - local_def(vid))); - } - _ { ret none; } - } - } - mie_native_item(native_item) { - alt native_item.node { - ast::native_item_fn(decl, _) { - if ns == ns_val(value_or_enum) { - ret some(ast::def_fn(local_def(native_item.id), - decl.purity)); - } - } - } - } - mie_class_item(parent_id, class_item) { - alt class_item.node.decl { - instance_var(_,_,_,id) { - ret some(ast::def_class_field(local_def(parent_id), - local_def(id))); - } - class_method(it) { - ret some(ast::def_class_method(local_def(parent_id), - local_def(it.id))); - } - } - } - } - ret none; -} - - -// Module indexing -fn add_to_index(index: hashmap<ident, list<mod_index_entry>>, id: ident, - ent: mod_index_entry) { - alt index.find(id) { - none { index.insert(id, cons(ent, @nil::<mod_index_entry>)); } - some(prev) { index.insert(id, cons(ent, @prev)); } - } -} - -fn index_view_items(view_items: [@ast::view_item], - index: hashmap<ident, list<mod_index_entry>>) { - for vi in view_items { - alt vi.node { - ast::view_item_use(ident, _, id) { - add_to_index(index, ident, mie_view_item(ident, id, vi.span)); - } - _ {} - } - - iter_effective_import_paths(*vi) {|vp| - alt vp.node { - ast::view_path_simple(ident, _, id) { - add_to_index(index, ident, mie_import_ident(id, vp.span)); - } - ast::view_path_list(_, idents, _) { - for ident in idents { - add_to_index(index, ident.node.name, - mie_import_ident(ident.node.id, - ident.span)); - } - } - - // globbed imports have to be resolved lazily. - ast::view_path_glob(_, _) {} - } - } - } -} - -fn index_mod(md: ast::_mod) -> mod_index { - let index = new_str_hash::<list<mod_index_entry>>(); - - index_view_items(md.view_items, index); - - for it: @ast::item in md.items { - alt it.node { - ast::item_const(_, _) | ast::item_fn(_, _, _) | ast::item_mod(_) | - ast::item_native_mod(_) | ast::item_ty(_, _) | - ast::item_res(_, _, _, _, _) | - ast::item_impl(_, _, _, _) | ast::item_iface(_, _) { - add_to_index(index, it.ident, mie_item(it)); - } - ast::item_enum(variants, _) { - add_to_index(index, it.ident, mie_item(it)); - let variant_idx: uint = 0u; - for v: ast::variant in variants { - add_to_index(index, v.node.name, - mie_enum_variant(variant_idx, variants, - it.id, it.span)); - variant_idx += 1u; - } - } - ast::item_class(tps, items, ctor_id, ctor_decl, ctor_body) { - // add the class name itself - add_to_index(index, it.ident, mie_item(it)); - // add the constructor decl - add_to_index(index, it.ident, - mie_item(@{ident: it.ident, attrs: [], - id: ctor_id, - node: - item_fn(ctor_decl, tps, ctor_body), - span: ctor_body.span})); - // add the members - for ci in items { - add_to_index(index, class_item_ident(ci), - mie_class_item(it.id, ci)); - } - } - } - } - ret index; -} - - -fn index_nmod(md: ast::native_mod) -> mod_index { - let index = new_str_hash::<list<mod_index_entry>>(); - - index_view_items(md.view_items, index); - - for it: @ast::native_item in md.items { - add_to_index(index, it.ident, mie_native_item(it)); - } - ret index; -} - - -// External lookups -fn ns_for_def(d: def) -> namespace { - alt d { - ast::def_variant(_, _) { ns_val(definite_enum) } - ast::def_fn(_, _) | ast::def_self(_) | - ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) | - ast::def_upvar(_, _, _) | ast::def_self(_) | - ast::def_class_field(_,_) | ast::def_class_method(_,_) - { ns_val(value_or_enum) } - ast::def_mod(_) | ast::def_native_mod(_) { ns_module } - ast::def_ty(_) | ast::def_binding(_) | ast::def_use(_) | - ast::def_ty_param(_, _) | ast::def_prim_ty(_) | ast::def_class(_) - { ns_type } - } -} - -// if we're searching for a value, it's ok if we found -// a enum -fn ns_ok(wanted:namespace, actual:namespace) -> bool { - alt actual { - ns_val(definite_enum) { - alt wanted { - ns_val(_) { true } - _ { false } - } - } - _ { wanted == actual} - } -} - -fn lookup_external(e: env, cnum: int, ids: [ident], ns: namespace) -> - option<def> { - for d: def in csearch::lookup_defs(e.sess.cstore, cnum, ids) { - e.ext_map.insert(def_id_of_def(d), ids); - if ns_ok(ns, ns_for_def(d)) { ret some(d); } - } - ret none; -} - - -// Collision detection -fn check_for_collisions(e: @env, c: ast::crate) { - // Module indices make checking those relatively simple -- just check each - // name for multiple entities in the same namespace. - e.mod_map.values {|val| - val.index.items {|k, v| check_mod_name(*e, k, v); }; - }; - // Other scopes have to be checked the hard way. - let v = - @{visit_item: bind check_item(e, _, _, _), - visit_block: bind check_block(e, _, _, _), - visit_arm: bind check_arm(e, _, _, _), - visit_expr: bind check_expr(e, _, _, _), - visit_ty: bind check_ty(e, _, _, _) with *visit::default_visitor()}; - visit::visit_crate(c, (), visit::mk_vt(v)); -} - -fn check_mod_name(e: env, name: ident, entries: list<mod_index_entry>) { - let saw_mod = false; - let saw_type = false; - let saw_value = false; - let entries = entries; - fn dup(e: env, sp: span, word: str, name: ident) { - e.sess.span_fatal(sp, "duplicate definition of " + word + name); - } - while true { - alt entries { - cons(entry, rest) { - if !is_none(lookup_in_mie(e, entry, ns_val(value_or_enum))) { - if saw_value { - dup(e, mie_span(entry), "", name); - } else { saw_value = true; } - } - if !is_none(lookup_in_mie(e, entry, ns_type)) { - if saw_type { - dup(e, mie_span(entry), "type ", name); - } else { saw_type = true; } - } - if !is_none(lookup_in_mie(e, entry, ns_module)) { - if saw_mod { - dup(e, mie_span(entry), "module ", name); - } else { saw_mod = true; } - } - entries = *rest; - } - nil { break; } - } - } -} - -fn mie_span(mie: mod_index_entry) -> span { - ret alt mie { - mie_view_item(_, _, span) { span } - mie_import_ident(_, span) { span } - mie_item(item) { item.span } - mie_enum_variant(_, _, _, span) { span } - mie_native_item(item) { item.span } - mie_class_item(_,item) { item.span } - }; -} - -fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) { - fn typaram_names(tps: [ast::ty_param]) -> [ident] { - let x: [ast::ident] = []; - for tp: ast::ty_param in tps { x += [tp.ident]; } - ret x; - } - visit::visit_item(i, x, v); - alt i.node { - ast::item_fn(decl, ty_params, _) { - check_fn(*e, i.span, decl); - ensure_unique(*e, i.span, typaram_names(ty_params), ident_id, - "type parameter"); - } - ast::item_enum(_, ty_params) { - ensure_unique(*e, i.span, typaram_names(ty_params), ident_id, - "type parameter"); - } - _ { } - } -} - -fn check_pat(e: @env, ch: checker, p: @ast::pat) { - pat_util::pat_bindings(e.def_map, p) {|_i, p_sp, n| - add_name(ch, p_sp, path_to_ident(n)); - }; -} - -fn check_arm(e: @env, a: ast::arm, &&x: (), v: vt<()>) { - visit::visit_arm(a, x, v); - let ch0 = checker(*e, "binding"); - check_pat(e, ch0, a.pats[0]); - let seen0 = ch0.seen; - let i = vec::len(a.pats); - while i > 1u { - i -= 1u; - let ch = checker(*e, "binding"); - check_pat(e, ch, a.pats[i]); - - // Ensure the bindings introduced in this pattern are the same as in - // the first pattern. - if vec::len(ch.seen) != vec::len(seen0) { - e.sess.span_err(a.pats[i].span, - "inconsistent number of bindings"); - } else { - for name: ident in ch.seen { - if is_none(vec::find(seen0, bind str::eq(name, _))) { - // Fight the alias checker - let name_ = name; - e.sess.span_err(a.pats[i].span, - "binding " + name_ + - " does not occur in first pattern"); - } - } - } - } -} - -fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) { - visit::visit_block(b, x, v); - let values = checker(*e, "value"); - let types = checker(*e, "type"); - let mods = checker(*e, "module"); - for st: @ast::stmt in b.node.stmts { - alt st.node { - ast::stmt_decl(d, _) { - alt d.node { - ast::decl_local(locs) { - let local_values = checker(*e, "value"); - for loc in locs { - pat_util::pat_bindings(e.def_map, loc.node.pat) - {|_i, p_sp, n| - let ident = path_to_ident(n); - add_name(local_values, p_sp, ident); - check_name(values, p_sp, ident); - }; - } - } - ast::decl_item(it) { - alt it.node { - ast::item_enum(variants, _) { - add_name(types, it.span, it.ident); - for v: ast::variant in variants { - add_name(values, v.span, v.node.name); - } - } - ast::item_mod(_) | ast::item_native_mod(_) { - add_name(mods, it.span, it.ident); - } - ast::item_const(_, _) | ast::item_fn(_, _, _) { - add_name(values, it.span, it.ident); - } - ast::item_ty(_, _) | ast::item_iface(_, _) { - add_name(types, it.span, it.ident); - } - ast::item_res(_, _, _, _, _) { - add_name(types, it.span, it.ident); - add_name(values, it.span, it.ident); - } - _ { } - } - } - } - } - _ { } - } - } -} - -fn check_fn(e: env, sp: span, decl: ast::fn_decl) { - fn arg_name(a: ast::arg) -> ident { ret a.ident; } - ensure_unique(e, sp, decl.inputs, arg_name, "argument"); -} - -fn check_expr(e: @env, ex: @ast::expr, &&x: (), v: vt<()>) { - alt ex.node { - ast::expr_rec(fields, _) { - fn field_name(f: ast::field) -> ident { ret f.node.ident; } - ensure_unique(*e, ex.span, fields, field_name, "field"); - } - _ { } - } - visit::visit_expr(ex, x, v); -} - -fn check_ty(e: @env, ty: @ast::ty, &&x: (), v: vt<()>) { - alt ty.node { - ast::ty_rec(fields) { - fn field_name(f: ast::ty_field) -> ident { ret f.node.ident; } - ensure_unique(*e, ty.span, fields, field_name, "field"); - } - _ { } - } - visit::visit_ty(ty, x, v); -} - -type checker = @{mutable seen: [ident], kind: str, sess: session}; - -fn checker(e: env, kind: str) -> checker { - let seen: [ident] = []; - ret @{mutable seen: seen, kind: kind, sess: e.sess}; -} - -fn check_name(ch: checker, sp: span, name: ident) { - for s: ident in ch.seen { - if str::eq(s, name) { - ch.sess.span_fatal(sp, "duplicate " + ch.kind + " name: " + name); - } - } -} -fn add_name(ch: checker, sp: span, name: ident) { - check_name(ch, sp, name); - ch.seen += [name]; -} - -fn ident_id(&&i: ident) -> ident { ret i; } - -fn ensure_unique<T>(e: env, sp: span, elts: [T], id: fn(T) -> ident, - kind: str) { - let ch = checker(e, kind); - for elt: T in elts { add_name(ch, sp, id(elt)); } -} - -fn check_exports(e: @env) { - - fn iter_mod(e: env, m: def, sp: span, _dr: dir, - f: fn(ident: ident, def: def)) { - let defid = def_id_of_def(m); - - if defid.crate != ast::local_crate { - // FIXME: ought to support external export-globs eventually. - e.sess.span_unimpl(sp, "glob-export of items in external crate"); - } else { - - let mid = def_id_of_def(m); - assert mid.crate == ast::local_crate; - let ixm = e.mod_map.get(mid.node); - - ixm.index.items() {|ident, mies| - list::iter(mies) {|mie| - alt mie { - mie_item(item) { - let defs = - [ found_def_item(item, ns_val(value_or_enum)), - found_def_item(item, ns_type), - found_def_item(item, ns_module) ]; - for d in defs { - alt d { - some(def) { - f(ident, def); - } - _ {} - } - } - } - _ { - let s = "glob-export from mod with non-items"; - e.sess.span_unimpl(sp, s); - } - } - } - } - } - } - - - - fn lookup_glob_any(e: @env, info: @indexed_mod, sp: span, path: str, - ident: ident) -> bool { - let lookup = - bind lookup_glob_in_mod(*e, info, sp, ident, _, inside); - let (m, v, t) = (lookup(ns_module), - lookup(ns_val(value_or_enum)), - lookup(ns_type)); - let full_path = path + ident; - maybe_add_reexport(e, full_path, m); - maybe_add_reexport(e, full_path, v); - maybe_add_reexport(e, full_path, t); - is_some(m) || is_some(v) || is_some(t) - } - - fn maybe_add_reexport(e: @env, path: str, def: option<def>) { - alt def { - some(def) { - alt e.exp_map.find(path) { - some(v) { - // If there are multiple reexports of the same def - // using the same path, then we only need one copy - if !vec::contains(*v, def) { - *v += [def]; - } - } - none { e.exp_map.insert(path, @mutable [def]); } - } - } - _ {} - } - } - - fn check_export(e: @env, ident: str, _mod: @indexed_mod, - vi: @view_item) { - let found_something = false; - let full_path = _mod.path + ident; - if _mod.index.contains_key(ident) { - found_something = true; - let xs = _mod.index.get(ident); - list::iter(xs) {|x| - alt x { - mie_import_ident(id, _) { - alt e.imports.get(id) { - resolved(v, t, m, _, rid, _) { - maybe_add_reexport(e, full_path, v); - maybe_add_reexport(e, full_path, t); - maybe_add_reexport(e, full_path, m); - } - _ { } - } - } - _ { } - } - } - } - found_something |= lookup_glob_any(e, _mod, vi.span, - _mod.path, ident); - if !found_something { - e.sess.span_warn(vi.span, - #fmt("exported item %s is not defined", ident)); - } - } - - fn check_enum_ok(e: @env, sp:span, id: ident, _mod: @indexed_mod) - -> node_id { - alt _mod.index.find(id) { - none { e.sess.span_fatal(sp, #fmt("error: undefined id %s \ - in an export", id)); } - some(ms) { - let maybe_id = list::find(ms) {|m| - alt m { - mie_item(an_item) { - alt an_item.node { - item_enum(_,_) { /* OK */ some(an_item.id) } - _ { none } - } - } - _ { none } - } - }; - alt maybe_id { - some(an_id) { ret an_id; } - _ { e.sess.span_fatal(sp, #fmt("error: %s does not refer \ - to an enumeration", id)); } - } - } - } - } - - fn check_export_enum_list(e: @env, _mod: @indexed_mod, - span: codemap::span, id: ast::ident, - ids: [ast::path_list_ident]) { - if vec::len(ids) == 0u { - let _ = check_enum_ok(e, span, id, _mod); - } else { - let parent_id = check_enum_ok(e, span, id, _mod); - for variant_id in ids { - alt _mod.index.find(variant_id.node.name) { - some(ms) { - list::iter(ms) {|m| - alt m { - mie_enum_variant(_, _, actual_parent_id, _) { - if actual_parent_id != parent_id { - let msg = #fmt("variant %s \ - doesn't belong to enum %s", - variant_id.node.name, - id); - e.sess.span_err(span, msg); - } - } - _ { - e.sess.span_err(span, - #fmt("%s is not a variant", - variant_id.node.name)); - } - } - } - } - _ { - e.sess.span_err(span, - #fmt("%s is not a variant", - variant_id.node.name)); - } - } - } - } - } - - e.mod_map.values {|_mod| - alt _mod.m { - some(m) { - let glob_is_re_exported = new_int_hash(); - - for vi in m.view_items { - iter_export_paths(*vi) { |vp| - alt vp.node { - ast::view_path_simple(ident, _, _) { - check_export(e, ident, _mod, vi); - } - ast::view_path_list(path, ids, _) { - let id = if vec::len(*path) == 1u { - path[0] - } else { - e.sess.span_fatal(vp.span, - #fmt("bad export name-list")) - }; - check_export_enum_list(e, _mod, vp.span, id, ids); - } - ast::view_path_glob(_, node_id) { - glob_is_re_exported.insert(node_id, ()); - } - } - } - } - // Now follow the export-glob links and fill in the - // globbed_exports and exp_map lists. - for glob in _mod.glob_imports { - alt check glob.path.node { - ast::view_path_glob(path, node_id) { - if ! glob_is_re_exported.contains_key(node_id) { - cont; - } - } - } - iter_mod(*e, glob.def, - glob.path.span, outside) {|ident, def| - let full_path = _mod.path + ident; - _mod.globbed_exports += [ident]; - maybe_add_reexport(e, full_path, some(def)); - } - } - } - none { } - } - } -} - -// Impl resolution - -type method_info = {did: def_id, n_tps: uint, ident: ast::ident}; -type _impl = {did: def_id, ident: ast::ident, methods: [@method_info]}; -type iscopes = list<@[@_impl]>; - -fn resolve_impls(e: @env, c: @ast::crate) { - visit::visit_crate(*c, nil, visit::mk_vt(@{ - visit_block: bind visit_block_with_impl_scope(e, _, _, _), - visit_mod: bind visit_mod_with_impl_scope(e, _, _, _, _, _), - visit_expr: bind resolve_impl_in_expr(e, _, _, _) - with *visit::default_visitor() - })); -} - -fn find_impls_in_view_item(e: env, vi: @ast::view_item, - &impls: [@_impl], sc: option<iscopes>) { - fn lookup_imported_impls(e: env, id: ast::node_id, - act: fn(@[@_impl])) { - alt e.imports.get(id) { - resolved(_, _, _, is, _, _) { act(is); } - todo(node_id, name, path, span, scopes) { - resolve_import(e, local_def(node_id), name, *path, span, - scopes); - alt check e.imports.get(id) { - resolved(_, _, _, is, _, _) { act(is); } - } - } - _ {} - } - } - - iter_effective_import_paths(*vi) { |vp| - alt vp.node { - ast::view_path_simple(name, pt, id) { - let found = []; - if vec::len(*pt) == 1u { - option::may(sc) {|sc| - list::iter(sc) {|level| - if vec::len(found) > 0u { ret; } - for imp in *level { - if imp.ident == pt[0] { - found += [@{ident: name with *imp}]; - } - } - if vec::len(found) > 0u { impls += found; } - } - } - } else { - lookup_imported_impls(e, id) {|is| - for i in *is { impls += [@{ident: name with *i}]; } - } - } - } - - ast::view_path_list(base, names, _) { - for nm in names { - lookup_imported_impls(e, nm.node.id) {|is| impls += *is; } - } - } - - ast::view_path_glob(ids, id) { - alt check e.imports.get(id) { - is_glob(path, sc, sp) { - alt follow_import(e, sc, *path, sp) { - some(def) { find_impls_in_mod(e, def, impls, none); } - _ {} - } - } - } - } - } - } -} - -fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl], - name: option<ident>, - ck_exports: option<@indexed_mod>) { - alt i.node { - ast::item_impl(_, ifce, _, mthds) { - if alt name { some(n) { n == i.ident } _ { true } } && - alt ck_exports { - some(m) { is_exported(e, i.ident, m) } - _ { true } - } { - impls += [@{did: local_def(i.id), - ident: i.ident, - methods: vec::map(mthds, {|m| - @{did: local_def(m.id), - n_tps: vec::len(m.tps), - ident: m.ident} - })}]; - } - } - _ {} - } -} - -fn find_impls_in_mod_by_id(e: env, defid: def_id, &impls: [@_impl], - name: option<ident>) { - let cached; - alt e.impl_cache.find(defid) { - some(some(v)) { cached = v; } - some(none) { ret; } - none { - e.impl_cache.insert(defid, none); - cached = if defid.crate == ast::local_crate { - let tmp = []; - let mi = e.mod_map.get(defid.node); - let md = option::get(mi.m); - for vi in md.view_items { - find_impls_in_view_item(e, vi, tmp, none); - } - for i in md.items { - find_impls_in_item(e, i, tmp, none, none); - } - @vec::filter(tmp) {|i| is_exported(e, i.ident, mi)} - } else { - csearch::get_impls_for_mod(e.sess.cstore, defid, none) - }; - e.impl_cache.insert(defid, some(cached)); - } - } - alt name { - some(n) { - for im in *cached { - if n == im.ident { impls += [im]; } - } - } - _ { impls += *cached; } - } -} - -fn find_impls_in_mod(e: env, m: def, &impls: [@_impl], - name: option<ident>) { - alt m { - ast::def_mod(defid) { - find_impls_in_mod_by_id(e, defid, impls, name); - } - _ {} - } -} - -fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes, - v: vt<iscopes>) { - let impls = []; - for vi in b.node.view_items { - find_impls_in_view_item(*e, vi, impls, some(sc)); - } - for st in b.node.stmts { - alt st.node { - ast::stmt_decl(@{node: ast::decl_item(i), _}, _) { - find_impls_in_item(*e, i, impls, none, none); - } - _ {} - } - } - let sc = if vec::len(impls) > 0u { cons(@impls, @sc) } else { sc }; - visit::visit_block(b, sc, v); -} - -fn visit_mod_with_impl_scope(e: @env, m: ast::_mod, s: span, id: node_id, - sc: iscopes, v: vt<iscopes>) { - let impls = []; - for vi in m.view_items { - find_impls_in_view_item(*e, vi, impls, some(sc)); - } - for i in m.items { find_impls_in_item(*e, i, impls, none, none); } - let impls = @impls; - visit::visit_mod(m, s, id, if vec::len(*impls) > 0u { - cons(impls, @sc) - } else { - sc - }, v); - e.impl_map.insert(id, cons(impls, @nil)); -} - -fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt<iscopes>) { - alt x.node { - // Store the visible impls in all exprs that might need them - ast::expr_field(_, _, _) | ast::expr_path(_) | ast::expr_cast(_, _) | - ast::expr_binary(_, _, _) | ast::expr_unary(_, _) | - ast::expr_assign_op(_, _, _) | ast::expr_index(_, _) { - e.impl_map.insert(x.id, sc); - } - _ {} - } - visit::visit_expr(x, sc, v); -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/trans/alt.rs b/src/comp/middle/trans/alt.rs deleted file mode 100644 index 29200a47287..00000000000 --- a/src/comp/middle/trans/alt.rs +++ /dev/null @@ -1,741 +0,0 @@ -import driver::session::session; -import lib::llvm::llvm; -import lib::llvm::{ValueRef, BasicBlockRef}; -import pat_util::*; -import build::*; -import base::*; -import syntax::ast; -import syntax::ast_util; -import syntax::ast_util::{dummy_sp}; -import syntax::ast::def_id; -import syntax::codemap::span; -import syntax::print::pprust::pat_to_str; -import back::abi; -import resolve::def_map; - -import common::*; - -// An option identifying a branch (either a literal, a enum variant or a -// range) -enum opt { - lit(@ast::expr), - var(/* disr val */int, /* variant dids */{enm: def_id, var: def_id}), - range(@ast::expr, @ast::expr) -} -fn opt_eq(a: opt, b: opt) -> bool { - alt (a, b) { - (lit(a), lit(b)) { ast_util::compare_lit_exprs(a, b) == 0 } - (range(a1, a2), range(b1, b2)) { - ast_util::compare_lit_exprs(a1, b1) == 0 && - ast_util::compare_lit_exprs(a2, b2) == 0 - } - (var(a, _), var(b, _)) { a == b } - _ { false } - } -} - -enum opt_result { - single_result(result), - range_result(result, result), -} -fn trans_opt(bcx: block, o: opt) -> opt_result { - let ccx = bcx.ccx(), bcx = bcx; - alt o { - lit(l) { - alt l.node { - ast::expr_lit(@{node: ast::lit_str(s), _}) { - let strty = ty::mk_str(bcx.tcx()); - let cell = empty_dest_cell(); - bcx = tvec::trans_str(bcx, s, by_val(cell)); - add_clean_temp(bcx, *cell, strty); - ret single_result(rslt(bcx, *cell)); - } - _ { - ret single_result( - rslt(bcx, trans_const_expr(ccx, l))); - } - } - } - var(disr_val, _) { ret single_result(rslt(bcx, C_int(ccx, disr_val))); } - range(l1, l2) { - ret range_result(rslt(bcx, trans_const_expr(ccx, l1)), - rslt(bcx, trans_const_expr(ccx, l2))); - } - } -} - -fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> opt { - let vdef = ast_util::variant_def_ids(tcx.def_map.get(pat_id)); - let variants = ty::enum_variants(tcx, vdef.enm); - for v: ty::variant_info in *variants { - if vdef.var == v.id { ret var(v.disr_val, vdef); } - } - fail; -} - -type bind_map = [{ident: ast::ident, val: ValueRef}]; -fn assoc(key: str, list: bind_map) -> option<ValueRef> { - for elt: {ident: ast::ident, val: ValueRef} in list { - if str::eq(elt.ident, key) { ret some(elt.val); } - } - ret none; -} - -type match_branch = - @{pats: [@ast::pat], - bound: bind_map, - data: @{body: BasicBlockRef, - guard: option<@ast::expr>, - id_map: pat_id_map}}; -type match = [match_branch]; - -fn has_nested_bindings(m: match, col: uint) -> bool { - for br in m { - alt br.pats[col].node { - ast::pat_ident(_, some(_)) { ret true; } - _ {} - } - } - ret false; -} - -fn expand_nested_bindings(m: match, col: uint, val: ValueRef) -> match { - let result = []; - for br in m { - alt br.pats[col].node { - ast::pat_ident(name, some(inner)) { - let pats = vec::slice(br.pats, 0u, col) + [inner] + - vec::slice(br.pats, col + 1u, br.pats.len()); - result += [@{pats: pats, - bound: br.bound + [{ident: path_to_ident(name), - val: val}] - with *br}]; - } - _ { result += [br]; } - } - } - result -} - -type enter_pat = fn(@ast::pat) -> option<[@ast::pat]>; - -fn enter_match(dm: def_map, m: match, col: uint, val: ValueRef, - e: enter_pat) -> match { - let result = []; - for br: match_branch in m { - alt e(br.pats[col]) { - some(sub) { - let pats = sub + vec::slice(br.pats, 0u, col) + - vec::slice(br.pats, col + 1u, br.pats.len()); - let self = br.pats[col]; - let bound = alt self.node { - ast::pat_ident(name, none) if !pat_is_variant(dm, self) { - br.bound + [{ident: path_to_ident(name), val: val}] - } - _ { br.bound } - }; - result += [@{pats: pats, bound: bound with *br}]; - } - none { } - } - } - ret result; -} - -fn enter_default(dm: def_map, m: match, col: uint, val: ValueRef) -> match { - enter_match(dm, m, col, val) {|p| - alt p.node { - ast::pat_wild | ast::pat_rec(_, _) | ast::pat_tup(_) { some([]) } - ast::pat_ident(_, none) if !pat_is_variant(dm, p) { - some([]) - } - _ { none } - } - } -} - -fn enter_opt(tcx: ty::ctxt, m: match, opt: opt, col: uint, - variant_size: uint, val: ValueRef) -> match { - let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()}; - enter_match(tcx.def_map, m, col, val) {|p| - alt p.node { - ast::pat_enum(_, subpats) { - if opt_eq(variant_opt(tcx, p.id), opt) { some(subpats) } - else { none } - } - ast::pat_ident(_, none) if pat_is_variant(tcx.def_map, p) { - if opt_eq(variant_opt(tcx, p.id), opt) { some([]) } - else { none } - } - ast::pat_lit(l) { - if opt_eq(lit(l), opt) { some([]) } else { none } - } - ast::pat_range(l1, l2) { - if opt_eq(range(l1, l2), opt) { some([]) } else { none } - } - _ { some(vec::init_elt(variant_size, dummy)) } - } - } -} - -fn enter_rec(dm: def_map, m: match, col: uint, fields: [ast::ident], - val: ValueRef) -> match { - let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()}; - enter_match(dm, m, col, val) {|p| - alt p.node { - ast::pat_rec(fpats, _) { - let pats = []; - for fname: ast::ident in fields { - let pat = dummy; - for fpat: ast::field_pat in fpats { - if str::eq(fpat.ident, fname) { pat = fpat.pat; break; } - } - pats += [pat]; - } - some(pats) - } - _ { some(vec::init_elt(fields.len(), dummy)) } - } - } -} - -fn enter_tup(dm: def_map, m: match, col: uint, val: ValueRef, - n_elts: uint) -> match { - let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()}; - enter_match(dm, m, col, val) {|p| - alt p.node { - ast::pat_tup(elts) { some(elts) } - _ { some(vec::init_elt(n_elts, dummy)) } - } - } -} - -fn enter_box(dm: def_map, m: match, col: uint, val: ValueRef) -> match { - let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()}; - enter_match(dm, m, col, val) {|p| - alt p.node { - ast::pat_box(sub) { some([sub]) } - _ { some([dummy]) } - } - } -} - -fn enter_uniq(dm: def_map, m: match, col: uint, val: ValueRef) -> match { - let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()}; - enter_match(dm, m, col, val) {|p| - alt p.node { - ast::pat_uniq(sub) { some([sub]) } - _ { some([dummy]) } - } - } -} - -fn get_options(ccx: crate_ctxt, m: match, col: uint) -> [opt] { - fn add_to_set(&set: [opt], val: opt) { - for l in set { if opt_eq(l, val) { ret; } } - set += [val]; - } - - let found = []; - for br in m { - let cur = br.pats[col]; - if pat_is_variant(ccx.tcx.def_map, cur) { - add_to_set(found, variant_opt(ccx.tcx, br.pats[col].id)); - } else { - alt cur.node { - ast::pat_lit(l) { add_to_set(found, lit(l)); } - ast::pat_range(l1, l2) { - add_to_set(found, range(l1, l2)); - } - _ {} - } - } - } - ret found; -} - -fn extract_variant_args(bcx: block, pat_id: ast::node_id, - vdefs: {enm: def_id, var: def_id}, val: ValueRef) -> - {vals: [ValueRef], bcx: block} { - let ccx = bcx.fcx.ccx, bcx = bcx; - // invariant: - // pat_id must have the same length ty_param_substs as vdefs? - let ty_param_substs = node_id_type_params(bcx, pat_id); - let blobptr = val; - let variants = ty::enum_variants(ccx.tcx, vdefs.enm); - let args = []; - let size = ty::enum_variant_with_id(ccx.tcx, vdefs.enm, - vdefs.var).args.len(); - if size > 0u && (*variants).len() != 1u { - let enumptr = - PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); - blobptr = GEPi(bcx, enumptr, [0, 1]); - } - let i = 0u; - let vdefs_tg = vdefs.enm; - let vdefs_var = vdefs.var; - while i < size { - let r = - // invariant needed: - // how do we know it even makes sense to pass in ty_param_substs - // here? What if it's [] and the enum type has variables in it? - GEP_enum(bcx, blobptr, vdefs_tg, vdefs_var, - ty_param_substs, i); - bcx = r.bcx; - args += [r.val]; - i += 1u; - } - ret {vals: args, bcx: bcx}; -} - -fn collect_record_fields(m: match, col: uint) -> [ast::ident] { - let fields = []; - for br: match_branch in m { - alt br.pats[col].node { - ast::pat_rec(fs, _) { - for f: ast::field_pat in fs { - if !vec::any(fields, bind str::eq(f.ident, _)) { - fields += [f.ident]; - } - } - } - _ { } - } - } - ret fields; -} - -fn any_box_pat(m: match, col: uint) -> bool { - for br: match_branch in m { - alt br.pats[col].node { ast::pat_box(_) { ret true; } _ { } } - } - ret false; -} - -fn any_uniq_pat(m: match, col: uint) -> bool { - for br: match_branch in m { - alt br.pats[col].node { ast::pat_uniq(_) { ret true; } _ { } } - } - ret false; -} - -fn any_tup_pat(m: match, col: uint) -> bool { - for br: match_branch in m { - alt br.pats[col].node { ast::pat_tup(_) { ret true; } _ { } } - } - ret false; -} - -type exit_node = {bound: bind_map, from: BasicBlockRef, to: BasicBlockRef}; -type mk_fail = fn@() -> BasicBlockRef; - -fn pick_col(m: match) -> uint { - fn score(p: @ast::pat) -> uint { - alt p.node { - ast::pat_lit(_) | ast::pat_enum(_, _) | ast::pat_range(_, _) { 1u } - ast::pat_ident(_, some(p)) { score(p) } - _ { 0u } - } - } - let scores = vec::to_mut(vec::init_elt(m[0].pats.len(), 0u)); - for br: match_branch in m { - let i = 0u; - for p: @ast::pat in br.pats { scores[i] += score(p); i += 1u; } - } - let max_score = 0u; - let best_col = 0u; - let i = 0u; - for score: uint in scores { - // Irrefutable columns always go first, they'd only be duplicated in - // the branches. - if score == 0u { ret i; } - // If no irrefutable ones are found, we pick the one with the biggest - // branching factor. - if score > max_score { max_score = score; best_col = i; } - i += 1u; - } - ret best_col; -} - -fn compile_submatch(bcx: block, m: match, vals: [ValueRef], f: mk_fail, - &exits: [exit_node]) { - let bcx = bcx, tcx = bcx.tcx(), dm = tcx.def_map; - if m.len() == 0u { Br(bcx, f()); ret; } - if m[0].pats.len() == 0u { - let data = m[0].data; - alt data.guard { - some(e) { - // Temporarily set bindings. They'll be rewritten to PHI nodes - // for the actual arm block. - data.id_map.items {|key, val| - let loc = local_mem(option::get(assoc(key, m[0].bound))); - bcx.fcx.lllocals.insert(val, loc); - }; - let {bcx: guard_cx, val} = with_scope_result(bcx, "guard") {|bcx| - trans_temp_expr(bcx, e) - }; - bcx = with_cond(guard_cx, Not(guard_cx, val)) {|bcx| - compile_submatch(bcx, vec::tail(m), vals, f, exits); - bcx - }; - } - _ { } - } - if !bcx.unreachable { - exits += [{bound: m[0].bound, from: bcx.llbb, to: data.body}]; - } - Br(bcx, data.body); - ret; - } - - let col = pick_col(m); - let val = vals[col]; - let m = if has_nested_bindings(m, col) { - expand_nested_bindings(m, col, val) - } else { - m - }; - - let vals_left = - vec::slice(vals, 0u, col) + - vec::slice(vals, col + 1u, vals.len()); - let ccx = bcx.fcx.ccx; - let pat_id = 0; - for br: match_branch in m { - // Find a real id (we're adding placeholder wildcard patterns, but - // each column is guaranteed to have at least one real pattern) - if pat_id == 0 { pat_id = br.pats[col].id; } - } - - let rec_fields = collect_record_fields(m, col); - // Separate path for extracting and binding record fields - if rec_fields.len() > 0u { - let rec_ty = node_id_type(bcx, pat_id); - let fields = ty::get_fields(rec_ty); - let rec_vals = []; - for field_name: ast::ident in rec_fields { - let ix = option::get(ty::field_idx(field_name, fields)); - let r = GEP_tup_like(bcx, rec_ty, val, [0, ix as int]); - rec_vals += [r.val]; - bcx = r.bcx; - } - compile_submatch(bcx, enter_rec(dm, m, col, rec_fields, val), - rec_vals + vals_left, f, exits); - ret; - } - - if any_tup_pat(m, col) { - let tup_ty = node_id_type(bcx, pat_id); - let n_tup_elts = alt ty::get(tup_ty).struct { - ty::ty_tup(elts) { elts.len() } - _ { ccx.sess.bug("Non-tuple type in tuple pattern"); } - }; - let tup_vals = [], i = 0u; - while i < n_tup_elts { - let r = GEP_tup_like(bcx, tup_ty, val, [0, i as int]); - tup_vals += [r.val]; - bcx = r.bcx; - i += 1u; - } - compile_submatch(bcx, enter_tup(dm, m, col, val, n_tup_elts), - tup_vals + vals_left, f, exits); - ret; - } - - // Unbox in case of a box field - if any_box_pat(m, col) { - let box = Load(bcx, val); - let unboxed = GEPi(bcx, box, [0, abi::box_field_body]); - compile_submatch(bcx, enter_box(dm, m, col, val), [unboxed] - + vals_left, f, exits); - ret; - } - - if any_uniq_pat(m, col) { - let unboxed = Load(bcx, val); - compile_submatch(bcx, enter_uniq(dm, m, col, val), - [unboxed] + vals_left, f, exits); - ret; - } - - // Decide what kind of branch we need - let opts = get_options(ccx, m, col); - enum branch_kind { no_branch, single, switch, compare, } - let kind = no_branch; - let test_val = val; - if opts.len() > 0u { - alt opts[0] { - var(_, vdef) { - if (*ty::enum_variants(tcx, vdef.enm)).len() == 1u { - kind = single; - } else { - let enumptr = - PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); - let discrimptr = GEPi(bcx, enumptr, [0, 0]); - test_val = Load(bcx, discrimptr); - kind = switch; - } - } - lit(l) { - test_val = Load(bcx, val); - let pty = node_id_type(bcx, pat_id); - kind = if ty::type_is_integral(pty) { switch } - else { compare }; - } - range(_, _) { - test_val = Load(bcx, val); - kind = compare; - } - } - } - for o: opt in opts { - alt o { - range(_, _) { kind = compare; break; } - _ { } - } - } - let else_cx = alt kind { - no_branch | single { bcx } - _ { sub_block(bcx, "match_else") } - }; - let sw = if kind == switch { - Switch(bcx, test_val, else_cx.llbb, opts.len()) - } else { C_int(ccx, 0) }; // Placeholder for when not using a switch - - // Compile subtrees for each option - for opt: opt in opts { - let opt_cx = sub_block(bcx, "match_case"); - alt kind { - single { Br(bcx, opt_cx.llbb); } - switch { - let res = trans_opt(bcx, opt); - alt check res { - single_result(r) { - llvm::LLVMAddCase(sw, r.val, opt_cx.llbb); - bcx = r.bcx; - } - } - } - compare { - let t = node_id_type(bcx, pat_id); - let {bcx: after_cx, val: matches} = - with_scope_result(bcx, "compare_scope") {|bcx| - alt trans_opt(bcx, opt) { - single_result({bcx, val}) { - trans_compare(bcx, ast::eq, test_val, t, val, t) - } - range_result({val: vbegin, _}, {bcx, val: vend}) { - let {bcx, val: ge} = trans_compare(bcx, ast::ge, test_val, - t, vbegin, t); - let {bcx, val: le} = trans_compare(bcx, ast::le, test_val, - t, vend, t); - {bcx: bcx, val: And(bcx, ge, le)} - } - } - }; - bcx = sub_block(after_cx, "compare_next"); - CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb); - } - _ { } - } - let size = 0u; - let unpacked = []; - alt opt { - var(_, vdef) { - let args = extract_variant_args(opt_cx, pat_id, vdef, val); - size = args.vals.len(); - unpacked = args.vals; - opt_cx = args.bcx; - } - lit(_) | range(_, _) { } - } - compile_submatch(opt_cx, enter_opt(tcx, m, opt, col, size, val), - unpacked + vals_left, f, exits); - } - - // Compile the fall-through case - if kind == compare { Br(bcx, else_cx.llbb); } - if kind != single { - compile_submatch(else_cx, enter_default(dm, m, col, val), vals_left, - f, exits); - } -} - -// Returns false for unreachable blocks -fn make_phi_bindings(bcx: block, map: [exit_node], - ids: pat_util::pat_id_map) -> bool { - let our_block = bcx.llbb as uint; - let success = true, bcx = bcx; - ids.items {|name, node_id| - let llbbs = []; - let vals = []; - for ex: exit_node in map { - if ex.to as uint == our_block { - alt assoc(name, ex.bound) { - some(val) { llbbs += [ex.from]; vals += [val]; } - none { } - } - } - } - if vals.len() > 0u { - let local = Phi(bcx, val_ty(vals[0]), vals, llbbs); - bcx.fcx.lllocals.insert(node_id, local_mem(local)); - } else { success = false; } - }; - if success { - // Copy references that the alias analysis considered unsafe - ids.values {|node_id| - if bcx.ccx().maps.copy_map.contains_key(node_id) { - let local = alt bcx.fcx.lllocals.find(node_id) { - some(local_mem(x)) { x } - _ { bcx.tcx().sess.bug("Someone \ - forgot to document an invariant in \ - make_phi_bindings"); } - }; - let e_ty = node_id_type(bcx, node_id); - let {bcx: abcx, val: alloc} = alloc_ty(bcx, e_ty); - bcx = copy_val(abcx, INIT, alloc, - load_if_immediate(abcx, local, e_ty), - e_ty); - add_clean(bcx, alloc, e_ty); - bcx.fcx.lllocals.insert(node_id, local_mem(alloc)); - } - }; - } else { - Unreachable(bcx); - } - ret success; -} - -fn trans_alt(bcx: block, expr: @ast::expr, arms: [ast::arm], - dest: dest) -> block { - with_scope(bcx, "alt") {|bcx| trans_alt_inner(bcx, expr, arms, dest)} -} - -fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: [ast::arm], - dest: dest) -> block { - let bcx = scope_cx, tcx = bcx.tcx(); - let bodies = [], match = []; - - let {bcx, val, _} = trans_temp_expr(bcx, expr); - if bcx.unreachable { ret bcx; } - - for a in arms { - let body = scope_block(bcx, "case_body"); - body.block_span = some(a.body.span); - let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]); - bodies += [body]; - for p in a.pats { - match += [@{pats: [p], - bound: [], - data: @{body: body.llbb, guard: a.guard, - id_map: id_map}}]; - } - } - - // Cached fail-on-fallthrough block - let fail_cx = @mutable none; - fn mk_fail(bcx: block, sp: span, - done: @mutable option<BasicBlockRef>) -> BasicBlockRef { - alt *done { some(bb) { ret bb; } _ { } } - let fail_cx = sub_block(bcx, "case_fallthrough"); - trans_fail(fail_cx, some(sp), "non-exhaustive match failure");; - *done = some(fail_cx.llbb); - ret fail_cx.llbb; - } - - let exit_map = []; - let t = node_id_type(bcx, expr.id); - let {bcx, val: spilled} = spill_if_immediate(bcx, val, t); - compile_submatch(bcx, match, [spilled], - bind mk_fail(scope_cx, expr.span, fail_cx), exit_map); - - let arm_cxs = [], arm_dests = [], i = 0u; - for a in arms { - let body_cx = bodies[i]; - let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]); - if make_phi_bindings(body_cx, exit_map, id_map) { - let arm_dest = dup_for_join(dest); - arm_dests += [arm_dest]; - let arm_cx = trans_block(body_cx, a.body, arm_dest); - arm_cx = trans_block_cleanups(arm_cx, body_cx); - arm_cxs += [arm_cx]; - } - i += 1u; - } - join_returns(scope_cx, arm_cxs, arm_dests, dest) -} - -// Not alt-related, but similar to the pattern-munging code above -fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, - make_copy: bool) -> block { - let ccx = bcx.fcx.ccx, bcx = bcx; - - // Necessary since bind_irrefutable_pat is called outside trans_alt - alt pat.node { - ast::pat_ident(_,inner) { - if pat_is_variant(bcx.tcx().def_map, pat) { ret bcx; } - if make_copy || ccx.maps.copy_map.contains_key(pat.id) { - let ty = node_id_type(bcx, pat.id); - let llty = type_of::type_of(ccx, ty); - let alloc = alloca(bcx, llty); - bcx = copy_val(bcx, INIT, alloc, - load_if_immediate(bcx, val, ty), ty); - bcx.fcx.lllocals.insert(pat.id, local_mem(alloc)); - add_clean(bcx, alloc, ty); - } else { bcx.fcx.lllocals.insert(pat.id, local_mem(val)); } - alt inner { - some(pat) { bcx = bind_irrefutable_pat(bcx, pat, val, true); } - _ {} - } - } - ast::pat_enum(_, sub) { - let vdefs = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat.id)); - let args = extract_variant_args(bcx, pat.id, vdefs, val); - let i = 0; - for argval: ValueRef in args.vals { - bcx = bind_irrefutable_pat(bcx, sub[i], argval, make_copy); - i += 1; - } - } - ast::pat_rec(fields, _) { - let rec_ty = node_id_type(bcx, pat.id); - let rec_fields = ty::get_fields(rec_ty); - for f: ast::field_pat in fields { - let ix = option::get(ty::field_idx(f.ident, rec_fields)); - // how to get rid of this check? - let r = GEP_tup_like(bcx, rec_ty, val, [0, ix as int]); - bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, make_copy); - } - } - ast::pat_tup(elems) { - let tup_ty = node_id_type(bcx, pat.id); - let i = 0u; - for elem in elems { - let r = GEP_tup_like(bcx, tup_ty, val, [0, i as int]); - bcx = bind_irrefutable_pat(r.bcx, elem, r.val, make_copy); - i += 1u; - } - } - ast::pat_box(inner) { - let box = Load(bcx, val); - let unboxed = - GEPi(bcx, box, [0, abi::box_field_body]); - bcx = bind_irrefutable_pat(bcx, inner, unboxed, true); - } - ast::pat_uniq(inner) { - let val = Load(bcx, val); - bcx = bind_irrefutable_pat(bcx, inner, val, true); - } - ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) { } - } - ret bcx; -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs deleted file mode 100644 index 6947a6875c4..00000000000 --- a/src/comp/middle/trans/base.rs +++ /dev/null @@ -1,4978 +0,0 @@ -// trans.rs: Translate the completed AST to the LLVM IR. -// -// Some functions here, such as trans_block and trans_expr, return a value -- -// the result of the translation to LLVM -- while others, such as trans_fn, -// trans_impl, and trans_item, are called only for the side effect of adding a -// 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, -// but many TypeRefs correspond to one ty::t; for instance, tup(int, int, -// int) and rec(x=int, y=int, z=int) will have the same TypeRef. - -import ctypes::c_uint; -import std::{map, time}; -import std::map::hashmap; -import std::map::{new_int_hash, new_str_hash}; -import driver::session; -import session::session; -import front::attr; -import middle::inline::inline_map; -import back::{link, abi, upcall}; -import syntax::{ast, ast_util, codemap}; -import ast_util::inlined_item_methods; -import ast_util::local_def; -import syntax::visit; -import syntax::codemap::span; -import syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str}; -import pat_util::*; -import visit::vt; -import util::common::*; -import lib::llvm::{llvm, mk_target_data, mk_type_names}; -import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef}; -import lib::llvm::{True, False}; -import link::{mangle_internal_name_by_type_only, - mangle_internal_name_by_seq, - mangle_internal_name_by_path, - mangle_internal_name_by_path_and_seq, - mangle_exported_name}; -import metadata::{csearch, cstore}; -import util::ppaux::{ty_to_str, ty_to_short_str}; - -import common::*; -import build::*; -import shape::*; -import type_of::*; -import type_of::type_of; // Issue #1873 -import ast_map::{path, path_mod, path_name}; - -// Destinations - -// These are passed around by the code generating functions to track the -// destination of a computation's value. - -enum dest { - by_val(@mutable ValueRef), - save_in(ValueRef), - ignore, -} - -fn dest_str(ccx: crate_ctxt, d: dest) -> str { - alt d { - by_val(v) { #fmt["by_val(%s)", val_str(ccx.tn, *v)] } - save_in(v) { #fmt["save_in(%s)", val_str(ccx.tn, v)] } - ignore { "ignore" } - } -} - -fn empty_dest_cell() -> @mutable ValueRef { - ret @mutable llvm::LLVMGetUndef(T_nil()); -} - -fn dup_for_join(dest: dest) -> dest { - alt dest { - by_val(_) { by_val(empty_dest_cell()) } - _ { dest } - } -} - -fn join_returns(parent_cx: block, in_cxs: [block], - in_ds: [dest], out_dest: dest) -> block { - let out = sub_block(parent_cx, "join"); - let reachable = false, i = 0u, phi = none; - for cx in in_cxs { - if !cx.unreachable { - Br(cx, out.llbb); - reachable = true; - alt in_ds[i] { - by_val(cell) { - if option::is_none(phi) { - phi = some(EmptyPhi(out, val_ty(*cell))); - } - AddIncomingToPhi(option::get(phi), *cell, cx.llbb); - } - _ {} - } - } - i += 1u; - } - if !reachable { - Unreachable(out); - } else { - alt out_dest { - by_val(cell) { *cell = option::get(phi); } - _ {} - } - } - ret out; -} - -// Used to put an immediate value in a dest. -fn store_in_dest(bcx: block, val: ValueRef, dest: dest) -> block { - alt dest { - ignore {} - by_val(cell) { *cell = val; } - save_in(addr) { Store(bcx, val, addr); } - } - ret bcx; -} - -fn get_dest_addr(dest: dest) -> ValueRef { - alt dest { - save_in(a) { a } - _ { fail "get_dest_addr: not a save_in"; } - } -} - -// Name sanitation. LLVM will happily accept identifiers with weird names, but -// gas doesn't! -fn sanitize(s: str) -> str { - let result = ""; - for c: u8 in s { - if c == '@' as u8 { - result += "boxed_"; - } else { - if c == ',' as u8 { - result += "_"; - } else { - if c == '{' as u8 || c == '(' as u8 { - result += "_of_"; - } else { - if c != 10u8 && c != '}' as u8 && c != ')' as u8 && - c != ' ' as u8 && c != '\t' as u8 && c != ';' as u8 - { - let v = [c]; - result += str::from_bytes(v); - } - } - } - } - } - ret result; -} - - -fn log_fn_time(ccx: crate_ctxt, name: str, start: time::timeval, - end: time::timeval) { - let elapsed = 1000 * ((end.sec - start.sec) as int) + - ((end.usec as int) - (start.usec as int)) / 1000; - *ccx.stats.fn_times += [{ident: name, time: elapsed}]; -} - - -fn decl_fn(llmod: ModuleRef, name: str, cc: lib::llvm::CallConv, - llty: TypeRef) -> ValueRef { - let llfn: ValueRef = str::as_buf(name, {|buf| - llvm::LLVMGetOrInsertFunction(llmod, buf, llty) - }); - lib::llvm::SetFunctionCallConv(llfn, cc); - ret llfn; -} - -fn decl_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) -> ValueRef { - ret decl_fn(llmod, name, lib::llvm::CCallConv, llty); -} - - -// Only use this if you are going to actually define the function. It's -// not valid to simply declare a function as internal. -fn decl_internal_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) -> - ValueRef { - let llfn = decl_cdecl_fn(llmod, name, llty); - lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage); - ret llfn; -} - -fn get_extern_fn(externs: hashmap<str, ValueRef>, llmod: ModuleRef, name: str, - cc: lib::llvm::CallConv, ty: TypeRef) -> ValueRef { - if externs.contains_key(name) { ret externs.get(name); } - let f = decl_fn(llmod, name, cc, ty); - externs.insert(name, f); - ret f; -} - -fn get_extern_const(externs: hashmap<str, ValueRef>, llmod: ModuleRef, - name: str, ty: TypeRef) -> ValueRef { - if externs.contains_key(name) { ret externs.get(name); } - let c = str::as_buf(name, {|buf| llvm::LLVMAddGlobal(llmod, ty, buf) }); - externs.insert(name, c); - ret c; -} - -fn get_simple_extern_fn(cx: block, - externs: hashmap<str, ValueRef>, - llmod: ModuleRef, - name: str, n_args: int) -> ValueRef { - let ccx = cx.fcx.ccx; - let inputs = vec::init_elt(n_args as uint, ccx.int_type); - let output = ccx.int_type; - let t = T_fn(inputs, output); - ret get_extern_fn(externs, llmod, name, lib::llvm::CCallConv, t); -} - -fn trans_native_call(cx: block, externs: hashmap<str, ValueRef>, - llmod: ModuleRef, name: str, args: [ValueRef]) -> - ValueRef { - let n = args.len() as int; - let llnative: ValueRef = - get_simple_extern_fn(cx, externs, llmod, name, n); - let call_args: [ValueRef] = []; - for a: ValueRef in args { - call_args += [ZExtOrBitCast(cx, a, cx.ccx().int_type)]; - } - ret Call(cx, llnative, call_args); -} - -fn trans_free(cx: block, v: ValueRef) -> block { - Call(cx, cx.ccx().upcalls.free, [PointerCast(cx, v, T_ptr(T_i8()))]); - cx -} - -fn trans_shared_free(cx: block, v: ValueRef) -> block { - Call(cx, cx.ccx().upcalls.shared_free, - [PointerCast(cx, v, T_ptr(T_i8()))]); - ret cx; -} - -fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { - let cond = ICmp(cx, lib::llvm::IntULT, a, b); - ret Select(cx, cond, b, a); -} - -fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { - let cond = ICmp(cx, lib::llvm::IntULT, a, b); - ret Select(cx, cond, a, b); -} - -fn alloca(cx: block, t: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(t); } - ret Alloca(raw_block(cx.fcx, cx.fcx.llstaticallocas), t); -} - -fn dynastack_alloca(cx: block, t: TypeRef, n: ValueRef, ty: ty::t) -> - ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(t)); } - let bcx = cx; - let dy_cx = raw_block(cx.fcx, cx.fcx.lldynamicallocas); - alt cx.fcx.llobstacktoken { - none { - cx.fcx.llobstacktoken = some(mk_obstack_token(cx.ccx(), cx.fcx)); - } - some(_) {/* no-op */ } - } - - let dynastack_alloc = bcx.ccx().upcalls.dynastack_alloc; - let llsz = Mul(dy_cx, - C_uint(bcx.ccx(), llsize_of_real(bcx.ccx(), t)), - n); - - let lltydesc = get_tydesc_simple(cx, ty, false).val; - - let llresult = Call(dy_cx, dynastack_alloc, [llsz, lltydesc]); - ret PointerCast(dy_cx, llresult, T_ptr(t)); -} - -fn mk_obstack_token(ccx: crate_ctxt, fcx: fn_ctxt) -> - ValueRef { - let cx = raw_block(fcx, fcx.lldynamicallocas); - ret Call(cx, ccx.upcalls.dynastack_mark, []); -} - -// Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes). -// The type of the returned pointer is always i8*. If you care about the -// return type, use bump_ptr(). -fn ptr_offs(bcx: block, base: ValueRef, sz: ValueRef) -> ValueRef { - let raw = PointerCast(bcx, base, T_ptr(T_i8())); - GEP(bcx, raw, [sz]) -} - -// Increment a pointer by a given amount and then cast it to be a pointer -// to a given type. -fn bump_ptr(bcx: block, t: ty::t, base: ValueRef, sz: ValueRef) -> - ValueRef { - let ccx = bcx.ccx(); - let bumped = ptr_offs(bcx, base, sz); - if check type_has_static_size(ccx, t) { - let typ = T_ptr(type_of(ccx, t)); - PointerCast(bcx, bumped, typ) - } else { bumped } -} - -// Replacement for the LLVM 'GEP' instruction when field-indexing into a -// tuple-like structure (tup, rec) with a static index. This one is driven off -// ty::struct and knows what to do when it runs into a ty_param stuck in the -// middle of the thing it's GEP'ing into. Much like size_of and align_of, -// above. -fn GEP_tup_like(bcx: block, t: ty::t, base: ValueRef, ixs: [int]) - -> result { - fn compute_off(bcx: block, - off: ValueRef, - t: ty::t, - ixs: [int], - n: uint) -> (block, ValueRef, ty::t) { - if n == ixs.len() { - ret (bcx, off, t); - } - - let ix = ixs[n]; - let bcx = bcx, off = off; - int::range(0, ix) {|i| - let comp_t = ty::get_element_type(t, i as uint); - let align = align_of(bcx, comp_t); - bcx = align.bcx; - off = align_to(bcx, off, align.val); - let sz = size_of(bcx, comp_t); - bcx = sz.bcx; - off = Add(bcx, off, sz.val); - } - - let comp_t = ty::get_element_type(t, ix as uint); - let align = align_of(bcx, comp_t); - bcx = align.bcx; - off = align_to(bcx, off, align.val); - - be compute_off(bcx, off, comp_t, ixs, n+1u); - } - - if !ty::type_has_dynamic_size(bcx.tcx(), t) { - ret rslt(bcx, GEPi(bcx, base, ixs)); - } - - #debug["GEP_tup_like(t=%s,base=%s,ixs=%?)", - ty_to_str(bcx.tcx(), t), - val_str(bcx.ccx().tn, base), - ixs]; - - // We require that ixs start with 0 and we expect the input to be a - // pointer to an instance of type t, so we can safely ignore ixs[0], - // basically. - assert ixs[0] == 0; - - let (bcx, off, tar_t) = { - compute_off(bcx, C_int(bcx.ccx(), 0), t, ixs, 1u) - }; - ret rslt(bcx, bump_ptr(bcx, tar_t, base, off)); -} - - -// Replacement for the LLVM 'GEP' instruction when field indexing into a enum. -// This function uses GEP_tup_like() above and automatically performs casts as -// appropriate. @llblobptr is the data part of a enum value; its actual type -// is meaningless, as it will be cast away. -fn GEP_enum(cx: block, llblobptr: ValueRef, enum_id: ast::def_id, - variant_id: ast::def_id, ty_substs: [ty::t], - ix: uint) -> result { - let variant = ty::enum_variant_with_id(cx.tcx(), enum_id, variant_id); - assert ix < variant.args.len(); - - // Synthesize a tuple type so that GEP_tup_like() can work its magic. - // Separately, store the type of the element we're interested in. - - let arg_tys = variant.args; - - let true_arg_tys: [ty::t] = []; - for aty: ty::t in arg_tys { - // Would be nice to have a way of stating the invariant - // that ty_substs is valid for aty - let arg_ty = ty::substitute_type_params(cx.tcx(), ty_substs, aty); - true_arg_tys += [arg_ty]; - } - - // We know that ix < len(variant.args) -- so - // it's safe to do this. (Would be nice to have - // typestate guarantee that a dynamic bounds check - // error can't happen here, but that's in the future.) - let elem_ty = true_arg_tys[ix]; - - let tup_ty = ty::mk_tup(cx.tcx(), true_arg_tys); - // Cast the blob pointer to the appropriate type, if we need to (i.e. if - // the blob pointer isn't dynamically sized). - - let llunionptr: ValueRef; - let ccx = cx.ccx(); - if check type_has_static_size(ccx, tup_ty) { - let llty = type_of(ccx, tup_ty); - llunionptr = TruncOrBitCast(cx, llblobptr, T_ptr(llty)); - } else { llunionptr = llblobptr; } - - // Do the GEP_tup_like(). - let rs = GEP_tup_like(cx, tup_ty, llunionptr, [0, ix as int]); - // Cast the result to the appropriate type, if necessary. - - let val = if check type_has_static_size(ccx, elem_ty) { - let llelemty = type_of(ccx, elem_ty); - PointerCast(rs.bcx, rs.val, T_ptr(llelemty)) - } else { rs.val }; - - ret rslt(rs.bcx, val); -} - -// trans_shared_malloc: expects a type indicating which pointer type we want -// and a size indicating how much space we want malloc'd. -fn trans_shared_malloc(cx: block, llptr_ty: TypeRef, llsize: ValueRef) - -> result { - let rval = Call(cx, cx.ccx().upcalls.shared_malloc, [llsize]); - ret rslt(cx, PointerCast(cx, rval, llptr_ty)); -} - -// Returns a pointer to the body for the box. The box may be an opaque -// box. The result will be casted to the type of body_t, if it is statically -// known. -// -// The runtime equivalent is box_body() in "rust_internal.h". -fn opaque_box_body(bcx: block, - body_t: ty::t, - boxptr: ValueRef) -> ValueRef { - let ccx = bcx.ccx(); - let boxptr = PointerCast(bcx, boxptr, T_ptr(T_box_header(ccx))); - let bodyptr = GEPi(bcx, boxptr, [1]); - if check type_has_static_size(ccx, body_t) { - PointerCast(bcx, bodyptr, T_ptr(type_of(ccx, body_t))) - } else { - PointerCast(bcx, bodyptr, T_ptr(T_i8())) - } -} - -// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to -// enough space for a box of that type. This includes a rust_opaque_box -// header. -fn trans_malloc_boxed_raw(bcx: block, t: ty::t, - &static_ti: option<@tydesc_info>) -> result { - let bcx = bcx, ccx = bcx.ccx(); - - // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc - // wants. - let box_ptr = ty::mk_imm_box(bcx.tcx(), t); - let llty = type_of(ccx, box_ptr); - - // Get the tydesc for the body: - let {bcx, val: lltydesc} = get_tydesc(bcx, t, true, static_ti); - lazily_emit_all_tydesc_glue(ccx, static_ti); - - // Allocate space: - let rval = Call(bcx, ccx.upcalls.malloc, [lltydesc]); - ret rslt(bcx, PointerCast(bcx, rval, llty)); -} - -// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box, -// initializes the reference count to 1, and pulls out the body and rc -fn trans_malloc_boxed(bcx: block, t: ty::t) -> - {bcx: block, box: ValueRef, body: ValueRef} { - let ti = none; - let {bcx, val:box} = trans_malloc_boxed_raw(bcx, t, ti); - let body = GEPi(bcx, box, [0, abi::box_field_body]); - ret {bcx: bcx, box: box, body: body}; -} - -// Type descriptor and type glue stuff - -// Given a type and a field index into its corresponding type descriptor, -// returns an LLVM ValueRef of that field from the tydesc, generating the -// tydesc if necessary. -fn field_of_tydesc(cx: block, t: ty::t, escapes: bool, field: int) -> - result { - let tydesc = get_tydesc_simple(cx, t, escapes); - ret rslt(tydesc.bcx, - GEPi(tydesc.bcx, tydesc.val, [0, field])); -} - -// Given a type containing ty params, build a vector containing a ValueRef for -// each of the ty params it uses (from the current frame) and a vector of the -// indices of the ty params present in the type. This is used solely for -// constructing derived tydescs. -fn linearize_ty_params(cx: block, t: ty::t) -> - {params: [uint], descs: [ValueRef]} { - let param_vals = [], param_defs = []; - ty::walk_ty(cx.tcx(), t) {|t| - alt ty::get(t).struct { - ty::ty_param(pid, _) { - if !vec::any(param_defs, {|d| d == pid}) { - param_vals += [cx.fcx.lltyparams[pid].desc]; - param_defs += [pid]; - } - } - _ { } - } - } - ret {params: param_defs, descs: param_vals}; -} - -fn trans_stack_local_derived_tydesc(cx: block, llsz: ValueRef, - llalign: ValueRef, llroottydesc: ValueRef, - llfirstparam: ValueRef, n_params: uint) - -> ValueRef { - let llmyroottydesc = alloca(cx, cx.ccx().tydesc_type); - - // By convention, desc 0 is the root descriptor. - let llroottydesc = Load(cx, llroottydesc); - Store(cx, llroottydesc, llmyroottydesc); - - // Store a pointer to the rest of the descriptors. - let ccx = cx.ccx(); - store_inbounds(cx, llfirstparam, llmyroottydesc, - [0, abi::tydesc_field_first_param]); - store_inbounds(cx, C_uint(ccx, n_params), llmyroottydesc, - [0, abi::tydesc_field_n_params]); - store_inbounds(cx, llsz, llmyroottydesc, - [0, abi::tydesc_field_size]); - store_inbounds(cx, llalign, llmyroottydesc, - [0, abi::tydesc_field_align]); - // FIXME legacy field, can be dropped - store_inbounds(cx, C_uint(ccx, 0u), llmyroottydesc, - [0, abi::tydesc_field_obj_params]); - ret llmyroottydesc; -} - -fn get_derived_tydesc(cx: block, t: ty::t, escapes: bool, - &static_ti: option<@tydesc_info>) -> result { - alt cx.fcx.derived_tydescs.find(t) { - some(info) { - // If the tydesc escapes in this context, the cached derived - // tydesc also has to be one that was marked as escaping. - if !(escapes && !info.escapes) { - ret rslt(cx, info.lltydesc); - } - } - none {/* fall through */ } - } - - cx.ccx().stats.n_derived_tydescs += 1u; - let bcx = raw_block(cx.fcx, cx.fcx.llderivedtydescs); - let tys = linearize_ty_params(bcx, t); - let root_ti = get_static_tydesc(bcx.ccx(), t, tys.params); - static_ti = some(root_ti); - lazily_emit_all_tydesc_glue(cx.ccx(), static_ti); - let root = root_ti.tydesc; - let sz = size_of(bcx, t); - bcx = sz.bcx; - let align = align_of(bcx, t); - bcx = align.bcx; - - // Store the captured type descriptors in an alloca if the caller isn't - // promising to do so itself. - let n_params = ty::count_ty_params(bcx.tcx(), t); - - assert n_params == tys.params.len(); - assert n_params == tys.descs.len(); - - let llparamtydescs = - alloca(bcx, T_array(T_ptr(bcx.ccx().tydesc_type), n_params + 1u)); - let i = 0; - - // If the type descriptor escapes, we need to add in the root as - // the first parameter, because upcall_get_type_desc() expects it. - if escapes { - Store(bcx, root, GEPi(bcx, llparamtydescs, [0, 0])); - i += 1; - } - - for td: ValueRef in tys.descs { - Store(bcx, td, GEPi(bcx, llparamtydescs, [0, i])); - i += 1; - } - - let llfirstparam = - PointerCast(bcx, llparamtydescs, - T_ptr(T_ptr(bcx.ccx().tydesc_type))); - - let v; - if escapes { - let ccx = bcx.ccx(); - let td_val = - Call(bcx, ccx.upcalls.get_type_desc, - [C_null(T_ptr(T_nil())), sz.val, - align.val, C_uint(ccx, 1u + n_params), llfirstparam, - C_uint(ccx, 0u)]); - v = td_val; - } else { - v = trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root, - llfirstparam, n_params); - } - bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes}); - ret rslt(cx, v); -} - -fn get_tydesc_simple(bcx: block, t: ty::t, escapes: bool) -> result { - let ti = none; - get_tydesc(bcx, t, escapes, ti) -} - -fn get_tydesc(cx: block, t: ty::t, escapes: bool, - &static_ti: option<@tydesc_info>) -> result { - - // Is the supplied type a type param? If so, return the passed-in tydesc. - alt ty::type_param(t) { - some(id) { ret rslt(cx, cx.fcx.lltyparams[id].desc); } - none {/* fall through */ } - } - - // Does it contain a type param? If so, generate a derived tydesc. - if ty::type_has_params(t) { - ret get_derived_tydesc(cx, t, escapes, static_ti); - } - // Otherwise, generate a tydesc if necessary, and return it. - let info = get_static_tydesc(cx.ccx(), t, []); - static_ti = some(info); - ret rslt(cx, info.tydesc); -} - -fn get_static_tydesc(ccx: crate_ctxt, t: ty::t, ty_params: [uint]) - -> @tydesc_info { - alt ccx.tydescs.find(t) { - some(info) { ret info; } - none { - ccx.stats.n_static_tydescs += 1u; - let info = declare_tydesc(ccx, t, ty_params); - ccx.tydescs.insert(t, info); - ret info; - } - } -} - -fn set_no_inline(f: ValueRef) { - llvm::LLVMAddFunctionAttr(f, lib::llvm::NoInlineAttribute as c_uint, - 0u as c_uint); -} - -// Tell LLVM to emit the information necessary to unwind the stack for the -// function f. -fn set_uwtable(f: ValueRef) { - llvm::LLVMAddFunctionAttr(f, lib::llvm::UWTableAttribute as c_uint, - 0u as c_uint); -} - -fn set_always_inline(f: ValueRef) { - llvm::LLVMAddFunctionAttr(f, lib::llvm::AlwaysInlineAttribute as c_uint, - 0u as c_uint); -} - -fn set_custom_stack_growth_fn(f: ValueRef) { - // FIXME: Remove this hack to work around the lack of u64 in the FFI. - llvm::LLVMAddFunctionAttr(f, 0u as c_uint, 1u as c_uint); -} - -fn set_glue_inlining(f: ValueRef, t: ty::t) { - if ty::type_is_structural(t) { - set_no_inline(f); - } else { set_always_inline(f); } -} - - -// Generates the declaration for (but doesn't emit) a type descriptor. -fn declare_tydesc(ccx: crate_ctxt, t: ty::t, ty_params: [uint]) - -> @tydesc_info { - log(debug, "+++ declare_tydesc " + ty_to_str(ccx.tcx, t)); - let llsize; - let llalign; - if check type_has_static_size(ccx, t) { - let llty = type_of(ccx, t); - llsize = llsize_of(ccx, llty); - llalign = llalign_of(ccx, llty); - } else { - // These will be overwritten as the derived tydesc is generated, so - // we create placeholder values. - - llsize = C_int(ccx, 0); - llalign = C_int(ccx, 0); - } - let name; - if ccx.sess.opts.debuginfo { - name = mangle_internal_name_by_type_only(ccx, t, "tydesc"); - name = sanitize(name); - } else { name = mangle_internal_name_by_seq(ccx, "tydesc"); } - let gvar = str::as_buf(name, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf) - }); - let info = - @{ty: t, - tydesc: gvar, - size: llsize, - align: llalign, - mutable take_glue: none, - mutable drop_glue: none, - mutable free_glue: none, - ty_params: ty_params}; - log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t)); - ret info; -} - -type glue_helper = fn@(block, ValueRef, ty::t); - -fn declare_generic_glue(ccx: crate_ctxt, t: ty::t, llfnty: TypeRef, - name: str) -> ValueRef { - let name = name; - let fn_nm; - if ccx.sess.opts.debuginfo { - fn_nm = mangle_internal_name_by_type_only(ccx, t, "glue_" + name); - fn_nm = sanitize(fn_nm); - } else { fn_nm = mangle_internal_name_by_seq(ccx, "glue_" + name); } - let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty); - set_glue_inlining(llfn, t); - ret llfn; -} - -fn make_generic_glue_inner(ccx: crate_ctxt, t: ty::t, - llfn: ValueRef, helper: glue_helper, - ty_params: [uint]) -> ValueRef { - let fcx = new_fn_ctxt(ccx, [], llfn, none); - lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage); - ccx.stats.n_glues_created += 1u; - // Any nontrivial glue is with values passed *by alias*; this is a - // requirement since in many contexts glue is invoked indirectly and - // the caller has no idea if it's dealing with something that can be - // passed by value. - - let llty = if check type_has_static_size(ccx, t) { - T_ptr(type_of(ccx, t)) - } else { T_ptr(T_i8()) }; - - let ty_param_count = ty_params.len(); - let lltyparams = llvm::LLVMGetParam(llfn, 2u as c_uint); - let load_env_bcx = raw_block(fcx, fcx.llloadenv); - let lltydescs = [mutable]; - let p = 0u; - while p < ty_param_count { - let llparam = GEPi(load_env_bcx, lltyparams, [p as int]); - llparam = Load(load_env_bcx, llparam); - vec::grow_set(lltydescs, ty_params[p], 0 as ValueRef, llparam); - p += 1u; - } - - fcx.lltyparams = vec::map(vec::from_mut(lltydescs), {|d| - {desc: d, dicts: none} - }); - - let bcx = top_scope_block(fcx, none); - let lltop = bcx.llbb; - let llrawptr0 = llvm::LLVMGetParam(llfn, 3u as c_uint); - let llval0 = BitCast(bcx, llrawptr0, llty); - helper(bcx, llval0, t); - finish_fn(fcx, lltop); - ret llfn; -} - -fn make_generic_glue(ccx: crate_ctxt, t: ty::t, llfn: ValueRef, - helper: glue_helper, ty_params: [uint], name: str) - -> ValueRef { - if !ccx.sess.opts.stats { - ret make_generic_glue_inner(ccx, t, llfn, helper, ty_params); - } - - let start = time::get_time(); - let llval = make_generic_glue_inner(ccx, t, llfn, helper, ty_params); - let end = time::get_time(); - log_fn_time(ccx, "glue " + name + " " + ty_to_short_str(ccx.tcx, t), - start, end); - ret llval; -} - -fn emit_tydescs(ccx: crate_ctxt) { - ccx.tydescs.items {|key, val| - let glue_fn_ty = T_ptr(T_glue_fn(ccx)); - let ti = val; - let take_glue = - alt ti.take_glue { - none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) } - some(v) { ccx.stats.n_real_glues += 1u; v } - }; - let drop_glue = - alt ti.drop_glue { - none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) } - some(v) { ccx.stats.n_real_glues += 1u; v } - }; - let free_glue = - alt ti.free_glue { - none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) } - some(v) { ccx.stats.n_real_glues += 1u; v } - }; - - let shape = shape_of(ccx, key, ti.ty_params); - let shape_tables = - llvm::LLVMConstPointerCast(ccx.shape_cx.llshapetables, - T_ptr(T_i8())); - - let tydesc = - C_named_struct(ccx.tydesc_type, - [C_null(T_ptr(T_ptr(ccx.tydesc_type))), - ti.size, // size - ti.align, // align - take_glue, // take_glue - drop_glue, // drop_glue - free_glue, // free_glue - C_null(T_ptr(T_i8())), // unused - C_null(glue_fn_ty), // sever_glue - C_null(glue_fn_ty), // mark_glue - C_null(glue_fn_ty), // unused - C_null(T_ptr(T_i8())), // cmp_glue - C_shape(ccx, shape), // shape - shape_tables, // shape_tables - C_int(ccx, 0), // n_params - C_int(ccx, 0)]); // n_obj_params - - let gvar = ti.tydesc; - llvm::LLVMSetInitializer(gvar, tydesc); - llvm::LLVMSetGlobalConstant(gvar, True); - lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage); - }; -} - -fn make_take_glue(cx: block, v: ValueRef, t: ty::t) { - let bcx = cx; - // NB: v is a *pointer* to type t here, not a direct value. - bcx = alt ty::get(t).struct { - ty::ty_box(_) | ty::ty_opaque_box { - incr_refcnt_of_boxed(bcx, Load(bcx, v)) - } - ty::ty_uniq(_) { - let r = uniq::duplicate(bcx, Load(bcx, v), t); - Store(r.bcx, r.val, v); - r.bcx - } - ty::ty_vec(_) | ty::ty_str { - let r = tvec::duplicate(bcx, Load(bcx, v), t); - Store(r.bcx, r.val, v); - r.bcx - } - ty::ty_send_type { - // sendable type descriptors are basically unique pointers, - // they must be cloned when copied: - let r = Load(bcx, v); - let s = Call(bcx, bcx.ccx().upcalls.create_shared_type_desc, [r]); - Store(bcx, s, v); - bcx - } - ty::ty_fn(_) { - closure::make_fn_glue(bcx, v, t, take_ty) - } - ty::ty_iface(_, _) { - let box = Load(bcx, GEPi(bcx, v, [0, 1])); - incr_refcnt_of_boxed(bcx, box) - } - ty::ty_opaque_closure_ptr(ck) { - closure::make_opaque_cbox_take_glue(bcx, ck, v) - } - _ if ty::type_is_structural(t) { - iter_structural_ty(bcx, v, t, take_ty) - } - _ { bcx } - }; - - build_return(bcx); -} - -fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) -> block { - let ccx = cx.ccx(); - maybe_validate_box(cx, box_ptr); - let rc_ptr = GEPi(cx, box_ptr, [0, abi::box_field_refcnt]); - let rc = Load(cx, rc_ptr); - rc = Add(cx, rc, C_int(ccx, 1)); - Store(cx, rc, rc_ptr); - ret cx; -} - -fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { - // v is a pointer to the actual box component of the type here. The - // ValueRef will have the wrong type here (make_generic_glue is casting - // everything to a pointer to the type that the glue acts on). - let ccx = bcx.ccx(); - let bcx = alt ty::get(t).struct { - ty::ty_box(body_mt) { - let v = PointerCast(bcx, v, type_of(ccx, t)); - let body = GEPi(bcx, v, [0, abi::box_field_body]); - let bcx = drop_ty(bcx, body, body_mt.ty); - trans_free(bcx, v) - } - ty::ty_opaque_box { - let v = PointerCast(bcx, v, type_of(ccx, t)); - let td = Load(bcx, GEPi(bcx, v, [0, abi::box_field_tydesc])); - let valptr = GEPi(bcx, v, [0, abi::box_field_body]); - call_tydesc_glue_full(bcx, valptr, td, abi::tydesc_field_drop_glue, - none); - trans_free(bcx, v) - } - ty::ty_uniq(content_mt) { - let v = PointerCast(bcx, v, type_of(ccx, t)); - uniq::make_free_glue(bcx, v, t) - } - ty::ty_vec(_) | ty::ty_str { - tvec::make_free_glue(bcx, PointerCast(bcx, v, type_of(ccx, t)), t) - } - ty::ty_send_type { - // sendable type descriptors are basically unique pointers, - // they must be freed. - let ccx = bcx.ccx(); - let v = PointerCast(bcx, v, T_ptr(ccx.tydesc_type)); - Call(bcx, ccx.upcalls.free_shared_type_desc, [v]); - bcx - } - ty::ty_fn(_) { - closure::make_fn_glue(bcx, v, t, free_ty) - } - ty::ty_opaque_closure_ptr(ck) { - closure::make_opaque_cbox_free_glue(bcx, ck, v) - } - _ { bcx } - }; - build_return(bcx); -} - -fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { - // NB: v0 is an *alias* of type t here, not a direct value. - let ccx = bcx.ccx(); - let bcx = alt ty::get(t).struct { - ty::ty_box(_) | ty::ty_opaque_box { - decr_refcnt_maybe_free(bcx, Load(bcx, v0), t) - } - ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str | ty::ty_send_type { - free_ty(bcx, Load(bcx, v0), t) - } - ty::ty_res(did, inner, tps) { - trans_res_drop(bcx, v0, did, inner, tps) - } - ty::ty_fn(_) { - closure::make_fn_glue(bcx, v0, t, drop_ty) - } - ty::ty_iface(_, _) { - let box = Load(bcx, GEPi(bcx, v0, [0, 1])); - decr_refcnt_maybe_free(bcx, box, ty::mk_opaque_box(ccx.tcx)) - } - ty::ty_opaque_closure_ptr(ck) { - closure::make_opaque_cbox_drop_glue(bcx, ck, v0) - } - _ { - if ty::type_needs_drop(ccx.tcx, t) && - ty::type_is_structural(t) { - iter_structural_ty(bcx, v0, t, drop_ty) - } else { bcx } - } - }; - build_return(bcx); -} - -fn trans_res_drop(bcx: block, rs: ValueRef, did: ast::def_id, - inner_t: ty::t, tps: [ty::t]) -> block { - let ccx = bcx.ccx(); - let inner_t_s = ty::substitute_type_params(ccx.tcx, tps, inner_t); - let tup_ty = ty::mk_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t_s]); - - let {bcx, val: drop_flag} = GEP_tup_like(bcx, tup_ty, rs, [0, 0]); - with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|bcx| - let {bcx, val: valptr} = GEP_tup_like(bcx, tup_ty, rs, [0, 1]); - // Find and call the actual destructor. - let dtor_addr = common::get_res_dtor(ccx, did, inner_t); - let args = [bcx.fcx.llretptr, null_env_ptr(bcx)]; - for tp in tps { - let td = get_tydesc_simple(bcx, tp, false); - args += [td.val]; - bcx = td.bcx; - } - // Kludge to work around the fact that we know the precise type of the - // value here, but the dtor expects a type that still has opaque - // pointers for type variables. - let val_llty = lib::llvm::fn_ty_param_tys - (llvm::LLVMGetElementType - (llvm::LLVMTypeOf(dtor_addr)))[args.len()]; - let val_cast = BitCast(bcx, valptr, val_llty); - Call(bcx, dtor_addr, args + [val_cast]); - - bcx = drop_ty(bcx, valptr, inner_t_s); - Store(bcx, C_u8(0u), drop_flag); - bcx - } -} - -fn maybe_validate_box(_cx: block, _box_ptr: ValueRef) { - // Uncomment this when debugging annoying use-after-free - // bugs. But do not commit with this uncommented! Big performance hit. - - // let cx = _cx, box_ptr = _box_ptr; - // let ccx = cx.ccx(); - // warn_not_to_commit(ccx, "validate_box() is uncommented"); - // let raw_box_ptr = PointerCast(cx, box_ptr, T_ptr(T_i8())); - // Call(cx, ccx.upcalls.validate_box, [raw_box_ptr]); -} - -fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t) -> block { - let ccx = bcx.ccx(); - maybe_validate_box(bcx, box_ptr); - - let llbox_ty = T_opaque_box_ptr(ccx); - let box_ptr = PointerCast(bcx, box_ptr, llbox_ty); - with_cond(bcx, IsNotNull(bcx, box_ptr)) {|bcx| - let rc_ptr = GEPi(bcx, box_ptr, [0, abi::box_field_refcnt]); - let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1)); - Store(bcx, rc, rc_ptr); - let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc); - with_cond(bcx, zero_test) {|bcx| free_ty(bcx, box_ptr, t)} - } -} - -// Structural comparison: a rather involved form of glue. -fn maybe_name_value(cx: crate_ctxt, v: ValueRef, s: str) { - if cx.sess.opts.save_temps { - let _: () = str::as_buf(s, {|buf| llvm::LLVMSetValueName(v, buf) }); - } -} - - -// Used only for creating scalar comparison glue. -enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, } - - -fn compare_scalar_types(cx: block, lhs: ValueRef, rhs: ValueRef, - t: ty::t, op: ast::binop) -> result { - let f = bind compare_scalar_values(cx, lhs, rhs, _, op); - - alt ty::get(t).struct { - ty::ty_nil { ret rslt(cx, f(nil_type)); } - ty::ty_bool | ty::ty_ptr(_) { ret rslt(cx, f(unsigned_int)); } - ty::ty_int(_) { ret rslt(cx, f(signed_int)); } - ty::ty_uint(_) { ret rslt(cx, f(unsigned_int)); } - ty::ty_float(_) { ret rslt(cx, f(floating_point)); } - ty::ty_type { - ret rslt(trans_fail(cx, none, - "attempt to compare values of type type"), - C_nil()); - } - _ { - // Should never get here, because t is scalar. - cx.sess().bug("non-scalar type passed to \ - compare_scalar_types"); - } - } -} - - -// A helper function to do the actual comparison of scalar values. -fn compare_scalar_values(cx: block, lhs: ValueRef, rhs: ValueRef, - nt: scalar_type, op: ast::binop) -> ValueRef { - fn die_(cx: block) -> ! { - cx.tcx().sess.bug("compare_scalar_values: must be a\ - comparison operator"); - } - let die = bind die_(cx); - alt nt { - nil_type { - // We don't need to do actual comparisons for nil. - // () == () holds but () < () does not. - alt op { - ast::eq | ast::le | ast::ge { ret C_bool(true); } - ast::ne | ast::lt | ast::gt { ret C_bool(false); } - // refinements would be nice - _ { die(); } - } - } - floating_point { - let cmp = alt op { - ast::eq { lib::llvm::RealOEQ } - ast::ne { lib::llvm::RealUNE } - ast::lt { lib::llvm::RealOLT } - ast::le { lib::llvm::RealOLE } - ast::gt { lib::llvm::RealOGT } - ast::ge { lib::llvm::RealOGE } - _ { die(); } - }; - ret FCmp(cx, cmp, lhs, rhs); - } - signed_int { - let cmp = alt op { - ast::eq { lib::llvm::IntEQ } - ast::ne { lib::llvm::IntNE } - ast::lt { lib::llvm::IntSLT } - ast::le { lib::llvm::IntSLE } - ast::gt { lib::llvm::IntSGT } - ast::ge { lib::llvm::IntSGE } - _ { die(); } - }; - ret ICmp(cx, cmp, lhs, rhs); - } - unsigned_int { - let cmp = alt op { - ast::eq { lib::llvm::IntEQ } - ast::ne { lib::llvm::IntNE } - ast::lt { lib::llvm::IntULT } - ast::le { lib::llvm::IntULE } - ast::gt { lib::llvm::IntUGT } - ast::ge { lib::llvm::IntUGE } - _ { die(); } - }; - ret ICmp(cx, cmp, lhs, rhs); - } - } -} - -type val_pair_fn = fn@(block, ValueRef, ValueRef) -> block; -type val_and_ty_fn = fn@(block, ValueRef, ty::t) -> block; - -fn load_inbounds(cx: block, p: ValueRef, idxs: [int]) -> ValueRef { - ret Load(cx, GEPi(cx, p, idxs)); -} - -fn store_inbounds(cx: block, v: ValueRef, p: ValueRef, - idxs: [int]) { - Store(cx, v, GEPi(cx, p, idxs)); -} - -// Iterates through the elements of a structural type. -fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, - f: val_and_ty_fn) -> block { - fn iter_variant(cx: block, a_tup: ValueRef, - variant: ty::variant_info, tps: [ty::t], tid: ast::def_id, - f: val_and_ty_fn) -> block { - if variant.args.len() == 0u { ret cx; } - let fn_ty = variant.ctor_ty; - let ccx = cx.ccx(); - let cx = cx; - alt ty::get(fn_ty).struct { - ty::ty_fn({inputs: args, _}) { - let j = 0u; - let v_id = variant.id; - for a: ty::arg in args { - let rslt = GEP_enum(cx, a_tup, tid, v_id, tps, j); - let llfldp_a = rslt.val; - cx = rslt.bcx; - let ty_subst = ty::substitute_type_params(ccx.tcx, tps, a.ty); - cx = f(cx, llfldp_a, ty_subst); - j += 1u; - } - } - _ { cx.tcx().sess.bug("iter_variant: not a function type"); } - } - ret cx; - } - - /* - Typestate constraint that shows the unimpl case doesn't happen? - */ - let cx = cx; - alt ty::get(t).struct { - ty::ty_rec(fields) { - let i: int = 0; - for fld: ty::field in fields { - let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]); - cx = f(bcx, llfld_a, fld.mt.ty); - i += 1; - } - } - ty::ty_tup(args) { - let i = 0; - for arg in args { - let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, t, av, [0, i]); - cx = f(bcx, llfld_a, arg); - i += 1; - } - } - ty::ty_res(_, inner, tps) { - let tcx = cx.tcx(); - let inner1 = ty::substitute_type_params(tcx, tps, inner); - let inner_t_s = ty::substitute_type_params(tcx, tps, inner); - let tup_t = ty::mk_tup(tcx, [ty::mk_int(tcx), inner_t_s]); - let {bcx: bcx, val: llfld_a} = GEP_tup_like(cx, tup_t, av, [0, 1]); - ret f(bcx, llfld_a, inner1); - } - ty::ty_enum(tid, tps) { - let variants = ty::enum_variants(cx.tcx(), tid); - let n_variants = (*variants).len(); - - // Cast the enums to types we can GEP into. - if n_variants == 1u { - ret iter_variant(cx, av, variants[0], tps, tid, f); - } - - let ccx = cx.ccx(); - let llenumty = T_opaque_enum_ptr(ccx); - let av_enum = PointerCast(cx, av, llenumty); - let lldiscrim_a_ptr = GEPi(cx, av_enum, [0, 0]); - let llunion_a_ptr = GEPi(cx, av_enum, [0, 1]); - let lldiscrim_a = Load(cx, lldiscrim_a_ptr); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - cx = f(cx, lldiscrim_a_ptr, ty::mk_int(cx.tcx())); - let unr_cx = sub_block(cx, "enum-iter-unr"); - Unreachable(unr_cx); - let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants); - let next_cx = sub_block(cx, "enum-iter-next"); - for variant: ty::variant_info in *variants { - let variant_cx = - sub_block(cx, - "enum-iter-variant-" + - int::to_str(variant.disr_val, 10u)); - AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb); - variant_cx = - iter_variant(variant_cx, llunion_a_ptr, variant, tps, tid, f); - Br(variant_cx, next_cx.llbb); - } - ret next_cx; - } - _ { cx.sess().unimpl("type in iter_structural_ty"); } - } - ret cx; -} - -fn lazily_emit_all_tydesc_glue(ccx: crate_ctxt, - static_ti: option<@tydesc_info>) { - lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, static_ti); - lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti); - lazily_emit_tydesc_glue(ccx, abi::tydesc_field_free_glue, static_ti); -} - -fn lazily_emit_all_generic_info_tydesc_glues(ccx: crate_ctxt, - gi: generic_info) { - for ti: option<@tydesc_info> in gi.static_tis { - lazily_emit_all_tydesc_glue(ccx, ti); - } -} - -fn lazily_emit_tydesc_glue(ccx: crate_ctxt, field: int, - static_ti: option<@tydesc_info>) { - alt static_ti { - none { } - some(ti) { - if field == abi::tydesc_field_take_glue { - alt ti.take_glue { - some(_) { } - none { - #debug("+++ lazily_emit_tydesc_glue TAKE %s", - ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = declare_generic_glue - (ccx, ti.ty, T_glue_fn(ccx), "take"); - ti.take_glue = some(glue_fn); - make_generic_glue(ccx, ti.ty, glue_fn, - make_take_glue, - ti.ty_params, "take"); - #debug("--- lazily_emit_tydesc_glue TAKE %s", - ty_to_str(ccx.tcx, ti.ty)); - } - } - } else if field == abi::tydesc_field_drop_glue { - alt ti.drop_glue { - some(_) { } - none { - #debug("+++ lazily_emit_tydesc_glue DROP %s", - ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = - declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "drop"); - ti.drop_glue = some(glue_fn); - make_generic_glue(ccx, ti.ty, glue_fn, - make_drop_glue, - ti.ty_params, "drop"); - #debug("--- lazily_emit_tydesc_glue DROP %s", - ty_to_str(ccx.tcx, ti.ty)); - } - } - } else if field == abi::tydesc_field_free_glue { - alt ti.free_glue { - some(_) { } - none { - #debug("+++ lazily_emit_tydesc_glue FREE %s", - ty_to_str(ccx.tcx, ti.ty)); - let glue_fn = - declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "free"); - ti.free_glue = some(glue_fn); - make_generic_glue(ccx, ti.ty, glue_fn, - make_free_glue, - ti.ty_params, "free"); - #debug("--- lazily_emit_tydesc_glue FREE %s", - ty_to_str(ccx.tcx, ti.ty)); - } - } - } - } - } -} - -fn call_tydesc_glue_full(cx: block, v: ValueRef, tydesc: ValueRef, - field: int, static_ti: option<@tydesc_info>) { - lazily_emit_tydesc_glue(cx.ccx(), field, static_ti); - if cx.unreachable { ret; } - - let static_glue_fn = none; - alt static_ti { - none {/* no-op */ } - some(sti) { - if field == abi::tydesc_field_take_glue { - static_glue_fn = sti.take_glue; - } else if field == abi::tydesc_field_drop_glue { - static_glue_fn = sti.drop_glue; - } else if field == abi::tydesc_field_free_glue { - static_glue_fn = sti.free_glue; - } - } - } - - let llrawptr = PointerCast(cx, v, T_ptr(T_i8())); - let lltydescs = - GEPi(cx, tydesc, [0, abi::tydesc_field_first_param]); - lltydescs = Load(cx, lltydescs); - - let llfn; - alt static_glue_fn { - none { - let llfnptr = GEPi(cx, tydesc, [0, field]); - llfn = Load(cx, llfnptr); - } - some(sgf) { llfn = sgf; } - } - - Call(cx, llfn, [C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())), - lltydescs, llrawptr]); -} - -fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: int) -> - block { - let ti: option<@tydesc_info> = none::<@tydesc_info>; - let {bcx: bcx, val: td} = get_tydesc(cx, t, false, ti); - call_tydesc_glue_full(bcx, v, td, field, ti); - ret bcx; -} - -fn call_cmp_glue(cx: block, lhs: ValueRef, rhs: ValueRef, t: ty::t, - llop: ValueRef) -> result { - // We can't use call_tydesc_glue_full() and friends here because compare - // glue has a special signature. - - let bcx = cx; - - let r = spill_if_immediate(bcx, lhs, t); - let lllhs = r.val; - bcx = r.bcx; - r = spill_if_immediate(bcx, rhs, t); - let llrhs = r.val; - bcx = r.bcx; - - let llrawlhsptr = BitCast(bcx, lllhs, T_ptr(T_i8())); - let llrawrhsptr = BitCast(bcx, llrhs, T_ptr(T_i8())); - r = get_tydesc_simple(bcx, t, false); - let lltydesc = r.val; - bcx = r.bcx; - let lltydescs = - GEPi(bcx, lltydesc, [0, abi::tydesc_field_first_param]); - lltydescs = Load(bcx, lltydescs); - - let llfn = bcx.ccx().upcalls.cmp_type; - - let llcmpresultptr = alloca(bcx, T_i1()); - Call(bcx, llfn, [llcmpresultptr, lltydesc, lltydescs, - llrawlhsptr, llrawrhsptr, llop]); - ret rslt(bcx, Load(bcx, llcmpresultptr)); -} - -fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block { - if ty::type_needs_drop(cx.tcx(), t) { - ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue); - } - ret cx; -} - -fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block { - if ty::type_needs_drop(cx.tcx(), t) { - ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue); - } - ret cx; -} - -fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { - alt ty::get(t).struct { - ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str { free_ty(bcx, v, t) } - ty::ty_box(_) | ty::ty_opaque_box { - decr_refcnt_maybe_free(bcx, v, t) - } - _ { bcx.tcx().sess.bug("drop_ty_immediate: non-box ty"); } - } -} - -fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> result { - alt ty::get(t).struct { - ty::ty_box(_) | ty::ty_opaque_box { - rslt(incr_refcnt_of_boxed(bcx, v), v) - } - ty::ty_uniq(_) { - uniq::duplicate(bcx, v, t) - } - ty::ty_str | ty::ty_vec(_) { tvec::duplicate(bcx, v, t) } - _ { rslt(bcx, v) } - } -} - -fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block { - if ty::type_needs_drop(cx.tcx(), t) { - ret call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue); - } - ret cx; -} - -fn call_memmove(cx: block, dst: ValueRef, src: ValueRef, - n_bytes: ValueRef) -> result { - // FIXME: Provide LLVM with better alignment information when the - // alignment is statically known (it must be nothing more than a constant - // int, or LLVM complains -- not even a constant element of a tydesc - // works). - - let ccx = cx.ccx(); - let key = alt ccx.sess.targ_cfg.arch { - session::arch_x86 | session::arch_arm { "llvm.memmove.p0i8.p0i8.i32" } - session::arch_x86_64 { "llvm.memmove.p0i8.p0i8.i64" } - }; - let i = ccx.intrinsics; - assert (i.contains_key(key)); - let memmove = i.get(key); - let src_ptr = PointerCast(cx, src, T_ptr(T_i8())); - let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8())); - let size = IntCast(cx, n_bytes, ccx.int_type); - let align = C_i32(1i32); - let volatile = C_bool(false); - let ret_val = Call(cx, memmove, [dst_ptr, src_ptr, size, - align, volatile]); - ret rslt(cx, ret_val); -} - -fn memmove_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) -> - block { - let ccx = bcx.ccx(); - if check type_has_static_size(ccx, t) { - if ty::type_is_structural(t) { - let llsz = llsize_of(ccx, type_of(ccx, t)); - ret call_memmove(bcx, dst, src, llsz).bcx; - } - Store(bcx, Load(bcx, src), dst); - ret bcx; - } - - let {bcx, val: llsz} = size_of(bcx, t); - ret call_memmove(bcx, dst, src, llsz).bcx; -} - -enum copy_action { INIT, DROP_EXISTING, } - -// These are the types that are passed by pointer. -fn type_is_structural_or_param(t: ty::t) -> bool { - if ty::type_is_structural(t) { ret true; } - alt ty::get(t).struct { - ty::ty_param(_, _) { ret true; } - _ { ret false; } - } -} - -fn copy_val(cx: block, action: copy_action, dst: ValueRef, - src: ValueRef, t: ty::t) -> block { - if action == DROP_EXISTING && - (type_is_structural_or_param(t) || - ty::type_is_unique(t)) { - let dstcmp = load_if_immediate(cx, dst, t); - let cast = PointerCast(cx, dstcmp, val_ty(src)); - // Self-copy check - with_cond(cx, ICmp(cx, lib::llvm::IntNE, cast, src)) {|bcx| - copy_val_no_check(bcx, action, dst, src, t) - } - } else { - copy_val_no_check(cx, action, dst, src, t) - } -} - -fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef, - src: ValueRef, t: ty::t) -> block { - let ccx = bcx.ccx(), bcx = bcx; - if ty::type_is_scalar(t) { - Store(bcx, src, dst); - ret bcx; - } - if ty::type_is_nil(t) || ty::type_is_bot(t) { ret bcx; } - if ty::type_is_boxed(t) || ty::type_is_vec(t) || - ty::type_is_unique_box(t) { - if action == DROP_EXISTING { bcx = drop_ty(bcx, dst, t); } - Store(bcx, src, dst); - ret take_ty(bcx, dst, t); - } - if type_is_structural_or_param(t) { - if action == DROP_EXISTING { bcx = drop_ty(bcx, dst, t); } - bcx = memmove_ty(bcx, dst, src, t); - ret take_ty(bcx, dst, t); - } - ccx.sess.bug("unexpected type in trans::copy_val_no_check: " + - ty_to_str(ccx.tcx, t)); -} - - -// This works like copy_val, except that it deinitializes the source. -// Since it needs to zero out the source, src also needs to be an lval. -// FIXME: We always zero out the source. Ideally we would detect the -// case where a variable is always deinitialized by block exit and thus -// doesn't need to be dropped. -fn move_val(cx: block, action: copy_action, dst: ValueRef, - src: lval_result, t: ty::t) -> block { - let src_val = src.val; - let tcx = cx.tcx(), cx = cx; - if ty::type_is_scalar(t) { - if src.kind == owned { src_val = Load(cx, src_val); } - Store(cx, src_val, dst); - ret cx; - } else if ty::type_is_nil(t) || ty::type_is_bot(t) { - ret cx; - } else if ty::type_is_boxed(t) || ty::type_is_unique(t) { - if src.kind == owned { src_val = Load(cx, src_val); } - if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); } - Store(cx, src_val, dst); - if src.kind == owned { ret zero_alloca(cx, src.val, t); } - // If we're here, it must be a temporary. - revoke_clean(cx, src_val); - ret cx; - } else if type_is_structural_or_param(t) { - if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); } - cx = memmove_ty(cx, dst, src_val, t); - if src.kind == owned { ret zero_alloca(cx, src_val, t); } - // If we're here, it must be a temporary. - revoke_clean(cx, src_val); - ret cx; - } - cx.sess().bug("unexpected type in trans::move_val: " + - ty_to_str(tcx, t)); -} - -fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef, - src: lval_result, t: ty::t, last_use: bool) - -> block { - // Lvals in memory are not temporaries. Copy them. - if src.kind != temporary && !last_use { - let v = if src.kind == owned { - load_if_immediate(cx, src.val, t) - } else { - src.val - }; - ret copy_val(cx, action, dst, v, t); - } - ret move_val(cx, action, dst, src, t); -} - -fn trans_crate_lit(cx: crate_ctxt, lit: ast::lit) -> ValueRef { - alt lit.node { - ast::lit_int(i, t) { C_integral(T_int_ty(cx, t), i as u64, True) } - ast::lit_uint(u, t) { C_integral(T_uint_ty(cx, t), u, False) } - ast::lit_float(fs, t) { C_floating(fs, T_float_ty(cx, t)) } - ast::lit_bool(b) { C_bool(b) } - ast::lit_nil { C_nil() } - ast::lit_str(s) { - cx.sess.span_unimpl(lit.span, "unique string in this context"); - } - } -} - -fn trans_lit(cx: block, lit: ast::lit, dest: dest) -> block { - if dest == ignore { ret cx; } - alt lit.node { - ast::lit_str(s) { ret tvec::trans_str(cx, s, dest); } - _ { - ret store_in_dest(cx, trans_crate_lit(cx.ccx(), lit), dest); - } - } -} - -fn trans_unary(bcx: block, op: ast::unop, e: @ast::expr, - un_expr: @ast::expr, dest: dest) -> block { - // Check for user-defined method call - alt bcx.ccx().maps.method_map.find(un_expr.id) { - some(origin) { - let callee_id = ast_util::op_expr_callee_id(un_expr); - let fty = node_id_type(bcx, callee_id); - ret trans_call_inner(bcx, fty, {|bcx| - impl::trans_method_callee(bcx, callee_id, e, origin) - }, [], un_expr.id, dest); - } - _ {} - } - - if dest == ignore { ret trans_expr(bcx, e, ignore); } - let e_ty = expr_ty(bcx, e); - alt op { - ast::not { - let {bcx, val} = trans_temp_expr(bcx, e); - ret store_in_dest(bcx, Not(bcx, val), dest); - } - ast::neg { - let {bcx, val} = trans_temp_expr(bcx, e); - let neg = if ty::type_is_fp(e_ty) { - FNeg(bcx, val) - } else { Neg(bcx, val) }; - ret store_in_dest(bcx, neg, dest); - } - ast::box(_) { - let {bcx, box, body} = trans_malloc_boxed(bcx, e_ty); - add_clean_free(bcx, box, false); - // Cast the body type to the type of the value. This is needed to - // make enums work, since enums have a different LLVM type depending - // on whether they're boxed or not - let ccx = bcx.ccx(); - if check type_has_static_size(ccx, e_ty) { - let llety = T_ptr(type_of(ccx, e_ty)); - body = PointerCast(bcx, body, llety); - } - bcx = trans_expr_save_in(bcx, e, body); - revoke_clean(bcx, box); - ret store_in_dest(bcx, box, dest); - } - ast::uniq(_) { - ret uniq::trans_uniq(bcx, e, un_expr.id, dest); - } - ast::deref { - bcx.sess().bug("deref expressions should have been \ - translated using trans_lval(), not \ - trans_unary()"); - } - } -} - -fn trans_compare(cx: block, op: ast::binop, lhs: ValueRef, - _lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t) -> result { - if ty::type_is_scalar(rhs_t) { - let rs = compare_scalar_types(cx, lhs, rhs, rhs_t, op); - ret rslt(rs.bcx, rs.val); - } - - // Determine the operation we need. - let llop; - alt op { - ast::eq | ast::ne { llop = C_u8(abi::cmp_glue_op_eq); } - ast::lt | ast::ge { llop = C_u8(abi::cmp_glue_op_lt); } - ast::le | ast::gt { llop = C_u8(abi::cmp_glue_op_le); } - _ { cx.tcx().sess.bug("trans_compare got non-comparison-op"); } - } - - let rs = call_cmp_glue(cx, lhs, rhs, rhs_t, llop); - - // Invert the result if necessary. - alt op { - ast::eq | ast::lt | ast::le { ret rslt(rs.bcx, rs.val); } - ast::ne | ast::ge | ast::gt { - ret rslt(rs.bcx, Not(rs.bcx, rs.val)); - } - _ { cx.tcx().sess.bug("trans_compare got\ - non-comparison-op"); } - } -} - -fn cast_shift_expr_rhs(cx: block, op: ast::binop, - lhs: ValueRef, rhs: ValueRef) -> ValueRef { - cast_shift_rhs(op, lhs, rhs, - bind Trunc(cx, _, _), bind ZExt(cx, _, _)) -} - -fn cast_shift_const_rhs(op: ast::binop, - lhs: ValueRef, rhs: ValueRef) -> ValueRef { - cast_shift_rhs(op, lhs, rhs, - llvm::LLVMConstTrunc, llvm::LLVMConstZExt) -} - -fn cast_shift_rhs(op: ast::binop, - lhs: ValueRef, rhs: ValueRef, - trunc: fn(ValueRef, TypeRef) -> ValueRef, - zext: fn(ValueRef, TypeRef) -> ValueRef - ) -> ValueRef { - - // Shifts may have any size int on the rhs - if ast_util::is_shift_binop(op) { - let rhs_llty = val_ty(rhs); - let lhs_llty = val_ty(lhs); - let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty); - let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty); - if lhs_sz < rhs_sz { - trunc(rhs, lhs_llty) - } else if lhs_sz > rhs_sz { - // FIXME: If shifting by negative values becomes not undefined - // then this is wrong. - zext(rhs, lhs_llty) - } else { - rhs - } - } else { - rhs - } -} - -// Important to get types for both lhs and rhs, because one might be _|_ -// and the other not. -fn trans_eager_binop(cx: block, op: ast::binop, lhs: ValueRef, - lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t, dest: dest) - -> block { - if dest == ignore { ret cx; } - let intype = lhs_t; - if ty::type_is_bot(intype) { intype = rhs_t; } - let is_float = ty::type_is_fp(intype); - - let rhs = cast_shift_expr_rhs(cx, op, lhs, rhs); - - if op == ast::add && ty::type_is_sequence(intype) { - ret tvec::trans_add(cx, intype, lhs, rhs, dest); - } - let cx = cx, val = alt op { - ast::add { - if is_float { FAdd(cx, lhs, rhs) } - else { Add(cx, lhs, rhs) } - } - ast::subtract { - if is_float { FSub(cx, lhs, rhs) } - else { Sub(cx, lhs, rhs) } - } - ast::mul { - if is_float { FMul(cx, lhs, rhs) } - else { Mul(cx, lhs, rhs) } - } - ast::div { - if is_float { FDiv(cx, lhs, rhs) } - else if ty::type_is_signed(intype) { - SDiv(cx, lhs, rhs) - } else { UDiv(cx, lhs, rhs) } - } - ast::rem { - if is_float { FRem(cx, lhs, rhs) } - else if ty::type_is_signed(intype) { - SRem(cx, lhs, rhs) - } else { URem(cx, lhs, rhs) } - } - ast::bitor { Or(cx, lhs, rhs) } - ast::bitand { And(cx, lhs, rhs) } - ast::bitxor { Xor(cx, lhs, rhs) } - ast::lsl { Shl(cx, lhs, rhs) } - ast::lsr { LShr(cx, lhs, rhs) } - ast::asr { AShr(cx, lhs, rhs) } - _ { - let cmpr = trans_compare(cx, op, lhs, lhs_t, rhs, rhs_t); - cx = cmpr.bcx; - cmpr.val - } - }; - ret store_in_dest(cx, val, dest); -} - -fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop, - dst: @ast::expr, src: @ast::expr) -> block { - let t = expr_ty(bcx, src); - let lhs_res = trans_lval(bcx, dst); - assert (lhs_res.kind == owned); - - // A user-defined operator method - alt bcx.ccx().maps.method_map.find(ex.id) { - some(origin) { - let callee_id = ast_util::op_expr_callee_id(ex); - let fty = node_id_type(bcx, callee_id); - ret trans_call_inner(bcx, fty, {|bcx| - // FIXME provide the already-computed address, not the expr - impl::trans_method_callee(bcx, callee_id, dst, origin) - }, [src], ex.id, save_in(lhs_res.val)); - } - _ {} - } - - // Special case for `+= [x]` - alt ty::get(t).struct { - ty::ty_vec(_) { - alt src.node { - ast::expr_vec(args, _) { - ret tvec::trans_append_literal(lhs_res.bcx, - lhs_res.val, t, args); - } - _ { } - } - } - _ { } - } - let {bcx, val: rhs_val} = trans_temp_expr(lhs_res.bcx, src); - if ty::type_is_sequence(t) { - alt op { - ast::add { - ret tvec::trans_append(bcx, t, lhs_res.val, rhs_val); - } - _ { } - } - } - ret trans_eager_binop(bcx, op, Load(bcx, lhs_res.val), t, rhs_val, t, - save_in(lhs_res.val)); -} - -fn autoderef(cx: block, v: ValueRef, t: ty::t) -> result_t { - let v1: ValueRef = v; - let t1: ty::t = t; - let ccx = cx.ccx(); - while true { - alt ty::get(t1).struct { - ty::ty_box(mt) { - let body = GEPi(cx, v1, [0, abi::box_field_body]); - t1 = mt.ty; - - // Since we're changing levels of box indirection, we may have - // to cast this pointer, since statically-sized enum types have - // different types depending on whether they're behind a box - // or not. - if check type_has_static_size(ccx, t1) { - let llty = type_of(ccx, t1); - v1 = PointerCast(cx, body, T_ptr(llty)); - } else { v1 = body; } - } - ty::ty_uniq(_) { - let derefed = uniq::autoderef(v1, t1); - t1 = derefed.t; - v1 = derefed.v; - } - ty::ty_res(did, inner, tps) { - t1 = ty::substitute_type_params(ccx.tcx, tps, inner); - v1 = GEPi(cx, v1, [0, 1]); - } - ty::ty_enum(did, tps) { - let variants = ty::enum_variants(ccx.tcx, did); - if (*variants).len() != 1u || variants[0].args.len() != 1u { - break; - } - t1 = - ty::substitute_type_params(ccx.tcx, tps, variants[0].args[0]); - if check type_has_static_size(ccx, t1) { - v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, t1))); - } else { } // FIXME: typestate hack - } - _ { break; } - } - v1 = load_if_immediate(cx, v1, t1); - } - ret {bcx: cx, val: v1, ty: t1}; -} - -// refinement types would obviate the need for this -enum lazy_binop_ty { lazy_and, lazy_or } - -fn trans_lazy_binop(bcx: block, op: lazy_binop_ty, a: @ast::expr, - b: @ast::expr, dest: dest) -> block { - - let {bcx: past_lhs, val: lhs} = with_scope_result(bcx, "lhs") - {|bcx| trans_temp_expr(bcx, a)}; - if past_lhs.unreachable { ret past_lhs; } - let join = sub_block(bcx, "join"), before_rhs = sub_block(bcx, "rhs"); - - alt op { - lazy_and { CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb); } - lazy_or { CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb); } - } - let {bcx: past_rhs, val: rhs} = with_scope_result(before_rhs, "rhs") - {|bcx| trans_temp_expr(bcx, b)}; - - if past_rhs.unreachable { ret store_in_dest(join, lhs, dest); } - Br(past_rhs, join.llbb); - let phi = Phi(join, T_bool(), [lhs, rhs], [past_lhs.llbb, past_rhs.llbb]); - ret store_in_dest(join, phi, dest); -} - -fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr, - rhs: @ast::expr, dest: dest, ex: @ast::expr) -> block { - // User-defined operators - alt bcx.ccx().maps.method_map.find(ex.id) { - some(origin) { - let callee_id = ast_util::op_expr_callee_id(ex); - let fty = node_id_type(bcx, callee_id); - ret trans_call_inner(bcx, fty, {|bcx| - impl::trans_method_callee(bcx, callee_id, lhs, origin) - }, [rhs], ex.id, dest); - } - _ {} - } - - // First couple cases are lazy: - alt op { - ast::and { - ret trans_lazy_binop(bcx, lazy_and, lhs, rhs, dest); - } - ast::or { - ret trans_lazy_binop(bcx, lazy_or, lhs, rhs, dest); - } - _ { - // Remaining cases are eager: - let lhs_res = trans_temp_expr(bcx, lhs); - let rhs_res = trans_temp_expr(lhs_res.bcx, rhs); - ret trans_eager_binop(rhs_res.bcx, op, lhs_res.val, - expr_ty(bcx, lhs), rhs_res.val, - expr_ty(bcx, rhs), dest); - } - } -} - -fn trans_if(cx: block, cond: @ast::expr, thn: ast::blk, - els: option<@ast::expr>, dest: dest) - -> block { - let {bcx, val: cond_val} = trans_temp_expr(cx, cond); - - let then_dest = dup_for_join(dest); - let else_dest = dup_for_join(dest); - let then_cx = scope_block(bcx, "then"); - then_cx.block_span = some(thn.span); - let else_cx = scope_block(bcx, "else"); - option::may(els) {|e| else_cx.block_span = some(e.span); } - CondBr(bcx, cond_val, then_cx.llbb, else_cx.llbb); - let then_bcx = trans_block(then_cx, thn, then_dest); - then_bcx = trans_block_cleanups(then_bcx, then_cx); - // Calling trans_block directly instead of trans_expr - // because trans_expr will create another scope block - // context for the block, but we've already got the - // 'else' context - let else_bcx = alt els { - some(elexpr) { - alt elexpr.node { - ast::expr_if(_, _, _) { - let elseif_blk = ast_util::block_from_expr(elexpr); - trans_block(else_cx, elseif_blk, else_dest) - } - ast::expr_block(blk) { - trans_block(else_cx, blk, else_dest) - } - // would be nice to have a constraint on ifs - _ { cx.tcx().sess.bug("Strange alternative in if"); } - } - } - _ { else_cx } - }; - else_bcx = trans_block_cleanups(else_bcx, else_cx); - ret join_returns(cx, [then_bcx, else_bcx], [then_dest, else_dest], dest); -} - -fn trans_for(cx: block, local: @ast::local, seq: @ast::expr, - body: ast::blk) -> block { - fn inner(bcx: block, local: @ast::local, curr: ValueRef, t: ty::t, - body: ast::blk, outer_next_cx: block) -> block { - let next_cx = sub_block(bcx, "next"); - let scope_cx = loop_scope_block(bcx, cont_other(next_cx), - outer_next_cx, "for loop scope", - body.span); - Br(bcx, scope_cx.llbb); - let curr = PointerCast(bcx, curr, - T_ptr(type_of_or_i8(bcx.ccx(), t))); - let bcx = alt::bind_irrefutable_pat(scope_cx, local.node.pat, - curr, false); - bcx = trans_block(bcx, body, ignore); - cleanup_and_Br(bcx, scope_cx, next_cx.llbb); - ret next_cx; - } - let ccx = cx.ccx(); - let next_cx = sub_block(cx, "next"); - let seq_ty = expr_ty(cx, seq); - let {bcx: bcx, val: seq} = trans_temp_expr(cx, seq); - let seq = PointerCast(bcx, seq, T_ptr(ccx.opaque_vec_type)); - let fill = tvec::get_fill(bcx, seq); - if ty::type_is_str(seq_ty) { - fill = Sub(bcx, fill, C_int(ccx, 1)); - } - let bcx = tvec::iter_vec_raw(bcx, seq, seq_ty, fill, - bind inner(_, local, _, _, body, next_cx)); - Br(bcx, next_cx.llbb); - ret next_cx; -} - -fn trans_while(cx: block, cond: @ast::expr, body: ast::blk) - -> block { - let next_cx = sub_block(cx, "while next"); - let cond_cx = loop_scope_block(cx, cont_self, next_cx, - "while cond", body.span); - let body_cx = scope_block(cond_cx, "while loop body"); - Br(cx, cond_cx.llbb); - let cond_res = trans_temp_expr(cond_cx, cond); - let cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx); - CondBr(cond_bcx, cond_res.val, body_cx.llbb, next_cx.llbb); - let body_end = trans_block(body_cx, body, ignore); - cleanup_and_Br(body_end, body_cx, cond_cx.llbb); - ret next_cx; -} - -fn trans_do_while(cx: block, body: ast::blk, cond: @ast::expr) -> - block { - let next_cx = sub_block(cx, "next"); - let body_cx = - loop_scope_block(cx, cont_self, next_cx, - "do-while loop body", body.span); - let body_end = trans_block(body_cx, body, ignore); - let cond_cx = scope_block(body_cx, "do-while cond"); - cleanup_and_Br(body_end, body_cx, cond_cx.llbb); - let cond_res = trans_temp_expr(cond_cx, cond); - let cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx); - CondBr(cond_bcx, cond_res.val, body_cx.llbb, next_cx.llbb); - Br(cx, body_cx.llbb); - ret next_cx; -} - -type generic_info = {item_type: ty::t, - static_tis: [option<@tydesc_info>], - tydescs: [ValueRef], - param_bounds: @[ty::param_bounds], - origins: option<typeck::dict_res>}; - -enum generic_callee { - generic_full(generic_info), - generic_mono(ty::t), - generic_none, -} - -enum lval_kind { - temporary, //< Temporary value passed by value if of immediate type - owned, //< Non-temporary value passed by pointer - owned_imm, //< Non-temporary value passed by value -} -type local_var_result = {val: ValueRef, kind: lval_kind}; -type lval_result = {bcx: block, val: ValueRef, kind: lval_kind}; -enum callee_env { - null_env, - is_closure, - self_env(ValueRef, ty::t), - dict_env(ValueRef, ValueRef), -} -type lval_maybe_callee = {bcx: block, - val: ValueRef, - kind: lval_kind, - env: callee_env, - generic: generic_callee}; - -fn null_env_ptr(bcx: block) -> ValueRef { - C_null(T_opaque_box_ptr(bcx.ccx())) -} - -fn lval_from_local_var(bcx: block, r: local_var_result) -> lval_result { - ret { bcx: bcx, val: r.val, kind: r.kind }; -} - -fn lval_owned(bcx: block, val: ValueRef) -> lval_result { - ret {bcx: bcx, val: val, kind: owned}; -} -fn lval_temp(bcx: block, val: ValueRef) -> lval_result { - ret {bcx: bcx, val: val, kind: temporary}; -} - -fn lval_no_env(bcx: block, val: ValueRef, kind: lval_kind) - -> lval_maybe_callee { - ret {bcx: bcx, val: val, kind: kind, env: is_closure, - generic: generic_none}; -} - -fn trans_external_path(cx: block, did: ast::def_id, - tpt: ty::ty_param_bounds_and_ty) -> ValueRef { - let ccx = cx.fcx.ccx; - let name = csearch::get_symbol(ccx.sess.cstore, did); - ret get_extern_const(ccx.externs, ccx.llmod, name, - type_of_ty_param_bounds_and_ty(ccx, tpt)); -} - -fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t], - dicts: option<typeck::dict_res>) - -> option<{llfn: ValueRef, fty: ty::t}> { - let substs = vec::map(substs, {|t| - alt ty::get(t).struct { - ty::ty_box(mt) { ty::mk_opaque_box(ccx.tcx) } - _ { t } - } - }); - let hash_id = @{def: fn_id, substs: substs, dicts: alt dicts { - some(os) { vec::map(*os, {|o| impl::dict_id(ccx.tcx, o)}) } - none { [] } - }}; - alt ccx.monomorphized.find(hash_id) { - some(val) { ret some(val); } - none {} - } - - let tpt = ty::lookup_item_type(ccx.tcx, fn_id); - let mono_ty = ty::substitute_type_params(ccx.tcx, substs, tpt.ty); - let llfty = type_of_fn_from_ty(ccx, mono_ty, []); - - let map_node = ccx.tcx.items.get(fn_id.node); - // Get the path so that we can create a symbol - let (pt, name) = alt map_node { - ast_map::node_item(i, pt) { (pt, i.ident) } - ast_map::node_variant(v, _, pt) { (pt, v.node.name) } - ast_map::node_method(m, _, pt) { (pt, m.ident) } - // We can't monomorphize native functions - ast_map::node_native_item(_, _) { ret none; } - _ { fail "Unexpected node type"; } - }; - let pt = *pt + [path_name(ccx.names(name))]; - let s = mangle_exported_name(ccx, pt, mono_ty); - let lldecl = decl_cdecl_fn(ccx.llmod, s, llfty); - ccx.monomorphized.insert(hash_id, {llfn: lldecl, fty: mono_ty}); - - let psubsts = some({tys: substs, dicts: dicts, bounds: tpt.bounds}); - alt check map_node { - ast_map::node_item(@{node: ast::item_fn(decl, _, body), _}, _) { - trans_fn(ccx, pt, decl, body, lldecl, no_self, [], - psubsts, fn_id.node); - } - ast_map::node_item(@{node: ast::item_res(decl, _, _, _, _), _}, _) { - trans_res_ctor(ccx, pt, decl, fn_id.node, [], psubsts, lldecl); - } - ast_map::node_variant(v, enum_id, _) { - let tvs = ty::enum_variants(ccx.tcx, enum_id); - let this_tv = option::get(vec::find(*tvs, {|tv| - tv.id.node == fn_id.node})); - trans_enum_variant(ccx, enum_id.node, v, this_tv.disr_val, - (*tvs).len() == 1u, [], psubsts, lldecl); - } - ast_map::node_method(mth, impl_def_id, _) { - let selfty = ty::lookup_item_type(ccx.tcx, impl_def_id).ty; - let selfty = ty::substitute_type_params(ccx.tcx, substs, selfty); - trans_fn(ccx, pt, mth.decl, mth.body, lldecl, - impl_self(selfty), [], psubsts, fn_id.node); - } - } - some({llfn: lldecl, fty: mono_ty}) -} - -fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id, - substs: option<([ty::t], typeck::dict_res)>) - -> lval_maybe_callee { - let ccx = bcx.ccx(); - let tcx = ccx.tcx; - let tys = node_id_type_params(bcx, id); - let tpt = ty::lookup_item_type(tcx, fn_id); - - // Check whether this fn has an inlined copy and, if so, redirect fn_id to - // the local id of the inlined copy. - let fn_id = { - if fn_id.crate == ast::local_crate { - fn_id - } else { - alt ccx.inline_map.find(fn_id) { - none { fn_id } - some(ii) { - #debug["Found inlined version of %s with id %d", - ty::item_path_str(tcx, fn_id), - ii.id()]; - {crate: ast::local_crate, - node: ii.id()} - } - } - } - }; - - // The awkwardness below mostly stems from the fact that we're mixing - // monomorphized and non-monomorphized functions at the moment. If - // monomorphizing becomes the only approach, this'll be much simpler. - if ccx.sess.opts.monomorphize && - (option::is_some(substs) || tys.len() > 0u) && - fn_id.crate == ast::local_crate && - !vec::any(tys, {|t| ty::type_has_params(t)}) { - let mono = alt substs { - some((stys, dicts)) { - if (stys.len() + tys.len()) > 0u { - monomorphic_fn(ccx, fn_id, stys + tys, some(dicts)) - } else { none } - } - none { - alt ccx.maps.dict_map.find(id) { - some(dicts) { - alt impl::resolve_dicts_in_fn_ctxt(bcx.fcx, dicts) { - some(dicts) { monomorphic_fn(ccx, fn_id, tys, some(dicts)) } - none { none } - } - } - none { monomorphic_fn(ccx, fn_id, tys, none) } - } - } - }; - alt mono { - some({llfn, fty}) { - ret {bcx: bcx, val: llfn, - kind: owned, env: null_env, - generic: generic_mono(fty)}; - } - none {} - } - } - - let val = if fn_id.crate == ast::local_crate { - // Internal reference. - assert (ccx.item_ids.contains_key(fn_id.node)); - ccx.item_ids.get(fn_id.node) - } else { - // External reference. - trans_external_path(bcx, fn_id, tpt) - }; - - // FIXME: Need to support external crust functions - if fn_id.crate == ast::local_crate { - alt bcx.tcx().def_map.find(id) { - some(ast::def_fn(_, ast::crust_fn)) { - // Crust functions are just opaque pointers - let val = PointerCast(bcx, val, T_ptr(T_i8())); - ret lval_no_env(bcx, val, owned_imm); - } - _ { } - } - } - - let gen = generic_none, bcx = bcx; - if tys.len() > 0u { - let tydescs = [], tis = []; - for t in tys { - let ti = none; - let td = get_tydesc(bcx, t, true, ti); - tis += [ti]; - bcx = td.bcx; - tydescs += [td.val]; - } - gen = generic_full({item_type: tpt.ty, - static_tis: tis, - tydescs: tydescs, - param_bounds: tpt.bounds, - origins: ccx.maps.dict_map.find(id)}); - } - ret {bcx: bcx, val: val, kind: owned, env: null_env, generic: gen}; -} - -fn lookup_discriminant(ccx: crate_ctxt, vid: ast::def_id) -> ValueRef { - alt ccx.discrims.find(vid) { - none { - // It's an external discriminant that we haven't seen yet. - assert (vid.crate != ast::local_crate); - let sym = csearch::get_symbol(ccx.sess.cstore, vid); - let gvar = str::as_buf(sym, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) - }); - lib::llvm::SetLinkage(gvar, lib::llvm::ExternalLinkage); - llvm::LLVMSetGlobalConstant(gvar, True); - ccx.discrims.insert(vid, gvar); - ret gvar; - } - some(llval) { ret llval; } - } -} - -fn trans_local_var(cx: block, def: ast::def) -> local_var_result { - fn take_local(table: hashmap<ast::node_id, local_val>, - id: ast::node_id) -> local_var_result { - alt table.find(id) { - some(local_mem(v)) { {val: v, kind: owned} } - some(local_imm(v)) { {val: v, kind: owned_imm} } - r { fail("take_local: internal error"); } - } - } - alt def { - ast::def_upvar(nid, _, _) { - assert (cx.fcx.llupvars.contains_key(nid)); - ret { val: cx.fcx.llupvars.get(nid), kind: owned }; - } - ast::def_arg(nid, _) { - assert (cx.fcx.llargs.contains_key(nid)); - ret take_local(cx.fcx.llargs, nid); - } - ast::def_local(nid, _) | ast::def_binding(nid) { - assert (cx.fcx.lllocals.contains_key(nid)); - ret take_local(cx.fcx.lllocals, nid); - } - ast::def_self(nid) { - let slf = option::get(cx.fcx.llself); - let ptr = PointerCast(cx, slf.v, - T_ptr(type_of_or_i8(cx.ccx(), slf.t))); - ret {val: ptr, kind: owned}; - } - _ { - cx.sess().unimpl("unsupported def type in trans_local_def"); - } - } -} - -fn trans_path(cx: block, id: ast::node_id) - -> lval_maybe_callee { - ret trans_var(cx, cx.tcx().def_map.get(id), id); -} - -fn trans_var(cx: block, def: ast::def, id: ast::node_id) - -> lval_maybe_callee { - let ccx = cx.ccx(); - alt def { - ast::def_fn(did, _) { - ret lval_static_fn(cx, did, id, none); - } - ast::def_variant(tid, vid) { - if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u { - // N-ary variant. - ret lval_static_fn(cx, vid, id, none); - } else { - // Nullary variant. - let enum_ty = node_id_type(cx, id); - let alloc_result = alloc_ty(cx, enum_ty); - let llenumblob = alloc_result.val; - let llenumty = type_of_enum(ccx, tid, enum_ty); - let bcx = alloc_result.bcx; - let llenumptr = PointerCast(bcx, llenumblob, T_ptr(llenumty)); - let lldiscrimptr = GEPi(bcx, llenumptr, [0, 0]); - let lldiscrim_gv = lookup_discriminant(bcx.fcx.ccx, vid); - let lldiscrim = Load(bcx, lldiscrim_gv); - Store(bcx, lldiscrim, lldiscrimptr); - ret lval_no_env(bcx, llenumptr, temporary); - } - } - ast::def_const(did) { - if did.crate == ast::local_crate { - assert (ccx.consts.contains_key(did.node)); - ret lval_no_env(cx, ccx.consts.get(did.node), owned); - } else { - let tp = node_id_type(cx, id); - let val = trans_external_path(cx, did, {bounds: @[], ty: tp}); - ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm); - } - } - _ { - let loc = trans_local_var(cx, def); - ret lval_no_env(cx, loc.val, loc.kind); - } - } -} - -fn trans_rec_field(bcx: block, base: @ast::expr, - field: ast::ident) -> lval_result { - let {bcx, val} = trans_temp_expr(bcx, base); - let {bcx, val, ty} = autoderef(bcx, val, expr_ty(bcx, base)); - let fields = alt ty::get(ty).struct { - ty::ty_rec(fs) { fs } - // Constraint? - _ { bcx.tcx().sess.span_bug(base.span, "trans_rec_field:\ - base expr has non-record type"); } - }; - let ix = option::get(ty::field_idx(field, fields)); - let {bcx, val} = GEP_tup_like(bcx, ty, val, [0, ix as int]); - ret {bcx: bcx, val: val, kind: owned}; -} - -fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr, - idx: @ast::expr) -> lval_result { - let base_ty = expr_ty(cx, base); - let exp = trans_temp_expr(cx, base); - let lv = autoderef(exp.bcx, exp.val, base_ty); - let ix = trans_temp_expr(lv.bcx, idx); - let v = lv.val; - let bcx = ix.bcx; - let ccx = cx.ccx(); - - // Cast to an LLVM integer. Rust is less strict than LLVM in this regard. - let ix_val; - let ix_size = llsize_of_real(cx.ccx(), val_ty(ix.val)); - let int_size = llsize_of_real(cx.ccx(), ccx.int_type); - if ix_size < int_size { - ix_val = ZExt(bcx, ix.val, ccx.int_type); - } else if ix_size > int_size { - ix_val = Trunc(bcx, ix.val, ccx.int_type); - } else { ix_val = ix.val; } - - let unit_ty = node_id_type(cx, ex.id); - let unit_sz = size_of(bcx, unit_ty); - bcx = unit_sz.bcx; - maybe_name_value(cx.ccx(), unit_sz.val, "unit_sz"); - let scaled_ix = Mul(bcx, ix_val, unit_sz.val); - maybe_name_value(cx.ccx(), scaled_ix, "scaled_ix"); - let lim = tvec::get_fill(bcx, v); - let body = tvec::get_dataptr(bcx, v, type_of_or_i8(ccx, unit_ty)); - let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, lim); - bcx = with_cond(bcx, bounds_check) {|bcx| - // fail: bad bounds check. - trans_fail(bcx, some(ex.span), "bounds check") - }; - let elt = if check type_has_static_size(ccx, unit_ty) { - let elt_1 = GEP(bcx, body, [ix_val]); - let llunitty = type_of(ccx, unit_ty); - PointerCast(bcx, elt_1, T_ptr(llunitty)) - } else { - body = PointerCast(bcx, body, T_ptr(T_i8())); - GEP(bcx, body, [scaled_ix]) - }; - ret lval_owned(bcx, elt); -} - -fn expr_is_lval(bcx: block, e: @ast::expr) -> bool { - let ccx = bcx.ccx(); - ty::expr_is_lval(ccx.maps.method_map, e) -} - -fn trans_callee(bcx: block, e: @ast::expr) -> lval_maybe_callee { - alt e.node { - ast::expr_path(_) { ret trans_path(bcx, e.id); } - ast::expr_field(base, ident, _) { - // Lval means this is a record field, so not a method - if !expr_is_lval(bcx, e) { - alt bcx.ccx().maps.method_map.find(e.id) { - some(origin) { // An impl method - ret impl::trans_method_callee(bcx, e.id, base, origin); - } - _ { - bcx.ccx().sess.span_bug(e.span, "trans_callee: weird expr"); - } - } - } - } - _ {} - } - let lv = trans_temp_lval(bcx, e); - ret lval_no_env(lv.bcx, lv.val, lv.kind); -} - -// Use this when you know you are compiling an lval. -// The additional bool returned indicates whether it's mem (that is -// represented as an alloca or heap, hence needs a 'load' to be used as an -// immediate). -fn trans_lval(cx: block, e: @ast::expr) -> lval_result { - alt e.node { - ast::expr_path(_) { - let v = trans_path(cx, e.id); - ret lval_maybe_callee_to_lval(v, expr_ty(cx, e)); - } - ast::expr_field(base, ident, _) { - ret trans_rec_field(cx, base, ident); - } - ast::expr_index(base, idx) { - ret trans_index(cx, e, base, idx); - } - ast::expr_unary(ast::deref, base) { - let ccx = cx.ccx(); - let sub = trans_temp_expr(cx, base); - let t = expr_ty(cx, base); - let val = alt check ty::get(t).struct { - ty::ty_box(_) { - GEPi(sub.bcx, sub.val, [0, abi::box_field_body]) - } - ty::ty_res(_, _, _) { - GEPi(sub.bcx, sub.val, [0, 1]) - } - ty::ty_enum(_, _) { - let ety = expr_ty(cx, e); - let ellty = if check type_has_static_size(ccx, ety) { - T_ptr(type_of(ccx, ety)) - } else { T_typaram_ptr(ccx.tn) }; - PointerCast(sub.bcx, sub.val, ellty) - } - ty::ty_ptr(_) | ty::ty_uniq(_) { sub.val } - }; - ret lval_owned(sub.bcx, val); - } - _ { cx.sess().span_bug(e.span, "non-lval in trans_lval"); } - } -} - -fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result { - let must_bind = alt c.generic { generic_full(_) { true } _ { false } } || - alt c.env { self_env(_, _) | dict_env(_, _) { true } _ { false } }; - if must_bind { - let n_args = ty::ty_fn_args(ty).len(); - let args = vec::init_elt(n_args, none); - let space = alloc_ty(c.bcx, ty); - let bcx = closure::trans_bind_1(space.bcx, ty, c, args, ty, - save_in(space.val)); - add_clean_temp(bcx, space.val, ty); - {bcx: bcx, val: space.val, kind: temporary} - } else { - alt check c.env { - is_closure { {bcx: c.bcx, val: c.val, kind: c.kind} } - null_env { - let llfnty = llvm::LLVMGetElementType(val_ty(c.val)); - let llfn = create_real_fn_pair(c.bcx, llfnty, c.val, - null_env_ptr(c.bcx)); - {bcx: c.bcx, val: llfn, kind: temporary} - } - } - } -} - -fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, - llsrc: ValueRef, signed: bool) -> ValueRef { - let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype); - let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype); - ret if dstsz == srcsz { - BitCast(bcx, llsrc, lldsttype) - } else if srcsz > dstsz { - TruncOrBitCast(bcx, llsrc, lldsttype) - } else if signed { - SExtOrBitCast(bcx, llsrc, lldsttype) - } else { ZExtOrBitCast(bcx, llsrc, lldsttype) }; -} - -fn float_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef, - llsrc: ValueRef) -> ValueRef { - let srcsz = lib::llvm::float_width(llsrctype); - let dstsz = lib::llvm::float_width(lldsttype); - ret if dstsz > srcsz { - FPExt(bcx, llsrc, lldsttype) - } else if srcsz > dstsz { - FPTrunc(bcx, llsrc, lldsttype) - } else { llsrc }; -} - -fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id, - dest: dest) -> block { - let ccx = cx.ccx(); - let t_out = node_id_type(cx, id); - alt ty::get(t_out).struct { - ty::ty_iface(_, _) { ret impl::trans_cast(cx, e, id, dest); } - _ {} - } - let e_res = trans_temp_expr(cx, e); - let ll_t_in = val_ty(e_res.val); - let t_in = expr_ty(cx, e); - let ll_t_out = type_of(ccx, t_out); - - enum kind { pointer, integral, float, enum_, other, } - fn t_kind(t: ty::t) -> kind { - ret if ty::type_is_fp(t) { float } - else if ty::type_is_unsafe_ptr(t) { pointer } - else if ty::type_is_integral(t) { integral } - else if ty::type_is_enum(t) { enum_ } - else { other }; - } - let k_in = t_kind(t_in); - let k_out = t_kind(t_out); - let s_in = k_in == integral && ty::type_is_signed(t_in); - - let newval = - alt {in: k_in, out: k_out} { - {in: integral, out: integral} { - int_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val, s_in) - } - {in: float, out: float} { - float_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val) - } - {in: integral, out: float} { - if s_in { - SIToFP(e_res.bcx, e_res.val, ll_t_out) - } else { UIToFP(e_res.bcx, e_res.val, ll_t_out) } - } - {in: float, out: integral} { - if ty::type_is_signed(t_out) { - FPToSI(e_res.bcx, e_res.val, ll_t_out) - } else { FPToUI(e_res.bcx, e_res.val, ll_t_out) } - } - {in: integral, out: pointer} { - IntToPtr(e_res.bcx, e_res.val, ll_t_out) - } - {in: pointer, out: integral} { - PtrToInt(e_res.bcx, e_res.val, ll_t_out) - } - {in: pointer, out: pointer} { - PointerCast(e_res.bcx, e_res.val, ll_t_out) - } - {in: enum_, out: integral} | {in: enum_, out: float} { - let cx = e_res.bcx; - let llenumty = T_opaque_enum_ptr(ccx); - let av_enum = PointerCast(cx, e_res.val, llenumty); - let lldiscrim_a_ptr = GEPi(cx, av_enum, [0, 0]); - let lldiscrim_a = Load(cx, lldiscrim_a_ptr); - alt k_out { - integral {int_cast(e_res.bcx, ll_t_out, - val_ty(lldiscrim_a), lldiscrim_a, true)} - float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)} - _ { ccx.sess.bug("Translating unsupported cast.") } - } - } - _ { ccx.sess.bug("Translating unsupported cast.") } - }; - ret store_in_dest(e_res.bcx, newval, dest); -} - -// temp_cleanups: cleanups that should run only if failure occurs before the -// call takes place: -fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr, - &temp_cleanups: [ValueRef]) -> result { - let ccx = cx.ccx(); - let e_ty = expr_ty(cx, e); - let is_bot = ty::type_is_bot(e_ty); - let lv = trans_temp_lval(cx, e); - let bcx = lv.bcx; - let val = lv.val; - let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode); - if is_bot { - // For values of type _|_, we generate an - // "undef" value, as such a value should never - // be inspected. It's important for the value - // to have type lldestty (the callee's expected type). - val = llvm::LLVMGetUndef(lldestty); - } else if arg_mode == ast::by_ref || arg_mode == ast::by_val { - let copied = false, imm = ty::type_is_immediate(e_ty); - if arg_mode == ast::by_ref && lv.kind != owned && imm { - val = do_spill_noroot(bcx, val); - copied = true; - } - if ccx.maps.copy_map.contains_key(e.id) && lv.kind != temporary { - if !copied { - let alloc = alloc_ty(bcx, e_ty); - bcx = copy_val(alloc.bcx, INIT, alloc.val, - load_if_immediate(alloc.bcx, val, e_ty), e_ty); - val = alloc.val; - } else { bcx = take_ty(bcx, val, e_ty); } - add_clean(bcx, val, e_ty); - } - if arg_mode == ast::by_val && (lv.kind == owned || !imm) { - val = Load(bcx, val); - } - } else if arg_mode == ast::by_copy || arg_mode == ast::by_move { - let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty); - let move_out = arg_mode == ast::by_move || - ccx.maps.last_uses.contains_key(e.id); - bcx = cx; - if lv.kind == temporary { revoke_clean(bcx, val); } - if lv.kind == owned || !ty::type_is_immediate(e_ty) { - bcx = memmove_ty(bcx, alloc, val, e_ty); - if move_out && ty::type_needs_drop(ccx.tcx, e_ty) { - bcx = zero_alloca(bcx, val, e_ty); - } - } else { Store(bcx, val, alloc); } - val = alloc; - if lv.kind != temporary && !move_out { - bcx = take_ty(bcx, val, e_ty); - } - - // In the event that failure occurs before the call actually - // happens, have to cleanup this copy: - add_clean_temp_mem(bcx, val, e_ty); - temp_cleanups += [val]; - } else if ty::type_is_immediate(e_ty) && lv.kind != owned { - let r = do_spill(bcx, val, e_ty); - val = r.val; - bcx = r.bcx; - } - - if !is_bot && arg.ty != e_ty || ty::type_has_params(arg.ty) { - val = PointerCast(bcx, val, lldestty); - } - ret rslt(bcx, val); -} - - -// NB: must keep 4 fns in sync: -// -// - type_of_fn -// - create_llargs_for_fn_args. -// - new_fn_ctxt -// - trans_args -fn trans_args(cx: block, llenv: ValueRef, - gen: generic_callee, es: [@ast::expr], fn_ty: ty::t, - dest: dest) - -> {bcx: block, - args: [ValueRef], - retslot: ValueRef} { - - let temp_cleanups = []; - let args = ty::ty_fn_args(fn_ty); - let llargs: [ValueRef] = []; - let lltydescs: [ValueRef] = []; - - let ccx = cx.ccx(); - let bcx = cx; - - let retty = ty::ty_fn_ret(fn_ty), full_retty = retty; - alt gen { - generic_full(g) { - lazily_emit_all_generic_info_tydesc_glues(ccx, g); - let i = 0u, n_orig = 0u; - for param in *g.param_bounds { - lltydescs += [g.tydescs[i]]; - for bound in *param { - alt bound { - ty::bound_iface(_) { - let res = impl::get_dict( - bcx, option::get(g.origins)[n_orig]); - lltydescs += [res.val]; - bcx = res.bcx; - n_orig += 1u; - } - _ {} - } - } - i += 1u; - } - args = ty::ty_fn_args(g.item_type); - retty = ty::ty_fn_ret(g.item_type); - } - generic_mono(t) { - args = ty::ty_fn_args(t); - retty = ty::ty_fn_ret(t); - } - _ { } - } - // Arg 0: Output pointer. - let llretslot = alt dest { - ignore { - if ty::type_is_nil(retty) { - llvm::LLVMGetUndef(T_ptr(T_nil())) - } else { - let {bcx: cx, val} = alloc_ty(bcx, full_retty); - bcx = cx; - val - } - } - save_in(dst) { dst } - by_val(_) { - let {bcx: cx, val} = alloc_ty(bcx, full_retty); - bcx = cx; - val - } - }; - - if retty != full_retty || ty::type_has_params(retty) { - // It's possible that the callee has some generic-ness somewhere in - // its return value -- say a method signature within an obj or a fn - // type deep in a structure -- which the caller has a concrete view - // of. If so, cast the caller's view of the restlot to the callee's - // view, for the sake of making a type-compatible call. - let llretty = T_ptr(type_of(ccx, retty)); - llargs += [PointerCast(cx, llretslot, llretty)]; - } else { llargs += [llretslot]; } - - // Arg 1: Env (closure-bindings / self value) - llargs += [llenv]; - - // Args >2: ty_params ... - llargs += lltydescs; - - // ... then explicit args. - - // First we figure out the caller's view of the types of the arguments. - // This will be needed if this is a generic call, because the callee has - // to cast her view of the arguments to the caller's view. - let arg_tys = type_of_explicit_args(ccx, args); - let i = 0u; - for e: @ast::expr in es { - let r = trans_arg_expr(bcx, args[i], arg_tys[i], e, temp_cleanups); - bcx = r.bcx; - llargs += [r.val]; - i += 1u; - } - - // now that all arguments have been successfully built, we can revoke any - // temporary cleanups, as they are only needed if argument construction - // should fail (for example, cleanup of copy mode args). - vec::iter(temp_cleanups) {|c| - revoke_clean(bcx, c) - } - - ret {bcx: bcx, - args: llargs, - retslot: llretslot}; -} - -fn trans_call(in_cx: block, f: @ast::expr, - args: [@ast::expr], id: ast::node_id, dest: dest) - -> block { - trans_call_inner(in_cx, expr_ty(in_cx, f), - {|cx| trans_callee(cx, f)}, args, id, dest) -} - -fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t, - get_callee: fn(block) -> lval_maybe_callee, - args: [@ast::expr], id: ast::node_id, dest: dest) - -> block { - with_scope(in_cx, "call") {|cx| - let f_res = get_callee(cx); - let bcx = f_res.bcx, ccx = cx.ccx(); - - let faddr = f_res.val; - let llenv, dict_param = none; - alt f_res.env { - null_env { - llenv = llvm::LLVMGetUndef(T_opaque_box_ptr(ccx)); - } - self_env(e, _) { - llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx)); - } - dict_env(dict, e) { - llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx)); - dict_param = some(dict); - } - is_closure { - // It's a closure. Have to fetch the elements - if f_res.kind == owned { - faddr = load_if_immediate(bcx, faddr, fn_expr_ty); - } - let pair = faddr; - faddr = GEPi(bcx, pair, [0, abi::fn_field_code]); - faddr = Load(bcx, faddr); - let llclosure = GEPi(bcx, pair, [0, abi::fn_field_box]); - llenv = Load(bcx, llclosure); - } - } - - let ret_ty = node_id_type(bcx, id); - let args_res = - trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest); - bcx = args_res.bcx; - let llargs = args_res.args; - option::may(dict_param) {|dict| llargs = [dict] + llargs} - let llretslot = args_res.retslot; - - /* If the block is terminated, - then one or more of the args has - type _|_. Since that means it diverges, the code - for the call itself is unreachable. */ - bcx = invoke_full(bcx, faddr, llargs); - alt dest { - ignore { - if llvm::LLVMIsUndef(llretslot) != lib::llvm::True { - bcx = drop_ty(bcx, llretslot, ret_ty); - } - } - save_in(_) { } // Already saved by callee - by_val(cell) { - *cell = Load(bcx, llretslot); - } - } - if ty::type_is_bot(ret_ty) { Unreachable(bcx); } - bcx - } -} - -fn invoke(bcx: block, llfn: ValueRef, - llargs: [ValueRef]) -> block { - ret invoke_(bcx, llfn, llargs, Invoke); -} - -fn invoke_full(bcx: block, llfn: ValueRef, llargs: [ValueRef]) - -> block { - ret invoke_(bcx, llfn, llargs, Invoke); -} - -fn invoke_(bcx: block, llfn: ValueRef, llargs: [ValueRef], - invoker: fn(block, ValueRef, [ValueRef], - BasicBlockRef, BasicBlockRef)) -> block { - // FIXME: May be worth turning this into a plain call when there are no - // cleanups to run - if bcx.unreachable { ret bcx; } - let normal_bcx = sub_block(bcx, "normal return"); - invoker(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx)); - ret normal_bcx; -} - -fn get_landing_pad(bcx: block) -> BasicBlockRef { - fn in_lpad_scope_cx(bcx: block, f: fn(scope_info)) { - let bcx = bcx; - while true { - alt bcx.kind { - block_scope(info) { - if info.cleanups.len() > 0u || bcx.parent == parent_none { - f(info); ret; - } - } - _ {} - } - bcx = block_parent(bcx); - } - } - - let cached = none, pad_bcx = bcx; // Guaranteed to be set below - in_lpad_scope_cx(bcx) {|info| - // If there is a valid landing pad still around, use it - alt info.landing_pad { - some(target) { cached = some(target); ret; } - none {} - } - pad_bcx = sub_block(bcx, "unwind"); - info.landing_pad = some(pad_bcx.llbb); - } - alt cached { some(b) { ret b; } none {} } // Can't return from block above - // The landing pad return type (the type being propagated). Not sure what - // this represents but it's determined by the personality function and - // this is what the EH proposal example uses. - let llretty = T_struct([T_ptr(T_i8()), T_i32()]); - // The exception handling personality function. This is the C++ - // personality function __gxx_personality_v0, wrapped in our naming - // convention. - let personality = bcx.ccx().upcalls.rust_personality; - // The only landing pad clause will be 'cleanup' - let llretval = LandingPad(pad_bcx, llretty, personality, 1u); - // The landing pad block is a cleanup - SetCleanup(pad_bcx, llretval); - - // Because we may have unwound across a stack boundary, we must call into - // the runtime to figure out which stack segment we are on and place the - // stack limit back into the TLS. - Call(pad_bcx, bcx.ccx().upcalls.reset_stack_limit, []); - - // We store the retval in a function-central alloca, so that calls to - // Resume can find it. - alt bcx.fcx.personality { - some(addr) { Store(pad_bcx, llretval, addr); } - none { - let addr = alloca(pad_bcx, val_ty(llretval)); - bcx.fcx.personality = some(addr); - Store(pad_bcx, llretval, addr); - } - } - - // Unwind all parent scopes, and finish with a Resume instr - cleanup_and_leave(pad_bcx, none, none); - ret pad_bcx.llbb; -} - -fn trans_tup(bcx: block, elts: [@ast::expr], id: ast::node_id, - dest: dest) -> block { - let t = node_id_type(bcx, id); - let bcx = bcx; - let addr = alt dest { - ignore { - for ex in elts { bcx = trans_expr(bcx, ex, ignore); } - ret bcx; - } - save_in(pos) { pos } - _ { bcx.tcx().sess.bug("trans_tup: weird dest"); } - }; - let temp_cleanups = [], i = 0; - for e in elts { - let dst = GEP_tup_like(bcx, t, addr, [0, i]); - let e_ty = expr_ty(bcx, e); - bcx = trans_expr_save_in(dst.bcx, e, dst.val); - add_clean_temp_mem(bcx, dst.val, e_ty); - temp_cleanups += [dst.val]; - i += 1; - } - for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); } - ret bcx; -} - -fn trans_rec(bcx: block, fields: [ast::field], - base: option<@ast::expr>, id: ast::node_id, - dest: dest) -> block { - let t = node_id_type(bcx, id); - let bcx = bcx; - let addr = alt dest { - ignore { - for fld in fields { - bcx = trans_expr(bcx, fld.node.expr, ignore); - } - ret bcx; - } - save_in(pos) { pos } - _ { bcx.tcx().sess.bug("trans_rec: weird dest"); } - }; - - let ty_fields = alt ty::get(t).struct { - ty::ty_rec(f) { f } - _ { bcx.tcx().sess.bug("trans_rec: id doesn't\ - have a record type") } }; - let temp_cleanups = []; - for fld in fields { - let ix = option::get(vec::position(ty_fields, {|ft| - str::eq(fld.node.ident, ft.ident) - })); - let dst = GEP_tup_like(bcx, t, addr, [0, ix as int]); - bcx = trans_expr_save_in(dst.bcx, fld.node.expr, dst.val); - add_clean_temp_mem(bcx, dst.val, ty_fields[ix].mt.ty); - temp_cleanups += [dst.val]; - } - alt base { - some(bexp) { - let {bcx: cx, val: base_val} = trans_temp_expr(bcx, bexp), i = 0; - bcx = cx; - // Copy over inherited fields - for tf in ty_fields { - if !vec::any(fields, {|f| str::eq(f.node.ident, tf.ident)}) { - let dst = GEP_tup_like(bcx, t, addr, [0, i]); - let base = GEP_tup_like(bcx, t, base_val, [0, i]); - let val = load_if_immediate(base.bcx, base.val, tf.mt.ty); - bcx = copy_val(base.bcx, INIT, dst.val, val, tf.mt.ty); - } - i += 1; - } - } - none {} - }; - - // Now revoke the cleanups as we pass responsibility for the data - // structure on to the caller - for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); } - ret bcx; -} - -// Store the result of an expression in the given memory location, ensuring -// that nil or bot expressions get ignore rather than save_in as destination. -fn trans_expr_save_in(bcx: block, e: @ast::expr, dest: ValueRef) - -> block { - let t = expr_ty(bcx, e); - let do_ignore = ty::type_is_bot(t) || ty::type_is_nil(t); - ret trans_expr(bcx, e, if do_ignore { ignore } else { save_in(dest) }); -} - -// Call this to compile an expression that you need as an intermediate value, -// and you want to know whether you're dealing with an lval or not (the kind -// field in the returned struct). For non-intermediates, use trans_expr or -// trans_expr_save_in. For intermediates where you don't care about lval-ness, -// use trans_temp_expr. -fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result { - let bcx = bcx; - if expr_is_lval(bcx, e) { - ret trans_lval(bcx, e); - } else { - let ty = expr_ty(bcx, e); - if ty::type_is_nil(ty) || ty::type_is_bot(ty) { - bcx = trans_expr(bcx, e, ignore); - ret {bcx: bcx, val: C_nil(), kind: temporary}; - } else if ty::type_is_immediate(ty) { - let cell = empty_dest_cell(); - bcx = trans_expr(bcx, e, by_val(cell)); - add_clean_temp(bcx, *cell, ty); - ret {bcx: bcx, val: *cell, kind: temporary}; - } else { - let {bcx, val: scratch} = alloc_ty(bcx, ty); - bcx = trans_expr_save_in(bcx, e, scratch); - add_clean_temp(bcx, scratch, ty); - ret {bcx: bcx, val: scratch, kind: temporary}; - } - } -} - -// Use only for intermediate values. See trans_expr and trans_expr_save_in for -// expressions that must 'end up somewhere' (or get ignored). -fn trans_temp_expr(bcx: block, e: @ast::expr) -> result { - let {bcx, val, kind} = trans_temp_lval(bcx, e); - if kind == owned { - val = load_if_immediate(bcx, val, expr_ty(bcx, e)); - } - ret {bcx: bcx, val: val}; -} - -// Translate an expression, with the dest argument deciding what happens with -// the result. Invariants: -// - exprs returning nil or bot always get dest=ignore -// - exprs with non-immediate type never get dest=by_val -fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { - let tcx = bcx.tcx(); - debuginfo::update_source_pos(bcx, e.span); - - #debug["trans_expr(e=%s,e.id=%d,dest=%s,ty=%s)", - expr_to_str(e), - e.id, - dest_str(bcx.ccx(), dest), - ty_to_str(tcx, expr_ty(bcx, e))]; - - if expr_is_lval(bcx, e) { - ret lval_to_dps(bcx, e, dest); - } - - alt e.node { - ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) { - ret trans_if(bcx, cond, thn, els, dest); - } - ast::expr_alt(expr, arms, _) { - ret alt::trans_alt(bcx, expr, arms, dest); - } - ast::expr_block(blk) { - ret with_scope(bcx, "block-expr body") {|bcx| - bcx.block_span = some(blk.span); - trans_block(bcx, blk, dest) - }; - } - ast::expr_rec(args, base) { - ret trans_rec(bcx, args, base, e.id, dest); - } - ast::expr_tup(args) { ret trans_tup(bcx, args, e.id, dest); } - ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); } - ast::expr_vec(args, _) { ret tvec::trans_vec(bcx, args, e.id, dest); } - ast::expr_binary(op, lhs, rhs) { - ret trans_binary(bcx, op, lhs, rhs, dest, e); - } - ast::expr_unary(op, x) { - assert op != ast::deref; // lvals are handled above - ret trans_unary(bcx, op, x, e, dest); - } - ast::expr_fn(proto, decl, body, cap_clause) { - ret closure::trans_expr_fn( - bcx, proto, decl, body, e.span, e.id, *cap_clause, dest); - } - ast::expr_fn_block(decl, body) { - alt ty::get(expr_ty(bcx, e)).struct { - ty::ty_fn({proto, _}) { - #debug("translating fn_block %s with type %s", - expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e))); - let cap_clause = { copies: [], moves: [] }; - ret closure::trans_expr_fn( - bcx, proto, decl, body, e.span, e.id, cap_clause, dest); - } - _ { - fail "Type of fn block is not a function!"; - } - } - } - ast::expr_bind(f, args) { - ret closure::trans_bind( - bcx, f, args, e.id, dest); - } - ast::expr_copy(a) { - if !expr_is_lval(bcx, a) { - ret trans_expr(bcx, a, dest); - } - else { ret lval_to_dps(bcx, a, dest); } - } - ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); } - ast::expr_call(f, args, _) { - ret trans_call(bcx, f, args, e.id, dest); - } - ast::expr_field(base, _, _) { - if dest == ignore { ret trans_expr(bcx, base, ignore); } - let callee = trans_callee(bcx, e), ty = expr_ty(bcx, e); - let lv = lval_maybe_callee_to_lval(callee, ty); - revoke_clean(lv.bcx, lv.val); - ret memmove_ty(lv.bcx, get_dest_addr(dest), lv.val, ty); - } - ast::expr_index(base, idx) { - // If it is here, it's not an lval, so this is a user-defined index op - let origin = bcx.ccx().maps.method_map.get(e.id); - let callee_id = ast_util::op_expr_callee_id(e); - let fty = node_id_type(bcx, callee_id); - ret trans_call_inner(bcx, fty, {|bcx| - impl::trans_method_callee(bcx, callee_id, base, origin) - }, [idx], e.id, dest); - } - - // These return nothing - ast::expr_break { - assert dest == ignore; - ret trans_break(bcx); - } - ast::expr_cont { - assert dest == ignore; - ret trans_cont(bcx); - } - ast::expr_ret(ex) { - assert dest == ignore; - ret trans_ret(bcx, ex); - } - ast::expr_be(ex) { - ret trans_be(bcx, ex); - } - ast::expr_fail(expr) { - assert dest == ignore; - ret trans_fail_expr(bcx, some(e.span), expr); - } - ast::expr_log(_, lvl, a) { - assert dest == ignore; - ret trans_log(lvl, bcx, a); - } - ast::expr_assert(a) { - assert dest == ignore; - ret trans_check_expr(bcx, a, "Assertion"); - } - ast::expr_check(ast::checked_expr, a) { - assert dest == ignore; - ret trans_check_expr(bcx, a, "Predicate"); - } - ast::expr_check(ast::claimed_expr, a) { - assert dest == ignore; - /* Claims are turned on and off by a global variable - that the RTS sets. This case generates code to - check the value of that variable, doing nothing - if it's set to false and acting like a check - otherwise. */ - let c = get_extern_const(bcx.ccx().externs, bcx.ccx().llmod, - "check_claims", T_bool()); - ret with_cond(bcx, Load(bcx, c)) {|bcx| - trans_check_expr(bcx, a, "Claim") - }; - } - ast::expr_for(decl, seq, body) { - assert dest == ignore; - ret trans_for(bcx, decl, seq, body); - } - ast::expr_while(cond, body) { - assert dest == ignore; - ret trans_while(bcx, cond, body); - } - ast::expr_do_while(body, cond) { - assert dest == ignore; - ret trans_do_while(bcx, body, cond); - } - ast::expr_assign(dst, src) { - assert dest == ignore; - let src_r = trans_temp_lval(bcx, src); - let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst); - assert kind == owned; - ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r, - expr_ty(bcx, src), - bcx.ccx().maps.last_uses.contains_key(src.id)); - } - ast::expr_move(dst, src) { - // FIXME: calculate copy init-ness in typestate. - assert dest == ignore; - let src_r = trans_temp_lval(bcx, src); - let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst); - assert kind == owned; - ret move_val(bcx, DROP_EXISTING, addr, src_r, - expr_ty(bcx, src)); - } - ast::expr_swap(dst, src) { - assert dest == ignore; - let lhs_res = trans_lval(bcx, dst); - assert lhs_res.kind == owned; - let rhs_res = trans_lval(lhs_res.bcx, src); - let t = expr_ty(bcx, src); - let {bcx: bcx, val: tmp_alloc} = alloc_ty(rhs_res.bcx, t); - // Swap through a temporary. - bcx = move_val(bcx, INIT, tmp_alloc, lhs_res, t); - bcx = move_val(bcx, INIT, lhs_res.val, rhs_res, t); - ret move_val(bcx, INIT, rhs_res.val, lval_owned(bcx, tmp_alloc), t); - } - ast::expr_assign_op(op, dst, src) { - assert dest == ignore; - ret trans_assign_op(bcx, e, op, dst, src); - } - _ { bcx.tcx().sess.span_bug(e.span, "trans_expr reached\ - fall-through case"); } - - } -} - -fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block { - let lv = trans_lval(bcx, e), ccx = bcx.ccx(); - let {bcx, val, kind} = lv; - let last_use = kind == owned && ccx.maps.last_uses.contains_key(e.id); - let ty = expr_ty(bcx, e); - alt dest { - by_val(cell) { - if kind == temporary { - revoke_clean(bcx, val); - *cell = val; - } else if last_use { - *cell = Load(bcx, val); - if ty::type_needs_drop(ccx.tcx, ty) { - bcx = zero_alloca(bcx, val, ty); - } - } else { - if kind == owned { val = Load(bcx, val); } - let {bcx: cx, val} = take_ty_immediate(bcx, val, ty); - *cell = val; - bcx = cx; - } - } - save_in(loc) { - bcx = store_temp_expr(bcx, INIT, loc, lv, ty, last_use); - } - ignore {} - } - ret bcx; -} - -fn do_spill(cx: block, v: ValueRef, t: ty::t) -> result { - // We have a value but we have to spill it, and root it, to pass by alias. - let bcx = cx; - - if ty::type_is_bot(t) { - ret rslt(bcx, C_null(T_ptr(T_i8()))); - } - - let r = alloc_ty(bcx, t); - bcx = r.bcx; - let llptr = r.val; - - Store(bcx, v, llptr); - - ret rslt(bcx, llptr); -} - -// Since this function does *not* root, it is the caller's responsibility to -// ensure that the referent is pointed to by a root. -fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef { - let llptr = alloca(cx, val_ty(v)); - Store(cx, v, llptr); - ret llptr; -} - -fn spill_if_immediate(cx: block, v: ValueRef, t: ty::t) -> result { - if ty::type_is_immediate(t) { ret do_spill(cx, v, t); } - ret rslt(cx, v); -} - -fn load_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef { - if ty::type_is_immediate(t) { ret Load(cx, v); } - ret v; -} - -fn trans_log(lvl: @ast::expr, bcx: block, e: @ast::expr) -> block { - let ccx = bcx.ccx(); - if ty::type_is_bot(expr_ty(bcx, lvl)) { - ret trans_expr(bcx, lvl, ignore); - } - - let modpath = [path_mod(ccx.link_meta.name)] + - vec::filter(bcx.fcx.path, {|e| - alt e { path_mod(_) { true } _ { false } } - }); - let modname = path_str(modpath); - - let global = if ccx.module_data.contains_key(modname) { - ccx.module_data.get(modname) - } else { - let s = link::mangle_internal_name_by_path_and_seq( - ccx, modpath, "loglevel"); - let global = str::as_buf(s, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf) - }); - llvm::LLVMSetGlobalConstant(global, False); - llvm::LLVMSetInitializer(global, C_null(T_i32())); - lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage); - ccx.module_data.insert(modname, global); - global - }; - let current_level = Load(bcx, global); - let {bcx, val: level} = with_scope_result(bcx, "level") {|bcx| - trans_temp_expr(bcx, lvl) - }; - - with_cond(bcx, ICmp(bcx, lib::llvm::IntUGE, current_level, level)) {|bcx| - with_scope(bcx, "log") {|bcx| - let {bcx, val, _} = trans_temp_expr(bcx, e); - let e_ty = expr_ty(bcx, e); - let {bcx, val: tydesc} = get_tydesc_simple(bcx, e_ty, false); - // Call the polymorphic log function. - let {bcx, val} = spill_if_immediate(bcx, val, e_ty); - let val = PointerCast(bcx, val, T_ptr(T_i8())); - Call(bcx, ccx.upcalls.log_type, [tydesc, val, level]); - bcx - } - } -} - -fn trans_check_expr(bcx: block, e: @ast::expr, s: str) -> block { - let expr_str = s + " " + expr_to_str(e) + " failed"; - let {bcx, val} = with_scope_result(bcx, "check") {|bcx| - trans_temp_expr(bcx, e) - }; - with_cond(bcx, Not(bcx, val)) {|bcx| - trans_fail(bcx, some(e.span), expr_str) - } -} - -fn trans_fail_expr(bcx: block, sp_opt: option<span>, - fail_expr: option<@ast::expr>) -> block { - let bcx = bcx; - alt fail_expr { - some(expr) { - let ccx = bcx.ccx(), tcx = ccx.tcx; - let expr_res = trans_temp_expr(bcx, expr); - let e_ty = expr_ty(bcx, expr); - bcx = expr_res.bcx; - - if ty::type_is_str(e_ty) { - let data = tvec::get_dataptr( - bcx, expr_res.val, type_of_or_i8( - ccx, ty::mk_mach_uint(tcx, ast::ty_u8))); - ret trans_fail_value(bcx, sp_opt, data); - } else if bcx.unreachable || ty::type_is_bot(e_ty) { - ret bcx; - } else { - bcx.sess().span_bug( - expr.span, "fail called with unsupported type " + - ty_to_str(tcx, e_ty)); - } - } - _ { ret trans_fail(bcx, sp_opt, "explicit failure"); } - } -} - -fn trans_fail(bcx: block, sp_opt: option<span>, fail_str: str) -> - block { - let V_fail_str = C_cstr(bcx.ccx(), fail_str); - ret trans_fail_value(bcx, sp_opt, V_fail_str); -} - -fn trans_fail_value(bcx: block, sp_opt: option<span>, - V_fail_str: ValueRef) -> block { - let ccx = bcx.ccx(); - let V_filename; - let V_line; - alt sp_opt { - some(sp) { - let sess = bcx.sess(); - let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo); - V_filename = C_cstr(bcx.ccx(), loc.file.name); - V_line = loc.line as int; - } - none { V_filename = C_cstr(bcx.ccx(), "<runtime>"); V_line = 0; } - } - let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8())); - V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8())); - let args = [V_str, V_filename, C_int(ccx, V_line)]; - let bcx = invoke(bcx, bcx.ccx().upcalls._fail, args); - Unreachable(bcx); - ret bcx; -} - -fn trans_break_cont(bcx: block, to_end: bool) - -> block { - // Locate closest loop block, outputting cleanup as we go. - let unwind = bcx, target = bcx; - while true { - alt unwind.kind { - block_scope({is_loop: some({cnt, brk}), _}) { - target = if to_end { - brk - } else { - alt cnt { - cont_other(o) { o } - cont_self { unwind } - } - }; - break; - } - _ {} - } - unwind = alt check unwind.parent { - parent_some(cx) { cx } - parent_none { - bcx.sess().bug - (if to_end { "break" } else { "cont" } + " outside a loop"); - } - }; - } - cleanup_and_Br(bcx, unwind, target.llbb); - Unreachable(bcx); - ret bcx; -} - -fn trans_break(cx: block) -> block { - ret trans_break_cont(cx, true); -} - -fn trans_cont(cx: block) -> block { - ret trans_break_cont(cx, false); -} - -fn trans_ret(bcx: block, e: option<@ast::expr>) -> block { - let bcx = bcx; - alt e { - some(x) { bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr); } - _ {} - } - cleanup_and_leave(bcx, none, some(bcx.fcx.llreturn)); - Unreachable(bcx); - ret bcx; -} - -fn build_return(bcx: block) { Br(bcx, bcx.fcx.llreturn); } - -fn trans_be(cx: block, e: @ast::expr) -> block { - // FIXME: Turn this into a real tail call once - // calling convention issues are settled - ret trans_ret(cx, some(e)); -} - -fn init_local(bcx: block, local: @ast::local) -> block { - let ty = node_id_type(bcx, local.node.id); - let llptr = alt bcx.fcx.lllocals.find(local.node.id) { - some(local_mem(v)) { v } - some(_) { bcx.tcx().sess.span_bug(local.span, - "init_local: Someone forgot to document why it's\ - safe to assume local.node.init must be local_mem!"); - } - // This is a local that is kept immediate - none { - let initexpr = alt local.node.init { - some({expr, _}) { expr } - none { bcx.tcx().sess.span_bug(local.span, - "init_local: Someone forgot to document why it's\ - safe to assume local.node.init isn't none!"); } - }; - let {bcx, val, kind} = trans_temp_lval(bcx, initexpr); - if kind != temporary { - if kind == owned { val = Load(bcx, val); } - let rs = take_ty_immediate(bcx, val, ty); - bcx = rs.bcx; val = rs.val; - add_clean_temp(bcx, val, ty); - } - bcx.fcx.lllocals.insert(local.node.pat.id, local_imm(val)); - ret bcx; - } - }; - - let bcx = bcx; - alt local.node.init { - some(init) { - if init.op == ast::init_assign || !expr_is_lval(bcx, init.expr) { - bcx = trans_expr_save_in(bcx, init.expr, llptr); - } else { // This is a move from an lval, must perform an actual move - let sub = trans_lval(bcx, init.expr); - bcx = move_val(sub.bcx, INIT, llptr, sub, ty); - } - } - _ { bcx = zero_alloca(bcx, llptr, ty); } - } - // Make a note to drop this slot on the way out. - add_clean(bcx, llptr, ty); - ret alt::bind_irrefutable_pat(bcx, local.node.pat, llptr, false); -} - -fn zero_alloca(cx: block, llptr: ValueRef, t: ty::t) - -> block { - let bcx = cx; - let ccx = cx.ccx(); - if check type_has_static_size(ccx, t) { - let llty = type_of(ccx, t); - Store(bcx, C_null(llty), llptr); - } else { - let key = alt ccx.sess.targ_cfg.arch { - session::arch_x86 | session::arch_arm { "llvm.memset.p0i8.i32" } - session::arch_x86_64 { "llvm.memset.p0i8.i64" } - }; - let i = ccx.intrinsics; - let memset = i.get(key); - let dst_ptr = PointerCast(cx, llptr, T_ptr(T_i8())); - let size = size_of(cx, t); - bcx = size.bcx; - let align = C_i32(1i32); // cannot use computed value here. - let volatile = C_bool(false); - Call(cx, memset, [dst_ptr, C_u8(0u), size.val, align, volatile]); - } - ret bcx; -} - -fn trans_stmt(cx: block, s: ast::stmt) -> block { - #debug["trans_expr(%s)", stmt_to_str(s)]; - - if (!cx.sess().opts.no_asm_comments) { - add_span_comment(cx, s.span, stmt_to_str(s)); - } - - let bcx = cx; - debuginfo::update_source_pos(cx, s.span); - - alt s.node { - ast::stmt_expr(e, _) | ast::stmt_semi(e, _) { - bcx = trans_expr(cx, e, ignore); - } - ast::stmt_decl(d, _) { - alt d.node { - ast::decl_local(locals) { - for local in locals { - bcx = init_local(bcx, local); - if cx.sess().opts.extra_debuginfo { - debuginfo::create_local_var(bcx, local); - } - } - } - ast::decl_item(i) { trans_item(cx.fcx.ccx, *i); } - } - } - _ { cx.sess().unimpl("stmt variant"); } - } - - ret bcx; -} - -// You probably don't want to use this one. See the -// next three functions instead. -fn new_block(cx: fn_ctxt, parent: block_parent, kind: block_kind, - name: str, block_span: option<span>) -> block { - let s = ""; - if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo { - s = cx.ccx.names(name); - } - let llbb: BasicBlockRef = str::as_buf(s, {|buf| - llvm::LLVMAppendBasicBlock(cx.llfn, buf) - }); - let bcx = @{llbb: llbb, - mutable terminated: false, - mutable unreachable: false, - parent: parent, - kind: kind, - mutable block_span: block_span, - fcx: cx}; - alt parent { - parent_some(cx) { - if cx.unreachable { Unreachable(bcx); } - } - _ {} - } - ret bcx; -} - -fn simple_block_scope() -> block_kind { - block_scope({is_loop: none, mutable cleanups: [], - mutable cleanup_paths: [], mutable landing_pad: none}) -} - -// Use this when you're at the top block of a function or the like. -fn top_scope_block(fcx: fn_ctxt, sp: option<span>) -> block { - ret new_block(fcx, parent_none, simple_block_scope(), - "function top level", sp); -} - -fn scope_block(bcx: block, n: str) -> block { - ret new_block(bcx.fcx, parent_some(bcx), simple_block_scope(), - n, none); -} - -fn loop_scope_block(bcx: block, _cont: loop_cont, - _break: block, n: str, sp: span) - -> block { - ret new_block(bcx.fcx, parent_some(bcx), block_scope({ - is_loop: some({cnt: _cont, brk: _break}), - mutable cleanups: [], - mutable cleanup_paths: [], - mutable landing_pad: none - }), n, some(sp)); -} - - -// Use this when you're making a general CFG BB within a scope. -fn sub_block(bcx: block, n: str) -> block { - ret new_block(bcx.fcx, parent_some(bcx), block_non_scope, n, none); -} - -fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block { - ret @{llbb: llbb, - mutable terminated: false, - mutable unreachable: false, - parent: parent_none, - kind: block_non_scope, - mutable block_span: none, - fcx: fcx}; -} - - -// trans_block_cleanups: Go through all the cleanups attached to this -// block and execute them. -// -// When translating a block that introdces new variables during its scope, we -// need to make sure those variables go out of scope when the block ends. We -// do that by running a 'cleanup' function for each variable. -// trans_block_cleanups runs all the cleanup functions for the block. -fn trans_block_cleanups(bcx: block, cleanup_cx: block) -> - block { - if bcx.unreachable { ret bcx; } - let bcx = bcx; - alt check cleanup_cx.kind { - block_scope({cleanups, _}) { - vec::riter(cleanups) {|cu| - alt cu { clean(cfn) | clean_temp(_, cfn) { bcx = cfn(bcx); } } - } - } - } - ret bcx; -} - -// In the last argument, some(block) mean jump to this block, and none means -// this is a landing pad and leaving should be accomplished with a resume -// instruction. -fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>, - leave: option<BasicBlockRef>) { - let cur = bcx, bcx = bcx; - while true { - alt cur.kind { - block_scope(info) if info.cleanups.len() > 0u { - for exists in info.cleanup_paths { - if exists.target == leave { - Br(bcx, exists.dest); - ret; - } - } - let sub_cx = sub_block(bcx, "cleanup"); - Br(bcx, sub_cx.llbb); - info.cleanup_paths += [{target: leave, dest: sub_cx.llbb}]; - bcx = trans_block_cleanups(sub_cx, cur); - } - _ {} - } - alt upto { - some(bb) { if cur.llbb == bb { break; } } - _ {} - } - cur = alt cur.parent { - parent_some(next) { next } - parent_none { assert option::is_none(upto); break; } - }; - } - alt leave { - some(target) { Br(bcx, target); } - none { Resume(bcx, Load(bcx, option::get(bcx.fcx.personality))); } - } -} - -fn cleanup_and_Br(bcx: block, upto: block, - target: BasicBlockRef) { - cleanup_and_leave(bcx, some(upto.llbb), some(target)); -} - -fn leave_block(bcx: block, out_of: block) -> block { - let next_cx = sub_block(block_parent(out_of), "next"); - if bcx.unreachable { Unreachable(next_cx); } - cleanup_and_Br(bcx, out_of, next_cx.llbb); - next_cx -} - -fn with_scope(bcx: block, name: str, f: fn(block) -> block) -> block { - let scope_cx = scope_block(bcx, name); - Br(bcx, scope_cx.llbb); - leave_block(f(scope_cx), scope_cx) -} - -fn with_scope_result(bcx: block, name: str, f: fn(block) -> result) - -> result { - let scope_cx = scope_block(bcx, name); - Br(bcx, scope_cx.llbb); - let {bcx, val} = f(scope_cx); - {bcx: leave_block(bcx, scope_cx), val: val} -} - -fn with_cond(bcx: block, val: ValueRef, f: fn(block) -> block) -> block { - let next_cx = sub_block(bcx, "next"), cond_cx = sub_block(bcx, "cond"); - CondBr(bcx, val, cond_cx.llbb, next_cx.llbb); - let after_cx = f(cond_cx); - if !after_cx.terminated { Br(after_cx, next_cx.llbb); } - next_cx -} - -fn trans_fn_cleanups(fcx: fn_ctxt, cx: block) { - option::may(fcx.llobstacktoken) {|lltoken| - Call(cx, fcx.ccx.upcalls.dynastack_free, [lltoken]); - } -} - -fn block_locals(b: ast::blk, it: fn(@ast::local)) { - for s: @ast::stmt in b.node.stmts { - alt s.node { - ast::stmt_decl(d, _) { - alt d.node { - ast::decl_local(locals) { - for local in locals { it(local); } - } - _ {/* fall through */ } - } - } - _ {/* fall through */ } - } - } -} - -fn alloc_ty(cx: block, t: ty::t) -> result { - let bcx = cx, ccx = cx.ccx(); - let llty = type_of(ccx, t); - let val = if type_has_static_size(ccx, t) { - alloca(bcx, llty) - } else { - // NB: we have to run this particular 'size_of' in a - // block built on the llderivedtydescs block for the fn, - // so that the size dominates the array_alloca that - // comes next. - let n = size_of(raw_block(cx.fcx, cx.fcx.llderivedtydescs), - t); - bcx.fcx.llderivedtydescs = n.bcx.llbb; - PointerCast(bcx, dynastack_alloca(bcx, T_i8(), n.val, t), T_ptr(llty)) - }; - - // NB: since we've pushed all size calculations in this - // function up to the alloca block, we actually return the - // block passed into us unmodified; it doesn't really - // have to be passed-and-returned here, but it fits - // past caller conventions and may well make sense again, - // so we leave it as-is. - - ret rslt(cx, val); -} - -fn alloc_local(cx: block, local: @ast::local) -> block { - let t = node_id_type(cx, local.node.id); - let simple_name = alt local.node.pat.node { - ast::pat_ident(pth, none) { some(path_to_ident(pth)) } - _ { none } - }; - // Do not allocate space for locals that can be kept immediate. - let ccx = cx.ccx(); - if option::is_some(simple_name) && - !ccx.maps.mutbl_map.contains_key(local.node.pat.id) && - !ccx.maps.last_uses.contains_key(local.node.pat.id) && - ty::type_is_immediate(t) { - alt local.node.init { - some({op: ast::init_assign, _}) { ret cx; } - _ {} - } - } - let {bcx, val} = alloc_ty(cx, t); - if cx.sess().opts.debuginfo { - option::may(simple_name) {|name| - str::as_buf(name, {|buf| - llvm::LLVMSetValueName(val, buf) - }); - } - } - cx.fcx.lllocals.insert(local.node.id, local_mem(val)); - ret bcx; -} - -fn trans_block(bcx: block, b: ast::blk, dest: dest) - -> block { - let bcx = bcx; - block_locals(b) {|local| bcx = alloc_local(bcx, local); }; - for s: @ast::stmt in b.node.stmts { - debuginfo::update_source_pos(bcx, b.span); - bcx = trans_stmt(bcx, *s); - } - alt b.node.expr { - some(e) { - let bt = ty::type_is_bot(expr_ty(bcx, e)); - debuginfo::update_source_pos(bcx, e.span); - bcx = trans_expr(bcx, e, if bt { ignore } else { dest }); - } - _ { assert dest == ignore || bcx.unreachable; } - } - ret bcx; -} - -// Creates the standard quartet of basic blocks: static allocas, copy args, -// derived tydescs, and dynamic allocas. -fn mk_standard_basic_blocks(llfn: ValueRef) -> - {sa: BasicBlockRef, - ca: BasicBlockRef, - dt: BasicBlockRef, - da: BasicBlockRef, - rt: BasicBlockRef} { - ret {sa: str::as_buf("static_allocas", {|buf| - llvm::LLVMAppendBasicBlock(llfn, buf) }), - ca: str::as_buf("load_env", {|buf| - llvm::LLVMAppendBasicBlock(llfn, buf) }), - dt: str::as_buf("derived_tydescs", {|buf| - llvm::LLVMAppendBasicBlock(llfn, buf) }), - da: str::as_buf("dynamic_allocas", {|buf| - llvm::LLVMAppendBasicBlock(llfn, buf) }), - rt: str::as_buf("return", {|buf| - llvm::LLVMAppendBasicBlock(llfn, buf) })}; -} - - -// NB: must keep 4 fns in sync: -// -// - type_of_fn -// - create_llargs_for_fn_args. -// - new_fn_ctxt -// - trans_args -fn new_fn_ctxt_w_id(ccx: crate_ctxt, path: path, - llfndecl: ValueRef, id: ast::node_id, - param_substs: option<param_substs>, - sp: option<span>) -> fn_ctxt { - let llbbs = mk_standard_basic_blocks(llfndecl); - ret @{llfn: llfndecl, - llenv: llvm::LLVMGetParam(llfndecl, 1u as c_uint), - llretptr: llvm::LLVMGetParam(llfndecl, 0u as c_uint), - mutable llstaticallocas: llbbs.sa, - mutable llloadenv: llbbs.ca, - mutable llderivedtydescs_first: llbbs.dt, - mutable llderivedtydescs: llbbs.dt, - mutable lldynamicallocas: llbbs.da, - mutable llreturn: llbbs.rt, - mutable llobstacktoken: none::<ValueRef>, - mutable llself: none, - mutable personality: none, - llargs: new_int_hash::<local_val>(), - lllocals: new_int_hash::<local_val>(), - llupvars: new_int_hash::<ValueRef>(), - mutable lltyparams: [], - derived_tydescs: ty::new_ty_hash(), - id: id, - param_substs: param_substs, - span: sp, - path: path, - ccx: ccx}; -} - -fn new_fn_ctxt(ccx: crate_ctxt, path: path, llfndecl: ValueRef, - sp: option<span>) -> fn_ctxt { - ret new_fn_ctxt_w_id(ccx, path, llfndecl, -1, none, sp); -} - -// NB: must keep 4 fns in sync: -// -// - type_of_fn -// - create_llargs_for_fn_args. -// - new_fn_ctxt -// - trans_args - -// create_llargs_for_fn_args: Creates a mapping from incoming arguments to -// allocas created for them. -// -// When we translate a function, we need to map its incoming arguments to the -// spaces that have been created for them (by code in the llallocas field of -// the function's fn_ctxt). create_llargs_for_fn_args populates the llargs -// field of the fn_ctxt with -fn create_llargs_for_fn_args(cx: fn_ctxt, - ty_self: self_arg, - args: [ast::arg], - tps_bounds: [ty::param_bounds]) { - // Skip the implicit arguments 0, and 1. - let arg_n = first_tp_arg; - alt ty_self { - impl_self(tt) { - cx.llself = some({v: cx.llenv, t: tt}); - } - no_self {} - } - for bounds in tps_bounds { - let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint); - let dicts = none; - arg_n += 1u; - for bound in *bounds { - alt bound { - ty::bound_iface(_) { - let dict = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint); - arg_n += 1u; - dicts = some(alt dicts { - none { [dict] } - some(ds) { ds + [dict] } - }); - } - _ {} - } - } - cx.lltyparams += [{desc: lltydesc, dicts: dicts}]; - } - - // Populate the llargs field of the function context with the ValueRefs - // that we get from llvm::LLVMGetParam for each argument. - for arg: ast::arg in args { - let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint); - assert (llarg as int != 0); - // Note that this uses local_mem even for things passed by value. - // copy_args_to_allocas will overwrite the table entry with local_imm - // before it's actually used. - cx.llargs.insert(arg.id, local_mem(llarg)); - arg_n += 1u; - } -} - -fn copy_args_to_allocas(fcx: fn_ctxt, bcx: block, args: [ast::arg], - arg_tys: [ty::arg]) -> block { - let tcx = bcx.tcx(); - let arg_n: uint = 0u, bcx = bcx; - let epic_fail = fn@() -> ! { - tcx.sess.bug("Someone forgot\ - to document an invariant in copy_args_to_allocas!"); - }; - for arg in arg_tys { - let id = args[arg_n].id; - let argval = alt fcx.llargs.get(id) { local_mem(v) { v } - _ { epic_fail() } }; - alt ty::resolved_mode(tcx, arg.mode) { - ast::by_mutbl_ref { } - ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); } - ast::by_val { - if !ty::type_is_immediate(arg.ty) { - let {bcx: cx, val: alloc} = alloc_ty(bcx, arg.ty); - bcx = cx; - Store(bcx, argval, alloc); - fcx.llargs.insert(id, local_mem(alloc)); - } else { - fcx.llargs.insert(id, local_imm(argval)); - } - } - ast::by_ref {} - } - if fcx.ccx.sess.opts.extra_debuginfo { - debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span); - } - arg_n += 1u; - } - ret bcx; -} - -// Ties up the llstaticallocas -> llloadenv -> llderivedtydescs -> -// lldynamicallocas -> lltop edges, and builds the return block. -fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) { - tie_up_header_blocks(fcx, lltop); - let ret_cx = raw_block(fcx, fcx.llreturn); - trans_fn_cleanups(fcx, ret_cx); - RetVoid(ret_cx); -} - -fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) { - Br(raw_block(fcx, fcx.llstaticallocas), fcx.llloadenv); - Br(raw_block(fcx, fcx.llloadenv), fcx.llderivedtydescs_first); - Br(raw_block(fcx, fcx.llderivedtydescs), fcx.lldynamicallocas); - Br(raw_block(fcx, fcx.lldynamicallocas), lltop); -} - -enum self_arg { impl_self(ty::t), no_self, } - -// trans_closure: Builds an LLVM function out of a source function. -// If the function closes over its environment a closure will be -// returned. -fn trans_closure(ccx: crate_ctxt, path: path, decl: ast::fn_decl, - body: ast::blk, llfndecl: ValueRef, - ty_self: self_arg, - tps_bounds: [ty::param_bounds], - param_substs: option<param_substs>, - id: ast::node_id, maybe_load_env: fn(fn_ctxt)) { - set_uwtable(llfndecl); - - // Set up arguments to the function. - let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs, - some(body.span)); - create_llargs_for_fn_args(fcx, ty_self, decl.inputs, tps_bounds); - - // Create the first basic block in the function and keep a handle on it to - // pass to finish_fn later. - let bcx_top = top_scope_block(fcx, some(body.span)), bcx = bcx_top; - let lltop = bcx.llbb; - let block_ty = node_id_type(bcx, body.node.id); - - let arg_tys = ty::ty_fn_args(node_id_type(bcx, id)); - bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, arg_tys); - - maybe_load_env(fcx); - - // This call to trans_block is the place where we bridge between - // translation calls that don't have a return value (trans_crate, - // trans_mod, trans_item, et cetera) and those that do - // (trans_block, trans_expr, et cetera). - if option::is_none(body.node.expr) || - ty::type_is_bot(block_ty) || - ty::type_is_nil(block_ty) { - bcx = trans_block(bcx, body, ignore); - } else { - bcx = trans_block(bcx, body, save_in(fcx.llretptr)); - } - cleanup_and_Br(bcx, bcx_top, fcx.llreturn); - - // Insert the mandatory first few basic blocks before lltop. - finish_fn(fcx, lltop); -} - -// trans_fn: creates an LLVM function corresponding to a source language -// function. -fn trans_fn(ccx: crate_ctxt, - path: path, - decl: ast::fn_decl, - body: ast::blk, - llfndecl: ValueRef, - ty_self: self_arg, - tps_bounds: [ty::param_bounds], - param_substs: option<param_substs>, - id: ast::node_id) { - let do_time = ccx.sess.opts.stats; - let start = if do_time { time::get_time() } - else { {sec: 0u32, usec: 0u32} }; - trans_closure(ccx, path, decl, body, llfndecl, ty_self, - tps_bounds, param_substs, id, {|fcx| - if ccx.sess.opts.extra_debuginfo { - debuginfo::create_function(fcx); - } - }); - if do_time { - let end = time::get_time(); - log_fn_time(ccx, path_str(path), start, end); - } -} - -fn trans_res_ctor(ccx: crate_ctxt, path: path, dtor: ast::fn_decl, - ctor_id: ast::node_id, tps_bounds: [ty::param_bounds], - param_substs: option<param_substs>, llfndecl: ValueRef) { - // Create a function for the constructor - let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, ctor_id, - param_substs, none); - create_llargs_for_fn_args(fcx, no_self, dtor.inputs, tps_bounds); - let bcx = top_scope_block(fcx, none), lltop = bcx.llbb; - let fty = node_id_type(bcx, ctor_id); - let arg_t = ty::ty_fn_args(fty)[0].ty; - let tup_t = ty::mk_tup(ccx.tcx, [ty::mk_mach_uint(ccx.tcx, ast::ty_u8), - arg_t]); - let arg = alt fcx.llargs.find(dtor.inputs[0].id) { - some(local_mem(x)) { x } - _ { ccx.sess.bug("Someone forgot to document an invariant \ - in trans_res_ctor"); } - }; - let llretptr = fcx.llretptr; - if ty::type_has_dynamic_size(ccx.tcx, ty::ty_fn_ret(fty)) { - let llret_t = T_ptr(T_struct([ccx.int_type, llvm::LLVMTypeOf(arg)])); - llretptr = BitCast(bcx, llretptr, llret_t); - } - - let {bcx, val: dst} = GEP_tup_like(bcx, tup_t, llretptr, [0, 1]); - bcx = memmove_ty(bcx, dst, arg, arg_t); - let flag = GEP_tup_like(bcx, tup_t, llretptr, [0, 0]); - bcx = flag.bcx; - let one = C_u8(1u); - Store(bcx, one, flag.val); - build_return(bcx); - finish_fn(fcx, lltop); -} - - -fn trans_enum_variant(ccx: crate_ctxt, enum_id: ast::node_id, - variant: ast::variant, disr: int, is_degen: bool, - ty_params: [ast::ty_param], - param_substs: option<param_substs>, - llfndecl: ValueRef) { - // Translate variant arguments to function arguments. - let fn_args = [], i = 0u; - for varg in variant.node.args { - fn_args += [{mode: ast::expl(ast::by_copy), - ty: varg.ty, - ident: "arg" + uint::to_str(i, 10u), - id: varg.id}]; - } - let fcx = new_fn_ctxt_w_id(ccx, [], llfndecl, variant.node.id, - param_substs, none); - create_llargs_for_fn_args(fcx, no_self, fn_args, - param_bounds(ccx, ty_params)); - let ty_param_substs = alt param_substs { - some(substs) { substs.tys } - none { - let i = 0u; - vec::map(ty_params, {|tp| - i += 1u; - ty::mk_param(ccx.tcx, i - 1u, local_def(tp.id)) - }) - } - }; - let bcx = top_scope_block(fcx, none), lltop = bcx.llbb; - let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id)); - bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys); - - // Cast the enum to a type we can GEP into. - let llblobptr = if is_degen { - fcx.llretptr - } else { - let llenumptr = - PointerCast(bcx, fcx.llretptr, T_opaque_enum_ptr(ccx)); - let lldiscrimptr = GEPi(bcx, llenumptr, [0, 0]); - Store(bcx, C_int(ccx, disr), lldiscrimptr); - GEPi(bcx, llenumptr, [0, 1]) - }; - let i = 0u; - let t_id = local_def(enum_id); - let v_id = local_def(variant.node.id); - for va: ast::variant_arg in variant.node.args { - let rslt = GEP_enum(bcx, llblobptr, t_id, v_id, ty_param_substs, i); - bcx = rslt.bcx; - let lldestptr = rslt.val; - // If this argument to this function is a enum, it'll have come in to - // this function as an opaque blob due to the way that type_of() - // works. So we have to cast to the destination's view of the type. - let llarg = alt check fcx.llargs.find(va.id) { - some(local_mem(x)) { x } - }; - let arg_ty = arg_tys[i].ty; - if ty::type_has_params(arg_ty) { - lldestptr = PointerCast(bcx, lldestptr, val_ty(llarg)); - } - bcx = memmove_ty(bcx, lldestptr, llarg, arg_ty); - i += 1u; - } - build_return(bcx); - finish_fn(fcx, lltop); -} - - -// FIXME: this should do some structural hash-consing to avoid -// duplicate constants. I think. Maybe LLVM has a magical mode -// that does so later on? -fn trans_const_expr(cx: crate_ctxt, e: @ast::expr) -> ValueRef { - alt e.node { - ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); } - ast::expr_binary(b, e1, e2) { - let te1 = trans_const_expr(cx, e1); - let te2 = trans_const_expr(cx, e2); - - let te2 = cast_shift_const_rhs(b, te1, te2); - - /* Neither type is bottom, and we expect them to be unified already, - * so the following is safe. */ - let ty = ty::expr_ty(cx.tcx, e1); - let is_float = ty::type_is_fp(ty); - let signed = ty::type_is_signed(ty); - ret alt b { - ast::add { - if is_float { llvm::LLVMConstFAdd(te1, te2) } - else { llvm::LLVMConstAdd(te1, te2) } - } - ast::subtract { - if is_float { llvm::LLVMConstFSub(te1, te2) } - else { llvm::LLVMConstSub(te1, te2) } - } - ast::mul { - if is_float { llvm::LLVMConstFMul(te1, te2) } - else { llvm::LLVMConstMul(te1, te2) } - } - ast::div { - if is_float { llvm::LLVMConstFDiv(te1, te2) } - else if signed { llvm::LLVMConstSDiv(te1, te2) } - else { llvm::LLVMConstUDiv(te1, te2) } - } - ast::rem { - if is_float { llvm::LLVMConstFRem(te1, te2) } - else if signed { llvm::LLVMConstSRem(te1, te2) } - else { llvm::LLVMConstURem(te1, te2) } - } - ast::and | - ast::or { cx.sess.span_unimpl(e.span, "binop logic"); } - ast::bitxor { llvm::LLVMConstXor(te1, te2) } - ast::bitand { llvm::LLVMConstAnd(te1, te2) } - ast::bitor { llvm::LLVMConstOr(te1, te2) } - ast::lsl { llvm::LLVMConstShl(te1, te2) } - ast::lsr { llvm::LLVMConstLShr(te1, te2) } - ast::asr { llvm::LLVMConstAShr(te1, te2) } - ast::eq | - ast::lt | - ast::le | - ast::ne | - ast::ge | - ast::gt { cx.sess.span_unimpl(e.span, "binop comparator"); } - } - } - ast::expr_unary(u, e) { - let te = trans_const_expr(cx, e); - let ty = ty::expr_ty(cx.tcx, e); - let is_float = ty::type_is_fp(ty); - ret alt u { - ast::box(_) | - ast::uniq(_) | - ast::deref { cx.sess.span_bug(e.span, - "bad unop type in trans_const_expr"); } - ast::not { llvm::LLVMConstNot(te) } - ast::neg { - if is_float { llvm::LLVMConstFNeg(te) } - else { llvm::LLVMConstNeg(te) } - } - } - } - _ { cx.sess.span_bug(e.span, - "bad constant expression type in trans_const_expr"); } - } -} - -fn trans_const(cx: crate_ctxt, e: @ast::expr, id: ast::node_id) { - let v = trans_const_expr(cx, e); - - // The scalars come back as 1st class LLVM vals - // which we have to stick into global constants. - - alt cx.consts.find(id) { - some(g) { - llvm::LLVMSetInitializer(g, v); - llvm::LLVMSetGlobalConstant(g, True); - } - _ { cx.sess.span_fatal(e.span, "Unbound const in trans_const"); } - } -} - -fn trans_item(ccx: crate_ctxt, item: ast::item) { - let path = alt check ccx.tcx.items.get(item.id) { - ast_map::node_item(_, p) { p } - }; - alt item.node { - ast::item_fn(decl, tps, body) { - let llfndecl = alt ccx.item_ids.find(item.id) { - some(llfndecl) { llfndecl } - _ { - ccx.sess.span_fatal(item.span, - "unbound function item in trans_item"); - } - }; - if decl.purity != ast::crust_fn { - trans_fn(ccx, *path + [path_name(item.ident)], decl, body, - llfndecl, no_self, param_bounds(ccx, tps), - none, item.id); - } else { - native::trans_crust_fn(ccx, *path + [path_name(item.ident)], - decl, body, llfndecl, item.id); - } - } - ast::item_impl(tps, _, _, ms) { - impl::trans_impl(ccx, *path, item.ident, ms, item.id, tps); - } - ast::item_res(decl, tps, body, dtor_id, ctor_id) { - let llctor_decl = ccx.item_ids.get(ctor_id); - trans_res_ctor(ccx, *path, decl, ctor_id, - param_bounds(ccx, tps), none, llctor_decl); - - // Create a function for the destructor - alt ccx.item_ids.find(item.id) { - some(lldtor_decl) { - trans_fn(ccx, *path + [path_name(item.ident)], decl, body, - lldtor_decl, no_self, param_bounds(ccx, tps), - none, dtor_id); - } - _ { - ccx.sess.span_fatal(item.span, "unbound dtor in trans_item"); - } - } - } - ast::item_mod(m) { - trans_mod(ccx, m); - } - ast::item_enum(variants, tps) { - let degen = variants.len() == 1u; - let vi = ty::enum_variants(ccx.tcx, local_def(item.id)); - let i = 0; - for variant: ast::variant in variants { - if variant.node.args.len() > 0u { - trans_enum_variant(ccx, item.id, variant, - vi[i].disr_val, degen, tps, - none, ccx.item_ids.get(variant.node.id)); - } - i += 1; - } - } - ast::item_const(_, expr) { trans_const(ccx, expr, item.id); } - ast::item_native_mod(native_mod) { - let abi = alt attr::native_abi(item.attrs) { - either::right(abi_) { abi_ } - either::left(msg) { ccx.sess.span_fatal(item.span, msg) } - }; - native::trans_native_mod(ccx, native_mod, abi); - } - _ {/* fall through */ } - } -} - -// Translate a module. Doing this amounts to translating the items in the -// module; there ends up being no artifact (aside from linkage names) of -// separate modules in the compiled program. That's because modules exist -// only as a convenience for humans working with the code, to organize names -// and control visibility. -fn trans_mod(ccx: crate_ctxt, m: ast::_mod) { - for item in m.items { trans_item(ccx, *item); } -} - -fn compute_ii_method_info(ccx: crate_ctxt, - impl_did: ast::def_id, - m: @ast::method, - f: fn(ty::t, [ty::param_bounds], ast_map::path)) { - let {bounds: impl_bnds, ty: impl_ty} = - ty::lookup_item_type(ccx.tcx, impl_did); - let m_bounds = *impl_bnds + param_bounds(ccx, m.tps); - let impl_path = ty::item_path(ccx.tcx, impl_did); - let m_path = impl_path + [path_name(m.ident)]; - f(impl_ty, m_bounds, m_path); -} - -fn trans_inlined_items(ccx: crate_ctxt, inline_map: inline_map) { - inline_map.values {|ii| - alt ii { - ast::ii_item(item) { - trans_item(ccx, *item) - } - ast::ii_method(impl_did, m) { - compute_ii_method_info(ccx, impl_did, m) { - |impl_ty, m_bounds, m_path| - let llfndecl = ccx.item_ids.get(m.id); - trans_fn(ccx, m_path, m.decl, m.body, - llfndecl, impl_self(impl_ty), m_bounds, - none, m.id); - } - } - } - } -} - -fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef { - // Bit of a kludge: pick the fn typeref out of the pair. - ret struct_elt(llpairty, 0u); -} - -fn register_fn(ccx: crate_ctxt, sp: span, path: path, flav: str, - ty_params: [ast::ty_param], node_id: ast::node_id) { - let t = ty::node_id_to_type(ccx.tcx, node_id); - let bnds = param_bounds(ccx, ty_params); - register_fn_full(ccx, sp, path, flav, bnds, node_id, t); -} - -fn param_bounds(ccx: crate_ctxt, tps: [ast::ty_param]) -> [ty::param_bounds] { - vec::map(tps) {|tp| ccx.tcx.ty_param_bounds.get(tp.id) } -} - -fn register_fn_full(ccx: crate_ctxt, sp: span, path: path, flav: str, - bnds: [ty::param_bounds], node_id: ast::node_id, - node_type: ty::t) { - let llfty = type_of_fn_from_ty(ccx, node_type, bnds); - register_fn_fuller(ccx, sp, path, flav, node_id, node_type, - lib::llvm::CCallConv, llfty); -} - -fn register_fn_fuller(ccx: crate_ctxt, sp: span, path: path, _flav: str, - node_id: ast::node_id, node_type: ty::t, - cc: lib::llvm::CallConv, llfty: TypeRef) { - let ps: str = mangle_exported_name(ccx, path, node_type); - let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty); - ccx.item_ids.insert(node_id, llfn); - ccx.item_symbols.insert(node_id, ps); - - #debug["register_fn_fuller created fn %s for item %d with path %s", - val_str(ccx.tn, llfn), node_id, ast_map::path_to_str(path)]; - - let is_main = is_main_name(path) && !ccx.sess.building_library; - if is_main { create_main_wrapper(ccx, sp, llfn, node_type); } -} - -// Create a _rust_main(args: [str]) function which will be called from the -// runtime rust_start function -fn create_main_wrapper(ccx: crate_ctxt, sp: span, main_llfn: ValueRef, - main_node_type: ty::t) { - - if ccx.main_fn != none::<ValueRef> { - ccx.sess.span_fatal(sp, "multiple 'main' functions"); - } - - let main_takes_argv = - // invariant! - alt ty::get(main_node_type).struct { - ty::ty_fn({inputs, _}) { inputs.len() != 0u } - _ { ccx.sess.span_fatal(sp, "main has a non-function type"); } - }; - - let llfn = create_main(ccx, main_llfn, main_takes_argv); - ccx.main_fn = some(llfn); - create_entry_fn(ccx, llfn); - - fn create_main(ccx: crate_ctxt, main_llfn: ValueRef, - takes_argv: bool) -> ValueRef { - let unit_ty = ty::mk_str(ccx.tcx); - let vecarg_ty: ty::arg = - {mode: ast::expl(ast::by_val), - ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mutbl: ast::m_imm})}; - let nt = ty::mk_nil(ccx.tcx); - let llfty = type_of_fn(ccx, [vecarg_ty], nt, []); - let llfdecl = decl_fn(ccx.llmod, "_rust_main", - lib::llvm::CCallConv, llfty); - - let fcx = new_fn_ctxt(ccx, [], llfdecl, none); - - let bcx = top_scope_block(fcx, none); - let lltop = bcx.llbb; - - let lloutputarg = llvm::LLVMGetParam(llfdecl, 0 as c_uint); - let llenvarg = llvm::LLVMGetParam(llfdecl, 1 as c_uint); - let args = [lloutputarg, llenvarg]; - if takes_argv { args += [llvm::LLVMGetParam(llfdecl, 2 as c_uint)]; } - Call(bcx, main_llfn, args); - build_return(bcx); - - finish_fn(fcx, lltop); - - ret llfdecl; - } - - fn create_entry_fn(ccx: crate_ctxt, rust_main: ValueRef) { - #[cfg(target_os = "win32")] - fn main_name() -> str { ret "WinMain@16"; } - #[cfg(target_os = "macos")] - fn main_name() -> str { ret "main"; } - #[cfg(target_os = "linux")] - fn main_name() -> str { ret "main"; } - #[cfg(target_os = "freebsd")] - fn main_name() -> str { ret "main"; } - let llfty = T_fn([ccx.int_type, ccx.int_type], ccx.int_type); - let llfn = decl_cdecl_fn(ccx.llmod, main_name(), llfty); - let llbb = str::as_buf("top", {|buf| - llvm::LLVMAppendBasicBlock(llfn, buf) - }); - let bld = *ccx.builder; - llvm::LLVMPositionBuilderAtEnd(bld, llbb); - let crate_map = ccx.crate_map; - let start_ty = T_fn([val_ty(rust_main), ccx.int_type, ccx.int_type, - val_ty(crate_map)], ccx.int_type); - let start = str::as_buf("rust_start", {|buf| - llvm::LLVMAddGlobal(ccx.llmod, start_ty, buf) - }); - let args = [rust_main, llvm::LLVMGetParam(llfn, 0 as c_uint), - llvm::LLVMGetParam(llfn, 1 as c_uint), crate_map]; - let result = unsafe { - llvm::LLVMBuildCall(bld, start, vec::unsafe::to_ptr(args), - args.len() as c_uint, noname()) - }; - llvm::LLVMBuildRet(bld, result); - } -} - -// Create a /real/ closure: this is like create_fn_pair, but creates a -// a fn value on the stack with a specified environment (which need not be -// on the stack). -fn create_real_fn_pair(cx: block, llfnty: TypeRef, llfn: ValueRef, - llenvptr: ValueRef) -> ValueRef { - let pair = alloca(cx, T_fn_pair(cx.ccx(), llfnty)); - fill_fn_pair(cx, pair, llfn, llenvptr); - ret pair; -} - -fn fill_fn_pair(bcx: block, pair: ValueRef, llfn: ValueRef, - llenvptr: ValueRef) { - let ccx = bcx.ccx(); - let code_cell = GEPi(bcx, pair, [0, abi::fn_field_code]); - Store(bcx, llfn, code_cell); - let env_cell = GEPi(bcx, pair, [0, abi::fn_field_box]); - let llenvblobptr = PointerCast(bcx, llenvptr, T_opaque_box_ptr(ccx)); - Store(bcx, llenvblobptr, env_cell); -} - -fn collect_native_item(ccx: crate_ctxt, - abi: @mutable option<ast::native_abi>, - i: @ast::native_item) { - alt i.node { - ast::native_item_fn(_, tps) { - let id = i.id; - let node_type = ty::node_id_to_type(ccx.tcx, id); - let fn_abi = - alt attr::get_meta_item_value_str_by_name(i.attrs, "abi") { - option::none { - // if abi isn't specified for this function, inherit from - // its enclosing native module - option::get(*abi) - } - _ { - alt attr::native_abi(i.attrs) { - either::right(abi_) { abi_ } - either::left(msg) { ccx.sess.span_fatal(i.span, msg) } - } - } - }; - alt fn_abi { - ast::native_abi_rust_intrinsic { - // For intrinsics: link the function directly to the intrinsic - // function itself. - let fn_type = type_of_fn_from_ty( - ccx, node_type, param_bounds(ccx, tps)); - let ri_name = "rust_intrinsic_" + native::link_name(i); - let llnativefn = get_extern_fn( - ccx.externs, ccx.llmod, ri_name, - lib::llvm::CCallConv, fn_type); - ccx.item_ids.insert(id, llnativefn); - ccx.item_symbols.insert(id, ri_name); - } - - ast::native_abi_cdecl | ast::native_abi_stdcall { - // For true external functions: create a rust wrapper - // and link to that. The rust wrapper will handle - // switching to the C stack. - let path = *alt check ccx.tcx.items.get(i.id) { - ast_map::node_native_item(_, p) { p } - } + [path_name(i.ident)]; - register_fn(ccx, i.span, path, "native fn", tps, i.id); - } - } - } - _ { } - } -} - -fn item_path(ccx: crate_ctxt, i: @ast::item) -> path { - *alt check ccx.tcx.items.get(i.id) { - ast_map::node_item(_, p) { p } - } + [path_name(i.ident)] -} - -fn collect_item(ccx: crate_ctxt, abi: @mutable option<ast::native_abi>, - i: @ast::item) { - let my_path = item_path(ccx, i); - alt i.node { - ast::item_const(_, _) { - let typ = ty::node_id_to_type(ccx.tcx, i.id); - let s = mangle_exported_name(ccx, my_path, typ); - let g = str::as_buf(s, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, typ), buf) - }); - ccx.item_symbols.insert(i.id, s); - ccx.consts.insert(i.id, g); - } - ast::item_native_mod(native_mod) { - // Propagate the native ABI down to collect_native_item(), - alt attr::native_abi(i.attrs) { - either::left(msg) { ccx.sess.span_fatal(i.span, msg); } - either::right(abi_) { *abi = option::some(abi_); } - } - } - ast::item_fn(decl, tps, _) { - if decl.purity != ast::crust_fn { - register_fn(ccx, i.span, my_path, "fn", tps, - i.id); - } else { - native::register_crust_fn(ccx, i.span, my_path, i.id); - } - } - ast::item_impl(tps, _, _, methods) { - let path = my_path + [path_name(int::str(i.id))]; - for m in methods { - register_fn(ccx, i.span, - path + [path_name(m.ident)], - "impl_method", tps + m.tps, m.id); - } - } - ast::item_res(_, tps, _, dtor_id, ctor_id) { - register_fn(ccx, i.span, my_path, "res_ctor", tps, ctor_id); - // Note that the destructor is associated with the item's id, not - // the dtor_id. This is a bit counter-intuitive, but simplifies - // ty_res, which would have to carry around two def_ids otherwise - // -- one to identify the type, and one to find the dtor symbol. - let t = ty::node_id_to_type(ccx.tcx, dtor_id); - register_fn_full(ccx, i.span, my_path + [path_name("dtor")], - "res_dtor", param_bounds(ccx, tps), i.id, t); - } - ast::item_enum(variants, tps) { - for variant in variants { - if variant.node.args.len() != 0u { - register_fn(ccx, i.span, - my_path + [path_name(variant.node.name)], - "enum", tps, variant.node.id); - } - } - } - _ { } - } -} - -fn collect_items(ccx: crate_ctxt, crate: @ast::crate) { - let abi = @mutable none::<ast::native_abi>; - visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{ - visit_native_item: bind collect_native_item(ccx, abi, _), - visit_item: bind collect_item(ccx, abi, _) - with *visit::default_simple_visitor() - })); -} - -fn collect_inlined_items(ccx: crate_ctxt, inline_map: inline::inline_map) { - let abi = @mutable none::<ast::native_abi>; - inline_map.values {|ii| - alt ii { - ast::ii_item(item) { - collect_item(ccx, abi, item); - alt item.node { - ast::item_fn(_, _, _) { - set_always_inline(ccx.item_ids.get(item.id)); - } - _ { /* fallthrough */ } - } - } - - ast::ii_method(impl_did, m) { - compute_ii_method_info(ccx, impl_did, m) { - |_impl_ty, m_bounds, m_path| - let mthd_ty = ty::node_id_to_type(ccx.tcx, m.id); - register_fn_full(ccx, m.span, m_path, "impl_method", - m_bounds, m.id, mthd_ty); - } - } - } - } -} - -// The constant translation pass. -fn trans_constant(ccx: crate_ctxt, it: @ast::item) { - alt it.node { - ast::item_enum(variants, _) { - let vi = ty::enum_variants(ccx.tcx, {crate: ast::local_crate, - node: it.id}); - let i = 0, path = item_path(ccx, it); - for variant in variants { - let p = path + [path_name(variant.node.name), - path_name("discrim")]; - let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); - let disr_val = vi[i].disr_val; - let discrim_gvar = str::as_buf(s, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) - }); - llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val)); - llvm::LLVMSetGlobalConstant(discrim_gvar, True); - ccx.discrims.insert( - local_def(variant.node.id), discrim_gvar); - ccx.discrim_symbols.insert(variant.node.id, s); - i += 1; - } - } - ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) { - let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id)); - impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it); - } - ast::item_iface(_, _) { - if !vec::any(*ty::iface_methods(ccx.tcx, local_def(it.id)), {|m| - ty::type_has_vars(ty::mk_fn(ccx.tcx, m.fty))}) { - impl::trans_iface_vtable(ccx, item_path(ccx, it), it); - } - } - _ { } - } -} - -fn trans_constants(ccx: crate_ctxt, crate: @ast::crate) { - visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{ - visit_item: bind trans_constant(ccx, _) - with *visit::default_simple_visitor() - })); -} - -fn vp2i(cx: block, v: ValueRef) -> ValueRef { - let ccx = cx.ccx(); - ret PtrToInt(cx, v, ccx.int_type); -} - -fn p2i(ccx: crate_ctxt, v: ValueRef) -> ValueRef { - ret llvm::LLVMConstPtrToInt(v, ccx.int_type); -} - -fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> { - let T_memmove32_args: [TypeRef] = - [T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()]; - let T_memmove64_args: [TypeRef] = - [T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()]; - let T_memset32_args: [TypeRef] = - [T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()]; - let T_memset64_args: [TypeRef] = - [T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()]; - let T_trap_args: [TypeRef] = []; - let gcroot = - decl_cdecl_fn(llmod, "llvm.gcroot", - T_fn([T_ptr(T_ptr(T_i8())), T_ptr(T_i8())], T_void())); - let gcread = - decl_cdecl_fn(llmod, "llvm.gcread", - T_fn([T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))], T_void())); - let memmove32 = - decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i32", - T_fn(T_memmove32_args, T_void())); - let memmove64 = - decl_cdecl_fn(llmod, "llvm.memmove.p0i8.p0i8.i64", - T_fn(T_memmove64_args, T_void())); - let memset32 = - decl_cdecl_fn(llmod, "llvm.memset.p0i8.i32", - T_fn(T_memset32_args, T_void())); - let memset64 = - decl_cdecl_fn(llmod, "llvm.memset.p0i8.i64", - T_fn(T_memset64_args, T_void())); - let trap = decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void())); - let intrinsics = new_str_hash::<ValueRef>(); - intrinsics.insert("llvm.gcroot", gcroot); - intrinsics.insert("llvm.gcread", gcread); - intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32); - intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64); - intrinsics.insert("llvm.memset.p0i8.i32", memset32); - intrinsics.insert("llvm.memset.p0i8.i64", memset64); - intrinsics.insert("llvm.trap", trap); - ret intrinsics; -} - -fn declare_dbg_intrinsics(llmod: ModuleRef, - intrinsics: hashmap<str, ValueRef>) { - let declare = - decl_cdecl_fn(llmod, "llvm.dbg.declare", - T_fn([T_metadata(), T_metadata()], T_void())); - let value = - decl_cdecl_fn(llmod, "llvm.dbg.value", - T_fn([T_metadata(), T_i64(), T_metadata()], T_void())); - intrinsics.insert("llvm.dbg.declare", declare); - intrinsics.insert("llvm.dbg.value", value); -} - -fn trap(bcx: block) { - let v: [ValueRef] = []; - alt bcx.ccx().intrinsics.find("llvm.trap") { - some(x) { Call(bcx, x, v); } - _ { bcx.sess().bug("unbound llvm.trap in trap"); } - } -} - -fn create_module_map(ccx: crate_ctxt) -> ValueRef { - let elttype = T_struct([ccx.int_type, ccx.int_type]); - let maptype = T_array(elttype, ccx.module_data.size() + 1u); - let map = str::as_buf("_rust_mod_map", {|buf| - llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) - }); - lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage); - let elts: [ValueRef] = []; - ccx.module_data.items {|key, val| - let elt = C_struct([p2i(ccx, C_cstr(ccx, key)), - p2i(ccx, val)]); - elts += [elt]; - }; - let term = C_struct([C_int(ccx, 0), C_int(ccx, 0)]); - elts += [term]; - llvm::LLVMSetInitializer(map, C_array(elttype, elts)); - ret map; -} - - -fn decl_crate_map(sess: session::session, mapname: str, - llmod: ModuleRef) -> ValueRef { - let targ_cfg = sess.targ_cfg; - let int_type = T_int(targ_cfg); - let n_subcrates = 1; - let cstore = sess.cstore; - while cstore::have_crate_data(cstore, n_subcrates) { n_subcrates += 1; } - let mapname = if sess.building_library { mapname } else { "toplevel" }; - let sym_name = "_rust_crate_map_" + mapname; - let arrtype = T_array(int_type, n_subcrates as uint); - let maptype = T_struct([int_type, arrtype]); - let map = str::as_buf(sym_name, {|buf| - llvm::LLVMAddGlobal(llmod, maptype, buf) - }); - lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage); - ret map; -} - -// FIXME use hashed metadata instead of crate names once we have that -fn fill_crate_map(ccx: crate_ctxt, map: ValueRef) { - let subcrates: [ValueRef] = []; - let i = 1; - let cstore = ccx.sess.cstore; - while cstore::have_crate_data(cstore, i) { - let nm = "_rust_crate_map_" + cstore::get_crate_data(cstore, i).name; - let cr = str::as_buf(nm, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) - }); - subcrates += [p2i(ccx, cr)]; - i += 1; - } - subcrates += [C_int(ccx, 0)]; - llvm::LLVMSetInitializer(map, C_struct( - [p2i(ccx, create_module_map(ccx)), - C_array(ccx.int_type, subcrates)])); -} - -fn write_metadata(cx: crate_ctxt, crate: @ast::crate) { - if !cx.sess.building_library { ret; } - let llmeta = C_bytes(metadata::encoder::encode_metadata(cx, crate)); - let llconst = C_struct([llmeta]); - let llglobal = str::as_buf("rust_metadata", {|buf| - llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst), buf) - }); - llvm::LLVMSetInitializer(llglobal, llconst); - str::as_buf(cx.sess.targ_cfg.target_strs.meta_sect_name, {|buf| - llvm::LLVMSetSection(llglobal, buf) - }); - lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); - - let t_ptr_i8 = T_ptr(T_i8()); - llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8); - let llvm_used = str::as_buf("llvm.used", {|buf| - llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u), buf) - }); - lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage); - llvm::LLVMSetInitializer(llvm_used, C_array(t_ptr_i8, [llglobal])); -} - -// Writes the current ABI version into the crate. -fn write_abi_version(ccx: crate_ctxt) { - mk_global(ccx, "rust_abi_version", C_uint(ccx, abi::abi_version), - false); -} - -fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, - output: str, emap: resolve::exp_map, maps: maps, - inline_map: inline::inline_map) - -> (ModuleRef, link::link_meta) { - let sha = std::sha1::mk_sha1(); - let link_meta = link::build_link_meta(sess, *crate, output, sha); - - // Append ".rc" to crate name as LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // crashes if the module identifer is same as other symbols - // such as a function name in the module. - // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = link_meta.name + ".rc"; - - let llmod = str::as_buf(llmod_id, {|buf| - llvm::LLVMModuleCreateWithNameInContext - (buf, llvm::LLVMGetGlobalContext()) - }); - let data_layout = sess.targ_cfg.target_strs.data_layout; - let targ_triple = sess.targ_cfg.target_strs.target_triple; - let _: () = - str::as_buf(data_layout, - {|buf| llvm::LLVMSetDataLayout(llmod, buf) }); - let _: () = - str::as_buf(targ_triple, - {|buf| llvm::LLVMSetTarget(llmod, buf) }); - let targ_cfg = sess.targ_cfg; - let td = mk_target_data(sess.targ_cfg.target_strs.data_layout); - let tn = mk_type_names(); - let intrinsics = declare_intrinsics(llmod); - if sess.opts.extra_debuginfo { - declare_dbg_intrinsics(llmod, intrinsics); - } - let int_type = T_int(targ_cfg); - let float_type = T_float(targ_cfg); - let task_type = T_task(targ_cfg); - let taskptr_type = T_ptr(task_type); - lib::llvm::associate_type(tn, "taskptr", taskptr_type); - let tydesc_type = T_tydesc(targ_cfg); - lib::llvm::associate_type(tn, "tydesc", tydesc_type); - let crate_map = decl_crate_map(sess, link_meta.name, llmod); - let dbg_cx = if sess.opts.debuginfo { - option::some(@{llmetadata: map::new_int_hash(), - names: new_namegen()}) - } else { - option::none - }; - - let ccx = - @{sess: sess, - llmod: llmod, - td: td, - tn: tn, - externs: new_str_hash::<ValueRef>(), - intrinsics: intrinsics, - item_ids: new_int_hash::<ValueRef>(), - exp_map: emap, - item_symbols: new_int_hash::<str>(), - mutable main_fn: none::<ValueRef>, - link_meta: link_meta, - enum_sizes: ty::new_ty_hash(), - discrims: ast_util::new_def_id_hash::<ValueRef>(), - discrim_symbols: new_int_hash::<str>(), - consts: new_int_hash::<ValueRef>(), - tydescs: ty::new_ty_hash(), - dicts: map::mk_hashmap(hash_dict_id, {|a, b| a == b}), - monomorphized: map::mk_hashmap(hash_mono_id, {|a, b| a == b}), - module_data: new_str_hash::<ValueRef>(), - lltypes: ty::new_ty_hash(), - names: new_namegen(), - sha: sha, - type_sha1s: ty::new_ty_hash(), - type_short_names: ty::new_ty_hash(), - tcx: tcx, - maps: maps, - inline_map: inline_map, - stats: - {mutable n_static_tydescs: 0u, - mutable n_derived_tydescs: 0u, - mutable n_glues_created: 0u, - mutable n_null_glues: 0u, - mutable n_real_glues: 0u, - fn_times: @mutable []}, - upcalls: - upcall::declare_upcalls(targ_cfg, tn, tydesc_type, - llmod), - tydesc_type: tydesc_type, - int_type: int_type, - float_type: float_type, - task_type: task_type, - opaque_vec_type: T_opaque_vec(targ_cfg), - builder: BuilderRef_res(llvm::LLVMCreateBuilder()), - shape_cx: mk_ctxt(llmod), - crate_map: crate_map, - dbg_cx: dbg_cx, - mutable do_not_commit_warning_issued: false}; - collect_items(ccx, crate); - collect_inlined_items(ccx, inline_map); - trans_constants(ccx, crate); - trans_mod(ccx, crate.node.module); - trans_inlined_items(ccx, inline_map); - fill_crate_map(ccx, crate_map); - emit_tydescs(ccx); - gen_shape_tables(ccx); - write_abi_version(ccx); - - // Translate the metadata. - write_metadata(ccx, crate); - if ccx.sess.opts.stats { - #error("--- trans stats ---"); - #error("n_static_tydescs: %u", ccx.stats.n_static_tydescs); - #error("n_derived_tydescs: %u", ccx.stats.n_derived_tydescs); - #error("n_glues_created: %u", ccx.stats.n_glues_created); - #error("n_null_glues: %u", ccx.stats.n_null_glues); - #error("n_real_glues: %u", ccx.stats.n_real_glues); - - for timing: {ident: str, time: int} in *ccx.stats.fn_times { - #error("time: %s took %d ms", timing.ident, timing.time); - } - } - ret (llmod, link_meta); -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/trans/build.rs b/src/comp/middle/trans/build.rs deleted file mode 100644 index e449aae2382..00000000000 --- a/src/comp/middle/trans/build.rs +++ /dev/null @@ -1,676 +0,0 @@ -import ctypes::{c_uint, c_int}; -import str::sbuf; -import lib::llvm::llvm; -import syntax::codemap; -import codemap::span; -import lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef}; -import lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False, - CallConv}; -import common::*; - -fn B(cx: block) -> BuilderRef { - let b = *cx.fcx.ccx.builder; - llvm::LLVMPositionBuilderAtEnd(b, cx.llbb); - ret b; -} - -// The difference between a block being unreachable and being terminated is -// somewhat obscure, and has to do with error checking. When a block is -// terminated, we're saying that trying to add any further statements in the -// block is an error. On the other hand, if something is unreachable, that -// means that the block was terminated in some way that we don't want to check -// for (fail/break/ret statements, call to diverging functions, etc), and -// further instructions to the block should simply be ignored. - -fn RetVoid(cx: block) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - llvm::LLVMBuildRetVoid(B(cx)); -} - -fn Ret(cx: block, V: ValueRef) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - llvm::LLVMBuildRet(B(cx), V); -} - -fn AggregateRet(cx: block, RetVals: [ValueRef]) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - unsafe { - llvm::LLVMBuildAggregateRet(B(cx), vec::unsafe::to_ptr(RetVals), - RetVals.len() as c_uint); - } -} - -fn Br(cx: block, Dest: BasicBlockRef) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - llvm::LLVMBuildBr(B(cx), Dest); -} - -fn CondBr(cx: block, If: ValueRef, Then: BasicBlockRef, - Else: BasicBlockRef) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - llvm::LLVMBuildCondBr(B(cx), If, Then, Else); -} - -fn Switch(cx: block, V: ValueRef, Else: BasicBlockRef, NumCases: uint) - -> ValueRef { - if cx.unreachable { ret _Undef(V); } - assert !cx.terminated; - cx.terminated = true; - ret llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases as c_uint); -} - -fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) { - if llvm::LLVMIsUndef(S) == lib::llvm::True { ret; } - llvm::LLVMAddCase(S, OnVal, Dest); -} - -fn IndirectBr(cx: block, Addr: ValueRef, NumDests: uint) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests as c_uint); -} - -// This is a really awful way to get a zero-length c-string, but better (and a -// lot more efficient) than doing str::as_buf("", ...) every time. -fn noname() -> sbuf unsafe { - const cnull: uint = 0u; - ret unsafe::reinterpret_cast(ptr::addr_of(cnull)); -} - -fn Invoke(cx: block, Fn: ValueRef, Args: [ValueRef], - Then: BasicBlockRef, Catch: BasicBlockRef) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - #debug["Invoke(%s with arguments (%s))", - val_str(cx.ccx().tn, Fn), - str::connect(vec::map(Args, {|a|val_str(cx.ccx().tn, a)}), - ", ")]; - unsafe { - llvm::LLVMBuildInvoke(B(cx), Fn, vec::unsafe::to_ptr(Args), - Args.len() as c_uint, Then, Catch, - noname()); - } -} - -fn FastInvoke(cx: block, Fn: ValueRef, Args: [ValueRef], - Then: BasicBlockRef, Catch: BasicBlockRef) { - if cx.unreachable { ret; } - assert (!cx.terminated); - cx.terminated = true; - unsafe { - let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::unsafe::to_ptr(Args), - Args.len() as c_uint, - Then, Catch, noname()); - lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv); - } -} - -fn Unreachable(cx: block) { - if cx.unreachable { ret; } - cx.unreachable = true; - if !cx.terminated { llvm::LLVMBuildUnreachable(B(cx)); } -} - -fn _Undef(val: ValueRef) -> ValueRef { - ret llvm::LLVMGetUndef(val_ty(val)); -} - -/* Arithmetic */ -fn Add(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname()); -} - -fn NSWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname()); -} - -fn NUWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname()); -} - -fn FAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname()); -} - -fn Sub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildSub(B(cx), LHS, RHS, noname()); -} - -fn NSWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname()); -} - -fn NUWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname()); -} - -fn FSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname()); -} - -fn Mul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildMul(B(cx), LHS, RHS, noname()); -} - -fn NSWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname()); -} - -fn NUWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname()); -} - -fn FMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname()); -} - -fn UDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname()); -} - -fn SDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname()); -} - -fn ExactSDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname()); -} - -fn FDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname()); -} - -fn URem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildURem(B(cx), LHS, RHS, noname()); -} - -fn SRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname()); -} - -fn FRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname()); -} - -fn Shl(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildShl(B(cx), LHS, RHS, noname()); -} - -fn LShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname()); -} - -fn AShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname()); -} - -fn And(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname()); -} - -fn Or(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildOr(B(cx), LHS, RHS, noname()); -} - -fn Xor(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildXor(B(cx), LHS, RHS, noname()); -} - -fn BinOp(cx: block, Op: Opcode, LHS: ValueRef, RHS: ValueRef) -> - ValueRef { - if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname()); -} - -fn Neg(cx: block, V: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNeg(B(cx), V, noname()); -} - -fn NSWNeg(cx: block, V: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNSWNeg(B(cx), V, noname()); -} - -fn NUWNeg(cx: block, V: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNUWNeg(B(cx), V, noname()); -} -fn FNeg(cx: block, V: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildFNeg(B(cx), V, noname()); -} - -fn Not(cx: block, V: ValueRef) -> ValueRef { - if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNot(B(cx), V, noname()); -} - -/* Memory */ -fn Malloc(cx: block, Ty: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildMalloc(B(cx), Ty, noname()); -} - -fn ArrayMalloc(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildArrayMalloc(B(cx), Ty, Val, noname()); -} - -fn Alloca(cx: block, Ty: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } - ret llvm::LLVMBuildAlloca(B(cx), Ty, noname()); -} - -fn ArrayAlloca(cx: block, Ty: TypeRef, Val: ValueRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } - ret llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname()); -} - -fn Free(cx: block, PointerVal: ValueRef) { - if cx.unreachable { ret; } - llvm::LLVMBuildFree(B(cx), PointerVal); -} - -fn Load(cx: block, PointerVal: ValueRef) -> ValueRef { - let ccx = cx.fcx.ccx; - if cx.unreachable { - let ty = val_ty(PointerVal); - let eltty = if llvm::LLVMGetTypeKind(ty) == 11 as c_int { - llvm::LLVMGetElementType(ty) } else { ccx.int_type }; - ret llvm::LLVMGetUndef(eltty); - } - ret llvm::LLVMBuildLoad(B(cx), PointerVal, noname()); -} - -fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) { - if cx.unreachable { ret; } - #debug["Store %s -> %s", - val_str(cx.ccx().tn, Val), - val_str(cx.ccx().tn, Ptr)]; - llvm::LLVMBuildStore(B(cx), Val, Ptr); -} - -fn GEP(cx: block, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - unsafe { - ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::unsafe::to_ptr(Indices), - Indices.len() as c_uint, noname()); - } -} - -// Simple wrapper around GEP that takes an array of ints and wraps them -// in C_i32() -fn GEPi(cx: block, base: ValueRef, ixs: [int]) -> ValueRef { - let v: [ValueRef] = []; - for i: int in ixs { v += [C_i32(i as i32)]; } - ret InBoundsGEP(cx, base, v); -} - -fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: [ValueRef]) -> - ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - unsafe { - ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, - vec::unsafe::to_ptr(Indices), - Indices.len() as c_uint, - noname()); - } -} - -fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - ret llvm::LLVMBuildStructGEP(B(cx), Pointer, Idx as c_uint, noname()); -} - -fn GlobalString(cx: block, _Str: sbuf) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildGlobalString(B(cx), _Str, noname()); -} - -fn GlobalStringPtr(cx: block, _Str: sbuf) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname()); -} - -/* Casts */ -fn Trunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname()); -} - -fn ZExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname()); -} - -fn SExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname()); -} - -fn FPToUI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname()); -} - -fn FPToSI(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname()); -} - -fn UIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname()); -} - -fn SIToFP(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname()); -} - -fn FPTrunc(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname()); -} - -fn FPExt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname()); -} - -fn PtrToInt(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname()); -} - -fn IntToPtr(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname()); -} - -fn BitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname()); -} - -fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> - ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname()); -} - -fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> - ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname()); -} - -fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> - ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname()); -} - -fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: TypeRef, - _Name: sbuf) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname()); -} - -fn PointerCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname()); -} - -fn IntCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname()); -} - -fn FPCast(cx: block, Val: ValueRef, DestTy: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname()); -} - - -/* Comparisons */ -fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef) - -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname()); -} - -fn FCmp(cx: block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef) - -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname()); -} - -/* Miscellaneous instructions */ -fn EmptyPhi(cx: block, Ty: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } - ret llvm::LLVMBuildPhi(B(cx), Ty, noname()); -} - -fn Phi(cx: block, Ty: TypeRef, vals: [ValueRef], bbs: [BasicBlockRef]) - -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } - assert vals.len() == bbs.len(); - let phi = EmptyPhi(cx, Ty); - unsafe { - llvm::LLVMAddIncoming(phi, vec::unsafe::to_ptr(vals), - vec::unsafe::to_ptr(bbs), - vals.len() as c_uint); - ret phi; - } -} - -fn AddIncomingToPhi(phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { - if llvm::LLVMIsUndef(phi) == lib::llvm::True { ret; } - unsafe { - let valptr = unsafe::reinterpret_cast(ptr::addr_of(val)); - let bbptr = unsafe::reinterpret_cast(ptr::addr_of(bb)); - llvm::LLVMAddIncoming(phi, valptr, bbptr, 1 as c_uint); - } -} - -fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef { - let ccx = cx.fcx.ccx; - let ty = val_ty(Fn); - let retty = if llvm::LLVMGetTypeKind(ty) == 8 as c_int { - llvm::LLVMGetReturnType(ty) } else { ccx.int_type }; - ret llvm::LLVMGetUndef(retty); -} - -fn add_span_comment(bcx: block, sp: span, text: str) { - let ccx = bcx.ccx(); - if (!ccx.sess.opts.no_asm_comments) { - let s = text + " (" + codemap::span_to_str(sp, ccx.sess.codemap) - + ")"; - log(debug, s); - add_comment(bcx, s); - } -} - -fn add_comment(bcx: block, text: str) { - let ccx = bcx.ccx(); - if (!ccx.sess.opts.no_asm_comments) { - let sanitized = str::replace(text, "$", ""); - let comment_text = "; " + sanitized; - let asm = str::as_buf(comment_text, {|c| - str::as_buf("", {|e| - llvm::LLVMConstInlineAsm(T_fn([], T_void()), c, e, - False, False) - }) - }); - Call(bcx, asm, []); - } -} - -fn Call(cx: block, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { - if cx.unreachable { ret _UndefReturn(cx, Fn); } - unsafe { - ret llvm::LLVMBuildCall(B(cx), Fn, vec::unsafe::to_ptr(Args), - Args.len() as c_uint, noname()); - } -} - -fn FastCall(cx: block, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { - if cx.unreachable { ret _UndefReturn(cx, Fn); } - unsafe { - let v = llvm::LLVMBuildCall(B(cx), Fn, vec::unsafe::to_ptr(Args), - Args.len() as c_uint, noname()); - lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv); - ret v; - } -} - -fn CallWithConv(cx: block, Fn: ValueRef, Args: [ValueRef], - Conv: CallConv) -> ValueRef { - if cx.unreachable { ret _UndefReturn(cx, Fn); } - unsafe { - let v = llvm::LLVMBuildCall(B(cx), Fn, vec::unsafe::to_ptr(Args), - Args.len() as c_uint, noname()); - lib::llvm::SetInstructionCallConv(v, Conv); - ret v; - } -} - -fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) -> - ValueRef { - if cx.unreachable { ret _Undef(Then); } - ret llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname()); -} - -fn VAArg(cx: block, list: ValueRef, Ty: TypeRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } - ret llvm::LLVMBuildVAArg(B(cx), list, Ty, noname()); -} - -fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) -> - ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } - ret llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname()); -} - -fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef, - Index: ValueRef) { - if cx.unreachable { ret; } - llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname()); -} - -fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef, - Mask: ValueRef) { - if cx.unreachable { ret; } - llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()); -} - -fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } - ret llvm::LLVMBuildExtractValue(B(cx), AggVal, Index as c_uint, noname()); -} - -fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef, - Index: uint) { - if cx.unreachable { ret; } - llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index as c_uint, - noname()); -} - -fn IsNull(cx: block, Val: ValueRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildIsNull(B(cx), Val, noname()); -} - -fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef { - if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildIsNotNull(B(cx), Val, noname()); -} - -fn PtrDiff(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef { - let ccx = cx.fcx.ccx; - if cx.unreachable { ret llvm::LLVMGetUndef(ccx.int_type); } - ret llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname()); -} - -fn Trap(cx: block) { - if cx.unreachable { ret; } - let b = B(cx); - let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(b); - let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB); - let M: ModuleRef = llvm::LLVMGetGlobalParent(FN); - let T: ValueRef = str::as_buf("llvm.trap", {|buf| - llvm::LLVMGetNamedFunction(M, buf) - }); - assert (T as int != 0); - let Args: [ValueRef] = []; - unsafe { - llvm::LLVMBuildCall(b, T, vec::unsafe::to_ptr(Args), - Args.len() as c_uint, noname()); - } -} - -fn LandingPad(cx: block, Ty: TypeRef, PersFn: ValueRef, - NumClauses: uint) -> ValueRef { - assert !cx.terminated && !cx.unreachable; - ret llvm::LLVMBuildLandingPad(B(cx), Ty, PersFn, - NumClauses as c_uint, noname()); -} - -fn SetCleanup(_cx: block, LandingPad: ValueRef) { - llvm::LLVMSetCleanup(LandingPad, lib::llvm::True); -} - -fn Resume(cx: block, Exn: ValueRef) -> ValueRef { - assert (!cx.terminated); - cx.terminated = true; - ret llvm::LLVMBuildResume(B(cx), Exn); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/trans/closure.rs b/src/comp/middle/trans/closure.rs deleted file mode 100644 index 4cd9eef01e3..00000000000 --- a/src/comp/middle/trans/closure.rs +++ /dev/null @@ -1,925 +0,0 @@ -import core::ctypes::c_uint; -import syntax::ast; -import syntax::ast_util; -import lib::llvm::llvm; -import lib::llvm::{ValueRef, TypeRef}; -import common::*; -import build::*; -import base::*; -import type_of::*; -import type_of::type_of; // Issue #1873 -import back::abi; -import syntax::codemap::span; -import syntax::print::pprust::expr_to_str; -import back::link::{ - mangle_internal_name_by_path, - mangle_internal_name_by_path_and_seq}; -import util::ppaux::ty_to_str; -import shape::{size_of}; -import ast_map::{path, path_mod, path_name}; -import driver::session::session; - -// ___Good to know (tm)__________________________________________________ -// -// The layout of a closure environment in memory is -// roughly as follows: -// -// struct rust_opaque_box { // see rust_internal.h -// unsigned ref_count; // only used for fn@() -// type_desc *tydesc; // describes closure_data struct -// rust_opaque_box *prev; // (used internally by memory alloc) -// rust_opaque_box *next; // (used internally by memory alloc) -// struct closure_data { -// type_desc *bound_tdescs[]; // bound descriptors -// struct { -// upvar1_t upvar1; -// ... -// upvarN_t upvarN; -// } bound_data; -// } -// }; -// -// Note that the closure is itself a rust_opaque_box. This is true -// even for fn~ and fn&, because we wish to keep binary compatibility -// between all kinds of closures. The allocation strategy for this -// closure depends on the closure type. For a sendfn, the closure -// (and the referenced type descriptors) will be allocated in the -// exchange heap. For a fn, the closure is allocated in the task heap -// and is reference counted. For a block, the closure is allocated on -// the stack. -// -// ## Opaque closures and the embedded type descriptor ## -// -// One interesting part of closures is that they encapsulate the data -// that they close over. So when I have a ptr to a closure, I do not -// know how many type descriptors it contains nor what upvars are -// captured within. That means I do not know precisely how big it is -// nor where its fields are located. This is called an "opaque -// closure". -// -// Typically an opaque closure suffices because we only manipulate it -// by ptr. The routine common::T_opaque_box_ptr() returns an -// appropriate type for such an opaque closure; it allows access to -// the box fields, but not the closure_data itself. -// -// But sometimes, such as when cloning or freeing a closure, we need -// to know the full information. That is where the type descriptor -// that defines the closure comes in handy. We can use its take and -// drop glue functions to allocate/free data as needed. -// -// ## Subtleties concerning alignment ## -// -// It is important that we be able to locate the closure data *without -// knowing the kind of data that is being bound*. This can be tricky -// because the alignment requirements of the bound data affects the -// alignment requires of the closure_data struct as a whole. However, -// right now this is a non-issue in any case, because the size of the -// rust_opaque_box header is always a mutiple of 16-bytes, which is -// the maximum alignment requirement we ever have to worry about. -// -// The only reason alignment matters is that, in order to learn what data -// is bound, we would normally first load the type descriptors: but their -// location is ultimately depend on their content! There is, however, a -// workaround. We can load the tydesc from the rust_opaque_box, which -// describes the closure_data struct and has self-contained derived type -// descriptors, and read the alignment from there. It's just annoying to -// do. Hopefully should this ever become an issue we'll have monomorphized -// and type descriptors will all be a bad dream. -// -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -enum environment_value { - // Evaluate expr and store result in env (used for bind). - env_expr(@ast::expr, ty::t), - - // Copy the value from this llvm ValueRef into the environment. - env_copy(ValueRef, ty::t, lval_kind), - - // Move the value from this llvm ValueRef into the environment. - env_move(ValueRef, ty::t, lval_kind), - - // Access by reference (used for blocks). - env_ref(ValueRef, ty::t, lval_kind), -} - -fn ev_to_str(ccx: crate_ctxt, ev: environment_value) -> str { - alt ev { - env_expr(ex, _) { expr_to_str(ex) } - env_copy(v, t, lk) { #fmt("copy(%s,%s)", val_str(ccx.tn, v), - ty_to_str(ccx.tcx, t)) } - env_move(v, t, lk) { #fmt("move(%s,%s)", val_str(ccx.tn, v), - ty_to_str(ccx.tcx, t)) } - env_ref(v, t, lk) { #fmt("ref(%s,%s)", val_str(ccx.tn, v), - ty_to_str(ccx.tcx, t)) } - } -} - -fn mk_tydesc_ty(tcx: ty::ctxt, ck: ty::closure_kind) -> ty::t { - ret alt ck { - ty::ck_block | ty::ck_box { ty::mk_type(tcx) } - ty::ck_uniq { ty::mk_send_type(tcx) } - }; -} - -fn mk_tuplified_uniq_cbox_ty(tcx: ty::ctxt, cdata_ty: ty::t) -> ty::t { - let tydesc_ty = mk_tydesc_ty(tcx, ty::ck_uniq); - let cbox_ty = tuplify_cbox_ty(tcx, cdata_ty, tydesc_ty); - ret ty::mk_imm_uniq(tcx, cbox_ty); -} - -// Given a closure ty, emits a corresponding tuple ty -fn mk_closure_tys(tcx: ty::ctxt, - ck: ty::closure_kind, - ty_params: [fn_ty_param], - bound_values: [environment_value]) - -> (ty::t, [ty::t]) { - let bound_tys = []; - - let tydesc_ty = mk_tydesc_ty(tcx, ck); - - // Compute the closed over tydescs - let param_ptrs = []; - for tp in ty_params { - param_ptrs += [tydesc_ty]; - option::may(tp.dicts) {|dicts| - for dict in dicts { param_ptrs += [tydesc_ty]; } - } - } - - // Compute the closed over data - for bv in bound_values { - bound_tys += [alt bv { - env_copy(_, t, _) { t } - env_move(_, t, _) { t } - env_ref(_, t, _) { t } - env_expr(_, t) { t } - }]; - } - let bound_data_ty = ty::mk_tup(tcx, bound_tys); - - let cdata_ty = ty::mk_tup(tcx, [ty::mk_tup(tcx, param_ptrs), - bound_data_ty]); - #debug["cdata_ty=%s", ty_to_str(tcx, cdata_ty)]; - ret (cdata_ty, bound_tys); -} - -fn allocate_cbox(bcx: block, - ck: ty::closure_kind, - cdata_ty: ty::t) - -> (block, ValueRef, [ValueRef]) { - - let ccx = bcx.ccx(), tcx = ccx.tcx; - - fn nuke_ref_count(bcx: block, box: ValueRef) { - // Initialize ref count to arbitrary value for debugging: - let ccx = bcx.ccx(); - let box = PointerCast(bcx, box, T_opaque_box_ptr(ccx)); - let ref_cnt = GEPi(bcx, box, [0, abi::box_field_refcnt]); - let rc = C_int(ccx, 0x12345678); - Store(bcx, rc, ref_cnt); - } - - fn store_uniq_tydesc(bcx: block, - cdata_ty: ty::t, - box: ValueRef, - &ti: option::t<@tydesc_info>) -> block { - let ccx = bcx.ccx(); - let bound_tydesc = GEPi(bcx, box, [0, abi::box_field_tydesc]); - let {bcx, val: td} = base::get_tydesc(bcx, cdata_ty, true, ti); - let td = Call(bcx, ccx.upcalls.create_shared_type_desc, [td]); - Store(bcx, td, bound_tydesc); - bcx - } - - // Allocate and initialize the box: - let ti = none; - let temp_cleanups = []; - let (bcx, box) = alt ck { - ty::ck_box { - let {bcx, val: box} = trans_malloc_boxed_raw(bcx, cdata_ty, ti); - (bcx, box) - } - ty::ck_uniq { - let uniq_cbox_ty = mk_tuplified_uniq_cbox_ty(tcx, cdata_ty); - let {bcx, val: box} = uniq::alloc_uniq(bcx, uniq_cbox_ty); - nuke_ref_count(bcx, box); - let bcx = store_uniq_tydesc(bcx, cdata_ty, box, ti); - (bcx, box) - } - ty::ck_block { - let cbox_ty = tuplify_box_ty(tcx, cdata_ty); - let {bcx, val: box} = base::alloc_ty(bcx, cbox_ty); - nuke_ref_count(bcx, box); - (bcx, box) - } - }; - - base::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, ti); - base::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, ti); - base::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_free_glue, ti); - - ret (bcx, box, temp_cleanups); -} - -type closure_result = { - llbox: ValueRef, // llvalue of ptr to closure - cdata_ty: ty::t, // type of the closure data - bcx: block // final bcx -}; - -fn cast_if_we_can(bcx: block, llbox: ValueRef, t: ty::t) -> ValueRef { - let ccx = bcx.ccx(); - if check type_has_static_size(ccx, t) { - let llty = type_of(ccx, t); - ret PointerCast(bcx, llbox, llty); - } else { - ret llbox; - } -} - -// Given a block context and a list of tydescs and values to bind -// construct a closure out of them. If copying is true, it is a -// heap allocated closure that copies the upvars into environment. -// Otherwise, it is stack allocated and copies pointers to the upvars. -fn store_environment( - bcx: block, lltyparams: [fn_ty_param], - bound_values: [environment_value], - ck: ty::closure_kind) - -> closure_result { - - fn maybe_clone_tydesc(bcx: block, - ck: ty::closure_kind, - td: ValueRef) -> ValueRef { - ret alt ck { - ty::ck_block | ty::ck_box { - td - } - ty::ck_uniq { - Call(bcx, bcx.ccx().upcalls.create_shared_type_desc, [td]) - } - }; - } - - let ccx = bcx.ccx(), tcx = ccx.tcx; - - // compute the shape of the closure - let (cdata_ty, bound_tys) = - mk_closure_tys(tcx, ck, lltyparams, bound_values); - - // allocate closure in the heap - let (bcx, llbox, temp_cleanups) = - allocate_cbox(bcx, ck, cdata_ty); - - // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a - // tuple. This could be a ptr in uniq or a box or on stack, - // whatever. - let cbox_ty = tuplify_box_ty(tcx, cdata_ty); - let cboxptr_ty = ty::mk_ptr(tcx, {ty:cbox_ty, mutbl:ast::m_imm}); - let llbox = cast_if_we_can(bcx, llbox, cboxptr_ty); - #debug["tuplify_box_ty = %s", ty_to_str(tcx, cbox_ty)]; - - // If necessary, copy tydescs describing type parameters into the - // appropriate slot in the closure. - let {bcx:bcx, val:ty_params_slot} = - GEP_tup_like(bcx, cbox_ty, llbox, - [0, abi::box_field_body, abi::closure_body_ty_params]); - let off = 0; - for tp in lltyparams { - let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc); - Store(bcx, cloned_td, GEPi(bcx, ty_params_slot, [0, off])); - off += 1; - option::may(tp.dicts, {|dicts| - for dict in dicts { - let cast = PointerCast(bcx, dict, val_ty(cloned_td)); - Store(bcx, cast, GEPi(bcx, ty_params_slot, [0, off])); - off += 1; - } - }); - } - - // Copy expr values into boxed bindings. - vec::iteri(bound_values) { |i, bv| - #debug["Copy %s into closure", ev_to_str(ccx, bv)]; - - if (!ccx.sess.opts.no_asm_comments) { - add_comment(bcx, #fmt("Copy %s into closure", - ev_to_str(ccx, bv))); - } - - let bound_data = GEP_tup_like(bcx, cbox_ty, llbox, - [0, abi::box_field_body, - abi::closure_body_bindings, i as int]); - bcx = bound_data.bcx; - let bound_data = bound_data.val; - alt bv { - env_expr(e, _) { - bcx = base::trans_expr_save_in(bcx, e, bound_data); - add_clean_temp_mem(bcx, bound_data, bound_tys[i]); - temp_cleanups += [bound_data]; - } - env_copy(val, ty, owned) { - let val1 = load_if_immediate(bcx, val, ty); - bcx = base::copy_val(bcx, INIT, bound_data, val1, ty); - } - env_copy(val, ty, owned_imm) { - bcx = base::copy_val(bcx, INIT, bound_data, val, ty); - } - env_copy(_, _, temporary) { - fail "Cannot capture temporary upvar"; - } - env_move(val, ty, kind) { - let src = {bcx:bcx, val:val, kind:kind}; - bcx = move_val(bcx, INIT, bound_data, src, ty); - } - env_ref(val, ty, owned) { - Store(bcx, val, bound_data); - } - env_ref(val, ty, owned_imm) { - let addr = do_spill_noroot(bcx, val); - Store(bcx, addr, bound_data); - } - env_ref(_, _, temporary) { - fail "Cannot capture temporary upvar"; - } - } - } - for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); } - - ret {llbox: llbox, cdata_ty: cdata_ty, bcx: bcx}; -} - -// Given a context and a list of upvars, build a closure. This just -// collects the upvars and packages them up for store_environment. -fn build_closure(bcx0: block, - cap_vars: [capture::capture_var], - ck: ty::closure_kind, - id: ast::node_id) -> closure_result { - // If we need to, package up the iterator body to call - let env_vals = []; - let bcx = bcx0, ccx = bcx.ccx(), tcx = ccx.tcx; - - // Package up the captured upvars - vec::iter(cap_vars) { |cap_var| - #debug["Building closure: captured variable %?", cap_var]; - let lv = trans_local_var(bcx, cap_var.def); - let nid = ast_util::def_id_of_def(cap_var.def).node; - let ty = node_id_type(bcx, nid); - alt cap_var.mode { - capture::cap_ref { - assert ck == ty::ck_block; - ty = ty::mk_mut_ptr(tcx, ty); - env_vals += [env_ref(lv.val, ty, lv.kind)]; - } - capture::cap_copy { - let mv = alt check ccx.maps.last_uses.find(id) { - none { false } - some(last_use::closes_over(vars)) { vec::contains(vars, nid) } - }; - if mv { env_vals += [env_move(lv.val, ty, lv.kind)]; } - else { env_vals += [env_copy(lv.val, ty, lv.kind)]; } - } - capture::cap_move { - env_vals += [env_move(lv.val, ty, lv.kind)]; - } - capture::cap_drop { - assert lv.kind == owned; - bcx = drop_ty(bcx, lv.val, ty); - bcx = zero_alloca(bcx, lv.val, ty); - } - } - } - ret store_environment(bcx, copy bcx.fcx.lltyparams, env_vals, ck); -} - -// Given an enclosing block context, a new function context, a closure type, -// and a list of upvars, generate code to load and populate the environment -// with the upvars and type descriptors. -fn load_environment(enclosing_cx: block, - fcx: fn_ctxt, - cdata_ty: ty::t, - cap_vars: [capture::capture_var], - ck: ty::closure_kind) { - let bcx = raw_block(fcx, fcx.llloadenv); - - // Load a pointer to the closure data, skipping over the box header: - let llcdata = base::opaque_box_body(bcx, cdata_ty, fcx.llenv); - - // Populate the type parameters from the environment. We need to - // do this first because the tydescs are needed to index into - // the bindings if they are dynamically sized. - let {bcx, val: lltydescs} = GEP_tup_like(bcx, cdata_ty, llcdata, - [0, abi::closure_body_ty_params]); - let off = 0; - for tp in copy enclosing_cx.fcx.lltyparams { - let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off])); - off += 1; - let dicts = option::map(tp.dicts, {|dicts| - let rslt = []; - for dict in dicts { - let dict = Load(bcx, GEPi(bcx, lltydescs, [0, off])); - rslt += [PointerCast(bcx, dict, T_ptr(T_dict()))]; - off += 1; - } - rslt - }); - fcx.lltyparams += [{desc: tydesc, dicts: dicts}]; - } - - // Populate the upvars from the environment. - let i = 0u; - vec::iter(cap_vars) { |cap_var| - alt cap_var.mode { - capture::cap_drop { /* ignore */ } - _ { - let upvarptr = - GEP_tup_like(bcx, cdata_ty, llcdata, - [0, abi::closure_body_bindings, i as int]); - bcx = upvarptr.bcx; - let llupvarptr = upvarptr.val; - alt ck { - ty::ck_block { llupvarptr = Load(bcx, llupvarptr); } - ty::ck_uniq | ty::ck_box { } - } - let def_id = ast_util::def_id_of_def(cap_var.def); - fcx.llupvars.insert(def_id.node, llupvarptr); - i += 1u; - } - } - } -} - -fn trans_expr_fn(bcx: block, - proto: ast::proto, - decl: ast::fn_decl, - body: ast::blk, - sp: span, - id: ast::node_id, - cap_clause: ast::capture_clause, - dest: dest) -> block { - if dest == ignore { ret bcx; } - let ccx = bcx.ccx(), bcx = bcx; - let fty = node_id_type(bcx, id); - let llfnty = type_of_fn_from_ty(ccx, fty, []); - let sub_path = bcx.fcx.path + [path_name("anon")]; - let s = mangle_internal_name_by_path(ccx, sub_path); - let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty); - register_fn(ccx, sp, sub_path, "anon fn", [], id); - - let trans_closure_env = fn@(ck: ty::closure_kind) -> ValueRef { - let cap_vars = capture::compute_capture_vars( - ccx.tcx, id, proto, cap_clause); - let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, ck, id); - trans_closure(ccx, sub_path, decl, body, llfn, no_self, [], - bcx.fcx.param_substs, id, {|fcx| - load_environment(bcx, fcx, cdata_ty, cap_vars, ck); - }); - llbox - }; - - let closure = alt proto { - ast::proto_any | ast::proto_block { trans_closure_env(ty::ck_block) } - ast::proto_box { trans_closure_env(ty::ck_box) } - ast::proto_uniq { trans_closure_env(ty::ck_uniq) } - ast::proto_bare { - trans_closure(ccx, sub_path, decl, body, llfn, no_self, [], none, - id, {|_fcx|}); - C_null(T_opaque_box_ptr(ccx)) - } - }; - fill_fn_pair(bcx, get_dest_addr(dest), llfn, closure); - ret bcx; -} - -fn trans_bind(cx: block, f: @ast::expr, args: [option<@ast::expr>], - id: ast::node_id, dest: dest) -> block { - let f_res = trans_callee(cx, f); - ret trans_bind_1(cx, expr_ty(cx, f), f_res, args, - node_id_type(cx, id), dest); -} - -fn trans_bind_1(cx: block, outgoing_fty: ty::t, - f_res: lval_maybe_callee, - args: [option<@ast::expr>], pair_ty: ty::t, - dest: dest) -> block { - let ccx = cx.ccx(); - let bound: [@ast::expr] = []; - for argopt: option<@ast::expr> in args { - alt argopt { none { } some(e) { bound += [e]; } } - } - let bcx = f_res.bcx; - if dest == ignore { - for ex in bound { bcx = trans_expr(bcx, ex, ignore); } - ret bcx; - } - - // Figure out which tydescs we need to pass, if any. - let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic { - generic_full(ginfo) { - let tds = [], orig = 0u; - vec::iter2(ginfo.tydescs, *ginfo.param_bounds) {|td, bounds| - tds += [td]; - for bound in *bounds { - alt bound { - ty::bound_iface(_) { - let dict = impl::get_dict( - bcx, option::get(ginfo.origins)[orig]); - tds += [PointerCast(bcx, dict.val, val_ty(td))]; - orig += 1u; - bcx = dict.bcx; - } - _ {} - } - } - } - lazily_emit_all_generic_info_tydesc_glues(ccx, ginfo); - (ginfo.item_type, tds, ginfo.param_bounds) - } - _ { (outgoing_fty, [], @[]) } - }; - - if bound.len() == 0u && lltydescs.len() == 0u && - (f_res.env == null_env || f_res.env == is_closure) { - // Trivial 'binding': just return the closure - let lv = lval_maybe_callee_to_lval(f_res, pair_ty); - ret memmove_ty(lv.bcx, get_dest_addr(dest), lv.val, pair_ty); - } - - // Arrange for the bound function to live in the first binding spot - // if the function is not statically known. - let (env_vals, target_info) = alt f_res.env { - null_env { ([], target_static(f_res.val)) } - is_closure { - // Cast the function we are binding to be the type that the - // closure will expect it to have. The type the closure knows - // about has the type parameters substituted with the real types. - let llclosurety = T_ptr(type_of(ccx, outgoing_fty)); - let src_loc = PointerCast(bcx, f_res.val, llclosurety); - ([env_copy(src_loc, pair_ty, owned)], target_closure) - } - self_env(slf, slf_t) { - ([env_copy(slf, slf_t, owned)], target_self(f_res.val)) - } - dict_env(_, _) { - ccx.sess.unimpl("binding of dynamic method calls"); - } - }; - - // Actually construct the closure - let {llbox, cdata_ty, bcx} = store_environment( - bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}), - env_vals + vec::map(bound, {|x| env_expr(x, expr_ty(bcx, x))}), - ty::ck_box); - - // Make thunk - let llthunk = trans_bind_thunk( - cx.fcx.ccx, cx.fcx.path, pair_ty, outgoing_fty_real, args, - cdata_ty, *param_bounds, target_info); - - // Fill the function pair - fill_fn_pair(bcx, get_dest_addr(dest), llthunk.val, llbox); - ret bcx; -} - -fn make_fn_glue( - cx: block, - v: ValueRef, - t: ty::t, - glue_fn: fn@(block, v: ValueRef, t: ty::t) -> block) - -> block { - let bcx = cx; - let tcx = cx.tcx(); - - let fn_env = fn@(ck: ty::closure_kind) -> block { - let box_cell_v = GEPi(cx, v, [0, abi::fn_field_box]); - let box_ptr_v = Load(cx, box_cell_v); - with_cond(cx, IsNotNull(cx, box_ptr_v)) {|bcx| - let closure_ty = ty::mk_opaque_closure_ptr(tcx, ck); - glue_fn(bcx, box_cell_v, closure_ty) - } - }; - - ret alt ty::get(t).struct { - ty::ty_fn({proto: ast::proto_bare, _}) | - ty::ty_fn({proto: ast::proto_block, _}) | - ty::ty_fn({proto: ast::proto_any, _}) { bcx } - ty::ty_fn({proto: ast::proto_uniq, _}) { fn_env(ty::ck_uniq) } - ty::ty_fn({proto: ast::proto_box, _}) { fn_env(ty::ck_box) } - _ { fail "make_fn_glue invoked on non-function type" } - }; -} - -fn make_opaque_cbox_take_glue( - bcx: block, - ck: ty::closure_kind, - cboxptr: ValueRef) // ptr to ptr to the opaque closure - -> block { - // Easy cases: - alt ck { - ty::ck_block { ret bcx; } - ty::ck_box { ret incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr)); } - ty::ck_uniq { /* hard case: */ } - } - - // Hard case, a deep copy: - let ccx = bcx.ccx(), tcx = ccx.tcx; - let llopaquecboxty = T_opaque_box_ptr(ccx); - let cbox_in = Load(bcx, cboxptr); - with_cond(bcx, IsNotNull(bcx, cbox_in)) {|bcx| - // Load the size from the type descr found in the cbox - let cbox_in = PointerCast(bcx, cbox_in, llopaquecboxty); - let tydescptr = GEPi(bcx, cbox_in, [0, abi::box_field_tydesc]); - let tydesc = Load(bcx, tydescptr); - let tydesc = PointerCast(bcx, tydesc, T_ptr(ccx.tydesc_type)); - let sz = Load(bcx, GEPi(bcx, tydesc, [0, abi::tydesc_field_size])); - - // Adjust sz to account for the rust_opaque_box header fields - let sz = Add(bcx, sz, shape::llsize_of(ccx, T_box_header(ccx))); - - // Allocate memory, update original ptr, and copy existing data - let malloc = ccx.upcalls.shared_malloc; - let cbox_out = Call(bcx, malloc, [sz]); - let cbox_out = PointerCast(bcx, cbox_out, llopaquecboxty); - let {bcx, val: _} = call_memmove(bcx, cbox_out, cbox_in, sz); - Store(bcx, cbox_out, cboxptr); - - // Take the (deeply cloned) type descriptor - let tydesc_out = GEPi(bcx, cbox_out, [0, abi::box_field_tydesc]); - let bcx = take_ty(bcx, tydesc_out, mk_tydesc_ty(tcx, ty::ck_uniq)); - - // Take the data in the tuple - let ti = none; - let cdata_out = GEPi(bcx, cbox_out, [0, abi::box_field_body]); - call_tydesc_glue_full(bcx, cdata_out, tydesc, - abi::tydesc_field_take_glue, ti); - bcx - } -} - -fn make_opaque_cbox_drop_glue( - bcx: block, - ck: ty::closure_kind, - cboxptr: ValueRef) // ptr to the opaque closure - -> block { - alt ck { - ty::ck_block { bcx } - ty::ck_box { - decr_refcnt_maybe_free(bcx, Load(bcx, cboxptr), - ty::mk_opaque_closure_ptr(bcx.tcx(), ck)) - } - ty::ck_uniq { - free_ty(bcx, Load(bcx, cboxptr), - ty::mk_opaque_closure_ptr(bcx.tcx(), ck)) - } - } -} - -fn make_opaque_cbox_free_glue( - bcx: block, - ck: ty::closure_kind, - cbox: ValueRef) // ptr to the opaque closure - -> block { - alt ck { - ty::ck_block { ret bcx; } - ty::ck_box | ty::ck_uniq { /* hard cases: */ } - } - - let ccx = bcx.ccx(), tcx = ccx.tcx; - with_cond(bcx, IsNotNull(bcx, cbox)) {|bcx| - // Load the type descr found in the cbox - let lltydescty = T_ptr(ccx.tydesc_type); - let cbox = PointerCast(bcx, cbox, T_opaque_cbox_ptr(ccx)); - let tydescptr = GEPi(bcx, cbox, [0, abi::box_field_tydesc]); - let tydesc = Load(bcx, tydescptr); - let tydesc = PointerCast(bcx, tydesc, lltydescty); - - // Drop the tuple data then free the descriptor - let ti = none; - let cdata = GEPi(bcx, cbox, [0, abi::box_field_body]); - call_tydesc_glue_full(bcx, cdata, tydesc, - abi::tydesc_field_drop_glue, ti); - - // Free the ty descr (if necc) and the box itself - alt ck { - ty::ck_block { fail "Impossible"; } - ty::ck_box { - trans_free(bcx, cbox) - } - ty::ck_uniq { - let bcx = free_ty(bcx, tydesc, mk_tydesc_ty(tcx, ck)); - trans_shared_free(bcx, cbox) - } - } - } -} - -enum target_info { - target_closure, - target_static(ValueRef), - target_self(ValueRef), -} - -// pth is cx.path -fn trans_bind_thunk(ccx: crate_ctxt, - path: path, - incoming_fty: ty::t, - outgoing_fty: ty::t, - args: [option<@ast::expr>], - cdata_ty: ty::t, - param_bounds: [ty::param_bounds], - target_info: target_info) - -> {val: ValueRef, ty: TypeRef} { - let tcx = ccx.tcx; - #debug["trans_bind_thunk[incoming_fty=%s,outgoing_fty=%s,\ - cdata_ty=%s,param_bounds=%?]", - ty_to_str(tcx, incoming_fty), - ty_to_str(tcx, outgoing_fty), - ty_to_str(tcx, cdata_ty), - param_bounds]; - - // Here we're not necessarily constructing a thunk in the sense of - // "function with no arguments". The result of compiling 'bind f(foo, - // bar, baz)' would be a thunk that, when called, applies f to those - // arguments and returns the result. But we're stretching the meaning of - // the word "thunk" here to also mean the result of compiling, say, 'bind - // f(foo, _, baz)', or any other bind expression that binds f and leaves - // some (or all) of the arguments unbound. - - // Here, 'incoming_fty' is the type of the entire bind expression, while - // 'outgoing_fty' is the type of the function that is having some of its - // arguments bound. If f is a function that takes three arguments of type - // int and returns int, and we're translating, say, 'bind f(3, _, 5)', - // then outgoing_fty is the type of f, which is (int, int, int) -> int, - // and incoming_fty is the type of 'bind f(3, _, 5)', which is int -> int. - - // Once translated, the entire bind expression will be the call f(foo, - // bar, baz) wrapped in a (so-called) thunk that takes 'bar' as its - // argument and that has bindings of 'foo' to 3 and 'baz' to 5 and a - // pointer to 'f' all saved in its environment. So, our job is to - // construct and return that thunk. - - // Give the thunk a name, type, and value. - let s = mangle_internal_name_by_path_and_seq(ccx, path, "thunk"); - let llthunk_ty = get_pair_fn_ty(type_of(ccx, incoming_fty)); - let llthunk = decl_internal_cdecl_fn(ccx.llmod, s, llthunk_ty); - - // Create a new function context and block context for the thunk, and hold - // onto a pointer to the first block in the function for later use. - let fcx = new_fn_ctxt(ccx, path, llthunk, none); - let bcx = top_scope_block(fcx, none); - let lltop = bcx.llbb; - // Since we might need to construct derived tydescs that depend on - // our bound tydescs, we need to load tydescs out of the environment - // before derived tydescs are constructed. To do this, we load them - // in the load_env block. - let l_bcx = raw_block(fcx, fcx.llloadenv); - - // The 'llenv' that will arrive in the thunk we're creating is an - // environment that will contain the values of its arguments and a - // pointer to the original function. This environment is always - // stored like an opaque box (see big comment at the header of the - // file), so we load the body body, which contains the type descr - // and cached data. - let llcdata = base::opaque_box_body(l_bcx, cdata_ty, fcx.llenv); - - // "target", in this context, means the function that's having some of its - // arguments bound and that will be called inside the thunk we're - // creating. (In our running example, target is the function f.) Pick - // out the pointer to the target function from the environment. The - // target function lives in the first binding spot. - let (lltargetfn, lltargetenv, starting_idx) = alt target_info { - target_static(fptr) { - (fptr, llvm::LLVMGetUndef(T_opaque_cbox_ptr(ccx)), 0) - } - target_closure { - let {bcx: cx, val: pair} = - GEP_tup_like(bcx, cdata_ty, llcdata, - [0, abi::closure_body_bindings, 0]); - let lltargetenv = - Load(cx, GEPi(cx, pair, [0, abi::fn_field_box])); - let lltargetfn = Load - (cx, GEPi(cx, pair, [0, abi::fn_field_code])); - bcx = cx; - (lltargetfn, lltargetenv, 1) - } - target_self(fptr) { - let rs = GEP_tup_like(bcx, cdata_ty, llcdata, - [0, abi::closure_body_bindings, 0]); - bcx = rs.bcx; - (fptr, PointerCast(bcx, rs.val, T_opaque_cbox_ptr(ccx)), 1) - } - }; - - // And then, pick out the target function's own environment. That's what - // we'll use as the environment the thunk gets. - - // Get f's return type, which will also be the return type of the entire - // bind expression. - let outgoing_ret_ty = ty::ty_fn_ret(outgoing_fty); - - // Get the types of the arguments to f. - let outgoing_args = ty::ty_fn_args(outgoing_fty); - - // The 'llretptr' that will arrive in the thunk we're creating also needs - // to be the correct type. Cast it to f's return type, if necessary. - let llretptr = fcx.llretptr; - if ty::type_has_params(outgoing_ret_ty) { - let llretty = type_of(ccx, outgoing_ret_ty); - llretptr = PointerCast(bcx, llretptr, T_ptr(llretty)); - } - - // Set up the three implicit arguments to the thunk. - let llargs: [ValueRef] = [llretptr, lltargetenv]; - - // Copy in the type parameters. - let {bcx: l_bcx, val: param_record} = - GEP_tup_like(l_bcx, cdata_ty, llcdata, - [0, abi::closure_body_ty_params]); - let off = 0; - for param in param_bounds { - let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])), - dicts = none; - llargs += [dsc]; - off += 1; - for bound in *param { - alt bound { - ty::bound_iface(_) { - let dict = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])); - dict = PointerCast(l_bcx, dict, T_ptr(T_dict())); - llargs += [dict]; - off += 1; - dicts = some(alt dicts { - none { [dict] } - some(ds) { ds + [dict] } - }); - } - _ {} - } - } - fcx.lltyparams += [{desc: dsc, dicts: dicts}]; - } - - let a: uint = first_tp_arg; // retptr, env come first - let b: int = starting_idx; - let outgoing_arg_index: uint = 0u; - let llout_arg_tys: [TypeRef] = - type_of_explicit_args(ccx, outgoing_args); - for arg: option<@ast::expr> in args { - let out_arg = outgoing_args[outgoing_arg_index]; - let llout_arg_ty = llout_arg_tys[outgoing_arg_index]; - alt arg { - // Arg provided at binding time; thunk copies it from - // closure. - some(e) { - let bound_arg = - GEP_tup_like(bcx, cdata_ty, llcdata, - [0, abi::closure_body_bindings, b]); - bcx = bound_arg.bcx; - let val = bound_arg.val; - - alt ty::resolved_mode(tcx, out_arg.mode) { - ast::by_val { - val = Load(bcx, val); - } - ast::by_copy { - let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty); - bcx = memmove_ty(cx, alloc, val, out_arg.ty); - bcx = take_ty(bcx, alloc, out_arg.ty); - val = alloc; - } - ast::by_ref | ast::by_mutbl_ref | ast::by_move { } - } - - // If the type is parameterized, then we need to cast the - // type we actually have to the parameterized out type. - if ty::type_has_params(out_arg.ty) { - val = PointerCast(bcx, val, llout_arg_ty); - } - llargs += [val]; - b += 1; - } - - // Arg will be provided when the thunk is invoked. - none { - let arg: ValueRef = llvm::LLVMGetParam(llthunk, a as c_uint); - if ty::type_has_params(out_arg.ty) { - arg = PointerCast(bcx, arg, llout_arg_ty); - } - llargs += [arg]; - a += 1u; - } - } - outgoing_arg_index += 1u; - } - - // Cast the outgoing function to the appropriate type. - // This is necessary because the type of the function that we have - // in the closure does not know how many type descriptors the function - // needs to take. - let lltargetty = - type_of_fn_from_ty(ccx, outgoing_fty, param_bounds); - lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(lltargetty)); - Call(bcx, lltargetfn, llargs); - build_return(bcx); - finish_fn(fcx, lltop); - ret {val: llthunk, ty: llthunk_ty}; -} diff --git a/src/comp/middle/trans/common.rs b/src/comp/middle/trans/common.rs deleted file mode 100644 index 4bc264e4098..00000000000 --- a/src/comp/middle/trans/common.rs +++ /dev/null @@ -1,933 +0,0 @@ -/** - Code that is useful in various trans modules. - -*/ - -import ctypes::unsigned; -import vec::unsafe::to_ptr; -import std::map::hashmap; -import syntax::ast; -import driver::session; -import session::session; -import middle::{resolve, ty}; -import back::{link, abi, upcall}; -import util::common::*; -import syntax::codemap::span; -import lib::llvm::{llvm, target_data, type_names, associate_type, - name_has_type}; -import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef}; -import lib::llvm::{True, False, Bool}; -import metadata::csearch; -import ast_map::path; -import middle::inline::inline_map; - -type namegen = fn@(str) -> str; -fn new_namegen() -> namegen { - let i = @mutable 0; - ret fn@(prefix: str) -> str { *i += 1; prefix + int::str(*i) }; -} - -type derived_tydesc_info = {lltydesc: ValueRef, escapes: bool}; - -type tydesc_info = - {ty: ty::t, - tydesc: ValueRef, - size: ValueRef, - align: ValueRef, - mutable take_glue: option<ValueRef>, - mutable drop_glue: option<ValueRef>, - mutable free_glue: option<ValueRef>, - ty_params: [uint]}; - -/* - * A note on nomenclature of linking: "upcall", "extern" and "native". - * - * An "extern" is an LLVM symbol we wind up emitting an undefined external - * reference to. This means "we don't have the thing in this compilation unit, - * please make sure you link it in at runtime". This could be a reference to - * C code found in a C library, or rust code found in a rust crate. - * - * A "native" is an extern that references C code. Called with cdecl. - * - * An upcall is a native call generated by the compiler (not corresponding to - * any user-written call in the code) into librustrt, to perform some helper - * task such as bringing a task to life, allocating memory, etc. - * - */ -type stats = - {mutable n_static_tydescs: uint, - mutable n_derived_tydescs: uint, - mutable n_glues_created: uint, - mutable n_null_glues: uint, - mutable n_real_glues: uint, - fn_times: @mutable [{ident: str, time: int}]}; - -resource BuilderRef_res(B: BuilderRef) { llvm::LLVMDisposeBuilder(B); } - -// Misc. auxiliary maps used in the crate_ctxt -type maps = { - mutbl_map: middle::mutbl::mutbl_map, - copy_map: middle::alias::copy_map, - last_uses: middle::last_use::last_uses, - impl_map: middle::resolve::impl_map, - method_map: middle::typeck::method_map, - dict_map: middle::typeck::dict_map -}; - -// Crate context. Every crate we compile has one of these. -type crate_ctxt = @{ - sess: session::session, - llmod: ModuleRef, - td: target_data, - tn: type_names, - externs: hashmap<str, ValueRef>, - intrinsics: hashmap<str, ValueRef>, - item_ids: hashmap<ast::node_id, ValueRef>, - exp_map: resolve::exp_map, - item_symbols: hashmap<ast::node_id, str>, - mutable main_fn: option<ValueRef>, - link_meta: link::link_meta, - enum_sizes: hashmap<ty::t, uint>, - discrims: hashmap<ast::def_id, ValueRef>, - discrim_symbols: hashmap<ast::node_id, str>, - consts: hashmap<ast::node_id, ValueRef>, - tydescs: hashmap<ty::t, @tydesc_info>, - dicts: hashmap<dict_id, ValueRef>, - monomorphized: hashmap<mono_id, {llfn: ValueRef, fty: ty::t}>, - module_data: hashmap<str, ValueRef>, - lltypes: hashmap<ty::t, TypeRef>, - names: namegen, - sha: std::sha1::sha1, - type_sha1s: hashmap<ty::t, str>, - type_short_names: hashmap<ty::t, str>, - tcx: ty::ctxt, - maps: maps, - inline_map: inline_map, - stats: stats, - upcalls: @upcall::upcalls, - tydesc_type: TypeRef, - int_type: TypeRef, - float_type: TypeRef, - task_type: TypeRef, - opaque_vec_type: TypeRef, - builder: BuilderRef_res, - shape_cx: shape::ctxt, - crate_map: ValueRef, - dbg_cx: option<@debuginfo::debug_ctxt>, - mutable do_not_commit_warning_issued: bool}; - -// Types used for llself. -type val_self_pair = {v: ValueRef, t: ty::t}; - -enum local_val { local_mem(ValueRef), local_imm(ValueRef), } - -type fn_ty_param = {desc: ValueRef, dicts: option<[ValueRef]>}; - -type param_substs = {tys: [ty::t], - dicts: option<typeck::dict_res>, - bounds: @[ty::param_bounds]}; - -// Function context. Every LLVM function we create will have one of -// these. -type fn_ctxt = @{ - // The ValueRef returned from a call to llvm::LLVMAddFunction; the - // address of the first instruction in the sequence of - // instructions for this function that will go in the .text - // section of the executable we're generating. - llfn: ValueRef, - - // The two implicit arguments that arrive in the function we're creating. - // For instance, foo(int, int) is really foo(ret*, env*, int, int). - llenv: ValueRef, - llretptr: ValueRef, - - // These 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 static allocas, so that LLVM - // will coalesce them into a single alloca call. - mutable llstaticallocas: BasicBlockRef, - // A block containing code that copies incoming arguments to space - // already allocated by code in one of the llallocas blocks. - // (LLVM requires that arguments be copied to local allocas before - // allowing most any operation to be performed on them.) - mutable llloadenv: BasicBlockRef, - // The first and last block containing derived tydescs received from the - // runtime. See description of derived_tydescs, below. - mutable llderivedtydescs_first: BasicBlockRef, - mutable llderivedtydescs: BasicBlockRef, - // A block for all of the dynamically sized allocas. This must be - // after llderivedtydescs, because these sometimes depend on - // information computed from derived tydescs. - mutable lldynamicallocas: BasicBlockRef, - mutable llreturn: BasicBlockRef, - // The token used to clear the dynamic allocas at the end of this frame. - mutable llobstacktoken: option<ValueRef>, - // The 'self' value currently in use in this function, if there - // is one. - mutable llself: option<val_self_pair>, - // The a value alloca'd for calls to upcalls.rust_personality. Used when - // outputting the resume instruction. - mutable personality: option<ValueRef>, - - // Maps arguments to allocas created for them in llallocas. - llargs: hashmap<ast::node_id, local_val>, - // Maps the def_ids for local variables to the allocas created for - // them in llallocas. - lllocals: hashmap<ast::node_id, local_val>, - // Same as above, but for closure upvars - llupvars: hashmap<ast::node_id, ValueRef>, - - // A vector of incoming type descriptors and their associated iface dicts. - mutable lltyparams: [fn_ty_param], - - // Derived tydescs are tydescs created at runtime, for types that - // involve type parameters inside type constructors. For example, - // suppose a function parameterized by T creates a vector of type - // [T]. The function doesn't know what T is until runtime, and - // the function's caller knows T but doesn't know that a vector is - // involved. So a tydesc for [T] can't be created until runtime, - // when information about both "[T]" and "T" are available. When - // such a tydesc is created, we cache it in the derived_tydescs - // table for the next time that such a tydesc is needed. - derived_tydescs: hashmap<ty::t, derived_tydesc_info>, - - // The node_id of the function, or -1 if it doesn't correspond to - // a user-defined function. - id: ast::node_id, - - // If this function is being monomorphized, this contains the type - // substitutions used. - param_substs: option<param_substs>, - - // The source span and nesting context where this function comes from, for - // error reporting and symbol generation. - span: option<span>, - path: path, - - // This function's enclosing crate context. - ccx: crate_ctxt -}; - -fn warn_not_to_commit(ccx: crate_ctxt, msg: str) { - if !ccx.do_not_commit_warning_issued { - ccx.do_not_commit_warning_issued = true; - ccx.sess.warn(msg + " -- do not commit like this!"); - } -} - -enum cleanup { - clean(fn@(block) -> block), - clean_temp(ValueRef, fn@(block) -> block), -} - -// Used to remember and reuse existing cleanup paths -// target: none means the path ends in an resume instruction -type cleanup_path = {target: option<BasicBlockRef>, - dest: BasicBlockRef}; - -fn scope_clean_changed(info: scope_info) { - if info.cleanup_paths.len() > 0u { info.cleanup_paths = []; } - info.landing_pad = none; -} - -fn add_clean(cx: block, val: ValueRef, ty: ty::t) { - if !ty::type_needs_drop(cx.tcx(), ty) { ret; } - in_scope_cx(cx) {|info| - info.cleanups += [clean(bind base::drop_ty(_, val, ty))]; - scope_clean_changed(info); - } -} -fn add_clean_temp(cx: block, val: ValueRef, ty: ty::t) { - if !ty::type_needs_drop(cx.tcx(), ty) { ret; } - fn do_drop(bcx: block, val: ValueRef, ty: ty::t) -> - block { - if ty::type_is_immediate(ty) { - ret base::drop_ty_immediate(bcx, val, ty); - } else { - ret base::drop_ty(bcx, val, ty); - } - } - in_scope_cx(cx) {|info| - info.cleanups += [clean_temp(val, bind do_drop(_, val, ty))]; - scope_clean_changed(info); - } -} -fn add_clean_temp_mem(cx: block, val: ValueRef, ty: ty::t) { - if !ty::type_needs_drop(cx.tcx(), ty) { ret; } - in_scope_cx(cx) {|info| - info.cleanups += [clean_temp(val, bind base::drop_ty(_, val, ty))]; - scope_clean_changed(info); - } -} -fn add_clean_free(cx: block, ptr: ValueRef, shared: bool) { - let free_fn = if shared { bind base::trans_shared_free(_, ptr) } - else { bind base::trans_free(_, ptr) }; - in_scope_cx(cx) {|info| - info.cleanups += [clean_temp(ptr, free_fn)]; - scope_clean_changed(info); - } -} - -// Note that this only works for temporaries. We should, at some point, move -// to a system where we can also cancel the cleanup on local variables, but -// this will be more involved. For now, we simply zero out the local, and the -// drop glue checks whether it is zero. -fn revoke_clean(cx: block, val: ValueRef) { - in_scope_cx(cx) {|info| - let i = 0u; - for cu in info.cleanups { - alt cu { - clean_temp(v, _) if v == val { - info.cleanups = - vec::slice(info.cleanups, 0u, i) + - vec::slice(info.cleanups, i + 1u, info.cleanups.len()); - scope_clean_changed(info); - ret; - } - _ {} - } - i += 1u; - } - } -} - -fn get_res_dtor(ccx: crate_ctxt, did: ast::def_id, inner_t: ty::t) - -> ValueRef { - if did.crate == ast::local_crate { - alt ccx.item_ids.find(did.node) { - some(x) { ret x; } - _ { ccx.sess.bug("get_res_dtor: can't find resource dtor!"); } - } - } - - let param_bounds = ty::lookup_item_type(ccx.tcx, did).bounds; - let nil_res = ty::mk_nil(ccx.tcx); - let fn_mode = ast::expl(ast::by_ref); - let f_t = type_of::type_of_fn(ccx, [{mode: fn_mode, ty: inner_t}], - nil_res, *param_bounds); - ret base::get_extern_const(ccx.externs, ccx.llmod, - csearch::get_symbol(ccx.sess.cstore, - did), f_t); -} - -enum block_kind { - // A scope at the end of which temporary values created inside of it are - // cleaned up. May correspond to an actual block in the language, but also - // to an implicit scope, for example, calls introduce an implicit scope in - // which the arguments are evaluated and cleaned up. - block_scope(scope_info), - // A non-scope block is a basic block created as a translation artifact - // from translating code that expresses conditional logic rather than by - // explicit { ... } block structure in the source language. It's called a - // non-scope block because it doesn't introduce a new variable scope. - block_non_scope, -} - -enum loop_cont { cont_self, cont_other(block), } - -type scope_info = { - is_loop: option<{cnt: loop_cont, brk: block}>, - // A list of functions that must be run at when leaving this - // block, cleaning up any variables that were introduced in the - // block. - mutable cleanups: [cleanup], - // Existing cleanup paths that may be reused, indexed by destination and - // cleared when the set of cleanups changes. - mutable cleanup_paths: [cleanup_path], - // Unwinding landing pad. Also cleared when cleanups change. - mutable landing_pad: option<BasicBlockRef>, -}; - -// Basic block context. We create a block context for each basic block -// (single-entry, single-exit sequence of instructions) we generate from Rust -// code. Each basic block we generate is attached to a function, typically -// with many basic blocks per function. All the basic blocks attached to a -// function are organized as a directed graph. -type block = @{ - // The BasicBlockRef returned from a call to - // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic - // block to the function pointed to by llfn. We insert - // instructions into that block by way of this block context. - // The block pointing to this one in the function's digraph. - llbb: BasicBlockRef, - mutable terminated: bool, - mutable unreachable: bool, - parent: block_parent, - // The 'kind' of basic block this is. - kind: block_kind, - // The source span where the block came from, if it is a block that - // actually appears in the source code. - mutable block_span: option<span>, - // The function context for the function to which this block is - // attached. - fcx: fn_ctxt -}; - -// First two args are retptr, env -const first_tp_arg: uint = 2u; - -// FIXME move blocks to a class once those are finished, and simply use -// option<block> for this. -enum block_parent { parent_none, parent_some(block), } - -type result = {bcx: block, val: ValueRef}; -type result_t = {bcx: block, val: ValueRef, ty: ty::t}; - -fn rslt(bcx: block, val: ValueRef) -> result { - {bcx: bcx, val: val} -} - -fn ty_str(tn: type_names, t: TypeRef) -> str { - ret lib::llvm::type_to_str(tn, t); -} - -fn val_ty(&&v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); } - -fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); } - -// Returns the nth element of the given LLVM structure type. -fn struct_elt(llstructty: TypeRef, n: uint) -> TypeRef unsafe { - let elt_count = llvm::LLVMCountStructElementTypes(llstructty) as uint; - assert (n < elt_count); - let elt_tys = vec::init_elt(elt_count, T_nil()); - llvm::LLVMGetStructElementTypes(llstructty, to_ptr(elt_tys)); - ret llvm::LLVMGetElementType(elt_tys[n]); -} - -fn in_scope_cx(cx: block, f: fn(scope_info)) { - let cur = cx; - while true { - alt cur.kind { - block_scope(info) { f(info); ret; } - _ {} - } - cur = block_parent(cur); - } -} - -fn block_parent(cx: block) -> block { - alt check cx.parent { parent_some(b) { b } } -} - -// Accessors - -impl bxc_cxs for block { - fn ccx() -> crate_ctxt { self.fcx.ccx } - fn tcx() -> ty::ctxt { self.fcx.ccx.tcx } - fn sess() -> session { self.fcx.ccx.sess } -} - -// LLVM type constructors. -fn T_void() -> TypeRef { - // Note: For the time being llvm is kinda busted here, it has the notion - // of a 'void' type that can only occur as part of the signature of a - // function, but no general unit type of 0-sized value. This is, afaict, - // vestigial from its C heritage, and we'll be attempting to submit a - // patch upstream to fix it. In the mean time we only model function - // outputs (Rust functions and C functions) using T_void, and model the - // Rust general purpose nil type you can construct as 1-bit (always - // zero). This makes the result incorrect for now -- things like a tuple - // of 10 nil values will have 10-bit size -- but it doesn't seem like we - // have any other options until it's fixed upstream. - - ret llvm::LLVMVoidType(); -} - -fn T_nil() -> TypeRef { - // NB: See above in T_void(). - - ret llvm::LLVMInt1Type(); -} - -fn T_metadata() -> TypeRef { ret llvm::LLVMMetadataType(); } - -fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); } - -fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); } - -fn T_i16() -> TypeRef { ret llvm::LLVMInt16Type(); } - -fn T_i32() -> TypeRef { ret llvm::LLVMInt32Type(); } - -fn T_i64() -> TypeRef { ret llvm::LLVMInt64Type(); } - -fn T_f32() -> TypeRef { ret llvm::LLVMFloatType(); } - -fn T_f64() -> TypeRef { ret llvm::LLVMDoubleType(); } - -fn T_bool() -> TypeRef { ret T_i1(); } - -fn T_int(targ_cfg: @session::config) -> TypeRef { - ret alt targ_cfg.arch { - session::arch_x86 { T_i32() } - session::arch_x86_64 { T_i64() } - session::arch_arm { T_i32() } - }; -} - -fn T_int_ty(cx: crate_ctxt, t: ast::int_ty) -> TypeRef { - alt t { - ast::ty_i { cx.int_type } - ast::ty_char { T_char() } - ast::ty_i8 { T_i8() } - ast::ty_i16 { T_i16() } - ast::ty_i32 { T_i32() } - ast::ty_i64 { T_i64() } - } -} - -fn T_uint_ty(cx: crate_ctxt, t: ast::uint_ty) -> TypeRef { - alt t { - ast::ty_u { cx.int_type } - ast::ty_u8 { T_i8() } - ast::ty_u16 { T_i16() } - ast::ty_u32 { T_i32() } - ast::ty_u64 { T_i64() } - } -} - -fn T_float_ty(cx: crate_ctxt, t: ast::float_ty) -> TypeRef { - alt t { - ast::ty_f { cx.float_type } - ast::ty_f32 { T_f32() } - ast::ty_f64 { T_f64() } - } -} - -fn T_float(targ_cfg: @session::config) -> TypeRef { - ret alt targ_cfg.arch { - session::arch_x86 { T_f64() } - session::arch_x86_64 { T_f64() } - session::arch_arm { T_f64() } - }; -} - -fn T_char() -> TypeRef { ret T_i32(); } - -fn T_size_t(targ_cfg: @session::config) -> TypeRef { - ret T_int(targ_cfg); -} - -fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef unsafe { - ret llvm::LLVMFunctionType(output, to_ptr(inputs), - inputs.len() as unsigned, - False); -} - -fn T_fn_pair(cx: crate_ctxt, tfn: TypeRef) -> TypeRef { - ret T_struct([T_ptr(tfn), T_opaque_cbox_ptr(cx)]); -} - -fn T_ptr(t: TypeRef) -> TypeRef { - ret llvm::LLVMPointerType(t, 0u as unsigned); -} - -fn T_struct(elts: [TypeRef]) -> TypeRef unsafe { - ret llvm::LLVMStructType(to_ptr(elts), elts.len() as unsigned, False); -} - -fn T_named_struct(name: str) -> TypeRef { - let c = llvm::LLVMGetGlobalContext(); - ret str::as_buf(name, {|buf| llvm::LLVMStructCreateNamed(c, buf) }); -} - -fn set_struct_body(t: TypeRef, elts: [TypeRef]) unsafe { - llvm::LLVMStructSetBody(t, to_ptr(elts), - elts.len() as unsigned, False); -} - -fn T_empty_struct() -> TypeRef { ret T_struct([]); } - -// A dict is, in reality, a vtable pointer followed by zero or more pointers -// to tydescs and other dicts that it closes over. But the types and number of -// those are rarely known to the code that needs to manipulate them, so they -// are described by this opaque type. -fn T_dict() -> TypeRef { T_array(T_ptr(T_i8()), 1u) } - -fn T_task(targ_cfg: @session::config) -> TypeRef { - let t = T_named_struct("task"); - - // Refcount - // Delegate pointer - // Stack segment pointer - // Runtime SP - // Rust SP - // GC chain - - - // Domain pointer - // Crate cache pointer - - let t_int = T_int(targ_cfg); - let elems = - [t_int, t_int, t_int, t_int, - t_int, t_int, t_int, t_int]; - set_struct_body(t, elems); - ret t; -} - -fn T_tydesc_field(cx: crate_ctxt, field: int) -> TypeRef unsafe { - // Bit of a kludge: pick the fn typeref out of the tydesc.. - - let tydesc_elts: [TypeRef] = - vec::init_elt::<TypeRef>(abi::n_tydesc_fields as uint, - T_nil()); - llvm::LLVMGetStructElementTypes(cx.tydesc_type, - to_ptr::<TypeRef>(tydesc_elts)); - let t = llvm::LLVMGetElementType(tydesc_elts[field]); - ret t; -} - -fn T_glue_fn(cx: crate_ctxt) -> TypeRef { - let s = "glue_fn"; - alt name_has_type(cx.tn, s) { some(t) { ret t; } _ {} } - let t = T_tydesc_field(cx, abi::tydesc_field_drop_glue); - associate_type(cx.tn, s, t); - ret t; -} - -fn T_tydesc(targ_cfg: @session::config) -> TypeRef { - let tydesc = T_named_struct("tydesc"); - let tydescpp = T_ptr(T_ptr(tydesc)); - let pvoid = T_ptr(T_i8()); - let glue_fn_ty = - T_ptr(T_fn([T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, - pvoid], T_void())); - - let int_type = T_int(targ_cfg); - let elems = - [tydescpp, int_type, int_type, - glue_fn_ty, glue_fn_ty, glue_fn_ty, - T_ptr(T_i8()), glue_fn_ty, glue_fn_ty, glue_fn_ty, T_ptr(T_i8()), - T_ptr(T_i8()), T_ptr(T_i8()), int_type, int_type]; - set_struct_body(tydesc, elems); - ret tydesc; -} - -fn T_array(t: TypeRef, n: uint) -> TypeRef { - ret llvm::LLVMArrayType(t, n as unsigned); -} - -// Interior vector. -// -// FIXME: Support user-defined vector sizes. -fn T_vec2(targ_cfg: @session::config, t: TypeRef) -> TypeRef { - ret T_struct([T_int(targ_cfg), // fill - T_int(targ_cfg), // alloc - T_array(t, 0u)]); // elements -} - -fn T_vec(ccx: crate_ctxt, t: TypeRef) -> TypeRef { - ret T_vec2(ccx.sess.targ_cfg, t); -} - -// Note that the size of this one is in bytes. -fn T_opaque_vec(targ_cfg: @session::config) -> TypeRef { - ret T_vec2(targ_cfg, T_i8()); -} - -// Let T be the content of a box @T. tuplify_box_ty(t) returns the -// representation of @T as a tuple (i.e., the ty::t version of what T_box() -// returns). -fn tuplify_box_ty(tcx: ty::ctxt, t: ty::t) -> ty::t { - ret tuplify_cbox_ty(tcx, t, ty::mk_type(tcx)); -} - -// As tuplify_box_ty(), but allows the caller to specify what type of type -// descr is embedded in the box (ty::type vs ty::send_type). This is useful -// for unique closure boxes, hence the name "cbox_ty" (closure box type). -fn tuplify_cbox_ty(tcx: ty::ctxt, t: ty::t, tydesc_t: ty::t) -> ty::t { - let ptr = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx), mutbl: ast::m_imm}); - ret ty::mk_tup(tcx, [ty::mk_uint(tcx), tydesc_t, - ptr, ptr, - t]); -} - -fn T_box_header_fields(cx: crate_ctxt) -> [TypeRef] { - let ptr = T_ptr(T_i8()); - ret [cx.int_type, T_ptr(cx.tydesc_type), ptr, ptr]; -} - -fn T_box_header(cx: crate_ctxt) -> TypeRef { - ret T_struct(T_box_header_fields(cx)); -} - -fn T_box(cx: crate_ctxt, t: TypeRef) -> TypeRef { - ret T_struct(T_box_header_fields(cx) + [t]); -} - -fn T_opaque_box(cx: crate_ctxt) -> TypeRef { - ret T_box(cx, T_i8()); -} - -fn T_opaque_box_ptr(cx: crate_ctxt) -> TypeRef { - ret T_ptr(T_opaque_box(cx)); -} - -fn T_port(cx: crate_ctxt, _t: TypeRef) -> TypeRef { - ret T_struct([cx.int_type]); // Refcount - -} - -fn T_chan(cx: crate_ctxt, _t: TypeRef) -> TypeRef { - ret T_struct([cx.int_type]); // Refcount - -} - -fn T_taskptr(cx: crate_ctxt) -> TypeRef { ret T_ptr(cx.task_type); } - - -// This type must never be used directly; it must always be cast away. -fn T_typaram(tn: type_names) -> TypeRef { - let s = "typaram"; - alt name_has_type(tn, s) { some(t) { ret t; } _ {} } - let t = T_i8(); - associate_type(tn, s, t); - ret t; -} - -fn T_typaram_ptr(tn: type_names) -> TypeRef { ret T_ptr(T_typaram(tn)); } - -fn T_opaque_cbox_ptr(cx: crate_ctxt) -> TypeRef { - // closures look like boxes (even when they are fn~ or fn&) - // see trans_closure.rs - ret T_opaque_box_ptr(cx); -} - -fn T_enum_variant(cx: crate_ctxt) -> TypeRef { - ret cx.int_type; -} - -fn T_enum(cx: crate_ctxt, size: uint) -> TypeRef { - let s = "enum_" + uint::to_str(size, 10u); - alt name_has_type(cx.tn, s) { some(t) { ret t; } _ {} } - let t = - if size == 0u { - T_struct([T_enum_variant(cx)]) - } else { T_struct([T_enum_variant(cx), T_array(T_i8(), size)]) }; - associate_type(cx.tn, s, t); - ret t; -} - -fn T_opaque_enum(cx: crate_ctxt) -> TypeRef { - let s = "opaque_enum"; - alt name_has_type(cx.tn, s) { some(t) { ret t; } _ {} } - let t = T_struct([T_enum_variant(cx), T_i8()]); - associate_type(cx.tn, s, t); - ret t; -} - -fn T_opaque_enum_ptr(cx: crate_ctxt) -> TypeRef { - ret T_ptr(T_opaque_enum(cx)); -} - -fn T_captured_tydescs(cx: crate_ctxt, n: uint) -> TypeRef { - ret T_struct(vec::init_elt::<TypeRef>(n, T_ptr(cx.tydesc_type))); -} - -fn T_opaque_iface(cx: crate_ctxt) -> TypeRef { - T_struct([T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]) -} - -fn T_opaque_port_ptr() -> TypeRef { ret T_ptr(T_i8()); } - -fn T_opaque_chan_ptr() -> TypeRef { ret T_ptr(T_i8()); } - - -// LLVM constant constructors. -fn C_null(t: TypeRef) -> ValueRef { ret llvm::LLVMConstNull(t); } - -fn C_integral(t: TypeRef, u: u64, sign_extend: Bool) -> ValueRef { - let u_hi = (u >> 32u64) as unsigned; - let u_lo = u as unsigned; - ret llvm::LLVMRustConstInt(t, u_hi, u_lo, sign_extend); -} - -fn C_floating(s: str, t: TypeRef) -> ValueRef { - ret str::as_buf(s, {|buf| llvm::LLVMConstRealOfString(t, buf) }); -} - -fn C_nil() -> ValueRef { - // NB: See comment above in T_void(). - - ret C_integral(T_i1(), 0u64, False); -} - -fn C_bool(b: bool) -> ValueRef { - if b { - ret C_integral(T_bool(), 1u64, False); - } else { ret C_integral(T_bool(), 0u64, False); } -} - -fn C_i32(i: i32) -> ValueRef { - ret C_integral(T_i32(), i as u64, True); -} - -fn C_i64(i: i64) -> ValueRef { - ret C_integral(T_i64(), i as u64, True); -} - -fn C_int(cx: crate_ctxt, i: int) -> ValueRef { - ret C_integral(cx.int_type, i as u64, True); -} - -fn C_uint(cx: crate_ctxt, i: uint) -> ValueRef { - ret C_integral(cx.int_type, i as u64, False); -} - -fn C_u8(i: uint) -> ValueRef { ret C_integral(T_i8(), i as u64, False); } - - -// This is a 'c-like' raw string, which differs from -// our boxed-and-length-annotated strings. -fn C_cstr(cx: crate_ctxt, s: str) -> ValueRef { - let sc = str::as_buf(s) {|buf| - llvm::LLVMConstString(buf, str::len(s) as unsigned, False) - }; - let g = - str::as_buf(cx.names("str"), - {|buf| llvm::LLVMAddGlobal(cx.llmod, val_ty(sc), buf) }); - llvm::LLVMSetInitializer(g, sc); - llvm::LLVMSetGlobalConstant(g, True); - lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage); - ret g; -} - -// Returns a Plain Old LLVM String: -fn C_postr(s: str) -> ValueRef { - ret str::as_buf(s) {|buf| - llvm::LLVMConstString(buf, str::len(s) as unsigned, False) - }; -} - -fn C_zero_byte_arr(size: uint) -> ValueRef unsafe { - let i = 0u; - let elts: [ValueRef] = []; - while i < size { elts += [C_u8(0u)]; i += 1u; } - ret llvm::LLVMConstArray(T_i8(), vec::unsafe::to_ptr(elts), - elts.len() as unsigned); -} - -fn C_struct(elts: [ValueRef]) -> ValueRef unsafe { - ret llvm::LLVMConstStruct(vec::unsafe::to_ptr(elts), - elts.len() as unsigned, False); -} - -fn C_named_struct(T: TypeRef, elts: [ValueRef]) -> ValueRef unsafe { - ret llvm::LLVMConstNamedStruct(T, vec::unsafe::to_ptr(elts), - elts.len() as unsigned); -} - -fn C_array(ty: TypeRef, elts: [ValueRef]) -> ValueRef unsafe { - ret llvm::LLVMConstArray(ty, vec::unsafe::to_ptr(elts), - elts.len() as unsigned); -} - -fn C_bytes(bytes: [u8]) -> ValueRef unsafe { - ret llvm::LLVMConstString( - unsafe::reinterpret_cast(vec::unsafe::to_ptr(bytes)), - bytes.len() as unsigned, False); -} - -fn C_shape(ccx: crate_ctxt, bytes: [u8]) -> ValueRef { - let llshape = C_bytes(bytes); - let llglobal = str::as_buf(ccx.names("shape"), {|buf| - llvm::LLVMAddGlobal(ccx.llmod, val_ty(llshape), buf) - }); - llvm::LLVMSetInitializer(llglobal, llshape); - llvm::LLVMSetGlobalConstant(llglobal, True); - lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); - ret llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8())); -} - -pure fn type_has_static_size(cx: crate_ctxt, t: ty::t) -> bool { - !ty::type_has_dynamic_size(cx.tcx, t) -} - -// Used to identify cached dictionaries -enum dict_param { - dict_param_dict(dict_id), - dict_param_ty(ty::t), -} -type dict_id = @{def: ast::def_id, params: [dict_param]}; -fn hash_dict_id(&&dp: dict_id) -> uint { - let h = syntax::ast_util::hash_def_id(dp.def); - for param in dp.params { - h = h << 2u; - alt param { - dict_param_dict(d) { h += hash_dict_id(d); } - dict_param_ty(t) { h += ty::type_id(t); } - } - } - h -} - -// Used to identify cached monomorphized functions -type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: [dict_id]}; -fn hash_mono_id(&&mi: mono_id) -> uint { - let h = syntax::ast_util::hash_def_id(mi.def); - for ty in mi.substs { h = (h << 2u) + ty::type_id(ty); } - for dict in mi.dicts { h = (h << 2u) + hash_dict_id(dict); } - h -} - -fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { - let cond = build::ICmp(cx, lib::llvm::IntULT, a, b); - ret build::Select(cx, cond, b, a); -} - -fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef { - let cond = build::ICmp(cx, lib::llvm::IntULT, a, b); - ret build::Select(cx, cond, a, b); -} - -fn align_to(cx: block, off: ValueRef, align: ValueRef) -> ValueRef { - let mask = build::Sub(cx, align, C_int(cx.ccx(), 1)); - let bumped = build::Add(cx, off, mask); - ret build::And(cx, bumped, build::Not(cx, mask)); -} - -fn path_str(p: path) -> str { - let r = "", first = true; - for e in p { - alt e { ast_map::path_name(s) | ast_map::path_mod(s) { - if first { first = false; } - else { r += "::"; } - r += s; - } } - } - r -} - -fn node_id_type(bcx: block, id: ast::node_id) -> ty::t { - let tcx = bcx.tcx(); - let t = ty::node_id_to_type(tcx, id); - alt bcx.fcx.param_substs { - some(substs) { ty::substitute_type_params(tcx, substs.tys, t) } - _ { t } - } -} -fn expr_ty(bcx: block, ex: @ast::expr) -> ty::t { - node_id_type(bcx, ex.id) -} -fn node_id_type_params(bcx: block, id: ast::node_id) -> [ty::t] { - let tcx = bcx.tcx(); - let params = ty::node_id_to_type_params(tcx, id); - alt bcx.fcx.param_substs { - some(substs) { - vec::map(params) {|t| ty::substitute_type_params(tcx, substs.tys, t) } - } - _ { params } - } -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/trans/debuginfo.rs b/src/comp/middle/trans/debuginfo.rs deleted file mode 100644 index 47a3d2e5716..00000000000 --- a/src/comp/middle/trans/debuginfo.rs +++ /dev/null @@ -1,876 +0,0 @@ -import std::fs; -import std::map::hashmap; -import lib::llvm::llvm; -import lib::llvm::ValueRef; -import trans::common::*; -import trans::base; -import trans::build::B; -import middle::ty; -import syntax::{ast, codemap, ast_util}; -import codemap::span; -import ast::ty; -import pat_util::*; -import util::ppaux::ty_to_str; -import driver::session::session; - -export create_local_var; -export create_function; -export create_arg; -export update_source_pos; -export debug_ctxt; - -const LLVMDebugVersion: int = (9 << 16); - -const DW_LANG_RUST: int = 0x9000; -const DW_VIRTUALITY_none: int = 0; - -const CompileUnitTag: int = 17; -const FileDescriptorTag: int = 41; -const SubprogramTag: int = 46; -const SubroutineTag: int = 21; -const BasicTypeDescriptorTag: int = 36; -const AutoVariableTag: int = 256; -const ArgVariableTag: int = 257; -const ReturnVariableTag: int = 258; -const LexicalBlockTag: int = 11; -const PointerTypeTag: int = 15; -const StructureTypeTag: int = 19; -const MemberTag: int = 13; -const ArrayTypeTag: int = 1; -const SubrangeTag: int = 33; - -const DW_ATE_boolean: int = 0x02; -const DW_ATE_float: int = 0x04; -const DW_ATE_signed: int = 0x05; -const DW_ATE_signed_char: int = 0x06; -const DW_ATE_unsigned: int = 0x07; -const DW_ATE_unsigned_char: int = 0x08; - -fn llstr(s: str) -> ValueRef { - str::as_buf(s, {|sbuf| - llvm::LLVMMDString(sbuf, str::len(s) as ctypes::c_uint) - }) -} -fn lltag(lltag: int) -> ValueRef { - lli32(LLVMDebugVersion | lltag) -} -fn lli32(val: int) -> ValueRef { - C_i32(val as i32) -} -fn lli64(val: int) -> ValueRef { - C_i64(val as i64) -} -fn lli1(bval: bool) -> ValueRef { - C_bool(bval) -} -fn llmdnode(elems: [ValueRef]) -> ValueRef unsafe { - llvm::LLVMMDNode(vec::unsafe::to_ptr(elems), - vec::len(elems) as ctypes::c_uint) -} -fn llunused() -> ValueRef { - lli32(0x0) -} -fn llnull() -> ValueRef unsafe { - unsafe::reinterpret_cast(ptr::null::<ValueRef>()) -} - -fn add_named_metadata(cx: crate_ctxt, name: str, val: ValueRef) { - str::as_buf(name, {|sbuf| - llvm::LLVMAddNamedMetadataOperand(cx.llmod, sbuf, - val) - }) -} - -//////////////// - -type debug_ctxt = { - llmetadata: metadata_cache, - names: namegen -}; - -fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) { - let existing = if cache.contains_key(mdtag) { - cache.get(mdtag) - } else { - [] - }; - cache.insert(mdtag, existing + [val]); -} - -type metadata<T> = {node: ValueRef, data: T}; - -type file_md = {path: str}; -type compile_unit_md = {path: str}; -type subprogram_md = {id: ast::node_id}; -type local_var_md = {id: ast::node_id}; -type tydesc_md = {hash: uint}; -type block_md = {start: codemap::loc, end: codemap::loc}; -type argument_md = {id: ast::node_id}; -type retval_md = {id: ast::node_id}; - -type metadata_cache = hashmap<int, [debug_metadata]>; - -enum debug_metadata { - file_metadata(@metadata<file_md>), - compile_unit_metadata(@metadata<compile_unit_md>), - subprogram_metadata(@metadata<subprogram_md>), - local_var_metadata(@metadata<local_var_md>), - tydesc_metadata(@metadata<tydesc_md>), - block_metadata(@metadata<block_md>), - argument_metadata(@metadata<argument_md>), - retval_metadata(@metadata<retval_md>), -} - -fn cast_safely<T: copy, U>(val: T) -> U unsafe { - let val2 = val; - let val3 = unsafe::reinterpret_cast(val2); - unsafe::leak(val2); - ret val3; -} - -fn md_from_metadata<T>(val: debug_metadata) -> T unsafe { - alt val { - file_metadata(md) { cast_safely(md) } - compile_unit_metadata(md) { cast_safely(md) } - subprogram_metadata(md) { cast_safely(md) } - local_var_metadata(md) { cast_safely(md) } - tydesc_metadata(md) { cast_safely(md) } - block_metadata(md) { cast_safely(md) } - argument_metadata(md) { cast_safely(md) } - retval_metadata(md) { cast_safely(md) } - } -} - -fn cached_metadata<T: copy>(cache: metadata_cache, mdtag: int, - eq: fn(md: T) -> bool) -> option<T> unsafe { - if cache.contains_key(mdtag) { - let items = cache.get(mdtag); - for item in items { - let md: T = md_from_metadata::<T>(item); - if eq(md) { - ret option::some(md); - } - } - } - ret option::none; -} - -fn create_compile_unit(cx: crate_ctxt, full_path: str) - -> @metadata<compile_unit_md> unsafe { - let cache = get_cache(cx); - let tg = CompileUnitTag; - alt cached_metadata::<@metadata<compile_unit_md>>(cache, tg, - {|md| md.data.path == full_path}) { - option::some(md) { ret md; } - option::none {} - } - - let work_dir = cx.sess.working_dir; - let file_path = if str::starts_with(full_path, work_dir) { - str::slice(full_path, str::len(work_dir), str::len(full_path)) - } else { - full_path - }; - let unit_metadata = [lltag(tg), - llunused(), - lli32(DW_LANG_RUST), - llstr(file_path), - llstr(work_dir), - llstr(#env["CFG_VERSION"]), - lli1(false), // main compile unit - lli1(cx.sess.opts.optimize != 0u), - llstr(""), // flags (???) - lli32(0) // runtime version (???) - // list of enum types - // list of retained values - // list of subprograms - // list of global variables - ]; - let unit_node = llmdnode(unit_metadata); - add_named_metadata(cx, "llvm.dbg.cu", unit_node); - let mdval = @{node: unit_node, data: {path: full_path}}; - update_cache(cache, tg, compile_unit_metadata(mdval)); - ret mdval; -} - -fn get_cache(cx: crate_ctxt) -> metadata_cache { - option::get(cx.dbg_cx).llmetadata -} - -fn create_file(cx: crate_ctxt, full_path: str) -> @metadata<file_md> { - let cache = get_cache(cx);; - let tg = FileDescriptorTag; - alt cached_metadata::<@metadata<file_md>>( - cache, tg, {|md| md.data.path == full_path}) { - option::some(md) { ret md; } - option::none {} - } - - let fname = fs::basename(full_path); - let path = fs::dirname(full_path); - let unit_node = create_compile_unit(cx, full_path).node; - let file_md = [lltag(tg), - llstr(fname), - llstr(path), - unit_node]; - let val = llmdnode(file_md); - let mdval = @{node: val, data: {path: full_path}}; - update_cache(cache, tg, file_metadata(mdval)); - ret mdval; -} - -fn line_from_span(cm: codemap::codemap, sp: span) -> uint { - codemap::lookup_char_pos(cm, sp.lo).line -} - -fn create_block(cx: block) -> @metadata<block_md> { - let cache = get_cache(cx.ccx()); - let cx = cx; - while option::is_none(cx.block_span) { - alt cx.parent { - parent_some(b) { cx = b; } - parent_none { fail; } - } - } - let sp = option::get(cx.block_span); - - let start = codemap::lookup_char_pos(cx.sess().codemap, - sp.lo); - let fname = start.file.name; - let end = codemap::lookup_char_pos(cx.sess().codemap, - sp.hi); - let tg = LexicalBlockTag; - /*alt cached_metadata::<@metadata<block_md>>( - cache, tg, - {|md| start == md.data.start && end == md.data.end}) { - option::some(md) { ret md; } - option::none {} - }*/ - - let parent = alt cx.parent { - parent_none { create_function(cx.fcx).node } - parent_some(bcx) { create_block(bcx).node } - }; - let file_node = create_file(cx.ccx(), fname); - let unique_id = alt cache.find(LexicalBlockTag) { - option::some(v) { vec::len(v) as int } - option::none { 0 } - }; - let lldata = [lltag(tg), - parent, - lli32(start.line as int), - lli32(start.col as int), - file_node.node, - lli32(unique_id) - ]; - let val = llmdnode(lldata); - let mdval = @{node: val, data: {start: start, end: end}}; - //update_cache(cache, tg, block_metadata(mdval)); - ret mdval; -} - -fn size_and_align_of<T>() -> (int, int) { - (sys::size_of::<T>() as int, sys::align_of::<T>() as int) -} - -fn create_basic_type(cx: crate_ctxt, t: ty::t, ty: ast::prim_ty, span: span) - -> @metadata<tydesc_md> { - let cache = get_cache(cx); - let tg = BasicTypeDescriptorTag; - alt cached_metadata::<@metadata<tydesc_md>>( - cache, tg, {|md| ty::type_id(t) == md.data.hash}) { - option::some(md) { ret md; } - option::none {} - } - - let (name, (size, align), encoding) = alt check ty { - ast::ty_bool {("bool", size_and_align_of::<bool>(), DW_ATE_boolean)} - ast::ty_int(m) { alt m { - ast::ty_char {("char", size_and_align_of::<char>(), DW_ATE_unsigned)} - ast::ty_i {("int", size_and_align_of::<int>(), DW_ATE_signed)} - ast::ty_i8 {("i8", size_and_align_of::<i8>(), DW_ATE_signed_char)} - ast::ty_i16 {("i16", size_and_align_of::<i16>(), DW_ATE_signed)} - ast::ty_i32 {("i32", size_and_align_of::<i32>(), DW_ATE_signed)} - ast::ty_i64 {("i64", size_and_align_of::<i64>(), DW_ATE_signed)} - }} - ast::ty_uint(m) { alt m { - ast::ty_u {("uint", size_and_align_of::<uint>(), DW_ATE_unsigned)} - ast::ty_u8 {("u8", size_and_align_of::<u8>(), DW_ATE_unsigned_char)} - ast::ty_u16 {("u16", size_and_align_of::<u16>(), DW_ATE_unsigned)} - ast::ty_u32 {("u32", size_and_align_of::<u32>(), DW_ATE_unsigned)} - ast::ty_u64 {("u64", size_and_align_of::<u64>(), DW_ATE_unsigned)} - }} - ast::ty_float(m) { alt m { - ast::ty_f {("float", size_and_align_of::<float>(), DW_ATE_float)} - ast::ty_f32 {("f32", size_and_align_of::<f32>(), DW_ATE_float)} - ast::ty_f64 {("f64", size_and_align_of::<f64>(), DW_ATE_float)} - }} - }; - - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname); - let cu_node = create_compile_unit(cx, fname); - let lldata = [lltag(tg), - cu_node.node, - llstr(name), - file_node.node, - lli32(0), //XXX source line - lli64(size * 8), // size in bits - lli64(align * 8), // alignment in bits - lli64(0), //XXX offset? - lli32(0), //XXX flags? - lli32(encoding)]; - let llnode = llmdnode(lldata); - let mdval = @{node: llnode, data: {hash: ty::type_id(t)}}; - update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, "llvm.dbg.ty", llnode); - ret mdval; -} - -fn create_pointer_type(cx: crate_ctxt, t: ty::t, span: span, - pointee: @metadata<tydesc_md>) - -> @metadata<tydesc_md> { - let tg = PointerTypeTag; - /*let cache = cx.llmetadata; - alt cached_metadata::<@metadata<tydesc_md>>( - cache, tg, {|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) { - option::some(md) { ret md; } - option::none {} - }*/ - let (size, align) = size_and_align_of::<ctypes::intptr_t>(); - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname); - //let cu_node = create_compile_unit(cx, fname); - let llnode = create_derived_type(tg, file_node.node, "", 0, size * 8, - align * 8, 0, pointee.node); - let mdval = @{node: llnode, data: {hash: ty::type_id(t)}}; - //update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, "llvm.dbg.ty", llnode); - ret mdval; -} - -type struct_ctxt = { - file: ValueRef, - name: str, - line: int, - mutable members: [ValueRef], - mutable total_size: int, - align: int -}; - -fn finish_structure(cx: @struct_ctxt) -> ValueRef { - ret create_composite_type(StructureTypeTag, cx.name, cx.file, cx.line, - cx.total_size, cx.align, 0, option::none, - option::some(cx.members)); -} - -fn create_structure(file: @metadata<file_md>, name: str, line: int) - -> @struct_ctxt { - let cx = @{file: file.node, - name: name, - line: line, - mutable members: [], - mutable total_size: 0, - align: 64 //XXX different alignment per arch? - }; - ret cx; -} - -fn create_derived_type(type_tag: int, file: ValueRef, name: str, line: int, - size: int, align: int, offset: int, ty: ValueRef) - -> ValueRef { - let lldata = [lltag(type_tag), - file, - llstr(name), - file, - lli32(line), - lli64(size), - lli64(align), - lli64(offset), - lli32(0), - ty]; - ret llmdnode(lldata); -} - -fn add_member(cx: @struct_ctxt, name: str, line: int, size: int, align: int, - ty: ValueRef) { - cx.members += [create_derived_type(MemberTag, cx.file, name, line, - size * 8, align * 8, cx.total_size, - ty)]; - cx.total_size += size * 8; -} - -fn create_record(cx: crate_ctxt, t: ty::t, fields: [ast::ty_field], - span: span) -> @metadata<tydesc_md> { - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname); - let scx = create_structure(file_node, - option::get(cx.dbg_cx).names("rec"), - line_from_span(cx.sess.codemap, - span) as int); - for field in fields { - let field_t = ty::get_field(t, field.node.ident).mt.ty; - let ty_md = create_ty(cx, field_t, field.node.mt.ty); - let (size, align) = member_size_and_align(cx.tcx, field.node.mt.ty); - add_member(scx, field.node.ident, - line_from_span(cx.sess.codemap, field.span) as int, - size as int, align as int, ty_md.node); - } - let mdval = @{node: finish_structure(scx), data:{hash: ty::type_id(t)}}; - ret mdval; -} - -fn create_boxed_type(cx: crate_ctxt, outer: ty::t, _inner: ty::t, - span: span, boxed: @metadata<tydesc_md>) - -> @metadata<tydesc_md> { - //let tg = StructureTypeTag; - /*let cache = cx.llmetadata; - alt cached_metadata::<@metadata<tydesc_md>>( - cache, tg, {|md| ty::hash_ty(outer) == ty::hash_ty(md.data.hash)}) { - option::some(md) { ret md; } - option::none {} - }*/ - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname); - //let cu_node = create_compile_unit_metadata(cx, fname); - let uint_t = ty::mk_uint(cx.tcx); - let refcount_type = create_basic_type(cx, uint_t, - ast::ty_uint(ast::ty_u), span); - let scx = create_structure(file_node, ty_to_str(cx.tcx, outer), 0); - add_member(scx, "refcnt", 0, sys::size_of::<uint>() as int, - sys::align_of::<uint>() as int, refcount_type.node); - add_member(scx, "boxed", 0, 8, //XXX member_size_and_align(??) - 8, //XXX just a guess - boxed.node); - let llnode = finish_structure(scx); - let mdval = @{node: llnode, data: {hash: ty::type_id(outer)}}; - //update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, "llvm.dbg.ty", llnode); - ret mdval; -} - -fn create_composite_type(type_tag: int, name: str, file: ValueRef, line: int, - size: int, align: int, offset: int, - derived: option<ValueRef>, - members: option<[ValueRef]>) - -> ValueRef { - let lldata = [lltag(type_tag), - file, - llstr(name), // type name - file, // source file definition - lli32(line), // source line definition - lli64(size), // size of members - lli64(align), // align - lli64(offset), // offset - lli32(0), // flags - if option::is_none(derived) { - llnull() - } else { // derived from - option::get(derived) - }, - if option::is_none(members) { - llnull() - } else { //members - llmdnode(option::get(members)) - }, - lli32(0), // runtime language - llnull() - ]; - ret llmdnode(lldata); -} - -fn create_vec(cx: crate_ctxt, vec_t: ty::t, elem_t: ty::t, - vec_ty_span: codemap::span, elem_ty: @ast::ty) - -> @metadata<tydesc_md> { - let fname = filename_from_span(cx, vec_ty_span); - let file_node = create_file(cx, fname); - let elem_ty_md = create_ty(cx, elem_t, elem_ty); - let scx = create_structure(file_node, ty_to_str(cx.tcx, vec_t), 0); - let size_t_type = create_basic_type(cx, ty::mk_uint(cx.tcx), - ast::ty_uint(ast::ty_u), vec_ty_span); - add_member(scx, "fill", 0, sys::size_of::<ctypes::size_t>() as int, - sys::align_of::<ctypes::size_t>() as int, size_t_type.node); - add_member(scx, "alloc", 0, sys::size_of::<ctypes::size_t>() as int, - sys::align_of::<ctypes::size_t>() as int, size_t_type.node); - let subrange = llmdnode([lltag(SubrangeTag), lli64(0), lli64(0)]); - let (arr_size, arr_align) = member_size_and_align(cx.tcx, elem_ty); - let data_ptr = create_composite_type(ArrayTypeTag, "", file_node.node, 0, - arr_size, arr_align, 0, - option::some(elem_ty_md.node), - option::some([subrange])); - add_member(scx, "data", 0, 0, // clang says the size should be 0 - sys::align_of::<u8>() as int, data_ptr); - let llnode = finish_structure(scx); - ret @{node: llnode, data: {hash: ty::type_id(vec_t)}}; -} - -fn member_size_and_align(tcx: ty::ctxt, ty: @ast::ty) -> (int, int) { - alt ty.node { - ast::ty_path(_, id) { - alt check tcx.def_map.get(id) { - ast::def_prim_ty(nty) { - alt check nty { - ast::ty_bool { size_and_align_of::<bool>() } - ast::ty_int(m) { alt m { - ast::ty_char { size_and_align_of::<char>() } - ast::ty_i { size_and_align_of::<int>() } - ast::ty_i8 { size_and_align_of::<i8>() } - ast::ty_i16 { size_and_align_of::<i16>() } - ast::ty_i32 { size_and_align_of::<i32>() } - ast::ty_i64 { size_and_align_of::<i64>() } - }} - ast::ty_uint(m) { alt m { - ast::ty_u { size_and_align_of::<uint>() } - ast::ty_u8 { size_and_align_of::<i8>() } - ast::ty_u16 { size_and_align_of::<u16>() } - ast::ty_u32 { size_and_align_of::<u32>() } - ast::ty_u64 { size_and_align_of::<u64>() } - }} - ast::ty_float(m) { alt m { - ast::ty_f { size_and_align_of::<float>() } - ast::ty_f32 { size_and_align_of::<f32>() } - ast::ty_f64 { size_and_align_of::<f64>() } - }} - } - } - } - } - ast::ty_box(_) | ast::ty_uniq(_) { - size_and_align_of::<ctypes::uintptr_t>() - } - ast::ty_rec(fields) { - let total_size = 0; - for field in fields { - let (size, _) = member_size_and_align(tcx, field.node.mt.ty); - total_size += size; - } - (total_size, 64) //XXX different align for other arches? - } - ast::ty_vec(_) { - size_and_align_of::<ctypes::uintptr_t>() - } - _ { fail "member_size_and_align: can't handle this type"; } - } -} - -fn create_ty(_cx: crate_ctxt, _t: ty::t, _ty: @ast::ty) - -> @metadata<tydesc_md> { - /*let cache = get_cache(cx); - alt cached_metadata::<@metadata<tydesc_md>>( - cache, tg, {|md| t == md.data.hash}) { - option::some(md) { ret md; } - option::none {} - }*/ - - /* FIXME I am disabling this code as part of the patch that moves - * recognition of named builtin types into resolve. I tried to fix - * it, but it seems to already be broken -- it's only called when - * --xg is given, and compiling with --xg fails on trivial programs. - * - * Generating an ast::ty from a ty::t seems like it should not be - * needed. It is only done to track spans, but you will not get the - * right spans anyway -- types tend to refer to stuff defined - * elsewhere, not be self-contained. - */ - - fail; - /* - fn t_to_ty(cx: crate_ctxt, t: ty::t, span: span) -> @ast::ty { - let ty = alt ty::get(t).struct { - ty::ty_nil { ast::ty_nil } - ty::ty_bot { ast::ty_bot } - ty::ty_bool { ast::ty_bool } - ty::ty_int(t) { ast::ty_int(t) } - ty::ty_float(t) { ast::ty_float(t) } - ty::ty_uint(t) { ast::ty_uint(t) } - ty::ty_box(mt) { ast::ty_box({ty: t_to_ty(cx, mt.ty, span), - mutbl: mt.mutbl}) } - ty::ty_uniq(mt) { ast::ty_uniq({ty: t_to_ty(cx, mt.ty, span), - mutbl: mt.mutbl}) } - ty::ty_rec(fields) { - let fs = []; - for field in fields { - fs += [{node: {ident: field.ident, - mt: {ty: t_to_ty(cx, field.mt.ty, span), - mutbl: field.mt.mutbl}}, - span: span}]; - } - ast::ty_rec(fs) - } - ty::ty_vec(mt) { ast::ty_vec({ty: t_to_ty(cx, mt.ty, span), - mutbl: mt.mutbl}) } - _ { - cx.sess.span_bug(span, "t_to_ty: Can't handle this type"); - } - }; - ret @{node: ty, span: span}; - } - - alt ty.node { - ast::ty_box(mt) { - let inner_t = alt ty::get(t).struct { - ty::ty_box(boxed) { boxed.ty } - _ { cx.sess.span_bug(ty.span, "t_to_ty was incoherent"); } - }; - let md = create_ty(cx, inner_t, mt.ty); - let box = create_boxed_type(cx, t, inner_t, ty.span, md); - ret create_pointer_type(cx, t, ty.span, box); - } - - ast::ty_uniq(mt) { - let inner_t = alt ty::get(t).struct { - ty::ty_uniq(boxed) { boxed.ty } - // Hoping we'll have a way to eliminate this check soon. - _ { cx.sess.span_bug(ty.span, "t_to_ty was incoherent"); } - }; - let md = create_ty(cx, inner_t, mt.ty); - ret create_pointer_type(cx, t, ty.span, md); - } - - ast::ty_infer { - let inferred = t_to_ty(cx, t, ty.span); - ret create_ty(cx, t, inferred); - } - - ast::ty_rec(fields) { - ret create_record(cx, t, fields, ty.span); - } - - ast::ty_vec(mt) { - let inner_t = ty::sequence_element_type(cx.tcx, t); - let inner_ast_t = t_to_ty(cx, inner_t, mt.ty.span); - let v = create_vec(cx, t, inner_t, ty.span, inner_ast_t); - ret create_pointer_type(cx, t, ty.span, v); - } - - ast::ty_path(_, id) { - alt cx.tcx.def_map.get(id) { - ast::def_prim_ty(pty) { - ret create_basic_type(cx, t, pty, ty.span); - } - _ {} - } - } - - _ {} - }; - */ -} - -fn filename_from_span(cx: crate_ctxt, sp: codemap::span) -> str { - codemap::lookup_char_pos(cx.sess.codemap, sp.lo).file.name -} - -fn create_var(type_tag: int, context: ValueRef, name: str, file: ValueRef, - line: int, ret_ty: ValueRef) -> ValueRef { - let lldata = [lltag(type_tag), - context, - llstr(name), - file, - lli32(line), - ret_ty, - lli32(0) - ]; - ret llmdnode(lldata); -} - -fn create_local_var(bcx: block, local: @ast::local) - -> @metadata<local_var_md> unsafe { - let cx = bcx.ccx(); - let cache = get_cache(cx); - let tg = AutoVariableTag; - alt cached_metadata::<@metadata<local_var_md>>( - cache, tg, {|md| md.data.id == local.node.id}) { - option::some(md) { ret md; } - option::none {} - } - - let name = alt local.node.pat.node { - ast::pat_ident(pth, _) { pat_util::path_to_ident(pth) } - // FIXME this should be handled - _ { fail "no single variable name for local"; } - }; - let loc = codemap::lookup_char_pos(cx.sess.codemap, - local.span.lo); - let ty = node_id_type(bcx, local.node.id); - let tymd = create_ty(cx, ty, local.node.ty); - let filemd = create_file(cx, loc.file.name); - let context = alt bcx.parent { - parent_none { create_function(bcx.fcx).node } - parent_some(_) { create_block(bcx).node } - }; - let mdnode = create_var(tg, context, name, filemd.node, - loc.line as int, tymd.node); - let mdval = @{node: mdnode, data: {id: local.node.id}}; - update_cache(cache, AutoVariableTag, local_var_metadata(mdval)); - - let llptr = alt bcx.fcx.lllocals.find(local.node.id) { - option::some(local_mem(v)) { v } - option::some(_) { - bcx.tcx().sess.span_bug(local.span, "local is bound to \ - something weird"); - } - option::none { - alt bcx.fcx.lllocals.get(local.node.pat.id) { - local_imm(v) { v } - _ { bcx.tcx().sess.span_bug(local.span, "local is bound to \ - something weird"); } - } - } - }; - let declargs = [llmdnode([llptr]), mdnode]; - trans::build::Call(bcx, cx.intrinsics.get("llvm.dbg.declare"), - declargs); - ret mdval; -} - -fn create_arg(bcx: block, arg: ast::arg, sp: span) - -> @metadata<argument_md> unsafe { - let fcx = bcx.fcx, cx = fcx.ccx; - let cache = get_cache(cx); - let tg = ArgVariableTag; - alt cached_metadata::<@metadata<argument_md>>( - cache, ArgVariableTag, {|md| md.data.id == arg.id}) { - option::some(md) { ret md; } - option::none {} - } - - let loc = codemap::lookup_char_pos(cx.sess.codemap, - sp.lo); - let ty = node_id_type(bcx, arg.id); - let tymd = create_ty(cx, ty, arg.ty); - let filemd = create_file(cx, loc.file.name); - let context = create_function(bcx.fcx); - let mdnode = create_var(tg, context.node, arg.ident, filemd.node, - loc.line as int, tymd.node); - let mdval = @{node: mdnode, data: {id: arg.id}}; - update_cache(cache, tg, argument_metadata(mdval)); - - let llptr = alt fcx.llargs.get(arg.id) { - local_mem(v) | local_imm(v) { v } - }; - let declargs = [llmdnode([llptr]), mdnode]; - trans::build::Call(bcx, cx.intrinsics.get("llvm.dbg.declare"), - declargs); - ret mdval; -} - -fn update_source_pos(cx: block, s: span) { - if !cx.sess().opts.debuginfo { - ret; - } - let cm = cx.sess().codemap; - let blockmd = create_block(cx); - let loc = codemap::lookup_char_pos(cm, s.lo); - let scopedata = [lli32(loc.line as int), - lli32(loc.col as int), - blockmd.node, - llnull()]; - let dbgscope = llmdnode(scopedata); - llvm::LLVMSetCurrentDebugLocation(trans::build::B(cx), dbgscope); -} - -fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> { - let cx = fcx.ccx; - let dbg_cx = option::get(cx.dbg_cx); - - #debug("~~"); - log(debug, fcx.id); - - let sp = option::get(fcx.span); - log(debug, codemap::span_to_str(sp, cx.sess.codemap)); - - let (ident, ret_ty, id) = alt cx.tcx.items.get(fcx.id) { - ast_map::node_item(item, _) { - alt item.node { - ast::item_fn(decl, _, _) | ast::item_res(decl, _, _, _, _) { - (item.ident, decl.output, item.id) - } - _ { fcx.ccx.sess.span_bug(item.span, "create_function: item \ - bound to non-function"); } - } - } - ast_map::node_method(method, _, _) { - (method.ident, method.decl.output, method.id) - } - ast_map::node_res_ctor(item) { - alt item.node { - ast::item_res(decl, _, _, _, ctor_id) { - (item.ident, decl.output, ctor_id) - } - _ { fcx.ccx.sess.span_bug(item.span, "create_function: \ - expected an item_res here"); } - } - } - ast_map::node_expr(expr) { - alt expr.node { - ast::expr_fn(_, decl, _, _) { - (dbg_cx.names("fn"), decl.output, expr.id) - } - ast::expr_fn_block(decl, _) { - (dbg_cx.names("fn"), decl.output, expr.id) - } - _ { fcx.ccx.sess.span_bug(expr.span, "create_function: \ - expected an expr_fn or fn_block here"); } - } - } - _ { fcx.ccx.sess.bug("create_function: unexpected \ - sort of node"); } - }; - - log(debug, ident); - log(debug, id); - - let cache = get_cache(cx); - alt cached_metadata::<@metadata<subprogram_md>>( - cache, SubprogramTag, {|md| md.data.id == id}) { - option::some(md) { ret md; } - option::none {} - } - - let path = path_str(fcx.path); - - let loc = codemap::lookup_char_pos(cx.sess.codemap, - sp.lo); - let file_node = create_file(cx, loc.file.name).node; - let key = if cx.item_symbols.contains_key(fcx.id) { fcx.id } else { id }; - let mangled = cx.item_symbols.get(key); - let ty_node = if cx.sess.opts.extra_debuginfo { - alt ret_ty.node { - ast::ty_nil { llnull() } - _ { create_ty(cx, ty::node_id_to_type(cx.tcx, id), ret_ty).node } - } - } else { - llnull() - }; - let sub_node = create_composite_type(SubroutineTag, "", file_node, 0, 0, - 0, 0, option::none, - option::some([ty_node])); - - let fn_metadata = [lltag(SubprogramTag), - llunused(), - file_node, - llstr(ident), - llstr(path), //XXX fully-qualified C++ name - llstr(mangled), //XXX MIPS name????? - file_node, - lli32(loc.line as int), - sub_node, - lli1(false), //XXX static (check export) - lli1(true), // not extern - lli32(DW_VIRTUALITY_none), // virtual-ness - lli32(0i), //index into virt func - llnull(), // base type with vtbl - lli1(false), // artificial - lli1(cx.sess.opts.optimize != 0u), - fcx.llfn - //list of template params - //func decl descriptor - //list of func vars - ]; - let val = llmdnode(fn_metadata); - add_named_metadata(cx, "llvm.dbg.sp", val); - let mdval = @{node: val, data: {id: id}}; - update_cache(cache, SubprogramTag, subprogram_metadata(mdval)); - ret mdval; -} diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs deleted file mode 100644 index b3660e3f672..00000000000 --- a/src/comp/middle/trans/impl.rs +++ /dev/null @@ -1,547 +0,0 @@ -import ctypes::c_uint; -import base::*; -import common::*; -import type_of::*; -import build::*; -import driver::session::session; -import syntax::{ast, ast_util}; -import metadata::csearch; -import back::{link, abi}; -import lib::llvm::llvm; -import lib::llvm::{ValueRef, TypeRef}; -import lib::llvm::llvm::LLVMGetParam; -import ast_map::{path, path_mod, path_name}; - -// Translation functionality related to impls and ifaces -// -// Terminology: -// vtable: a table of function pointers pointing to method wrappers -// of an impl that implements an iface -// dict: a record containing a vtable pointer along with pointers to -// all tydescs and other dicts needed to run methods in this vtable -// (i.e. corresponding to the type parameters of the impl) -// wrapper: a function that takes a dict as first argument, along -// with the method-specific tydescs for a method (and all -// other args the method expects), which fetches the extra -// tydescs and dicts from the dict, splices them into the -// arglist, and calls through to the actual method -// -// Generic functions take, along with their normal arguments, a number -// of extra tydesc and dict arguments -- one tydesc for each type -// parameter, one dict (following the tydesc in the arg order) for -// each interface bound on a type parameter. -// -// Most dicts are completely static, and are allocated and filled at -// compile time. Dicts that depend on run-time values (tydescs or -// dicts for type parameter types) are built at run-time, and interned -// through upcall_intern_dict in the runtime. This means that dict -// pointers are self-contained things that do not need to be cleaned -// up. -// -// The trans_constants pass in trans.rs outputs the vtables. Typeck -// annotates nodes with information about the methods and dicts that -// are referenced (ccx.method_map and ccx.dict_map). - -fn trans_impl(ccx: crate_ctxt, path: path, name: ast::ident, - methods: [@ast::method], id: ast::node_id, - tps: [ast::ty_param]) { - let sub_path = path + [path_name(name)]; - for m in methods { - alt ccx.item_ids.find(m.id) { - some(llfn) { - let m_bounds = param_bounds(ccx, tps + m.tps); - trans_fn(ccx, sub_path + [path_name(m.ident)], m.decl, m.body, - llfn, impl_self(ty::node_id_to_type(ccx.tcx, id)), - m_bounds, none, m.id); - } - _ { - ccx.sess.bug("Unbound id in trans_impl"); - } - } - } -} - -fn trans_self_arg(bcx: block, base: @ast::expr) -> result { - let basety = expr_ty(bcx, base); - let m_by_ref = ast::expl(ast::by_ref); - let temp_cleanups = []; - let result = trans_arg_expr(bcx, {mode: m_by_ref, ty: basety}, - T_ptr(type_of_or_i8(bcx.ccx(), basety)), base, - temp_cleanups); - - // by-ref self argument should not require cleanup in the case of - // other arguments failing: - assert temp_cleanups == []; - - ret result; -} - -fn trans_method_callee(bcx: block, callee_id: ast::node_id, - self: @ast::expr, origin: typeck::method_origin) - -> lval_maybe_callee { - alt origin { - typeck::method_static(did) { - trans_static_callee(bcx, callee_id, self, did, none) - } - typeck::method_param(iid, off, p, b) { - alt bcx.fcx.param_substs { - some(substs) { - trans_monomorphized_callee(bcx, callee_id, self, - iid, off, p, b, substs) - } - none { - trans_param_callee(bcx, callee_id, self, iid, off, p, b) - } - } - } - typeck::method_iface(iid, off) { - trans_iface_callee(bcx, callee_id, self, iid, off) - } - } -} - -// Method callee where the method is statically known -fn trans_static_callee(bcx: block, callee_id: ast::node_id, - base: @ast::expr, did: ast::def_id, - substs: option<([ty::t], typeck::dict_res)>) - -> lval_maybe_callee { - let {bcx, val} = trans_self_arg(bcx, base); - {env: self_env(val, node_id_type(bcx, base.id)) - with lval_static_fn(bcx, did, callee_id, substs)} -} - -fn wrapper_fn_ty(ccx: crate_ctxt, dict_ty: TypeRef, fty: ty::t, - tps: @[ty::param_bounds]) -> {ty: ty::t, llty: TypeRef} { - let bare_fn_ty = type_of_fn_from_ty(ccx, fty, *tps); - let {inputs, output} = llfn_arg_tys(bare_fn_ty); - {ty: fty, llty: T_fn([dict_ty] + inputs, output)} -} - -fn trans_vtable_callee(bcx: block, env: callee_env, dict: ValueRef, - callee_id: ast::node_id, iface_id: ast::def_id, - n_method: uint) -> lval_maybe_callee { - let bcx = bcx, ccx = bcx.ccx(), tcx = ccx.tcx; - let method = ty::iface_methods(tcx, iface_id)[n_method]; - let method_ty = ty::mk_fn(tcx, method.fty); - let {ty: fty, llty: llfty} = - wrapper_fn_ty(ccx, val_ty(dict), method_ty, method.tps); - let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])), - T_ptr(T_array(T_ptr(llfty), n_method + 1u))); - let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int])); - let generic = generic_none; - if (*method.tps).len() > 0u || ty::type_has_params(fty) { - let tydescs = [], tis = []; - let tptys = node_id_type_params(bcx, callee_id); - for t in vec::tail_n(tptys, tptys.len() - (*method.tps).len()) { - let ti = none; - let td = get_tydesc(bcx, t, true, ti); - tis += [ti]; - tydescs += [td.val]; - bcx = td.bcx; - } - generic = generic_full({item_type: fty, - static_tis: tis, - tydescs: tydescs, - param_bounds: method.tps, - origins: ccx.maps.dict_map.find(callee_id)}); - } - {bcx: bcx, val: mptr, kind: owned, - env: env, - generic: generic} -} - -fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id, - base: @ast::expr, iface_id: ast::def_id, - n_method: uint, n_param: uint, n_bound: uint, - substs: param_substs) -> lval_maybe_callee { - alt find_dict_in_fn_ctxt(substs, n_param, n_bound) { - typeck::dict_static(impl_did, tys, sub_origins) { - let tcx = bcx.tcx(); - if impl_did.crate != ast::local_crate { - ret trans_param_callee(bcx, callee_id, base, iface_id, - n_method, n_param, n_bound); - } - let mname = ty::iface_methods(tcx, iface_id)[n_method].ident; - let mth = alt check tcx.items.get(impl_did.node) { - ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) { - option::get(vec::find(ms, {|m| m.ident == mname})) - } - }; - ret trans_static_callee(bcx, callee_id, base, - ast_util::local_def(mth.id), - some((tys, sub_origins))); - } - typeck::dict_iface(iid) { - ret trans_iface_callee(bcx, callee_id, base, iid, n_method); - } - typeck::dict_param(n_param, n_bound) { - fail "dict_param left in monomorphized function's dict substs"; - } - } -} - - -// Method callee where the dict comes from a type param -fn trans_param_callee(bcx: block, callee_id: ast::node_id, - base: @ast::expr, iface_id: ast::def_id, n_method: uint, - n_param: uint, n_bound: uint) -> lval_maybe_callee { - let {bcx, val} = trans_self_arg(bcx, base); - let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound]; - trans_vtable_callee(bcx, dict_env(dict, val), dict, - callee_id, iface_id, n_method) -} - -// Method callee where the dict comes from a boxed iface -fn trans_iface_callee(bcx: block, callee_id: ast::node_id, - base: @ast::expr, iface_id: ast::def_id, n_method: uint) - -> lval_maybe_callee { - let {bcx, val} = trans_temp_expr(bcx, base); - let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]), - T_ptr(T_ptr(T_dict())))); - let box = Load(bcx, GEPi(bcx, val, [0, 1])); - // FIXME[impl] I doubt this is alignment-safe - let self = GEPi(bcx, box, [0, abi::box_field_body]); - trans_vtable_callee(bcx, dict_env(dict, self), dict, - callee_id, iface_id, n_method) -} - -fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} { - let out_ty = llvm::LLVMGetReturnType(ft); - let n_args = llvm::LLVMCountParamTypes(ft); - let args = vec::init_elt(n_args as uint, 0 as TypeRef); - unsafe { llvm::LLVMGetParamTypes(ft, vec::unsafe::to_ptr(args)); } - {inputs: args, output: out_ty} -} - -fn trans_vtable(ccx: crate_ctxt, id: ast::node_id, name: str, - ptrs: [ValueRef]) { - let tbl = C_struct(ptrs); - let vt_gvar = str::as_buf(name, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf) - }); - llvm::LLVMSetInitializer(vt_gvar, tbl); - llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True); - ccx.item_ids.insert(id, vt_gvar); - ccx.item_symbols.insert(id, name); -} - -fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint) - -> typeck::dict_origin { - let dict_off = n_bound, i = 0u; - // Dicts are stored in a flat array, finding the right one is - // somewhat awkward - for bounds in *ps.bounds { - i += 1u; - if i >= n_param { break; } - for bound in *bounds { - alt bound { ty::bound_iface(_) { dict_off += 1u; } _ {} } - } - } - option::get(ps.dicts)[dict_off] -} - -fn resolve_dicts_in_fn_ctxt(fcx: fn_ctxt, dicts: typeck::dict_res) - -> option<typeck::dict_res> { - let result = []; - for dict in *dicts { - result += [alt dict { - typeck::dict_static(iid, tys, sub) { - alt resolve_dicts_in_fn_ctxt(fcx, sub) { - some(sub) { - let tys = alt fcx.param_substs { - some(substs) { - vec::map(tys, {|t| - ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t) - }) - } - _ { tys } - }; - typeck::dict_static(iid, tys, sub) - } - none { ret none; } - } - } - typeck::dict_param(n_param, n_bound) { - alt fcx.param_substs { - some(substs) { - find_dict_in_fn_ctxt(substs, n_param, n_bound) - } - none { ret none; } - } - } - _ { dict } - }]; - } - some(@result) -} - -fn trans_wrapper(ccx: crate_ctxt, pt: path, llfty: TypeRef, - fill: fn(ValueRef, block) -> block) - -> ValueRef { - let name = link::mangle_internal_name_by_path(ccx, pt); - let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty); - let fcx = new_fn_ctxt(ccx, [], llfn, none); - let bcx = top_scope_block(fcx, none), lltop = bcx.llbb; - let bcx = fill(llfn, bcx); - build_return(bcx); - finish_fn(fcx, lltop); - ret llfn; -} - -fn trans_impl_wrapper(ccx: crate_ctxt, pt: path, - extra_tps: [ty::param_bounds], real_fn: ValueRef) - -> ValueRef { - let {inputs: real_args, output: real_ret} = - llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn))); - let extra_ptrs = []; - for tp in extra_tps { - extra_ptrs += [T_ptr(ccx.tydesc_type)]; - for bound in *tp { - alt bound { - ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; } - _ {} - } - } - } - let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs)); - let n_extra_ptrs = extra_ptrs.len(); - - let wrap_args = [T_ptr(T_dict())] + - vec::slice(real_args, 0u, first_tp_arg) + - vec::slice(real_args, first_tp_arg + n_extra_ptrs, real_args.len()); - let llfn_ty = T_fn(wrap_args, real_ret); - trans_wrapper(ccx, pt, llfn_ty, {|llfn, bcx| - let dict = PointerCast(bcx, LLVMGetParam(llfn, 0 as c_uint), env_ty); - // retptr, self - let args = [LLVMGetParam(llfn, 1 as c_uint), - LLVMGetParam(llfn, 2 as c_uint)]; - let i = 0u; - // saved tydescs/dicts - while i < n_extra_ptrs { - i += 1u; - args += [load_inbounds(bcx, dict, [0, i as int])]; - } - // the rest of the parameters - let j = 3u as c_uint; - let params_total = llvm::LLVMCountParamTypes(llfn_ty); - while j < params_total { - args += [LLVMGetParam(llfn, j)]; - j += 1u as c_uint; - } - Call(bcx, real_fn, args); - bcx - }) -} - -fn trans_impl_vtable(ccx: crate_ctxt, pt: path, - iface_id: ast::def_id, ms: [@ast::method], - tps: [ast::ty_param], it: @ast::item) { - let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)), - path_name("wrap")]; - let extra_tps = param_bounds(ccx, tps); - let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im| - alt vec::find(ms, {|m| m.ident == im.ident}) { - some(m) { - let target = ccx.item_ids.get(m.id); - trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)], - extra_tps, target) - } - _ { - ccx.sess.span_bug(it.span, "No matching method \ - in trans_impl_vtable"); - } - } - }); - let s = link::mangle_internal_name_by_path( - ccx, new_pt + [path_name("!vtable")]); - trans_vtable(ccx, it.id, s, ptrs); -} - -fn trans_iface_wrapper(ccx: crate_ctxt, pt: path, m: ty::method, - n: uint) -> ValueRef { - let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()), - ty::mk_fn(ccx.tcx, m.fty), m.tps); - trans_wrapper(ccx, pt, llfty, {|llfn, bcx| - let param = PointerCast(bcx, LLVMGetParam(llfn, 2u as c_uint), - T_ptr(T_opaque_iface(ccx))); - let dict = Load(bcx, GEPi(bcx, param, [0, 0])); - let box = Load(bcx, GEPi(bcx, param, [0, 1])); - let self = GEPi(bcx, box, [0, abi::box_field_body]); - let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])), - T_ptr(T_array(T_ptr(llfty), n + 1u))); - let mptr = Load(bcx, GEPi(bcx, vtable, [0, n as int])); - let args = [PointerCast(bcx, dict, T_ptr(T_i8())), - LLVMGetParam(llfn, 1u as c_uint), - PointerCast(bcx, self, T_opaque_cbox_ptr(ccx))]; - let i = 3u as c_uint, total = llvm::LLVMCountParamTypes(llfty); - while i < total { - args += [LLVMGetParam(llfn, i)]; - i += 1u as c_uint; - } - Call(bcx, mptr, args); - bcx - }) -} - -fn trans_iface_vtable(ccx: crate_ctxt, pt: path, it: @ast::item) { - let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))]; - let i_did = ast_util::local_def(it.id), i = 0u; - let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m| - let w = trans_iface_wrapper(ccx, new_pt + [path_name(m.ident)], m, i); - i += 1u; - w - }); - let s = link::mangle_internal_name_by_path( - ccx, new_pt + [path_name("!vtable")]); - trans_vtable(ccx, it.id, s, ptrs); -} - -fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool { - alt origin { - typeck::dict_static(_, ts, origs) { - vec::all(ts, {|t| !ty::type_has_params(t)}) && - vec::all(*origs, {|o| dict_is_static(tcx, o)}) - } - typeck::dict_iface(_) { true } - _ { false } - } -} - -fn get_dict(bcx: block, origin: typeck::dict_origin) -> result { - let ccx = bcx.ccx(); - alt origin { - typeck::dict_static(impl_did, tys, sub_origins) { - if dict_is_static(ccx.tcx, origin) { - ret rslt(bcx, get_static_dict(bcx, origin)); - } - let {bcx, ptrs} = get_dict_ptrs(bcx, origin); - let pty = T_ptr(T_i8()), dict_ty = T_array(pty, ptrs.len()); - let dict = alloca(bcx, dict_ty), i = 0; - for ptr in ptrs { - Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i])); - i += 1; - } - dict = Call(bcx, ccx.upcalls.intern_dict, - [C_uint(ccx, ptrs.len()), - PointerCast(bcx, dict, T_ptr(T_dict()))]); - rslt(bcx, dict) - } - typeck::dict_param(n_param, n_bound) { - rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound]) - } - typeck::dict_iface(did) { - ret rslt(bcx, get_static_dict(bcx, origin)); - } - } -} - -fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id { - alt origin { - typeck::dict_static(did, ts, origs) { - let d_params = [], orig = 0u; - if ts.len() == 0u { ret @{def: did, params: d_params}; } - let impl_params = ty::lookup_item_type(tcx, did).bounds; - vec::iter2(ts, *impl_params) {|t, bounds| - d_params += [dict_param_ty(t)]; - for bound in *bounds { - alt bound { - ty::bound_iface(_) { - d_params += [dict_param_dict(dict_id(tcx, origs[orig]))]; - orig += 1u; - } - _ {} - } - } - } - @{def: did, params: d_params} - } - typeck::dict_iface(did) { - @{def: did, params: []} - } - _ { - tcx.sess.bug("Unexpected dict_param in dict_id"); - } - } -} - -fn get_static_dict(bcx: block, origin: typeck::dict_origin) - -> ValueRef { - let ccx = bcx.ccx(); - let id = dict_id(ccx.tcx, origin); - alt ccx.dicts.find(id) { - some(d) { ret d; } - none {} - } - let ptrs = C_struct(get_dict_ptrs(bcx, origin).ptrs); - let name = ccx.names("dict"); - let gvar = str::as_buf(name, {|buf| - llvm::LLVMAddGlobal(ccx.llmod, val_ty(ptrs), buf) - }); - llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True); - llvm::LLVMSetInitializer(gvar, ptrs); - lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage); - let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict())); - ccx.dicts.insert(id, cast); - cast -} - -fn get_dict_ptrs(bcx: block, origin: typeck::dict_origin) - -> {bcx: block, ptrs: [ValueRef]} { - let ccx = bcx.ccx(); - fn get_vtable(ccx: crate_ctxt, did: ast::def_id) -> ValueRef { - if did.crate == ast::local_crate { - ccx.item_ids.get(did.node) - } else { - let name = csearch::get_symbol(ccx.sess.cstore, did); - get_extern_const(ccx.externs, ccx.llmod, name, T_ptr(T_i8())) - } - } - alt origin { - typeck::dict_static(impl_did, tys, sub_origins) { - let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds; - let ptrs = [get_vtable(ccx, impl_did)]; - let origin = 0u, bcx = bcx; - vec::iter2(*impl_params, tys) {|param, ty| - let rslt = get_tydesc_simple(bcx, ty, true); - ptrs += [rslt.val]; - bcx = rslt.bcx; - for bound in *param { - alt bound { - ty::bound_iface(_) { - let res = get_dict(bcx, sub_origins[origin]); - ptrs += [res.val]; - bcx = res.bcx; - origin += 1u; - } - _ {} - } - } - } - {bcx: bcx, ptrs: ptrs} - } - typeck::dict_iface(did) { - {bcx: bcx, ptrs: [get_vtable(ccx, did)]} - } - _ { - bcx.tcx().sess.bug("Unexpected dict_param in get_dict_ptrs"); - } - } -} - -fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest) - -> block { - if dest == ignore { ret trans_expr(bcx, val, ignore); } - let ccx = bcx.ccx(); - let v_ty = expr_ty(bcx, val); - let {bcx, box, body} = trans_malloc_boxed(bcx, v_ty); - add_clean_free(bcx, box, false); - bcx = trans_expr_save_in(bcx, val, body); - revoke_clean(bcx, box); - let result = get_dest_addr(dest); - Store(bcx, box, PointerCast(bcx, GEPi(bcx, result, [0, 1]), - T_ptr(val_ty(box)))); - let {bcx, val: dict} = get_dict(bcx, ccx.maps.dict_map.get(id)[0]); - Store(bcx, dict, PointerCast(bcx, GEPi(bcx, result, [0, 0]), - T_ptr(val_ty(dict)))); - bcx -} diff --git a/src/comp/middle/trans/native.rs b/src/comp/middle/trans/native.rs deleted file mode 100644 index 22791047ef9..00000000000 --- a/src/comp/middle/trans/native.rs +++ /dev/null @@ -1,359 +0,0 @@ -import driver::session::session; -import syntax::codemap::span; -import ctypes::c_uint; -import front::attr; -import lib::llvm::{ llvm, TypeRef, ValueRef }; -import syntax::ast; -import back::link; -import common::*; -import build::*; -import base::*; -import type_of::*; - -export link_name, trans_native_mod, register_crust_fn, trans_crust_fn; - -fn link_name(i: @ast::native_item) -> str { - alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") { - none { ret i.ident; } - option::some(ln) { ret ln; } - } -} - -type c_stack_tys = { - arg_tys: [TypeRef], - ret_ty: TypeRef, - ret_def: bool, - bundle_ty: TypeRef, - shim_fn_ty: TypeRef -}; - -fn c_arg_and_ret_lltys(ccx: crate_ctxt, - id: ast::node_id) -> ([TypeRef], TypeRef, ty::t) { - alt ty::get(ty::node_id_to_type(ccx.tcx, id)).struct { - ty::ty_fn({inputs: arg_tys, output: ret_ty, _}) { - let llargtys = type_of_explicit_args(ccx, arg_tys); - let llretty = type_of::type_of(ccx, ret_ty); - (llargtys, llretty, ret_ty) - } - _ { ccx.sess.bug("c_arg_and_ret_lltys called on non-function type"); } - } -} - -fn c_stack_tys(ccx: crate_ctxt, - id: ast::node_id) -> @c_stack_tys { - let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, id); - let bundle_ty = T_struct(llargtys + [T_ptr(llretty)]); - ret @{ - arg_tys: llargtys, - ret_ty: llretty, - ret_def: !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty), - bundle_ty: bundle_ty, - shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void()) - }; -} - -type shim_arg_builder = fn(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef) -> [ValueRef]; - -type shim_ret_builder = fn(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef, llretval: ValueRef); - -fn build_shim_fn_(ccx: crate_ctxt, - shim_name: str, - llbasefn: ValueRef, - tys: @c_stack_tys, - cc: lib::llvm::CallConv, - arg_builder: shim_arg_builder, - ret_builder: shim_ret_builder) -> ValueRef { - - let llshimfn = decl_internal_cdecl_fn( - ccx.llmod, shim_name, tys.shim_fn_ty); - - // Declare the body of the shim function: - let fcx = new_fn_ctxt(ccx, [], llshimfn, none); - let bcx = top_scope_block(fcx, none); - let lltop = bcx.llbb; - let llargbundle = llvm::LLVMGetParam(llshimfn, 0 as c_uint); - let llargvals = arg_builder(bcx, tys, llargbundle); - - // Create the call itself and store the return value: - let llretval = CallWithConv(bcx, llbasefn, - llargvals, cc); // r - - ret_builder(bcx, tys, llargbundle, llretval); - - build_return(bcx); - finish_fn(fcx, lltop); - - ret llshimfn; -} - -type wrap_arg_builder = fn(bcx: block, tys: @c_stack_tys, - llwrapfn: ValueRef, - llargbundle: ValueRef); - -type wrap_ret_builder = fn(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef); - -fn build_wrap_fn_(ccx: crate_ctxt, - tys: @c_stack_tys, - llshimfn: ValueRef, - llwrapfn: ValueRef, - shim_upcall: ValueRef, - arg_builder: wrap_arg_builder, - ret_builder: wrap_ret_builder) { - - let fcx = new_fn_ctxt(ccx, [], llwrapfn, none); - let bcx = top_scope_block(fcx, none); - let lltop = bcx.llbb; - - // Allocate the struct and write the arguments into it. - let llargbundle = alloca(bcx, tys.bundle_ty); - arg_builder(bcx, tys, llwrapfn, llargbundle); - - // Create call itself. - let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8())); - let llrawargbundle = PointerCast(bcx, llargbundle, T_ptr(T_i8())); - Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]); - ret_builder(bcx, tys, llargbundle); - - tie_up_header_blocks(fcx, lltop); - - // Make sure our standard return block (that we didn't use) is terminated - let ret_cx = raw_block(fcx, fcx.llreturn); - Unreachable(ret_cx); -} - -// For each native function F, we generate a wrapper function W and a shim -// function S that all work together. The wrapper function W is the function -// that other rust code actually invokes. Its job is to marshall the -// arguments into a struct. It then uses a small bit of assembly to switch -// over to the C stack and invoke the shim function. The shim function S then -// unpacks the arguments from the struct and invokes the actual function F -// according to its specified calling convention. -// -// Example: Given a native c-stack function F(x: X, y: Y) -> Z, -// we generate a wrapper function W that looks like: -// -// void W(Z* dest, void *env, X x, Y y) { -// struct { X x; Y y; Z *z; } args = { x, y, z }; -// call_on_c_stack_shim(S, &args); -// } -// -// The shim function S then looks something like: -// -// void S(struct { X x; Y y; Z *z; } *args) { -// *args->z = F(args->x, args->y); -// } -// -// However, if the return type of F is dynamically sized or of aggregate type, -// the shim function looks like: -// -// void S(struct { X x; Y y; Z *z; } *args) { -// F(args->z, args->x, args->y); -// } -// -// Note: on i386, the layout of the args struct is generally the same as the -// desired layout of the arguments on the C stack. Therefore, we could use -// upcall_alloc_c_stack() to allocate the `args` structure and switch the -// stack pointer appropriately to avoid a round of copies. (In fact, the shim -// function itself is unnecessary). We used to do this, in fact, and will -// perhaps do so in the future. -fn trans_native_mod(ccx: crate_ctxt, - native_mod: ast::native_mod, abi: ast::native_abi) { - fn build_shim_fn(ccx: crate_ctxt, - native_item: @ast::native_item, - tys: @c_stack_tys, - cc: lib::llvm::CallConv) -> ValueRef { - - fn build_args(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef) -> [ValueRef] { - let llargvals = []; - let i = 0u; - let n = vec::len(tys.arg_tys); - while i < n { - let llargval = load_inbounds(bcx, llargbundle, [0, i as int]); - llargvals += [llargval]; - i += 1u; - } - ret llargvals; - } - - fn build_ret(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef, llretval: ValueRef) { - if tys.ret_def { - let n = vec::len(tys.arg_tys); - // R** llretptr = &args->r; - let llretptr = GEPi(bcx, llargbundle, [0, n as int]); - // R* llretloc = *llretptr; /* (args->r) */ - let llretloc = Load(bcx, llretptr); - // *args->r = r; - Store(bcx, llretval, llretloc); - } - } - - let lname = link_name(native_item); - // Declare the "prototype" for the base function F: - let llbasefnty = T_fn(tys.arg_tys, tys.ret_ty); - let llbasefn = decl_fn(ccx.llmod, lname, cc, llbasefnty); - // Name the shim function - let shim_name = lname + "__c_stack_shim"; - ret build_shim_fn_(ccx, shim_name, llbasefn, tys, cc, - build_args, build_ret); - } - - fn build_wrap_fn(ccx: crate_ctxt, - tys: @c_stack_tys, - num_tps: uint, - llshimfn: ValueRef, - llwrapfn: ValueRef) { - - fn build_args(bcx: block, tys: @c_stack_tys, - llwrapfn: ValueRef, llargbundle: ValueRef, - num_tps: uint) { - let i = 0u, n = vec::len(tys.arg_tys); - let implicit_args = first_tp_arg + num_tps; // ret + env - while i < n { - let llargval = llvm::LLVMGetParam( - llwrapfn, - (i + implicit_args) as c_uint); - store_inbounds(bcx, llargval, llargbundle, [0, i as int]); - i += 1u; - } - let llretptr = llvm::LLVMGetParam(llwrapfn, 0 as c_uint); - store_inbounds(bcx, llretptr, llargbundle, [0, n as int]); - } - - fn build_ret(bcx: block, _tys: @c_stack_tys, - _llargbundle: ValueRef) { - RetVoid(bcx); - } - - build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, - ccx.upcalls.call_shim_on_c_stack, - bind build_args(_, _ ,_ , _, num_tps), - build_ret); - } - - let cc = lib::llvm::CCallConv; - alt abi { - ast::native_abi_rust_intrinsic { ret; } - ast::native_abi_cdecl { cc = lib::llvm::CCallConv; } - ast::native_abi_stdcall { cc = lib::llvm::X86StdcallCallConv; } - } - - for native_item in native_mod.items { - alt native_item.node { - ast::native_item_fn(fn_decl, tps) { - let id = native_item.id; - let tys = c_stack_tys(ccx, id); - alt ccx.item_ids.find(id) { - some(llwrapfn) { - let llshimfn = build_shim_fn(ccx, native_item, tys, cc); - build_wrap_fn(ccx, tys, vec::len(tps), llshimfn, llwrapfn); - } - none { - ccx.sess.span_bug( - native_item.span, - "unbound function item in trans_native_mod"); - } - } - } - } - } -} - -fn trans_crust_fn(ccx: crate_ctxt, path: ast_map::path, decl: ast::fn_decl, - body: ast::blk, llwrapfn: ValueRef, id: ast::node_id) { - - fn build_rust_fn(ccx: crate_ctxt, path: ast_map::path, - decl: ast::fn_decl, body: ast::blk, - id: ast::node_id) -> ValueRef { - let t = ty::node_id_to_type(ccx.tcx, id); - let ps = link::mangle_internal_name_by_path( - ccx, path + [ast_map::path_name("__rust_abi")]); - let llty = type_of_fn_from_ty(ccx, t, []); - let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty); - trans_fn(ccx, path, decl, body, llfndecl, no_self, [], none, id); - ret llfndecl; - } - - fn build_shim_fn(ccx: crate_ctxt, path: ast_map::path, - llrustfn: ValueRef, tys: @c_stack_tys) -> ValueRef { - - fn build_args(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef) -> [ValueRef] { - let llargvals = []; - let i = 0u; - let n = vec::len(tys.arg_tys); - let llretptr = load_inbounds(bcx, llargbundle, [0, n as int]); - llargvals += [llretptr]; - let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx())); - llargvals += [llenvptr]; - while i < n { - let llargval = load_inbounds(bcx, llargbundle, [0, i as int]); - llargvals += [llargval]; - i += 1u; - } - ret llargvals; - } - - fn build_ret(_bcx: block, _tys: @c_stack_tys, - _llargbundle: ValueRef, _llretval: ValueRef) { - // Nop. The return pointer in the Rust ABI function - // is wired directly into the return slot in the shim struct - } - - let shim_name = link::mangle_internal_name_by_path( - ccx, path + [ast_map::path_name("__rust_stack_shim")]); - ret build_shim_fn_(ccx, shim_name, llrustfn, tys, - lib::llvm::CCallConv, - build_args, build_ret); - } - - fn build_wrap_fn(ccx: crate_ctxt, llshimfn: ValueRef, - llwrapfn: ValueRef, tys: @c_stack_tys) { - - fn build_args(bcx: block, tys: @c_stack_tys, - llwrapfn: ValueRef, llargbundle: ValueRef) { - let llretptr = alloca(bcx, tys.ret_ty); - let i = 0u, n = vec::len(tys.arg_tys); - while i < n { - let llargval = llvm::LLVMGetParam( - llwrapfn, i as c_uint); - store_inbounds(bcx, llargval, llargbundle, [0, i as int]); - i += 1u; - } - store_inbounds(bcx, llretptr, llargbundle, [0, n as int]); - } - - fn build_ret(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef) { - let n = vec::len(tys.arg_tys); - let llretval = load_inbounds(bcx, llargbundle, [0, n as int]); - let llretval = Load(bcx, llretval); - Ret(bcx, llretval); - } - - build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, - ccx.upcalls.call_shim_on_rust_stack, - build_args, build_ret); - } - - let tys = c_stack_tys(ccx, id); - // The internal Rust ABI function - runs on the Rust stack - let llrustfn = build_rust_fn(ccx, path, decl, body, id); - // The internal shim function - runs on the Rust stack - let llshimfn = build_shim_fn(ccx, path, llrustfn, tys); - // The external C function - runs on the C stack - build_wrap_fn(ccx, llshimfn, llwrapfn, tys) -} - -fn register_crust_fn(ccx: crate_ctxt, sp: span, - path: ast_map::path, node_id: ast::node_id) { - let t = ty::node_id_to_type(ccx.tcx, node_id); - let (llargtys, llretty, _) = c_arg_and_ret_lltys(ccx, node_id); - let llfty = T_fn(llargtys, llretty); - register_fn_fuller(ccx, sp, path, "crust fn", node_id, - t, lib::llvm::CCallConv, llfty); -} \ No newline at end of file diff --git a/src/comp/middle/trans/shape.rs b/src/comp/middle/trans/shape.rs deleted file mode 100644 index 2805778e927..00000000000 --- a/src/comp/middle/trans/shape.rs +++ /dev/null @@ -1,787 +0,0 @@ -// A "shape" is a compact encoding of a type that is used by interpreted glue. -// This substitutes for the runtime tags used by e.g. MLs. - -import lib::llvm::llvm; -import lib::llvm::{True, False, ModuleRef, TypeRef, ValueRef}; -import driver::session; -import driver::session::session; -import trans::base; -import middle::trans::common::*; -import back::abi; -import middle::ty; -import middle::ty::field; -import syntax::ast; -import syntax::ast_util::dummy_sp; -import syntax::util::interner; -import util::common; -import trans::build::{Load, Store, Add, GEPi}; -import syntax::codemap::span; - -import std::map::hashmap; - -import ty_ctxt = middle::ty::ctxt; - -type res_info = {did: ast::def_id, t: ty::t}; - -type ctxt = - {mutable next_tag_id: u16, - pad: u16, - tag_id_to_index: hashmap<ast::def_id, u16>, - mutable tag_order: [ast::def_id], - resources: interner::interner<res_info>, - llshapetablesty: TypeRef, - llshapetables: ValueRef}; - -const shape_u8: u8 = 0u8; -const shape_u16: u8 = 1u8; -const shape_u32: u8 = 2u8; -const shape_u64: u8 = 3u8; -const shape_i8: u8 = 4u8; -const shape_i16: u8 = 5u8; -const shape_i32: u8 = 6u8; -const shape_i64: u8 = 7u8; -const shape_f32: u8 = 8u8; -const shape_f64: u8 = 9u8; -const shape_box: u8 = 10u8; -const shape_vec: u8 = 11u8; -const shape_enum: u8 = 12u8; -const shape_box_old: u8 = 13u8; // deprecated, remove after snapshot -const shape_struct: u8 = 17u8; -const shape_box_fn: u8 = 18u8; -const shape_UNUSED: u8 = 19u8; -const shape_res: u8 = 20u8; -const shape_var: u8 = 21u8; -const shape_uniq: u8 = 22u8; -const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself. -const shape_uniq_fn: u8 = 25u8; -const shape_stack_fn: u8 = 26u8; -const shape_bare_fn: u8 = 27u8; -const shape_tydesc: u8 = 28u8; -const shape_send_tydesc: u8 = 29u8; -const shape_class: u8 = 30u8; - -fn hash_res_info(ri: res_info) -> uint { - let h = 5381u; - h *= 33u; - h += ri.did.crate as uint; - h *= 33u; - h += ri.did.node as uint; - h *= 33u; - h += ty::type_id(ri.t); - ret h; -} - -fn eq_res_info(a: res_info, b: res_info) -> bool { - ret a.did.crate == b.did.crate && a.did.node == b.did.node && a.t == b.t; -} - -fn mk_global(ccx: crate_ctxt, name: str, llval: ValueRef, internal: bool) -> - ValueRef { - let llglobal = - str::as_buf(name, - {|buf| - lib::llvm::llvm::LLVMAddGlobal(ccx.llmod, - val_ty(llval), buf) - }); - lib::llvm::llvm::LLVMSetInitializer(llglobal, llval); - lib::llvm::llvm::LLVMSetGlobalConstant(llglobal, True); - - if internal { - lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage); - } - - ret llglobal; -} - - -// Computes a set of variants of a enum that are guaranteed to have size and -// alignment at least as large as any other variant of the enum. This is an -// important performance optimization. -// -// FIXME: Use this in dynamic_size_of() as well. - -fn largest_variants(ccx: crate_ctxt, tag_id: ast::def_id) -> [uint] { - // Compute the minimum and maximum size and alignment for each variant. - // - // FIXME: We could do better here; e.g. we know that any variant that - // contains (T,T) must be as least as large as any variant that contains - // just T. - let ranges = []; - let variants = ty::enum_variants(ccx.tcx, tag_id); - for variant: ty::variant_info in *variants { - let bounded = true; - let {a: min_size, b: min_align} = {a: 0u, b: 0u}; - for elem_t: ty::t in variant.args { - if ty::type_has_params(elem_t) { - // FIXME: We could do better here; this causes us to - // conservatively assume that (int, T) has minimum size 0, - // when in fact it has minimum size sizeof(int). - bounded = false; - } else { - let llty = type_of::type_of(ccx, elem_t); - min_size += llsize_of_real(ccx, llty); - min_align += llalign_of_real(ccx, llty); - } - } - - ranges += - [{size: {min: min_size, bounded: bounded}, - align: {min: min_align, bounded: bounded}}]; - } - - // Initialize the candidate set to contain all variants. - let candidates = [mutable]; - for variant in *variants { candidates += [mutable true]; } - - // Do a pairwise comparison among all variants still in the candidate set. - // Throw out any variant that we know has size and alignment at least as - // small as some other variant. - let i = 0u; - while i < vec::len(ranges) - 1u { - if candidates[i] { - let j = i + 1u; - while j < vec::len(ranges) { - if candidates[j] { - if ranges[i].size.bounded && ranges[i].align.bounded && - ranges[j].size.bounded && ranges[j].align.bounded { - if ranges[i].size >= ranges[j].size && - ranges[i].align >= ranges[j].align { - // Throw out j. - candidates[j] = false; - } else if ranges[j].size >= ranges[i].size && - ranges[j].align >= ranges[j].align { - // Throw out i. - candidates[i] = false; - } - } - } - j += 1u; - } - } - i += 1u; - } - - // Return the resulting set. - let result = []; - i = 0u; - while i < vec::len(candidates) { - if candidates[i] { result += [i]; } - i += 1u; - } - ret result; -} - -fn round_up(size: u16, align: u8) -> u16 { - assert (align >= 1u8); - let alignment = align as u16; - ret size - 1u16 + alignment & !(alignment - 1u16); -} - -type size_align = {size: u16, align: u8}; - -fn compute_static_enum_size(ccx: crate_ctxt, largest_variants: [uint], - did: ast::def_id) -> size_align { - let max_size = 0u16; - let max_align = 1u8; - let variants = ty::enum_variants(ccx.tcx, did); - for vid: uint in largest_variants { - // We increment a "virtual data pointer" to compute the size. - let lltys = []; - for typ: ty::t in variants[vid].args { - lltys += [type_of::type_of(ccx, typ)]; - } - - let llty = trans::common::T_struct(lltys); - let dp = llsize_of_real(ccx, llty) as u16; - let variant_align = llalign_of_real(ccx, llty) as u8; - - if max_size < dp { max_size = dp; } - if max_align < variant_align { max_align = variant_align; } - } - - // Add space for the enum if applicable. - // FIXME (issue #792): This is wrong. If the enum starts with an 8 byte - // aligned quantity, we don't align it. - if vec::len(*variants) > 1u { - let variant_t = T_enum_variant(ccx); - max_size += llsize_of_real(ccx, variant_t) as u16; - let align = llalign_of_real(ccx, variant_t) as u8; - if max_align < align { max_align = align; } - } - - ret {size: max_size, align: max_align}; -} - -enum enum_kind { - tk_unit, // 1 variant, no data - tk_enum, // N variants, no data - tk_newtype, // 1 variant, data - tk_complex // N variants, no data -} - -fn enum_kind(ccx: crate_ctxt, did: ast::def_id) -> enum_kind { - let variants = ty::enum_variants(ccx.tcx, did); - if vec::any(*variants) {|v| vec::len(v.args) > 0u} { - if vec::len(*variants) == 1u { tk_newtype } - else { tk_complex } - } else { - if vec::len(*variants) <= 1u { tk_unit } - else { tk_enum } - } -} - -// Returns the code corresponding to the pointer size on this architecture. -fn s_int(tcx: ty_ctxt) -> u8 { - ret alt tcx.sess.targ_cfg.arch { - session::arch_x86 { shape_i32 } - session::arch_x86_64 { shape_i64 } - session::arch_arm { shape_i32 } - }; -} - -fn s_uint(tcx: ty_ctxt) -> u8 { - ret alt tcx.sess.targ_cfg.arch { - session::arch_x86 { shape_u32 } - session::arch_x86_64 { shape_u64 } - session::arch_arm { shape_u32 } - }; -} - -fn s_float(tcx: ty_ctxt) -> u8 { - ret alt tcx.sess.targ_cfg.arch { - session::arch_x86 { shape_f64 } - session::arch_x86_64 { shape_f64 } - session::arch_arm { shape_f64 } - }; -} - -fn s_variant_enum_t(tcx: ty_ctxt) -> u8 { - ret s_int(tcx); -} - -fn s_tydesc(_tcx: ty_ctxt) -> u8 { - ret shape_tydesc; -} - -fn s_send_tydesc(_tcx: ty_ctxt) -> u8 { - ret shape_send_tydesc; -} - -fn mk_ctxt(llmod: ModuleRef) -> ctxt { - let llshapetablesty = trans::common::T_named_struct("shapes"); - let llshapetables = str::as_buf("shapes", {|buf| - lib::llvm::llvm::LLVMAddGlobal(llmod, llshapetablesty, buf) - }); - - ret {mutable next_tag_id: 0u16, - pad: 0u16, - tag_id_to_index: common::new_def_hash(), - mutable tag_order: [], - resources: interner::mk(hash_res_info, eq_res_info), - llshapetablesty: llshapetablesty, - llshapetables: llshapetables}; -} - -fn add_bool(&dest: [u8], val: bool) { dest += [if val { 1u8 } else { 0u8 }]; } - -fn add_u16(&dest: [u8], val: u16) { - dest += [(val & 0xffu16) as u8, (val >> 8u16) as u8]; -} - -fn add_substr(&dest: [u8], src: [u8]) { - add_u16(dest, vec::len(src) as u16); - dest += src; -} - -fn shape_of(ccx: crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] { - let s = []; - - alt ty::get(t).struct { - ty::ty_nil | ty::ty_bool | ty::ty_uint(ast::ty_u8) | - ty::ty_bot { s += [shape_u8]; } - ty::ty_int(ast::ty_i) { s += [s_int(ccx.tcx)]; } - ty::ty_float(ast::ty_f) { s += [s_float(ccx.tcx)]; } - ty::ty_uint(ast::ty_u) | ty::ty_ptr(_) { s += [s_uint(ccx.tcx)]; } - ty::ty_type { s += [s_tydesc(ccx.tcx)]; } - ty::ty_send_type { s += [s_send_tydesc(ccx.tcx)]; } - ty::ty_int(ast::ty_i8) { s += [shape_i8]; } - ty::ty_uint(ast::ty_u16) { s += [shape_u16]; } - ty::ty_int(ast::ty_i16) { s += [shape_i16]; } - ty::ty_uint(ast::ty_u32) { s += [shape_u32]; } - ty::ty_int(ast::ty_i32) | ty::ty_int(ast::ty_char) {s += [shape_i32];} - ty::ty_uint(ast::ty_u64) { s += [shape_u64]; } - ty::ty_int(ast::ty_i64) { s += [shape_i64]; } - ty::ty_float(ast::ty_f32) { s += [shape_f32]; } - ty::ty_float(ast::ty_f64) { s += [shape_f64]; } - ty::ty_str { - s += [shape_vec]; - add_bool(s, true); // type is POD - let unit_ty = ty::mk_mach_uint(ccx.tcx, ast::ty_u8); - add_substr(s, shape_of(ccx, unit_ty, ty_param_map)); - } - ty::ty_enum(did, tps) { - alt enum_kind(ccx, did) { - tk_unit { - // FIXME: For now we do this. - s += [s_variant_enum_t(ccx.tcx)]; - } - tk_enum { s += [s_variant_enum_t(ccx.tcx)]; } - tk_newtype | tk_complex { - s += [shape_enum]; - - let sub = []; - - let id; - alt ccx.shape_cx.tag_id_to_index.find(did) { - none { - id = ccx.shape_cx.next_tag_id; - ccx.shape_cx.tag_id_to_index.insert(did, id); - ccx.shape_cx.tag_order += [did]; - ccx.shape_cx.next_tag_id += 1u16; - } - some(existing_id) { id = existing_id; } - } - add_u16(sub, id as u16); - - add_u16(sub, vec::len(tps) as u16); - for tp: ty::t in tps { - let subshape = shape_of(ccx, tp, ty_param_map); - add_u16(sub, vec::len(subshape) as u16); - sub += subshape; - } - - s += sub; - } - } - } - ty::ty_box(_) | ty::ty_opaque_box { - s += [shape_box]; - } - ty::ty_uniq(mt) { - s += [shape_uniq]; - add_substr(s, shape_of(ccx, mt.ty, ty_param_map)); - } - ty::ty_vec(mt) { - s += [shape_vec]; - add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty)); - add_substr(s, shape_of(ccx, mt.ty, ty_param_map)); - } - ty::ty_rec(fields) { - s += [shape_struct]; - let sub = []; - for f: field in fields { - sub += shape_of(ccx, f.mt.ty, ty_param_map); - } - add_substr(s, sub); - } - ty::ty_tup(elts) { - s += [shape_struct]; - let sub = []; - for elt in elts { - sub += shape_of(ccx, elt, ty_param_map); - } - add_substr(s, sub); - } - ty::ty_iface(_, _) { s += [shape_box_fn]; } - ty::ty_class(_, _) { s += [shape_class]; } - ty::ty_res(did, raw_subt, tps) { - let subt = ty::substitute_type_params(ccx.tcx, tps, raw_subt); - let ri = {did: did, t: subt}; - let id = interner::intern(ccx.shape_cx.resources, ri); - - s += [shape_res]; - add_u16(s, id as u16); - add_u16(s, vec::len(tps) as u16); - for tp: ty::t in tps { - add_substr(s, shape_of(ccx, tp, ty_param_map)); - } - add_substr(s, shape_of(ccx, subt, ty_param_map)); - - } - ty::ty_param(n, _) { - // Find the type parameter in the parameter list. - alt vec::position_elt(ty_param_map, n) { - some(i) { s += [shape_var, i as u8]; } - none { fail "ty param not found in ty_param_map"; } - } - } - ty::ty_fn({proto: ast::proto_box, _}) { - s += [shape_box_fn]; - } - ty::ty_fn({proto: ast::proto_uniq, _}) { - s += [shape_uniq_fn]; - } - ty::ty_fn({proto: ast::proto_block, _}) | - ty::ty_fn({proto: ast::proto_any, _}) { - s += [shape_stack_fn]; - } - ty::ty_fn({proto: ast::proto_bare, _}) { - s += [shape_bare_fn]; - } - ty::ty_opaque_closure_ptr(_) { - s += [shape_opaque_closure_ptr]; - } - ty::ty_constr(inner_t, _) { - s += shape_of(ccx, inner_t, ty_param_map); - } - ty::ty_var(_) | ty::ty_self(_) { - ccx.sess.bug("shape_of: unexpected type struct found"); - } - } - - ret s; -} - -// FIXME: We might discover other variants as we traverse these. Handle this. -fn shape_of_variant(ccx: crate_ctxt, v: ty::variant_info, - ty_param_count: uint) -> [u8] { - let ty_param_map = []; - let i = 0u; - while i < ty_param_count { ty_param_map += [i]; i += 1u; } - - let s = []; - for t: ty::t in v.args { s += shape_of(ccx, t, ty_param_map); } - ret s; -} - -fn gen_enum_shapes(ccx: crate_ctxt) -> ValueRef { - // Loop over all the enum variants and write their shapes into a - // data buffer. As we do this, it's possible for us to discover - // new enums, so we must do this first. - let i = 0u; - let data = []; - let offsets = []; - while i < vec::len(ccx.shape_cx.tag_order) { - let did = ccx.shape_cx.tag_order[i]; - let variants = ty::enum_variants(ccx.tcx, did); - let item_tyt = ty::lookup_item_type(ccx.tcx, did); - let ty_param_count = vec::len(*item_tyt.bounds); - - vec::iter(*variants) {|v| - offsets += [vec::len(data) as u16]; - - let variant_shape = shape_of_variant(ccx, v, ty_param_count); - add_substr(data, variant_shape); - - let zname = str::bytes(v.name) + [0u8]; - add_substr(data, zname); - } - - i += 1u; - } - - // Now calculate the sizes of the header space (which contains offsets to - // info records for each enum) and the info space (which contains offsets - // to each variant shape). As we do so, build up the header. - - let header = []; - let info = []; - let header_sz = 2u16 * ccx.shape_cx.next_tag_id; - let data_sz = vec::len(data) as u16; - - let info_sz = 0u16; - for did_: ast::def_id in ccx.shape_cx.tag_order { - let did = did_; // Satisfy alias checker. - let num_variants = vec::len(*ty::enum_variants(ccx.tcx, did)) as u16; - add_u16(header, header_sz + info_sz); - info_sz += 2u16 * (num_variants + 2u16) + 3u16; - } - - // Construct the info tables, which contain offsets to the shape of each - // variant. Also construct the largest-variant table for each enum, which - // contains the variants that the size-of operation needs to look at. - - let lv_table = []; - i = 0u; - for did_: ast::def_id in ccx.shape_cx.tag_order { - let did = did_; // Satisfy alias checker. - let variants = ty::enum_variants(ccx.tcx, did); - add_u16(info, vec::len(*variants) as u16); - - // Construct the largest-variants table. - add_u16(info, - header_sz + info_sz + data_sz + (vec::len(lv_table) as u16)); - - let lv = largest_variants(ccx, did); - add_u16(lv_table, vec::len(lv) as u16); - for v: uint in lv { add_u16(lv_table, v as u16); } - - // Determine whether the enum has dynamic size. - let dynamic = false; - for variant: ty::variant_info in *variants { - for typ: ty::t in variant.args { - if ty::type_has_dynamic_size(ccx.tcx, typ) { dynamic = true; } - } - } - - // If we can, write in the static size and alignment of the enum. - // Otherwise, write a placeholder. - let size_align; - if dynamic { - size_align = {size: 0u16, align: 0u8}; - } else { size_align = compute_static_enum_size(ccx, lv, did); } - add_u16(info, size_align.size); - info += [size_align.align]; - - // Now write in the offset of each variant. - for v: ty::variant_info in *variants { - add_u16(info, header_sz + info_sz + offsets[i]); - i += 1u; - } - } - - assert (i == vec::len(offsets)); - assert (header_sz == vec::len(header) as u16); - assert (info_sz == vec::len(info) as u16); - assert (data_sz == vec::len(data) as u16); - - header += info; - header += data; - header += lv_table; - - ret mk_global(ccx, "tag_shapes", C_bytes(header), true); -} - -fn gen_resource_shapes(ccx: crate_ctxt) -> ValueRef { - let dtors = []; - let i = 0u; - let len = interner::len(ccx.shape_cx.resources); - while i < len { - let ri = interner::get(ccx.shape_cx.resources, i); - dtors += [trans::common::get_res_dtor(ccx, ri.did, ri.t)]; - i += 1u; - } - - ret mk_global(ccx, "resource_shapes", C_struct(dtors), true); -} - -fn gen_shape_tables(ccx: crate_ctxt) { - let lltagstable = gen_enum_shapes(ccx); - let llresourcestable = gen_resource_shapes(ccx); - trans::common::set_struct_body(ccx.shape_cx.llshapetablesty, - [val_ty(lltagstable), - val_ty(llresourcestable)]); - - let lltables = - C_named_struct(ccx.shape_cx.llshapetablesty, - [lltagstable, llresourcestable]); - lib::llvm::llvm::LLVMSetInitializer(ccx.shape_cx.llshapetables, lltables); - lib::llvm::llvm::LLVMSetGlobalConstant(ccx.shape_cx.llshapetables, True); - lib::llvm::SetLinkage(ccx.shape_cx.llshapetables, - lib::llvm::InternalLinkage); -} - -// ______________________________________________________________________ -// compute sizeof / alignof - -type metrics = { - bcx: block, - sz: ValueRef, - align: ValueRef -}; - -type tag_metrics = { - bcx: block, - sz: ValueRef, - align: ValueRef, - payload_align: ValueRef -}; - -fn size_of(bcx: block, t: ty::t) -> result { - let ccx = bcx.ccx(); - if check type_has_static_size(ccx, t) { - rslt(bcx, llsize_of(ccx, type_of::type_of(ccx, t))) - } else { - let { bcx, sz, align: _ } = dynamic_metrics(bcx, t); - rslt(bcx, sz) - } -} - -fn align_of(bcx: block, t: ty::t) -> result { - let ccx = bcx.ccx(); - if check type_has_static_size(ccx, t) { - rslt(bcx, llalign_of(ccx, type_of::type_of(ccx, t))) - } else { - let { bcx, sz: _, align } = dynamic_metrics(bcx, t); - rslt(bcx, align) - } -} - -fn metrics(bcx: block, t: ty::t) -> metrics { - let ccx = bcx.ccx(); - if check type_has_static_size(ccx, t) { - let llty = type_of::type_of(ccx, t); - { bcx: bcx, sz: llsize_of(ccx, llty), align: llalign_of(ccx, llty) } - } else { - dynamic_metrics(bcx, t) - } -} - -// Returns the real size of the given type for the current target. -fn llsize_of_real(cx: crate_ctxt, t: TypeRef) -> uint { - ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint; -} - -// Returns the real alignment of the given type for the current target. -fn llalign_of_real(cx: crate_ctxt, t: TypeRef) -> uint { - ret llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, t) as uint; -} - -fn llsize_of(cx: crate_ctxt, t: TypeRef) -> ValueRef { - ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMSizeOf(t), cx.int_type, - False); -} - -fn llalign_of(cx: crate_ctxt, t: TypeRef) -> ValueRef { - ret llvm::LLVMConstIntCast(lib::llvm::llvm::LLVMAlignOf(t), cx.int_type, - False); -} - -// Computes the static size of a enum, without using mk_tup(), which is -// bad for performance. -// -// FIXME: Migrate trans over to use this. - -// Computes the size of the data part of a non-dynamically-sized enum. -fn static_size_of_enum(cx: crate_ctxt, t: ty::t) -> uint { - if cx.enum_sizes.contains_key(t) { ret cx.enum_sizes.get(t); } - alt ty::get(t).struct { - ty::ty_enum(tid, subtys) { - // Compute max(variant sizes). - let max_size = 0u; - let variants = ty::enum_variants(cx.tcx, tid); - for variant: ty::variant_info in *variants { - let tup_ty = simplify_type(cx.tcx, - ty::mk_tup(cx.tcx, variant.args)); - // Perform any type parameter substitutions. - tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty); - // Here we possibly do a recursive call. - let this_size = - llsize_of_real(cx, type_of::type_of(cx, tup_ty)); - if max_size < this_size { max_size = this_size; } - } - cx.enum_sizes.insert(t, max_size); - ret max_size; - } - _ { cx.sess.bug("static_size_of_enum called on non-enum"); } - } -} - -fn dynamic_metrics(cx: block, t: ty::t) -> metrics { - fn align_elements(cx: block, elts: [ty::t]) -> metrics { - // - // C padding rules: - // - // - // - Pad after each element so that next element is aligned. - // - Pad after final structure member so that whole structure - // is aligned to max alignment of interior. - // - - let off = C_int(cx.ccx(), 0); - let max_align = C_int(cx.ccx(), 1); - let bcx = cx; - for e: ty::t in elts { - let elt_align = align_of(bcx, e); - bcx = elt_align.bcx; - let elt_size = size_of(bcx, e); - bcx = elt_size.bcx; - let aligned_off = align_to(bcx, off, elt_align.val); - off = Add(bcx, aligned_off, elt_size.val); - max_align = umax(bcx, max_align, elt_align.val); - } - off = align_to(bcx, off, max_align); - ret { bcx: bcx, sz: off, align: max_align }; - } - - alt ty::get(t).struct { - ty::ty_param(p, _) { - let {bcx, val: tydesc} = base::get_tydesc_simple(cx, t, false); - let szptr = GEPi(bcx, tydesc, [0, abi::tydesc_field_size]); - let aptr = GEPi(bcx, tydesc, [0, abi::tydesc_field_align]); - {bcx: bcx, sz: Load(bcx, szptr), align: Load(bcx, aptr)} - } - ty::ty_rec(flds) { - let tys: [ty::t] = []; - for f: ty::field in flds { tys += [f.mt.ty]; } - align_elements(cx, tys) - } - ty::ty_tup(elts) { - let tys = []; - for tp in elts { tys += [tp]; } - align_elements(cx, tys) - } - ty::ty_enum(tid, tps) { - let bcx = cx; - let ccx = bcx.ccx(); - - let compute_max_variant_size = fn@(bcx: block) -> result { - // Compute max(variant sizes). - let bcx = bcx; - let max_size: ValueRef = C_int(ccx, 0); - let variants = ty::enum_variants(bcx.tcx(), tid); - for variant: ty::variant_info in *variants { - // Perform type substitution on the raw argument types. - let tys = vec::map(variant.args) {|raw_ty| - ty::substitute_type_params(cx.tcx(), tps, raw_ty) - }; - let rslt = align_elements(bcx, tys); - bcx = rslt.bcx; - max_size = umax(bcx, rslt.sz, max_size); - } - rslt(bcx, max_size) - }; - - let {bcx, val: sz} = alt enum_kind(ccx, tid) { - tk_unit | tk_enum { rslt(bcx, llsize_of(ccx, T_enum_variant(ccx))) } - tk_newtype { compute_max_variant_size(bcx) } - tk_complex { - let {bcx, val} = compute_max_variant_size(bcx); - rslt(bcx, Add(bcx, val, llsize_of(ccx, T_enum_variant(ccx)))) - } - }; - - { bcx: bcx, sz: sz, align: C_int(ccx, 1) } - } - _ { - cx.tcx().sess.bug("dynamic_metrics: type has static size"); - } - } -} - -// Creates a simpler, size-equivalent type. The resulting type is guaranteed -// to have (a) the same size as the type that was passed in; (b) to be non- -// recursive. This is done by replacing all boxes in a type with boxed unit -// types. -// This should reduce all pointers to some simple pointer type, to -// ensure that we don't recurse endlessly when computing the size of a -// nominal type that has pointers to itself in it. -fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t { - fn nilptr(tcx: ty::ctxt) -> ty::t { - ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx), mutbl: ast::m_imm}) - } - fn simplifier(tcx: ty::ctxt, typ: ty::t) -> ty::t { - alt ty::get(typ).struct { - ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) | ty::ty_vec(_) | - ty::ty_ptr(_) { nilptr(tcx) } - ty::ty_fn(_) { ty::mk_tup(tcx, [nilptr(tcx), nilptr(tcx)]) } - ty::ty_res(_, sub, tps) { - let sub1 = ty::substitute_type_params(tcx, tps, sub); - ty::mk_tup(tcx, [ty::mk_int(tcx), simplify_type(tcx, sub1)]) - } - _ { typ } - } - } - ty::fold_ty(tcx, ty::fm_general(bind simplifier(tcx, _)), typ) -} - -// Given a tag type `ty`, returns the offset of the payload. -//fn tag_payload_offs(bcx: block, tag_id: ast::def_id, tps: [ty::t]) -// -> ValueRef { -// alt tag_kind(tag_id) { -// tk_unit | tk_enum | tk_newtype { C_int(bcx.ccx(), 0) } -// tk_complex { -// compute_tag_metrics(tag_id, tps) -// } -// } -//} diff --git a/src/comp/middle/trans/tvec.rs b/src/comp/middle/trans/tvec.rs deleted file mode 100644 index aeaf65db7f4..00000000000 --- a/src/comp/middle/trans/tvec.rs +++ /dev/null @@ -1,315 +0,0 @@ -import syntax::ast; -import driver::session::session; -import lib::llvm::{ValueRef, TypeRef}; -import back::abi; -import base::{call_memmove, trans_shared_malloc, - INIT, copy_val, load_if_immediate, get_tydesc, - sub_block, do_spill_noroot, - dest}; -import shape::{llsize_of, size_of}; -import build::*; -import common::*; - -fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef { - Load(bcx, GEPi(bcx, vptr, [0, abi::vec_elt_fill])) -} -fn get_dataptr(bcx: block, vptr: ValueRef, unit_ty: TypeRef) - -> ValueRef { - let ptr = GEPi(bcx, vptr, [0, abi::vec_elt_elems]); - PointerCast(bcx, ptr, T_ptr(unit_ty)) -} - -fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { - let old_ty = val_ty(ptr); - let bptr = PointerCast(bcx, ptr, T_ptr(T_i8())); - ret PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty); -} - -fn alloc_raw(bcx: block, fill: ValueRef, alloc: ValueRef) -> result { - let ccx = bcx.ccx(); - let llvecty = ccx.opaque_vec_type; - let vecsize = Add(bcx, alloc, llsize_of(ccx, llvecty)); - let {bcx: bcx, val: vecptr} = - trans_shared_malloc(bcx, T_ptr(llvecty), vecsize); - Store(bcx, fill, GEPi(bcx, vecptr, [0, abi::vec_elt_fill])); - Store(bcx, alloc, GEPi(bcx, vecptr, [0, abi::vec_elt_alloc])); - ret {bcx: bcx, val: vecptr}; -} - -type alloc_result = - {bcx: block, - val: ValueRef, - unit_ty: ty::t, - llunitsz: ValueRef, - llunitty: TypeRef}; - -fn alloc(bcx: block, vec_ty: ty::t, elts: uint) -> alloc_result { - let ccx = bcx.ccx(); - let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); - let llunitty = type_of::type_of_or_i8(ccx, unit_ty); - let llvecty = T_vec(ccx, llunitty); - let {bcx: bcx, val: unit_sz} = size_of(bcx, unit_ty); - - let fill = Mul(bcx, C_uint(ccx, elts), unit_sz); - let alloc = if elts < 4u { - Mul(bcx, C_int(ccx, 4), unit_sz) - } else { - fill - }; - let {bcx: bcx, val: vptr} = alloc_raw(bcx, fill, alloc); - let vptr = PointerCast(bcx, vptr, T_ptr(llvecty)); - - ret {bcx: bcx, - val: vptr, - unit_ty: unit_ty, - llunitsz: unit_sz, - llunitty: llunitty}; -} - -fn duplicate(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> result { - let ccx = bcx.ccx(); - let fill = get_fill(bcx, vptr); - let size = Add(bcx, fill, llsize_of(ccx, ccx.opaque_vec_type)); - let {bcx: bcx, val: newptr} = - trans_shared_malloc(bcx, val_ty(vptr), size); - let bcx = call_memmove(bcx, newptr, vptr, size).bcx; - let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); - Store(bcx, fill, GEPi(bcx, newptr, [0, abi::vec_elt_alloc])); - if ty::type_needs_drop(bcx.tcx(), unit_ty) { - bcx = iter_vec(bcx, newptr, vec_ty, base::take_ty); - } - ret rslt(bcx, newptr); -} -fn make_free_glue(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> - block { - let tcx = bcx.tcx(), unit_ty = ty::sequence_element_type(tcx, vec_ty); - base::with_cond(bcx, IsNotNull(bcx, vptr)) {|bcx| - let bcx = if ty::type_needs_drop(tcx, unit_ty) { - iter_vec(bcx, vptr, vec_ty, base::drop_ty) - } else { bcx }; - base::trans_shared_free(bcx, vptr) - } -} - -fn trans_vec(bcx: block, args: [@ast::expr], id: ast::node_id, - dest: dest) -> block { - let ccx = bcx.ccx(), bcx = bcx; - if dest == base::ignore { - for arg in args { - bcx = base::trans_expr(bcx, arg, base::ignore); - } - ret bcx; - } - let vec_ty = node_id_type(bcx, id); - let {bcx: bcx, - val: vptr, - llunitsz: llunitsz, - unit_ty: unit_ty, - llunitty: llunitty} = - alloc(bcx, vec_ty, args.len()); - - add_clean_free(bcx, vptr, true); - // Store the individual elements. - let dataptr = get_dataptr(bcx, vptr, llunitty); - let i = 0u, temp_cleanups = [vptr]; - for e in args { - let lleltptr = if ty::type_has_dynamic_size(bcx.tcx(), unit_ty) { - InBoundsGEP(bcx, dataptr, [Mul(bcx, C_uint(ccx, i), llunitsz)]) - } else { InBoundsGEP(bcx, dataptr, [C_uint(ccx, i)]) }; - bcx = base::trans_expr_save_in(bcx, e, lleltptr); - add_clean_temp_mem(bcx, lleltptr, unit_ty); - temp_cleanups += [lleltptr]; - i += 1u; - } - for cln in temp_cleanups { revoke_clean(bcx, cln); } - ret base::store_in_dest(bcx, vptr, dest); -} - -fn trans_str(bcx: block, s: str, dest: dest) -> block { - let veclen = str::len(s) + 1u; // +1 for \0 - let {bcx: bcx, val: sptr, _} = - alloc(bcx, ty::mk_str(bcx.tcx()), veclen); - - let ccx = bcx.ccx(); - let llcstr = C_cstr(ccx, s); - let bcx = call_memmove(bcx, get_dataptr(bcx, sptr, T_i8()), llcstr, - C_uint(ccx, veclen)).bcx; - ret base::store_in_dest(bcx, sptr, dest); -} - -fn trans_append(cx: block, vec_ty: ty::t, lhsptr: ValueRef, - rhs: ValueRef) -> block { - // Cast to opaque interior vector types if necessary. - let ccx = cx.ccx(); - let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty); - let dynamic = ty::type_has_dynamic_size(cx.tcx(), unit_ty); - let (lhsptr, rhs) = - if !dynamic { - (lhsptr, rhs) - } else { - (PointerCast(cx, lhsptr, T_ptr(T_ptr(ccx.opaque_vec_type))), - PointerCast(cx, rhs, T_ptr(ccx.opaque_vec_type))) - }; - let strings = alt check ty::get(vec_ty).struct { - ty::ty_str { true } - ty::ty_vec(_) { false } - }; - - let {bcx: bcx, val: unit_sz} = size_of(cx, unit_ty); - let llunitty = type_of::type_of_or_i8(ccx, unit_ty); - - let lhs = Load(bcx, lhsptr); - let self_append = ICmp(bcx, lib::llvm::IntEQ, lhs, rhs); - let lfill = get_fill(bcx, lhs); - let rfill = get_fill(bcx, rhs); - let new_fill = Add(bcx, lfill, rfill); - if strings { new_fill = Sub(bcx, new_fill, C_int(ccx, 1)); } - let opaque_lhs = PointerCast(bcx, lhsptr, - T_ptr(T_ptr(ccx.opaque_vec_type))); - Call(bcx, cx.ccx().upcalls.vec_grow, - [opaque_lhs, new_fill]); - // Was overwritten if we resized - let lhs = Load(bcx, lhsptr); - rhs = Select(bcx, self_append, lhs, rhs); - - let lhs_data = get_dataptr(bcx, lhs, llunitty); - let lhs_off = lfill; - if strings { lhs_off = Sub(bcx, lhs_off, C_int(ccx, 1)); } - let write_ptr = pointer_add(bcx, lhs_data, lhs_off); - let write_ptr_ptr = do_spill_noroot(bcx, write_ptr); - let bcx = iter_vec_raw(bcx, rhs, vec_ty, rfill, - // We have to increment by the dynamically-computed size. - {|bcx, addr, _ty| - let write_ptr = Load(bcx, write_ptr_ptr); - let bcx = - copy_val(bcx, INIT, write_ptr, - load_if_immediate(bcx, addr, unit_ty), - unit_ty); - let incr = if dynamic { - unit_sz - } else { - C_int(ccx, 1) - }; - Store(bcx, InBoundsGEP(bcx, write_ptr, [incr]), - write_ptr_ptr); - ret bcx; - }); - ret bcx; -} - -fn trans_append_literal(bcx: block, vptrptr: ValueRef, vec_ty: ty::t, - vals: [@ast::expr]) -> block { - let ccx = bcx.ccx(); - let elt_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); - let ti = none; - let {bcx: bcx, val: td} = get_tydesc(bcx, elt_ty, false, ti); - base::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, ti); - let opaque_v = PointerCast(bcx, vptrptr, - T_ptr(T_ptr(ccx.opaque_vec_type))); - for val in vals { - let {bcx: e_bcx, val: elt} = base::trans_temp_expr(bcx, val); - bcx = e_bcx; - let r = base::spill_if_immediate(bcx, elt, elt_ty); - let spilled = r.val; - bcx = r.bcx; - Call(bcx, bcx.ccx().upcalls.vec_push, - [opaque_v, td, PointerCast(bcx, spilled, T_ptr(T_i8()))]); - } - ret bcx; -} - -fn trans_add(bcx: block, vec_ty: ty::t, lhs: ValueRef, - rhs: ValueRef, dest: dest) -> block { - let ccx = bcx.ccx(); - let strings = alt ty::get(vec_ty).struct { - ty::ty_str { true } - _ { false } - }; - let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); - let llunitty = type_of::type_of_or_i8(ccx, unit_ty); - let {bcx: bcx, val: llunitsz} = size_of(bcx, unit_ty); - - let lhs_fill = get_fill(bcx, lhs); - if strings { lhs_fill = Sub(bcx, lhs_fill, C_int(ccx, 1)); } - let rhs_fill = get_fill(bcx, rhs); - let new_fill = Add(bcx, lhs_fill, rhs_fill); - let {bcx: bcx, val: new_vec_ptr} = alloc_raw(bcx, new_fill, new_fill); - new_vec_ptr = PointerCast(bcx, new_vec_ptr, T_ptr(T_vec(ccx, llunitty))); - - let write_ptr_ptr = do_spill_noroot - (bcx, get_dataptr(bcx, new_vec_ptr, llunitty)); - let copy_fn = fn@(bcx: block, addr: ValueRef, - _ty: ty::t) -> block { - let ccx = bcx.ccx(); - let write_ptr = Load(bcx, write_ptr_ptr); - let bcx = copy_val(bcx, INIT, write_ptr, - load_if_immediate(bcx, addr, unit_ty), unit_ty); - let incr = - if ty::type_has_dynamic_size(bcx.tcx(), unit_ty) { - llunitsz - } else { - C_int(ccx, 1) - }; - Store(bcx, InBoundsGEP(bcx, write_ptr, [incr]), - write_ptr_ptr); - ret bcx; - }; - - let bcx = iter_vec_raw(bcx, lhs, vec_ty, lhs_fill, copy_fn); - bcx = iter_vec_raw(bcx, rhs, vec_ty, rhs_fill, copy_fn); - ret base::store_in_dest(bcx, new_vec_ptr, dest); -} - -type val_and_ty_fn = fn@(block, ValueRef, ty::t) -> result; - -type iter_vec_block = fn(block, ValueRef, ty::t) -> block; - -fn iter_vec_raw(bcx: block, vptr: ValueRef, vec_ty: ty::t, - fill: ValueRef, f: iter_vec_block) -> block { - let ccx = bcx.ccx(); - let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); - let llunitty = type_of::type_of_or_i8(ccx, unit_ty); - let {bcx: bcx, val: unit_sz} = size_of(bcx, unit_ty); - let vptr = PointerCast(bcx, vptr, T_ptr(T_vec(ccx, llunitty))); - let data_ptr = get_dataptr(bcx, vptr, llunitty); - - // Calculate the last pointer address we want to handle. - // FIXME: Optimize this when the size of the unit type is statically - // known to not use pointer casts, which tend to confuse LLVM. - let data_end_ptr = pointer_add(bcx, data_ptr, fill); - - // Now perform the iteration. - let header_cx = sub_block(bcx, "iter_vec_loop_header"); - Br(bcx, header_cx.llbb); - let data_ptr = Phi(header_cx, val_ty(data_ptr), [data_ptr], [bcx.llbb]); - let not_yet_at_end = - ICmp(header_cx, lib::llvm::IntULT, data_ptr, data_end_ptr); - let body_cx = sub_block(header_cx, "iter_vec_loop_body"); - let next_cx = sub_block(header_cx, "iter_vec_next"); - CondBr(header_cx, not_yet_at_end, body_cx.llbb, next_cx.llbb); - body_cx = f(body_cx, data_ptr, unit_ty); - let increment = - if ty::type_has_dynamic_size(bcx.tcx(), unit_ty) { - unit_sz - } else { C_int(ccx, 1) }; - AddIncomingToPhi(data_ptr, InBoundsGEP(body_cx, data_ptr, [increment]), - body_cx.llbb); - Br(body_cx, header_cx.llbb); - ret next_cx; -} - -fn iter_vec(bcx: block, vptr: ValueRef, vec_ty: ty::t, - f: iter_vec_block) -> block { - let vptr = PointerCast(bcx, vptr, T_ptr(bcx.ccx().opaque_vec_type)); - ret iter_vec_raw(bcx, vptr, vec_ty, get_fill(bcx, vptr), f); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/trans/type_of.rs b/src/comp/middle/trans/type_of.rs deleted file mode 100644 index f7095be55ff..00000000000 --- a/src/comp/middle/trans/type_of.rs +++ /dev/null @@ -1,145 +0,0 @@ -import common::*; -import lib::llvm::{TypeRef}; -import syntax::ast; -import lib::llvm::llvm; - -fn type_of_explicit_args(cx: crate_ctxt, inputs: [ty::arg]) -> [TypeRef] { - vec::map(inputs) {|arg| - let arg_ty = arg.ty; - let llty = type_of(cx, arg_ty); - alt ty::resolved_mode(cx.tcx, arg.mode) { - ast::by_val { llty } - _ { T_ptr(llty) } - } - } -} - -fn type_of_fn(cx: crate_ctxt, inputs: [ty::arg], - output: ty::t, params: [ty::param_bounds]) -> TypeRef { - let atys: [TypeRef] = []; - - // Arg 0: Output pointer. - atys += [T_ptr(type_of(cx, output))]; - - // Arg 1: Environment - atys += [T_opaque_box_ptr(cx)]; - - // Args >2: ty params, if not acquired via capture... - for bounds in params { - atys += [T_ptr(cx.tydesc_type)]; - for bound in *bounds { - alt bound { - ty::bound_iface(_) { atys += [T_ptr(T_dict())]; } - _ {} - } - } - } - // ... then explicit args. - atys += type_of_explicit_args(cx, inputs); - ret T_fn(atys, llvm::LLVMVoidType()); -} - -// Given a function type and a count of ty params, construct an llvm type -fn type_of_fn_from_ty(cx: crate_ctxt, fty: ty::t, - param_bounds: [ty::param_bounds]) -> TypeRef { - type_of_fn(cx, ty::ty_fn_args(fty), ty::ty_fn_ret(fty), param_bounds) -} - -fn type_of(cx: crate_ctxt, t: ty::t) -> TypeRef { - assert !ty::type_has_vars(t); - // Check the cache. - - if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); } - let llty = alt ty::get(t).struct { - ty::ty_nil | ty::ty_bot { T_nil() } - ty::ty_bool { T_bool() } - ty::ty_int(t) { T_int_ty(cx, t) } - ty::ty_uint(t) { T_uint_ty(cx, t) } - ty::ty_float(t) { T_float_ty(cx, t) } - ty::ty_str { T_ptr(T_vec(cx, T_i8())) } - ty::ty_enum(did, _) { type_of_enum(cx, did, t) } - ty::ty_box(mt) { - let mt_ty = mt.ty; - T_ptr(T_box(cx, type_of(cx, mt_ty))) } - ty::ty_opaque_box { T_ptr(T_box(cx, T_i8())) } - ty::ty_uniq(mt) { - let mt_ty = mt.ty; - T_ptr(type_of(cx, mt_ty)) } - ty::ty_vec(mt) { - let mt_ty = mt.ty; - if ty::type_has_dynamic_size(cx.tcx, mt_ty) { - T_ptr(cx.opaque_vec_type) - } else { - T_ptr(T_vec(cx, type_of(cx, mt_ty))) } - } - ty::ty_ptr(mt) { - let mt_ty = mt.ty; - T_ptr(type_of(cx, mt_ty)) } - ty::ty_rec(fields) { - let tys: [TypeRef] = []; - for f: ty::field in fields { - let mt_ty = f.mt.ty; - tys += [type_of(cx, mt_ty)]; - } - T_struct(tys) - } - ty::ty_fn(_) { - T_fn_pair(cx, type_of_fn_from_ty(cx, t, [])) - } - ty::ty_iface(_, _) { T_opaque_iface(cx) } - ty::ty_res(_, sub, tps) { - let sub1 = ty::substitute_type_params(cx.tcx, tps, sub); - ret T_struct([T_i8(), type_of(cx, sub1)]); - } - ty::ty_param(_, _) { T_typaram(cx.tn) } - ty::ty_send_type | ty::ty_type { T_ptr(cx.tydesc_type) } - ty::ty_tup(elts) { - let tys = []; - for elt in elts { - tys += [type_of(cx, elt)]; - } - T_struct(tys) - } - ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) } - ty::ty_constr(subt,_) { type_of(cx, subt) } - - _ { fail "type_of not implemented for this kind of type"; } - }; - cx.lltypes.insert(t, llty); - ret llty; -} - -fn type_of_enum(cx: crate_ctxt, did: ast::def_id, t: ty::t) - -> TypeRef { - let degen = (*ty::enum_variants(cx.tcx, did)).len() == 1u; - if check type_has_static_size(cx, t) { - let size = shape::static_size_of_enum(cx, t); - if !degen { T_enum(cx, size) } - else if size == 0u { T_struct([T_enum_variant(cx)]) } - else { T_array(T_i8(), size) } - } - else { - if degen { T_struct([T_enum_variant(cx)]) } - else { T_opaque_enum(cx) } - } -} - -fn type_of_ty_param_bounds_and_ty - (ccx: crate_ctxt, tpt: ty::ty_param_bounds_and_ty) -> TypeRef { - let t = tpt.ty; - alt ty::get(t).struct { - ty::ty_fn(_) { - ret type_of_fn_from_ty(ccx, t, *tpt.bounds); - } - _ { - // fall through - } - } - type_of(ccx, t) -} - -fn type_of_or_i8(ccx: crate_ctxt, typ: ty::t) -> TypeRef { - if check type_has_static_size(ccx, typ) { - type_of(ccx, typ) - } else { T_i8() } -} diff --git a/src/comp/middle/trans/uniq.rs b/src/comp/middle/trans/uniq.rs deleted file mode 100644 index d6d32510858..00000000000 --- a/src/comp/middle/trans/uniq.rs +++ /dev/null @@ -1,64 +0,0 @@ -import syntax::ast; -import lib::llvm::ValueRef; -import common::*; -import build::*; -import base::*; -import shape::size_of; - -export trans_uniq, make_free_glue, autoderef, duplicate, alloc_uniq; - -fn trans_uniq(bcx: block, contents: @ast::expr, - node_id: ast::node_id, dest: dest) -> block { - let uniq_ty = node_id_type(bcx, node_id); - let {bcx, val: llptr} = alloc_uniq(bcx, uniq_ty); - add_clean_free(bcx, llptr, true); - bcx = trans_expr_save_in(bcx, contents, llptr); - revoke_clean(bcx, llptr); - ret store_in_dest(bcx, llptr, dest); -} - -fn alloc_uniq(cx: block, uniq_ty: ty::t) -> result { - let bcx = cx; - let contents_ty = content_ty(uniq_ty); - let r = size_of(bcx, contents_ty); - bcx = r.bcx; - let llsz = r.val; - - let llptrty = T_ptr(type_of::type_of(bcx.ccx(), contents_ty)); - - r = trans_shared_malloc(bcx, llptrty, llsz); - bcx = r.bcx; - let llptr = r.val; - - ret rslt(bcx, llptr); -} - -fn make_free_glue(bcx: block, vptr: ValueRef, t: ty::t) - -> block { - with_cond(bcx, IsNotNull(bcx, vptr)) {|bcx| - let bcx = drop_ty(bcx, vptr, content_ty(t)); - trans_shared_free(bcx, vptr) - } -} - -fn content_ty(t: ty::t) -> ty::t { - alt ty::get(t).struct { - ty::ty_uniq({ty: ct, _}) { ct } - _ { std::util::unreachable(); } - } -} - -fn autoderef(v: ValueRef, t: ty::t) -> {v: ValueRef, t: ty::t} { - let content_ty = content_ty(t); - ret {v: v, t: content_ty}; -} - -fn duplicate(bcx: block, v: ValueRef, t: ty::t) -> result { - let content_ty = content_ty(t); - let {bcx, val: llptr} = alloc_uniq(bcx, t); - - let src = load_if_immediate(bcx, v, content_ty); - let dst = llptr; - let bcx = copy_val(bcx, INIT, dst, src, content_ty); - ret rslt(bcx, dst); -} \ No newline at end of file diff --git a/src/comp/middle/tstate/ann.rs b/src/comp/middle/tstate/ann.rs deleted file mode 100644 index f3862e3d20f..00000000000 --- a/src/comp/middle/tstate/ann.rs +++ /dev/null @@ -1,253 +0,0 @@ - -import tritv::*; - -type precond = t; - -/* 2 means "this constraint may or may not be true after execution" - 1 means "this constraint is definitely true after execution" - 0 means "this constraint is definitely false after execution" */ -type postcond = t; - - -/* 2 means "don't know about this constraint" - 1 means "this constraint is definitely true before entry" - 0 means "this constraint is definitely false on entry" */ -type prestate = t; - - -/* similar to postcond */ -type poststate = t; - - -/* 1 means "this variable is definitely initialized" - 0 means "don't know whether this variable is - initialized" */ - -/* - This says: this expression requires the constraints whose value is 1 in - <pre> to be true, and given the precondition, it guarantees that the - constraints in <post> whose values are 1 are true, and that the constraints - in <post> whose values are 0 are false. - */ - -/* named thus so as not to confuse with prestate and poststate */ -type pre_and_post = @{precondition: precond, postcondition: postcond}; - - -/* FIXME: once it's implemented: */ - -// : ((*.precondition).nbits == (*.postcondition).nbits); -type pre_and_post_state = {prestate: prestate, poststate: poststate}; - -type ts_ann = @{conditions: pre_and_post, states: pre_and_post_state}; - -fn true_precond(num_vars: uint) -> precond { be create_tritv(num_vars); } - -fn true_postcond(num_vars: uint) -> postcond { be true_precond(num_vars); } - -fn empty_prestate(num_vars: uint) -> prestate { be true_precond(num_vars); } - -fn empty_poststate(num_vars: uint) -> poststate { be true_precond(num_vars); } - -fn false_postcond(num_vars: uint) -> postcond { - let rslt = create_tritv(num_vars); - tritv_set_all(rslt); - ret rslt; -} - -fn empty_pre_post(num_vars: uint) -> pre_and_post { - ret @{precondition: empty_prestate(num_vars), - postcondition: empty_poststate(num_vars)}; -} - -fn empty_states(num_vars: uint) -> pre_and_post_state { - ret {prestate: true_precond(num_vars), - poststate: true_postcond(num_vars)}; -} - -fn empty_ann(num_vars: uint) -> ts_ann { - ret @{conditions: empty_pre_post(num_vars), - states: empty_states(num_vars)}; -} - -fn get_pre(&&p: pre_and_post) -> precond { ret p.precondition; } - -fn get_post(&&p: pre_and_post) -> postcond { ret p.postcondition; } - -fn difference(p1: precond, p2: precond) -> bool { - ret tritv_difference(p1, p2); -} - -fn union(p1: precond, p2: precond) -> bool { ret tritv_union(p1, p2); } - -fn intersect(p1: precond, p2: precond) -> bool { - ret tritv_intersect(p1, p2); -} - -fn pps_len(p: pre_and_post) -> uint { - // gratuitous check - - assert (p.precondition.nbits == p.postcondition.nbits); - ret p.precondition.nbits; -} - -fn require(i: uint, p: pre_and_post) { - // sets the ith bit in p's pre - tritv_set(i, p.precondition, ttrue); -} - -fn require_and_preserve(i: uint, p: pre_and_post) { - // sets the ith bit in p's pre and post - tritv_set(i, p.precondition, ttrue); - tritv_set(i, p.postcondition, ttrue); -} - -fn set_in_postcond(i: uint, p: pre_and_post) -> bool { - // sets the ith bit in p's post - ret set_in_postcond_(i, p.postcondition); -} - -fn set_in_postcond_(i: uint, p: postcond) -> bool { - let was_set = tritv_get(p, i); - tritv_set(i, p, ttrue); - ret was_set != ttrue; -} - -fn set_in_poststate(i: uint, s: pre_and_post_state) -> bool { - // sets the ith bit in p's post - ret set_in_poststate_(i, s.poststate); -} - -fn set_in_poststate_(i: uint, p: poststate) -> bool { - let was_set = tritv_get(p, i); - tritv_set(i, p, ttrue); - ret was_set != ttrue; - -} - -fn clear_in_poststate(i: uint, s: pre_and_post_state) -> bool { - // sets the ith bit in p's post - ret clear_in_poststate_(i, s.poststate); -} - -fn clear_in_poststate_(i: uint, s: poststate) -> bool { - let was_set = tritv_get(s, i); - tritv_set(i, s, tfalse); - ret was_set != tfalse; -} - -fn clear_in_prestate(i: uint, s: pre_and_post_state) -> bool { - // sets the ith bit in p's pre - ret clear_in_prestate_(i, s.prestate); -} - -fn clear_in_prestate_(i: uint, s: prestate) -> bool { - let was_set = tritv_get(s, i); - tritv_set(i, s, tfalse); - ret was_set != tfalse; -} - -fn clear_in_postcond(i: uint, s: pre_and_post) -> bool { - // sets the ith bit in p's post - let was_set = tritv_get(s.postcondition, i); - tritv_set(i, s.postcondition, tfalse); - ret was_set != tfalse; -} - -// Sets all the bits in a's precondition to equal the -// corresponding bit in p's precondition. -fn set_precondition(a: ts_ann, p: precond) { - tritv_copy(a.conditions.precondition, p); -} - - -// Sets all the bits in a's postcondition to equal the -// corresponding bit in p's postcondition. -fn set_postcondition(a: ts_ann, p: postcond) { - tritv_copy(a.conditions.postcondition, p); -} - - -// Sets all the bits in a's prestate to equal the -// corresponding bit in p's prestate. -fn set_prestate(a: ts_ann, p: prestate) -> bool { - ret tritv_copy(a.states.prestate, p); -} - - -// Sets all the bits in a's postcondition to equal the -// corresponding bit in p's postcondition. -fn set_poststate(a: ts_ann, p: poststate) -> bool { - ret tritv_copy(a.states.poststate, p); -} - - -// Set all the bits in p that are set in new -fn extend_prestate(p: prestate, new: poststate) -> bool { - ret tritv_union(p, new); -} - - -// Set all the bits in p that are set in new -fn extend_poststate(p: poststate, new: poststate) -> bool { - ret tritv_union(p, new); -} - -// Sets the given bit in p to "don't care" -// FIXME: is this correct? -fn relax_prestate(i: uint, p: prestate) -> bool { - let was_set = tritv_get(p, i); - tritv_set(i, p, dont_care); - ret was_set != dont_care; -} - -// Clears the given bit in p -fn relax_poststate(i: uint, p: poststate) -> bool { - ret relax_prestate(i, p); -} - -// Clears the given bit in p -fn relax_precond(i: uint, p: precond) { relax_prestate(i, p); } - -// Sets all the bits in p to "don't care" -fn clear(p: precond) { tritv_clear(p); } - -// Sets all the bits in p to true -fn set(p: precond) { tritv_set_all(p); } - -fn ann_precond(a: ts_ann) -> precond { ret a.conditions.precondition; } - -fn ann_prestate(a: ts_ann) -> prestate { ret a.states.prestate; } - -fn ann_poststate(a: ts_ann) -> poststate { ret a.states.poststate; } - -fn pp_clone(p: pre_and_post) -> pre_and_post { - ret @{precondition: clone(p.precondition), - postcondition: clone(p.postcondition)}; -} - -fn clone(p: prestate) -> prestate { ret tritv_clone(p); } - - -// returns true if a implies b -// that is, returns true except if for some bits c and d, -// c = 1 and d = either 0 or "don't know" -// FIXME: is this correct? -fn implies(a: t, b: t) -> bool { - let tmp = tritv_clone(b); - tritv_difference(tmp, a); - ret tritv_doesntcare(tmp); -} - -fn trit_str(t: trit) -> str { - alt t { dont_care { "?" } ttrue { "1" } tfalse { "0" } } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/annotate.rs b/src/comp/middle/tstate/annotate.rs deleted file mode 100644 index d4271693112..00000000000 --- a/src/comp/middle/tstate/annotate.rs +++ /dev/null @@ -1,75 +0,0 @@ - -import syntax::ast::*; -import syntax::visit; -import syntax::codemap::span; -import util::common::{log_stmt}; -import aux::{num_constraints, get_fn_info, crate_ctxt, add_node}; -import ann::empty_ann; -import pat_util::pat_binding_ids; - -fn collect_ids_expr(e: @expr, rs: @mutable [node_id]) { *rs += [e.id]; } - -fn collect_ids_block(b: blk, rs: @mutable [node_id]) { *rs += [b.node.id]; } - -fn collect_ids_stmt(s: @stmt, rs: @mutable [node_id]) { - alt s.node { - stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) { - log(debug, "node_id " + int::str(id)); - log_stmt(*s); - *rs += [id]; - } - _ { } - } -} - -fn collect_ids_local(tcx: ty::ctxt, l: @local, rs: @mutable [node_id]) { - *rs += pat_binding_ids(tcx.def_map, l.node.pat); -} - -fn node_ids_in_fn(tcx: ty::ctxt, body: blk, rs: @mutable [node_id]) { - let collect_ids = - visit::mk_simple_visitor(@{visit_expr: bind collect_ids_expr(_, rs), - visit_block: bind collect_ids_block(_, rs), - visit_stmt: bind collect_ids_stmt(_, rs), - visit_local: - bind collect_ids_local(tcx, _, rs) - with *visit::default_simple_visitor()}); - collect_ids.visit_block(body, (), collect_ids); -} - -fn init_vecs(ccx: crate_ctxt, node_ids: [node_id], len: uint) { - for i: node_id in node_ids { - log(debug, int::str(i) + " |-> " + uint::str(len)); - add_node(ccx, i, empty_ann(len)); - } -} - -fn visit_fn(ccx: crate_ctxt, num_constraints: uint, body: blk) { - let node_ids: @mutable [node_id] = @mutable []; - node_ids_in_fn(ccx.tcx, body, node_ids); - let node_id_vec = *node_ids; - init_vecs(ccx, node_id_vec, num_constraints); -} - -fn annotate_in_fn(ccx: crate_ctxt, _fk: visit::fn_kind, _decl: fn_decl, - body: blk, _sp: span, id: node_id) { - let f_info = get_fn_info(ccx, id); - visit_fn(ccx, num_constraints(f_info), body); -} - -fn annotate_crate(ccx: crate_ctxt, crate: crate) { - let do_ann = - visit::mk_simple_visitor( - @{visit_fn: bind annotate_in_fn(ccx, _, _, _, _, _) - with *visit::default_simple_visitor()}); - visit::visit_crate(crate, (), do_ann); -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs deleted file mode 100644 index df358a86004..00000000000 --- a/src/comp/middle/tstate/auxiliary.rs +++ /dev/null @@ -1,1115 +0,0 @@ -import option::*; -import pat_util::*; -import syntax::ast::*; -import syntax::ast_util::*; -import syntax::{visit, codemap}; -import codemap::span; -import std::map::{new_int_hash}; -import syntax::print::pprust::path_to_str; -import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate, - poststate, precond, postcond, - set_prestate, set_poststate, set_in_poststate_, - extend_prestate, extend_poststate, set_precondition, - set_postcondition, ts_ann, - clear_in_postcond, - clear_in_poststate_}; -import tritv::*; -import bitvectors::promises_; -import driver::session::session; - -import syntax::print::pprust::{constr_args_to_str, lit_to_str}; - -// Used to communicate which operands should be invalidated -// to helper functions -enum oper_type { - oper_move, - oper_swap, - oper_assign, - oper_assign_op, - oper_pure, -} - -/* logging funs */ -fn def_id_to_str(d: def_id) -> str { - ret int::str(d.crate) + "," + int::str(d.node); -} - -fn comma_str(args: [@constr_arg_use]) -> str { - let rslt = ""; - let comma = false; - for a: @constr_arg_use in args { - if comma { rslt += ", "; } else { comma = true; } - alt a.node { - carg_base { rslt += "*"; } - carg_ident(i) { rslt += i.ident; } - carg_lit(l) { rslt += lit_to_str(l); } - } - } - ret rslt; -} - -fn constraint_to_str(tcx: ty::ctxt, c: sp_constr) -> str { - alt c.node { - ninit(id, i) { - ret #fmt("init(%s id=%d - arising from %s)", - i, id, codemap::span_to_str(c.span, tcx.sess.codemap)); - } - npred(p, _, args) { - ret #fmt("%s(%s) - arising from %s", - path_to_str(p), - comma_str(args), - codemap::span_to_str(c.span, tcx.sess.codemap)); - } - } -} - -fn tritv_to_str(fcx: fn_ctxt, v: tritv::t) -> str { - let s = ""; - let comma = false; - for p: norm_constraint in constraints(fcx) { - alt tritv_get(v, p.bit_num) { - dont_care { } - tt { - s += - if comma { ", " } else { comma = true; "" } + - if tt == tfalse { "!" } else { "" } + - constraint_to_str(fcx.ccx.tcx, p.c); - } - } - } - ret s; -} - -fn log_tritv(fcx: fn_ctxt, v: tritv::t) { - log(debug, tritv_to_str(fcx, v)); -} - -fn first_difference_string(fcx: fn_ctxt, expected: tritv::t, actual: tritv::t) - -> str { - let s: str = ""; - for c: norm_constraint in constraints(fcx) { - if tritv_get(expected, c.bit_num) == ttrue && - tritv_get(actual, c.bit_num) != ttrue { - ret constraint_to_str(fcx.ccx.tcx, c.c); - } - } - ret s; -} - -fn log_tritv_err(fcx: fn_ctxt, v: tritv::t) { - log(error, tritv_to_str(fcx, v)); -} - -fn tos(v: [uint]) -> str { - let rslt = ""; - for i: uint in v { - if i == 0u { - rslt += "0"; - } else if i == 1u { rslt += "1"; } else { rslt += "?"; } - } - ret rslt; -} - -fn log_cond(v: [uint]) { log(debug, tos(v)); } - -fn log_cond_err(v: [uint]) { log(error, tos(v)); } - -fn log_pp(pp: pre_and_post) { - let p1 = tritv::to_vec(pp.precondition); - let p2 = tritv::to_vec(pp.postcondition); - #debug("pre:"); - log_cond(p1); - #debug("post:"); - log_cond(p2); -} - -fn log_pp_err(pp: pre_and_post) { - let p1 = tritv::to_vec(pp.precondition); - let p2 = tritv::to_vec(pp.postcondition); - #error("pre:"); - log_cond_err(p1); - #error("post:"); - log_cond_err(p2); -} - -fn log_states(pp: pre_and_post_state) { - let p1 = tritv::to_vec(pp.prestate); - let p2 = tritv::to_vec(pp.poststate); - #debug("prestate:"); - log_cond(p1); - #debug("poststate:"); - log_cond(p2); -} - -fn log_states_err(pp: pre_and_post_state) { - let p1 = tritv::to_vec(pp.prestate); - let p2 = tritv::to_vec(pp.poststate); - #error("prestate:"); - log_cond_err(p1); - #error("poststate:"); - log_cond_err(p2); -} - -fn print_ident(i: ident) { log(debug, " " + i + " "); } - -fn print_idents(&idents: [ident]) { - if vec::len::<ident>(idents) == 0u { ret; } - log(debug, "an ident: " + vec::pop::<ident>(idents)); - print_idents(idents); -} - - -/* data structures */ - -/**********************************************************************/ - -/* Two different data structures represent constraints in different - contexts: constraint and norm_constraint. - -constraint gets used to record constraints in a table keyed by def_ids. -cinit constraints represent a single constraint, for the initialization -state of a variable; a cpred constraint, with a single operator and a -list of possible argument lists, could represent several constraints at -once. - -norm_constraint, in contrast, gets used when handling an instance -of a constraint rather than a definition of a constraint. It can -also be init or pred (ninit or npred), but the npred case just has -a single argument list. - -The representation of constraints, where multiple instances of the -same predicate are collapsed into one entry in the table, makes it -easier to look up a specific instance. - -Both types are in constrast with the constraint type defined in -syntax::ast, which is for predicate constraints only, and is what -gets generated by the parser. aux and ast share the same type -to represent predicate *arguments* however. This type -(constr_arg_general) is parameterized (see comments in syntax::ast). - -Both types store an ident and span, for error-logging purposes. -*/ -type pred_args_ = {args: [@constr_arg_use], bit_num: uint}; - -type pred_args = spanned<pred_args_>; - -// The attached node ID is the *defining* node ID -// for this local. -type constr_arg_use = spanned<constr_arg_general_<inst>>; - -enum constraint { - cinit(uint, span, ident), - - // FIXME: really only want it to be mutable during collect_locals. - // freeze it after that. - cpred(@path, @mutable [pred_args]), -} - -// An ninit variant has a node_id because it refers to a local var. -// An npred has a def_id since the definition of the typestate -// predicate need not be local. -// FIXME: would be nice to give both a def_id field, -// and give ninit a constraint saying it's local. -enum tsconstr { - ninit(node_id, ident), - npred(@path, def_id, [@constr_arg_use]), -} - -type sp_constr = spanned<tsconstr>; - -type norm_constraint = {bit_num: uint, c: sp_constr}; - -type constr_map = std::map::hashmap<def_id, constraint>; - -/* Contains stuff that has to be computed up front */ -/* For easy access, the fn_info stores two special constraints for each -function. i_return holds if all control paths in this function terminate -in either a return expression, or an appropriate tail expression. -i_diverge holds if all control paths in this function terminate in a fail -or diverging call. - -It might be tempting to use a single constraint C for both properties, -where C represents i_return and !C represents i_diverge. This is -inadvisable, because then the sense of the bit depends on context. If we're -inside a ! function, that reverses the sense of the bit: C would be -i_diverge and !C would be i_return. That's awkward, because we have to -pass extra context around to functions that shouldn't care. - -Okay, suppose C represents i_return and !C represents i_diverge, regardless -of context. Consider this code: - -if (foo) { ret; } else { fail; } - -C is true in the consequent and false in the alternative. What's T `join` -F, then? ? doesn't work, because this code should definitely-return if the -context is a returning function (and be definitely-rejected if the context -is a ! function). F doesn't work, because then the code gets incorrectly -rejected if the context is a returning function. T would work, but it -doesn't make sense for T `join` F to be T (consider init constraints, for -example).; - -So we need context. And so it seems clearer to just have separate -constraints. -*/ -type fn_info = - /* list, accumulated during pre/postcondition - computation, of all local variables that may be - used */ - // Doesn't seem to work without the @ -- bug - {constrs: constr_map, - num_constraints: uint, - cf: ret_style, - i_return: tsconstr, - i_diverge: tsconstr, - used_vars: @mutable [node_id]}; - -fn tsconstr_to_def_id(t: tsconstr) -> def_id { - alt t { ninit(id, _) { local_def(id) } npred(_, id, _) { id } } -} - -fn tsconstr_to_node_id(t: tsconstr) -> node_id { - alt t { - ninit(id, _) { id } - npred(_, id, _) { fail "tsconstr_to_node_id called on pred constraint" } - } -} - -/* mapping from node ID to typestate annotation */ -type node_ann_table = @mutable [mutable ts_ann]; - - -/* mapping from function name to fn_info map */ -type fn_info_map = std::map::hashmap<node_id, fn_info>; - -type fn_ctxt = - {enclosing: fn_info, id: node_id, name: ident, ccx: crate_ctxt}; - -type crate_ctxt = {tcx: ty::ctxt, node_anns: node_ann_table, fm: fn_info_map}; - -fn get_fn_info(ccx: crate_ctxt, id: node_id) -> fn_info { - assert (ccx.fm.contains_key(id)); - ret ccx.fm.get(id); -} - -fn add_node(ccx: crate_ctxt, i: node_id, a: ts_ann) { - let sz = vec::len(*ccx.node_anns); - if sz <= i as uint { - vec::grow(*ccx.node_anns, (i as uint) - sz + 1u, empty_ann(0u)); - } - ccx.node_anns[i] = a; -} - -fn get_ts_ann(ccx: crate_ctxt, i: node_id) -> option<ts_ann> { - if i as uint < vec::len(*ccx.node_anns) { - ret some::<ts_ann>(ccx.node_anns[i]); - } else { ret none::<ts_ann>; } -} - - -/********* utils ********/ -fn node_id_to_ts_ann(ccx: crate_ctxt, id: node_id) -> ts_ann { - alt get_ts_ann(ccx, id) { - none { - #error("node_id_to_ts_ann: no ts_ann for node_id %d", id); - fail; - } - some(tt) { ret tt; } - } -} - -fn node_id_to_poststate(ccx: crate_ctxt, id: node_id) -> poststate { - #debug("node_id_to_poststate"); - ret node_id_to_ts_ann(ccx, id).states.poststate; -} - -fn stmt_to_ann(ccx: crate_ctxt, s: stmt) -> ts_ann { - #debug("stmt_to_ann"); - alt s.node { - stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) { - ret node_id_to_ts_ann(ccx, id); - } - } -} - - -/* fails if e has no annotation */ -fn expr_states(ccx: crate_ctxt, e: @expr) -> pre_and_post_state { - #debug("expr_states"); - ret node_id_to_ts_ann(ccx, e.id).states; -} - - -/* fails if e has no annotation */ -fn expr_pp(ccx: crate_ctxt, e: @expr) -> pre_and_post { - #debug("expr_pp"); - ret node_id_to_ts_ann(ccx, e.id).conditions; -} - -fn stmt_pp(ccx: crate_ctxt, s: stmt) -> pre_and_post { - ret stmt_to_ann(ccx, s).conditions; -} - - -/* fails if b has no annotation */ -fn block_pp(ccx: crate_ctxt, b: blk) -> pre_and_post { - #debug("block_pp"); - ret node_id_to_ts_ann(ccx, b.node.id).conditions; -} - -fn clear_pp(pp: pre_and_post) { - ann::clear(pp.precondition); - ann::clear(pp.postcondition); -} - -fn clear_precond(ccx: crate_ctxt, id: node_id) { - let pp = node_id_to_ts_ann(ccx, id); - ann::clear(pp.conditions.precondition); -} - -fn block_states(ccx: crate_ctxt, b: blk) -> pre_and_post_state { - #debug("block_states"); - ret node_id_to_ts_ann(ccx, b.node.id).states; -} - -fn stmt_states(ccx: crate_ctxt, s: stmt) -> pre_and_post_state { - ret stmt_to_ann(ccx, s).states; -} - -fn expr_precond(ccx: crate_ctxt, e: @expr) -> precond { - ret expr_pp(ccx, e).precondition; -} - -fn expr_postcond(ccx: crate_ctxt, e: @expr) -> postcond { - ret expr_pp(ccx, e).postcondition; -} - -fn expr_prestate(ccx: crate_ctxt, e: @expr) -> prestate { - ret expr_states(ccx, e).prestate; -} - -fn expr_poststate(ccx: crate_ctxt, e: @expr) -> poststate { - ret expr_states(ccx, e).poststate; -} - -fn stmt_precond(ccx: crate_ctxt, s: stmt) -> precond { - ret stmt_pp(ccx, s).precondition; -} - -fn stmt_postcond(ccx: crate_ctxt, s: stmt) -> postcond { - ret stmt_pp(ccx, s).postcondition; -} - -fn states_to_poststate(ss: pre_and_post_state) -> poststate { - ret ss.poststate; -} - -fn stmt_prestate(ccx: crate_ctxt, s: stmt) -> prestate { - ret stmt_states(ccx, s).prestate; -} - -fn stmt_poststate(ccx: crate_ctxt, s: stmt) -> poststate { - ret stmt_states(ccx, s).poststate; -} - -fn block_precond(ccx: crate_ctxt, b: blk) -> precond { - ret block_pp(ccx, b).precondition; -} - -fn block_postcond(ccx: crate_ctxt, b: blk) -> postcond { - ret block_pp(ccx, b).postcondition; -} - -fn block_prestate(ccx: crate_ctxt, b: blk) -> prestate { - ret block_states(ccx, b).prestate; -} - -fn block_poststate(ccx: crate_ctxt, b: blk) -> poststate { - ret block_states(ccx, b).poststate; -} - -fn set_prestate_ann(ccx: crate_ctxt, id: node_id, pre: prestate) -> bool { - #debug("set_prestate_ann"); - ret set_prestate(node_id_to_ts_ann(ccx, id), pre); -} - -fn extend_prestate_ann(ccx: crate_ctxt, id: node_id, pre: prestate) -> bool { - #debug("extend_prestate_ann"); - ret extend_prestate(node_id_to_ts_ann(ccx, id).states.prestate, pre); -} - -fn set_poststate_ann(ccx: crate_ctxt, id: node_id, post: poststate) -> bool { - #debug("set_poststate_ann"); - ret set_poststate(node_id_to_ts_ann(ccx, id), post); -} - -fn extend_poststate_ann(ccx: crate_ctxt, id: node_id, post: poststate) -> - bool { - #debug("extend_poststate_ann"); - ret extend_poststate(node_id_to_ts_ann(ccx, id).states.poststate, post); -} - -fn set_pre_and_post(ccx: crate_ctxt, id: node_id, pre: precond, - post: postcond) { - #debug("set_pre_and_post"); - let tt = node_id_to_ts_ann(ccx, id); - set_precondition(tt, pre); - set_postcondition(tt, post); -} - -fn copy_pre_post(ccx: crate_ctxt, id: node_id, sub: @expr) { - #debug("set_pre_and_post"); - let p = expr_pp(ccx, sub); - copy_pre_post_(ccx, id, p.precondition, p.postcondition); -} - -fn copy_pre_post_(ccx: crate_ctxt, id: node_id, pre: prestate, - post: poststate) { - #debug("set_pre_and_post"); - let tt = node_id_to_ts_ann(ccx, id); - set_precondition(tt, pre); - set_postcondition(tt, post); -} - -/* sets all bits to *1* */ -fn set_postcond_false(ccx: crate_ctxt, id: node_id) { - let p = node_id_to_ts_ann(ccx, id); - ann::set(p.conditions.postcondition); -} - -fn pure_exp(ccx: crate_ctxt, id: node_id, p: prestate) -> bool { - ret set_prestate_ann(ccx, id, p) | set_poststate_ann(ccx, id, p); -} - -fn num_constraints(m: fn_info) -> uint { ret m.num_constraints; } - -fn new_crate_ctxt(cx: ty::ctxt) -> crate_ctxt { - let na: [mutable ts_ann] = [mutable]; - ret {tcx: cx, node_anns: @mutable na, fm: new_int_hash::<fn_info>()}; -} - -/* Use e's type to determine whether it returns. - If it has a function type with a ! annotation, -the answer is noreturn. */ -fn controlflow_expr(ccx: crate_ctxt, e: @expr) -> ret_style { - alt ty::get(ty::node_id_to_type(ccx.tcx, e.id)).struct { - ty::ty_fn(f) { ret f.ret_style; } - _ { ret return_val; } - } -} - -fn constraints_expr(cx: ty::ctxt, e: @expr) -> [@ty::constr] { - alt ty::get(ty::node_id_to_type(cx, e.id)).struct { - ty::ty_fn(f) { ret f.constraints; } - _ { ret []; } - } -} - -fn node_id_to_def_strict(cx: ty::ctxt, id: node_id) -> def { - alt cx.def_map.find(id) { - none { - #error("node_id_to_def: node_id %d has no def", id); - fail; - } - some(d) { ret d; } - } -} - -fn node_id_to_def(ccx: crate_ctxt, id: node_id) -> option<def> { - ret ccx.tcx.def_map.find(id); -} - -fn norm_a_constraint(id: def_id, c: constraint) -> [norm_constraint] { - alt c { - cinit(n, sp, i) { - ret [{bit_num: n, c: respan(sp, ninit(id.node, i))}]; - } - cpred(p, descs) { - let rslt: [norm_constraint] = []; - for pd: pred_args in *descs { - rslt += - [{bit_num: pd.node.bit_num, - c: respan(pd.span, npred(p, id, pd.node.args))}]; - } - ret rslt; - } - } -} - - -// Tried to write this as an iterator, but I got a -// non-exhaustive match in trans. -fn constraints(fcx: fn_ctxt) -> [norm_constraint] { - let rslt: [norm_constraint] = []; - fcx.enclosing.constrs.items {|key, val| - rslt += norm_a_constraint(key, val); - }; - ret rslt; -} - -// FIXME -// Would rather take an immutable vec as an argument, -// should freeze it at some earlier point. -fn match_args(fcx: fn_ctxt, occs: @mutable [pred_args], - occ: [@constr_arg_use]) -> uint { - #debug("match_args: looking at %s", - constr_args_to_str(fn@(i: inst) -> str { ret i.ident; }, occ)); - for pd: pred_args in *occs { - log(debug, - "match_args: candidate " + pred_args_to_str(pd)); - fn eq(p: inst, q: inst) -> bool { ret p.node == q.node; } - if ty::args_eq(eq, pd.node.args, occ) { ret pd.node.bit_num; } - } - fcx.ccx.tcx.sess.bug("match_args: no match for occurring args"); -} - -fn def_id_for_constr(tcx: ty::ctxt, t: node_id) -> def_id { - alt tcx.def_map.find(t) { - none { - tcx.sess.bug("node_id_for_constr: bad node_id " + int::str(t)); - } - some(def_fn(i, _)) { ret i; } - _ { tcx.sess.bug("node_id_for_constr: pred is not a function"); } - } -} - -fn expr_to_constr_arg(tcx: ty::ctxt, e: @expr) -> @constr_arg_use { - alt e.node { - expr_path(p) { - alt tcx.def_map.find(e.id) { - some(def_local(nid, _)) | some(def_arg(nid, _)) | - some(def_binding(nid)) | some(def_upvar(nid, _, _)) { - ret @respan(p.span, - carg_ident({ident: p.node.idents[0], node: nid})); - } - some(what) { - tcx.sess.span_bug(e.span, - #fmt("exprs_to_constr_args: non-local variable %? \ - as pred arg", what)); - } - none { - tcx.sess.span_bug(e.span, - "exprs_to_constr_args: unbound id as pred arg"); - - } - } - } - expr_lit(l) { ret @respan(e.span, carg_lit(l)); } - _ { - tcx.sess.span_fatal(e.span, - "Arguments to constrained functions must be " + - "literals or local variables"); - } - } -} - -fn exprs_to_constr_args(tcx: ty::ctxt, args: [@expr]) -> [@constr_arg_use] { - let f = bind expr_to_constr_arg(tcx, _); - let rslt: [@constr_arg_use] = []; - for e: @expr in args { rslt += [f(e)]; } - rslt -} - -fn expr_to_constr(tcx: ty::ctxt, e: @expr) -> sp_constr { - alt e.node { - expr_call(operator, args, _) { - alt operator.node { - expr_path(p) { - ret respan(e.span, - npred(p, def_id_for_constr(tcx, operator.id), - exprs_to_constr_args(tcx, args))); - } - _ { - tcx.sess.span_fatal(operator.span, - "Internal error: " + - " ill-formed operator \ - in predicate"); - } - } - } - _ { - tcx.sess.span_fatal(e.span, - "Internal error: " + " ill-formed predicate"); - } - } -} - -fn pred_args_to_str(p: pred_args) -> str { - "<" + uint::str(p.node.bit_num) + ", " + - constr_args_to_str(fn@(i: inst) -> str { ret i.ident; }, p.node.args) - + ">" -} - -fn substitute_constr_args(cx: ty::ctxt, actuals: [@expr], c: @ty::constr) -> - tsconstr { - let rslt: [@constr_arg_use] = []; - for a: @constr_arg in c.node.args { - rslt += [substitute_arg(cx, actuals, a)]; - } - ret npred(c.node.path, c.node.id, rslt); -} - -fn substitute_arg(cx: ty::ctxt, actuals: [@expr], a: @constr_arg) -> - @constr_arg_use { - let num_actuals = vec::len(actuals); - alt a.node { - carg_ident(i) { - if i < num_actuals { - ret expr_to_constr_arg(cx, actuals[i]); - } else { - cx.sess.span_fatal(a.span, "Constraint argument out of bounds"); - } - } - carg_base { ret @respan(a.span, carg_base); } - carg_lit(l) { ret @respan(a.span, carg_lit(l)); } - } -} - -fn pred_args_matches(pattern: [constr_arg_general_<inst>], desc: pred_args) -> - bool { - let i = 0u; - for c: @constr_arg_use in desc.node.args { - let n = pattern[i]; - alt c.node { - carg_ident(p) { - alt n { - carg_ident(q) { if p.node != q.node { ret false; } } - _ { ret false; } - } - } - carg_base { if n != carg_base { ret false; } } - carg_lit(l) { - alt n { - carg_lit(m) { if !lit_eq(l, m) { ret false; } } - _ { ret false; } - } - } - } - i += 1u; - } - ret true; -} - -fn find_instance_(pattern: [constr_arg_general_<inst>], descs: [pred_args]) -> - option<uint> { - for d: pred_args in descs { - if pred_args_matches(pattern, d) { ret some(d.node.bit_num); } - } - ret none; -} - -type inst = {ident: ident, node: node_id}; -type subst = [{from: inst, to: inst}]; - -fn find_instances(_fcx: fn_ctxt, subst: subst, c: constraint) -> - [{from: uint, to: uint}] { - - let rslt = []; - if vec::len(subst) == 0u { ret rslt; } - - alt c { - cinit(_, _, _) {/* this is dealt with separately */ } - cpred(p, descs) { - for d: pred_args in *descs { - if args_mention(d.node.args, find_in_subst_bool, subst) { - let old_bit_num = d.node.bit_num; - let new = replace(subst, d); - alt find_instance_(new, *descs) { - some(d1) { rslt += [{from: old_bit_num, to: d1}]; } - _ { } - } - } - } - } - } - rslt -} - -fn find_in_subst(id: node_id, s: subst) -> option<inst> { - for p: {from: inst, to: inst} in s { - if id == p.from.node { ret some(p.to); } - } - ret none; -} - -fn find_in_subst_bool(s: subst, id: node_id) -> bool { - is_some(find_in_subst(id, s)) -} - -fn insts_to_str(stuff: [constr_arg_general_<inst>]) -> str { - let rslt = "<"; - for i: constr_arg_general_<inst> in stuff { - rslt += - " " + - alt i { - carg_ident(p) { p.ident } - carg_base { "*" } - carg_lit(_) { "[lit]" } - } + " "; - } - rslt += ">"; - rslt -} - -fn replace(subst: subst, d: pred_args) -> [constr_arg_general_<inst>] { - let rslt: [constr_arg_general_<inst>] = []; - for c: @constr_arg_use in d.node.args { - alt c.node { - carg_ident(p) { - alt find_in_subst(p.node, subst) { - some(new) { rslt += [carg_ident(new)]; } - _ { rslt += [c.node]; } - } - } - _ { - // #error("##"); - rslt += [c.node]; - } - } - } - - /* - for (constr_arg_general_<tup(ident, def_id)> p in rslt) { - alt (p) { - case (carg_ident(?p)) { - log(error, p._0); - } - case (_) {} - } - } - */ - - ret rslt; -} - -enum if_ty { if_check, plain_if, } - -fn local_node_id_to_def_id_strict(fcx: fn_ctxt, sp: span, i: node_id) -> - def_id { - alt local_node_id_to_def(fcx, i) { - some(def_local(nid, _)) | some(def_arg(nid, _)) | - some(def_upvar(nid, _, _)) { - ret local_def(nid); - } - some(_) { - fcx.ccx.tcx.sess.span_fatal(sp, - "local_node_id_to_def_id: id \ - isn't a local"); - } - none { - // should really be bug. span_bug()? - fcx.ccx.tcx.sess.span_fatal(sp, - "local_node_id_to_def_id: id \ - is unbound"); - } - } -} - -fn local_node_id_to_def(fcx: fn_ctxt, i: node_id) -> option<def> { - fcx.ccx.tcx.def_map.find(i) -} - -fn local_node_id_to_def_id(fcx: fn_ctxt, i: node_id) -> option<def_id> { - alt local_node_id_to_def(fcx, i) { - some(def_local(nid, _)) | some(def_arg(nid, _)) | - some(def_binding(nid)) | some(def_upvar(nid, _, _)) { - some(local_def(nid)) - } - _ { none } - } -} - -fn local_node_id_to_local_def_id(fcx: fn_ctxt, i: node_id) -> - option<node_id> { - alt local_node_id_to_def_id(fcx, i) { - some(did) { some(did.node) } - _ { none } - } -} - -fn copy_in_postcond(fcx: fn_ctxt, parent_exp: node_id, dest: inst, src: inst, - ty: oper_type) { - let post = - node_id_to_ts_ann(fcx.ccx, parent_exp).conditions.postcondition; - copy_in_poststate_two(fcx, post, post, dest, src, ty); -} - -// FIXME refactor -fn copy_in_poststate(fcx: fn_ctxt, post: poststate, dest: inst, src: inst, - ty: oper_type) { - copy_in_poststate_two(fcx, post, post, dest, src, ty); -} - -// In target_post, set the bits corresponding to copies of any -// constraints mentioning src that are set in src_post, with -// dest substituted for src. -// (This doesn't create any new constraints. If a new, substituted -// constraint isn't already in the bit vector, it's ignored.) -fn copy_in_poststate_two(fcx: fn_ctxt, src_post: poststate, - target_post: poststate, dest: inst, src: inst, - ty: oper_type) { - let subst; - alt ty { - oper_swap { subst = [{from: dest, to: src}, {from: src, to: dest}]; } - oper_assign_op { - ret; // Don't do any propagation - } - _ { subst = [{from: src, to: dest}]; } - } - - - fcx.enclosing.constrs.values {|val| - // replace any occurrences of the src def_id with the - // dest def_id - let insts = find_instances(fcx, subst, val); - for p: {from: uint, to: uint} in insts { - if promises_(p.from, src_post) { - set_in_poststate_(p.to, target_post); - } - } - }; -} - -/* FIXME should refactor this better */ -fn forget_in_postcond(fcx: fn_ctxt, parent_exp: node_id, dead_v: node_id) { - // In the postcondition given by parent_exp, clear the bits - // for any constraints mentioning dead_v - let d = local_node_id_to_local_def_id(fcx, dead_v); - alt d { - some(d_id) { - for c: norm_constraint in constraints(fcx) { - if constraint_mentions(fcx, c, d_id) { - #debug("clearing constraint %u %s", - c.bit_num, - constraint_to_str(fcx.ccx.tcx, c.c)); - clear_in_postcond(c.bit_num, - node_id_to_ts_ann(fcx.ccx, - parent_exp).conditions); - } - } - } - _ { } - } -} - -fn forget_in_postcond_still_init(fcx: fn_ctxt, parent_exp: node_id, - dead_v: node_id) { - // In the postcondition given by parent_exp, clear the bits - // for any constraints mentioning dead_v - let d = local_node_id_to_local_def_id(fcx, dead_v); - alt d { - some(d_id) { - for c: norm_constraint in constraints(fcx) { - if non_init_constraint_mentions(fcx, c, d_id) { - clear_in_postcond(c.bit_num, - node_id_to_ts_ann(fcx.ccx, - parent_exp).conditions); - } - } - } - _ { } - } -} - -fn forget_in_poststate(fcx: fn_ctxt, p: poststate, dead_v: node_id) -> bool { - // In the poststate given by parent_exp, clear the bits - // for any constraints mentioning dead_v - let d = local_node_id_to_local_def_id(fcx, dead_v); - let changed = false; - alt d { - some(d_id) { - for c: norm_constraint in constraints(fcx) { - if constraint_mentions(fcx, c, d_id) { - changed |= clear_in_poststate_(c.bit_num, p); - } - } - } - _ { } - } - ret changed; -} - -fn forget_in_poststate_still_init(fcx: fn_ctxt, p: poststate, dead_v: node_id) - -> bool { - // In the poststate given by parent_exp, clear the bits - // for any constraints mentioning dead_v - let d = local_node_id_to_local_def_id(fcx, dead_v); - let changed = false; - alt d { - some(d_id) { - for c: norm_constraint in constraints(fcx) { - if non_init_constraint_mentions(fcx, c, d_id) { - changed |= clear_in_poststate_(c.bit_num, p); - } - } - } - _ { } - } - ret changed; -} - -fn any_eq(v: [node_id], d: node_id) -> bool { - for i: node_id in v { if i == d { ret true; } } - false -} - -fn constraint_mentions(_fcx: fn_ctxt, c: norm_constraint, v: node_id) -> - bool { - ret alt c.c.node { - ninit(id, _) { v == id } - npred(_, _, args) { args_mention(args, any_eq, [v]) } - }; -} - -fn non_init_constraint_mentions(_fcx: fn_ctxt, c: norm_constraint, v: node_id) - -> bool { - ret alt c.c.node { - ninit(_, _) { false } - npred(_, _, args) { args_mention(args, any_eq, [v]) } - }; -} - -fn args_mention<T>(args: [@constr_arg_use], - q: fn([T], node_id) -> bool, - s: [T]) -> bool { - /* - FIXME - The following version causes an assertion in trans to fail - (something about type_is_tup_like) - fn mentions<T>(&[T] s, &fn(&[T], def_id) -> bool q, - &@constr_arg_use a) -> bool { - alt (a.node) { - case (carg_ident(?p1)) { - auto res = q(s, p1._1); - log(error, (res)); - res - } - case (_) { false } - } - } - ret vec::any(bind mentions(s,q,_), args); - */ - - for a: @constr_arg_use in args { - alt a.node { carg_ident(p1) { if q(s, p1.node) { ret true; } } _ { } } - } - ret false; -} - -fn use_var(fcx: fn_ctxt, v: node_id) { *fcx.enclosing.used_vars += [v]; } - -// FIXME: This should be a function in vec::. -fn vec_contains(v: @mutable [node_id], i: node_id) -> bool { - for d: node_id in *v { if d == i { ret true; } } - ret false; -} - -fn op_to_oper_ty(io: init_op) -> oper_type { - alt io { init_move { oper_move } _ { oper_assign } } -} - -// default function visitor -fn do_nothing<T>(_fk: visit::fn_kind, _decl: fn_decl, _body: blk, - _sp: span, _id: node_id, - _t: T, _v: visit::vt<T>) { -} - - -fn args_to_constr_args(tcx: ty::ctxt, args: [arg], - indices: [@sp_constr_arg<uint>]) -> [@constr_arg_use] { - let actuals: [@constr_arg_use] = []; - let num_args = vec::len(args); - for a: @sp_constr_arg<uint> in indices { - actuals += - [@respan(a.span, - alt a.node { - carg_base { carg_base } - carg_ident(i) { - if i < num_args { - carg_ident({ident: args[i].ident, - node: args[i].id}) - } else { - tcx.sess.span_bug(a.span, - "Index out of bounds in \ - constraint arg"); - } - } - carg_lit(l) { carg_lit(l) } - })]; - } - ret actuals; -} - -fn ast_constr_to_ts_constr(tcx: ty::ctxt, args: [arg], c: @constr) -> - tsconstr { - let tconstr = ty::ast_constr_to_constr(tcx, c); - ret npred(tconstr.node.path, tconstr.node.id, - args_to_constr_args(tcx, args, tconstr.node.args)); -} - -fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: [arg], c: @constr) -> - sp_constr { - let tconstr = ast_constr_to_ts_constr(tcx, args, c); - ret respan(c.span, tconstr); -} - -type binding = {lhs: [inst], rhs: option<initializer>}; - -fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding { - let lhs = []; - pat_bindings(tcx.def_map, loc.node.pat) {|p_id, _s, name| - lhs += [{ident: path_to_ident(name), node: p_id}]; - }; - {lhs: lhs, rhs: loc.node.init} -} - -fn locals_to_bindings(tcx: ty::ctxt, locals: [@local]) -> [binding] { - let rslt = []; - for loc in locals { rslt += [local_to_bindings(tcx, loc)]; } - ret rslt; -} - -fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [mode] { - let ty = ty::type_autoderef(fcx.ccx.tcx, - ty::node_id_to_type(fcx.ccx.tcx, callee)); - alt ty::get(ty).struct { - ty::ty_fn({inputs: args, _}) { - let modes = []; - for arg: ty::arg in args { modes += [arg.mode]; } - ret modes; - } - _ { - // Shouldn't happen; callee should be ty_fn. - fcx.ccx.tcx.sess.bug("non-fn callee type in callee_modes: " + - util::ppaux::ty_to_str(fcx.ccx.tcx, ty)); - } - } -} - -fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] { - vec::map(callee_modes(fcx, callee)) {|m| - alt ty::resolved_mode(fcx.ccx.tcx, m) { - by_move { init_move } - by_copy | by_ref | by_val | by_mutbl_ref { init_assign } - } - } -} - -fn anon_bindings(ops: [init_op], es: [@expr]) -> [binding] { - let bindings: [binding] = []; - let i = 0; - for op: init_op in ops { - bindings += [{lhs: [], rhs: some({op: op, expr: es[i]})}]; - i += 1; - } - ret bindings; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs deleted file mode 100644 index 6acb23d906a..00000000000 --- a/src/comp/middle/tstate/bitvectors.rs +++ /dev/null @@ -1,242 +0,0 @@ -import syntax::ast::*; -import syntax::visit; -import option::*; -import aux::*; -import tstate::ann::{pre_and_post, precond, postcond, prestate, poststate, - relax_prestate, relax_precond, relax_poststate, - pps_len, true_precond, - difference, union, clone, - set_in_postcond, set_in_poststate, set_in_poststate_, - clear_in_poststate, clear_in_prestate, - clear_in_poststate_}; -import tritv::*; -import util::common::*; -import driver::session::session; - -fn bit_num(fcx: fn_ctxt, c: tsconstr) -> uint { - let d = tsconstr_to_def_id(c); - assert (fcx.enclosing.constrs.contains_key(d)); - let rslt = fcx.enclosing.constrs.get(d); - alt c { - ninit(_, _) { - alt rslt { - cinit(n, _, _) { ret n; } - _ { - fcx.ccx.tcx.sess.bug("bit_num: asked for init constraint," + - " found a pred constraint"); - } - } - } - npred(_, _, args) { - alt rslt { - cpred(_, descs) { ret match_args(fcx, descs, args); } - _ { - fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint," + - " found an init constraint"); - } - } - } - } -} - -fn promises(fcx: fn_ctxt, p: poststate, c: tsconstr) -> bool { - ret promises_(bit_num(fcx, c), p); -} - -fn promises_(n: uint, p: poststate) -> bool { ret tritv_get(p, n) == ttrue; } - -// v "happens after" u -fn seq_trit(u: trit, v: trit) -> trit { - alt v { ttrue { ttrue } tfalse { tfalse } dont_care { u } } -} - -// idea: q "happens after" p -- so if something is -// 1 in q and 0 in p, it's 1 in the result; however, -// if it's 0 in q and 1 in p, it's 0 in the result -fn seq_tritv(p: postcond, q: postcond) { - let i = 0u; - assert (p.nbits == q.nbits); - while i < p.nbits { - tritv_set(i, p, seq_trit(tritv_get(p, i), tritv_get(q, i))); - i += 1u; - } -} - -fn seq_postconds(fcx: fn_ctxt, ps: [postcond]) -> postcond { - let sz = vec::len(ps); - if sz >= 1u { - let prev = tritv_clone(ps[0]); - for p: postcond in vec::slice(ps, 1u, sz) { seq_tritv(prev, p); } - ret prev; - } else { ret ann::empty_poststate(num_constraints(fcx.enclosing)); } -} - -// Given a list of pres and posts for exprs e0 ... en, -// return the precondition for evaluating each expr in order. -// So, if e0's post is {x} and e1's pre is {x, y, z}, the entire -// precondition shouldn't include x. -fn seq_preconds(fcx: fn_ctxt, pps: [pre_and_post]) -> precond { - let sz: uint = vec::len(pps); - let num_vars: uint = num_constraints(fcx.enclosing); - - fn seq_preconds_go(fcx: fn_ctxt, pps: [pre_and_post], first: pre_and_post) - -> precond { - let sz: uint = vec::len(pps); - if sz >= 1u { - let second = pps[0]; - assert (pps_len(second) == num_constraints(fcx.enclosing)); - let second_pre = clone(second.precondition); - difference(second_pre, first.postcondition); - let next_first = clone(first.precondition); - union(next_first, second_pre); - let next_first_post = clone(first.postcondition); - seq_tritv(next_first_post, second.postcondition); - ret seq_preconds_go(fcx, vec::slice(pps, 1u, sz), - @{precondition: next_first, - postcondition: next_first_post}); - } else { ret first.precondition; } - } - - - if sz >= 1u { - let first = pps[0]; - assert (pps_len(first) == num_vars); - ret seq_preconds_go(fcx, vec::slice(pps, 1u, sz), first); - } else { ret true_precond(num_vars); } -} - -fn intersect_states(p: prestate, q: prestate) -> prestate { - let rslt = tritv_clone(p); - tritv_intersect(rslt, q); - ret rslt; -} - -fn gen(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { - ret set_in_postcond(bit_num(fcx, c), - node_id_to_ts_ann(fcx.ccx, id).conditions); -} - -fn declare_var(fcx: fn_ctxt, c: tsconstr, pre: prestate) -> prestate { - let rslt = clone(pre); - relax_prestate(bit_num(fcx, c), rslt); - // idea is this is scoped - relax_poststate(bit_num(fcx, c), rslt); - ret rslt; -} - -fn relax_precond_expr(e: @expr, cx: relax_ctxt, vt: visit::vt<relax_ctxt>) { - relax_precond(cx.i as uint, expr_precond(cx.fcx.ccx, e)); - visit::visit_expr(e, cx, vt); -} - -fn relax_precond_stmt(s: @stmt, cx: relax_ctxt, vt: visit::vt<relax_ctxt>) { - relax_precond(cx.i as uint, stmt_precond(cx.fcx.ccx, *s)); - visit::visit_stmt(s, cx, vt); -} - -type relax_ctxt = {fcx: fn_ctxt, i: node_id}; - -fn relax_precond_block_inner(b: blk, cx: relax_ctxt, - vt: visit::vt<relax_ctxt>) { - relax_precond(cx.i as uint, block_precond(cx.fcx.ccx, b)); - visit::visit_block(b, cx, vt); -} - -fn relax_precond_block(fcx: fn_ctxt, i: node_id, b: blk) { - let cx = {fcx: fcx, i: i}; - let visitor = visit::default_visitor::<relax_ctxt>(); - visitor = - @{visit_block: relax_precond_block_inner, - visit_expr: relax_precond_expr, - visit_stmt: relax_precond_stmt, - visit_item: - fn@(_i: @item, _cx: relax_ctxt, _vt: visit::vt<relax_ctxt>) { }, - visit_fn: bind do_nothing(_, _, _, _, _, _, _) - with *visitor}; - let v1 = visit::mk_vt(visitor); - v1.visit_block(b, cx, v1); -} - -fn gen_poststate(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { - #debug("gen_poststate"); - ret set_in_poststate(bit_num(fcx, c), - node_id_to_ts_ann(fcx.ccx, id).states); -} - -fn kill_prestate(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { - ret clear_in_prestate(bit_num(fcx, c), - node_id_to_ts_ann(fcx.ccx, id).states); -} - -fn kill_all_prestate(fcx: fn_ctxt, id: node_id) { - tritv::tritv_kill(node_id_to_ts_ann(fcx.ccx, id).states.prestate); -} - - -fn kill_poststate(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { - #debug("kill_poststate"); - ret clear_in_poststate(bit_num(fcx, c), - node_id_to_ts_ann(fcx.ccx, id).states); -} - -fn clear_in_poststate_expr(fcx: fn_ctxt, e: @expr, t: poststate) { - alt e.node { - expr_path(p) { - alt vec::last(p.node.idents) { - some(i) { - alt local_node_id_to_def(fcx, e.id) { - some(def_local(nid, _)) { - clear_in_poststate_(bit_num(fcx, ninit(nid, i)), t); - } - some(_) {/* ignore args (for now...) */ } - _ { - fcx.ccx.tcx.sess.bug("clear_in_poststate_expr: \ - unbound var"); - } - } - } - _ { fcx.ccx.tcx.sess.bug("clear_in_poststate_expr"); } - } - } - _ {/* do nothing */ } - } -} - -fn kill_poststate_(fcx: fn_ctxt, c: tsconstr, post: poststate) -> bool { - #debug("kill_poststate_"); - ret clear_in_poststate_(bit_num(fcx, c), post); -} - -fn set_in_poststate_ident(fcx: fn_ctxt, id: node_id, ident: ident, - t: poststate) -> bool { - ret set_in_poststate_(bit_num(fcx, ninit(id, ident)), t); -} - -fn set_in_prestate_constr(fcx: fn_ctxt, c: tsconstr, t: prestate) -> bool { - ret set_in_poststate_(bit_num(fcx, c), t); -} - -fn clear_in_poststate_ident(fcx: fn_ctxt, id: node_id, ident: ident, - parent: node_id) -> bool { - ret kill_poststate(fcx, parent, ninit(id, ident)); -} - -fn clear_in_prestate_ident(fcx: fn_ctxt, id: node_id, ident: ident, - parent: node_id) -> bool { - ret kill_prestate(fcx, parent, ninit(id, ident)); -} - -fn clear_in_poststate_ident_(fcx: fn_ctxt, id: node_id, ident: ident, - post: poststate) -> bool { - ret kill_poststate_(fcx, ninit(id, ident), post); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/ck.rs b/src/comp/middle/tstate/ck.rs deleted file mode 100644 index 08415119e4a..00000000000 --- a/src/comp/middle/tstate/ck.rs +++ /dev/null @@ -1,201 +0,0 @@ - -import syntax::ast; -import ast::{stmt, fn_ident, node_id, crate, return_val, noreturn, expr}; -import syntax::{visit, print}; -import syntax::codemap::span; -import middle::ty; -import tstate::ann::{precond, prestate, - implies, ann_precond, ann_prestate}; -import aux::*; -import syntax::print::pprust::ty_to_str; -import bitvectors::*; -import annotate::annotate_crate; -import collect_locals::mk_f_to_fn_info; -import pre_post_conditions::fn_pre_post; -import states::find_pre_post_state_fn; -import driver::session::session; - -fn check_unused_vars(fcx: fn_ctxt) { - - // FIXME: could be more efficient - for c: norm_constraint in constraints(fcx) { - alt c.c.node { - ninit(id, v) { - if !vec_contains(fcx.enclosing.used_vars, id) && v[0] != '_' as u8 - { - fcx.ccx.tcx.sess.span_warn(c.c.span, "unused variable " + v); - } - } - _ {/* ignore pred constraints */ } - } - } -} - -fn check_states_expr(e: @expr, fcx: fn_ctxt, v: visit::vt<fn_ctxt>) { - visit::visit_expr(e, fcx, v); - - let prec: precond = expr_precond(fcx.ccx, e); - let pres: prestate = expr_prestate(fcx.ccx, e); - - - /* - log_err("check_states_expr:"); - util::common::log_expr_err(*e); - log_err("prec = "); - log_tritv_err(fcx, prec); - log_err("pres = "); - log_tritv_err(fcx, pres); - */ - - if !implies(pres, prec) { - let s = ""; - let diff = first_difference_string(fcx, prec, pres); - s += - "Unsatisfied precondition constraint (for example, " + diff + - ") for expression:\n"; - s += syntax::print::pprust::expr_to_str(e); - s += "\nPrecondition:\n"; - s += tritv_to_str(fcx, prec); - s += "\nPrestate:\n"; - s += tritv_to_str(fcx, pres); - fcx.ccx.tcx.sess.span_fatal(e.span, s); - } -} - -fn check_states_stmt(s: @stmt, fcx: fn_ctxt, v: visit::vt<fn_ctxt>) { - visit::visit_stmt(s, fcx, v); - - let a = stmt_to_ann(fcx.ccx, *s); - let prec: precond = ann_precond(a); - let pres: prestate = ann_prestate(a); - - - #debug("check_states_stmt:"); - log(debug, print::pprust::stmt_to_str(*s)); - #debug("prec = "); - log_tritv(fcx, prec); - #debug("pres = "); - log_tritv(fcx, pres); - - if !implies(pres, prec) { - let ss = ""; - let diff = first_difference_string(fcx, prec, pres); - ss += - "Unsatisfied precondition constraint (for example, " + diff + - ") for statement:\n"; - ss += syntax::print::pprust::stmt_to_str(*s); - ss += "\nPrecondition:\n"; - ss += tritv_to_str(fcx, prec); - ss += "\nPrestate: \n"; - ss += tritv_to_str(fcx, pres); - fcx.ccx.tcx.sess.span_fatal(s.span, ss); - } -} - -fn check_states_against_conditions(fcx: fn_ctxt, - fk: visit::fn_kind, - f_decl: ast::fn_decl, - f_body: ast::blk, - sp: span, - id: node_id) { - /* Postorder traversal instead of pre is important - because we want the smallest possible erroneous statement - or expression. */ - let visitor = visit::mk_vt( - @{visit_stmt: check_states_stmt, - visit_expr: check_states_expr, - visit_fn: bind do_nothing::<fn_ctxt>(_, _, _, _, _, _, _) - with *visit::default_visitor::<fn_ctxt>()}); - visit::visit_fn(fk, f_decl, f_body, sp, id, fcx, visitor); - - /* Check that the return value is initialized */ - let post = aux::block_poststate(fcx.ccx, f_body); - if !promises(fcx, post, fcx.enclosing.i_return) && - !ty::type_is_nil(ty::ty_fn_ret(ty::node_id_to_type( - fcx.ccx.tcx, id))) && - f_decl.cf == return_val { - fcx.ccx.tcx.sess.span_err(f_body.span, - "In function " + fcx.name + - ", not all control paths \ - return a value"); - fcx.ccx.tcx.sess.span_fatal(f_decl.output.span, - "see declared return type of '" + - ty_to_str(f_decl.output) + "'"); - } else if f_decl.cf == noreturn { - - // check that this really always fails - // Note that it's ok for i_diverge and i_return to both be true. - // In fact, i_diverge implies i_return. (But not vice versa!) - - if !promises(fcx, post, fcx.enclosing.i_diverge) { - fcx.ccx.tcx.sess.span_fatal(f_body.span, - "In non-returning function " + - fcx.name + - ", some control paths may \ - return to the caller"); - } - } - - /* Finally, check for unused variables */ - check_unused_vars(fcx); -} - -fn check_fn_states(fcx: fn_ctxt, - fk: visit::fn_kind, - f_decl: ast::fn_decl, - f_body: ast::blk, - sp: span, - id: node_id) { - /* Compute the pre- and post-states for this function */ - - // Fixpoint iteration - while find_pre_post_state_fn(fcx, f_decl, f_body) { } - - /* Now compare each expr's pre-state to its precondition - and post-state to its postcondition */ - - check_states_against_conditions(fcx, fk, f_decl, f_body, sp, id); -} - -fn fn_states(fk: visit::fn_kind, f_decl: ast::fn_decl, f_body: ast::blk, - sp: span, id: node_id, - ccx: crate_ctxt, v: visit::vt<crate_ctxt>) { - visit::visit_fn(fk, f_decl, f_body, sp, id, ccx, v); - /* Look up the var-to-bit-num map for this function */ - - assert (ccx.fm.contains_key(id)); - let f_info = ccx.fm.get(id); - let name = visit::name_of_fn(fk); - let fcx = {enclosing: f_info, id: id, name: name, ccx: ccx}; - check_fn_states(fcx, fk, f_decl, f_body, sp, id) -} - -fn check_crate(cx: ty::ctxt, crate: @crate) { - let ccx: crate_ctxt = new_crate_ctxt(cx); - /* Build the global map from function id to var-to-bit-num-map */ - - mk_f_to_fn_info(ccx, crate); - /* Add a blank ts_ann for every statement (and expression) */ - - annotate_crate(ccx, *crate); - /* Compute the pre and postcondition for every subexpression */ - - let vtor = visit::default_visitor::<crate_ctxt>(); - vtor = @{visit_fn: fn_pre_post with *vtor}; - visit::visit_crate(*crate, ccx, visit::mk_vt(vtor)); - - /* Check the pre- and postcondition against the pre- and poststate - for every expression */ - let vtor = visit::default_visitor::<crate_ctxt>(); - vtor = @{visit_fn: fn_states with *vtor}; - visit::visit_crate(*crate, ccx, visit::mk_vt(vtor)); -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs deleted file mode 100644 index 9b39814e141..00000000000 --- a/src/comp/middle/tstate/collect_locals.rs +++ /dev/null @@ -1,175 +0,0 @@ -import option::*; -import pat_util::*; -import syntax::ast::*; -import syntax::ast_util::*; -import syntax::visit; -import util::common::new_def_hash; -import syntax::codemap::span; -import syntax::ast_util::respan; -import driver::session::session; -import aux::*; - -type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt}; - -fn collect_local(loc: @local, cx: ctxt, v: visit::vt<ctxt>) { - pat_bindings(cx.tcx.def_map, loc.node.pat) {|p_id, _s, id| - *cx.cs += [respan(loc.span, ninit(p_id, path_to_ident(id)))]; - }; - visit::visit_local(loc, cx, v); -} - -fn collect_pred(e: @expr, cx: ctxt, v: visit::vt<ctxt>) { - alt e.node { - expr_check(_, ch) { *cx.cs += [expr_to_constr(cx.tcx, ch)]; } - expr_if_check(ex, _, _) { *cx.cs += [expr_to_constr(cx.tcx, ex)]; } - - // If it's a call, generate appropriate instances of the - // call's constraints. - expr_call(operator, operands, _) { - for c: @ty::constr in constraints_expr(cx.tcx, operator) { - let ct: sp_constr = - respan(c.span, - aux::substitute_constr_args(cx.tcx, operands, c)); - *cx.cs += [ct]; - } - } - _ { } - } - // visit subexpressions - visit::visit_expr(e, cx, v); -} - -fn find_locals(tcx: ty::ctxt, - fk: visit::fn_kind, - f_decl: fn_decl, - f_body: blk, - sp: span, - id: node_id) -> ctxt { - let cx: ctxt = {cs: @mutable [], tcx: tcx}; - let visitor = visit::default_visitor::<ctxt>(); - - visitor = - @{visit_local: collect_local, - visit_expr: collect_pred, - visit_fn: bind do_nothing(_, _, _, _, _, _, _) - with *visitor}; - visit::visit_fn(fk, f_decl, f_body, sp, - id, cx, visit::mk_vt(visitor)); - ret cx; -} - -fn add_constraint(tcx: ty::ctxt, c: sp_constr, next: uint, tbl: constr_map) -> - uint { - log(debug, - constraint_to_str(tcx, c) + " |-> " + uint::str(next)); - alt c.node { - ninit(id, i) { tbl.insert(local_def(id), cinit(next, c.span, i)); } - npred(p, d_id, args) { - alt tbl.find(d_id) { - some(ct) { - alt ct { - cinit(_, _, _) { - tcx.sess.bug("add_constraint: same def_id used" + - " as a variable and a pred"); - } - cpred(_, pds) { - *pds += [respan(c.span, {args: args, bit_num: next})]; - } - } - } - none { - let rslt: @mutable [pred_args] = - @mutable [respan(c.span, {args: args, bit_num: next})]; - tbl.insert(d_id, cpred(p, rslt)); - } - } - } - } - ret next + 1u; -} - - -/* builds a table mapping each local var defined in f - to a bit number in the precondition/postcondition vectors */ -fn mk_fn_info(ccx: crate_ctxt, - fk: visit::fn_kind, - f_decl: fn_decl, - f_body: blk, - f_sp: span, - id: node_id) { - let name = visit::name_of_fn(fk); - let res_map = new_def_hash::<constraint>(); - let next: uint = 0u; - - let cx: ctxt = find_locals(ccx.tcx, fk, f_decl, f_body, f_sp, id); - /* now we have to add bit nums for both the constraints - and the variables... */ - - for c: sp_constr in { *cx.cs } { - next = add_constraint(cx.tcx, c, next, res_map); - } - /* if this function has any constraints, instantiate them to the - argument names and add them */ - let sc; - for c: @constr in f_decl.constraints { - sc = ast_constr_to_sp_constr(cx.tcx, f_decl.inputs, c); - next = add_constraint(cx.tcx, sc, next, res_map); - } - - /* Need to add constraints for args too, b/c they - can be deinitialized */ - for a: arg in f_decl.inputs { - next = add_constraint( - cx.tcx, - respan(f_sp, ninit(a.id, a.ident)), - next, - res_map); - } - - /* add the special i_diverge and i_return constraints - (see the type definition for auxiliary::fn_info for an explanation) */ - - // use the function name for the "returns" constraint" - let returns_id = ccx.tcx.sess.next_node_id(); - let returns_constr = ninit(returns_id, name); - next = - add_constraint(cx.tcx, respan(f_sp, returns_constr), next, res_map); - // and the name of the function, with a '!' appended to it, for the - // "diverges" constraint - let diverges_id = ccx.tcx.sess.next_node_id(); - let diverges_constr = ninit(diverges_id, name + "!"); - next = add_constraint(cx.tcx, respan(f_sp, diverges_constr), next, - res_map); - - let v: @mutable [node_id] = @mutable []; - let rslt = - {constrs: res_map, - num_constraints: next, - cf: f_decl.cf, - i_return: returns_constr, - i_diverge: diverges_constr, - used_vars: v}; - ccx.fm.insert(id, rslt); - #debug("%s has %u constraints", name, num_constraints(rslt)); -} - - -/* initializes the global fn_info_map (mapping each function ID, including - nested locally defined functions, onto a mapping from local variable name - to bit number) */ -fn mk_f_to_fn_info(ccx: crate_ctxt, c: @crate) { - let visitor = - visit::mk_simple_visitor(@{visit_fn: - bind mk_fn_info(ccx, _, _, _, _, _) - with *visit::default_simple_visitor()}); - visit::visit_crate(*c, (), visitor); -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs deleted file mode 100644 index 8a83f7dd7b4..00000000000 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ /dev/null @@ -1,718 +0,0 @@ -import tstate::ann::*; -import aux::*; -import bitvectors::{bit_num, seq_preconds, seq_postconds, - intersect_states, - relax_precond_block, gen}; -import tritv::*; - -import pat_util::*; -import syntax::ast::*; -import syntax::ast_util::*; -import syntax::visit; -import util::common::{new_def_hash, log_expr, field_exprs, - has_nonlocal_exits, log_stmt}; -import syntax::codemap::span; -import driver::session::session; - -fn find_pre_post_mod(_m: _mod) -> _mod { - #debug("implement find_pre_post_mod!"); - fail; -} - -fn find_pre_post_native_mod(_m: native_mod) -> native_mod { - #debug("implement find_pre_post_native_mod"); - fail; -} - -fn find_pre_post_method(ccx: crate_ctxt, m: @method) { - assert (ccx.fm.contains_key(m.id)); - let fcx: fn_ctxt = - {enclosing: ccx.fm.get(m.id), - id: m.id, - name: m.ident, - ccx: ccx}; - find_pre_post_fn(fcx, m.body); -} - -fn find_pre_post_item(ccx: crate_ctxt, i: item) { - alt i.node { - item_const(_, e) { - // do nothing -- item_consts don't refer to local vars - } - item_fn(_, _, body) { - assert (ccx.fm.contains_key(i.id)); - let fcx = - {enclosing: ccx.fm.get(i.id), id: i.id, name: i.ident, ccx: ccx}; - find_pre_post_fn(fcx, body); - } - item_mod(m) { find_pre_post_mod(m); } - item_native_mod(nm) { find_pre_post_native_mod(nm); } - item_ty(_, _) | item_enum(_, _) | item_iface(_, _) { ret; } - item_res(_, _, body, dtor_id, _) { - let fcx = - {enclosing: ccx.fm.get(dtor_id), - id: dtor_id, - name: i.ident, - ccx: ccx}; - find_pre_post_fn(fcx, body); - } - item_class(_,_,_,_,_) { - fail "find_pre_post_item: implement item_class"; - } - item_impl(_, _, _, ms) { for m in ms { find_pre_post_method(ccx, m); } } - } -} - - -/* Finds the pre and postcondition for each expr in <args>; - sets the precondition in a to be the result of combining - the preconditions for <args>, and the postcondition in a to - be the union of all postconditions for <args> */ -fn find_pre_post_exprs(fcx: fn_ctxt, args: [@expr], id: node_id) { - if vec::len::<@expr>(args) > 0u { - #debug("find_pre_post_exprs: oper ="); - log_expr(*args[0]); - } - fn do_one(fcx: fn_ctxt, e: @expr) { find_pre_post_expr(fcx, e); } - for e: @expr in args { do_one(fcx, e); } - - fn get_pp(ccx: crate_ctxt, &&e: @expr) -> pre_and_post { - ret expr_pp(ccx, e); - } - let pps = vec::map(args, bind get_pp(fcx.ccx, _)); - - set_pre_and_post(fcx.ccx, id, seq_preconds(fcx, pps), - seq_postconds(fcx, vec::map(pps, get_post))); -} - -fn find_pre_post_loop(fcx: fn_ctxt, l: @local, index: @expr, body: blk, - id: node_id) { - find_pre_post_expr(fcx, index); - find_pre_post_block(fcx, body); - pat_bindings(fcx.ccx.tcx.def_map, l.node.pat) {|p_id, _s, n| - let v_init = ninit(p_id, path_to_ident(n)); - relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body); - // Hack: for-loop index variables are frequently ignored, - // so we pretend they're used - use_var(fcx, p_id); - }; - - let loop_precond = - seq_preconds(fcx, [expr_pp(fcx.ccx, index), block_pp(fcx.ccx, body)]); - let loop_postcond = - intersect_states(expr_postcond(fcx.ccx, index), - block_postcond(fcx.ccx, body)); - copy_pre_post_(fcx.ccx, id, loop_precond, loop_postcond); -} - -// Generates a pre/post assuming that a is the -// annotation for an if-expression with consequent conseq -// and alternative maybe_alt -fn join_then_else(fcx: fn_ctxt, antec: @expr, conseq: blk, - maybe_alt: option<@expr>, id: node_id, chck: if_ty) { - find_pre_post_expr(fcx, antec); - find_pre_post_block(fcx, conseq); - alt maybe_alt { - none { - alt chck { - if_check { - let c: sp_constr = expr_to_constr(fcx.ccx.tcx, antec); - gen(fcx, antec.id, c.node); - } - _ { } - } - - let precond_res = - seq_preconds(fcx, - [expr_pp(fcx.ccx, antec), - block_pp(fcx.ccx, conseq)]); - set_pre_and_post(fcx.ccx, id, precond_res, - expr_poststate(fcx.ccx, antec)); - } - some(altern) { - /* - if check = if_check, then - be sure that the predicate implied by antec - is *not* true in the alternative - */ - find_pre_post_expr(fcx, altern); - let precond_false_case = - seq_preconds(fcx, - [expr_pp(fcx.ccx, antec), expr_pp(fcx.ccx, altern)]); - let postcond_false_case = - seq_postconds(fcx, - [expr_postcond(fcx.ccx, antec), - expr_postcond(fcx.ccx, altern)]); - - /* Be sure to set the bit for the check condition here, - so that it's *not* set in the alternative. */ - alt chck { - if_check { - let c: sp_constr = expr_to_constr(fcx.ccx.tcx, antec); - gen(fcx, antec.id, c.node); - } - _ { } - } - let precond_true_case = - seq_preconds(fcx, - [expr_pp(fcx.ccx, antec), - block_pp(fcx.ccx, conseq)]); - let postcond_true_case = - seq_postconds(fcx, - [expr_postcond(fcx.ccx, antec), - block_postcond(fcx.ccx, conseq)]); - - let precond_res = - seq_postconds(fcx, [precond_true_case, precond_false_case]); - let postcond_res = - intersect_states(postcond_true_case, postcond_false_case); - set_pre_and_post(fcx.ccx, id, precond_res, postcond_res); - } - } -} - -fn gen_if_local(fcx: fn_ctxt, lhs: @expr, rhs: @expr, larger_id: node_id, - new_var: node_id, pth: @path) { - alt node_id_to_def(fcx.ccx, new_var) { - some(d) { - alt d { - def_local(nid, _) { - find_pre_post_expr(fcx, rhs); - let p = expr_pp(fcx.ccx, rhs); - set_pre_and_post(fcx.ccx, larger_id, p.precondition, - p.postcondition); - gen(fcx, larger_id, - ninit(nid, path_to_ident(pth))); - } - _ { find_pre_post_exprs(fcx, [lhs, rhs], larger_id); } - } - } - _ { find_pre_post_exprs(fcx, [lhs, rhs], larger_id); } - } -} - -fn handle_update(fcx: fn_ctxt, parent: @expr, lhs: @expr, rhs: @expr, - ty: oper_type) { - find_pre_post_expr(fcx, rhs); - alt lhs.node { - expr_path(p) { - let post = expr_postcond(fcx.ccx, parent); - let tmp = tritv_clone(post); - - alt ty { - oper_move { - if is_path(rhs) { forget_in_postcond(fcx, parent.id, rhs.id); } - } - oper_swap { - forget_in_postcond_still_init(fcx, parent.id, lhs.id); - forget_in_postcond_still_init(fcx, parent.id, rhs.id); - } - oper_assign { - forget_in_postcond_still_init(fcx, parent.id, lhs.id); - } - _ { - // pure and assign_op require the lhs to be init'd - let df = node_id_to_def_strict(fcx.ccx.tcx, lhs.id); - alt df { - def_local(nid, _) { - let i = bit_num(fcx, ninit(nid, path_to_ident(p))); - require_and_preserve(i, expr_pp(fcx.ccx, lhs)); - } - _ { } - } - } - } - - gen_if_local(fcx, lhs, rhs, parent.id, lhs.id, p); - alt rhs.node { - expr_path(p1) { - let d = local_node_id_to_local_def_id(fcx, lhs.id); - let d1 = local_node_id_to_local_def_id(fcx, rhs.id); - alt d { - some(id) { - alt d1 { - some(id1) { - let instlhs = - {ident: path_to_ident(p), node: id}; - let instrhs = - {ident: path_to_ident(p1), node: id1}; - copy_in_poststate_two(fcx, tmp, post, instlhs, instrhs, - ty); - } - _ { } - } - } - _ { } - } - } - _ {/* do nothing */ } - } - } - _ { find_pre_post_expr(fcx, lhs); } - } -} - -fn handle_var(fcx: fn_ctxt, rslt: pre_and_post, id: node_id, name: ident) { - handle_var_def(fcx, rslt, node_id_to_def_strict(fcx.ccx.tcx, id), name); -} - -fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) { - log(debug, ("handle_var_def: ", def, name)); - alt def { - def_local(nid, _) | def_arg(nid, _) { - use_var(fcx, nid); - let i = bit_num(fcx, ninit(nid, name)); - require_and_preserve(i, rslt); - } - _ {/* nothing to check */ } - } -} - -fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [mode], - operands: [@expr]) { - vec::iteri(modes) {|i,mode| - alt ty::resolved_mode(fcx.ccx.tcx, mode) { - by_move { forget_in_postcond(fcx, parent.id, operands[i].id); } - by_ref | by_val | by_mutbl_ref | by_copy { } - } - } -} - -fn find_pre_post_expr_fn_upvars(fcx: fn_ctxt, e: @expr) { - let rslt = expr_pp(fcx.ccx, e); - clear_pp(rslt); - for def in *freevars::get_freevars(fcx.ccx.tcx, e.id) { - log(debug, ("handle_var_def: def=", def)); - handle_var_def(fcx, rslt, def.def, "upvar"); - } -} - -/* Fills in annotations as a side effect. Does not rebuild the expr */ -fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { - let enclosing = fcx.enclosing; - let num_local_vars = num_constraints(enclosing); - fn do_rand_(fcx: fn_ctxt, e: @expr) { find_pre_post_expr(fcx, e); } - - - alt e.node { - expr_call(operator, operands, _) { - /* copy */ - - let args = operands; - args += [operator]; - - find_pre_post_exprs(fcx, args, e.id); - /* see if the call has any constraints on its type */ - for c: @ty::constr in constraints_expr(fcx.ccx.tcx, operator) { - let i = - bit_num(fcx, substitute_constr_args(fcx.ccx.tcx, args, c)); - require(i, expr_pp(fcx.ccx, e)); - } - - forget_args_moved_in(fcx, e, callee_modes(fcx, operator.id), - operands); - - /* if this is a failing call, its postcondition sets everything */ - alt controlflow_expr(fcx.ccx, operator) { - noreturn { set_postcond_false(fcx.ccx, e.id); } - _ { } - } - } - expr_vec(args, _) { find_pre_post_exprs(fcx, args, e.id); } - expr_path(p) { - let rslt = expr_pp(fcx.ccx, e); - clear_pp(rslt); - handle_var(fcx, rslt, e.id, path_to_ident(p)); - } - expr_log(_, lvl, arg) { - find_pre_post_exprs(fcx, [lvl, arg], e.id); - } - expr_fn(_, _, _, cap_clause) { - find_pre_post_expr_fn_upvars(fcx, e); - - let use_cap_item = fn@(&&cap_item: @capture_item) { - let d = local_node_id_to_local_def_id(fcx, cap_item.id); - option::may(d, { |id| use_var(fcx, id) }); - }; - vec::iter(cap_clause.copies, use_cap_item); - vec::iter(cap_clause.moves, use_cap_item); - - vec::iter(cap_clause.moves) { |cap_item| - log(debug, ("forget_in_postcond: ", cap_item)); - forget_in_postcond(fcx, e.id, cap_item.id); - } - } - expr_fn_block(_, _) { - find_pre_post_expr_fn_upvars(fcx, e); - } - expr_block(b) { - find_pre_post_block(fcx, b); - let p = block_pp(fcx.ccx, b); - set_pre_and_post(fcx.ccx, e.id, p.precondition, p.postcondition); - } - expr_rec(fields, maybe_base) { - let es = field_exprs(fields); - alt maybe_base { none {/* no-op */ } some(b) { es += [b]; } } - find_pre_post_exprs(fcx, es, e.id); - } - expr_tup(elts) { find_pre_post_exprs(fcx, elts, e.id); } - expr_copy(a) { - find_pre_post_expr(fcx, a); - copy_pre_post(fcx.ccx, e.id, a); - } - expr_move(lhs, rhs) { handle_update(fcx, e, lhs, rhs, oper_move); } - expr_swap(lhs, rhs) { handle_update(fcx, e, lhs, rhs, oper_swap); } - expr_assign(lhs, rhs) { handle_update(fcx, e, lhs, rhs, oper_assign); } - expr_assign_op(_, lhs, rhs) { - /* Different from expr_assign in that the lhs *must* - already be initialized */ - - find_pre_post_exprs(fcx, [lhs, rhs], e.id); - forget_in_postcond_still_init(fcx, e.id, lhs.id); - } - expr_lit(_) { clear_pp(expr_pp(fcx.ccx, e)); } - expr_ret(maybe_val) { - alt maybe_val { - none { - clear_precond(fcx.ccx, e.id); - set_postcond_false(fcx.ccx, e.id); - } - some(ret_val) { - find_pre_post_expr(fcx, ret_val); - set_precondition(node_id_to_ts_ann(fcx.ccx, e.id), - expr_precond(fcx.ccx, ret_val)); - set_postcond_false(fcx.ccx, e.id); - } - } - } - expr_be(val) { - find_pre_post_expr(fcx, val); - set_pre_and_post(fcx.ccx, e.id, expr_prestate(fcx.ccx, val), - false_postcond(num_local_vars)); - } - expr_if(antec, conseq, maybe_alt) { - join_then_else(fcx, antec, conseq, maybe_alt, e.id, plain_if); - } - expr_binary(bop, l, r) { - if lazy_binop(bop) { - find_pre_post_expr(fcx, l); - find_pre_post_expr(fcx, r); - let overall_pre = - seq_preconds(fcx, [expr_pp(fcx.ccx, l), expr_pp(fcx.ccx, r)]); - set_precondition(node_id_to_ts_ann(fcx.ccx, e.id), overall_pre); - set_postcondition(node_id_to_ts_ann(fcx.ccx, e.id), - expr_postcond(fcx.ccx, l)); - } else { find_pre_post_exprs(fcx, [l, r], e.id); } - } - expr_unary(_, operand) { - find_pre_post_expr(fcx, operand); - copy_pre_post(fcx.ccx, e.id, operand); - } - expr_cast(operand, _) { - find_pre_post_expr(fcx, operand); - copy_pre_post(fcx.ccx, e.id, operand); - } - expr_while(test, body) { - find_pre_post_expr(fcx, test); - find_pre_post_block(fcx, body); - set_pre_and_post(fcx.ccx, e.id, - seq_preconds(fcx, - [expr_pp(fcx.ccx, test), - block_pp(fcx.ccx, body)]), - intersect_states(expr_postcond(fcx.ccx, test), - block_postcond(fcx.ccx, body))); - } - expr_do_while(body, test) { - find_pre_post_block(fcx, body); - find_pre_post_expr(fcx, test); - let loop_postcond = - seq_postconds(fcx, - [block_postcond(fcx.ccx, body), - expr_postcond(fcx.ccx, test)]); - /* conservative approximation: if the body - could break or cont, the test may never be executed */ - - if has_nonlocal_exits(body) { - loop_postcond = empty_poststate(num_local_vars); - } - set_pre_and_post(fcx.ccx, e.id, - seq_preconds(fcx, - [block_pp(fcx.ccx, body), - expr_pp(fcx.ccx, test)]), - loop_postcond); - } - expr_for(d, index, body) { - find_pre_post_loop(fcx, d, index, body, e.id); - } - expr_index(val, sub) { find_pre_post_exprs(fcx, [val, sub], e.id); } - expr_alt(ex, alts, _) { - find_pre_post_expr(fcx, ex); - fn do_an_alt(fcx: fn_ctxt, an_alt: arm) -> pre_and_post { - alt an_alt.guard { - some(e) { find_pre_post_expr(fcx, e); } - _ {} - } - find_pre_post_block(fcx, an_alt.body); - ret block_pp(fcx.ccx, an_alt.body); - } - let alt_pps = []; - for a: arm in alts { alt_pps += [do_an_alt(fcx, a)]; } - fn combine_pp(antec: pre_and_post, fcx: fn_ctxt, &&pp: pre_and_post, - &&next: pre_and_post) -> pre_and_post { - union(pp.precondition, seq_preconds(fcx, [antec, next])); - intersect(pp.postcondition, next.postcondition); - ret pp; - } - let antec_pp = pp_clone(expr_pp(fcx.ccx, ex)); - let e_pp = - @{precondition: empty_prestate(num_local_vars), - postcondition: false_postcond(num_local_vars)}; - let g = bind combine_pp(antec_pp, fcx, _, _); - let alts_overall_pp = - vec::foldl(e_pp, alt_pps, g); - set_pre_and_post(fcx.ccx, e.id, alts_overall_pp.precondition, - alts_overall_pp.postcondition); - } - expr_field(operator, _, _) { - find_pre_post_expr(fcx, operator); - copy_pre_post(fcx.ccx, e.id, operator); - } - expr_fail(maybe_val) { - let prestate; - alt maybe_val { - none { prestate = empty_prestate(num_local_vars); } - some(fail_val) { - find_pre_post_expr(fcx, fail_val); - prestate = expr_precond(fcx.ccx, fail_val); - } - } - set_pre_and_post(fcx.ccx, e.id, - /* if execution continues after fail, - then everything is true! */ - prestate, false_postcond(num_local_vars)); - } - expr_assert(p) { - find_pre_post_expr(fcx, p); - copy_pre_post(fcx.ccx, e.id, p); - } - expr_check(_, p) { - find_pre_post_expr(fcx, p); - copy_pre_post(fcx.ccx, e.id, p); - /* predicate p holds after this expression executes */ - - let c: sp_constr = expr_to_constr(fcx.ccx.tcx, p); - gen(fcx, e.id, c.node); - } - expr_if_check(p, conseq, maybe_alt) { - join_then_else(fcx, p, conseq, maybe_alt, e.id, if_check); - } - - - - - - - expr_bind(operator, maybe_args) { - let args = []; - let cmodes = callee_modes(fcx, operator.id); - let modes = []; - let i = 0; - for expr_opt: option<@expr> in maybe_args { - alt expr_opt { - none {/* no-op */ } - some(expr) { modes += [cmodes[i]]; args += [expr]; } - } - i += 1; - } - args += [operator]; /* ??? order of eval? */ - forget_args_moved_in(fcx, e, modes, args); - find_pre_post_exprs(fcx, args, e.id); - } - expr_break { clear_pp(expr_pp(fcx.ccx, e)); } - expr_cont { clear_pp(expr_pp(fcx.ccx, e)); } - expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); } - } -} - -fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { - #debug("stmt ="); - log_stmt(s); - alt s.node { - stmt_decl(adecl, id) { - alt adecl.node { - decl_local(alocals) { - let e_pp; - let prev_pp = empty_pre_post(num_constraints(fcx.enclosing)); - for alocal in alocals { - alt alocal.node.init { - some(an_init) { - /* LHS always becomes initialized, - whether or not this is a move */ - find_pre_post_expr(fcx, an_init.expr); - pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat) - {|p_id, _s, _n| - copy_pre_post(fcx.ccx, p_id, an_init.expr); - }; - /* Inherit ann from initializer, and add var being - initialized to the postcondition */ - copy_pre_post(fcx.ccx, id, an_init.expr); - - let p = none; - alt an_init.expr.node { - expr_path(_p) { p = some(_p); } - _ { } - } - - pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat) - {|p_id, _s, n| - let ident = path_to_ident(n); - alt p { - some(p) { - copy_in_postcond(fcx, id, - {ident: ident, node: p_id}, - {ident: - path_to_ident(p), - node: an_init.expr.id}, - op_to_oper_ty(an_init.op)); - } - none { } - } - gen(fcx, id, ninit(p_id, ident)); - }; - - if an_init.op == init_move && is_path(an_init.expr) { - forget_in_postcond(fcx, id, an_init.expr.id); - } - - /* Clear out anything that the previous initializer - guaranteed */ - e_pp = expr_pp(fcx.ccx, an_init.expr); - tritv_copy(prev_pp.precondition, - seq_preconds(fcx, [prev_pp, e_pp])); - /* Include the LHSs too, since those aren't in the - postconds of the RHSs themselves */ - pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat) - {|pat_id, _s, n| - set_in_postcond(bit_num(fcx, - ninit(pat_id, path_to_ident(n))), prev_pp); - }; - copy_pre_post_(fcx.ccx, id, prev_pp.precondition, - prev_pp.postcondition); - } - none { - pat_bindings(fcx.ccx.tcx.def_map, alocal.node.pat) - {|p_id, _s, _n| - clear_pp(node_id_to_ts_ann(fcx.ccx, p_id).conditions); - }; - clear_pp(node_id_to_ts_ann(fcx.ccx, id).conditions); - } - } - } - } - decl_item(anitem) { - clear_pp(node_id_to_ts_ann(fcx.ccx, id).conditions); - find_pre_post_item(fcx.ccx, *anitem); - } - } - } - stmt_expr(e, id) | stmt_semi(e, id) { - find_pre_post_expr(fcx, e); - copy_pre_post(fcx.ccx, id, e); - } - } -} - -fn find_pre_post_block(fcx: fn_ctxt, b: blk) { - /* Want to say that if there is a break or cont in this - block, then that invalidates the poststate upheld by - any of the stmts after it. - Given that the typechecker has run, we know any break will be in - a block that forms a loop body. So that's ok. There'll never be an - expr_break outside a loop body, therefore, no expr_break outside a block. - */ - - /* Conservative approximation for now: This says that if a block contains - *any* breaks or conts, then its postcondition doesn't promise anything. - This will mean that: - x = 0; - break; - - won't have a postcondition that says x is initialized, but that's ok. - */ - - let nv = num_constraints(fcx.enclosing); - fn do_one_(fcx: fn_ctxt, s: @stmt) { - find_pre_post_stmt(fcx, *s); - /* - #error("pre_post for stmt:"); - log_stmt_err(*s); - #error("is:"); - log_pp_err(stmt_pp(fcx.ccx, *s)); - */ - } - for s: @stmt in b.node.stmts { do_one_(fcx, s); } - fn do_inner_(fcx: fn_ctxt, &&e: @expr) { find_pre_post_expr(fcx, e); } - let do_inner = bind do_inner_(fcx, _); - option::map::<@expr, ()>(b.node.expr, do_inner); - - let pps: [pre_and_post] = []; - for s: @stmt in b.node.stmts { pps += [stmt_pp(fcx.ccx, *s)]; } - alt b.node.expr { - none {/* no-op */ } - some(e) { pps += [expr_pp(fcx.ccx, e)]; } - } - - let block_precond = seq_preconds(fcx, pps); - - let postconds = []; - for pp: pre_and_post in pps { postconds += [get_post(pp)]; } - - /* A block may be empty, so this next line ensures that the postconds - vector is non-empty. */ - postconds += [block_precond]; - - let block_postcond = empty_poststate(nv); - /* conservative approximation */ - - if !has_nonlocal_exits(b) { - block_postcond = seq_postconds(fcx, postconds); - } - set_pre_and_post(fcx.ccx, b.node.id, block_precond, block_postcond); -} - -fn find_pre_post_fn(fcx: fn_ctxt, body: blk) { - // hack - use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_return)); - use_var(fcx, tsconstr_to_node_id(fcx.enclosing.i_diverge)); - - find_pre_post_block(fcx, body); - - // Treat the tail expression as a return statement - alt body.node.expr { - some(tailexpr) { set_postcond_false(fcx.ccx, tailexpr.id); } - none {/* fallthrough */ } - } -} - -fn fn_pre_post(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span, - id: node_id, - ccx: crate_ctxt, v: visit::vt<crate_ctxt>) { - visit::visit_fn(fk, decl, body, sp, id, ccx, v); - assert (ccx.fm.contains_key(id)); - let fcx = - {enclosing: ccx.fm.get(id), - id: id, - name: visit::name_of_fn(fk), - ccx: ccx}; - find_pre_post_fn(fcx, body); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs deleted file mode 100644 index b90e39f2b23..00000000000 --- a/src/comp/middle/tstate/states.rs +++ /dev/null @@ -1,783 +0,0 @@ -import ann::*; -import aux::*; -import tritv::{tritv_clone, tritv_set, ttrue}; - -import bitvectors::*; -import pat_util::*; -import syntax::ast::*; -import syntax::ast_util::*; -import syntax::codemap::span; -import middle::ty::{expr_ty, type_is_bot}; -import util::common::*; -import driver::session::session; - -fn forbid_upvar(fcx: fn_ctxt, rhs_id: node_id, sp: span, t: oper_type) { - alt t { - oper_move { - alt local_node_id_to_def(fcx, rhs_id) { - some(def_upvar(_, _, _)) { - fcx.ccx.tcx.sess.span_err(sp, - "Tried to deinitialize a variable \ - declared in a different scope"); - } - _ { } - } - } - _ {/* do nothing */ } - } -} - -fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path, - rhs_id: node_id, instlhs: inst, init_op: init_op) { - forbid_upvar(fcx, rhs_id, rhs_path.span, op_to_oper_ty(init_op)); - - let rhs_d_id = local_node_id_to_def_id(fcx, rhs_id); - alt rhs_d_id { - some(rhsid) { - // RHS is a local var - let instrhs = - {ident: path_to_ident(rhs_path), node: rhsid.node}; - copy_in_poststate(fcx, post, instlhs, instrhs, - op_to_oper_ty(init_op)); - } - _ { - // not a local -- do nothing - } - } -} - -fn handle_fail(fcx: fn_ctxt, pres:prestate, post:poststate) { - // Remember what the old value of the "I return" trit was, so that - // we can avoid changing that (if it was true, there was a return - // that dominates this fail and the fail is unreachable) - if !promises(fcx, pres, fcx.enclosing.i_return) - // (only if we're in a diverging function -- you can fail when - // you're supposed to return, but not vice versa). - && fcx.enclosing.cf == noreturn { - kill_poststate_(fcx, fcx.enclosing.i_return, post); - } else { - // This code is unreachable (it's dominated by a return), - // so doesn't diverge. - kill_poststate_(fcx, fcx.enclosing.i_diverge, post); - } -} - -fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: [binding]) -> - {changed: bool, post: poststate} { - let changed = false; - let post = tritv_clone(pres); - for b: binding in bindings { - alt b.rhs { - some(an_init) { - // an expression, with or without a destination - changed |= - find_pre_post_state_expr(fcx, post, an_init.expr) || changed; - post = tritv_clone(expr_poststate(fcx.ccx, an_init.expr)); - for i: inst in b.lhs { - alt an_init.expr.node { - expr_path(p) { - handle_move_or_copy(fcx, post, p, an_init.expr.id, i, - an_init.op); - } - _ { } - } - set_in_poststate_ident(fcx, i.node, i.ident, post); - } - - // Forget the RHS if we just moved it. - if an_init.op == init_move { - forget_in_poststate(fcx, post, an_init.expr.id); - } - } - none { - for i: inst in b.lhs { - // variables w/o an initializer - clear_in_poststate_ident_(fcx, i.node, i.ident, post); - } - } - } - } - ret {changed: changed, post: post}; -} - -fn find_pre_post_state_sub(fcx: fn_ctxt, pres: prestate, e: @expr, - parent: node_id, c: option<tsconstr>) -> bool { - let changed = find_pre_post_state_expr(fcx, pres, e); - - changed = set_prestate_ann(fcx.ccx, parent, pres) || changed; - - let post = tritv_clone(expr_poststate(fcx.ccx, e)); - alt c { - none { } - some(c1) { set_in_poststate_(bit_num(fcx, c1), post); } - } - - changed = set_poststate_ann(fcx.ccx, parent, post) || changed; - ret changed; -} - -fn find_pre_post_state_two(fcx: fn_ctxt, pres: prestate, lhs: @expr, - rhs: @expr, parent: node_id, ty: oper_type) -> - bool { - let changed = set_prestate_ann(fcx.ccx, parent, pres); - changed = find_pre_post_state_expr(fcx, pres, lhs) || changed; - changed = - find_pre_post_state_expr(fcx, expr_poststate(fcx.ccx, lhs), rhs) || - changed; - forbid_upvar(fcx, rhs.id, rhs.span, ty); - - let post = tritv_clone(expr_poststate(fcx.ccx, rhs)); - - alt lhs.node { - expr_path(p) { - // for termination, need to make sure intermediate changes don't set - // changed flag - // tmp remembers "old" constraints we'd otherwise forget, - // for substitution purposes - let tmp = tritv_clone(post); - - alt ty { - oper_move { - if is_path(rhs) { forget_in_poststate(fcx, post, rhs.id); } - forget_in_poststate_still_init(fcx, post, lhs.id); - } - oper_swap { - forget_in_poststate_still_init(fcx, post, lhs.id); - forget_in_poststate_still_init(fcx, post, rhs.id); - } - _ { forget_in_poststate_still_init(fcx, post, lhs.id); } - } - - gen_if_local(fcx, post, lhs); - alt rhs.node { - expr_path(p1) { - let d = local_node_id_to_local_def_id(fcx, lhs.id); - let d1 = local_node_id_to_local_def_id(fcx, rhs.id); - alt d { - some(id) { - alt d1 { - some(id1) { - let instlhs = - {ident: path_to_ident(p), node: id}; - let instrhs = - {ident: path_to_ident(p1), node: id1}; - copy_in_poststate_two(fcx, tmp, post, instlhs, instrhs, - ty); - } - _ { } - } - } - _ { } - } - } - _ {/* do nothing */ } - } - } - _ { } - } - changed = set_poststate_ann(fcx.ccx, parent, post) || changed; - ret changed; -} - -fn find_pre_post_state_call(fcx: fn_ctxt, pres: prestate, a: @expr, - id: node_id, ops: [init_op], bs: [@expr], - cf: ret_style) -> bool { - let changed = find_pre_post_state_expr(fcx, pres, a); - // FIXME: This could be a typestate constraint - if vec::len(bs) != vec::len(ops) { - fcx.ccx.tcx.sess.span_bug(a.span, - #fmt["mismatched arg lengths: \ - %u exprs vs. %u ops", - vec::len(bs), vec::len(ops)]); - } - ret find_pre_post_state_exprs(fcx, pres, id, ops, - bs, cf) || changed; -} - -fn find_pre_post_state_exprs(fcx: fn_ctxt, pres: prestate, id: node_id, - ops: [init_op], es: [@expr], cf: ret_style) -> - bool { - let rs = seq_states(fcx, pres, anon_bindings(ops, es)); - let changed = rs.changed | set_prestate_ann(fcx.ccx, id, pres); - /* if this is a failing call, it sets everything as initialized */ - alt cf { - noreturn { - let post = false_postcond(num_constraints(fcx.enclosing)); - handle_fail(fcx, pres, post); - changed |= set_poststate_ann(fcx.ccx, id, post); - } - _ { changed |= set_poststate_ann(fcx.ccx, id, rs.post); } - } - ret changed; -} - -fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local, - index: @expr, body: blk, id: node_id) -> bool { - // I'm confused about this -- how does the poststate for the body - // ever grow larger? It seems like it can't? - let loop_pres = intersect_states(pres, block_poststate(fcx.ccx, body)); - - let changed = - set_prestate_ann(fcx.ccx, id, loop_pres) | - find_pre_post_state_expr(fcx, pres, index); - - // Make sure the index vars are considered initialized - // in the body - let index_post = tritv_clone(expr_poststate(fcx.ccx, index)); - pat_bindings(fcx.ccx.tcx.def_map, l.node.pat) {|p_id, _s, n| - set_in_poststate_ident(fcx, p_id, path_to_ident(n), index_post); - }; - - changed |= find_pre_post_state_block(fcx, index_post, body); - - - if has_nonlocal_exits(body) { - // See [Break-unsound] - ret changed | set_poststate_ann(fcx.ccx, id, pres); - } else { - let res_p = - intersect_states(expr_poststate(fcx.ccx, index), - block_poststate(fcx.ccx, body)); - ret changed | set_poststate_ann(fcx.ccx, id, res_p); - } -} - -fn gen_if_local(fcx: fn_ctxt, p: poststate, e: @expr) -> bool { - alt e.node { - expr_path(pth) { - alt fcx.ccx.tcx.def_map.find(e.id) { - some(def_local(nid, _)) { - ret set_in_poststate_ident(fcx, nid, path_to_ident(pth), p); - } - _ { ret false; } - } - } - _ { ret false; } - } -} - -fn join_then_else(fcx: fn_ctxt, antec: @expr, conseq: blk, - maybe_alt: option<@expr>, id: node_id, chk: if_ty, - pres: prestate) -> bool { - let changed = - set_prestate_ann(fcx.ccx, id, pres) | - find_pre_post_state_expr(fcx, pres, antec); - - /* - log_err("join_then_else:"); - log_expr_err(*antec); - log_bitv_err(fcx, expr_prestate(fcx.ccx, antec)); - log_bitv_err(fcx, expr_poststate(fcx.ccx, antec)); - log_block_err(conseq); - log_bitv_err(fcx, block_prestate(fcx.ccx, conseq)); - log_bitv_err(fcx, block_poststate(fcx.ccx, conseq)); - log_err("****"); - log_bitv_err(fcx, expr_precond(fcx.ccx, antec)); - log_bitv_err(fcx, expr_postcond(fcx.ccx, antec)); - log_bitv_err(fcx, block_precond(fcx.ccx, conseq)); - log_bitv_err(fcx, block_postcond(fcx.ccx, conseq)); - */ - - alt maybe_alt { - none { - alt chk { - if_check { - let c: sp_constr = expr_to_constr(fcx.ccx.tcx, antec); - let conseq_prestate = tritv_clone(expr_poststate(fcx.ccx, antec)); - tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue); - changed |= - find_pre_post_state_block(fcx, conseq_prestate, conseq) | - set_poststate_ann(fcx.ccx, id, - expr_poststate(fcx.ccx, antec)); - } - _ { - changed |= - find_pre_post_state_block(fcx, expr_poststate(fcx.ccx, antec), - conseq) | - set_poststate_ann(fcx.ccx, id, - expr_poststate(fcx.ccx, antec)); - } - } - } - some(altern) { - changed |= - find_pre_post_state_expr(fcx, expr_poststate(fcx.ccx, antec), - altern); - - let conseq_prestate = expr_poststate(fcx.ccx, antec); - alt chk { - if_check { - let c: sp_constr = expr_to_constr(fcx.ccx.tcx, antec); - conseq_prestate = tritv_clone(conseq_prestate); - tritv_set(bit_num(fcx, c.node), conseq_prestate, ttrue); - } - _ { } - } - - - changed |= find_pre_post_state_block(fcx, conseq_prestate, conseq); - - let poststate_res = - intersect_states(block_poststate(fcx.ccx, conseq), - expr_poststate(fcx.ccx, altern)); - /* - fcx.ccx.tcx.sess.span_note(antec.span, - "poststate_res = " + aux::tritv_to_str(fcx, poststate_res)); - fcx.ccx.tcx.sess.span_note(antec.span, - "altern poststate = " + - aux::tritv_to_str(fcx, expr_poststate(fcx.ccx, altern))); - fcx.ccx.tcx.sess.span_note(antec.span, - "conseq poststate = " + aux::tritv_to_str(fcx, - block_poststate(fcx.ccx, conseq))); - */ - - changed |= set_poststate_ann(fcx.ccx, id, poststate_res); - } - } - ret changed; -} - -fn find_pre_post_state_cap_clause(fcx: fn_ctxt, e_id: node_id, - pres: prestate, cap_clause: capture_clause) - -> bool -{ - let ccx = fcx.ccx; - let pres_changed = set_prestate_ann(ccx, e_id, pres); - let post = tritv_clone(pres); - vec::iter(cap_clause.moves) { |cap_item| - forget_in_poststate(fcx, post, cap_item.id); - } - ret set_poststate_ann(ccx, e_id, post) || pres_changed; -} - -fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { - let num_constrs = num_constraints(fcx.enclosing); - - - alt e.node { - expr_vec(elts, _) { - ret find_pre_post_state_exprs(fcx, pres, e.id, - vec::init_elt(vec::len(elts), - init_assign), elts, - return_val); - } - expr_call(operator, operands, _) { - ret find_pre_post_state_call(fcx, pres, operator, e.id, - callee_arg_init_ops(fcx, operator.id), - operands, - controlflow_expr(fcx.ccx, operator)); - } - expr_bind(operator, maybe_args) { - let args = []; - let callee_ops = callee_arg_init_ops(fcx, operator.id); - let ops = []; - let i = 0; - for a_opt: option<@expr> in maybe_args { - alt a_opt { - none {/* no-op */ } - some(a) { ops += [callee_ops[i]]; args += [a]; } - } - i += 1; - } - ret find_pre_post_state_call(fcx, pres, operator, e.id, ops, args, - return_val); - } - expr_path(_) { ret pure_exp(fcx.ccx, e.id, pres); } - expr_log(_, lvl, ex) { - ret find_pre_post_state_two(fcx, pres, lvl, ex, e.id, oper_pure); - } - expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); } - expr_lit(l) { ret pure_exp(fcx.ccx, e.id, pres); } - expr_fn(_, _, _, cap_clause) { - ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause); - } - expr_fn_block(_, _) { ret pure_exp(fcx.ccx, e.id, pres); } - expr_block(b) { - ret find_pre_post_state_block(fcx, pres, b) | - set_prestate_ann(fcx.ccx, e.id, pres) | - set_poststate_ann(fcx.ccx, e.id, block_poststate(fcx.ccx, b)); - } - expr_rec(fields, maybe_base) { - let exs = field_exprs(fields); - let changed = - find_pre_post_state_exprs(fcx, pres, e.id, - vec::init_elt(vec::len(fields), - init_assign), - exs, return_val); - - let base_pres = alt vec::last(exs) { none { pres } - some(f) { expr_poststate(fcx.ccx, f) }}; - option::may(maybe_base, {|base| - changed |= find_pre_post_state_expr(fcx, base_pres, base) | - set_poststate_ann(fcx.ccx, e.id, - expr_poststate(fcx.ccx, base))}); - ret changed; - } - expr_tup(elts) { - ret find_pre_post_state_exprs(fcx, pres, e.id, - vec::init_elt(vec::len(elts), - init_assign), elts, - return_val); - } - expr_copy(a) { ret find_pre_post_state_sub(fcx, pres, a, e.id, none); } - expr_move(lhs, rhs) { - ret find_pre_post_state_two(fcx, pres, lhs, rhs, e.id, oper_move); - } - expr_assign(lhs, rhs) { - ret find_pre_post_state_two(fcx, pres, lhs, rhs, e.id, oper_assign); - } - expr_swap(lhs, rhs) { - ret find_pre_post_state_two(fcx, pres, lhs, rhs, e.id, oper_swap); - // Could be more precise and actually swap the role of - // lhs and rhs in constraints - } - expr_ret(maybe_ret_val) { - let changed = set_prestate_ann(fcx.ccx, e.id, pres); - /* normally, everything is true if execution continues after - a ret expression (since execution never continues locally - after a ret expression */ - // FIXME should factor this out - let post = false_postcond(num_constrs); - // except for the "diverges" bit... - kill_poststate_(fcx, fcx.enclosing.i_diverge, post); - - set_poststate_ann(fcx.ccx, e.id, post); - - alt maybe_ret_val { - none {/* do nothing */ } - some(ret_val) { - changed |= find_pre_post_state_expr(fcx, pres, ret_val); - } - } - ret changed; - } - expr_be(val) { - let changed = set_prestate_ann(fcx.ccx, e.id, pres); - let post = false_postcond(num_constrs); - // except for the "diverges" bit... - kill_poststate_(fcx, fcx.enclosing.i_diverge, post); - set_poststate_ann(fcx.ccx, e.id, post); - ret changed | find_pre_post_state_expr(fcx, pres, val); - } - expr_if(antec, conseq, maybe_alt) { - ret join_then_else(fcx, antec, conseq, maybe_alt, e.id, plain_if, - pres); - } - expr_binary(bop, l, r) { - if lazy_binop(bop) { - let changed = find_pre_post_state_expr(fcx, pres, l); - changed |= - find_pre_post_state_expr(fcx, expr_poststate(fcx.ccx, l), r); - ret changed | set_prestate_ann(fcx.ccx, e.id, pres) | - set_poststate_ann(fcx.ccx, e.id, - expr_poststate(fcx.ccx, l)); - } else { - ret find_pre_post_state_two(fcx, pres, l, r, e.id, oper_pure); - } - } - expr_assign_op(op, lhs, rhs) { - ret find_pre_post_state_two(fcx, pres, lhs, rhs, e.id, - oper_assign_op); - } - expr_while(test, body) { - /* - #error("in a while loop:"); - log_expr_err(*e); - aux::log_tritv_err(fcx, block_poststate(fcx.ccx, body)); - aux::log_tritv_err(fcx, pres); - */ - let loop_pres = - intersect_states(block_poststate(fcx.ccx, body), pres); - // aux::log_tritv_err(fcx, loop_pres); - // #error("---------------"); - - let changed = - set_prestate_ann(fcx.ccx, e.id, loop_pres) | - find_pre_post_state_expr(fcx, loop_pres, test) | - find_pre_post_state_block(fcx, expr_poststate(fcx.ccx, test), - body); - - /* conservative approximation: if a loop contains a break - or cont, we assume nothing about the poststate */ - /* which is still unsound -- see [Break-unsound] */ - if has_nonlocal_exits(body) { - ret changed | set_poststate_ann(fcx.ccx, e.id, pres); - } else { - let e_post = expr_poststate(fcx.ccx, test); - let b_post = block_poststate(fcx.ccx, body); - ret changed | - set_poststate_ann(fcx.ccx, e.id, - intersect_states(e_post, b_post)); - } - } - expr_do_while(body, test) { - let loop_pres = intersect_states(expr_poststate(fcx.ccx, test), pres); - - let changed = set_prestate_ann(fcx.ccx, e.id, loop_pres); - changed |= find_pre_post_state_block(fcx, loop_pres, body); - /* conservative approximination: if the body of the loop - could break or cont, we revert to the prestate - (TODO: could treat cont differently from break, since - if there's a cont, the test will execute) */ - - changed |= - find_pre_post_state_expr(fcx, block_poststate(fcx.ccx, body), - test); - - let breaks = has_nonlocal_exits(body); - if breaks { - // this should probably be true_poststate and not pres, - // b/c the body could invalidate stuff - // FIXME [Break-unsound] - // This is unsound as it is -- consider - // while (true) { - // x <- y; - // break; - // } - // The poststate wouldn't take into account that - // y gets deinitialized - changed |= set_poststate_ann(fcx.ccx, e.id, pres); - } else { - changed |= - set_poststate_ann(fcx.ccx, e.id, - expr_poststate(fcx.ccx, test)); - } - ret changed; - } - expr_for(d, index, body) { - ret find_pre_post_state_loop(fcx, pres, d, index, body, e.id); - } - expr_index(val, sub) { - ret find_pre_post_state_two(fcx, pres, val, sub, e.id, oper_pure); - } - expr_alt(val, alts, _) { - let changed = - set_prestate_ann(fcx.ccx, e.id, pres) | - find_pre_post_state_expr(fcx, pres, val); - let e_post = expr_poststate(fcx.ccx, val); - let a_post; - if vec::len(alts) > 0u { - a_post = false_postcond(num_constrs); - for an_alt: arm in alts { - alt an_alt.guard { - some(e) { - changed |= find_pre_post_state_expr(fcx, e_post, e); - } - _ {} - } - changed |= - find_pre_post_state_block(fcx, e_post, an_alt.body); - intersect(a_post, block_poststate(fcx.ccx, an_alt.body)); - // We deliberately do *not* update changed here, because - // we'd go into an infinite loop that way, and the change - // gets made after the if expression. - - } - } else { - // No alts; poststate is the poststate of the test - - a_post = e_post; - } - ret changed | set_poststate_ann(fcx.ccx, e.id, a_post); - } - expr_field(val, _, _) { - ret find_pre_post_state_sub(fcx, pres, val, e.id, none); - } - expr_unary(_, operand) { - ret find_pre_post_state_sub(fcx, pres, operand, e.id, none); - } - expr_cast(operand, _) { - ret find_pre_post_state_sub(fcx, pres, operand, e.id, none); - } - expr_fail(maybe_fail_val) { - // FIXME Should factor out this code, - // which also appears in find_pre_post_state_exprs - /* if execution continues after fail, then everything is true! - woo! */ - let post = false_postcond(num_constrs); - handle_fail(fcx, pres, post); - ret set_prestate_ann(fcx.ccx, e.id, pres) | - set_poststate_ann(fcx.ccx, e.id, post) | - option::maybe(false, maybe_fail_val, {|fail_val| - find_pre_post_state_expr(fcx, pres, fail_val)}); - } - expr_assert(p) { - ret find_pre_post_state_sub(fcx, pres, p, e.id, none); - } - expr_check(_, p) { - /* predicate p holds after this expression executes */ - let c: sp_constr = expr_to_constr(fcx.ccx.tcx, p); - ret find_pre_post_state_sub(fcx, pres, p, e.id, some(c.node)); - } - expr_if_check(p, conseq, maybe_alt) { - ret join_then_else(fcx, p, conseq, maybe_alt, e.id, if_check, pres); - } - expr_break { ret pure_exp(fcx.ccx, e.id, pres); } - expr_cont { ret pure_exp(fcx.ccx, e.id, pres); } - } -} - -fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool { - let stmt_ann = stmt_to_ann(fcx.ccx, *s); - - log(debug, "[" + fcx.name + "]"); - #debug("*At beginning: stmt = "); - log_stmt(*s); - #debug("*prestate = "); - log(debug, tritv::to_str(stmt_ann.states.prestate)); - #debug("*poststate ="); - log(debug, tritv::to_str(stmt_ann.states.prestate)); - - alt s.node { - stmt_decl(adecl, id) { - alt adecl.node { - decl_local(alocals) { - set_prestate(stmt_ann, pres); - let c_and_p = seq_states(fcx, pres, - locals_to_bindings(fcx.ccx.tcx, alocals)); - /* important to do this in one step to ensure - termination (don't want to set changed to true - for intermediate changes) */ - - let changed = - set_poststate(stmt_ann, c_and_p.post) | c_and_p.changed; - - #debug("Summary: stmt = "); - log_stmt(*s); - #debug("prestate = "); - log(debug, tritv::to_str(stmt_ann.states.prestate)); - #debug("poststate ="); - log(debug, tritv::to_str(stmt_ann.states.prestate)); - #debug("changed ="); - log(debug, changed); - - ret changed; - } - decl_item(an_item) { - ret set_prestate(stmt_ann, pres) | set_poststate(stmt_ann, pres); - /* the outer visitor will recurse into the item */ - } - } - } - stmt_expr(ex, _) | stmt_semi(ex, _) { - let changed = - find_pre_post_state_expr(fcx, pres, ex) | - set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) | - set_poststate(stmt_ann, expr_poststate(fcx.ccx, ex)); - - - #debug("Finally:"); - log_stmt(*s); - log(debug, "prestate = "); - log(debug, tritv::to_str(stmt_ann.states.prestate)); - #debug("poststate ="); - log(debug, (tritv::to_str(stmt_ann.states.poststate))); - #debug("changed ="); - - ret changed; - } - _ { ret false; } - } -} - - -/* Updates the pre- and post-states of statements in the block, - returns a boolean flag saying whether any pre- or poststates changed */ -fn find_pre_post_state_block(fcx: fn_ctxt, pres0: prestate, b: blk) -> bool { - /* First, set the pre-states and post-states for every expression */ - - let pres = pres0; - /* Iterate over each stmt. The new prestate is <pres>. The poststate - consist of improving <pres> with whatever variables this stmt - initializes. Then <pres> becomes the new poststate. */ - - let changed = false; - for s: @stmt in b.node.stmts { - changed |= find_pre_post_state_stmt(fcx, pres, s); - pres = stmt_poststate(fcx.ccx, *s); - } - let post = pres; - alt b.node.expr { - none { } - some(e) { - changed |= find_pre_post_state_expr(fcx, pres, e); - post = expr_poststate(fcx.ccx, e); - } - } - - set_prestate_ann(fcx.ccx, b.node.id, pres0); - set_poststate_ann(fcx.ccx, b.node.id, post); - - - /* - #error("For block:"); - log_block_err(b); - #error("poststate = "); - log_states_err(block_states(fcx.ccx, b)); - #error("pres0:"); - log_tritv_err(fcx, pres0); - #error("post:"); - log_tritv_err(fcx, post); - #error("changed = "); - log(error, changed); - */ - - ret changed; -} - -fn find_pre_post_state_fn(fcx: fn_ctxt, - f_decl: fn_decl, - f_body: blk) -> bool { - let num_constrs = num_constraints(fcx.enclosing); - // All constraints are considered false until proven otherwise. - // This ensures that intersect works correctly. - kill_all_prestate(fcx, f_body.node.id); - - // Arguments start out initialized - let block_pre = block_prestate(fcx.ccx, f_body); - for a: arg in f_decl.inputs { - set_in_prestate_constr(fcx, ninit(a.id, a.ident), block_pre); - } - - // Instantiate any constraints on the arguments so we can use them - for c: @constr in f_decl.constraints { - let tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f_decl.inputs, c); - set_in_prestate_constr(fcx, tsc, block_pre); - } - - let changed = find_pre_post_state_block(fcx, block_pre, f_body); - - // Treat the tail expression as a return statement - alt f_body.node.expr { - some(tailexpr) { - - // We don't want to clear the diverges bit for bottom typed things, - // which really do diverge. I feel like there is a cleaner way - // to do this than checking the type. - if !type_is_bot(expr_ty(fcx.ccx.tcx, tailexpr)) { - let post = false_postcond(num_constrs); - // except for the "diverges" bit... - kill_poststate_(fcx, fcx.enclosing.i_diverge, post); - set_poststate_ann(fcx.ccx, f_body.node.id, post); - } - } - none {/* fallthrough */ } - } - - /* - #error("find_pre_post_state_fn"); - log(error, changed); - fcx.ccx.tcx.sess.span_note(f_body.span, fcx.name); - */ - - ret changed; -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/tstate/tritv.rs b/src/comp/middle/tstate/tritv.rs deleted file mode 100644 index 37cc22edf3b..00000000000 --- a/src/comp/middle/tstate/tritv.rs +++ /dev/null @@ -1,308 +0,0 @@ -import std::bitv; - -export t; -export create_tritv; -export tritv_clone; -export tritv_set; -export to_vec; -export trit; -export dont_care; -export ttrue; -export tfalse; -export tritv_get; -export tritv_set_all; -export tritv_difference; -export tritv_union; -export tritv_intersect; -export tritv_copy; -export tritv_clear; -export tritv_kill; -export tritv_doesntcare; -export to_str; - -/* for a fixed index: - 10 = "this constraint may or may not be true after execution" - 01 = "this constraint is definitely true" - 00 = "this constraint is definitely false" - 11 should never appear - FIXME: typestate precondition (uncertain and val must - have the same length; 11 should never appear in a given position) -*/ - -type t = {uncertain: bitv::t, val: bitv::t, nbits: uint}; -enum trit { ttrue, tfalse, dont_care, } - -fn create_tritv(len: uint) -> t { - ret {uncertain: bitv::create(len, true), - val: bitv::create(len, false), - nbits: len}; -} - - -fn trit_minus(a: trit, b: trit) -> trit { - - /* 2 - anything = 2 - 1 - 1 = 2 - 1 - 0 is an error - 1 - 2 = 1 - 0 - 1 is an error - 0 - anything else - 0 - */ - alt a { - dont_care { dont_care } - ttrue { - alt b { - ttrue { dont_care } - tfalse { ttrue } - - - - - /* internally contradictory, but - I guess it'll get flagged? */ - dont_care { - ttrue - } - } - } - tfalse { - alt b { - ttrue { tfalse } - - - - - /* see above comment */ - _ { - tfalse - } - } - } - } -} - -fn trit_or(a: trit, b: trit) -> trit { - alt a { - dont_care { b } - ttrue { ttrue } - tfalse { - alt b { - ttrue { dont_care } - - - - - /* FIXME: ?????? */ - _ { - tfalse - } - } - } - } -} - -// FIXME: This still seems kind of dodgy to me (that is, -// that 1 + ? = 1. But it might work out given that -// all variables start out in a 0 state. Probably I need -// to make it so that all constraints start out in a 0 state -// (we consider a constraint false until proven true), too. -fn trit_and(a: trit, b: trit) -> trit { - alt a { - dont_care { b } - - - - - // also seems wrong for case b = ttrue - ttrue { - alt b { - dont_care { ttrue } - - - - - // ??? Seems wrong - ttrue { - ttrue - } - - - - - - // false wins, since if something is uninit - // on one path, we care - // (Rationale: it's always safe to assume that - // a var is uninitialized or that a constraint - // needs to be re-established) - tfalse { - tfalse - } - } - } - - - - - - // Rationale: if it's uninit on one path, - // we can consider it as uninit on all paths - tfalse { - tfalse - } - } - // if the result is dont_care, that means - // a and b were both dont_care -} - -fn change(changed: bool, old: trit, new: trit) -> bool { - changed || new != old -} - -fn tritv_difference(p1: t, p2: t) -> bool { - let i: uint = 0u; - assert (p1.nbits == p2.nbits); - let sz: uint = p1.nbits; - let changed = false; - while i < sz { - let old = tritv_get(p1, i); - let new = trit_minus(old, tritv_get(p2, i)); - changed = change(changed, old, new); - tritv_set(i, p1, new); - i += 1u; - } - ret changed; -} - -fn tritv_union(p1: t, p2: t) -> bool { - let i: uint = 0u; - assert (p1.nbits == p2.nbits); - let sz: uint = p1.nbits; - let changed = false; - while i < sz { - let old = tritv_get(p1, i); - let new = trit_or(old, tritv_get(p2, i)); - changed = change(changed, old, new); - tritv_set(i, p1, new); - i += 1u; - } - ret changed; -} - -fn tritv_intersect(p1: t, p2: t) -> bool { - let i: uint = 0u; - assert (p1.nbits == p2.nbits); - let sz: uint = p1.nbits; - let changed = false; - while i < sz { - let old = tritv_get(p1, i); - let new = trit_and(old, tritv_get(p2, i)); - changed = change(changed, old, new); - tritv_set(i, p1, new); - i += 1u; - } - ret changed; -} - -fn tritv_get(v: t, i: uint) -> trit { - let b1 = bitv::get(v.uncertain, i); - let b2 = bitv::get(v.val, i); - assert (!(b1 && b2)); - if b1 { dont_care } else if b2 { ttrue } else { tfalse } -} - -fn tritv_set(i: uint, v: t, t: trit) -> bool { - let old = tritv_get(v, i); - alt t { - dont_care { - bitv::set(v.uncertain, i, true); - bitv::set(v.val, i, false); - } - ttrue { bitv::set(v.uncertain, i, false); bitv::set(v.val, i, true); } - tfalse { - bitv::set(v.uncertain, i, false); - bitv::set(v.val, i, false); - } - } - ret change(false, old, t); -} - -fn tritv_copy(target: t, source: t) -> bool { - assert (target.nbits == source.nbits); - let changed = - !bitv::equal(target.uncertain, source.uncertain) || - !bitv::equal(target.val, source.val); - bitv::assign(target.uncertain, source.uncertain); - bitv::assign(target.val, source.val); - ret changed; -} - -fn tritv_set_all(v: t) { - let i: uint = 0u; - while i < v.nbits { tritv_set(i, v, ttrue); i += 1u; } -} - -fn tritv_clear(v: t) { - let i: uint = 0u; - while i < v.nbits { tritv_set(i, v, dont_care); i += 1u; } -} - -fn tritv_kill(v: t) { - let i: uint = 0u; - while i < v.nbits { tritv_set(i, v, tfalse); i += 1u; } -} - -fn tritv_clone(v: t) -> t { - ret {uncertain: bitv::clone(v.uncertain), - val: bitv::clone(v.val), - nbits: v.nbits}; -} - -fn tritv_doesntcare(v: t) -> bool { - let i: uint = 0u; - while i < v.nbits { - if tritv_get(v, i) != dont_care { ret false; } - i += 1u; - } - ret true; -} - -fn to_vec(v: t) -> [uint] { - let i: uint = 0u; - let rslt: [uint] = []; - while i < v.nbits { - rslt += - [alt tritv_get(v, i) { - dont_care { 2u } - ttrue { 1u } - tfalse { 0u } - }]; - i += 1u; - } - ret rslt; -} - -fn to_str(v: t) -> str { - let i: uint = 0u; - let rs: str = ""; - while i < v.nbits { - rs += - alt tritv_get(v, i) { - dont_care { "?" } - ttrue { "1" } - tfalse { "0" } - }; - i += 1u; - } - ret rs; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs deleted file mode 100644 index a7e218e581b..00000000000 --- a/src/comp/middle/ty.rs +++ /dev/null @@ -1,2400 +0,0 @@ -import std::{ufind, map, smallintmap}; -import std::map::hashmap; -import driver::session; -import session::session; -import syntax::ast; -import syntax::ast::*; -import syntax::ast_util; -import syntax::codemap::span; -import metadata::csearch; -import util::common::*; -import util::ppaux::ty_to_str; -import util::ppaux::ty_constr_to_str; -import syntax::print::pprust::*; - -export node_id_to_type; -export node_id_to_type_params; -export arg; -export args_eq; -export ast_constr_to_constr; -export block_ty; -export constr; -export constr_general; -export constr_table; -export count_ty_params; -export ctxt; -export def_has_ty_params; -export expr_has_ty_params; -export expr_ty; -export expr_ty_params_and_ty; -export expr_is_lval; -export fold_ty; -export field; -export field_idx; -export get_field; -export get_fields; -export fm_general; -export get_element_type; -export is_binopable; -export is_pred_ty; -export lookup_item_type; -export method; -export method_idx; -export mk_class; -export mk_ctxt; -export mk_with_id, type_def_id; -export mt; -export node_type_table; -export pat_ty; -export sequence_element_type; -export sort_methods; -export stmt_node_id; -export sty; -export substitute_type_params; -export t; -export new_ty_hash; -export enum_variants, substd_enum_variants; -export iface_methods, store_iface_methods, impl_iface; -export enum_variant_with_id; -export ty_param_bounds_and_ty; -export ty_bool, mk_bool, type_is_bool; -export ty_bot, mk_bot, type_is_bot; -export ty_box, mk_box, mk_imm_box, type_is_box, type_is_boxed; -export ty_constr, mk_constr; -export ty_opaque_closure_ptr, mk_opaque_closure_ptr; -export ty_opaque_box, mk_opaque_box; -export ty_constr_arg; -export ty_float, mk_float, mk_mach_float, type_is_fp; -export ty_fn, fn_ty, mk_fn; -export ty_fn_proto, ty_fn_ret, ty_fn_ret_style; -export ty_int, mk_int, mk_mach_int, mk_char; -export ty_str, mk_str, type_is_str; -export ty_vec, mk_vec, type_is_vec; -export ty_nil, mk_nil, type_is_nil; -export ty_iface, mk_iface; -export ty_res, mk_res; -export ty_param, mk_param; -export ty_ptr, mk_ptr, mk_mut_ptr, type_is_unsafe_ptr; -export ty_rec, mk_rec; -export ty_enum, mk_enum, type_is_enum; -export ty_tup, mk_tup; -export ty_send_type, mk_send_type; -export ty_type, mk_type; -export ty_uint, mk_uint, mk_mach_uint; -export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box; -export ty_var, mk_var; -export ty_self, mk_self; -export get, type_has_params, type_has_vars, type_id; -export same_type; -export ty_var_id; -export ty_fn_args; -export type_constr; -export kind, kind_sendable, kind_copyable, kind_noncopyable; -export kind_can_be_copied, kind_can_be_sent, proto_kind, kind_lteq, type_kind; -export type_err; -export type_err_to_str; -export type_has_dynamic_size; -export type_needs_drop; -export type_allows_implicit_copy; -export type_is_integral; -export type_is_numeric; -export type_is_pod; -export type_is_scalar; -export type_is_immediate; -export type_is_sequence; -export type_is_signed; -export type_is_structural; -export type_is_copyable; -export type_is_tup_like; -export type_is_unique; -export type_is_c_like_enum; -export type_structurally_contains; -export type_structurally_contains_uniques; -export type_autoderef; -export type_param; -export canon_mode; -export resolved_mode; -export arg_mode; -export unify_mode; -export set_default_mode; -export unify; -export variant_info; -export walk_ty; -export occurs_check_fails; -export closure_kind; -export ck_block; -export ck_box; -export ck_uniq; -export param_bound, param_bounds, bound_copy, bound_send, bound_iface; -export param_bounds_to_kind; -export default_arg_mode_for_ty; -export item_path; -export item_path_str; - -// Data types - -// Note: after typeck, you should use resolved_mode() to convert this mode -// into an rmode, which will take into account the results of mode inference. -type arg = {mode: ast::mode, ty: t}; - -type field = {ident: ast::ident, mt: mt}; - -type param_bounds = @[param_bound]; - -type method = {ident: ast::ident, - tps: @[param_bounds], - fty: fn_ty, - purity: ast::purity}; - -type constr_table = hashmap<ast::node_id, [constr]>; - -type mt = {ty: t, mutbl: ast::mutability}; - - -// Contains information needed to resolve types and (in the future) look up -// the types of AST nodes. -type creader_cache = hashmap<{cnum: int, pos: uint, len: uint}, t>; - -type intern_key = {struct: sty, o_def_id: option<ast::def_id>}; - -type ctxt = - @{interner: hashmap<intern_key, t_box>, - mutable next_id: uint, - sess: session::session, - def_map: resolve::def_map, - node_types: node_type_table, - node_type_substs: hashmap<node_id, [t]>, - items: ast_map::map, - freevars: freevars::freevar_map, - tcache: type_cache, - rcache: creader_cache, - short_names_cache: hashmap<t, @str>, - needs_drop_cache: hashmap<t, bool>, - kind_cache: hashmap<t, kind>, - ast_ty_to_ty_cache: hashmap<@ast::ty, option<t>>, - enum_var_cache: hashmap<def_id, @[variant_info]>, - iface_method_cache: hashmap<def_id, @[method]>, - ty_param_bounds: hashmap<ast::node_id, param_bounds>, - inferred_modes: hashmap<ast::node_id, ast::mode>}; - -type t_box = @{struct: sty, - id: uint, - has_params: bool, - has_vars: bool, - o_def_id: option<ast::def_id>}; - -// To reduce refcounting cost, we're representing types as unsafe pointers -// throughout the compiler. These are simply casted t_box values. Use ty::get -// to cast them back to a box. (Without the cast, compiler performance suffers -// ~15%.) This does mean that a t value relies on the ctxt to keep its box -// alive, and using ty::get is unsafe when the ctxt is no longer alive. -enum t_opaque {} -type t = *t_opaque; - -pure fn get(t: t) -> t_box unsafe { - let t2 = unsafe::reinterpret_cast::<t, t_box>(t); - let t3 = t2; - unsafe::leak(t2); - t3 -} - -fn type_has_params(t: t) -> bool { get(t).has_params } -fn type_has_vars(t: t) -> bool { get(t).has_vars } -fn type_def_id(t: t) -> option<ast::def_id> { get(t).o_def_id } -fn type_id(t: t) -> uint { get(t).id } - -enum closure_kind { - ck_block, - ck_box, - ck_uniq, -} - -type fn_ty = {proto: ast::proto, - inputs: [arg], - output: t, - ret_style: ret_style, - constraints: [@constr]}; - -// NB: If you change this, you'll probably want to change the corresponding -// AST structure in front/ast::rs as well. -enum sty { - ty_nil, - ty_bot, - ty_bool, - ty_int(ast::int_ty), - ty_uint(ast::uint_ty), - ty_float(ast::float_ty), - ty_str, - ty_enum(def_id, [t]), - ty_box(mt), - ty_uniq(mt), - ty_vec(mt), - ty_ptr(mt), - ty_rec([field]), - ty_fn(fn_ty), - ty_iface(def_id, [t]), - ty_class(def_id, [t]), - ty_res(def_id, t, [t]), - ty_tup([t]), - - ty_var(int), // type variable during typechecking - ty_param(uint, def_id), // type parameter - ty_self([t]), // interface method self type - - ty_type, // type_desc* - ty_send_type, // type_desc* that has been cloned into exchange heap - ty_opaque_box, // used by monomorphizer to represend any @ box - ty_constr(t, [@type_constr]), - ty_opaque_closure_ptr(closure_kind), // ptr to env for fn, fn@, fn~ -} - -// In the middle end, constraints have a def_id attached, referring -// to the definition of the operator in the constraint. -type constr_general<ARG> = spanned<constr_general_<ARG, def_id>>; -type type_constr = constr_general<@path>; -type constr = constr_general<uint>; - -// Data structures used in type unification -enum type_err { - terr_mismatch, - terr_ret_style_mismatch(ast::ret_style, ast::ret_style), - terr_box_mutability, - terr_ptr_mutability, - terr_vec_mutability, - terr_tuple_size(uint, uint), - terr_record_size(uint, uint), - terr_record_mutability, - terr_record_fields(ast::ident, ast::ident), - terr_arg_count, - terr_mode_mismatch(mode, mode), - terr_constr_len(uint, uint), - terr_constr_mismatch(@type_constr, @type_constr), -} - -enum param_bound { - bound_copy, - bound_send, - bound_iface(t), -} - -fn param_bounds_to_kind(bounds: param_bounds) -> kind { - let kind = kind_noncopyable; - for bound in *bounds { - alt bound { - bound_copy { - if kind != kind_sendable { kind = kind_copyable; } - } - bound_send { kind = kind_sendable; } - _ {} - } - } - kind -} - -type ty_param_bounds_and_ty = {bounds: @[param_bounds], ty: t}; - -type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>; - -type node_type_table = @smallintmap::smallintmap<t>; - -fn mk_rcache() -> creader_cache { - type val = {cnum: int, pos: uint, len: uint}; - fn hash_cache_entry(k: val) -> uint { - ret (k.cnum as uint) + k.pos + k.len; - } - fn eq_cache_entries(a: val, b: val) -> bool { - ret a.cnum == b.cnum && a.pos == b.pos && a.len == b.len; - } - ret map::mk_hashmap(hash_cache_entry, eq_cache_entries); -} - -fn new_ty_hash<V: copy>() -> map::hashmap<t, V> { - map::mk_hashmap({|&&t: t| type_id(t)}, - {|&&a: t, &&b: t| type_id(a) == type_id(b)}) -} - -fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map, - freevars: freevars::freevar_map) -> ctxt { - let interner = map::mk_hashmap({|&&k: intern_key| - hash_type_structure(k.struct) + - option::maybe(0u, k.o_def_id, ast_util::hash_def_id) - }, {|&&a, &&b| a == b}); - @{interner: interner, - mutable next_id: 0u, - sess: s, - def_map: dm, - node_types: @smallintmap::mk(), - node_type_substs: map::new_int_hash(), - items: amap, - freevars: freevars, - tcache: new_def_hash(), - rcache: mk_rcache(), - short_names_cache: new_ty_hash(), - needs_drop_cache: new_ty_hash(), - kind_cache: new_ty_hash(), - ast_ty_to_ty_cache: map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty), - enum_var_cache: new_def_hash(), - iface_method_cache: new_def_hash(), - ty_param_bounds: map::new_int_hash(), - inferred_modes: map::new_int_hash()} -} - - -// Type constructors -fn mk_t(cx: ctxt, st: sty) -> t { mk_t_with_id(cx, st, none) } - -// Interns a type/name combination, stores the resulting box in cx.interner, -// and returns the box as cast to an unsafe ptr (see comments for t above). -fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t { - let key = {struct: st, o_def_id: o_def_id}; - alt cx.interner.find(key) { - some(t) { unsafe { ret unsafe::reinterpret_cast(t); } } - _ {} - } - let has_params = false, has_vars = false; - fn derive_flags(&has_params: bool, &has_vars: bool, tt: t) { - let t = get(tt); - has_params |= t.has_params; - has_vars |= t.has_vars; - } - alt st { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) | - ty_opaque_box {} - ty_param(_, _) { has_params = true; } - ty_var(_) | ty_self(_) { has_vars = true; } - ty_enum(_, tys) | ty_iface(_, tys) | ty_class(_, tys) { - for tt in tys { derive_flags(has_params, has_vars, tt); } - } - ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_ptr(m) { - derive_flags(has_params, has_vars, m.ty); - } - ty_rec(flds) { - for f in flds { derive_flags(has_params, has_vars, f.mt.ty); } - } - ty_tup(ts) { - for tt in ts { derive_flags(has_params, has_vars, tt); } - } - ty_fn(f) { - for a in f.inputs { derive_flags(has_params, has_vars, a.ty); } - derive_flags(has_params, has_vars, f.output); - } - ty_res(_, tt, tps) { - derive_flags(has_params, has_vars, tt); - for tt in tps { derive_flags(has_params, has_vars, tt); } - } - ty_constr(tt, _) { - derive_flags(has_params, has_vars, tt); - } - } - let t = @{struct: st, - id: cx.next_id, - has_params: has_params, - has_vars: has_vars, - o_def_id: o_def_id}; - cx.interner.insert(key, t); - cx.next_id += 1u; - unsafe { unsafe::reinterpret_cast(t) } -} - -fn mk_nil(cx: ctxt) -> t { mk_t(cx, ty_nil) } - -fn mk_bot(cx: ctxt) -> t { mk_t(cx, ty_bot) } - -fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) } - -fn mk_int(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i)) } - -fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) } - -fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) } - -fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) } - -fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) } - -fn mk_mach_float(cx: ctxt, tm: ast::float_ty) -> t { mk_t(cx, ty_float(tm)) } - -fn mk_char(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_char)) } - -fn mk_str(cx: ctxt) -> t { mk_t(cx, ty_str) } - -fn mk_enum(cx: ctxt, did: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_enum(did, tys)) -} - -fn mk_box(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_box(tm)) } - -fn mk_imm_box(cx: ctxt, ty: t) -> t { mk_box(cx, {ty: ty, - mutbl: ast::m_imm}) } - -fn mk_uniq(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_uniq(tm)) } - -fn mk_imm_uniq(cx: ctxt, ty: t) -> t { mk_uniq(cx, {ty: ty, - mutbl: ast::m_imm}) } - -fn mk_ptr(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_ptr(tm)) } - -fn mk_mut_ptr(cx: ctxt, ty: t) -> t { mk_ptr(cx, {ty: ty, - mutbl: ast::m_mutbl}) } - -fn mk_vec(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_vec(tm)) } - -fn mk_rec(cx: ctxt, fs: [field]) -> t { mk_t(cx, ty_rec(fs)) } - -fn mk_constr(cx: ctxt, t: t, cs: [@type_constr]) -> t { - mk_t(cx, ty_constr(t, cs)) -} - -fn mk_tup(cx: ctxt, ts: [t]) -> t { mk_t(cx, ty_tup(ts)) } - -fn mk_fn(cx: ctxt, fty: fn_ty) -> t { mk_t(cx, ty_fn(fty)) } - -fn mk_iface(cx: ctxt, did: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_iface(did, tys)) -} - -fn mk_class(cx: ctxt, class_id: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_class(class_id, tys)) -} - -fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t { - mk_t(cx, ty_res(did, inner, tps)) -} - -fn mk_var(cx: ctxt, v: int) -> t { mk_t(cx, ty_var(v)) } - -fn mk_self(cx: ctxt, tps: [t]) -> t { mk_t(cx, ty_self(tps)) } - -fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { mk_t(cx, ty_param(n, k)) } - -fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) } - -fn mk_send_type(cx: ctxt) -> t { mk_t(cx, ty_send_type) } - -fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t { - mk_t(cx, ty_opaque_closure_ptr(ck)) -} - -fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) } - -fn mk_with_id(cx: ctxt, base: t, def_id: ast::def_id) -> t { - mk_t_with_id(cx, get(base).struct, some(def_id)) -} - -// Converts s to its machine type equivalent -pure fn mach_sty(cfg: @session::config, t: t) -> sty { - alt get(t).struct { - ty_int(ast::ty_i) { ty_int(cfg.int_type) } - ty_uint(ast::ty_u) { ty_uint(cfg.uint_type) } - ty_float(ast::ty_f) { ty_float(cfg.float_type) } - s { s } - } -} - -fn default_arg_mode_for_ty(ty: ty::t) -> ast::rmode { - if ty::type_is_immediate(ty) { ast::by_val } - else { ast::by_ref } -} - -fn walk_ty(cx: ctxt, ty: t, f: fn(t)) { - alt get(ty).struct { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_send_type | ty_type | ty_opaque_box | - ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {} - ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, f); } - ty_enum(_, subtys) | ty_iface(_, subtys) | ty_class(_, subtys) - | ty_self(subtys) { - for subty: t in subtys { walk_ty(cx, subty, f); } - } - ty_rec(fields) { - for fl: field in fields { walk_ty(cx, fl.mt.ty, f); } - } - ty_tup(ts) { for tt in ts { walk_ty(cx, tt, f); } } - ty_fn(ft) { - for a: arg in ft.inputs { walk_ty(cx, a.ty, f); } - walk_ty(cx, ft.output, f); - } - ty_res(_, sub, tps) { - walk_ty(cx, sub, f); - for tp: t in tps { walk_ty(cx, tp, f); } - } - ty_constr(sub, _) { walk_ty(cx, sub, f); } - ty_uniq(tm) { walk_ty(cx, tm.ty, f); } - } - f(ty); -} - -enum fold_mode { - fm_var(fn@(int) -> t), - fm_param(fn@(uint, def_id) -> t), - fm_general(fn@(t) -> t), -} - -fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t { - let ty = ty_0; - - let tb = get(ty); - alt fld { - fm_var(_) { if !tb.has_vars { ret ty; } } - fm_param(_) { if !tb.has_params { ret ty; } } - fm_general(_) {/* no fast path */ } - } - - alt tb.struct { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) | - ty_opaque_box {} - ty_box(tm) { - ty = mk_box(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); - } - ty_uniq(tm) { - ty = mk_uniq(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); - } - ty_ptr(tm) { - ty = mk_ptr(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); - } - ty_vec(tm) { - ty = mk_vec(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl}); - } - ty_enum(tid, subtys) { - ty = mk_enum(cx, tid, vec::map(subtys, {|t| fold_ty(cx, fld, t) })); - } - ty_iface(did, subtys) { - ty = mk_iface(cx, did, vec::map(subtys, {|t| fold_ty(cx, fld, t) })); - } - ty_self(subtys) { - ty = mk_self(cx, vec::map(subtys, {|t| fold_ty(cx, fld, t) })); - } - ty_rec(fields) { - let new_fields: [field] = []; - for fl: field in fields { - let new_ty = fold_ty(cx, fld, fl.mt.ty); - let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl}; - new_fields += [{ident: fl.ident, mt: new_mt}]; - } - ty = mk_rec(cx, new_fields); - } - ty_tup(ts) { - let new_ts = []; - for tt in ts { new_ts += [fold_ty(cx, fld, tt)]; } - ty = mk_tup(cx, new_ts); - } - ty_fn(f) { - let new_args: [arg] = []; - for a: arg in f.inputs { - let new_ty = fold_ty(cx, fld, a.ty); - new_args += [{mode: a.mode, ty: new_ty}]; - } - ty = mk_fn(cx, {inputs: new_args, - output: fold_ty(cx, fld, f.output) - with f}); - } - ty_res(did, subty, tps) { - let new_tps = []; - for tp: t in tps { new_tps += [fold_ty(cx, fld, tp)]; } - ty = mk_res(cx, did, fold_ty(cx, fld, subty), new_tps); - } - ty_var(id) { - alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } } - } - ty_param(id, did) { - alt fld { fm_param(folder) { ty = folder(id, did); } _ {} } - } - ty_constr(subty, cs) { - ty = mk_constr(cx, fold_ty(cx, fld, subty), cs); - } - _ { - cx.sess.fatal("Unsupported sort of type in fold_ty"); - } - } - alt tb.o_def_id { - some(did) { ty = mk_t_with_id(cx, get(ty).struct, some(did)); } - _ {} - } - - // If this is a general type fold, then we need to run it now. - alt fld { fm_general(folder) { ret folder(ty); } _ { ret ty; } } -} - - -// Type utilities - -fn type_is_nil(ty: t) -> bool { get(ty).struct == ty_nil } - -fn type_is_bot(ty: t) -> bool { get(ty).struct == ty_bot } - -fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool } - -fn type_is_structural(ty: t) -> bool { - alt get(ty).struct { - ty_rec(_) | ty_tup(_) | ty_enum(_, _) | ty_fn(_) | - ty_iface(_, _) | ty_res(_, _, _) { true } - _ { false } - } -} - -fn type_is_copyable(cx: ctxt, ty: t) -> bool { - ret kind_can_be_copied(type_kind(cx, ty)); -} - -fn type_is_sequence(ty: t) -> bool { - alt get(ty).struct { - ty_str { ret true; } - ty_vec(_) { ret true; } - _ { ret false; } - } -} - -fn type_is_str(ty: t) -> bool { get(ty).struct == ty_str } - -fn sequence_element_type(cx: ctxt, ty: t) -> t { - alt get(ty).struct { - ty_str { ret mk_mach_uint(cx, ast::ty_u8); } - ty_vec(mt) { ret mt.ty; } - _ { cx.sess.bug("sequence_element_type called on non-sequence value"); } - } -} - -pure fn type_is_tup_like(ty: t) -> bool { - alt get(ty).struct { - ty_rec(_) | ty_tup(_) { true } - _ { false } - } -} - -fn get_element_type(ty: t, i: uint) -> t { - alt get(ty).struct { - ty_rec(flds) { ret flds[i].mt.ty; } - ty_tup(ts) { ret ts[i]; } - _ { fail "get_element_type called on invalid type"; } - } -} - -pure fn type_is_box(ty: t) -> bool { - alt get(ty).struct { - ty_box(_) { ret true; } - _ { ret false; } - } -} - -pure fn type_is_boxed(ty: t) -> bool { - alt get(ty).struct { - ty_box(_) | ty_opaque_box { true } - _ { false } - } -} - -pure fn type_is_unique_box(ty: t) -> bool { - alt get(ty).struct { - ty_uniq(_) { ret true; } - _ { ret false; } - } -} - -pure fn type_is_unsafe_ptr(ty: t) -> bool { - alt get(ty).struct { - ty_ptr(_) { ret true; } - _ { ret false; } - } -} - -pure fn type_is_vec(ty: t) -> bool { - ret alt get(ty).struct { - ty_vec(_) { true } - ty_str { true } - _ { false } - }; -} - -pure fn type_is_unique(ty: t) -> bool { - alt get(ty).struct { - ty_uniq(_) { ret true; } - ty_vec(_) { true } - ty_str { true } - _ { ret false; } - } -} - -pure fn type_is_scalar(ty: t) -> bool { - alt get(ty).struct { - ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_send_type | ty_type | ty_ptr(_) { true } - _ { false } - } -} - -// FIXME maybe inline this for speed? -fn type_is_immediate(ty: t) -> bool { - ret type_is_scalar(ty) || type_is_boxed(ty) || - type_is_unique(ty); -} - -fn type_needs_drop(cx: ctxt, ty: t) -> bool { - alt cx.needs_drop_cache.find(ty) { - some(result) { ret result; } - none {/* fall through */ } - } - - let accum = false; - let result = alt get(ty).struct { - // scalar types - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_type | ty_ptr(_) { false } - ty_rec(flds) { - for f in flds { if type_needs_drop(cx, f.mt.ty) { accum = true; } } - accum - } - ty_tup(elts) { - for m in elts { if type_needs_drop(cx, m) { accum = true; } } - accum - } - ty_enum(did, tps) { - let variants = enum_variants(cx, did); - for variant in *variants { - for aty in variant.args { - // Perform any type parameter substitutions. - let arg_ty = substitute_type_params(cx, tps, aty); - if type_needs_drop(cx, arg_ty) { accum = true; } - } - if accum { break; } - } - accum - } - _ { true } - }; - - cx.needs_drop_cache.insert(ty, result); - ret result; -} - -enum kind { kind_sendable, kind_copyable, kind_noncopyable, } - -// Using these query functons is preferable to direct comparison or matching -// against the kind constants, as we may modify the kind hierarchy in the -// future. -pure fn kind_can_be_copied(k: kind) -> bool { - ret alt k { - kind_sendable { true } - kind_copyable { true } - kind_noncopyable { false } - }; -} - -pure fn kind_can_be_sent(k: kind) -> bool { - ret alt k { - kind_sendable { true } - kind_copyable { false } - kind_noncopyable { false } - }; -} - -fn proto_kind(p: proto) -> kind { - alt p { - ast::proto_any { kind_noncopyable } - ast::proto_block { kind_noncopyable } - ast::proto_box { kind_copyable } - ast::proto_uniq { kind_sendable } - ast::proto_bare { kind_sendable } - } -} - -fn kind_lteq(a: kind, b: kind) -> bool { - alt a { - kind_noncopyable { true } - kind_copyable { b != kind_noncopyable } - kind_sendable { b == kind_sendable } - } -} - -fn lower_kind(a: kind, b: kind) -> kind { - if kind_lteq(a, b) { a } else { b } -} - -fn type_kind(cx: ctxt, ty: t) -> kind { - alt cx.kind_cache.find(ty) { - some(result) { ret result; } - none {/* fall through */ } - } - - // Insert a default in case we loop back on self recursively. - cx.kind_cache.insert(ty, kind_sendable); - - let result = alt get(ty).struct { - // Scalar and unique types are sendable - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_ptr(_) | ty_send_type | ty_str { kind_sendable } - ty_type { kind_copyable } - ty_fn(f) { proto_kind(f.proto) } - ty_opaque_closure_ptr(ck_block) { kind_noncopyable } - ty_opaque_closure_ptr(ck_box) { kind_copyable } - ty_opaque_closure_ptr(ck_uniq) { kind_sendable } - // Those with refcounts-to-inner raise pinned to shared, - // lower unique to shared. Therefore just set result to shared. - ty_box(_) | ty_iface(_, _) | ty_opaque_box { kind_copyable } - // Boxes and unique pointers raise pinned to shared. - ty_vec(tm) | ty_uniq(tm) { type_kind(cx, tm.ty) } - // Records lower to the lowest of their members. - ty_rec(flds) { - let lowest = kind_sendable; - for f in flds { lowest = lower_kind(lowest, type_kind(cx, f.mt.ty)); } - lowest - } - // Tuples lower to the lowest of their members. - ty_tup(tys) { - let lowest = kind_sendable; - for ty in tys { lowest = lower_kind(lowest, type_kind(cx, ty)); } - lowest - } - // Enums lower to the lowest of their variants. - ty_enum(did, tps) { - let lowest = kind_sendable; - for variant in *enum_variants(cx, did) { - for aty in variant.args { - // Perform any type parameter substitutions. - let arg_ty = substitute_type_params(cx, tps, aty); - lowest = lower_kind(lowest, type_kind(cx, arg_ty)); - if lowest == kind_noncopyable { break; } - } - } - lowest - } - // Resources are always noncopyable. - ty_res(did, inner, tps) { kind_noncopyable } - ty_param(_, did) { - param_bounds_to_kind(cx.ty_param_bounds.get(did.node)) - } - ty_constr(t, _) { type_kind(cx, t) } - _ { cx.sess.bug("Bad type in type_kind"); } - }; - - cx.kind_cache.insert(ty, result); - ret result; -} - -fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) -> - bool { - let sty = get(ty).struct; - if test(sty) { ret true; } - alt sty { - ty_enum(did, tps) { - for variant in *enum_variants(cx, did) { - for aty in variant.args { - let sty = substitute_type_params(cx, tps, aty); - if type_structurally_contains(cx, sty, test) { ret true; } - } - } - ret false; - } - ty_rec(fields) { - for field in fields { - if type_structurally_contains(cx, field.mt.ty, test) { ret true; } - } - ret false; - } - ty_tup(ts) { - for tt in ts { - if type_structurally_contains(cx, tt, test) { ret true; } - } - ret false; - } - ty_res(_, sub, tps) { - let sty = substitute_type_params(cx, tps, sub); - ret type_structurally_contains(cx, sty, test); - } - _ { ret false; } - } -} - -pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked { - /* type_structurally_contains can't be declared pure - because it takes a function argument. But it should be - referentially transparent, since a given type's size should - never change once it's created. - (It would be interesting to think about how to make such properties - actually checkable. It seems to me like a lot of properties - that the type context tracks about types should be immutable.) - */ - type_has_params(ty) && type_structurally_contains(cx, ty) {|sty| - alt sty { - ty_param(_, _) { true } - _ { false } - } - } -} - -// Returns true for noncopyable types and types where a copy of a value can be -// distinguished from the value itself. I.e. types with mutable content that's -// not shared through a pointer. -fn type_allows_implicit_copy(cx: ctxt, ty: t) -> bool { - ret !type_structurally_contains(cx, ty, {|sty| - alt sty { - ty_param(_, _) { true } - ty_vec(mt) { - mt.mutbl != ast::m_imm - } - ty_rec(fields) { - for field in fields { - if field.mt.mutbl != ast::m_imm { - ret true; - } - } - false - } - _ { false } - } - }) && type_kind(cx, ty) != kind_noncopyable; -} - -fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool { - ret type_structurally_contains(cx, ty, {|sty| - ret alt sty { - ty_uniq(_) { ret true; } - ty_vec(_) { true } - ty_str { true } - _ { ret false; } - }; - }); -} - -fn type_is_integral(ty: t) -> bool { - alt get(ty).struct { - ty_int(_) | ty_uint(_) | ty_bool { true } - _ { false } - } -} - -fn type_is_fp(ty: t) -> bool { - alt get(ty).struct { - ty_float(_) { true } - _ { false } - } -} - -fn type_is_numeric(ty: t) -> bool { - ret type_is_integral(ty) || type_is_fp(ty); -} - -fn type_is_signed(ty: t) -> bool { - alt get(ty).struct { - ty_int(_) { true } - _ { false } - } -} - -// Whether a type is Plain Old Data -- meaning it does not contain pointers -// that the cycle collector might care about. -fn type_is_pod(cx: ctxt, ty: t) -> bool { - let result = true; - alt get(ty).struct { - // Scalar types - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_send_type | ty_type | ty_ptr(_) { result = true; } - // Boxed types - ty_str | ty_box(_) | ty_uniq(_) | ty_vec(_) | ty_fn(_) | - ty_iface(_, _) | ty_opaque_box { result = false; } - // Structural types - ty_enum(did, tps) { - let variants = enum_variants(cx, did); - for variant: variant_info in *variants { - let tup_ty = mk_tup(cx, variant.args); - - // Perform any type parameter substitutions. - tup_ty = substitute_type_params(cx, tps, tup_ty); - if !type_is_pod(cx, tup_ty) { result = false; } - } - } - ty_rec(flds) { - for f: field in flds { - if !type_is_pod(cx, f.mt.ty) { result = false; } - } - } - ty_tup(elts) { - for elt in elts { if !type_is_pod(cx, elt) { result = false; } } - } - ty_res(_, inner, tps) { - result = type_is_pod(cx, substitute_type_params(cx, tps, inner)); - } - ty_constr(subt, _) { result = type_is_pod(cx, subt); } - ty_param(_, _) { result = false; } - ty_opaque_closure_ptr(_) { result = true; } - _ { cx.sess.bug("unexpected type in type_is_pod"); } - } - - ret result; -} - -fn type_is_enum(ty: t) -> bool { - alt get(ty).struct { - ty_enum(_, _) { ret true; } - _ { ret false;} - } -} - -// Whether a type is enum like, that is a enum type with only nullary -// constructors -fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { - alt get(ty).struct { - ty_enum(did, tps) { - let variants = enum_variants(cx, did); - let some_n_ary = vec::any(*variants, {|v| vec::len(v.args) > 0u}); - ret !some_n_ary; - } - _ { ret false;} - } -} - -fn type_param(ty: t) -> option<uint> { - alt get(ty).struct { - ty_param(id, _) { ret some(id); } - _ {/* fall through */ } - } - ret none; -} - -// Returns a vec of all the type variables -// occurring in t. It may contain duplicates. -fn vars_in_type(cx: ctxt, ty: t) -> [int] { - let rslt = []; - walk_ty(cx, ty) {|ty| - alt get(ty).struct { ty_var(v) { rslt += [v]; } _ { } } - } - rslt -} - -fn type_autoderef(cx: ctxt, t: t) -> t { - let t1 = t; - while true { - alt get(t1).struct { - ty_box(mt) | ty_uniq(mt) { t1 = mt.ty; } - ty_res(_, inner, tps) { - t1 = substitute_type_params(cx, tps, inner); - } - ty_enum(did, tps) { - let variants = enum_variants(cx, did); - if vec::len(*variants) != 1u || vec::len(variants[0].args) != 1u { - break; - } - t1 = substitute_type_params(cx, tps, variants[0].args[0]); - } - _ { break; } - } - } - ret t1; -} - -// Type hashing. -fn hash_type_structure(st: sty) -> uint { - fn hash_uint(id: uint, n: uint) -> uint { (id << 2u) + n } - fn hash_def(id: uint, did: ast::def_id) -> uint { - let h = (id << 2u) + (did.crate as uint); - (h << 2u) + (did.node as uint) - } - fn hash_subty(id: uint, subty: t) -> uint { (id << 2u) + type_id(subty) } - fn hash_subtys(id: uint, subtys: [t]) -> uint { - let h = id; - for s in subtys { h = (h << 2u) + type_id(s) } - h - } - fn hash_type_constr(id: uint, c: @type_constr) -> uint { - let h = id; - h = (h << 2u) + hash_def(h, c.node.id); - // FIXME this makes little sense - for a in c.node.args { - alt a.node { - carg_base { h += h << 2u; } - carg_lit(_) { fail "lit args not implemented yet"; } - carg_ident(p) { h += h << 2u; } - } - } - h - } - alt st { - ty_nil { 0u } ty_bool { 1u } - ty_int(t) { - alt t { - ast::ty_i { 2u } ast::ty_char { 3u } ast::ty_i8 { 4u } - ast::ty_i16 { 5u } ast::ty_i32 { 6u } ast::ty_i64 { 7u } - } - } - ty_uint(t) { - alt t { - ast::ty_u { 8u } ast::ty_u8 { 9u } ast::ty_u16 { 10u } - ast::ty_u32 { 11u } ast::ty_u64 { 12u } - } - } - ty_float(t) { - alt t { ast::ty_f { 13u } ast::ty_f32 { 14u } ast::ty_f64 { 15u } } - } - ty_str { 17u } - ty_enum(did, tys) { - let h = hash_def(18u, did); - for typ: t in tys { h = hash_subty(h, typ); } - h - } - ty_box(mt) { hash_subty(19u, mt.ty) } - ty_vec(mt) { hash_subty(21u, mt.ty) } - ty_rec(fields) { - let h = 26u; - for f in fields { h = hash_subty(h, f.mt.ty); } - h - } - ty_tup(ts) { hash_subtys(25u, ts) } - ty_fn(f) { - let h = 27u; - for a in f.inputs { h = hash_subty(h, a.ty); } - hash_subty(h, f.output) - } - ty_var(v) { hash_uint(30u, v as uint) } - ty_param(pid, did) { hash_def(hash_uint(31u, pid), did) } - ty_self(ts) { - let h = 28u; - for t in ts { h = hash_subty(h, t); } - h - } - ty_type { 32u } - ty_bot { 34u } - ty_ptr(mt) { hash_subty(35u, mt.ty) } - ty_res(did, sub, tps) { - let h = hash_subty(hash_def(18u, did), sub); - hash_subtys(h, tps) - } - ty_constr(t, cs) { - let h = hash_subty(36u, t); - for c in cs { h = (h << 2u) + hash_type_constr(h, c); } - h - } - ty_uniq(mt) { hash_subty(37u, mt.ty) } - ty_send_type { 38u } - ty_iface(did, tys) { - let h = hash_def(40u, did); - for typ: t in tys { h = hash_subty(h, typ); } - h - } - ty_opaque_closure_ptr(ck_block) { 41u } - ty_opaque_closure_ptr(ck_box) { 42u } - ty_opaque_closure_ptr(ck_uniq) { 43u } - ty_opaque_box { 44u } - ty_class(did, tys) { - let h = hash_def(45u, did); - for typ: t in tys { h = hash_subty(h, typ); } - h - } - } -} - -fn arg_eq<T>(eq: fn(T, T) -> bool, - a: @sp_constr_arg<T>, - b: @sp_constr_arg<T>) - -> bool { - alt a.node { - ast::carg_base { - alt b.node { ast::carg_base { ret true; } _ { ret false; } } - } - ast::carg_ident(s) { - alt b.node { ast::carg_ident(t) { ret eq(s, t); } _ { ret false; } } - } - ast::carg_lit(l) { - alt b.node { - ast::carg_lit(m) { ret ast_util::lit_eq(l, m); } _ { ret false; } - } - } - } -} - -fn args_eq<T>(eq: fn(T, T) -> bool, - a: [@sp_constr_arg<T>], - b: [@sp_constr_arg<T>]) -> bool { - let i: uint = 0u; - for arg: @sp_constr_arg<T> in a { - if !arg_eq(eq, arg, b[i]) { ret false; } - i += 1u; - } - ret true; -} - -fn constr_eq(c: @constr, d: @constr) -> bool { - fn eq_int(&&x: uint, &&y: uint) -> bool { ret x == y; } - ret path_to_str(c.node.path) == path_to_str(d.node.path) && - // FIXME: hack - args_eq(eq_int, c.node.args, d.node.args); -} - -fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool { - if vec::len(cs) != vec::len(ds) { ret false; } - let i = 0u; - for c: @constr in cs { if !constr_eq(c, ds[i]) { ret false; } i += 1u; } - ret true; -} - -fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t { - smallintmap::get(*cx.node_types, id as uint) -} - -fn node_id_to_type_params(cx: ctxt, id: ast::node_id) -> [t] { - alt cx.node_type_substs.find(id) { - none { ret []; } - some(ts) { ret ts; } - } -} - -fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool { - ret cx.node_type_substs.contains_key(id); -} - -// Returns the number of distinct type parameters in the given type. -fn count_ty_params(cx: ctxt, ty: t) -> uint { - let param_indices = []; - walk_ty(cx, ty) {|t| - alt get(t).struct { - ty_param(param_idx, _) { - if !vec::any(param_indices, {|i| i == param_idx}) { - param_indices += [param_idx]; - } - } - _ {} - } - } - vec::len(param_indices) -} - -// Type accessors for substructures of types -fn ty_fn_args(fty: t) -> [arg] { - alt get(fty).struct { - ty_fn(f) { f.inputs } - _ { fail "ty_fn_args() called on non-fn type"; } - } -} - -fn ty_fn_proto(fty: t) -> ast::proto { - alt get(fty).struct { - ty_fn(f) { f.proto } - _ { fail "ty_fn_proto() called on non-fn type"; } - } -} - -pure fn ty_fn_ret(fty: t) -> t { - alt get(fty).struct { - ty_fn(f) { f.output } - _ { fail "ty_fn_ret() called on non-fn type"; } - } -} - -fn ty_fn_ret_style(fty: t) -> ast::ret_style { - alt get(fty).struct { - ty_fn(f) { f.ret_style } - _ { fail "ty_fn_ret_style() called on non-fn type"; } - } -} - -fn is_fn_ty(fty: t) -> bool { - alt get(fty).struct { - ty_fn(_) { ret true; } - _ { ret false; } - } -} - -// Just checks whether it's a fn that returns bool, -// not its purity. -fn is_pred_ty(fty: t) -> bool { - is_fn_ty(fty) && type_is_bool(ty_fn_ret(fty)) -} - -fn ty_var_id(typ: t) -> int { - alt get(typ).struct { - ty_var(vid) { ret vid; } - _ { #error("ty_var_id called on non-var ty"); fail; } - } -} - - -// Type accessors for AST nodes -fn block_ty(cx: ctxt, b: ast::blk) -> t { - ret node_id_to_type(cx, b.node.id); -} - - -// Returns the type of a pattern as a monotype. Like @expr_ty, this function -// doesn't provide type parameter substitutions. -fn pat_ty(cx: ctxt, pat: @ast::pat) -> t { - ret node_id_to_type(cx, pat.id); -} - - -// Returns the type of an expression as a monotype. -// -// NB: This type doesn't provide type parameter substitutions; e.g. if you -// ask for the type of "id" in "id(3)", it will return "fn(&int) -> int" -// instead of "fn(t) -> T with T = int". If this isn't what you want, see -// expr_ty_params_and_ty() below. -fn expr_ty(cx: ctxt, expr: @ast::expr) -> t { - ret node_id_to_type(cx, expr.id); -} - -fn expr_ty_params_and_ty(cx: ctxt, expr: @ast::expr) -> {params: [t], ty: t} { - ret {params: node_id_to_type_params(cx, expr.id), - ty: node_id_to_type(cx, expr.id)}; -} - -fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool { - ret node_id_has_type_params(cx, expr.id); -} - -fn expr_is_lval(method_map: typeck::method_map, e: @ast::expr) -> bool { - alt e.node { - ast::expr_path(_) | ast::expr_unary(ast::deref, _) { true } - ast::expr_field(_, _, _) | ast::expr_index(_, _) { - !method_map.contains_key(e.id) - } - _ { false } - } -} - -fn stmt_node_id(s: @ast::stmt) -> ast::node_id { - alt s.node { - ast::stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) { - ret id; - } - } -} - -fn field_idx(id: ast::ident, fields: [field]) -> option<uint> { - let i = 0u; - for f in fields { if f.ident == id { ret some(i); } i += 1u; } - ret none; -} - -fn get_field(rec_ty: t, id: ast::ident) -> field { - alt check vec::find(get_fields(rec_ty), {|f| str::eq(f.ident, id) }) { - some(f) { f } - } -} - -fn get_fields(rec_ty:t) -> [field] { - alt check get(rec_ty).struct { - ty_rec(fields) { fields } - } -} - -fn method_idx(id: ast::ident, meths: [method]) -> option<uint> { - let i = 0u; - for m in meths { if m.ident == id { ret some(i); } i += 1u; } - ret none; -} - -fn sort_methods(meths: [method]) -> [method] { - fn method_lteq(a: method, b: method) -> bool { - ret str::le(a.ident, b.ident); - } - ret std::sort::merge_sort(bind method_lteq(_, _), meths); -} - -fn occurs_check_fails(tcx: ctxt, sp: option<span>, vid: int, rt: t) -> - bool { - // Fast path - if !type_has_vars(rt) { ret false; } - - // Occurs check! - if vec::contains(vars_in_type(tcx, rt), vid) { - alt sp { - some(s) { - // Maybe this should be span_err -- however, there's an - // assertion later on that the type doesn't contain - // variables, so in this case we have to be sure to die. - tcx.sess.span_fatal - (s, "Type inference failed because I \ - could not find a type\n that's both of the form " - + ty_to_str(tcx, mk_var(tcx, vid)) + - " and of the form " + ty_to_str(tcx, rt) + - ". Such a type would have to be infinitely large."); - } - _ { ret true; } - } - } else { ret false; } -} - -// Maintains a little union-set tree for inferred modes. `canon()` returns -// the current head value for `m0`. -fn canon<T:copy>(tbl: hashmap<ast::node_id, ast::inferable<T>>, - m0: ast::inferable<T>) -> ast::inferable<T> { - alt m0 { - ast::infer(id) { - alt tbl.find(id) { - none { m0 } - some(m1) { - let cm1 = canon(tbl, m1); - // path compression: - if cm1 != m1 { tbl.insert(id, cm1); } - cm1 - } - } - } - _ { m0 } - } -} - -// Maintains a little union-set tree for inferred modes. `resolve_mode()` -// returns the current head value for `m0`. -fn canon_mode(cx: ctxt, m0: ast::mode) -> ast::mode { - canon(cx.inferred_modes, m0) -} - -// Returns the head value for mode, failing if `m` was a infer(_) that -// was never inferred. This should be safe for use after typeck. -fn resolved_mode(cx: ctxt, m: ast::mode) -> ast::rmode { - alt canon_mode(cx, m) { - ast::infer(_) { - cx.sess.bug(#fmt["mode %? was never resolved", m]); - } - ast::expl(m0) { m0 } - } -} - -fn arg_mode(cx: ctxt, a: arg) -> ast::rmode { resolved_mode(cx, a.mode) } - -// Unifies `m1` and `m2`. Returns unified value or failure code. -fn unify_mode(cx: ctxt, m1: ast::mode, m2: ast::mode) - -> result::t<ast::mode, type_err> { - alt (canon_mode(cx, m1), canon_mode(cx, m2)) { - (m1, m2) if (m1 == m2) { - result::ok(m1) - } - (ast::infer(id1), ast::infer(id2)) { - cx.inferred_modes.insert(id2, m1); - result::ok(m1) - } - (ast::infer(id), m) | (m, ast::infer(id)) { - cx.inferred_modes.insert(id, m); - result::ok(m1) - } - (m1, m2) { - result::err(terr_mode_mismatch(m1, m2)) - } - } -} - -// If `m` was never unified, unifies it with `m_def`. Returns the final value -// for `m`. -fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) { - alt canon_mode(cx, m) { - ast::infer(id) { - cx.inferred_modes.insert(id, ast::expl(m_def)); - } - ast::expl(_) { } - } -} - -// Type unification via Robinson's algorithm (Robinson 1965). Implemented as -// described in Hoder and Voronkov: -// -// http://www.cs.man.ac.uk/~hoderk/ubench/unification_full.pdf -mod unify { - export fixup_result; - export fixup_vars; - export fix_ok; - export fix_err; - export mk_var_bindings; - export resolve_type_structure; - export resolve_type_var; - export result; - export unify; - export ures_ok; - export ures_err; - export var_bindings; - export precise, in_bindings; - - enum result { ures_ok(t), ures_err(type_err), } - enum union_result { unres_ok, unres_err(type_err), } - enum fixup_result { - fix_ok(t), // fixup succeeded - fix_err(int), // fixup failed because a type variable was unresolved - } - type var_bindings = - {sets: ufind::ufind, types: smallintmap::smallintmap<t>}; - - enum unify_style { - precise, - in_bindings(@var_bindings), - } - type uctxt = {st: unify_style, tcx: ctxt}; - - fn mk_var_bindings() -> @var_bindings { - ret @{sets: ufind::make(), types: smallintmap::mk::<t>()}; - } - - // Unifies two sets. - fn union(cx: @uctxt, set_a: uint, set_b: uint, - variance: variance) -> union_result { - let vb = alt cx.st { - in_bindings(vb) { vb } - _ { cx.tcx.sess.bug("Someone forgot to document an invariant \ - in union"); } - }; - ufind::grow(vb.sets, math::max(set_a, set_b) + 1u); - let root_a = ufind::find(vb.sets, set_a); - let root_b = ufind::find(vb.sets, set_b); - - let replace_type = ( - fn@(vb: @var_bindings, t: t) { - ufind::union(vb.sets, set_a, set_b); - let root_c: uint = ufind::find(vb.sets, set_a); - smallintmap::insert::<t>(vb.types, root_c, t); - } - ); - - alt smallintmap::find(vb.types, root_a) { - none { - alt smallintmap::find(vb.types, root_b) { - none { ufind::union(vb.sets, set_a, set_b); ret unres_ok; } - some(t_b) { replace_type(vb, t_b); ret unres_ok; } - } - } - some(t_a) { - alt smallintmap::find(vb.types, root_b) { - none { replace_type(vb, t_a); ret unres_ok; } - some(t_b) { - alt unify_step(cx, t_a, t_b, variance) { - ures_ok(t_c) { replace_type(vb, t_c); ret unres_ok; } - ures_err(terr) { ret unres_err(terr); } - } - } - } - } - } - } - - fn record_var_binding(cx: @uctxt, key: int, typ: t, variance: variance) - -> result { - let vb = alt check cx.st { in_bindings(vb) { vb } }; - ufind::grow(vb.sets, (key as uint) + 1u); - let root = ufind::find(vb.sets, key as uint); - let result_type = typ; - alt smallintmap::find(vb.types, root) { - some(old_type) { - alt unify_step(cx, old_type, typ, variance) { - ures_ok(unified_type) { result_type = unified_type; } - rs { ret rs; } - } - } - none {/* fall through */ } - } - smallintmap::insert(vb.types, root, result_type); - ret ures_ok(mk_var(cx.tcx, key)); - } - - // Simple structural type comparison. - fn struct_cmp(cx: @uctxt, expected: t, actual: t) -> result { - let tcx = cx.tcx; - let cfg = tcx.sess.targ_cfg; - if mach_sty(cfg, expected) == mach_sty(cfg, actual) { - ret ures_ok(expected); - } - ret ures_err(terr_mismatch); - } - - // Right now this just checks that the lists of constraints are - // pairwise equal. - fn unify_constrs(base_t: t, expected: [@type_constr], - actual: [@type_constr]) -> result { - let expected_len = vec::len(expected); - let actual_len = vec::len(actual); - - if expected_len != actual_len { - ret ures_err(terr_constr_len(expected_len, actual_len)); - } - let i = 0u; - let rslt; - for c: @type_constr in expected { - rslt = unify_constr(base_t, c, actual[i]); - alt rslt { ures_ok(_) { } ures_err(_) { ret rslt; } } - i += 1u; - } - ret ures_ok(base_t); - } - fn unify_constr(base_t: t, expected: @type_constr, - actual_constr: @type_constr) -> result { - let ok_res = ures_ok(base_t); - let err_res = ures_err(terr_constr_mismatch(expected, actual_constr)); - if expected.node.id != actual_constr.node.id { ret err_res; } - let expected_arg_len = vec::len(expected.node.args); - let actual_arg_len = vec::len(actual_constr.node.args); - if expected_arg_len != actual_arg_len { ret err_res; } - let i = 0u; - let actual; - for a: @ty_constr_arg in expected.node.args { - actual = actual_constr.node.args[i]; - alt a.node { - carg_base { - alt actual.node { carg_base { } _ { ret err_res; } } - } - carg_lit(l) { - alt actual.node { - carg_lit(m) { if l != m { ret err_res; } } - _ { ret err_res; } - } - } - carg_ident(p) { - alt actual.node { - carg_ident(q) { if p.node != q.node { ret err_res; } } - _ { ret err_res; } - } - } - } - i += 1u; - } - ret ok_res; - } - - // Unifies two mutability flags. - fn unify_mut(expected: ast::mutability, actual: ast::mutability, - variance: variance) -> - option<(ast::mutability, variance)> { - - // If you're unifying on something mutable then we have to - // be invariant on the inner type - let newvariance = alt expected { - ast::m_mutbl { - variance_transform(variance, invariant) - } - _ { - variance_transform(variance, covariant) - } - }; - - if expected == actual { ret some((expected, newvariance)); } - if variance == covariant { - if expected == ast::m_const { - ret some((actual, newvariance)); - } - } else if variance == contravariant { - if actual == ast::m_const { - ret some((expected, newvariance)); - } - } - ret none; - } - fn unify_fn_proto(e_proto: ast::proto, a_proto: ast::proto, - variance: variance) -> option<result> { - // Prototypes form a diamond-shaped partial order: - // - // block - // ^ ^ - // shared send - // ^ ^ - // bare - // - // where "^" means "subtype of" (forgive the abuse of the term - // subtype). - fn sub_proto(p_sub: ast::proto, p_sup: ast::proto) -> bool { - ret alt (p_sub, p_sup) { - (_, ast::proto_any) { true } - (ast::proto_bare, _) { true } - - // Equal prototypes are always subprotos: - (_, _) { p_sub == p_sup } - }; - } - - ret alt variance { - invariant if e_proto == a_proto { none } - covariant if sub_proto(a_proto, e_proto) { none } - contravariant if sub_proto(e_proto, a_proto) { none } - _ { some(ures_err(terr_mismatch)) } - }; - } - fn unify_args(cx: @uctxt, e_args: [arg], a_args: [arg], - variance: variance) -> either::t<result, [arg]> { - if !vec::same_length(e_args, a_args) { - ret either::left(ures_err(terr_arg_count)); - } - // The variance changes (flips basically) when descending - // into arguments of function types - let variance = variance_transform(variance, contravariant); - // Would use vec::map2(), but for the need to return in case of - // error: - let i = 0u, result = []; - for expected_input in e_args { - let actual_input = a_args[i]; - i += 1u; - - // Unify the result modes. - let result_mode = - alt unify_mode(cx.tcx, expected_input.mode, - actual_input.mode) { - result::err(err) { ret either::left(ures_err(err)); } - result::ok(m) { m } - }; - - alt unify_step(cx, expected_input.ty, actual_input.ty, - variance) { - ures_ok(rty) { result += [{mode: result_mode, ty: rty}]; } - err { ret either::left(err); } - } - } - either::right(result) - } - fn unify_fn(cx: @uctxt, e_f: fn_ty, a_f: fn_ty, variance: variance) - -> result { - alt unify_fn_proto(e_f.proto, a_f.proto, variance) { - some(err) { ret err; } - none { /* fall through */ } - } - - if a_f.ret_style != ast::noreturn && a_f.ret_style != e_f.ret_style { - /* even though typestate checking is mostly - responsible for checking control flow annotations, - this check is necessary to ensure that the - annotation in an object method matches the - declared object type */ - ret ures_err(terr_ret_style_mismatch(e_f.ret_style, - a_f.ret_style)); - } - let result_ins = alt unify_args(cx, e_f.inputs, a_f.inputs, - variance) { - either::left(err) { ret err; } - either::right(ts) { ts } - }; - - // Check the output. - alt unify_step(cx, e_f.output, a_f.output, variance) { - ures_ok(rty) { - ures_ok(mk_fn(cx.tcx, {proto: e_f.proto, - inputs: result_ins, - output: rty - with a_f})) - } - x { x } - } - } - - // If the given type is a variable, returns the structure of that type. - fn resolve_type_structure(vb: @var_bindings, typ: t) -> - fixup_result { - alt get(typ).struct { - ty_var(vid) { - if vid as uint >= ufind::set_count(vb.sets) { ret fix_err(vid); } - let root_id = ufind::find(vb.sets, vid as uint); - alt smallintmap::find::<t>(vb.types, root_id) { - none { ret fix_err(vid); } - some(rt) { ret fix_ok(rt); } - } - } - _ { ret fix_ok(typ); } - } - } - - // Specifies the allowable subtyping between expected and actual types - enum variance { - // Actual may be a subtype of expected - covariant, - // Actual may be a supertype of expected - contravariant, - // Actual must be the same type as expected - invariant, - } - - // The calculation for recursive variance - // "Taming the Wildcards: Combining Definition- and Use-Site Variance" - // by John Altidor, et. al. - // - // I'm just copying the table from figure 1 - haven't actually - // read the paper (yet). - fn variance_transform(a: variance, b: variance) -> variance { - alt a { - covariant { - alt b { - covariant { covariant } - contravariant { contravariant } - invariant { invariant } - } - } - contravariant { - alt b { - covariant { contravariant } - contravariant { covariant } - invariant { invariant } - } - } - invariant { - alt b { - covariant { invariant } - contravariant { invariant } - invariant { invariant } - } - } - } - } - - fn unify_tps(cx: @uctxt, expected_tps: [t], actual_tps: [t], - variance: variance, finish: fn([t]) -> t) -> result { - let result_tps = [], i = 0u; - for exp in expected_tps { - let act = actual_tps[i]; - i += 1u; - let result = unify_step(cx, exp, act, variance); - alt result { - ures_ok(rty) { result_tps += [rty]; } - _ { ret result; } - } - } - ures_ok(finish(result_tps)) - } - fn unify_mt(cx: @uctxt, e_mt: mt, a_mt: mt, variance: variance, - mut_err: type_err, finish: fn(ctxt, mt) -> t) -> result { - alt unify_mut(e_mt.mutbl, a_mt.mutbl, variance) { - none { ures_err(mut_err) } - some((mutt, var)) { - alt unify_step(cx, e_mt.ty, a_mt.ty, var) { - ures_ok(result_sub) { - ures_ok(finish(cx.tcx, {ty: result_sub, mutbl: mutt})) - } - err { err } - } - } - } - } - - fn unify_step(cx: @uctxt, expected: t, actual: t, - variance: variance) -> result { - // Fast path. - if expected == actual { ret ures_ok(expected); } - - alt (get(expected).struct, get(actual).struct) { - (ty_var(e_id), ty_var(a_id)) { - alt union(cx, e_id as uint, a_id as uint, variance) { - unres_ok { ures_ok(actual) } - unres_err(err) { ures_err(err) } - } - } - (_, ty_var(a_id)) { - let v = variance_transform(variance, contravariant); - record_var_binding(cx, a_id, expected, v) - } - (ty_var(e_id), _) { - let v = variance_transform(variance, covariant); - record_var_binding(cx, e_id, actual, v) - } - (_, ty_bot) { ures_ok(expected) } - (ty_bot, _) { ures_ok(actual) } - (ty_nil, _) | (ty_bool, _) | (ty_int(_), _) | (ty_uint(_), _) | - (ty_float(_), _) | (ty_str, _) | (ty_send_type, _) { - struct_cmp(cx, expected, actual) - } - (ty_param(e_n, _), ty_param(a_n, _)) if e_n == a_n { - ures_ok(expected) - } - (ty_enum(e_id, e_tps), ty_enum(a_id, a_tps)) if e_id == a_id { - unify_tps(cx, e_tps, a_tps, variance, {|tps| - mk_enum(cx.tcx, e_id, tps) - }) - } - (ty_iface(e_id, e_tps), ty_iface(a_id, a_tps)) if e_id == a_id { - unify_tps(cx, e_tps, a_tps, variance, {|tps| - mk_iface(cx.tcx, e_id, tps) - }) - } - (ty_class(e_id, e_tps), ty_class(a_id, a_tps)) if e_id == a_id { - unify_tps(cx, e_tps, a_tps, variance, {|tps| - mk_class(cx.tcx, e_id, tps) - }) - } - (ty_box(e_mt), ty_box(a_mt)) { - unify_mt(cx, e_mt, a_mt, variance, terr_box_mutability, mk_box) - } - (ty_uniq(e_mt), ty_uniq(a_mt)) { - unify_mt(cx, e_mt, a_mt, variance, terr_box_mutability, mk_uniq) - } - (ty_vec(e_mt), ty_vec(a_mt)) { - unify_mt(cx, e_mt, a_mt, variance, terr_vec_mutability, mk_vec) - } - (ty_ptr(e_mt), ty_ptr(a_mt)) { - unify_mt(cx, e_mt, a_mt, variance, terr_ptr_mutability, mk_ptr) - } - (ty_res(e_id, e_inner, e_tps), ty_res(a_id, a_inner, a_tps)) - if e_id == a_id { - alt unify_step(cx, e_inner, a_inner, variance) { - ures_ok(res_inner) { - unify_tps(cx, e_tps, a_tps, variance, {|tps| - mk_res(cx.tcx, a_id, res_inner, tps) - }) - } - err { err } - } - } - (ty_rec(e_fields), ty_rec(a_fields)) { - let e_len = e_fields.len(), a_len = a_fields.len(); - if e_len != a_len { - ret ures_err(terr_record_size(e_len, a_len)); - } - let result_fields = [], i = 0u; - while i < a_len { - let e_field = e_fields[i], a_field = a_fields[i]; - if e_field.ident != a_field.ident { - ret ures_err(terr_record_fields(e_field.ident, - a_field.ident)); - } - alt unify_mt(cx, e_field.mt, a_field.mt, variance, - terr_record_mutability, {|cx, mt| - result_fields += [{mt: mt with e_field}]; - mk_nil(cx) - }) { - ures_ok(_) {} - err { ret err; } - } - i += 1u; - } - ures_ok(mk_rec(cx.tcx, result_fields)) - } - (ty_tup(e_elems), ty_tup(a_elems)) { - let e_len = e_elems.len(), a_len = a_elems.len(); - if e_len != a_len { ret ures_err(terr_tuple_size(e_len, a_len)); } - let result_elems = [], i = 0u; - while i < a_len { - alt unify_step(cx, e_elems[i], a_elems[i], variance) { - ures_ok(rty) { result_elems += [rty]; } - err { ret err; } - } - i += 1u; - } - ures_ok(mk_tup(cx.tcx, result_elems)) - } - (ty_fn(e_fty), ty_fn(a_fty)) { - unify_fn(cx, e_fty, a_fty, variance) - } - (ty_constr(e_t, e_constrs), ty_constr(a_t, a_constrs)) { - // unify the base types... - alt unify_step(cx, e_t, a_t, variance) { - ures_ok(rty) { - // FIXME: probably too restrictive -- - // requires the constraints to be syntactically equal - unify_constrs(expected, e_constrs, a_constrs) - } - err { err } - } - } - (ty_constr(e_t, _), _) { - // If the actual type is *not* a constrained type, - // then we go ahead and just ignore the constraints on - // the expected type. typestate handles the rest. - unify_step(cx, e_t, actual, variance) - } - _ { ures_err(terr_mismatch) } - } - } - fn unify(expected: t, actual: t, st: unify_style, - tcx: ctxt) -> result { - let cx = @{st: st, tcx: tcx}; - ret unify_step(cx, expected, actual, covariant); - } - fn dump_var_bindings(tcx: ctxt, vb: @var_bindings) { - let i = 0u; - while i < vec::len::<ufind::node>(vb.sets.nodes) { - let sets = ""; - let j = 0u; - while j < vec::len::<option<uint>>(vb.sets.nodes) { - if ufind::find(vb.sets, j) == i { sets += #fmt[" %u", j]; } - j += 1u; - } - let typespec; - alt smallintmap::find::<t>(vb.types, i) { - none { typespec = ""; } - some(typ) { typespec = " =" + ty_to_str(tcx, typ); } - } - #error("set %u:%s%s", i, typespec, sets); - i += 1u; - } - } - - // Fixups and substitutions - // Takes an optional span - complain about occurs check violations - // iff the span is present (so that if we already know we're going - // to error anyway, we don't complain) - fn fixup_vars(tcx: ctxt, sp: option<span>, vb: @var_bindings, - typ: t) -> fixup_result { - fn subst_vars(tcx: ctxt, sp: option<span>, vb: @var_bindings, - unresolved: @mutable option<int>, - vars_seen: std::list::list<int>, vid: int) -> t { - // Should really return a fixup_result instead of a t, but fold_ty - // doesn't allow returning anything but a t. - if vid as uint >= ufind::set_count(vb.sets) { - *unresolved = some(vid); - ret mk_var(tcx, vid); - } - let root_id = ufind::find(vb.sets, vid as uint); - alt smallintmap::find::<t>(vb.types, root_id) { - none { *unresolved = some(vid); ret mk_var(tcx, vid); } - some(rt) { - let give_up = false; - std::list::iter(vars_seen) {|v| - if v == vid { - give_up = true; - option::may(sp) {|sp| - tcx.sess.span_fatal( - sp, "can not instantiate infinite type"); - } - } - } - // Return the type unchanged, so we can error out - // downstream - if give_up { ret rt; } - ret fold_ty(tcx, fm_var(bind subst_vars( - tcx, sp, vb, unresolved, std::list::cons(vid, @vars_seen), - _)), rt); - } - } - } - let unresolved = @mutable none::<int>; - let rty = fold_ty(tcx, fm_var(bind subst_vars( - tcx, sp, vb, unresolved, std::list::nil, _)), typ); - let ur = *unresolved; - alt ur { - none { ret fix_ok(rty); } - some(var_id) { ret fix_err(var_id); } - } - } - fn resolve_type_var(tcx: ctxt, sp: option<span>, vb: @var_bindings, - vid: int) -> fixup_result { - if vid as uint >= ufind::set_count(vb.sets) { ret fix_err(vid); } - let root_id = ufind::find(vb.sets, vid as uint); - alt smallintmap::find::<t>(vb.types, root_id) { - none { ret fix_err(vid); } - some(rt) { ret fixup_vars(tcx, sp, vb, rt); } - } - } -} - -fn same_type(cx: ctxt, a: t, b: t) -> bool { - alt unify::unify(a, b, unify::precise, cx) { - unify::ures_ok(_) { true } - _ { false } - } -} - -fn type_err_to_str(err: type_err) -> str { - alt err { - terr_mismatch { ret "types differ"; } - terr_ret_style_mismatch(expect, actual) { - fn to_str(s: ast::ret_style) -> str { - alt s { - ast::noreturn { "non-returning" } - ast::return_val { "return-by-value" } - } - } - ret to_str(actual) + " function found where " + to_str(expect) + - " function was expected"; - } - terr_box_mutability { ret "boxed values differ in mutability"; } - terr_vec_mutability { ret "vectors differ in mutability"; } - terr_ptr_mutability { ret "pointers differ in mutability"; } - terr_tuple_size(e_sz, a_sz) { - ret "expected a tuple with " + uint::to_str(e_sz, 10u) + - " elements but found one with " + uint::to_str(a_sz, 10u) + - " elements"; - } - terr_record_size(e_sz, a_sz) { - ret "expected a record with " + uint::to_str(e_sz, 10u) + - " fields but found one with " + uint::to_str(a_sz, 10u) + - " fields"; - } - terr_record_mutability { ret "record elements differ in mutability"; } - terr_record_fields(e_fld, a_fld) { - ret "expected a record with field '" + e_fld + - "' but found one with field '" + a_fld + "'"; - } - terr_arg_count { ret "incorrect number of function parameters"; } - terr_mode_mismatch(e_mode, a_mode) { - ret "expected argument mode " + mode_to_str(e_mode) + " but found " + - mode_to_str(a_mode); - } - terr_constr_len(e_len, a_len) { - ret "Expected a type with " + uint::str(e_len) + - " constraints, but found one with " + uint::str(a_len) + - " constraints"; - } - terr_constr_mismatch(e_constr, a_constr) { - ret "Expected a type with constraint " + ty_constr_to_str(e_constr) + - " but found one with constraint " + - ty_constr_to_str(a_constr); - } - } -} - -// Replaces type parameters in the given type using the given list of -// substitions. -fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t { - // Precondition? idx < vec::len(substs) - fold_ty(cx, fm_param({|idx, _id| substs[idx]}), typ) -} - -fn def_has_ty_params(def: ast::def) -> bool { - alt def { - ast::def_fn(_, _) | ast::def_variant(_, _) { true } - _ { false } - } -} - -fn store_iface_methods(cx: ctxt, id: ast::node_id, ms: @[method]) { - cx.iface_method_cache.insert(ast_util::local_def(id), ms); -} - -fn iface_methods(cx: ctxt, id: ast::def_id) -> @[method] { - alt cx.iface_method_cache.find(id) { - some(ms) { ret ms; } - _ {} - } - // Local interfaces are supposed to have been added explicitly. - assert id.crate != ast::local_crate; - let result = csearch::get_iface_methods(cx, id); - cx.iface_method_cache.insert(id, result); - result -} - -fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> { - if id.crate == ast::local_crate { - option::map(cx.tcache.find(id), {|it| it.ty}) - } else { - csearch::get_impl_iface(cx, id) - } -} - -// Enum information -type variant_info = @{args: [t], ctor_ty: t, name: str, - id: ast::def_id, disr_val: int}; - -fn substd_enum_variants(cx: ctxt, id: ast::def_id, tps: [ty::t]) - -> [variant_info] { - vec::map(*enum_variants(cx, id)) { |variant_info| - let substd_args = vec::map(variant_info.args) {|aty| - substitute_type_params(cx, tps, aty) - }; - - let substd_ctor_ty = - substitute_type_params(cx, tps, variant_info.ctor_ty); - - @{args: substd_args, ctor_ty: substd_ctor_ty with *variant_info} - } -} - -fn item_path_str(cx: ctxt, id: ast::def_id) -> str { - ast_map::path_to_str(item_path(cx, id)) -} - -fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { - if id.crate != ast::local_crate { - csearch::get_item_path(cx, id) - } else { - let node = cx.items.get(id.node); - alt node { - ast_map::node_item(item, path) { - let item_elt = alt item.node { - item_mod(_) | item_native_mod(_) { - ast_map::path_mod(item.ident) - } - _ { - ast_map::path_name(item.ident) - } - }; - *path + [item_elt] - } - - ast_map::node_native_item(nitem, path) { - *path + [ast_map::path_name(nitem.ident)] - } - - ast_map::node_method(method, _, path) { - *path + [ast_map::path_name(method.ident)] - } - - ast_map::node_variant(variant, _, path) { - vec::init(*path) + [ast_map::path_name(variant.node.name)] - } - - ast_map::node_expr(_) | ast_map::node_arg(_, _) | - ast_map::node_local(_) | ast_map::node_res_ctor(_) { - cx.sess.bug(#fmt["cannot find item_path for node %?", node]); - } - } - } -} - -fn enum_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] { - alt cx.enum_var_cache.find(id) { - some(variants) { ret variants; } - _ { /* fallthrough */ } - } - let result = if ast::local_crate != id.crate { - @csearch::get_enum_variants(cx, id) - } else { - // FIXME: Now that the variants are run through the type checker (to - // check the disr_expr if it exists), this code should likely be - // moved there to avoid having to call eval_const_expr twice. - alt cx.items.get(id.node) { - ast_map::node_item(@{node: ast::item_enum(variants, _), _}, _) { - let disr_val = -1; - @vec::map(variants, {|variant| - let ctor_ty = node_id_to_type(cx, variant.node.id); - let arg_tys = if vec::len(variant.node.args) > 0u { - vec::map(ty_fn_args(ctor_ty), {|a| a.ty}) - } else { [] }; - alt variant.node.disr_expr { - some (ex) { - // FIXME: issue #1417 - disr_val = alt syntax::ast_util::eval_const_expr(ex) { - ast_util::const_int(val) {val as int} - _ { cx.sess.bug("tag_variants: bad disr expr"); } - } - } - _ {disr_val += 1;} - } - @{args: arg_tys, - ctor_ty: ctor_ty, - name: variant.node.name, - id: ast_util::local_def(variant.node.id), - disr_val: disr_val - } - }) - } - _ { cx.sess.bug("tag_variants: id not bound to an enum"); } - } - }; - cx.enum_var_cache.insert(id, result); - result -} - - -// Returns information about the enum variant with the given ID: -fn enum_variant_with_id(cx: ctxt, enum_id: ast::def_id, - variant_id: ast::def_id) -> variant_info { - let variants = enum_variants(cx, enum_id); - let i = 0u; - while i < vec::len::<variant_info>(*variants) { - let variant = variants[i]; - if def_eq(variant.id, variant_id) { ret variant; } - i += 1u; - } - cx.sess.bug("enum_variant_with_id(): no variant exists with that ID"); -} - - -// If the given item is in an external crate, looks up its type and adds it to -// the type cache. Returns the type parameters and type. -fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty { - alt cx.tcache.find(did) { - some(tpt) { ret tpt; } - none { - // The item is in this crate. The caller should have added it to the - // type cache already - assert did.crate != ast::local_crate; - let tyt = csearch::get_type(cx, did); - cx.tcache.insert(did, tyt); - ret tyt; - } - } -} - -fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { - const tycat_other: int = 0; - const tycat_bool: int = 1; - const tycat_int: int = 2; - const tycat_float: int = 3; - const tycat_str: int = 4; - const tycat_vec: int = 5; - const tycat_struct: int = 6; - const tycat_bot: int = 7; - - const opcat_add: int = 0; - const opcat_sub: int = 1; - const opcat_mult: int = 2; - const opcat_shift: int = 3; - const opcat_rel: int = 4; - const opcat_eq: int = 5; - const opcat_bit: int = 6; - const opcat_logic: int = 7; - - fn opcat(op: ast::binop) -> int { - alt op { - ast::add { opcat_add } - ast::subtract { opcat_sub } - ast::mul { opcat_mult } - ast::div { opcat_mult } - ast::rem { opcat_mult } - ast::and { opcat_logic } - ast::or { opcat_logic } - ast::bitxor { opcat_bit } - ast::bitand { opcat_bit } - ast::bitor { opcat_bit } - ast::lsl { opcat_shift } - ast::lsr { opcat_shift } - ast::asr { opcat_shift } - ast::eq { opcat_eq } - ast::ne { opcat_eq } - ast::lt { opcat_rel } - ast::le { opcat_rel } - ast::ge { opcat_rel } - ast::gt { opcat_rel } - } - } - - fn tycat(ty: t) -> int { - alt get(ty).struct { - ty_bool { tycat_bool } - ty_int(_) { tycat_int } - ty_uint(_) { tycat_int } - ty_float(_) { tycat_float } - ty_str { tycat_str } - ty_vec(_) { tycat_vec } - ty_rec(_) { tycat_struct } - ty_tup(_) { tycat_struct } - ty_enum(_, _) { tycat_struct } - ty_bot { tycat_bot } - _ { tycat_other } - } - } - - const t: bool = true; - const f: bool = false; - - /*. add, shift, bit - . sub, rel, logic - . mult, eq, */ - /*other*/ - /*bool*/ - /*int*/ - /*float*/ - /*str*/ - /*vec*/ - /*bot*/ - let tbl = - [[f, f, f, f, t, t, f, f], [f, f, f, f, t, t, t, t], - [t, t, t, t, t, t, t, f], [t, t, t, f, t, t, f, f], - [t, f, f, f, t, t, f, f], [t, f, f, f, t, t, f, f], - [f, f, f, f, t, t, f, f], [t, t, t, t, t, t, t, t]]; /*struct*/ - - ret tbl[tycat(ty)][opcat(op)]; -} - -fn ast_constr_to_constr<T>(tcx: ctxt, c: @ast::constr_general<T>) -> - @constr_general<T> { - alt tcx.def_map.find(c.node.id) { - some(ast::def_fn(pred_id, ast::pure_fn)) { - ret @ast_util::respan(c.span, - {path: c.node.path, - args: c.node.args, - id: pred_id}); - } - _ { - tcx.sess.span_fatal(c.span, - "Predicate " + path_to_str(c.node.path) + - " is unbound or bound to a non-function or an \ - impure function"); - } - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs deleted file mode 100644 index e1c56b9fc54..00000000000 --- a/src/comp/middle/typeck.rs +++ /dev/null @@ -1,3341 +0,0 @@ -import syntax::{ast, ast_util}; -import ast::spanned; -import syntax::ast_util::{local_def, respan}; -import syntax::visit; -import metadata::csearch; -import driver::session::session; -import util::common::*; -import syntax::codemap::span; -import pat_util::*; -import middle::ty; -import middle::ty::{node_id_to_type, arg, block_ty, - expr_ty, field, node_type_table, mk_nil, - ty_param_bounds_and_ty}; -import util::ppaux::ty_to_str; -import middle::ty::unify::{ures_ok, ures_err, fix_ok, fix_err}; -import std::smallintmap; -import std::map::{hashmap, new_int_hash}; -import syntax::print::pprust::*; - -export check_crate; -export method_map, method_origin, method_static, method_param, method_iface; -export dict_map, dict_res, dict_origin, dict_static, dict_param, dict_iface; - -enum method_origin { - method_static(ast::def_id), - // iface id, method num, param num, bound num - method_param(ast::def_id, uint, uint, uint), - method_iface(ast::def_id, uint), -} -type method_map = hashmap<ast::node_id, method_origin>; - -// Resolutions for bounds of all parameters, left to right, for a given path. -type dict_res = @[dict_origin]; -enum dict_origin { - dict_static(ast::def_id, [ty::t], dict_res), - // Param number, bound number - dict_param(uint, uint), - dict_iface(ast::def_id), -} -type dict_map = hashmap<ast::node_id, dict_res>; - -type ty_table = hashmap<ast::def_id, ty::t>; - -// Used for typechecking the methods of an impl -enum self_info { self_impl(ty::t) } - -type crate_ctxt = {mutable self_infos: [self_info], - impl_map: resolve::impl_map, - method_map: method_map, - dict_map: dict_map, - // Not at all sure it's right to put these here - /* node_id for the class this fn is in -- - none if it's not in a class */ - enclosing_class_id: option<ast::node_id>, - /* map from node_ids for enclosing-class - vars and methods to types */ - enclosing_class: class_map, - tcx: ty::ctxt}; - -type class_map = hashmap<ast::node_id, ty::t>; - -type fn_ctxt = - // var_bindings, locals and next_var_id are shared - // with any nested functions that capture the environment - // (and with any functions whose environment is being captured). - {ret_ty: ty::t, - purity: ast::purity, - proto: ast::proto, - var_bindings: @ty::unify::var_bindings, - locals: hashmap<ast::node_id, int>, - next_var_id: @mutable int, - ccx: @crate_ctxt}; - - -fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> int { - alt fcx.locals.find(id) { - some(x) { x } - _ { - fcx.ccx.tcx.sess.span_fatal(sp, - "internal error looking up a local var") - } - } -} - -fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def { - alt fcx.ccx.tcx.def_map.find(id) { - some(x) { x } - _ { - fcx.ccx.tcx.sess.span_fatal(sp, - "internal error looking up a definition") - } - } -} - -// Returns the type parameter count and the type for the given definition. -fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> - ty_param_bounds_and_ty { - alt defn { - ast::def_arg(nid, _) { - assert (fcx.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - ret {bounds: @[], ty: typ}; - } - ast::def_local(nid, _) { - assert (fcx.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - ret {bounds: @[], ty: typ}; - } - ast::def_self(id) { - alt get_self_info(fcx.ccx) { - some(self_impl(impl_t)) { - ret {bounds: @[], ty: impl_t}; - } - none { - fcx.ccx.tcx.sess.span_bug(sp, "def_self with no self_info"); - } - } - } - ast::def_fn(id, ast::crust_fn) { - // Crust functions are just u8 pointers - ret { - bounds: @[], - ty: ty::mk_ptr( - fcx.ccx.tcx, - { - ty: ty::mk_mach_uint(fcx.ccx.tcx, ast::ty_u8), - mutbl: ast::m_imm - }) - }; - } - ast::def_fn(id, _) | ast::def_const(id) | - ast::def_variant(_, id) | ast::def_class(id) - { ret ty::lookup_item_type(fcx.ccx.tcx, id); } - ast::def_binding(nid) { - assert (fcx.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - ret {bounds: @[], ty: typ}; - } - ast::def_ty(_) | ast::def_prim_ty(_) { - fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type"); - } - ast::def_upvar(_, inner, _) { - ret ty_param_bounds_and_ty_for_def(fcx, sp, *inner); - } - ast::def_class_method(_, id) | ast::def_class_field(_, id) { - if id.crate != ast::local_crate { - fcx.ccx.tcx.sess.span_fatal(sp, - "class method or field referred to \ - out of scope"); - } - alt fcx.ccx.enclosing_class.find(id.node) { - some(a_ty) { ret {bounds: @[], ty: a_ty}; } - _ { fcx.ccx.tcx.sess.span_fatal(sp, - "class method or field referred to \ - out of scope"); } - } - } - - _ { - // FIXME: handle other names. - fcx.ccx.tcx.sess.unimpl("definition variant"); - } - } -} - -// Instantiates the given path, which must refer to an item with the given -// number of type parameters and type. -fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path, - tpt: ty_param_bounds_and_ty, sp: span, - id: ast::node_id) { - let ty_param_count = vec::len(*tpt.bounds); - let ty_substs_len = vec::len(pth.node.types); - if ty_substs_len > 0u { - if ty_param_count == 0u { - fcx.ccx.tcx.sess.span_fatal - (sp, "this item does not take type parameters"); - } else if ty_substs_len > ty_param_count { - fcx.ccx.tcx.sess.span_fatal - (sp, "too many type parameter provided for this item"); - } else if ty_substs_len < ty_param_count { - fcx.ccx.tcx.sess.span_fatal - (sp, "not enough type parameters provided for this item"); - } - if ty_param_count == 0u { - fcx.ccx.tcx.sess.span_fatal( - sp, "this item does not take type parameters"); - } - let substs = vec::map(pth.node.types, {|aty| - ast_ty_to_ty_crate(fcx.ccx, aty) - }); - write_ty_substs(fcx.ccx.tcx, id, tpt.ty, substs); - } else if ty_param_count > 0u { - let vars = vec::init_fn(ty_param_count, {|_i| next_ty_var(fcx)}); - write_ty_substs(fcx.ccx.tcx, id, tpt.ty, vars); - } else { - write_ty(fcx.ccx.tcx, id, tpt.ty); - } -} - -// Type tests -fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { - alt ty::unify::resolve_type_structure(fcx.var_bindings, tp) { - fix_ok(typ_s) { ret typ_s; } - fix_err(_) { - fcx.ccx.tcx.sess.span_fatal - (sp, "the type of this value must be known in this context"); - } - } -} - - -// Returns the one-level-deep structure of the given type. -fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty { - ty::get(structurally_resolved_type(fcx, sp, typ)).struct -} - -// Returns the one-level-deep structure of the given type or none if it -// is not known yet. -fn structure_of_maybe(fcx: @fn_ctxt, _sp: span, typ: ty::t) -> - option<ty::sty> { - let r = - ty::unify::resolve_type_structure(fcx.var_bindings, typ); - ret alt r { - fix_ok(typ_s) { some(ty::get(typ_s).struct) } - fix_err(_) { none } - } -} - -fn type_is_integral(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - ret ty::type_is_integral(typ_s); -} - -fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - ret ty::type_is_scalar(typ_s); -} - -fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); -} - -enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), } - -// Parses the programmer's textual representation of a type into our -// internal notion of a type. `getter` is a function that returns the type -// corresponding to a definition ID: -fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { - fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id) - -> ty::ty_param_bounds_and_ty { - alt mode { - m_check | m_check_tyvar(_) { ty::lookup_item_type(tcx, id) } - m_collect { - if id.crate != ast::local_crate { csearch::get_type(tcx, id) } - else { - alt tcx.items.find(id.node) { - some(ast_map::node_item(item, _)) { - ty_of_item(tcx, mode, item) - } - some(ast_map::node_native_item(native_item, _)) { - ty_of_native_item(tcx, mode, native_item) - } - _ { - tcx.sess.bug("Unexpected sort of item in ast_ty_to_ty"); - } - } - } - } - } - } - alt tcx.ast_ty_to_ty_cache.find(ast_ty) { - some(some(ty)) { ret ty; } - some(none) { - tcx.sess.span_fatal(ast_ty.span, "illegal recursive type. \ - insert a enum in the cycle, \ - if this is desired)"); - } - none { } - } /* go on */ - - tcx.ast_ty_to_ty_cache.insert(ast_ty, none::<ty::t>); - fn ast_mt_to_mt(tcx: ty::ctxt, mode: mode, mt: ast::mt) -> ty::mt { - ret {ty: ast_ty_to_ty(tcx, mode, mt.ty), mutbl: mt.mutbl}; - } - fn instantiate(tcx: ty::ctxt, sp: span, mode: mode, - id: ast::def_id, args: [@ast::ty]) -> ty::t { - let ty_param_bounds_and_ty = getter(tcx, mode, id); - if vec::len(*ty_param_bounds_and_ty.bounds) == 0u { - ret ty_param_bounds_and_ty.ty; - } - - // The typedef is type-parametric. Do the type substitution. - let param_bindings: [ty::t] = []; - if vec::len(args) != vec::len(*ty_param_bounds_and_ty.bounds) { - tcx.sess.span_fatal(sp, "Wrong number of type arguments for a \ - polymorphic type"); - } - for ast_ty: @ast::ty in args { - param_bindings += [ast_ty_to_ty(tcx, mode, ast_ty)]; - } - let typ = - ty::substitute_type_params(tcx, param_bindings, - ty_param_bounds_and_ty.ty); - ret typ; - } - let typ = alt ast_ty.node { - ast::ty_nil { ty::mk_nil(tcx) } - ast::ty_bot { ty::mk_bot(tcx) } - ast::ty_box(mt) { - ty::mk_box(tcx, ast_mt_to_mt(tcx, mode, mt)) - } - ast::ty_uniq(mt) { - ty::mk_uniq(tcx, ast_mt_to_mt(tcx, mode, mt)) - } - ast::ty_vec(mt) { - ty::mk_vec(tcx, ast_mt_to_mt(tcx, mode, mt)) - } - ast::ty_ptr(mt) { - ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt)) - } - ast::ty_tup(fields) { - let flds = vec::map(fields, bind ast_ty_to_ty(tcx, mode, _)); - ty::mk_tup(tcx, flds) - } - ast::ty_rec(fields) { - let flds: [field] = []; - for f: ast::ty_field in fields { - let tm = ast_mt_to_mt(tcx, mode, f.node.mt); - flds += [{ident: f.node.ident, mt: tm}]; - } - ty::mk_rec(tcx, flds) - } - ast::ty_fn(proto, decl) { - ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl)) - } - ast::ty_path(path, id) { - let a_def = alt tcx.def_map.find(id) { - none { tcx.sess.span_fatal(ast_ty.span, #fmt("unbound path %s", - path_to_str(path))); } - some(d) { d }}; - alt a_def { - ast::def_ty(id) { - instantiate(tcx, ast_ty.span, mode, id, path.node.types) - } - ast::def_prim_ty(nty) { - alt nty { - ast::ty_bool { ty::mk_bool(tcx) } - ast::ty_int(it) { ty::mk_mach_int(tcx, it) } - ast::ty_uint(uit) { ty::mk_mach_uint(tcx, uit) } - ast::ty_float(ft) { ty::mk_mach_float(tcx, ft) } - ast::ty_str { ty::mk_str(tcx) } - } - } - ast::def_ty_param(id, n) { - if vec::len(path.node.types) > 0u { - tcx.sess.span_err(ast_ty.span, "provided type parameters to \ - a type parameter"); - } - ty::mk_param(tcx, n, id) - } - ast::def_self(iface_id) { - alt check tcx.items.get(iface_id) { - ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) { - if vec::len(tps) != vec::len(path.node.types) { - tcx.sess.span_err(ast_ty.span, "incorrect number of type \ - parameter to self type"); - } - ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty| - ast_ty_to_ty(tcx, mode, ast_ty) - })) - } - } - } - ast::def_class(class_id) { - alt tcx.items.find(class_id.node) { - some(ast_map::node_item( - @{node: ast::item_class(tps, _, _, _, _), _}, _)) { - if vec::len(tps) != vec::len(path.node.types) { - tcx.sess.span_err(ast_ty.span, "incorrect number of \ - type parameters to object type"); - } - ty::mk_class(tcx, class_id, vec::map(path.node.types, - {|ast_ty| ast_ty_to_ty(tcx, mode, ast_ty)})) - } - _ { - tcx.sess.span_bug(ast_ty.span, "class id is unbound \ - in items"); - } - } - } - _ { - tcx.sess.span_fatal(ast_ty.span, - "found type name used as a variable"); - } - } - } - ast::ty_constr(t, cs) { - let out_cs = []; - for constr: @ast::ty_constr in cs { - out_cs += [ty::ast_constr_to_constr(tcx, constr)]; - } - ty::mk_constr(tcx, ast_ty_to_ty(tcx, mode, t), out_cs) - } - ast::ty_infer { - alt mode { - m_check_tyvar(fcx) { ret next_ty_var(fcx); } - _ { tcx.sess.span_bug(ast_ty.span, - "found `ty_infer` in unexpected place"); } - } - } - ast::ty_mac(_) { - tcx.sess.span_bug(ast_ty.span, - "found `ty_mac` in unexpected place"); - } - }; - tcx.ast_ty_to_ty_cache.insert(ast_ty, some(typ)); - ret typ; -} - -fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) - -> ty::ty_param_bounds_and_ty { - let def_id = local_def(it.id); - alt tcx.tcache.find(def_id) { - some(tpt) { ret tpt; } - _ {} - } - alt it.node { - ast::item_const(t, _) { - let typ = ast_ty_to_ty(tcx, mode, t); - let tpt = {bounds: @[], ty: typ}; - tcx.tcache.insert(local_def(it.id), tpt); - ret tpt; - } - ast::item_fn(decl, tps, _) { - ret ty_of_fn(tcx, mode, decl, tps, local_def(it.id)); - } - ast::item_ty(t, tps) { - alt tcx.tcache.find(local_def(it.id)) { - some(tpt) { ret tpt; } - none { } - } - // Tell ast_ty_to_ty() that we want to perform a recursive - // call to resolve any named types. - let tpt = { - let t0 = ast_ty_to_ty(tcx, mode, t); - let t1 = { - // Do not associate a def id with a named, parameterized type - // like "foo<X>". This is because otherwise ty_to_str will - // print the name as merely "foo", as it has no way to - // reconstruct the value of X. - if vec::is_empty(tps) { - ty::mk_with_id(tcx, t0, def_id) - } else { - t0 - } - }; - {bounds: ty_param_bounds(tcx, mode, tps), ty: t1} - }; - tcx.tcache.insert(local_def(it.id), tpt); - ret tpt; - } - ast::item_res(decl, tps, _, _, _) { - let {bounds, params} = mk_ty_params(tcx, tps); - let t_arg = ty_of_arg(tcx, mode, decl.inputs[0]); - let t = { - let t0 = ty::mk_res(tcx, local_def(it.id), t_arg.ty, params); - ty::mk_with_id(tcx, t0, def_id) - }; - let t_res = {bounds: bounds, ty: t}; - tcx.tcache.insert(local_def(it.id), t_res); - ret t_res; - } - ast::item_enum(_, tps) { - // Create a new generic polytype. - let {bounds, params} = mk_ty_params(tcx, tps); - let t = { - let t0 = ty::mk_enum(tcx, local_def(it.id), params); - ty::mk_with_id(tcx, t0, def_id) - }; - let tpt = {bounds: bounds, ty: t}; - tcx.tcache.insert(local_def(it.id), tpt); - ret tpt; - } - ast::item_iface(tps, ms) { - let {bounds, params} = mk_ty_params(tcx, tps); - let t = { - let t0 = ty::mk_iface(tcx, local_def(it.id), params); - ty::mk_with_id(tcx, t0, def_id) - }; - let tpt = {bounds: bounds, ty: t}; - tcx.tcache.insert(local_def(it.id), tpt); - ret tpt; - } - ast::item_class(tps,_,_,_,_) { - let {bounds,params} = mk_ty_params(tcx, tps); - let t = ty::mk_class(tcx, local_def(it.id), params); - let tpt = {bounds: bounds, ty: t}; - tcx.tcache.insert(local_def(it.id), tpt); - ret tpt; - } - ast::item_impl(_, _, _, _) | ast::item_mod(_) | - ast::item_native_mod(_) { fail; } - } -} -fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) - -> ty::ty_param_bounds_and_ty { - alt it.node { - ast::native_item_fn(fn_decl, params) { - ret ty_of_native_fn_decl(tcx, mode, fn_decl, params, - local_def(it.id)); - } - } -} -fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg { - fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode { - alt m { - ast::infer(_) { - alt ty::get(ty).struct { - // If the type is not specified, then this must be a fn expr. - // Leave the mode as infer(_), it will get inferred based - // on constraints elsewhere. - ty::ty_var(_) { m } - - // If the type is known, then use the default for that type. - // Here we unify m and the default. This should update the - // tables in tcx but should never fail, because nothing else - // will have been unified with m yet: - _ { - let m1 = ast::expl(ty::default_arg_mode_for_ty(ty)); - result::get(ty::unify_mode(tcx, m, m1)) - } - } - } - ast::expl(_) { m } - } - } - - let ty = ast_ty_to_ty(tcx, mode, a.ty); - let mode = arg_mode(tcx, a.mode, ty); - {mode: mode, ty: ty} -} -fn ty_of_fn_decl(tcx: ty::ctxt, - mode: mode, - proto: ast::proto, - decl: ast::fn_decl) -> ty::fn_ty { - let input_tys = vec::map(decl.inputs) {|a| ty_of_arg(tcx, mode, a) }; - let output_ty = ast_ty_to_ty(tcx, mode, decl.output); - - let out_constrs = []; - for constr: @ast::constr in decl.constraints { - out_constrs += [ty::ast_constr_to_constr(tcx, constr)]; - } - {proto: proto, inputs: input_tys, - output: output_ty, ret_style: decl.cf, constraints: out_constrs} -} -fn ty_of_fn(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, - ty_params: [ast::ty_param], def_id: ast::def_id) - -> ty::ty_param_bounds_and_ty { - let bounds = ty_param_bounds(tcx, mode, ty_params); - let tofd = ty_of_fn_decl(tcx, mode, ast::proto_bare, decl); - let tpt = {bounds: bounds, ty: ty::mk_fn(tcx, tofd)}; - tcx.tcache.insert(def_id, tpt); - ret tpt; -} -fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, - ty_params: [ast::ty_param], def_id: ast::def_id) - -> ty::ty_param_bounds_and_ty { - let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params); - for a: ast::arg in decl.inputs { - input_tys += [ty_of_arg(tcx, mode, a)]; - } - let output_ty = ast_ty_to_ty(tcx, mode, decl.output); - - let t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare, - inputs: input_tys, - output: output_ty, - ret_style: ast::return_val, - constraints: []}); - let tpt = {bounds: bounds, ty: t_fn}; - tcx.tcache.insert(def_id, tpt); - ret tpt; -} -fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param]) - -> @[ty::param_bounds] { - let result = []; - for param in params { - result += [alt tcx.ty_param_bounds.find(param.id) { - some(bs) { bs } - none { - let bounds = []; - for b in *param.bounds { - bounds += [alt b { - ast::bound_send { ty::bound_send } - ast::bound_copy { ty::bound_copy } - ast::bound_iface(t) { - let ity = ast_ty_to_ty(tcx, mode, t); - alt ty::get(ity).struct { - ty::ty_iface(_, _) {} - _ { - tcx.sess.span_fatal( - t.span, "type parameter bounds must be \ - interface types"); - } - } - ty::bound_iface(ity) - } - }]; - } - let boxed = @bounds; - tcx.ty_param_bounds.insert(param.id, boxed); - boxed - } - }]; - } - @result -} -fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method { - {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), - fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), - purity: m.decl.purity} -} -fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method) - -> ty::method { - {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), - fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), - purity: m.decl.purity} -} - -// A convenience function to use a crate_ctxt to resolve names for -// ast_ty_to_ty. -fn ast_ty_to_ty_crate(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> ty::t { - ret ast_ty_to_ty(ccx.tcx, m_check, ast_ty); -} - -// A wrapper around ast_ty_to_ty_crate that handles ty_infer. -fn ast_ty_to_ty_crate_infer(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> - option<ty::t> { - alt ast_ty.node { - ast::ty_infer { none } - _ { some(ast_ty_to_ty_crate(ccx, ast_ty)) } - } -} - - -// Functions that write types into the node type table -fn write_ty(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) { - smallintmap::insert(*tcx.node_types, node_id as uint, ty); -} -fn write_substs(tcx: ty::ctxt, node_id: ast::node_id, +substs: [ty::t]) { - tcx.node_type_substs.insert(node_id, substs); -} -fn write_ty_substs(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, - +substs: [ty::t]) { - let ty = if ty::type_has_params(ty) { - ty::substitute_type_params(tcx, substs, ty) - } else { ty }; - write_ty(tcx, node_id, ty); - write_substs(tcx, node_id, substs); -} -fn write_nil(tcx: ty::ctxt, node_id: ast::node_id) { - write_ty(tcx, node_id, ty::mk_nil(tcx)); -} -fn write_bot(tcx: ty::ctxt, node_id: ast::node_id) { - write_ty(tcx, node_id, ty::mk_bot(tcx)); -} - -fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param]) - -> {bounds: @[ty::param_bounds], params: [ty::t]} { - let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps); - {bounds: bounds, - params: vec::map(atps, {|atp| - let t = ty::mk_param(tcx, i, local_def(atp.id)); - i += 1u; - t - })} -} - -fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, - impl_tps: uint, if_m: ty::method, substs: [ty::t], - self_ty: ty::t) -> ty::t { - if impl_m.tps != if_m.tps { - tcx.sess.span_err(sp, "method `" + if_m.ident + - "` has an incompatible set of type parameters"); - ty::mk_fn(tcx, impl_m.fty) - } else if vec::len(impl_m.fty.inputs) != vec::len(if_m.fty.inputs) { - tcx.sess.span_err(sp,#fmt["method `%s` has %u parameters \ - but the iface has %u", - if_m.ident, - vec::len(impl_m.fty.inputs), - vec::len(if_m.fty.inputs)]); - ty::mk_fn(tcx, impl_m.fty) - } else { - let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f| - alt ty::get(f.ty).struct { - ty::ty_param(_, _) | ty::ty_self(_) - if alt i.mode { ast::infer(_) { true } _ { false } } { - {mode: ast::expl(ast::by_ref) with i} - } - _ { i } - } - }); - let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty}); - // Add dummy substs for the parameters of the impl method - let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i| - ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0}) - }); - let if_fty = ty::mk_fn(tcx, if_m.fty); - if_fty = ty::substitute_type_params(tcx, substs, if_fty); - if ty::type_has_vars(if_fty) { - if_fty = fixup_self_in_method_ty(tcx, if_fty, substs, - self_full(self_ty, impl_tps)); - } - alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) { - ty::unify::ures_err(err) { - tcx.sess.span_err(sp, "method `" + if_m.ident + - "` has an incompatible type: " + - ty::type_err_to_str(err)); - impl_fty - } - ty::unify::ures_ok(tp) { tp } - } - } -} - -enum self_subst { self_param(ty::t, @fn_ctxt, span), self_full(ty::t, uint) } - -// Mangles an iface method ty to make its self type conform to the self type -// of a specific impl or bounded type parameter. This is rather involved -// because the type parameters of ifaces and impls are not required to line up -// (an impl can have less or more parameters than the iface it implements), so -// some mangling of the substituted types is required. -fn fixup_self_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t], - self: self_subst) -> ty::t { - if ty::type_has_vars(mty) { - ty::fold_ty(cx, ty::fm_general(fn@(t: ty::t) -> ty::t { - alt ty::get(t).struct { - ty::ty_self(tps) { - if vec::len(tps) > 0u { - // Move the substs into the type param system of the - // context. - let substs = vec::map(tps, {|t| - let f = fixup_self_in_method_ty(cx, t, m_substs, - self); - ty::substitute_type_params(cx, m_substs, f) - }); - alt self { - self_param(t, fcx, sp) { - // Simply ensure that the type parameters for the self - // type match the context. - vec::iter2(substs, m_substs) {|s, ms| - demand::simple(fcx, sp, s, ms); - } - t - } - self_full(selfty, impl_n_tps) { - // Add extra substs for impl type parameters. - while vec::len(substs) < impl_n_tps { - substs += [ty::mk_param(cx, vec::len(substs), - {crate: 0, node: 0})]; - } - // And for method type parameters. - let method_n_tps = - (vec::len(m_substs) - vec::len(tps)) as int; - if method_n_tps > 0 { - substs += vec::tail_n(m_substs, vec::len(m_substs) - - (method_n_tps as uint)); - } - // And then instantiate the self type using all those. - ty::substitute_type_params(cx, substs, selfty) - } - } - } else { - alt self { self_param(t, _, _) | self_full(t, _) { t } } - } - } - _ { t } - } - }), mty) - } else { mty } -} - -// Item collection - a pair of bootstrap passes: -// -// (1) Collect the IDs of all type items (typedefs) and store them in a table. -// -// (2) Translate the AST fragments that describe types to determine a type for -// each item. When we encounter a named type, we consult the table built -// in pass 1 to find its item, and recursively translate it. -// -// We then annotate the AST with the resulting types and return the annotated -// AST, along with a table mapping item IDs to their types. -mod collect { - fn get_enum_variant_types(tcx: ty::ctxt, enum_ty: ty::t, - variants: [ast::variant], - ty_params: [ast::ty_param]) { - // Create a set of parameter types shared among all the variants. - for variant in variants { - // Nullary enum constructors get turned into constants; n-ary enum - // constructors get turned into functions. - let result_ty = if vec::len(variant.node.args) == 0u { - enum_ty - } else { - // As above, tell ast_ty_to_ty() that trans_ty_item_to_ty() - // should be called to resolve named types. - let args: [arg] = []; - for va: ast::variant_arg in variant.node.args { - let arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty); - args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}]; - } - // FIXME: this will be different for constrained types - ty::mk_fn(tcx, - {proto: ast::proto_box, - inputs: args, output: enum_ty, - ret_style: ast::return_val, constraints: []}) - }; - let tpt = {bounds: ty_param_bounds(tcx, m_collect, ty_params), - ty: result_ty}; - tcx.tcache.insert(local_def(variant.node.id), tpt); - write_ty(tcx, variant.node.id, result_ty); - } - } - fn ensure_iface_methods(tcx: ty::ctxt, id: ast::node_id) { - alt check tcx.items.get(id) { - ast_map::node_item(@{node: ast::item_iface(_, ms), _}, _) { - ty::store_iface_methods(tcx, id, @vec::map(ms, {|m| - ty_of_ty_method(tcx, m_collect, m) - })); - } - } - } - fn convert_class_item(tcx: ty::ctxt, ci: ast::class_member) { - /* we want to do something here, b/c within the - scope of the class, it's ok to refer to fields & - methods unqualified */ - - /* they have these types *within the scope* of the - class. outside the class, it's done with expr_field */ - alt ci { - ast::instance_var(_,t,_,id) { - let tt = ast_ty_to_ty(tcx, m_collect, t); - write_ty(tcx, id, tt); - } - ast::class_method(it) { convert(tcx, it); } - } - } - fn convert(tcx: ty::ctxt, it: @ast::item) { - alt it.node { - // These don't define types. - ast::item_mod(_) | ast::item_native_mod(_) {} - ast::item_enum(variants, ty_params) { - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); - get_enum_variant_types(tcx, tpt.ty, variants, ty_params); - } - ast::item_impl(tps, ifce, selfty, ms) { - let i_bounds = ty_param_bounds(tcx, m_collect, tps); - let my_methods = []; - for m in ms { - let bounds = ty_param_bounds(tcx, m_collect, m.tps); - let mty = ty_of_method(tcx, m_collect, m); - my_methods += [{mty: mty, id: m.id, span: m.span}]; - let fty = ty::mk_fn(tcx, mty.fty); - tcx.tcache.insert(local_def(m.id), - {bounds: @(*i_bounds + *bounds), - ty: fty}); - write_ty(tcx, m.id, fty); - } - let selfty = ast_ty_to_ty(tcx, m_collect, selfty); - write_ty(tcx, it.id, selfty); - alt ifce { - some(t) { - let iface_ty = ast_ty_to_ty(tcx, m_collect, t); - tcx.tcache.insert(local_def(it.id), - {bounds: i_bounds, ty: iface_ty}); - alt ty::get(iface_ty).struct { - ty::ty_iface(did, tys) { - if did.crate == ast::local_crate { - ensure_iface_methods(tcx, did.node); - } - for if_m in *ty::iface_methods(tcx, did) { - alt vec::find(my_methods, - {|m| if_m.ident == m.mty.ident}) { - some({mty: m, id, span}) { - if m.purity != if_m.purity { - tcx.sess.span_err( - span, "method `" + m.ident + "`'s purity \ - not match the iface method's \ - purity"); - } - let mt = compare_impl_method( - tcx, span, m, vec::len(tps), if_m, tys, - selfty); - let old = tcx.tcache.get(local_def(id)); - if old.ty != mt { - tcx.tcache.insert(local_def(id), - {bounds: old.bounds, - ty: mt}); - write_ty(tcx, id, mt); - } - } - none { - tcx.sess.span_err(t.span, "missing method `" + - if_m.ident + "`"); - } - } - } - } - _ { - tcx.sess.span_fatal(t.span, "can only implement \ - interface types"); - } - } - } - _ {} - } - } - ast::item_res(decl, tps, _, dtor_id, ctor_id) { - let {bounds, params} = mk_ty_params(tcx, tps); - let def_id = local_def(it.id); - let t_arg = ty_of_arg(tcx, m_collect, decl.inputs[0]); - let t_res = ty::mk_res(tcx, def_id, t_arg.ty, params); - let t_res = ty::mk_with_id(tcx, t_res, def_id); - let t_ctor = ty::mk_fn(tcx, { - proto: ast::proto_box, - inputs: [{mode: ast::expl(ast::by_copy) with t_arg}], - output: t_res, - ret_style: ast::return_val, constraints: [] - }); - let t_dtor = ty::mk_fn(tcx, { - proto: ast::proto_box, - inputs: [t_arg], output: ty::mk_nil(tcx), - ret_style: ast::return_val, constraints: [] - }); - write_ty(tcx, it.id, t_res); - write_ty(tcx, ctor_id, t_ctor); - tcx.tcache.insert(local_def(ctor_id), - {bounds: bounds, ty: t_ctor}); - tcx.tcache.insert(def_id, {bounds: bounds, ty: t_res}); - write_ty(tcx, dtor_id, t_dtor); - } - ast::item_iface(_, ms) { - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); - ensure_iface_methods(tcx, it.id); - } - ast::item_class(tps, members, ctor_id, ctor_decl, ctor_block) { - // Write the class type - let {bounds,params} = mk_ty_params(tcx, tps); - let class_ty = ty::mk_class(tcx, local_def(it.id), params); - let tpt = {bounds: bounds, ty: class_ty}; - tcx.tcache.insert(local_def(it.id), tpt); - write_ty(tcx, it.id, class_ty); - // Write the ctor type - let t_ctor = ty::mk_fn(tcx, - ty_of_fn_decl(tcx, m_collect, - ast::proto_any, ctor_decl)); - write_ty(tcx, ctor_id, t_ctor); - tcx.tcache.insert(local_def(ctor_id), - {bounds: bounds, ty: t_ctor}); - /* FIXME: check for proper public/privateness */ - // Write the type of each of the members - for m in members { - convert_class_item(tcx, m.node.decl); - } - } - _ { - // This call populates the type cache with the converted type - // of the item in passing. All we have to do here is to write - // it into the node type table. - let tpt = ty_of_item(tcx, m_collect, it); - write_ty(tcx, it.id, tpt.ty); - } - } - } - fn convert_native(tcx: ty::ctxt, i: @ast::native_item) { - // As above, this call populates the type table with the converted - // type of the native item. We simply write it into the node type - // table. - let tpt = ty_of_native_item(tcx, m_collect, i); - alt i.node { - ast::native_item_fn(_, _) { write_ty(tcx, i.id, tpt.ty); } - } - } - fn collect_item_types(tcx: ty::ctxt, crate: @ast::crate) { - visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{ - visit_item: bind convert(tcx, _), - visit_native_item: bind convert_native(tcx, _) - with *visit::default_simple_visitor() - })); - } -} - - -// Type unification -mod unify { - fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> - ty::unify::result { - ret ty::unify::unify(expected, actual, - ty::unify::in_bindings(fcx.var_bindings), - fcx.ccx.tcx); - } -} - - -// FIXME This is almost a duplicate of ty::type_autoderef, with structure_of -// instead of ty::struct. -fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t { - let t1 = t; - while true { - alt structure_of(fcx, sp, t1) { - ty::ty_box(inner) | ty::ty_uniq(inner) { - alt ty::get(t1).struct { - ty::ty_var(v1) { - if ty::occurs_check_fails(fcx.ccx.tcx, some(sp), v1, - ty::mk_box(fcx.ccx.tcx, inner)) { - break; - } - } - _ { } - } - t1 = inner.ty; - } - ty::ty_res(_, inner, tps) { - t1 = ty::substitute_type_params(fcx.ccx.tcx, tps, inner); - } - ty::ty_enum(did, tps) { - let variants = ty::enum_variants(fcx.ccx.tcx, did); - if vec::len(*variants) != 1u || vec::len(variants[0].args) != 1u { - ret t1; - } - t1 = - ty::substitute_type_params(fcx.ccx.tcx, tps, - variants[0].args[0]); - } - _ { ret t1; } - } - } - fail; -} - -fn resolve_type_vars_if_possible(fcx: @fn_ctxt, typ: ty::t) -> ty::t { - alt ty::unify::fixup_vars(fcx.ccx.tcx, none, fcx.var_bindings, typ) { - fix_ok(new_type) { ret new_type; } - fix_err(_) { ret typ; } - } -} - - -// Demands - procedures that require that two types unify and emit an error -// message if they don't. -type ty_param_substs_and_ty = {substs: [ty::t], ty: ty::t}; - -mod demand { - fn simple(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) -> - ty::t { - full(fcx, sp, expected, actual, []).ty - } - - fn with_substs(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t, - ty_param_substs_0: [ty::t]) -> ty_param_substs_and_ty { - full(fcx, sp, expected, actual, ty_param_substs_0) - } - - // 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(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t, - ty_param_substs_0: [ty::t]) -> - ty_param_substs_and_ty { - - let ty_param_substs: [mutable ty::t] = [mutable]; - let ty_param_subst_var_ids: [int] = []; - for ty_param_subst: ty::t in ty_param_substs_0 { - // Generate a type variable and unify it with the type parameter - // substitution. We will then pull out these type variables. - let t_0 = next_ty_var(fcx); - ty_param_substs += [mutable t_0]; - ty_param_subst_var_ids += [ty::ty_var_id(t_0)]; - simple(fcx, sp, ty_param_subst, t_0); - } - - fn mk_result(fcx: @fn_ctxt, result_ty: ty::t, - ty_param_subst_var_ids: [int]) -> - ty_param_substs_and_ty { - let result_ty_param_substs: [ty::t] = []; - for var_id: int in ty_param_subst_var_ids { - let tp_subst = ty::mk_var(fcx.ccx.tcx, var_id); - result_ty_param_substs += [tp_subst]; - } - ret {substs: result_ty_param_substs, ty: result_ty}; - } - - - alt unify::unify(fcx, expected, actual) { - ures_ok(t) { ret mk_result(fcx, t, ty_param_subst_var_ids); } - ures_err(err) { - let e_err = resolve_type_vars_if_possible(fcx, expected); - let a_err = resolve_type_vars_if_possible(fcx, actual); - fcx.ccx.tcx.sess.span_err(sp, - "mismatched types: expected `" + - ty_to_str(fcx.ccx.tcx, e_err) + - "` but found `" + - ty_to_str(fcx.ccx.tcx, a_err) + - "` (" + ty::type_err_to_str(err) + - ")"); - ret mk_result(fcx, expected, ty_param_subst_var_ids); - } - } - } -} - - -// Returns true if the two types unify and false if they don't. -fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool { - alt unify::unify(fcx, expected, actual) { - ures_ok(_) { ret true; } - ures_err(_) { ret false; } - } -} - - -// Returns the types of the arguments to a enum variant. -fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, - enum_ty_params: [ty::t]) -> [ty::t] { - let result: [ty::t] = []; - let tpt = ty::lookup_item_type(ccx.tcx, vid); - alt ty::get(tpt.ty).struct { - ty::ty_fn(f) { - // N-ary variant. - for arg: ty::arg in f.inputs { - let arg_ty = - ty::substitute_type_params(ccx.tcx, enum_ty_params, arg.ty); - result += [arg_ty]; - } - } - _ { - // Nullary variant. Do nothing, as there are no arguments. - } - } - /* result is a vector of the *expected* types of all the fields */ - - ret result; -} - - -// Type resolution: the phase that finds all the types in the AST with -// unresolved type variables and replaces "ty_var" types with their -// substitutions. -mod writeback { - - export resolve_type_vars_in_block; - export resolve_type_vars_in_expr; - - fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) -> - option<ty::t> { - if !ty::type_has_vars(typ) { ret some(typ); } - alt ty::unify::fixup_vars(fcx.ccx.tcx, some(sp), fcx.var_bindings, - typ) { - fix_ok(new_type) { ret some(new_type); } - fix_err(vid) { - if !fcx.ccx.tcx.sess.has_errors() { - fcx.ccx.tcx.sess.span_err(sp, "cannot determine a type \ - for this expression"); - } - ret none; - } - } - } - fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) - -> option<ty::t> { - let fcx = wbcx.fcx, tcx = fcx.ccx.tcx; - alt resolve_type_vars_in_type(fcx, sp, ty::node_id_to_type(tcx, id)) { - none { - wbcx.success = false; - ret none; - } - - some(t) { - write_ty(tcx, id, t); - alt tcx.node_type_substs.find(id) { - some(substs) { - let new_substs = []; - for subst: ty::t in substs { - alt resolve_type_vars_in_type(fcx, sp, subst) { - some(t) { new_substs += [t]; } - none { wbcx.success = false; ret none; } - } - } - write_substs(tcx, id, new_substs); - } - none {} - } - ret some(t); - } - } - } - - type wb_ctxt = - // As soon as we hit an error we have to stop resolving - // the entire function - {fcx: @fn_ctxt, mutable success: bool}; - type wb_vt = visit::vt<wb_ctxt>; - - fn visit_stmt(s: @ast::stmt, wbcx: wb_ctxt, v: wb_vt) { - if !wbcx.success { ret; } - resolve_type_vars_for_node(wbcx, s.span, ty::stmt_node_id(s)); - visit::visit_stmt(s, wbcx, v); - } - fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) { - if !wbcx.success { ret; } - resolve_type_vars_for_node(wbcx, e.span, e.id); - alt e.node { - ast::expr_fn(_, decl, _, _) | - ast::expr_fn_block(decl, _) { - vec::iter(decl.inputs) {|input| - let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id); - - // Just in case we never constrained the mode to anything, - // constrain it to the default for the type in question. - alt (r_ty, input.mode) { - (some(t), ast::infer(_)) { - let tcx = wbcx.fcx.ccx.tcx; - let m_def = ty::default_arg_mode_for_ty(t); - ty::set_default_mode(tcx, input.mode, m_def); - } - _ {} - } - } - } - _ { } - } - visit::visit_expr(e, wbcx, v); - } - fn visit_block(b: ast::blk, wbcx: wb_ctxt, v: wb_vt) { - if !wbcx.success { ret; } - resolve_type_vars_for_node(wbcx, b.span, b.node.id); - visit::visit_block(b, wbcx, v); - } - fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) { - if !wbcx.success { ret; } - resolve_type_vars_for_node(wbcx, p.span, p.id); - visit::visit_pat(p, wbcx, v); - } - fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) { - if !wbcx.success { ret; } - let var_id = lookup_local(wbcx.fcx, l.span, l.node.id); - let fix_rslt = - ty::unify::resolve_type_var(wbcx.fcx.ccx.tcx, some(l.span), - wbcx.fcx.var_bindings, var_id); - alt fix_rslt { - fix_ok(lty) { write_ty(wbcx.fcx.ccx.tcx, l.node.id, lty); } - fix_err(_) { - wbcx.fcx.ccx.tcx.sess.span_err(l.span, - "cannot determine a type \ - for this local variable"); - wbcx.success = false; - } - } - visit::visit_local(l, wbcx, v); - } - fn visit_item(_item: @ast::item, _wbcx: wb_ctxt, _v: wb_vt) { - // Ignore items - } - - fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool { - let wbcx = {fcx: fcx, mutable success: true}; - let visit = - visit::mk_vt(@{visit_item: visit_item, - visit_stmt: visit_stmt, - visit_expr: visit_expr, - visit_block: visit_block, - visit_pat: visit_pat, - visit_local: visit_local - with *visit::default_visitor()}); - visit::visit_expr(e, wbcx, visit); - ret wbcx.success; - } - - fn resolve_type_vars_in_block(fcx: @fn_ctxt, blk: ast::blk) -> bool { - let wbcx = {fcx: fcx, mutable success: true}; - let visit = - visit::mk_vt(@{visit_item: visit_item, - visit_stmt: visit_stmt, - visit_expr: visit_expr, - visit_block: visit_block, - visit_pat: visit_pat, - visit_local: visit_local - with *visit::default_visitor()}); - visit.visit_block(blk, wbcx, visit); - ret wbcx.success; - } -} - - -// Local variable gathering. We gather up all locals and create variable IDs -// for them before typechecking the function. -type gather_result = - {var_bindings: @ty::unify::var_bindings, - locals: hashmap<ast::node_id, int>, - next_var_id: @mutable int}; - -// Used only as a helper for check_fn. -fn gather_locals(ccx: @crate_ctxt, - decl: ast::fn_decl, - body: ast::blk, - id: ast::node_id, - old_fcx: option<@fn_ctxt>) -> gather_result { - let {vb: vb, locals: locals, nvi: nvi} = alt old_fcx { - none { - {vb: ty::unify::mk_var_bindings(), - locals: new_int_hash::<int>(), - nvi: @mutable 0} - } - some(fcx) { - {vb: fcx.var_bindings, - locals: fcx.locals, - nvi: fcx.next_var_id} - } - }; - let tcx = ccx.tcx; - - let next_var_id = fn@() -> int { let rv = *nvi; *nvi += 1; ret rv; }; - - let assign = fn@(nid: ast::node_id, ty_opt: option<ty::t>) { - let var_id = next_var_id(); - locals.insert(nid, var_id); - alt ty_opt { - none {/* nothing to do */ } - some(typ) { - ty::unify::unify(ty::mk_var(tcx, var_id), typ, - ty::unify::in_bindings(vb), tcx); - } - } - }; - - // Add formal parameters. - let args = ty::ty_fn_args(ty::node_id_to_type(ccx.tcx, id)); - let i = 0u; - for arg: ty::arg in args { - assign(decl.inputs[i].id, some(arg.ty)); - i += 1u; - } - - // Add explicitly-declared locals. - let visit_local = fn@(local: @ast::local, &&e: (), v: visit::vt<()>) { - let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty); - assign(local.node.id, local_ty); - visit::visit_local(local, e, v); - }; - - // Add pattern bindings. - let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) { - alt p.node { - ast::pat_ident(_, _) - if !pat_util::pat_is_variant(ccx.tcx.def_map, p) { - assign(p.id, none); - } - _ {} - } - visit::visit_pat(p, e, v); - }; - - // Don't descend into fns and items - fn visit_fn<T>(_fk: visit::fn_kind, _decl: ast::fn_decl, _body: ast::blk, - _sp: span, _id: ast::node_id, _t: T, _v: visit::vt<T>) { - } - fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { } - - let visit = - @{visit_local: visit_local, - visit_pat: visit_pat, - visit_fn: bind visit_fn(_, _, _, _, _, _, _), - visit_item: bind visit_item(_, _, _) - with *visit::default_visitor()}; - - visit::visit_block(body, (), visit::mk_vt(visit)); - ret {var_bindings: vb, - locals: locals, - next_var_id: nvi}; -} - -// AST fragment checking -fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t { - alt lit.node { - ast::lit_str(_) { ty::mk_str(ccx.tcx) } - ast::lit_int(_, t) { ty::mk_mach_int(ccx.tcx, t) } - ast::lit_uint(_, t) { ty::mk_mach_uint(ccx.tcx, t) } - ast::lit_float(_, t) { ty::mk_mach_float(ccx.tcx, t) } - ast::lit_nil { ty::mk_nil(ccx.tcx) } - ast::lit_bool(_) { ty::mk_bool(ccx.tcx) } - } -} - -fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool { - ast_util::compare_lit_exprs(from, to) <= 0 -} - -fn check_pat_variant(fcx: @fn_ctxt, map: pat_util::pat_id_map, - pat: @ast::pat, path: @ast::path, subpats: [@ast::pat], - expected: ty::t) { - // Typecheck the path. - let tcx = fcx.ccx.tcx; - let v_def = lookup_def(fcx, path.span, pat.id); - let v_def_ids = ast_util::variant_def_ids(v_def); - let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.enm); - instantiate_path(fcx, path, ctor_tpt, pat.span, pat.id); - - // Take the enum type params out of `expected`. - alt structure_of(fcx, pat.span, expected) { - ty::ty_enum(_, expected_tps) { - let ctor_ty = ty::node_id_to_type(tcx, pat.id); - demand::with_substs(fcx, pat.span, expected, ctor_ty, - expected_tps); - // Get the number of arguments in this enum variant. - let arg_types = variant_arg_types(fcx.ccx, pat.span, - v_def_ids.var, expected_tps); - let subpats_len = subpats.len(), arg_len = arg_types.len(); - if arg_len > 0u { - // N-ary variant. - if arg_len != subpats_len { - let s = #fmt["this pattern has %u field%s, but the \ - corresponding variant has %u field%s", - subpats_len, - if subpats_len == 1u { "" } else { "s" }, - arg_len, - if arg_len == 1u { "" } else { "s" }]; - tcx.sess.span_err(pat.span, s); - } - - vec::iter2(subpats, arg_types) {|subpat, arg_ty| - check_pat(fcx, map, subpat, arg_ty); - } - } else if subpats_len > 0u { - 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 == 1u { "" } - else { "s" }]); - } - } - _ { - tcx.sess.span_err - (pat.span, - #fmt["mismatched types: expected enum but found `%s`", - ty_to_str(tcx, expected)]); - } - } -} - -// Pattern checking is top-down rather than bottom-up so that bindings get -// their types immediately. -fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat, - expected: ty::t) { - let tcx = fcx.ccx.tcx; - alt pat.node { - ast::pat_wild { - alt structure_of(fcx, pat.span, expected) { - ty::ty_enum(_, expected_tps) { - write_ty_substs(tcx, pat.id, expected, - expected_tps); - } - _ { - write_ty(tcx, pat.id, expected); - } - } - } - ast::pat_lit(lt) { - check_expr_with(fcx, lt, expected); - write_ty(tcx, pat.id, expr_ty(tcx, lt)); - } - ast::pat_range(begin, end) { - check_expr_with(fcx, begin, expected); - check_expr_with(fcx, end, expected); - let b_ty = resolve_type_vars_if_possible(fcx, expr_ty(tcx, begin)); - if !ty::same_type(tcx, b_ty, resolve_type_vars_if_possible( - fcx, expr_ty(tcx, end))) { - tcx.sess.span_err(pat.span, "mismatched types in range"); - } else if !ty::type_is_numeric(b_ty) { - tcx.sess.span_err(pat.span, "non-numeric type used in range"); - } else if !valid_range_bounds(begin, end) { - tcx.sess.span_err(begin.span, "lower range bound must be less \ - than upper"); - } - write_ty(tcx, pat.id, b_ty); - } - ast::pat_ident(name, sub) - if !pat_util::pat_is_variant(tcx.def_map, pat) { - let vid = lookup_local(fcx, pat.span, pat.id); - let typ = ty::mk_var(tcx, vid); - typ = demand::simple(fcx, pat.span, expected, typ); - let canon_id = map.get(path_to_ident(name)); - if canon_id != pat.id { - let ct = ty::mk_var(tcx, lookup_local(fcx, pat.span, canon_id)); - typ = demand::simple(fcx, pat.span, ct, typ); - } - write_ty(tcx, pat.id, typ); - alt sub { - some(p) { check_pat(fcx, map, p, expected); } - _ {} - } - } - ast::pat_ident(path, _) { - check_pat_variant(fcx, map, pat, path, [], expected); - } - ast::pat_enum(path, subpats) { - check_pat_variant(fcx, map, pat, path, subpats, expected); - } - ast::pat_rec(fields, etc) { - let ex_fields; - alt structure_of(fcx, pat.span, expected) { - ty::ty_rec(fields) { ex_fields = fields; } - _ { - tcx.sess.span_fatal - (pat.span, - #fmt["mismatched types: expected `%s` but found record", - ty_to_str(tcx, expected)]); - } - } - let f_count = vec::len(fields); - let ex_f_count = vec::len(ex_fields); - if ex_f_count < f_count || !etc && ex_f_count > f_count { - tcx.sess.span_fatal - (pat.span, #fmt["mismatched types: expected a record \ - with %u fields, found one with %u \ - fields", - ex_f_count, f_count]); - } - fn matches(name: str, f: ty::field) -> bool { - ret str::eq(name, f.ident); - } - for f: ast::field_pat in fields { - alt vec::find(ex_fields, bind matches(f.ident, _)) { - some(field) { check_pat(fcx, map, f.pat, field.mt.ty); } - none { - tcx.sess.span_fatal(pat.span, - #fmt["mismatched types: did not \ - expect a record with a field `%s`", - f.ident]); - } - } - } - write_ty(tcx, pat.id, expected); - } - ast::pat_tup(elts) { - let ex_elts; - alt structure_of(fcx, pat.span, expected) { - ty::ty_tup(elts) { ex_elts = elts; } - _ { - tcx.sess.span_fatal - (pat.span, - #fmt["mismatched types: expected `%s`, found tuple", - ty_to_str(tcx, expected)]); - } - } - let e_count = vec::len(elts); - if e_count != vec::len(ex_elts) { - tcx.sess.span_fatal - (pat.span, #fmt["mismatched types: expected a tuple \ - with %u fields, found one with %u \ - fields", vec::len(ex_elts), e_count]); - } - let i = 0u; - for elt in elts { check_pat(fcx, map, elt, ex_elts[i]); i += 1u; } - write_ty(tcx, pat.id, expected); - } - ast::pat_box(inner) { - alt structure_of(fcx, pat.span, expected) { - ty::ty_box(e_inner) { - check_pat(fcx, map, inner, e_inner.ty); - write_ty(tcx, pat.id, expected); - } - _ { - tcx.sess.span_fatal(pat.span, - "mismatched types: expected `" + - ty_to_str(tcx, expected) + - "` found box"); - } - } - } - ast::pat_uniq(inner) { - alt structure_of(fcx, pat.span, expected) { - ty::ty_uniq(e_inner) { - check_pat(fcx, map, inner, e_inner.ty); - write_ty(tcx, pat.id, expected); - } - _ { - tcx.sess.span_fatal(pat.span, - "mismatched types: expected `" + - ty_to_str(tcx, expected) + - "` found uniq"); - } - } - } - } -} - -fn require_unsafe(sess: session, f_purity: ast::purity, sp: span) { - alt f_purity { - ast::unsafe_fn { ret; } - _ { - sess.span_err( - sp, - "unsafe operation requires unsafe function or block"); - } - } -} - -fn require_impure(sess: session, f_purity: ast::purity, sp: span) { - alt f_purity { - ast::unsafe_fn { ret; } - ast::impure_fn | ast::crust_fn { ret; } - ast::pure_fn { - sess.span_err(sp, "Found impure expression in pure function decl"); - } - } -} - -fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity, - callee: @ast::expr, sp: span) { - if caller_purity == ast::unsafe_fn { ret; } - let callee_purity = alt ccx.tcx.def_map.find(callee.id) { - some(ast::def_fn(_, p)) { p } - some(ast::def_variant(_, _)) { ast::pure_fn } - _ { - alt ccx.method_map.find(callee.id) { - some(method_static(did)) { - if did.crate == ast::local_crate { - alt check ccx.tcx.items.get(did.node) { - ast_map::node_method(m, _, _) { m.decl.purity } - } - } else { - csearch::lookup_method_purity(ccx.tcx.sess.cstore, did) - } - } - some(method_param(iid, n_m, _, _)) | some(method_iface(iid, n_m)) { - ty::iface_methods(ccx.tcx, iid)[n_m].purity - } - none { ast::impure_fn } - } - } - }; - alt (caller_purity, callee_purity) { - (ast::impure_fn, ast::unsafe_fn) | (ast::crust_fn, ast::unsafe_fn) { - ccx.tcx.sess.span_err(sp, "safe function calls function marked \ - unsafe"); - } - (ast::pure_fn, ast::unsafe_fn) | (ast::pure_fn, ast::impure_fn) { - ccx.tcx.sess.span_err(sp, "pure function calls function not \ - known to be pure"); - } - _ {} - } -} - -type unifier = fn@(@fn_ctxt, span, ty::t, ty::t) -> ty::t; - -fn check_expr(fcx: @fn_ctxt, expr: @ast::expr) -> bool { - fn dummy_unify(_fcx: @fn_ctxt, _sp: span, _expected: ty::t, actual: ty::t) - -> ty::t { - actual - } - ret check_expr_with_unifier(fcx, expr, dummy_unify, - ty::mk_nil(fcx.ccx.tcx)); -} -fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { - ret check_expr_with_unifier(fcx, expr, demand::simple, expected); -} - -fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} { - if did.crate == ast::local_crate { - alt check tcx.items.get(did.node) { - ast_map::node_item(@{node: ast::item_impl(ts, _, st, _), - _}, _) { - {n_tps: vec::len(ts), ty: ast_ty_to_ty(tcx, m_check, st)} - } - } - } else { - let tpt = csearch::get_type(tcx, did); - {n_tps: vec::len(*tpt.bounds), ty: tpt.ty} - } -} - -fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id, - name: ast::ident, ty: ty::t, tps: [ty::t]) - -> option::t<method_origin> { - alt lookup_method_inner(fcx, expr, name, ty) { - some({method_ty: fty, n_tps: method_n_tps, substs, origin, self_sub}) { - let tcx = fcx.ccx.tcx; - let substs = substs, n_tps = vec::len(substs), n_tys = vec::len(tps); - let has_self = ty::type_has_params(fty); - if method_n_tps + n_tps > 0u { - if n_tys == 0u || n_tys != method_n_tps { - if n_tys != 0u { - tcx.sess.span_err - (expr.span, "incorrect number of type \ - parameters given for this method"); - - } - substs += vec::init_fn(method_n_tps, {|_i| - ty::mk_var(tcx, next_ty_var_id(fcx)) - }); - } else { - substs += tps; - } - write_ty_substs(tcx, node_id, fty, substs); - } else { - if n_tys > 0u { - tcx.sess.span_err(expr.span, "this method does not take type \ - parameters"); - } - write_ty(tcx, node_id, fty); - } - if has_self && !option::is_none(self_sub) { - let fty = ty::node_id_to_type(tcx, node_id); - fty = fixup_self_in_method_ty( - tcx, fty, substs, option::get(self_sub)); - write_ty(tcx, node_id, fty); - } - some(origin) - } - none { none } - } -} - -fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr, - name: ast::ident, ty: ty::t) - -> option::t<{method_ty: ty::t, n_tps: uint, substs: [ty::t], - origin: method_origin, - self_sub: option::t<self_subst>}> { - let tcx = fcx.ccx.tcx; - // First, see whether this is an interface-bounded parameter - alt ty::get(ty).struct { - ty::ty_param(n, did) { - let bound_n = 0u; - for bound in *tcx.ty_param_bounds.get(did.node) { - alt bound { - ty::bound_iface(t) { - let (iid, tps) = alt check ty::get(t).struct { - ty::ty_iface(i, tps) { (i, tps) } - }; - let ifce_methods = ty::iface_methods(tcx, iid); - alt vec::position(*ifce_methods, {|m| m.ident == name}) { - some(pos) { - let m = ifce_methods[pos]; - ret some({method_ty: ty::mk_fn(tcx, {proto: ast::proto_box - with m.fty}), - n_tps: vec::len(*m.tps), - substs: tps, - origin: method_param(iid, pos, n, bound_n), - self_sub: some(self_param(ty, fcx, expr.span)) - }); - } - _ {} - } - bound_n += 1u; - } - _ {} - } - } - } - ty::ty_iface(did, tps) { - let i = 0u; - for m in *ty::iface_methods(tcx, did) { - if m.ident == name { - let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty}); - if ty::type_has_vars(fty) { - tcx.sess.span_fatal( - expr.span, "can not call a method that contains a \ - self type through a boxed iface"); - } - ret some({method_ty: fty, - n_tps: vec::len(*m.tps), - substs: tps, - origin: method_iface(did, i), - self_sub: none}); - } - i += 1u; - } - } - _ {} - } - - fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t { - if did.crate == ast::local_crate { - alt check tcx.items.get(did.node) { - ast_map::node_method(m, _, _) { - let mt = ty_of_method(tcx, m_check, m); - ty::mk_fn(tcx, {proto: ast::proto_box with mt.fty}) - } - } - } else { - alt check ty::get(csearch::get_type(tcx, did).ty).struct { - ty::ty_fn(fty) { - ty::mk_fn(tcx, {proto: ast::proto_box with fty}) - } - } - } - } - - let result = none, complained = false; - std::list::iter(fcx.ccx.impl_map.get(expr.id)) {|impls| - if option::is_some(result) { ret; } - for @{did, methods, _} in *impls { - alt vec::find(methods, {|m| m.ident == name}) { - some(m) { - let {n_tps, ty: self_ty} = impl_self_ty(tcx, did); - let {vars, ty: self_ty} = if n_tps > 0u { - bind_params(fcx, self_ty, n_tps) - } else { {vars: [], ty: self_ty} }; - alt unify::unify(fcx, ty, self_ty) { - ures_ok(_) { - if option::is_some(result) { - // FIXME[impl] score specificity to resolve ambiguity? - if !complained { - tcx.sess.span_err(expr.span, "multiple applicable \ - methods in scope"); - complained = true; - } - } else { - result = some({ - method_ty: ty_from_did(tcx, m.did), - n_tps: m.n_tps, - substs: vars, - origin: method_static(m.did), - self_sub: none - }); - } - } - _ {} - } - } - _ {} - } - } - } - result -} - -fn lookup_field_ty(cx: ty::ctxt, items:[@ast::class_item], - fieldname: ast::ident, sp: span) - -> ty::t { - for item in items { - // this is an access outside the class, so accessing a private - // field is an error - alt item.node.decl { - ast::instance_var(declname, t, _, _) if declname == fieldname { - alt item.node.privacy { - ast::priv { - cx.sess.span_fatal(sp, "Accessed private field outside \ - its enclosing class"); - } - ast::pub { - ret ast_ty_to_ty(cx, m_check, t); - } - } - } - _ { /* do nothing */ } - } - } - cx.sess.span_fatal(sp, #fmt("Unbound field %s", fieldname)); -} - -fn check_expr_fn_with_unifier(fcx: @fn_ctxt, - expr: @ast::expr, - proto: ast::proto, - decl: ast::fn_decl, - body: ast::blk, - unify: unifier, - expected: ty::t) { - let tcx = fcx.ccx.tcx; - let fty = ty::mk_fn(tcx, - ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl)); - - #debug("check_expr_fn_with_unifier %s fty=%s", - expr_to_str(expr), - ty_to_str(tcx, fty)); - - write_ty(tcx, expr.id, fty); - - // Unify the type of the function with the expected type before we - // typecheck the body so that we have more information about the - // argument types in the body. This is needed to make binops and - // record projection work on type inferred arguments. - unify(fcx, expr.span, expected, fty); - - check_fn(fcx.ccx, proto, decl, body, expr.id, some(fcx)); -} - -fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, - expected: ty::t) -> bool { - #debug("typechecking expr %s", - syntax::print::pprust::expr_to_str(expr)); - - // A generic function to factor out common logic from call and bind - // expressions. - fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t, - args: [option<@ast::expr>]) -> bool { - let sty = structure_of(fcx, sp, fty); - // Grab the argument types - let arg_tys = alt sty { - ty::ty_fn({inputs: arg_tys, _}) { arg_tys } - _ { - fcx.ccx.tcx.sess.span_fatal(sp, "mismatched types: \ - expected function or native \ - function but found " - + ty_to_str(fcx.ccx.tcx, fty)) - } - }; - - // Check that the correct number of arguments were supplied. - let expected_arg_count = vec::len(arg_tys); - let supplied_arg_count = vec::len(args); - if expected_arg_count != supplied_arg_count { - fcx.ccx.tcx.sess.span_err( - sp, #fmt["this function takes %u parameter%s but %u \ - parameter%s supplied", expected_arg_count, - if expected_arg_count == 1u { - "" - } else { - "s" - }, - supplied_arg_count, - if supplied_arg_count == 1u { - " was" - } else { - "s were" - }]); - // HACK: build an arguments list with dummy arguments to - // check against - let dummy = {mode: ast::expl(ast::by_ref), - ty: ty::mk_bot(fcx.ccx.tcx)}; - arg_tys = vec::init_elt(supplied_arg_count, dummy); - } - - // Check the arguments. - // We do this in a pretty awful way: first we typecheck any arguments - // that are not anonymous functions, then we typecheck the anonymous - // functions. This is so that we have more information about the types - // of arguments when we typecheck the functions. This isn't really the - // right way to do this. - let check_args = fn@(check_blocks: bool) -> bool { - let i = 0u; - let bot = false; - for a_opt in args { - alt a_opt { - some(a) { - let is_block = alt a.node { - ast::expr_fn_block(_, _) { true } - _ { false } - }; - if is_block == check_blocks { - bot |= check_expr_with_unifier( - fcx, a, demand::simple, arg_tys[i].ty); - } - } - none { } - } - i += 1u; - } - ret bot; - }; - check_args(false) | check_args(true) - } - - // A generic function for checking assignment expressions - fn check_assignment(fcx: @fn_ctxt, _sp: span, lhs: @ast::expr, - rhs: @ast::expr, id: ast::node_id) -> bool { - let t = next_ty_var(fcx); - let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t); - write_ty(fcx.ccx.tcx, id, ty::mk_nil(fcx.ccx.tcx)); - ret bot; - } - - // A generic function for checking call expressions - fn check_call(fcx: @fn_ctxt, sp: span, f: @ast::expr, args: [@ast::expr]) - -> bool { - let args_opt_0: [option<@ast::expr>] = []; - for arg: @ast::expr in args { - args_opt_0 += [some::<@ast::expr>(arg)]; - } - - let bot = check_expr(fcx, f); - // Call the generic checker. - bot | check_call_or_bind(fcx, sp, expr_ty(fcx.ccx.tcx, f), args_opt_0) - } - - // A generic function for doing all of the checking for call expressions - fn check_call_full(fcx: @fn_ctxt, sp: span, f: @ast::expr, - args: [@ast::expr], id: ast::node_id) -> bool { - let bot = check_call(fcx, sp, f, args); - /* here we're kind of hosed, as f can be any 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(fcx.ccx, fcx.purity, f, sp); - - // Pull the return type out of the type of the function. - let fty = ty::expr_ty(fcx.ccx.tcx, f); - let rt_1 = alt structure_of(fcx, sp, fty) { - ty::ty_fn(f) { - bot |= f.ret_style == ast::noreturn; - f.output - } - _ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); } - }; - write_ty(fcx.ccx.tcx, id, rt_1); - ret bot; - } - - // A generic function for checking for or for-each loops - fn check_for(fcx: @fn_ctxt, local: @ast::local, - element_ty: ty::t, body: ast::blk, - node_id: ast::node_id) -> bool { - let locid = lookup_local(fcx, local.span, local.node.id); - let element_ty = demand::simple(fcx, local.span, element_ty, - ty::mk_var(fcx.ccx.tcx, locid)); - let bot = check_decl_local(fcx, local); - check_block_no_value(fcx, body); - // Unify type of decl with element type of the seq - demand::simple(fcx, local.span, - ty::node_id_to_type(fcx.ccx.tcx, local.node.id), - element_ty); - write_nil(fcx.ccx.tcx, node_id); - ret bot; - } - - - // A generic function for checking the then and else in an if - // or if-check - fn check_then_else(fcx: @fn_ctxt, thn: ast::blk, - elsopt: option<@ast::expr>, id: ast::node_id, - _sp: span) -> bool { - let (if_t, if_bot) = - alt elsopt { - some(els) { - let thn_bot = check_block(fcx, thn); - let thn_t = block_ty(fcx.ccx.tcx, thn); - let els_bot = check_expr_with(fcx, els, thn_t); - let els_t = expr_ty(fcx.ccx.tcx, els); - let if_t = if !ty::type_is_bot(els_t) { - els_t - } else { - thn_t - }; - (if_t, thn_bot & els_bot) - } - none { - check_block_no_value(fcx, thn); - (ty::mk_nil(fcx.ccx.tcx), false) - } - }; - write_ty(fcx.ccx.tcx, id, if_t); - ret if_bot; - } - - fn binop_method(op: ast::binop) -> option<str> { - alt op { - ast::add | ast::subtract | ast::mul | ast::div | ast::rem | - ast::bitxor | ast::bitand | ast::bitor | ast::lsl | ast::lsr | - ast::asr { some(ast_util::binop_to_str(op)) } - _ { none } - } - } - fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t, - opname: str, args: [option::t<@ast::expr>]) - -> option::t<ty::t> { - let callee_id = ast_util::op_expr_callee_id(op_ex); - alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) { - some(origin) { - let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id); - check_call_or_bind(fcx, op_ex.span, method_ty, args); - fcx.ccx.method_map.insert(op_ex.id, origin); - some(ty::ty_fn_ret(method_ty)) - } - _ { none } - } - } - fn check_binop(fcx: @fn_ctxt, ex: @ast::expr, ty: ty::t, - op: ast::binop, rhs: @ast::expr) -> ty::t { - let resolved_t = structurally_resolved_type(fcx, ex.span, ty); - let tcx = fcx.ccx.tcx; - if ty::is_binopable(tcx, resolved_t, op) { - ret alt op { - ast::eq | ast::lt | ast::le | ast::ne | ast::ge | - ast::gt { ty::mk_bool(tcx) } - _ { resolved_t } - }; - } - - alt binop_method(op) { - some(name) { - alt lookup_op_method(fcx, ex, resolved_t, name, [some(rhs)]) { - some(ret_ty) { ret ret_ty; } - _ {} - } - } - _ {} - } - tcx.sess.span_err( - ex.span, "binary operation " + ast_util::binop_to_str(op) + - " cannot be applied to type `" + ty_to_str(tcx, resolved_t) + - "`"); - resolved_t - } - fn check_user_unop(fcx: @fn_ctxt, op_str: str, mname: str, - ex: @ast::expr, rhs_t: ty::t) -> ty::t { - alt lookup_op_method(fcx, ex, rhs_t, mname, []) { - some(ret_ty) { ret_ty } - _ { - fcx.ccx.tcx.sess.span_err( - ex.span, #fmt["cannot apply unary operator `%s` to type `%s`", - op_str, ty_to_str(fcx.ccx.tcx, rhs_t)]); - rhs_t - } - } - } - - let tcx = fcx.ccx.tcx; - let id = expr.id; - let bot = false; - alt expr.node { - ast::expr_lit(lit) { - let typ = check_lit(fcx.ccx, lit); - write_ty(tcx, id, typ); - } - ast::expr_binary(binop, lhs, rhs) { - let lhs_t = next_ty_var(fcx); - bot = check_expr_with(fcx, lhs, lhs_t); - - let rhs_bot = if !ast_util::is_shift_binop(binop) { - check_expr_with(fcx, rhs, lhs_t) - } else { - let rhs_bot = check_expr(fcx, rhs); - let rhs_t = expr_ty(tcx, rhs); - require_integral(fcx, rhs.span, rhs_t); - rhs_bot - }; - - if !ast_util::lazy_binop(binop) { bot |= rhs_bot; } - - let result = check_binop(fcx, expr, lhs_t, binop, rhs); - write_ty(tcx, id, result); - } - ast::expr_assign_op(op, lhs, rhs) { - require_impure(tcx.sess, fcx.purity, expr.span); - bot = check_assignment(fcx, expr.span, lhs, rhs, id); - let lhs_t = ty::expr_ty(tcx, lhs); - let result = check_binop(fcx, expr, lhs_t, op, rhs); - demand::simple(fcx, expr.span, result, lhs_t); - } - ast::expr_unary(unop, oper) { - bot = check_expr(fcx, oper); - let oper_t = expr_ty(tcx, oper); - alt unop { - ast::box(mutbl) { - oper_t = ty::mk_box(tcx, {ty: oper_t, mutbl: mutbl}); - } - ast::uniq(mutbl) { - oper_t = ty::mk_uniq(tcx, {ty: oper_t, mutbl: mutbl}); - } - ast::deref { - alt structure_of(fcx, expr.span, oper_t) { - ty::ty_box(inner) { oper_t = inner.ty; } - ty::ty_uniq(inner) { oper_t = inner.ty; } - ty::ty_res(_, inner, _) { oper_t = inner; } - ty::ty_enum(id, tps) { - let variants = ty::enum_variants(tcx, id); - if vec::len(*variants) != 1u || - vec::len(variants[0].args) != 1u { - tcx.sess.span_err(expr.span, - "can only dereference enums " + - "with a single variant which has a " - + "single argument"); - } - oper_t = - ty::substitute_type_params(tcx, tps, variants[0].args[0]); - } - ty::ty_ptr(inner) { - oper_t = inner.ty; - require_unsafe(tcx.sess, fcx.purity, expr.span); - } - _ { - tcx.sess.span_err(expr.span, - "dereferencing non-" + - "dereferenceable type: " + - ty_to_str(tcx, oper_t)); - } - } - } - ast::not { - oper_t = structurally_resolved_type(fcx, oper.span, oper_t); - if !(ty::type_is_integral(oper_t) || - ty::get(oper_t).struct == ty::ty_bool) { - oper_t = check_user_unop(fcx, "!", "!", expr, oper_t); - } - } - ast::neg { - oper_t = structurally_resolved_type(fcx, oper.span, oper_t); - if !(ty::type_is_integral(oper_t) || - ty::type_is_fp(oper_t)) { - oper_t = check_user_unop(fcx, "-", "unary-", expr, oper_t); - } - } - } - write_ty(tcx, id, oper_t); - } - ast::expr_path(pth) { - let defn = lookup_def(fcx, pth.span, id); - - let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn); - if ty::def_has_ty_params(defn) { - instantiate_path(fcx, pth, tpt, expr.span, expr.id); - } else { - // 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 { - tcx.sess.span_fatal(expr.span, - "this kind of value does not \ - take type parameters"); - } - write_ty(tcx, id, tpt.ty); - } - } - ast::expr_mac(_) { tcx.sess.bug("unexpanded macro"); } - ast::expr_fail(expr_opt) { - bot = true; - alt expr_opt { - none {/* do nothing */ } - some(e) { check_expr_with(fcx, e, ty::mk_str(tcx)); } - } - write_bot(tcx, id); - } - ast::expr_break { write_bot(tcx, id); bot = true; } - ast::expr_cont { write_bot(tcx, id); bot = true; } - ast::expr_ret(expr_opt) { - bot = true; - alt expr_opt { - none { - let nil = ty::mk_nil(tcx); - if !are_compatible(fcx, fcx.ret_ty, nil) { - tcx.sess.span_err(expr.span, - "ret; in function returning non-nil"); - } - } - some(e) { check_expr_with(fcx, e, fcx.ret_ty); } - } - write_bot(tcx, id); - } - ast::expr_be(e) { - // FIXME: prove instead of assert - assert (ast_util::is_call_expr(e)); - check_expr_with(fcx, e, fcx.ret_ty); - bot = true; - write_nil(tcx, id); - } - ast::expr_log(_, lv, e) { - bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32)); - bot |= check_expr(fcx, e); - write_nil(tcx, id); - } - ast::expr_check(_, e) { - bot = check_pred_expr(fcx, e); - write_nil(tcx, id); - } - ast::expr_if_check(cond, thn, elsopt) { - bot = - check_pred_expr(fcx, cond) | - check_then_else(fcx, thn, elsopt, id, expr.span); - } - ast::expr_assert(e) { - bot = check_expr_with(fcx, e, ty::mk_bool(tcx)); - write_nil(tcx, id); - } - ast::expr_copy(a) { - bot = check_expr_with_unifier(fcx, a, unify, expected); - write_ty(tcx, id, ty::node_id_to_type(tcx, a.id)); - } - ast::expr_move(lhs, rhs) { - require_impure(tcx.sess, fcx.purity, expr.span); - bot = check_assignment(fcx, expr.span, lhs, rhs, id); - } - ast::expr_assign(lhs, rhs) { - require_impure(tcx.sess, fcx.purity, expr.span); - bot = check_assignment(fcx, expr.span, lhs, rhs, id); - } - ast::expr_swap(lhs, rhs) { - require_impure(tcx.sess, fcx.purity, expr.span); - bot = check_assignment(fcx, expr.span, lhs, rhs, id); - } - ast::expr_if(cond, thn, elsopt) { - bot = - check_expr_with(fcx, cond, ty::mk_bool(tcx)) | - check_then_else(fcx, thn, elsopt, id, expr.span); - } - ast::expr_for(decl, seq, body) { - bot = check_expr(fcx, seq); - let elt_ty; - let ety = expr_ty(tcx, seq); - alt structure_of(fcx, expr.span, ety) { - ty::ty_vec(vec_elt_ty) { elt_ty = vec_elt_ty.ty; } - ty::ty_str { elt_ty = ty::mk_mach_uint(tcx, ast::ty_u8); } - _ { - tcx.sess.span_fatal(expr.span, - "mismatched types: expected vector or string " - + "but found `" + ty_to_str(tcx, ety) + "`"); - } - } - bot |= check_for(fcx, decl, elt_ty, body, id); - } - ast::expr_while(cond, body) { - bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)); - check_block_no_value(fcx, body); - write_ty(tcx, id, ty::mk_nil(tcx)); - } - ast::expr_do_while(body, cond) { - bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) | - check_block_no_value(fcx, body); - write_ty(tcx, id, block_ty(tcx, body)); - } - ast::expr_alt(expr, arms, _) { - bot = check_expr(fcx, expr); - - // Typecheck the patterns first, so that we get types for all the - // bindings. - let pattern_ty = ty::expr_ty(tcx, expr); - for arm: ast::arm in arms { - let id_map = pat_util::pat_id_map(tcx.def_map, arm.pats[0]); - for p: @ast::pat in arm.pats { - check_pat(fcx, id_map, p, pattern_ty); - } - } - // Now typecheck the blocks. - let result_ty = next_ty_var(fcx); - let arm_non_bot = false; - for arm: ast::arm in arms { - alt arm.guard { - some(e) { check_expr_with(fcx, e, ty::mk_bool(tcx)); } - none { } - } - if !check_block(fcx, arm.body) { arm_non_bot = true; } - let bty = block_ty(tcx, arm.body); - result_ty = demand::simple(fcx, arm.body.span, result_ty, bty); - } - bot |= !arm_non_bot; - if !arm_non_bot { result_ty = ty::mk_bot(tcx); } - write_ty(tcx, id, result_ty); - } - ast::expr_fn(proto, decl, body, captures) { - check_expr_fn_with_unifier(fcx, expr, proto, decl, body, - unify, expected); - capture::check_capture_clause(tcx, expr.id, proto, *captures); - } - ast::expr_fn_block(decl, body) { - // Take the prototype from the expected type, but default to block: - let proto = alt ty::get(expected).struct { - ty::ty_fn({proto, _}) { proto } - _ { ast::proto_box } - }; - #debug("checking expr_fn_block %s expected=%s", - expr_to_str(expr), - ty_to_str(tcx, expected)); - check_expr_fn_with_unifier(fcx, expr, proto, decl, body, - unify, expected); - } - ast::expr_block(b) { - // If this is an unchecked block, turn off purity-checking - bot = check_block(fcx, b); - let typ = - alt b.node.expr { - some(expr) { expr_ty(tcx, expr) } - none { ty::mk_nil(tcx) } - }; - write_ty(tcx, id, typ); - } - ast::expr_bind(f, args) { - // Call the generic checker. - bot = check_expr(fcx, f); - bot |= check_call_or_bind(fcx, expr.span, expr_ty(tcx, f), args); - - // Pull the argument and return types out. - let proto, arg_tys, rt, cf, constrs; - alt structure_of(fcx, expr.span, expr_ty(tcx, f)) { - // FIXME: - // probably need to munge the constrs to drop constraints - // for any bound args - ty::ty_fn(f) { - proto = f.proto; - arg_tys = f.inputs; - rt = f.output; - cf = f.ret_style; - constrs = f.constraints; - } - _ { fail "LHS of bind expr didn't have a function type?!"; } - } - - let proto = alt proto { - ast::proto_bare | ast::proto_box { ast::proto_box } - ast::proto_uniq | ast::proto_any | ast::proto_block { - tcx.sess.span_err(expr.span, - #fmt["cannot bind %s closures", - proto_to_str(proto)]); - proto // dummy value so compilation can proceed - } - }; - - // For each blank argument, add the type of that argument - // to the resulting function type. - let out_args = []; - let i = 0u; - while i < vec::len(args) { - alt args[i] { - some(_) {/* no-op */ } - none { out_args += [arg_tys[i]]; } - } - i += 1u; - } - - let ft = ty::mk_fn(tcx, {proto: proto, - inputs: out_args, output: rt, - ret_style: cf, constraints: constrs}); - write_ty(tcx, id, ft); - } - ast::expr_call(f, args, _) { - bot = check_call_full(fcx, expr.span, f, args, expr.id); - } - ast::expr_cast(e, t) { - bot = check_expr(fcx, e); - let t_1 = ast_ty_to_ty_crate(fcx.ccx, t); - let t_e = ty::expr_ty(tcx, e); - - alt ty::get(t_1).struct { - // This will be looked up later on - ty::ty_iface(_, _) {} - _ { - if ty::type_is_nil(t_e) { - tcx.sess.span_err(expr.span, "cast from nil: " + - ty_to_str(tcx, t_e) + " as " + - ty_to_str(tcx, t_1)); - } else if ty::type_is_nil(t_1) { - tcx.sess.span_err(expr.span, "cast to nil: " + - ty_to_str(tcx, t_e) + " as " + - ty_to_str(tcx, t_1)); - } - - let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1); - if type_is_c_like_enum(fcx,expr.span,t_e) && t_1_is_scalar { - /* this case is allowed */ - } else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) { - // FIXME there are more forms of cast to support, eventually. - tcx.sess.span_err(expr.span, - "non-scalar cast: " + - ty_to_str(tcx, t_e) + " as " + - ty_to_str(tcx, t_1)); - } - } - } - write_ty(tcx, id, t_1); - } - ast::expr_vec(args, mutbl) { - let t: ty::t = next_ty_var(fcx); - for e: @ast::expr in args { bot |= check_expr_with(fcx, e, t); } - let typ = ty::mk_vec(tcx, {ty: t, mutbl: mutbl}); - write_ty(tcx, id, typ); - } - ast::expr_tup(elts) { - let elt_ts = []; - vec::reserve(elt_ts, vec::len(elts)); - for e in elts { - check_expr(fcx, e); - let ety = expr_ty(tcx, e); - elt_ts += [ety]; - } - let typ = ty::mk_tup(tcx, elt_ts); - write_ty(tcx, id, typ); - } - ast::expr_rec(fields, base) { - alt base { none {/* no-op */ } some(b_0) { check_expr(fcx, b_0); } } - let fields_t: [spanned<field>] = []; - for f: ast::field in fields { - bot |= check_expr(fcx, f.node.expr); - let expr_t = expr_ty(tcx, f.node.expr); - let expr_mt = {ty: expr_t, mutbl: f.node.mutbl}; - // for the most precise error message, - // should be f.node.expr.span, not f.span - fields_t += - [respan(f.node.expr.span, - {ident: f.node.ident, mt: expr_mt})]; - } - alt base { - none { - fn get_node(f: spanned<field>) -> field { f.node } - let typ = ty::mk_rec(tcx, vec::map(fields_t, get_node)); - write_ty(tcx, id, typ); - } - some(bexpr) { - bot |= check_expr(fcx, bexpr); - let bexpr_t = expr_ty(tcx, bexpr); - let base_fields: [field] = []; - alt structure_of(fcx, expr.span, bexpr_t) { - ty::ty_rec(flds) { base_fields = flds; } - _ { - tcx.sess.span_fatal(expr.span, - "record update has non-record base"); - } - } - write_ty(tcx, id, bexpr_t); - for f: spanned<ty::field> in fields_t { - let found = false; - for bf: ty::field in base_fields { - if str::eq(f.node.ident, bf.ident) { - demand::simple(fcx, f.span, bf.mt.ty, f.node.mt.ty); - found = true; - } - } - if !found { - tcx.sess.span_fatal(f.span, - "unknown field in record update: " + - f.node.ident); - } - } - } - } - } - ast::expr_field(base, field, tys) { - bot |= check_expr(fcx, base); - let expr_t = structurally_resolved_type(fcx, expr.span, - expr_ty(tcx, base)); - let base_t = do_autoderef(fcx, expr.span, expr_t); - let handled = false, n_tys = vec::len(tys); - alt structure_of(fcx, expr.span, base_t) { - ty::ty_rec(fields) { - alt ty::field_idx(field, fields) { - some(ix) { - if n_tys > 0u { - tcx.sess.span_err(expr.span, - "can't provide type parameters \ - to a field access"); - } - write_ty(tcx, id, fields[ix].mt.ty); - handled = true; - } - _ {} - } - } - ty::ty_class(base_id, _params) { - // (1) verify that the class id actually has a field called - // field - // For now, this code assumes the class is defined in the local - // crate - // FIXME: handle field references to classes in external crate - let err = "Class ID is not bound to a class"; - let field_ty = alt fcx.ccx.tcx.items.find(base_id.node) { - some(ast_map::node_item(i,_)) { - alt i.node { - ast::item_class(_, items, _, _, _) { - lookup_field_ty(fcx.ccx.tcx, items, field, - expr.span) - } - _ { fcx.ccx.tcx.sess.span_bug(expr.span, err); } - } - } - _ { fcx.ccx.tcx.sess.span_bug(expr.span, err); } - }; - // (2) look up what field's type is, and return it - // FIXME: actually instantiate any type params - write_ty(tcx, id, field_ty); - handled = true; - } - _ {} - } - if !handled { - let tps = vec::map(tys, {|ty| ast_ty_to_ty_crate(fcx.ccx, ty)}); - alt lookup_method(fcx, expr, expr.id, field, expr_t, tps) { - some(origin) { - fcx.ccx.method_map.insert(id, origin); - } - none { - let t_err = resolve_type_vars_if_possible(fcx, expr_t); - let msg = #fmt["attempted access of field %s on type %s, but \ - no method implementation was found", - field, ty_to_str(tcx, t_err)]; - tcx.sess.span_err(expr.span, msg); - // NB: Adding a bogus type to allow typechecking to continue - write_ty(tcx, id, next_ty_var(fcx)); - } - } - } - } - ast::expr_index(base, idx) { - bot |= check_expr(fcx, base); - let raw_base_t = expr_ty(tcx, base); - let base_t = do_autoderef(fcx, expr.span, raw_base_t); - bot |= check_expr(fcx, idx); - let idx_t = expr_ty(tcx, idx); - alt structure_of(fcx, expr.span, base_t) { - ty::ty_vec(mt) { - require_integral(fcx, idx.span, idx_t); - write_ty(tcx, id, mt.ty); - } - ty::ty_str { - require_integral(fcx, idx.span, idx_t); - let typ = ty::mk_mach_uint(tcx, ast::ty_u8); - write_ty(tcx, id, typ); - } - _ { - let resolved = structurally_resolved_type(fcx, expr.span, - raw_base_t); - alt lookup_op_method(fcx, expr, resolved, "[]", - [some(idx)]) { - some(ret_ty) { write_ty(tcx, id, ret_ty); } - _ { - tcx.sess.span_fatal( - expr.span, "cannot index a value of type `" + - ty_to_str(tcx, base_t) + "`"); - } - } - } - } - } - _ { tcx.sess.unimpl("expr type in typeck::check_expr"); } - } - if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); } - - unify(fcx, expr.span, expected, expr_ty(tcx, expr)); - ret bot; -} - -fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { - if !type_is_integral(fcx, sp, t) { - fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \ - `integer` but found `" - + ty_to_str(fcx.ccx.tcx, t) + "`"); - } -} - -fn next_ty_var_id(fcx: @fn_ctxt) -> int { - let id = *fcx.next_var_id; - *fcx.next_var_id += 1; - ret id; -} - -fn next_ty_var(fcx: @fn_ctxt) -> ty::t { - ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx)); -} - -fn bind_params(fcx: @fn_ctxt, tp: ty::t, count: uint) - -> {vars: [ty::t], ty: ty::t} { - let vars = vec::init_fn(count, {|_i| next_ty_var(fcx)}); - {vars: vars, ty: ty::substitute_type_params(fcx.ccx.tcx, vars, tp)} -} - -fn get_self_info(ccx: @crate_ctxt) -> option<self_info> { - ret vec::last(ccx.self_infos); -} - -fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, - init: ast::initializer) -> bool { - let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid)); - ret check_expr_with(fcx, init.expr, lty); -} - -fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { - let bot = false; - - let t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.node.id)); - write_ty(fcx.ccx.tcx, local.node.id, t); - alt local.node.init { - some(init) { - bot = check_decl_initializer(fcx, local.node.id, init); - } - _ {/* fall through */ } - } - let id_map = pat_util::pat_id_map(fcx.ccx.tcx.def_map, local.node.pat); - check_pat(fcx, id_map, local.node.pat, t); - ret bot; -} - -fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool { - let node_id; - let bot = false; - alt stmt.node { - ast::stmt_decl(decl, id) { - node_id = id; - alt decl.node { - ast::decl_local(ls) { - for l in ls { bot |= check_decl_local(fcx, l); } - } - ast::decl_item(_) {/* ignore for now */ } - } - } - ast::stmt_expr(expr, id) { - node_id = id; - bot = check_expr_with(fcx, expr, ty::mk_nil(fcx.ccx.tcx)); - } - ast::stmt_semi(expr, id) { - node_id = id; - bot = check_expr(fcx, expr); - } - } - write_nil(fcx.ccx.tcx, node_id); - ret bot; -} - -fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool { - let bot = check_block(fcx, blk); - if !bot { - let blkty = ty::node_id_to_type(fcx.ccx.tcx, blk.node.id); - let nilty = ty::mk_nil(fcx.ccx.tcx); - demand::simple(fcx, blk.span, nilty, blkty); - } - ret bot; -} - -fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { - let fcx = alt blk.node.rules { - ast::unchecked_blk { @{purity: ast::impure_fn with *fcx0} } - ast::unsafe_blk { @{purity: ast::unsafe_fn with *fcx0} } - ast::default_blk { fcx0 } - }; - let bot = false; - let warned = false; - for s: @ast::stmt in blk.node.stmts { - if bot && !warned && - alt s.node { - ast::stmt_decl(@{node: ast::decl_local(_), _}, _) | - ast::stmt_expr(_, _) | ast::stmt_semi(_, _) { - true - } - _ { false } - } { - fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement"); - warned = true; - } - bot |= check_stmt(fcx, s); - } - alt blk.node.expr { - none { write_nil(fcx.ccx.tcx, blk.node.id); } - some(e) { - if bot && !warned { - fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression"); - } - bot |= check_expr(fcx, e); - let ety = expr_ty(fcx.ccx.tcx, e); - write_ty(fcx.ccx.tcx, blk.node.id, ety); - } - } - if bot { - write_ty(fcx.ccx.tcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx)); - } - ret bot; -} - -fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { - // FIXME: this is kinda a kludge; we manufacture a fake function context - // and statement context for checking the initializer expression. - let rty = node_id_to_type(ccx.tcx, id); - let fcx: @fn_ctxt = - @{ret_ty: rty, - purity: ast::pure_fn, - proto: ast::proto_box, - var_bindings: ty::unify::mk_var_bindings(), - locals: new_int_hash::<int>(), - next_var_id: @mutable 0, - ccx: ccx}; - check_expr(fcx, e); - let cty = expr_ty(fcx.ccx.tcx, e); - let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty; - demand::simple(fcx, e.span, declty, cty); -} - -fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], - id: ast::node_id) { - // FIXME: this is kinda a kludge; we manufacture a fake function context - // and statement context for checking the initializer expression. - let rty = node_id_to_type(ccx.tcx, id); - let fcx: @fn_ctxt = - @{ret_ty: rty, - purity: ast::pure_fn, - proto: ast::proto_box, - var_bindings: ty::unify::mk_var_bindings(), - locals: new_int_hash::<int>(), - next_var_id: @mutable 0, - ccx: ccx}; - let disr_vals: [int] = []; - let disr_val = 0; - for v in vs { - alt v.node.disr_expr { - some(e) { - check_expr(fcx, e); - let cty = expr_ty(fcx.ccx.tcx, e); - let declty = ty::mk_int(fcx.ccx.tcx); - demand::simple(fcx, e.span, declty, cty); - // FIXME: issue #1417 - // Also, check_expr (from check_const pass) doesn't guarantee that - // the expression in an form that eval_const_expr can handle, so - // we may still get an internal compiler error - alt syntax::ast_util::eval_const_expr(e) { - syntax::ast_util::const_int(val) { - disr_val = val as int; - } - _ { - ccx.tcx.sess.span_err(e.span, - "expected signed integer constant"); - } - } - } - _ {} - } - if vec::contains(disr_vals, disr_val) { - ccx.tcx.sess.span_err(v.span, - "discriminator value already exists."); - } - disr_vals += [disr_val]; - disr_val += 1; - } - let outer = true, did = local_def(id); - if ty::type_structurally_contains(ccx.tcx, rty, {|sty| - alt sty { - ty::ty_enum(id, _) if id == did { - if outer { outer = false; false } - else { true } - } - _ { false } - } - }) { - ccx.tcx.sess.span_fatal(sp, "illegal recursive enum type. \ - wrap the inner value in a box to \ - make it represenable"); - } -} - -// A generic function for checking the pred in a check -// or if-check -fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool { - let bot = check_expr_with(fcx, e, ty::mk_bool(fcx.ccx.tcx)); - - /* e must be a call expr where all arguments are either - literals or slots */ - alt e.node { - ast::expr_call(operator, operands, _) { - if !ty::is_pred_ty(expr_ty(fcx.ccx.tcx, operator)) { - fcx.ccx.tcx.sess.span_err - (operator.span, - "operator in constraint has non-boolean return type"); - } - - alt operator.node { - ast::expr_path(oper_name) { - alt fcx.ccx.tcx.def_map.find(operator.id) { - some(ast::def_fn(_, ast::pure_fn)) { - // do nothing - } - _ { - fcx.ccx.tcx.sess.span_err(operator.span, - "Impure function as operator \ - in constraint"); - } - } - for operand: @ast::expr in operands { - if !ast_util::is_constraint_arg(operand) { - let s = - "Constraint args must be slot variables or literals"; - fcx.ccx.tcx.sess.span_err(e.span, s); - } - } - } - _ { - let s = "In a constraint, expected the \ - constraint name to be an explicit name"; - fcx.ccx.tcx.sess.span_err(e.span, s); - } - } - } - _ { fcx.ccx.tcx.sess.span_err(e.span, "check on non-predicate"); } - } - ret bot; -} - -fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { - let c_args; - let num_args = vec::len(args); - for c: @ast::constr in cs { - c_args = []; - for a: @spanned<ast::fn_constr_arg> in c.node.args { - c_args += [ - // "base" should not occur in a fn type thing, as of - // yet, b/c we don't allow constraints on the return type - - // Works b/c no higher-order polymorphism - /* - This is kludgy, and we probably shouldn't be assigning - node IDs here, but we're creating exprs that are - ephemeral, just for the purposes of typechecking. So - that's my justification. - */ - @alt a.node { - ast::carg_base { - fcx.ccx.tcx.sess.span_bug(a.span, - "check_constraints:\ - unexpected carg_base"); - } - ast::carg_lit(l) { - let tmp_node_id = fcx.ccx.tcx.sess.next_node_id(); - {id: tmp_node_id, node: ast::expr_lit(l), span: a.span} - } - ast::carg_ident(i) { - if i < num_args { - let p: ast::path_ = - {global: false, - idents: [args[i].ident], - types: []}; - let arg_occ_node_id = - fcx.ccx.tcx.sess.next_node_id(); - fcx.ccx.tcx.def_map.insert - (arg_occ_node_id, - ast::def_arg(args[i].id, args[i].mode)); - {id: arg_occ_node_id, - node: ast::expr_path(@respan(a.span, p)), - span: a.span} - } else { - fcx.ccx.tcx.sess.span_bug(a.span, - "check_constraints:\ - carg_ident index out of bounds"); - } - } - }]; - } - let p_op: ast::expr_ = ast::expr_path(c.node.path); - let oper: @ast::expr = @{id: c.node.id, node: p_op, span: c.span}; - // Another ephemeral expr - let call_expr_id = fcx.ccx.tcx.sess.next_node_id(); - let call_expr = - @{id: call_expr_id, - node: ast::expr_call(oper, c_args, false), - span: c.span}; - check_pred_expr(fcx, call_expr); - } -} - -fn check_fn(ccx: @crate_ctxt, - proto: ast::proto, - decl: ast::fn_decl, - body: ast::blk, - id: ast::node_id, - old_fcx: option<@fn_ctxt>) { - // If old_fcx is some(...), this is a block fn { |x| ... }. - // In that case, the purity is inherited from the context. - let purity = alt old_fcx { - none { decl.purity } - some(f) { assert decl.purity == ast::impure_fn; f.purity } - }; - - let gather_result = gather_locals(ccx, decl, body, id, old_fcx); - let fcx: @fn_ctxt = - @{ret_ty: ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id)), - purity: purity, - proto: proto, - var_bindings: gather_result.var_bindings, - locals: gather_result.locals, - next_var_id: gather_result.next_var_id, - ccx: ccx}; - - check_constraints(fcx, decl.constraints, decl.inputs); - check_block(fcx, body); - - // We unify the tail expr's type with the - // function result type, if there is a tail expr. - alt body.node.expr { - some(tail_expr) { - let tail_expr_ty = expr_ty(ccx.tcx, tail_expr); - demand::simple(fcx, tail_expr.span, fcx.ret_ty, tail_expr_ty); - } - none { } - } - - let args = ty::ty_fn_args(ty::node_id_to_type(ccx.tcx, id)); - let i = 0u; - for arg: ty::arg in args { - write_ty(ccx.tcx, decl.inputs[i].id, arg.ty); - i += 1u; - } - - // If we don't have any enclosing function scope, it is time to - // force any remaining type vars to be resolved. - // If we have an enclosing function scope, our type variables will be - // resolved when the enclosing scope finishes up. - if option::is_none(old_fcx) { - dict::resolve_in_block(fcx, body); - writeback::resolve_type_vars_in_block(fcx, body); - } -} - -fn check_method(ccx: @crate_ctxt, method: @ast::method) { - check_fn(ccx, ast::proto_bare, method.decl, method.body, method.id, none); -} - -fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map { - let rslt = new_int_hash::<ty::t>(); - for m in members { - alt m.node.decl { - ast::instance_var(_,t,_,id) { - rslt.insert(id, ast_ty_to_ty(ccx.tcx, m_collect, t)); - } - ast::class_method(it) { - rslt.insert(it.id, ty_of_item(ccx.tcx, m_collect, it).ty); - } - } - } - rslt -} - -fn check_class_member(ccx: @crate_ctxt, cm: ast::class_member) { - alt cm { - ast::instance_var(_,t,_,_) { // ??? Not sure - } - // not right yet -- need a scope - ast::class_method(i) { check_item(ccx, i); } - } -} - -fn check_item(ccx: @crate_ctxt, it: @ast::item) { - alt it.node { - ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); } - ast::item_enum(vs, _) { check_enum_variants(ccx, it.span, vs, it.id); } - ast::item_fn(decl, tps, body) { - check_fn(ccx, ast::proto_bare, decl, body, it.id, none); - } - ast::item_res(decl, tps, body, dtor_id, _) { - check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none); - } - ast::item_impl(tps, _, ty, ms) { - ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))]; - for m in ms { check_method(ccx, m); } - vec::pop(ccx.self_infos); - } - ast::item_class(tps, members, ctor_id, ctor_decl, ctor_body) { - let cid = some(it.id); - let members_info = class_types(ccx, members); - let class_ccx = @{enclosing_class_id:cid, - enclosing_class:members_info with *ccx}; - // typecheck the ctor - check_fn(class_ccx, ast::proto_bare, ctor_decl, ctor_body, ctor_id, - none); - // typecheck the members - for m in members { check_class_member(class_ccx, m.node.decl); } - } - _ {/* nothing to do */ } - } -} - -fn arg_is_argv_ty(_tcx: ty::ctxt, a: ty::arg) -> bool { - alt ty::get(a.ty).struct { - ty::ty_vec(mt) { - if mt.mutbl != ast::m_imm { ret false; } - alt ty::get(mt.ty).struct { - ty::ty_str { ret true; } - _ { ret false; } - } - } - _ { ret false; } - } -} - -fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id, main_span: span) { - let main_t = ty::node_id_to_type(tcx, main_id); - alt ty::get(main_t).struct { - ty::ty_fn({proto: ast::proto_bare, inputs, output, - ret_style: ast::return_val, constraints}) { - alt tcx.items.find(main_id) { - some(ast_map::node_item(it,_)) { - alt it.node { - ast::item_fn(_,ps,_) if vec::is_not_empty(ps) { - tcx.sess.span_err(main_span, - "main function is not allowed to have type parameters"); - ret; - } - _ {} - } - } - _ {} - } - let ok = vec::len(constraints) == 0u; - ok &= ty::type_is_nil(output); - let num_args = vec::len(inputs); - ok &= num_args == 0u || num_args == 1u && - arg_is_argv_ty(tcx, inputs[0]); - if !ok { - tcx.sess.span_err(main_span, - "wrong type in main function: found `" + - ty_to_str(tcx, main_t) + "`"); - } - } - _ { - tcx.sess.span_bug(main_span, - "main has a non-function type: found `" + - ty_to_str(tcx, main_t) + "`"); - } - } -} - -fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) { - if !tcx.sess.building_library { - alt tcx.sess.main_fn { - some((id, sp)) { check_main_fn_ty(tcx, id, sp); } - none { tcx.sess.span_err(crate.span, "main function not found"); } - } - } -} - -mod dict { - fn has_iface_bounds(tps: [ty::param_bounds]) -> bool { - vec::any(tps, {|bs| - vec::any(*bs, {|b| - alt b { ty::bound_iface(_) { true } _ { false } } - }) - }) - } - - fn lookup_dicts(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span, - bounds: @[ty::param_bounds], tys: [ty::t]) - -> dict_res { - let tcx = fcx.ccx.tcx, result = [], i = 0u; - for ty in tys { - for bound in *bounds[i] { - alt bound { - ty::bound_iface(i_ty) { - let i_ty = ty::substitute_type_params(tcx, tys, i_ty); - result += [lookup_dict(fcx, isc, sp, ty, i_ty)]; - } - _ {} - } - } - i += 1u; - } - @result - } - - fn lookup_dict(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span, - ty: ty::t, iface_ty: ty::t) -> dict_origin { - let tcx = fcx.ccx.tcx; - let (iface_id, iface_tps) = alt check ty::get(iface_ty).struct { - ty::ty_iface(did, tps) { (did, tps) } - }; - let ty = fixup_ty(fcx, sp, ty); - alt ty::get(ty).struct { - ty::ty_param(n, did) { - let n_bound = 0u; - for bound in *tcx.ty_param_bounds.get(did.node) { - alt bound { - ty::bound_iface(ity) { - alt check ty::get(ity).struct { - ty::ty_iface(idid, _) { - if iface_id == idid { ret dict_param(n, n_bound); } - } - } - n_bound += 1u; - } - _ {} - } - } - } - ty::ty_iface(did, _) if iface_id == did { - ret dict_iface(did); - } - _ { - let found = none; - std::list::iter(isc) {|impls| - if option::is_some(found) { ret; } - for im in *impls { - let match = alt ty::impl_iface(tcx, im.did) { - some(ity) { - alt check ty::get(ity).struct { - ty::ty_iface(id, _) { id == iface_id } - } - } - _ { false } - }; - if match { - let {n_tps, ty: self_ty} = impl_self_ty(tcx, im.did); - let {vars, ty: self_ty} = if n_tps > 0u { - bind_params(fcx, self_ty, n_tps) - } else { {vars: [], ty: self_ty} }; - let im_bs = ty::lookup_item_type(tcx, im.did).bounds; - alt unify::unify(fcx, ty, self_ty) { - ures_ok(_) { - if option::is_some(found) { - tcx.sess.span_err( - sp, "multiple applicable implementations \ - in scope"); - } else { - connect_iface_tps(fcx, sp, vars, iface_tps, - im.did); - let params = vec::map(vars, {|t| - fixup_ty(fcx, sp, t)}); - let subres = lookup_dicts(fcx, isc, sp, im_bs, - params); - found = some(dict_static(im.did, params, - subres)); - } - } - _ {} - } - } - } - } - alt found { - some(rslt) { ret rslt; } - _ {} - } - } - } - - tcx.sess.span_fatal( - sp, "failed to find an implementation of interface " + - ty_to_str(tcx, iface_ty) + " for " + - ty_to_str(tcx, ty)); - } - - fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t { - let tcx = fcx.ccx.tcx; - alt ty::unify::fixup_vars(tcx, some(sp), fcx.var_bindings, ty) { - fix_ok(new_type) { new_type } - fix_err(vid) { - tcx.sess.span_fatal(sp, "could not determine a type for a \ - bounded type parameter"); - } - } - } - - fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: [ty::t], - iface_tys: [ty::t], impl_did: ast::def_id) { - let tcx = fcx.ccx.tcx; - let ity = option::get(ty::impl_iface(tcx, impl_did)); - let iface_ty = ty::substitute_type_params(tcx, impl_tys, ity); - alt check ty::get(iface_ty).struct { - ty::ty_iface(_, tps) { - vec::iter2(tps, iface_tys, - {|a, b| demand::simple(fcx, sp, a, b);}); - } - } - } - - fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) { - let cx = fcx.ccx; - alt ex.node { - ast::expr_path(_) { - alt cx.tcx.node_type_substs.find(ex.id) { - some(ts) { - let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)); - let item_ty = ty::lookup_item_type(cx.tcx, did); - if has_iface_bounds(*item_ty.bounds) { - let impls = cx.impl_map.get(ex.id); - cx.dict_map.insert(ex.id, lookup_dicts( - fcx, impls, ex.span, item_ty.bounds, ts)); - } - } - _ {} - } - } - // Must resolve bounds on methods with bounded params - ast::expr_field(_, _, _) | ast::expr_binary(_, _, _) | - ast::expr_unary(_, _) | ast::expr_assign_op(_, _, _) | - ast::expr_index(_, _) { - alt cx.method_map.find(ex.id) { - some(method_static(did)) { - let bounds = ty::lookup_item_type(cx.tcx, did).bounds; - if has_iface_bounds(*bounds) { - let callee_id = alt ex.node { - ast::expr_field(_, _, _) { ex.id } - _ { ast_util::op_expr_callee_id(ex) } - }; - let ts = ty::node_id_to_type_params(cx.tcx, callee_id); - let iscs = cx.impl_map.get(ex.id); - cx.dict_map.insert(callee_id, lookup_dicts( - fcx, iscs, ex.span, bounds, ts)); - } - } - _ {} - } - } - ast::expr_cast(src, _) { - let target_ty = expr_ty(cx.tcx, ex); - alt ty::get(target_ty).struct { - ty::ty_iface(_, _) { - let impls = cx.impl_map.get(ex.id); - let dict = lookup_dict(fcx, impls, ex.span, - expr_ty(cx.tcx, src), target_ty); - cx.dict_map.insert(ex.id, @[dict]); - } - _ {} - } - } - ast::expr_fn(p, _, _, _) if ast::is_blockish(p) {} - ast::expr_fn(_, _, _, _) { ret; } - _ {} - } - visit::visit_expr(ex, fcx, v); - } - - // Detect points where an interface-bounded type parameter is - // instantiated, resolve the impls for the parameters. - fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) { - visit::visit_block(bl, fcx, visit::mk_vt(@{ - visit_expr: resolve_expr, - visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt, - _v: visit::vt<@fn_ctxt>) {} - with *visit::default_visitor() - })); - } -} - -fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map, - crate: @ast::crate) -> (method_map, dict_map) { - collect::collect_item_types(tcx, crate); - - let ccx = @{mutable self_infos: [], - impl_map: impl_map, - method_map: std::map::new_int_hash(), - dict_map: std::map::new_int_hash(), - enclosing_class_id: none, - enclosing_class: std::map::new_int_hash(), - tcx: tcx}; - let visit = visit::mk_simple_visitor(@{ - visit_item: bind check_item(ccx, _) - with *visit::default_simple_visitor() - }); - visit::visit_crate(*crate, (), visit); - check_for_main_fn(tcx, crate); - tcx.sess.abort_if_errors(); - (ccx.method_map, ccx.dict_map) -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc deleted file mode 100644 index 8102e4d8cd8..00000000000 --- a/src/comp/rustc.rc +++ /dev/null @@ -1,155 +0,0 @@ -// -*- rust -*- - -#[link(name = "rustc", - vers = "0.1", - uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", - url = "http://rust-lang.org/src/rustc")]; - -#[comment = "The Rust compiler"]; -#[license = "MIT"]; -#[crate_type = "lib"]; - -use std (name = "std", - vers = "0.1", - url = "http://rust-lang.org/src/std"); - -mod middle { - mod trans { - mod common; - mod type_of; - mod build; - mod base; - mod alt; - mod uniq; - mod closure; - mod tvec; - mod impl; - mod native; - mod shape; - mod debuginfo; - } - mod inline; - mod ty; - mod ast_map; - mod resolve; - mod typeck; - mod fn_usage; - mod check_alt; - mod check_const; - mod lint; - mod mutbl; - mod alias; - mod last_use; - mod block_use; - mod kind; - mod freevars; - mod capture; - mod pat_util; - - mod tstate { - mod ck; - mod annotate; - #[path = "auxiliary.rs"] - mod aux; - mod bitvectors; - mod collect_locals; - mod pre_post_conditions; - mod states; - mod ann; - mod tritv; - } -} - - -mod syntax { - mod ast; - mod ast_util; - - mod fold; - mod visit; - mod codemap; - mod parse { - mod lexer; - mod parser; - mod token; - mod eval; - } - mod ext { - mod base; - mod expand; - mod qquote; - mod build; - - mod fmt; - mod env; - mod simplext; - mod concat_idents; - mod ident_to_str; - mod log_syntax; - } - mod print { - mod pprust; - mod pp; - } - mod util { - mod interner; - } -} - -mod front { - mod attr; - mod config; - mod test; - mod core_inject; -} - -mod back { - mod link; - mod abi; - mod upcall; - mod x86; - mod x86_64; - mod rpath; - mod target_strs; -} - -mod metadata { - export encoder; - export creader; - export cstore; - export csearch; - - mod common; - mod tyencode; - mod tydecode; - mod astencode; - mod astencode_gen; - mod encoder; - mod decoder; - mod creader; - mod cstore; - mod csearch; -} - -mod driver { - mod driver; - mod session; - mod diagnostic; -} - -mod util { - mod common; - mod ppaux; - mod filesearch; -} - -mod lib { - mod llvm; -} - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs deleted file mode 100644 index eea47191eef..00000000000 --- a/src/comp/syntax/ast.rs +++ /dev/null @@ -1,553 +0,0 @@ -// The Rust abstract syntax tree. - -import codemap::{span, filename}; - -type spanned<T> = {node: T, span: span}; - -type ident = str; - -// Functions may or may not have names. -type fn_ident = option<ident>; - -// FIXME: with typestate constraint, could say -// idents and types are the same length, and are -// non-empty -type path_ = {global: bool, idents: [ident], types: [@ty]}; - -type path = spanned<path_>; - -type crate_num = int; -type node_id = int; -type def_id = {crate: crate_num, node: node_id}; - -const local_crate: crate_num = 0; -const crate_node_id: node_id = 0; - -enum ty_param_bound { - bound_copy, - bound_send, - bound_iface(@ty), -} - -type ty_param = {ident: ident, id: node_id, bounds: @[ty_param_bound]}; - -enum def { - def_fn(def_id, purity), - def_self(node_id), - def_mod(def_id), - def_native_mod(def_id), - def_const(def_id), - def_arg(node_id, mode), - def_local(node_id, bool /* is_mutbl */), - def_variant(def_id /* enum */, def_id /* variant */), - def_ty(def_id), - def_prim_ty(prim_ty), - def_ty_param(def_id, uint), - def_binding(node_id), - def_use(def_id), - def_upvar(node_id /* local id of closed over var */, - @def /* closed over def */, - node_id /* expr node that creates the closure */), - def_class(def_id), - // first def_id is for parent class - def_class_field(def_id, def_id), - // No purity allowed for now, I guess - // (simpler this way, b/c presumably methods read mutable state) - def_class_method(def_id, def_id) -} - -// The set of meta_items that define the compilation environment of the crate, -// used to drive conditional compilation -type crate_cfg = [@meta_item]; - -type crate = spanned<crate_>; - -type crate_ = - {directives: [@crate_directive], - module: _mod, - attrs: [attribute], - config: crate_cfg}; - -enum crate_directive_ { - cdir_src_mod(ident, [attribute]), - cdir_dir_mod(ident, [@crate_directive], [attribute]), - - // NB: cdir_view_item is *not* processed by the rest of the compiler, the - // attached view_items are sunk into the crate's module during parsing, - // and processed (resolved, imported, etc.) there. This enum-variant - // exists only to preserve the view items in order in case we decide to - // pretty-print crates in the future. - cdir_view_item(@view_item), - - cdir_syntax(@path), -} - -type crate_directive = spanned<crate_directive_>; - -type meta_item = spanned<meta_item_>; - -enum meta_item_ { - meta_word(ident), - meta_list(ident, [@meta_item]), - meta_name_value(ident, lit), -} - -type blk = spanned<blk_>; - -type blk_ = {view_items: [@view_item], stmts: [@stmt], expr: option<@expr>, - id: node_id, rules: blk_check_mode}; - -type pat = {id: node_id, node: pat_, span: span}; - -type field_pat = {ident: ident, pat: @pat}; - -enum pat_ { - pat_wild, - // A pat_ident may either be a new bound variable, - // or a nullary enum (in which case the second field - // is none). - // In the nullary enum case, the parser can't determine - // which it is. The resolver determines this, and - // records this pattern's node_id in an auxiliary - // set (of "pat_idents that refer to nullary enums") - pat_ident(@path, option<@pat>), - pat_enum(@path, [@pat]), - pat_rec([field_pat], bool), - pat_tup([@pat]), - pat_box(@pat), - pat_uniq(@pat), - pat_lit(@expr), - pat_range(@expr, @expr), -} - -enum mutability { m_mutbl, m_imm, m_const, } - -enum proto { - proto_bare, // native fn - proto_any, // fn - proto_uniq, // fn~ - proto_box, // fn@ - proto_block, // fn& -} - -pure fn is_blockish(p: ast::proto) -> bool { - alt p { - proto_any | proto_block { true } - proto_bare | proto_uniq | proto_box { false } - } -} - -enum binop { - add, - subtract, - mul, - div, - rem, - and, - or, - bitxor, - bitand, - bitor, - lsl, - lsr, - asr, - eq, - lt, - le, - ne, - ge, - gt, -} - -enum unop { - box(mutability), - uniq(mutability), - deref, not, neg, -} - -// Generally, after typeck you can get the inferred value -// using ty::resolved_T(...). -enum inferable<T> { - expl(T), infer(node_id) -} - -// "resolved" mode: the real modes. -enum rmode { by_ref, by_val, by_mutbl_ref, by_move, by_copy } - -// inferable mode. -type mode = inferable<rmode>; - -type stmt = spanned<stmt_>; - -enum stmt_ { - stmt_decl(@decl, node_id), - - // expr without trailing semi-colon (must have unit type): - stmt_expr(@expr, node_id), - - // expr with trailing semi-colon (may have any type): - stmt_semi(@expr, node_id), -} - -enum init_op { init_assign, init_move, } - -type initializer = {op: init_op, expr: @expr}; - -type local_ = // FIXME: should really be a refinement on pat - {is_mutbl: bool, ty: @ty, pat: @pat, - init: option<initializer>, id: node_id}; - -type local = spanned<local_>; - -type decl = spanned<decl_>; - -enum decl_ { decl_local([@local]), decl_item(@item), } - -type arm = {pats: [@pat], guard: option<@expr>, body: blk}; - -type field_ = {mutbl: mutability, ident: ident, expr: @expr}; - -type field = spanned<field_>; - -enum blk_check_mode { default_blk, unchecked_blk, unsafe_blk, } - -enum expr_check_mode { claimed_expr, checked_expr, } - -type expr = {id: node_id, node: expr_, span: span}; - -enum alt_mode { alt_check, alt_exhaustive, } - -enum expr_ { - expr_vec([@expr], mutability), - expr_rec([field], option<@expr>), - expr_call(@expr, [@expr], bool), - expr_tup([@expr]), - expr_bind(@expr, [option<@expr>]), - expr_binary(binop, @expr, @expr), - expr_unary(unop, @expr), - expr_lit(@lit), - expr_cast(@expr, @ty), - expr_if(@expr, blk, option<@expr>), - expr_while(@expr, blk), - expr_for(@local, @expr, blk), - expr_do_while(blk, @expr), - expr_alt(@expr, [arm], alt_mode), - expr_fn(proto, fn_decl, blk, @capture_clause), - expr_fn_block(fn_decl, blk), - expr_block(blk), - - /* - * FIXME: many of these @exprs should be constrained with - * is_lval once we have constrained types working. - */ - expr_copy(@expr), - expr_move(@expr, @expr), - expr_assign(@expr, @expr), - expr_swap(@expr, @expr), - expr_assign_op(binop, @expr, @expr), - expr_field(@expr, ident, [@ty]), - expr_index(@expr, @expr), - expr_path(@path), - expr_fail(option<@expr>), - expr_break, - expr_cont, - expr_ret(option<@expr>), - expr_be(@expr), - expr_log(int, @expr, @expr), - - /* just an assert, no significance to typestate */ - expr_assert(@expr), - - /* preds that typestate is aware of */ - expr_check(expr_check_mode, @expr), - - /* FIXME Would be nice if expr_check desugared - to expr_if_check. */ - expr_if_check(@expr, blk, option<@expr>), - expr_mac(mac), -} - -type capture_item = { - id: int, - name: ident, // Currently, can only capture a local var. - span: span -}; -type capture_clause = { - copies: [@capture_item], - moves: [@capture_item] -}; - -/* -// Says whether this is a block the user marked as -// "unchecked" -enum blk_sort { - blk_unchecked, // declared as "exception to effect-checking rules" - blk_checked, // all typing rules apply -} -*/ - -type mac = spanned<mac_>; - -type mac_arg = option::t<@expr>; - -type mac_body_ = {span: span}; -type mac_body = option::t<mac_body_>; - -enum mac_ { - mac_invoc(@path, mac_arg, mac_body), - mac_embed_type(@ty), - mac_embed_block(blk), - mac_ellipsis, - // the span is used by the quoter/anti-quoter ... - mac_aq(span /* span of quote */, @expr), // anti-quote - mac_var(uint) -} - -type lit = spanned<lit_>; - -enum lit_ { - lit_str(str), - lit_int(i64, int_ty), - lit_uint(u64, uint_ty), - lit_float(str, float_ty), - lit_nil, - lit_bool(bool), -} - -// NB: If you change this, you'll probably want to change the corresponding -// type structure in middle/ty.rs as well. -type mt = {ty: @ty, mutbl: mutability}; - -type ty_field_ = {ident: ident, mt: mt}; - -type ty_field = spanned<ty_field_>; - -type ty_method = {ident: ident, attrs: [attribute], - decl: fn_decl, tps: [ty_param], span: span}; - -enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, } - -enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, } - -enum float_ty { ty_f, ty_f32, ty_f64, } - -type ty = spanned<ty_>; - -// Not represented directly in the AST, referred to by name through a ty_path. -enum prim_ty { - ty_int(int_ty), - ty_uint(uint_ty), - ty_float(float_ty), - ty_str, - ty_bool, -} - -enum ty_ { - ty_nil, - ty_bot, /* bottom type */ - ty_box(mt), - ty_uniq(mt), - ty_vec(mt), - ty_ptr(mt), - ty_rec([ty_field]), - ty_fn(proto, fn_decl), - ty_tup([@ty]), - ty_path(@path, node_id), - ty_constr(@ty, [@ty_constr]), - ty_mac(mac), - // ty_infer means the type should be inferred instead of it having been - // specified. This should only appear at the "top level" of a type and not - // nested in one. - ty_infer, -} - - -/* -A constraint arg that's a function argument is referred to by its position -rather than name. This is so we could have higher-order functions that have -constraints (potentially -- right now there's no way to write that), and also -so that the typestate pass doesn't have to map a function name onto its decl. -So, the constr_arg type is parameterized: it's instantiated with uint for -declarations, and ident for uses. -*/ -enum constr_arg_general_<T> { carg_base, carg_ident(T), carg_lit(@lit), } - -type fn_constr_arg = constr_arg_general_<uint>; -type sp_constr_arg<T> = spanned<constr_arg_general_<T>>; -type ty_constr_arg = sp_constr_arg<@path>; -type constr_arg = spanned<fn_constr_arg>; - -// Constrained types' args are parameterized by paths, since -// we refer to paths directly and not by indices. -// The implicit root of such path, in the constraint-list for a -// constrained type, is * (referring to the base record) - -type constr_general_<ARG, ID> = - {path: @path, args: [@spanned<constr_arg_general_<ARG>>], id: ID}; - -// In the front end, constraints have a node ID attached. -// Typeck turns this to a def_id, using the output of resolve. -type constr_general<ARG> = spanned<constr_general_<ARG, node_id>>; -type constr_ = constr_general_<uint, node_id>; -type constr = spanned<constr_general_<uint, node_id>>; -type ty_constr_ = constr_general_<@path, node_id>; -type ty_constr = spanned<ty_constr_>; - -/* The parser generates ast::constrs; resolve generates - a mapping from each function to a list of ty::constr_defs, - corresponding to these. */ -type arg = {mode: mode, ty: @ty, ident: ident, id: node_id}; - -type fn_decl = - {inputs: [arg], - output: @ty, - purity: purity, - cf: ret_style, - constraints: [@constr]}; - -enum purity { - pure_fn, // declared with "pure fn" - unsafe_fn, // declared with "unsafe fn" - impure_fn, // declared with "fn" - crust_fn, // declared with "crust fn" -} - -enum ret_style { - noreturn, // functions with return type _|_ that always - // raise an error or exit (i.e. never return to the caller) - return_val, // everything else -} - -type method = {ident: ident, attrs: [attribute], - tps: [ty_param], decl: fn_decl, body: blk, - id: node_id, span: span}; - -type _mod = {view_items: [@view_item], items: [@item]}; - -enum native_abi { - native_abi_rust_intrinsic, - native_abi_cdecl, - native_abi_stdcall, -} - -type native_mod = - {view_items: [@view_item], - items: [@native_item]}; - -type variant_arg = {ty: @ty, id: node_id}; - -type variant_ = {name: ident, attrs: [attribute], args: [variant_arg], - id: node_id, disr_expr: option<@expr>}; - -type variant = spanned<variant_>; - - -// FIXME: May want to just use path here, which would allow things like -// 'import ::foo' -type simple_path = [ident]; - -type path_list_ident_ = {name: ident, id: node_id}; -type path_list_ident = spanned<path_list_ident_>; - -type view_path = spanned<view_path_>; -enum view_path_ { - - // quux = foo::bar::baz - // - // or just - // - // foo::bar::baz (with 'baz =' implicitly on the left) - view_path_simple(ident, @simple_path, node_id), - - // foo::bar::* - view_path_glob(@simple_path, node_id), - - // foo::bar::{a,b,c} - view_path_list(@simple_path, [path_list_ident], node_id) -} - -type view_item = spanned<view_item_>; -enum view_item_ { - view_item_use(ident, [@meta_item], node_id), - view_item_import([@view_path]), - view_item_export([@view_path]) -} - -// Meta-data associated with an item -type attribute = spanned<attribute_>; - - -// Distinguishes between attributes that decorate items and attributes that -// are contained as statements within items. These two cases need to be -// distinguished for pretty-printing. -enum attr_style { attr_outer, attr_inner, } - -type attribute_ = {style: attr_style, value: meta_item}; - -type item = {ident: ident, attrs: [attribute], - id: node_id, node: item_, span: span}; - -enum item_ { - item_const(@ty, @expr), - item_fn(fn_decl, [ty_param], blk), - item_mod(_mod), - item_native_mod(native_mod), - item_ty(@ty, [ty_param]), - item_enum([variant], [ty_param]), - item_res(fn_decl /* dtor */, [ty_param], blk, - node_id /* dtor id */, node_id /* ctor id */), - item_class([ty_param], /* ty params for class */ - [@class_item], /* methods, etc. */ - /* (not including ctor) */ - node_id, /* ctor id */ - fn_decl, /* ctor decl */ - blk /* ctor body */ - ), - item_iface([ty_param], [ty_method]), - item_impl([ty_param], option<@ty> /* iface */, - @ty /* self */, [@method]), -} - -type class_item_ = {privacy: privacy, decl: class_member}; -type class_item = spanned<class_item_>; - -enum class_member { - instance_var(ident, @ty, class_mutability, node_id), - class_method(@item) // FIXME: methods aren't allowed to be - // type-parametric. - // without constrained types, have to duplicate some stuff. or factor out - // item to separate out things with type params? -} - -enum class_mutability { class_mutable, class_immutable } - -enum privacy { priv, pub } - -type native_item = - {ident: ident, - attrs: [attribute], - node: native_item_, - id: node_id, - span: span}; - -enum native_item_ { - native_item_fn(fn_decl, [ty_param]), -} - -// The data we save and restore about an inlined item or method. This is not -// part of the AST that we parse from a file, but it becomes part of the tree -// that we trans. -enum inlined_item { - ii_item(@item), - ii_method(def_id /* impl id */, @method) -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs deleted file mode 100644 index 04bd4236c9b..00000000000 --- a/src/comp/syntax/ast_util.rs +++ /dev/null @@ -1,443 +0,0 @@ -import codemap::span; -import ast::*; - -fn respan<T: copy>(sp: span, t: T) -> spanned<T> { - ret {node: t, span: sp}; -} - -/* assuming that we're not in macro expansion */ -fn mk_sp(lo: uint, hi: uint) -> span { - ret {lo: lo, hi: hi, expn_info: none}; -} - -// make this a const, once the compiler supports it -fn dummy_sp() -> span { ret mk_sp(0u, 0u); } - -fn path_name(p: @path) -> str { path_name_i(p.node.idents) } - -fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") } - -fn local_def(id: node_id) -> def_id { ret {crate: local_crate, node: id}; } - -fn stmt_id(s: stmt) -> node_id { - alt s.node { - stmt_decl(_, id) { id } - stmt_expr(_, id) { id } - stmt_semi(_, id) { id } - } -} - -fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} { - alt d { def_variant(enum_id, var_id) { - ret {enm: enum_id, var: var_id}; } - _ { fail "non-variant in variant_def_ids"; } } -} - -fn def_id_of_def(d: def) -> def_id { - alt d { - def_fn(id, _) | def_mod(id) | - def_native_mod(id) | def_const(id) | - def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | - def_class(id) | def_class_field(_, id) | def_class_method(_, id) { id } - - def_self(id) | def_arg(id, _) | def_local(id, _) | - def_upvar(id, _, _) | def_binding(id) { - local_def(id) - } - - def_prim_ty(_) { fail; } - } -} - -fn binop_to_str(op: binop) -> str { - alt op { - add { ret "+"; } - subtract { ret "-"; } - mul { ret "*"; } - div { ret "/"; } - rem { ret "%"; } - and { ret "&&"; } - or { ret "||"; } - bitxor { ret "^"; } - bitand { ret "&"; } - bitor { ret "|"; } - lsl { ret "<<"; } - lsr { ret ">>"; } - asr { ret ">>>"; } - eq { ret "=="; } - lt { ret "<"; } - le { ret "<="; } - ne { ret "!="; } - ge { ret ">="; } - gt { ret ">"; } - } -} - -pure fn lazy_binop(b: binop) -> bool { - alt b { and { true } or { true } _ { false } } -} - -pure fn is_shift_binop(b: binop) -> bool { - alt b { - lsl { true } - lsr { true } - asr { true } - _ { false } - } -} - -fn unop_to_str(op: unop) -> str { - alt op { - box(mt) { if mt == m_mutbl { ret "@mut "; } ret "@"; } - uniq(mt) { if mt == m_mutbl { ret "~mut "; } ret "~"; } - deref { ret "*"; } - not { ret "!"; } - neg { ret "-"; } - } -} - -fn is_path(e: @expr) -> bool { - ret alt e.node { expr_path(_) { true } _ { false } }; -} - -fn int_ty_to_str(t: int_ty) -> str { - alt t { - ty_char { "u8" } // ??? - ty_i { "" } ty_i8 { "i8" } ty_i16 { "i16" } - ty_i32 { "i32" } ty_i64 { "i64" } - } -} - -fn int_ty_max(t: int_ty) -> u64 { - alt t { - ty_i8 { 0x80u64 } - ty_i16 { 0x800u64 } - ty_i | ty_char | ty_i32 { 0x80000000u64 } // actually ni about ty_i - ty_i64 { 0x8000000000000000u64 } - } -} - -fn uint_ty_to_str(t: uint_ty) -> str { - alt t { - ty_u { "u" } ty_u8 { "u8" } ty_u16 { "u16" } - ty_u32 { "u32" } ty_u64 { "u64" } - } -} - -fn uint_ty_max(t: uint_ty) -> u64 { - alt t { - ty_u8 { 0xffu64 } - ty_u16 { 0xffffu64 } - ty_u | ty_u32 { 0xffffffffu64 } // actually ni about ty_u - ty_u64 { 0xffffffffffffffffu64 } - } -} - -fn float_ty_to_str(t: float_ty) -> str { - alt t { ty_f { "" } ty_f32 { "f32" } ty_f64 { "f64" } } -} - -fn is_exported(i: ident, m: _mod) -> bool { - let local = false; - let parent_enum : option<ident> = none; - for it: @item in m.items { - if it.ident == i { local = true; } - alt it.node { - item_enum(variants, _) { - for v: variant in variants { - if v.node.name == i { - local = true; - parent_enum = some(it.ident); - } - } - } - _ { } - } - if local { break; } - } - let has_explicit_exports = false; - for vi: @view_item in m.view_items { - alt vi.node { - view_item_export(vps) { - has_explicit_exports = true; - for vp in vps { - alt vp.node { - ast::view_path_simple(id, _, _) { - if id == i { ret true; } - alt parent_enum { - some(parent_enum_id) { - if id == parent_enum_id { ret true; } - } - _ {} - } - } - - ast::view_path_list(path, ids, _) { - if vec::len(*path) == 1u { - if i == path[0] { ret true; } - for id in ids { - if id.node.name == i { ret true; } - } - } else { - fail "export of path-qualified list"; - } - } - - // FIXME: glob-exports aren't supported yet. - _ {} - } - } - } - _ {} - } - } - // If there are no declared exports then - // everything not imported is exported - // even if it's local (since it's explicit) - ret !has_explicit_exports && local; -} - -pure fn is_call_expr(e: @expr) -> bool { - alt e.node { expr_call(_, _, _) { true } _ { false } } -} - -fn is_constraint_arg(e: @expr) -> bool { - alt e.node { - expr_lit(_) { ret true; } - expr_path(_) { ret true; } - _ { ret false; } - } -} - -fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret box::ptr_eq(a, b); } - -fn hash_ty(&&t: @ty) -> uint { - let res = (t.span.lo << 16u) + t.span.hi; - ret res; -} - -fn hash_def_id(&&id: def_id) -> uint { - (id.crate as uint << 16u) + (id.node as uint) -} - -fn eq_def_id(&&a: def_id, &&b: def_id) -> bool { - a == b -} - -fn new_def_id_hash<T: copy>() -> std::map::hashmap<def_id, T> { - std::map::mk_hashmap(hash_def_id, eq_def_id) -} - -fn block_from_expr(e: @expr) -> blk { - let blk_ = default_block([], option::some::<@expr>(e), e.id); - ret {node: blk_, span: e.span}; -} - -fn default_block(stmts1: [@stmt], expr1: option<@expr>, id1: node_id) -> - blk_ { - {view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk} -} - -// FIXME this doesn't handle big integer/float literals correctly (nor does -// the rest of our literal handling) -enum const_val { - const_float(float), - const_int(i64), - const_uint(u64), - const_str(str), -} - -// FIXME: issue #1417 -fn eval_const_expr(e: @expr) -> const_val { - fn fromb(b: bool) -> const_val { const_int(b as i64) } - alt e.node { - expr_unary(neg, inner) { - alt eval_const_expr(inner) { - const_float(f) { const_float(-f) } - const_int(i) { const_int(-i) } - const_uint(i) { const_uint(-i) } - _ { fail "eval_const_expr: bad neg argument"; } - } - } - expr_unary(not, inner) { - alt eval_const_expr(inner) { - const_int(i) { const_int(!i) } - const_uint(i) { const_uint(!i) } - _ { fail "eval_const_expr: bad not argument"; } - } - } - expr_binary(op, a, b) { - alt (eval_const_expr(a), eval_const_expr(b)) { - (const_float(a), const_float(b)) { - alt op { - add { const_float(a + b) } subtract { const_float(a - b) } - mul { const_float(a * b) } div { const_float(a / b) } - rem { const_float(a % b) } eq { fromb(a == b) } - lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } - ge { fromb(a >= b) } gt { fromb(a > b) } - _ { fail "eval_const_expr: can't apply this binop to floats"; } - } - } - (const_int(a), const_int(b)) { - alt op { - add { const_int(a + b) } subtract { const_int(a - b) } - mul { const_int(a * b) } div { const_int(a / b) } - rem { const_int(a % b) } and | bitand { const_int(a & b) } - or | bitor { const_int(a | b) } bitxor { const_int(a ^ b) } - lsl { const_int(a << b) } lsr { const_int(a >> b) } - asr { const_int(a >>> b) } - eq { fromb(a == b) } lt { fromb(a < b) } - le { fromb(a <= b) } ne { fromb(a != b) } - ge { fromb(a >= b) } gt { fromb(a > b) } - _ { fail "eval_const_expr: can't apply this binop to ints"; } - } - } - (const_uint(a), const_uint(b)) { - alt op { - add { const_uint(a + b) } subtract { const_uint(a - b) } - mul { const_uint(a * b) } div { const_uint(a / b) } - rem { const_uint(a % b) } and | bitand { const_uint(a & b) } - or | bitor { const_uint(a | b) } bitxor { const_uint(a ^ b) } - lsl { const_int((a << b) as i64) } - lsr { const_int((a >> b) as i64) } - asr { const_int((a >>> b) as i64) } - eq { fromb(a == b) } lt { fromb(a < b) } - le { fromb(a <= b) } ne { fromb(a != b) } - ge { fromb(a >= b) } gt { fromb(a > b) } - _ { fail "eval_const_expr: can't apply this binop to uints"; } - } - } - _ { fail "eval_constr_expr: bad binary arguments"; } - } - } - expr_lit(lit) { lit_to_const(lit) } - // Precondition? - _ { - fail "eval_const_expr: non-constant expression"; - } - } -} - -fn lit_to_const(lit: @lit) -> const_val { - alt lit.node { - lit_str(s) { const_str(s) } - lit_int(n, _) { const_int(n) } - lit_uint(n, _) { const_uint(n) } - lit_float(n, _) { const_float(option::get(float::from_str(n))) } - lit_nil { const_int(0i64) } - lit_bool(b) { const_int(b as i64) } - } -} - -fn compare_const_vals(a: const_val, b: const_val) -> int { - alt (a, b) { - (const_int(a), const_int(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - (const_uint(a), const_uint(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - (const_float(a), const_float(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - (const_str(a), const_str(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - _ { - fail "compare_const_vals: ill-typed comparison"; - } - } -} - -fn compare_lit_exprs(a: @expr, b: @expr) -> int { - compare_const_vals(eval_const_expr(a), eval_const_expr(b)) -} - -fn lit_expr_eq(a: @expr, b: @expr) -> bool { compare_lit_exprs(a, b) == 0 } - -fn lit_eq(a: @lit, b: @lit) -> bool { - compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0 -} - -fn ident_to_path(s: span, i: ident) -> @path { - @respan(s, {global: false, idents: [i], types: []}) -} - -pure fn is_unguarded(&&a: arm) -> bool { - alt a.guard { - none { true } - _ { false } - } -} - -pure fn unguarded_pat(a: arm) -> option<[@pat]> { - if is_unguarded(a) { some(a.pats) } else { none } -} - -// Provides an extra node_id to hang callee information on, in case the -// operator is deferred to a user-supplied method. The parser is responsible -// for reserving this id. -fn op_expr_callee_id(e: @expr) -> node_id { e.id - 1 } - -pure fn class_item_ident(ci: @class_item) -> ident { - alt ci.node.decl { - instance_var(i,_,_,_) { i } - class_method(it) { it.ident } - } -} - -impl inlined_item_methods for inlined_item { - fn ident() -> ident { - alt self { - ii_item(i) { i.ident } - ii_method(_, m) { m.ident } - } - } - - fn id() -> ast::node_id { - alt self { - ii_item(i) { i.id } - ii_method(_, m) { m.id } - } - } - - fn accept<E>(e: E, v: visit::vt<E>) { - alt self { - ii_item(i) { v.visit_item(i, e, v) } - ii_method(_, m) { visit::visit_method_helper(m, e, v) } - } - } -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/syntax/codemap.rs b/src/comp/syntax/codemap.rs deleted file mode 100644 index a7dbe574717..00000000000 --- a/src/comp/syntax/codemap.rs +++ /dev/null @@ -1,204 +0,0 @@ -type filename = str; - -type file_pos = {ch: uint, byte: uint}; - -/* A codemap is a thing that maps uints to file/line/column positions - * in a crate. This to make it possible to represent the positions - * with single-word things, rather than passing records all over the - * compiler. - */ - -enum file_substr { - fss_none, - fss_internal(span), - fss_external({filename: str, line: uint, col: uint}) -} - -type filemap = - @{name: filename, substr: file_substr, src: @str, - start_pos: file_pos, mutable lines: [file_pos]}; - -type codemap = @{mutable files: [filemap]}; - -type loc = {file: filemap, line: uint, col: uint}; - -fn new_codemap() -> codemap { @{mutable files: [] } } - -fn new_filemap_w_substr(filename: filename, substr: file_substr, - src: @str, - start_pos_ch: uint, start_pos_byte: uint) - -> filemap { - ret @{name: filename, substr: substr, src: src, - start_pos: {ch: start_pos_ch, byte: start_pos_byte}, - mutable lines: [{ch: start_pos_ch, byte: start_pos_byte}]}; -} - -fn new_filemap(filename: filename, src: @str, - start_pos_ch: uint, start_pos_byte: uint) - -> filemap { - ret new_filemap_w_substr(filename, fss_none, src, - start_pos_ch, start_pos_byte); -} - -fn mk_substr_filename(cm: codemap, sp: span) -> str -{ - let pos = lookup_char_pos(cm, sp.lo); - ret #fmt("<%s:%u:%u>", pos.file.name, pos.line, pos.col); -} - -fn next_line(file: filemap, chpos: uint, byte_pos: uint) { - file.lines += [{ch: chpos, byte: byte_pos}]; -} - -type lookup_fn = fn@(file_pos) -> uint; - -fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn) - -> {fm: filemap, line: uint} -{ - let len = vec::len(map.files); - let a = 0u; - let b = len; - while b - a > 1u { - let m = (a + b) / 2u; - if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; } - } - if (a >= len) { - fail #fmt("position %u does not resolve to a source location", pos) - } - let f = map.files[a]; - a = 0u; - b = vec::len(f.lines); - while b - a > 1u { - let m = (a + b) / 2u; - if lookup(f.lines[m]) > pos { b = m; } else { a = m; } - } - ret {fm: f, line: a}; -} - -fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc { - let {fm: f, line: a} = lookup_line(map, pos, lookup); - ret {file: f, line: a + 1u, col: pos - lookup(f.lines[a])}; -} - -fn lookup_char_pos(map: codemap, pos: uint) -> loc { - fn lookup(pos: file_pos) -> uint { ret pos.ch; } - ret lookup_pos(map, pos, lookup); -} - -fn lookup_byte_pos(map: codemap, pos: uint) -> loc { - fn lookup(pos: file_pos) -> uint { ret pos.byte; } - ret lookup_pos(map, pos, lookup); -} - -fn lookup_char_pos_adj(map: codemap, pos: uint) - -> {filename: str, line: uint, col: uint, file: option<filemap>} -{ - let loc = lookup_char_pos(map, pos); - alt (loc.file.substr) { - fss_none { - {filename: loc.file.name, line: loc.line, col: loc.col, - file: some(loc.file)} - } - fss_internal(sp) { - lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch)) - } - fss_external(eloc) { - {filename: eloc.filename, - line: eloc.line + loc.line - 1u, - col: if loc.line == 1u {eloc.col + loc.col} else {loc.col}, - file: none} - } - } -} - -fn adjust_span(map: codemap, sp: span) -> span { - fn lookup(pos: file_pos) -> uint { ret pos.ch; } - let line = lookup_line(map, sp.lo, lookup); - alt (line.fm.substr) { - fss_none {sp} - fss_internal(s) { - adjust_span(map, {lo: s.lo + (sp.lo - line.fm.start_pos.ch), - hi: s.lo + (sp.hi - line.fm.start_pos.ch), - expn_info: sp.expn_info})} - fss_external(_) {sp} - } -} - -enum expn_info_ { - expanded_from({call_site: span, - callie: {name: str, span: option<span>}}) -} -type expn_info = option<@expn_info_>; -type span = {lo: uint, hi: uint, expn_info: expn_info}; - -fn span_to_str_no_adj(sp: span, cm: codemap) -> str { - let lo = lookup_char_pos(cm, sp.lo); - let hi = lookup_char_pos(cm, sp.hi); - ret #fmt("%s:%u:%u: %u:%u", lo.file.name, - lo.line, lo.col, hi.line, hi.col) -} - -fn span_to_str(sp: span, cm: codemap) -> str { - let lo = lookup_char_pos_adj(cm, sp.lo); - let hi = lookup_char_pos_adj(cm, sp.hi); - ret #fmt("%s:%u:%u: %u:%u", lo.filename, - lo.line, lo.col, hi.line, hi.col) -} - -type file_lines = {file: filemap, lines: [uint]}; - -fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines { - let lo = lookup_char_pos(cm, sp.lo); - let hi = lookup_char_pos(cm, sp.hi); - let lines = []; - uint::range(lo.line - 1u, hi.line as uint) {|i| lines += [i]; }; - ret @{file: lo.file, lines: lines}; -} - -fn get_line(fm: filemap, line: int) -> str unsafe { - let begin: uint = fm.lines[line].byte - fm.start_pos.byte; - let end = alt str::find_char_from(*fm.src, '\n', begin) { - some(e) { e } - none { str::len(*fm.src) } - }; - str::slice(*fm.src, begin, end) -} - -fn lookup_byte_offset(cm: codemap::codemap, chpos: uint) - -> {fm: filemap, pos: uint} { - let {fm, line} = lookup_line(cm, chpos, {|pos| pos.ch}); - let line_offset = fm.lines[line].byte - fm.start_pos.byte; - let col = chpos - fm.lines[line].ch; - let col_offset = str::count_bytes(*fm.src, line_offset, col); - {fm: fm, pos: line_offset + col_offset} -} - -fn span_to_snippet(sp: span, cm: codemap::codemap) -> str { - let begin = lookup_byte_offset(cm, sp.lo); - let end = lookup_byte_offset(cm, sp.hi); - assert begin.fm == end.fm; - ret str::slice(*begin.fm.src, begin.pos, end.pos); -} - -fn get_snippet(cm: codemap::codemap, fidx: uint, lo: uint, hi: uint) -> str -{ - let fm = cm.files[fidx]; - ret str::slice(*fm.src, lo, hi) -} - -fn get_filemap(cm: codemap, filename: str) -> filemap { - for fm: filemap in cm.files { if fm.name == filename { ret fm; } } - //XXjdm the following triggers a mismatched type bug - // (or expected function, found _|_) - fail; // ("asking for " + filename + " which we don't know about"); -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/ext/base.rs b/src/comp/syntax/ext/base.rs deleted file mode 100644 index d59591d849a..00000000000 --- a/src/comp/syntax/ext/base.rs +++ /dev/null @@ -1,157 +0,0 @@ -import std::map::hashmap; -import driver::session::session; -import codemap::{span, expn_info, expanded_from}; -import std::map::new_str_hash; - -type syntax_expander_ = - fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> @ast::expr; -type syntax_expander = { - expander: syntax_expander_, - span: option<span>}; -type macro_def = {ident: str, ext: syntax_extension}; -type macro_definer = - fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def; - -enum syntax_extension { - normal(syntax_expander), - macro_defining(macro_definer), -} - -// A temporary hard-coded map of methods for expanding syntax extension -// AST nodes into full ASTs -fn syntax_expander_table() -> hashmap<str, syntax_extension> { - fn builtin(f: syntax_expander_) -> syntax_extension - {normal({expander: f, span: none})} - let syntax_expanders = new_str_hash::<syntax_extension>(); - syntax_expanders.insert("fmt", builtin(ext::fmt::expand_syntax_ext)); - syntax_expanders.insert("env", builtin(ext::env::expand_syntax_ext)); - syntax_expanders.insert("macro", - macro_defining(ext::simplext::add_new_extension)); - syntax_expanders.insert("concat_idents", - builtin(ext::concat_idents::expand_syntax_ext)); - syntax_expanders.insert("ident_to_str", - builtin(ext::ident_to_str::expand_syntax_ext)); - syntax_expanders.insert("log_syntax", - builtin(ext::log_syntax::expand_syntax_ext)); - syntax_expanders.insert("ast", - builtin(ext::qquote::expand_ast)); - ret syntax_expanders; -} - -iface ext_ctxt { - fn session() -> session; - fn print_backtrace(); - fn backtrace() -> expn_info; - fn bt_push(ei: codemap::expn_info_); - fn bt_pop(); - fn span_fatal(sp: span, msg: str) -> !; - fn span_err(sp: span, msg: str); - fn span_unimpl(sp: span, msg: str) -> !; - fn span_bug(sp: span, msg: str) -> !; - fn bug(msg: str) -> !; - fn next_id() -> ast::node_id; -} - -fn mk_ctxt(sess: session) -> ext_ctxt { - type ctxt_repr = {sess: session, - mutable backtrace: expn_info}; - impl of ext_ctxt for ctxt_repr { - fn session() -> session { self.sess } - fn print_backtrace() { } - fn backtrace() -> expn_info { self.backtrace } - fn bt_push(ei: codemap::expn_info_) { - alt ei { - expanded_from({call_site: cs, callie: callie}) { - self.backtrace = - some(@expanded_from({ - call_site: {lo: cs.lo, hi: cs.hi, - expn_info: self.backtrace}, - callie: callie})); - } - } - } - fn bt_pop() { - alt self.backtrace { - some(@expanded_from({call_site: {expn_info: prev, _}, _})) { - self.backtrace = prev - } - _ { self.bug("tried to pop without a push"); } - } - } - fn span_fatal(sp: span, msg: str) -> ! { - self.print_backtrace(); - self.sess.span_fatal(sp, msg); - } - fn span_err(sp: span, msg: str) { - self.print_backtrace(); - self.sess.span_err(sp, msg); - } - fn span_unimpl(sp: span, msg: str) -> ! { - self.print_backtrace(); - self.sess.span_unimpl(sp, msg); - } - fn span_bug(sp: span, msg: str) -> ! { - self.print_backtrace(); - self.sess.span_bug(sp, msg); - } - fn bug(msg: str) -> ! { self.print_backtrace(); self.sess.bug(msg); } - fn next_id() -> ast::node_id { ret self.sess.next_node_id(); } - } - let imp : ctxt_repr = {sess: sess, mutable backtrace: none}; - ret imp as ext_ctxt -} - -fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, error: str) -> str { - alt expr.node { - ast::expr_lit(l) { - alt l.node { - ast::lit_str(s) { ret s; } - _ { cx.span_fatal(l.span, error); } - } - } - _ { cx.span_fatal(expr.span, error); } - } -} - -fn expr_to_ident(cx: ext_ctxt, expr: @ast::expr, error: str) -> ast::ident { - alt expr.node { - ast::expr_path(p) { - if vec::len(p.node.types) > 0u || vec::len(p.node.idents) != 1u { - cx.span_fatal(expr.span, error); - } else { ret p.node.idents[0]; } - } - _ { cx.span_fatal(expr.span, error); } - } -} - -fn make_new_lit(cx: ext_ctxt, sp: codemap::span, lit: ast::lit_) -> - @ast::expr { - let sp_lit = @{node: lit, span: sp}; - ret @{id: cx.next_id(), node: ast::expr_lit(sp_lit), span: sp}; -} - -fn get_mac_arg(cx: ext_ctxt, sp: span, arg: ast::mac_arg) -> @ast::expr { - alt (arg) { - some(expr) {expr} - none {cx.span_fatal(sp, "missing macro args")} - } -} - -fn get_mac_body(cx: ext_ctxt, sp: span, args: ast::mac_body) - -> ast::mac_body_ -{ - alt (args) { - some(body) {body} - none {cx.span_fatal(sp, "missing macro body")} - } -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/ext/build.rs b/src/comp/syntax/ext/build.rs deleted file mode 100644 index 5d615c4305d..00000000000 --- a/src/comp/syntax/ext/build.rs +++ /dev/null @@ -1,81 +0,0 @@ -import codemap::span; -import syntax::ext::base::ext_ctxt; - -// NOTE: Moved from fmt.rs which had this fixme: -// FIXME: Cleanup the naming of these functions - -fn mk_lit(cx: ext_ctxt, sp: span, lit: ast::lit_) -> @ast::expr { - let sp_lit = @{node: lit, span: sp}; - ret @{id: cx.next_id(), node: ast::expr_lit(sp_lit), span: sp}; -} -fn mk_str(cx: ext_ctxt, sp: span, s: str) -> @ast::expr { - let lit = ast::lit_str(s); - ret mk_lit(cx, sp, lit); -} -fn mk_int(cx: ext_ctxt, sp: span, i: int) -> @ast::expr { - let lit = ast::lit_int(i as i64, ast::ty_i); - ret mk_lit(cx, sp, lit); -} -fn mk_uint(cx: ext_ctxt, sp: span, u: uint) -> @ast::expr { - let lit = ast::lit_uint(u as u64, ast::ty_u); - ret mk_lit(cx, sp, lit); -} -fn mk_binary(cx: ext_ctxt, sp: span, op: ast::binop, - lhs: @ast::expr, rhs: @ast::expr) - -> @ast::expr { - let binexpr = ast::expr_binary(op, lhs, rhs); - ret @{id: cx.next_id(), node: binexpr, span: sp}; -} -fn mk_unary(cx: ext_ctxt, sp: span, op: ast::unop, e: @ast::expr) - -> @ast::expr { - let expr = ast::expr_unary(op, e); - ret @{id: cx.next_id(), node: expr, span: sp}; -} -fn mk_path(cx: ext_ctxt, sp: span, idents: [ast::ident]) -> - @ast::expr { - let path = {global: false, idents: idents, types: []}; - let sp_path = @{node: path, span: sp}; - let pathexpr = ast::expr_path(sp_path); - ret @{id: cx.next_id(), node: pathexpr, span: sp}; -} -fn mk_access_(cx: ext_ctxt, sp: span, p: @ast::expr, m: ast::ident) - -> @ast::expr { - let expr = ast::expr_field(p, m, []); - ret @{id: cx.next_id(), node: expr, span: sp}; -} -fn mk_access(cx: ext_ctxt, sp: span, p: [ast::ident], m: ast::ident) - -> @ast::expr { - let pathexpr = mk_path(cx, sp, p); - ret mk_access_(cx, sp, pathexpr, m); -} -fn mk_call_(cx: ext_ctxt, sp: span, fn_expr: @ast::expr, - args: [@ast::expr]) -> @ast::expr { - let callexpr = ast::expr_call(fn_expr, args, false); - ret @{id: cx.next_id(), node: callexpr, span: sp}; -} -fn mk_call(cx: ext_ctxt, sp: span, fn_path: [ast::ident], - args: [@ast::expr]) -> @ast::expr { - let pathexpr = mk_path(cx, sp, fn_path); - ret mk_call_(cx, sp, pathexpr, args); -} -// e = expr, t = type -fn mk_vec_e(cx: ext_ctxt, sp: span, exprs: [@ast::expr]) -> - @ast::expr { - let vecexpr = ast::expr_vec(exprs, ast::m_imm); - ret @{id: cx.next_id(), node: vecexpr, span: sp}; -} -fn mk_rec_e(cx: ext_ctxt, sp: span, - fields: [{ident: ast::ident, ex: @ast::expr}]) -> - @ast::expr { - let astfields: [ast::field] = []; - for field: {ident: ast::ident, ex: @ast::expr} in fields { - let ident = field.ident; - let val = field.ex; - let astfield = - {node: {mutbl: ast::m_imm, ident: ident, expr: val}, span: sp}; - astfields += [astfield]; - } - let recexpr = ast::expr_rec(astfields, option::none::<@ast::expr>); - ret @{id: cx.next_id(), node: recexpr, span: sp}; -} - diff --git a/src/comp/syntax/ext/concat_idents.rs b/src/comp/syntax/ext/concat_idents.rs deleted file mode 100644 index 4b9402f9cd9..00000000000 --- a/src/comp/syntax/ext/concat_idents.rs +++ /dev/null @@ -1,24 +0,0 @@ -import base::*; -import syntax::ast; - -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let arg = get_mac_arg(cx,sp,arg); - let args: [@ast::expr] = - alt arg.node { - ast::expr_vec(elts, _) { elts } - _ { - cx.span_fatal(sp, "#concat_idents requires a vector argument .") - } - }; - let res: ast::ident = ""; - for e: @ast::expr in args { - res += expr_to_ident(cx, e, "expected an ident"); - } - - ret @{id: cx.next_id(), - node: ast::expr_path(@{node: {global: false, idents: [res], - types: []}, - span: sp}), - span: sp}; -} diff --git a/src/comp/syntax/ext/env.rs b/src/comp/syntax/ext/env.rs deleted file mode 100644 index cb9453ae062..00000000000 --- a/src/comp/syntax/ext/env.rs +++ /dev/null @@ -1,45 +0,0 @@ - -/* - * The compiler code necessary to support the #env extension. Eventually this - * should all get sucked into either the compiler syntax extension plugin - * interface. - */ -import std::generic_os; -import base::*; -export expand_syntax_ext; - -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let arg = get_mac_arg(cx,sp,arg); - let args: [@ast::expr] = - alt arg.node { - ast::expr_vec(elts, _) { elts } - _ { - cx.span_fatal(sp, "#env requires arguments of the form `[...]`.") - } - }; - if vec::len::<@ast::expr>(args) != 1u { - cx.span_fatal(sp, "malformed #env call"); - } - // FIXME: if this was more thorough it would manufacture an - // option<str> rather than just an maybe-empty string. - - let var = expr_to_str(cx, args[0], "#env requires a string"); - alt generic_os::getenv(var) { - option::none { ret make_new_str(cx, sp, ""); } - option::some(s) { ret make_new_str(cx, sp, s); } - } -} - -fn make_new_str(cx: ext_ctxt, sp: codemap::span, s: str) -> @ast::expr { - ret make_new_lit(cx, sp, ast::lit_str(s)); -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/ext/expand.rs b/src/comp/syntax/ext/expand.rs deleted file mode 100644 index 104f49aebac..00000000000 --- a/src/comp/syntax/ext/expand.rs +++ /dev/null @@ -1,102 +0,0 @@ -import driver::session; - -import std::map::hashmap; - -import syntax::ast::{crate, expr_, expr_mac, mac_invoc}; -import syntax::fold::*; -import syntax::ext::base::*; -import syntax::ext::qquote::{qq_helper}; -import syntax::parse::parser::parse_expr_from_source_str; - -import codemap::{span, expanded_from}; - -fn expand_expr(exts: hashmap<str, syntax_extension>, cx: ext_ctxt, - e: expr_, s: span, fld: ast_fold, - orig: fn@(expr_, span, ast_fold) -> (expr_, span)) - -> (expr_, span) -{ - ret alt e { - expr_mac(mac) { - alt mac.node { - mac_invoc(pth, args, body) { - assert (vec::len(pth.node.idents) > 0u); - let extname = pth.node.idents[0]; - alt exts.find(extname) { - none { - cx.span_fatal(pth.span, - #fmt["macro undefined: '%s'", extname]) - } - some(normal({expander: exp, span: exp_sp})) { - let expanded = exp(cx, pth.span, args, body); - - let info = {call_site: s, - callie: {name: extname, span: exp_sp}}; - cx.bt_push(expanded_from(info)); - //keep going, outside-in - let fully_expanded = fld.fold_expr(expanded).node; - cx.bt_pop(); - - (fully_expanded, s) - } - some(macro_defining(ext)) { - let named_extension = ext(cx, pth.span, args, body); - exts.insert(named_extension.ident, named_extension.ext); - (ast::expr_rec([], none), s) - } - } - } - _ { cx.span_bug(mac.span, "naked syntactic bit") } - } - } - _ { orig(e, s, fld) } - }; -} - -fn new_span(cx: ext_ctxt, sp: span) -> span { - /* this discards information in the case of macro-defining macros */ - ret {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()}; -} - -// FIXME: this is a terrible kludge to inject some macros into the default -// compilation environment. When the macro-definition system is substantially -// more mature, these should move from here, into a compiled part of libcore -// at very least. - -fn core_macros() -> str { - ret -"{ - #macro([#error[f, ...], log(core::error, #fmt[f, ...])]); - #macro([#warn[f, ...], log(core::warn, #fmt[f, ...])]); - #macro([#info[f, ...], log(core::info, #fmt[f, ...])]); - #macro([#debug[f, ...], log(core::debug, #fmt[f, ...])]); -}"; -} - -fn expand_crate(sess: session::session, c: @crate) -> @crate { - let exts = syntax_expander_table(); - let afp = default_ast_fold(); - let cx: ext_ctxt = mk_ctxt(sess); - let f_pre = - {fold_expr: bind expand_expr(exts, cx, _, _, _, afp.fold_expr), - new_span: bind new_span(cx, _) - with *afp}; - let f = make_fold(f_pre); - let cm = parse_expr_from_source_str("<core-macros>", - @core_macros(), - sess.opts.cfg, - sess.parse_sess); - - // This is run for its side-effects on the expander env, - // as it registers all the core macros as expanders. - f.fold_expr(cm); - - let res = @f.fold_crate(*c); - ret res; -} -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/syntax/ext/fmt.rs b/src/comp/syntax/ext/fmt.rs deleted file mode 100644 index 29b19a2d66c..00000000000 --- a/src/comp/syntax/ext/fmt.rs +++ /dev/null @@ -1,300 +0,0 @@ - - -/* - * The compiler code necessary to support the #fmt extension. Eventually this - * should all get sucked into either the standard library extfmt module or the - * compiler syntax extension plugin interface. - */ -import extfmt::ct::*; -import base::*; -import codemap::span; -import syntax::ext::build::*; -export expand_syntax_ext; - -fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let arg = get_mac_arg(cx,sp,arg); - let args: [@ast::expr] = - alt arg.node { - ast::expr_vec(elts, _) { elts } - _ { - cx.span_fatal(sp, "#fmt requires arguments of the form `[...]`.") - } - }; - if vec::len::<@ast::expr>(args) == 0u { - cx.span_fatal(sp, "#fmt requires a format string"); - } - let fmt = - expr_to_str(cx, args[0], - "first argument to #fmt must be a string literal."); - let fmtspan = args[0].span; - #debug("Format string:"); - log(debug, fmt); - fn parse_fmt_err_(cx: ext_ctxt, sp: span, msg: str) -> ! { - cx.span_fatal(sp, msg); - } - let parse_fmt_err = bind parse_fmt_err_(cx, fmtspan, _); - let pieces = parse_fmt_string(fmt, parse_fmt_err); - ret pieces_to_expr(cx, sp, pieces, args); -} - -// FIXME: A lot of these functions for producing expressions can probably -// be factored out in common with other code that builds expressions. -// FIXME: Cleanup the naming of these functions -// NOTE: Moved many of the common ones to build.rs --kevina -fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr]) - -> @ast::expr { - fn make_path_vec(_cx: ext_ctxt, ident: ast::ident) -> [ast::ident] { - ret ["extfmt", "rt", ident]; - } - fn make_rt_path_expr(cx: ext_ctxt, sp: span, ident: str) -> @ast::expr { - let path = make_path_vec(cx, ident); - ret mk_path(cx, sp, path); - } - // Produces an AST expression that represents a RT::conv record, - // which tells the RT::conv* functions how to perform the conversion - - fn make_rt_conv_expr(cx: ext_ctxt, sp: span, cnv: conv) -> @ast::expr { - fn make_flags(cx: ext_ctxt, sp: span, flags: [flag]) -> @ast::expr { - let flagexprs: [@ast::expr] = []; - for f: flag in flags { - let fstr; - alt f { - flag_left_justify { fstr = "flag_left_justify"; } - flag_left_zero_pad { fstr = "flag_left_zero_pad"; } - flag_space_for_sign { fstr = "flag_space_for_sign"; } - flag_sign_always { fstr = "flag_sign_always"; } - flag_alternate { fstr = "flag_alternate"; } - } - flagexprs += [make_rt_path_expr(cx, sp, fstr)]; - } - // FIXME: 0-length vectors can't have their type inferred - // through the rec that these flags are a member of, so - // this is a hack placeholder flag - - if vec::len::<@ast::expr>(flagexprs) == 0u { - flagexprs += [make_rt_path_expr(cx, sp, "flag_none")]; - } - ret mk_vec_e(cx, sp, flagexprs); - } - fn make_count(cx: ext_ctxt, sp: span, cnt: count) -> @ast::expr { - alt cnt { - count_implied { - ret make_rt_path_expr(cx, sp, "count_implied"); - } - count_is(c) { - let count_lit = mk_int(cx, sp, c); - let count_is_path = make_path_vec(cx, "count_is"); - let count_is_args = [count_lit]; - ret mk_call(cx, sp, count_is_path, count_is_args); - } - _ { cx.span_unimpl(sp, "unimplemented #fmt conversion"); } - } - } - fn make_ty(cx: ext_ctxt, sp: span, t: ty) -> @ast::expr { - let rt_type; - alt t { - ty_hex(c) { - alt c { - case_upper { rt_type = "ty_hex_upper"; } - case_lower { rt_type = "ty_hex_lower"; } - } - } - ty_bits { rt_type = "ty_bits"; } - ty_octal { rt_type = "ty_octal"; } - _ { rt_type = "ty_default"; } - } - ret make_rt_path_expr(cx, sp, rt_type); - } - fn make_conv_rec(cx: ext_ctxt, sp: span, flags_expr: @ast::expr, - width_expr: @ast::expr, precision_expr: @ast::expr, - ty_expr: @ast::expr) -> @ast::expr { - ret mk_rec_e(cx, sp, - [{ident: "flags", ex: flags_expr}, - {ident: "width", ex: width_expr}, - {ident: "precision", ex: precision_expr}, - {ident: "ty", ex: ty_expr}]); - } - let rt_conv_flags = make_flags(cx, sp, cnv.flags); - let rt_conv_width = make_count(cx, sp, cnv.width); - let rt_conv_precision = make_count(cx, sp, cnv.precision); - let rt_conv_ty = make_ty(cx, sp, cnv.ty); - ret make_conv_rec(cx, sp, rt_conv_flags, rt_conv_width, - rt_conv_precision, rt_conv_ty); - } - fn make_conv_call(cx: ext_ctxt, sp: span, conv_type: str, cnv: conv, - arg: @ast::expr) -> @ast::expr { - let fname = "conv_" + conv_type; - let path = make_path_vec(cx, fname); - let cnv_expr = make_rt_conv_expr(cx, sp, cnv); - let args = [cnv_expr, arg]; - ret mk_call(cx, arg.span, path, args); - } - fn make_new_conv(cx: ext_ctxt, sp: span, cnv: conv, arg: @ast::expr) -> - @ast::expr { - // FIXME: Extract all this validation into extfmt::ct - - fn is_signed_type(cnv: conv) -> bool { - alt cnv.ty { - ty_int(s) { - alt s { signed { ret true; } unsigned { ret false; } } - } - ty_float { ret true; } - _ { ret false; } - } - } - let unsupported = "conversion not supported in #fmt string"; - alt cnv.param { - option::none { } - _ { cx.span_unimpl(sp, unsupported); } - } - for f: flag in cnv.flags { - alt f { - flag_left_justify { } - flag_sign_always { - if !is_signed_type(cnv) { - cx.span_fatal(sp, - "+ flag only valid in " + - "signed #fmt conversion"); - } - } - flag_space_for_sign { - if !is_signed_type(cnv) { - cx.span_fatal(sp, - "space flag only valid in " + - "signed #fmt conversions"); - } - } - flag_left_zero_pad { } - _ { cx.span_unimpl(sp, unsupported); } - } - } - alt cnv.width { - count_implied { } - count_is(_) { } - _ { cx.span_unimpl(sp, unsupported); } - } - alt cnv.precision { - count_implied { } - count_is(_) { } - _ { cx.span_unimpl(sp, unsupported); } - } - alt cnv.ty { - ty_str { ret make_conv_call(cx, arg.span, "str", cnv, arg); } - ty_int(sign) { - alt sign { - signed { ret make_conv_call(cx, arg.span, "int", cnv, arg); } - unsigned { - ret make_conv_call(cx, arg.span, "uint", cnv, arg); - } - } - } - ty_bool { ret make_conv_call(cx, arg.span, "bool", cnv, arg); } - ty_char { ret make_conv_call(cx, arg.span, "char", cnv, arg); } - ty_hex(_) { ret make_conv_call(cx, arg.span, "uint", cnv, arg); } - ty_bits { ret make_conv_call(cx, arg.span, "uint", cnv, arg); } - ty_octal { ret make_conv_call(cx, arg.span, "uint", cnv, arg); } - ty_float { ret make_conv_call(cx, arg.span, "float", cnv, arg); } - ty_poly { ret make_conv_call(cx, arg.span, "poly", cnv, arg); } - _ { cx.span_unimpl(sp, unsupported); } - } - } - fn log_conv(c: conv) { - alt c.param { - some(p) { log(debug, "param: " + int::to_str(p, 10u)); } - _ { #debug("param: none"); } - } - for f: flag in c.flags { - alt f { - flag_left_justify { #debug("flag: left justify"); } - flag_left_zero_pad { #debug("flag: left zero pad"); } - flag_space_for_sign { #debug("flag: left space pad"); } - flag_sign_always { #debug("flag: sign always"); } - flag_alternate { #debug("flag: alternate"); } - } - } - alt c.width { - count_is(i) { log(debug, - "width: count is " + int::to_str(i, 10u)); } - count_is_param(i) { - log(debug, - "width: count is param " + int::to_str(i, 10u)); - } - count_is_next_param { #debug("width: count is next param"); } - count_implied { #debug("width: count is implied"); } - } - alt c.precision { - count_is(i) { log(debug, - "prec: count is " + int::to_str(i, 10u)); } - count_is_param(i) { - log(debug, - "prec: count is param " + int::to_str(i, 10u)); - } - count_is_next_param { #debug("prec: count is next param"); } - count_implied { #debug("prec: count is implied"); } - } - alt c.ty { - ty_bool { #debug("type: bool"); } - ty_str { #debug("type: str"); } - ty_char { #debug("type: char"); } - ty_int(s) { - alt s { - signed { #debug("type: signed"); } - unsigned { #debug("type: unsigned"); } - } - } - ty_bits { #debug("type: bits"); } - ty_hex(cs) { - alt cs { - case_upper { #debug("type: uhex"); } - case_lower { #debug("type: lhex"); } - } - } - ty_octal { #debug("type: octal"); } - ty_float { #debug("type: float"); } - ty_poly { #debug("type: poly"); } - } - } - let fmt_sp = args[0].span; - let n = 0u; - let tmp_expr = mk_str(cx, sp, ""); - let nargs = vec::len::<@ast::expr>(args); - for pc: piece in pieces { - alt pc { - piece_string(s) { - let s_expr = mk_str(cx, fmt_sp, s); - tmp_expr = mk_binary(cx, fmt_sp, ast::add, tmp_expr, s_expr); - } - piece_conv(conv) { - n += 1u; - if n >= nargs { - cx.span_fatal(sp, - "not enough arguments to #fmt " + - "for the given format string"); - } - #debug("Building conversion:"); - log_conv(conv); - let arg_expr = args[n]; - let c_expr = make_new_conv(cx, fmt_sp, conv, arg_expr); - tmp_expr = mk_binary(cx, fmt_sp, ast::add, tmp_expr, c_expr); - } - } - } - let expected_nargs = n + 1u; // n conversions + the fmt string - - if expected_nargs < nargs { - cx.span_fatal - (sp, #fmt["too many arguments to #fmt. found %u, expected %u", - nargs, expected_nargs]); - } - ret tmp_expr; -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/ext/ident_to_str.rs b/src/comp/syntax/ext/ident_to_str.rs deleted file mode 100644 index 2bb6dac7f2a..00000000000 --- a/src/comp/syntax/ext/ident_to_str.rs +++ /dev/null @@ -1,22 +0,0 @@ -import base::*; -import syntax::ast; - -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let arg = get_mac_arg(cx,sp,arg); - let args: [@ast::expr] = - alt arg.node { - ast::expr_vec(elts, _) { elts } - _ { - cx.span_fatal(sp, "#ident_to_str requires a vector argument .") - } - }; - if vec::len::<@ast::expr>(args) != 1u { - cx.span_fatal(sp, "malformed #ident_to_str call"); - } - - ret make_new_lit(cx, sp, - ast::lit_str(expr_to_ident(cx, args[0u], - "expected an ident"))); - -} diff --git a/src/comp/syntax/ext/log_syntax.rs b/src/comp/syntax/ext/log_syntax.rs deleted file mode 100644 index 911cf9ff2eb..00000000000 --- a/src/comp/syntax/ext/log_syntax.rs +++ /dev/null @@ -1,13 +0,0 @@ -import base::*; -import syntax::ast; -import std::io::writer_util; - -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let arg = get_mac_arg(cx,sp,arg); - cx.print_backtrace(); - std::io::stdout().write_line(print::pprust::expr_to_str(arg)); - - //trivial expression - ret @{id: cx.next_id(), node: ast::expr_rec([], option::none), span: sp}; -} diff --git a/src/comp/syntax/ext/qquote.rs b/src/comp/syntax/ext/qquote.rs deleted file mode 100644 index 7f7d5a387f0..00000000000 --- a/src/comp/syntax/ext/qquote.rs +++ /dev/null @@ -1,338 +0,0 @@ -import driver::session; - -import syntax::ast::{crate, expr_, mac_invoc, - mac_aq, mac_var}; -import syntax::fold::*; -import syntax::visit::*; -import syntax::ext::base::*; -import syntax::ext::build::*; -import syntax::parse::parser; -import syntax::parse::parser::{parser, parse_from_source_str}; - -import syntax::print::*; -import std::io::*; - -import codemap::span; - -type aq_ctxt = @{lo: uint, - mutable gather: [{lo: uint, hi: uint, - e: @ast::expr, - constr: str}]}; -enum fragment { - from_expr(@ast::expr), - from_ty(@ast::ty) -} - -iface qq_helper { - fn span() -> span; - fn visit(aq_ctxt, vt<aq_ctxt>); - fn extract_mac() -> option<ast::mac_>; - fn mk_parse_fn(ext_ctxt,span) -> @ast::expr; - fn get_fold_fn() -> str; -} - -impl of qq_helper for @ast::crate { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_crate(*self, cx, v);} - fn extract_mac() -> option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_crate"]) - } - fn get_fold_fn() -> str {"fold_crate"} -} -impl of qq_helper for @ast::expr { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_expr(self, cx, v);} - fn extract_mac() -> option<ast::mac_> { - alt (self.node) { - ast::expr_mac({node: mac, _}) {some(mac)} - _ {none} - } - } - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ["syntax", "parse", "parser", "parse_expr"]) - } - fn get_fold_fn() -> str {"fold_expr"} -} -impl of qq_helper for @ast::ty { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_ty(self, cx, v);} - fn extract_mac() -> option<ast::mac_> { - alt (self.node) { - ast::ty_mac({node: mac, _}) {some(mac)} - _ {none} - } - } - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_ty"]) - } - fn get_fold_fn() -> str {"fold_ty"} -} -impl of qq_helper for @ast::item { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_item(self, cx, v);} - fn extract_mac() -> option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_item"]) - } - fn get_fold_fn() -> str {"fold_item"} -} -impl of qq_helper for @ast::stmt { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_stmt(self, cx, v);} - fn extract_mac() -> option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_stmt"]) - } - fn get_fold_fn() -> str {"fold_stmt"} -} -impl of qq_helper for @ast::pat { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_pat(self, cx, v);} - fn extract_mac() -> option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ["syntax", "parse", "parser", "parse_pat"]) - } - fn get_fold_fn() -> str {"fold_pat"} -} - -fn gather_anti_quotes<N: qq_helper>(lo: uint, node: N) -> aq_ctxt -{ - let v = @{visit_expr: visit_aq_expr, - visit_ty: visit_aq_ty - with *default_visitor()}; - let cx = @{lo:lo, mutable gather: []}; - node.visit(cx, mk_vt(v)); - ret cx; -} - -fn visit_aq<T:qq_helper>(node: T, constr: str, &&cx: aq_ctxt, v: vt<aq_ctxt>) -{ - alt (node.extract_mac()) { - some(mac_aq(sp, e)) { - cx.gather += [{lo: sp.lo - cx.lo, hi: sp.hi - cx.lo, - e: e, constr: constr}]; - } - _ {node.visit(cx, v);} - } -} -// FIXME: these are only here because I (kevina) couldn't figure out how to -// get bind to work in gather_anti_quotes -fn visit_aq_expr(node: @ast::expr, &&cx: aq_ctxt, v: vt<aq_ctxt>) { - visit_aq(node,"from_expr",cx,v); -} -fn visit_aq_ty(node: @ast::ty, &&cx: aq_ctxt, v: vt<aq_ctxt>) { - visit_aq(node,"from_ty",cx,v); -} - -fn is_space(c: char) -> bool { - syntax::parse::lexer::is_whitespace(c) -} - -fn expand_ast(ecx: ext_ctxt, _sp: span, - arg: ast::mac_arg, body: ast::mac_body) - -> @ast::expr -{ - let what = "expr"; - option::may(arg) {|arg| - let args: [@ast::expr] = - alt arg.node { - ast::expr_vec(elts, _) { elts } - _ { - ecx.span_fatal - (_sp, "#ast requires arguments of the form `[...]`.") - } - }; - if vec::len::<@ast::expr>(args) != 1u { - ecx.span_fatal(_sp, "#ast requires exactly one arg"); - } - alt (args[0].node) { - ast::expr_path(@{node: {idents: id, _},_}) if vec::len(id) == 1u - {what = id[0]} - _ {ecx.span_fatal(args[0].span, "expected an identifier");} - } - } - let body = get_mac_body(ecx,_sp,body); - - ret alt what { - "crate" {finish(ecx, body, parse_crate)} - "expr" {finish(ecx, body, parser::parse_expr)} - "ty" {finish(ecx, body, parse_ty)} - "item" {finish(ecx, body, parse_item)} - "stmt" {finish(ecx, body, parse_stmt)} - "pat" {finish(ecx, body, parser::parse_pat)} - _ {ecx.span_fatal(_sp, "unsupported ast type")} - }; -} - -fn parse_crate(p: parser) -> @ast::crate { - parser::parse_crate_mod(p, []) -} - -fn parse_ty(p: parser) -> @ast::ty { - parser::parse_ty(p, false) -} - -fn parse_stmt(p: parser) -> @ast::stmt { - parser::parse_stmt(p, []) -} - -fn parse_item(p: parser) -> @ast::item { - alt (parser::parse_item(p, [])) { - some(item) {item} - none {fail; /* FIXME: Error message, somehow */} - } -} - -fn finish<T: qq_helper> - (ecx: ext_ctxt, body: ast::mac_body_, f: fn (p: parser) -> T) - -> @ast::expr -{ - let cm = ecx.session().parse_sess.cm; - let str = @codemap::span_to_snippet(body.span, cm); - let fname = codemap::mk_substr_filename(cm, body.span); - let node = parse_from_source_str - (f, fname, codemap::fss_internal(body.span), str, - ecx.session().opts.cfg, ecx.session().parse_sess); - let loc = codemap::lookup_char_pos(cm, body.span.lo); - - let sp = node.span(); - let qcx = gather_anti_quotes(sp.lo, node); - let cx = qcx; - - // assert that the vector is sorted by position: - uint::range(1u, vec::len(cx.gather)) {|i| - assert cx.gather[i-1u].lo < cx.gather[i].lo; - } - - let str2 = ""; - enum state {active, skip(uint), blank}; - let state = active; - let i = 0u, j = 0u; - let g_len = vec::len(cx.gather); - str::chars_iter(*str) {|ch| - if (j < g_len && i == cx.gather[j].lo) { - assert ch == '$'; - let repl = #fmt("$%u ", j); - state = skip(str::char_len(repl)); - str2 += repl; - } - alt state { - active {str::push_char(str2, ch);} - skip(1u) {state = blank;} - skip(sk) {state = skip (sk-1u);} - blank if is_space(ch) {str::push_char(str2, ch);} - blank {str::push_char(str2, ' ');} - } - i += 1u; - if (j < g_len && i == cx.gather[j].hi) { - assert ch == ')'; - state = active; - j += 1u; - } - } - - let cx = ecx; - let session_call = bind mk_call_(cx,sp, - mk_access(cx,sp,["ext_cx"], "session"), - []); - let pcall = mk_call(cx,sp, - ["syntax", "parse", "parser", - "parse_from_source_str"], - [node.mk_parse_fn(cx,sp), - mk_str(cx,sp, fname), - mk_call(cx,sp, - ["syntax","ext","qquote", "mk_file_substr"], - [mk_str(cx,sp, loc.file.name), - mk_uint(cx,sp, loc.line), - mk_uint(cx,sp, loc.col)]), - mk_unary(cx,sp, ast::box(ast::m_imm), - mk_str(cx,sp, str2)), - mk_access_(cx,sp, - mk_access_(cx,sp, session_call(), "opts"), - "cfg"), - mk_access_(cx,sp, session_call(), "parse_sess")] - ); - let rcall = pcall; - if (g_len > 0u) { - rcall = mk_call(cx,sp, - ["syntax", "ext", "qquote", "replace"], - [pcall, - mk_vec_e(cx,sp, vec::map(copy qcx.gather) {|g| - mk_call(cx,sp, - ["syntax", "ext", "qquote", g.constr], - [g.e])}), - mk_path(cx,sp, - ["syntax", "ext", "qquote", - node.get_fold_fn()])]); - } - ret rcall; -} - -fn replace<T>(node: T, repls: [fragment], ff: fn (ast_fold, T) -> T) - -> T -{ - let aft = default_ast_fold(); - let f_pre = {fold_expr: bind replace_expr(repls, _, _, _, - aft.fold_expr), - fold_ty: bind replace_ty(repls, _, _, _, - aft.fold_ty) - with *aft}; - ret ff(make_fold(f_pre), node); -} -fn fold_crate(f: ast_fold, &&n: @ast::crate) -> @ast::crate { - @f.fold_crate(*n) -} -fn fold_expr(f: ast_fold, &&n: @ast::expr) -> @ast::expr {f.fold_expr(n)} -fn fold_ty(f: ast_fold, &&n: @ast::ty) -> @ast::ty {f.fold_ty(n)} -fn fold_item(f: ast_fold, &&n: @ast::item) -> @ast::item {f.fold_item(n)} -fn fold_stmt(f: ast_fold, &&n: @ast::stmt) -> @ast::stmt {f.fold_stmt(n)} -fn fold_pat(f: ast_fold, &&n: @ast::pat) -> @ast::pat {f.fold_pat(n)} - -fn replace_expr(repls: [fragment], - e: ast::expr_, s: span, fld: ast_fold, - orig: fn@(ast::expr_, span, ast_fold)->(ast::expr_, span)) - -> (ast::expr_, span) -{ - alt e { - ast::expr_mac({node: mac_var(i), _}) { - alt (repls[i]) { - from_expr(r) {(r.node, r.span)} - _ {fail /* fixme error message */}}} - _ {orig(e,s,fld)} - } -} - -fn replace_ty(repls: [fragment], - e: ast::ty_, s: span, fld: ast_fold, - orig: fn@(ast::ty_, span, ast_fold)->(ast::ty_, span)) - -> (ast::ty_, span) -{ - alt e { - ast::ty_mac({node: mac_var(i), _}) { - alt (repls[i]) { - from_ty(r) {(r.node, r.span)} - _ {fail /* fixme error message */}}} - _ {orig(e,s,fld)} - } -} - -fn print_expr(expr: @ast::expr) { - let stdout = std::io::stdout(); - let pp = pprust::rust_printer(stdout); - pprust::print_expr(pp, expr); - pp::eof(pp.s); - stdout.write_str("\n"); -} - -fn mk_file_substr(fname: str, line: uint, col: uint) -> codemap::file_substr { - codemap::fss_external({filename: fname, line: line, col: col}) -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/syntax/ext/simplext.rs b/src/comp/syntax/ext/simplext.rs deleted file mode 100644 index 1baf5f97d20..00000000000 --- a/src/comp/syntax/ext/simplext.rs +++ /dev/null @@ -1,779 +0,0 @@ -use std; - -import codemap::span; -import std::map::{hashmap, new_str_hash}; -import driver::session::session; - -import base::*; - -import fold::*; -import ast_util::respan; -import ast::{ident, path, ty, blk_, expr, path_, expr_path, - expr_vec, expr_mac, mac_invoc, node_id}; - -export add_new_extension; - -fn path_to_ident(pth: @path) -> option<ident> { - if vec::len(pth.node.idents) == 1u && vec::len(pth.node.types) == 0u { - ret some(pth.node.idents[0u]); - } - ret none; -} - -//a vec of binders might be a little big. -type clause = {params: binders, body: @expr}; - -/* logically, an arb_depth should contain only one kind of matchable */ -enum arb_depth<T> { leaf(T), seq(@[arb_depth<T>], span), } - - -enum matchable { - match_expr(@expr), - match_path(@path), - match_ident(ast::spanned<ident>), - match_ty(@ty), - match_block(ast::blk), - match_exact, /* don't bind anything, just verify the AST traversal */ -} - -/* for when given an incompatible bit of AST */ -fn match_error(cx: ext_ctxt, m: matchable, expected: str) -> ! { - alt m { - match_expr(x) { - cx.span_fatal(x.span, - "this argument is an expr, expected " + expected); - } - match_path(x) { - cx.span_fatal(x.span, - "this argument is a path, expected " + expected); - } - match_ident(x) { - cx.span_fatal(x.span, - "this argument is an ident, expected " + expected); - } - match_ty(x) { - cx.span_fatal(x.span, - "this argument is a type, expected " + expected); - } - match_block(x) { - cx.span_fatal(x.span, - "this argument is a block, expected " + expected); - } - match_exact { cx.bug("what is a match_exact doing in a bindings?"); } - } -} - -// We can't make all the matchables in a match_result the same type because -// idents can be paths, which can be exprs. - -// If we want better match failure error messages (like in Fortifying Syntax), -// we'll want to return something indicating amount of progress and location -// of failure instead of `none`. -type match_result = option<arb_depth<matchable>>; -type selector = fn@(matchable) -> match_result; - -fn elts_to_ell(cx: ext_ctxt, elts: [@expr]) -> - {pre: [@expr], rep: option<@expr>, post: [@expr]} { - let idx: uint = 0u; - let res = none; - for elt: @expr in elts { - alt elt.node { - expr_mac(m) { - alt m.node { - ast::mac_ellipsis { - if res != none { - cx.span_fatal(m.span, "only one ellipsis allowed"); - } - res = - some({pre: vec::slice(elts, 0u, idx - 1u), - rep: some(elts[idx - 1u]), - post: vec::slice(elts, idx + 1u, vec::len(elts))}); - } - _ { } - } - } - _ { } - } - idx += 1u; - } - ret alt res { - some(val) { val } - none { {pre: elts, rep: none, post: []} } - } -} - -fn option_flatten_map<T: copy, U: copy>(f: fn@(T) -> option<U>, v: [T]) -> - option<[U]> { - let res = []; - for elem: T in v { - alt f(elem) { none { ret none; } some(fv) { res += [fv]; } } - } - ret some(res); -} - -fn a_d_map(ad: arb_depth<matchable>, f: selector) -> match_result { - alt ad { - leaf(x) { ret f(x); } - seq(ads, span) { - alt option_flatten_map(bind a_d_map(_, f), *ads) { - none { ret none; } - some(ts) { ret some(seq(@ts, span)); } - } - } - } -} - -fn compose_sels(s1: selector, s2: selector) -> selector { - fn scomp(s1: selector, s2: selector, m: matchable) -> match_result { - ret alt s1(m) { - none { none } - some(matches) { a_d_map(matches, s2) } - } - } - ret bind scomp(s1, s2, _); -} - - - -type binders = - {real_binders: hashmap<ident, selector>, - mutable literal_ast_matchers: [selector]}; -type bindings = hashmap<ident, arb_depth<matchable>>; - -fn acumm_bindings(_cx: ext_ctxt, _b_dest: bindings, _b_src: bindings) { } - -/* these three functions are the big moving parts */ - -/* create the selectors needed to bind and verify the pattern */ - -fn pattern_to_selectors(cx: ext_ctxt, e: @expr) -> binders { - let res: binders = - {real_binders: new_str_hash::<selector>(), - mutable literal_ast_matchers: []}; - //this oughta return binders instead, but macro args are a sequence of - //expressions, rather than a single expression - fn trivial_selector(m: matchable) -> match_result { ret some(leaf(m)); } - p_t_s_rec(cx, match_expr(e), trivial_selector, res); - ret res; -} - - - -/* use the selectors on the actual arguments to the macro to extract -bindings. Most of the work is done in p_t_s, which generates the -selectors. */ - -fn use_selectors_to_bind(b: binders, e: @expr) -> option<bindings> { - let res = new_str_hash::<arb_depth<matchable>>(); - //need to do this first, to check vec lengths. - for sel: selector in b.literal_ast_matchers { - alt sel(match_expr(e)) { none { ret none; } _ { } } - } - let never_mind: bool = false; - b.real_binders.items {|key, val| - alt val(match_expr(e)) { - none { never_mind = true; } - some(mtc) { res.insert(key, mtc); } - } - }; - //HACK: `ret` doesn't work in `for each` - if never_mind { ret none; } - ret some(res); -} - -/* use the bindings on the body to generate the expanded code */ - -fn transcribe(cx: ext_ctxt, b: bindings, body: @expr) -> @expr { - let idx_path: @mutable [uint] = @mutable []; - fn new_id(_old: node_id, cx: ext_ctxt) -> node_id { ret cx.next_id(); } - fn new_span(cx: ext_ctxt, sp: span) -> span { - /* this discards information in the case of macro-defining macros */ - ret {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()}; - } - let afp = default_ast_fold(); - let f_pre = - {fold_ident: bind transcribe_ident(cx, b, idx_path, _, _), - fold_path: bind transcribe_path(cx, b, idx_path, _, _, _), - fold_expr: - bind transcribe_expr(cx, b, idx_path, _, _, _, afp.fold_expr), - fold_ty: bind transcribe_type(cx, b, idx_path, _, _, _, afp.fold_ty), - fold_block: - bind transcribe_block(cx, b, idx_path, _, _, _, afp.fold_block), - map_exprs: bind transcribe_exprs(cx, b, idx_path, _, _), - new_id: bind new_id(_, cx) - with *afp}; - let f = make_fold(f_pre); - let result = f.fold_expr(body); - ret result; -} - - -/* helper: descend into a matcher */ -fn follow(m: arb_depth<matchable>, idx_path: @mutable [uint]) -> - arb_depth<matchable> { - let res: arb_depth<matchable> = m; - for idx: uint in *idx_path { - alt res { - leaf(_) { ret res;/* end of the line */ } - seq(new_ms, _) { res = new_ms[idx]; } - } - } - ret res; -} - -fn follow_for_trans(cx: ext_ctxt, mmaybe: option<arb_depth<matchable>>, - idx_path: @mutable [uint]) -> option<matchable> { - alt mmaybe { - none { ret none } - some(m) { - ret alt follow(m, idx_path) { - seq(_, sp) { - cx.span_fatal(sp, - "syntax matched under ... but not " + - "used that way.") - } - leaf(m) { ret some(m) } - } - } - } - -} - -/* helper for transcribe_exprs: what vars from `b` occur in `e`? */ -fn free_vars(b: bindings, e: @expr, it: fn(ident)) { - let idents: hashmap<ident, ()> = new_str_hash::<()>(); - fn mark_ident(&&i: ident, _fld: ast_fold, b: bindings, - idents: hashmap<ident, ()>) -> ident { - if b.contains_key(i) { idents.insert(i, ()); } - ret i; - } - // using fold is a hack: we want visit, but it doesn't hit idents ) : - // solve this with macros - let f_pre = - {fold_ident: bind mark_ident(_, _, b, idents) - with *default_ast_fold()}; - let f = make_fold(f_pre); - f.fold_expr(e); // ignore result - idents.keys {|x| it(x); }; -} - - -/* handle sequences (anywhere in the AST) of exprs, either real or ...ed */ -fn transcribe_exprs(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint], - recur: fn@(&&@expr) -> @expr, exprs: [@expr]) -> [@expr] { - alt elts_to_ell(cx, exprs) { - {pre: pre, rep: repeat_me_maybe, post: post} { - let res = vec::map(pre, recur); - alt repeat_me_maybe { - none { } - some(repeat_me) { - let repeat: option<{rep_count: uint, name: ident}> = none; - /* we need to walk over all the free vars in lockstep, except for - the leaves, which are just duplicated */ - free_vars(b, repeat_me) {|fv| - let cur_pos = follow(b.get(fv), idx_path); - alt cur_pos { - leaf(_) { } - seq(ms, _) { - alt repeat { - none { - repeat = some({rep_count: vec::len(*ms), name: fv}); - } - some({rep_count: old_len, name: old_name}) { - let len = vec::len(*ms); - if old_len != len { - let msg = - #fmt["'%s' occurs %u times, but ", fv, len] + - #fmt["'%s' occurs %u times", old_name, - old_len]; - cx.span_fatal(repeat_me.span, msg); - } - } - } - } - } - }; - alt repeat { - none { - cx.span_fatal(repeat_me.span, - "'...' surrounds an expression without any" + - " repeating syntax variables"); - } - some({rep_count: rc, _}) { - /* Whew, we now know how how many times to repeat */ - let idx: uint = 0u; - while idx < rc { - *idx_path += [idx]; - res += [recur(repeat_me)]; // whew! - vec::pop(*idx_path); - idx += 1u; - } - } - } - } - } - res += vec::map(post, recur); - ret res; - } - } -} - - - -// substitute, in a position that's required to be an ident -fn transcribe_ident(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint], - &&i: ident, _fld: ast_fold) -> ident { - ret alt follow_for_trans(cx, b.find(i), idx_path) { - some(match_ident(a_id)) { a_id.node } - some(m) { match_error(cx, m, "an identifier") } - none { i } - } -} - - -fn transcribe_path(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint], - p: path_, s:span, _fld: ast_fold) -> (path_, span) { - // Don't substitute into qualified names. - if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { ret (p, s); } - ret alt follow_for_trans(cx, b.find(p.idents[0]), idx_path) { - some(match_ident(id)) { - ({global: false, idents: [id.node], types: []}, id.span) - } - some(match_path(a_pth)) { (a_pth.node, a_pth.span) } - some(m) { match_error(cx, m, "a path") } - none { (p, s) } - } -} - - -fn transcribe_expr(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint], - e: ast::expr_, s: span, fld: ast_fold, - orig: fn@(ast::expr_, span, ast_fold)->(ast::expr_, span)) - -> (ast::expr_, span) -{ - ret alt e { - expr_path(p) { - // Don't substitute into qualified names. - if vec::len(p.node.types) > 0u || vec::len(p.node.idents) != 1u { - (e, s); - } - alt follow_for_trans(cx, b.find(p.node.idents[0]), idx_path) { - some(match_ident(id)) { - (expr_path(@respan(id.span, - {global: false, - idents: [id.node], - types: []})), id.span) - } - some(match_path(a_pth)) { (expr_path(a_pth), s) } - some(match_expr(a_exp)) { (a_exp.node, a_exp.span) } - some(m) { match_error(cx, m, "an expression") } - none { orig(e, s, fld) } - } - } - _ { orig(e, s, fld) } - } -} - -fn transcribe_type(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint], - t: ast::ty_, s: span, fld: ast_fold, - orig: fn@(ast::ty_, span, ast_fold) -> (ast::ty_, span)) - -> (ast::ty_, span) -{ - ret alt t { - ast::ty_path(pth, _) { - alt path_to_ident(pth) { - some(id) { - alt follow_for_trans(cx, b.find(id), idx_path) { - some(match_ty(ty)) { (ty.node, ty.span) } - some(m) { match_error(cx, m, "a type") } - none { orig(t, s, fld) } - } - } - none { orig(t, s, fld) } - } - } - _ { orig(t, s, fld) } - } -} - - -/* for parsing reasons, syntax variables bound to blocks must be used like -`{v}` */ - -fn transcribe_block(cx: ext_ctxt, b: bindings, idx_path: @mutable [uint], - blk: blk_, s: span, fld: ast_fold, - orig: fn@(blk_, span, ast_fold) -> (blk_, span)) - -> (blk_, span) -{ - ret alt block_to_ident(blk) { - some(id) { - alt follow_for_trans(cx, b.find(id), idx_path) { - some(match_block(new_blk)) { (new_blk.node, new_blk.span) } - - - - - - // possibly allow promotion of ident/path/expr to blocks? - some(m) { - match_error(cx, m, "a block") - } - none { orig(blk, s, fld) } - } - } - none { orig(blk, s, fld) } - } -} - - -/* traverse the pattern, building instructions on how to bind the actual -argument. ps accumulates instructions on navigating the tree.*/ -fn p_t_s_rec(cx: ext_ctxt, m: matchable, s: selector, b: binders) { - - //it might be possible to traverse only exprs, not matchables - alt m { - match_expr(e) { - alt e.node { - expr_path(p_pth) { p_t_s_r_path(cx, p_pth, s, b); } - expr_vec(p_elts, _) { - alt elts_to_ell(cx, p_elts) { - {pre: pre, rep: some(repeat_me), post: post} { - p_t_s_r_length(cx, vec::len(pre) + vec::len(post), true, s, - b); - if vec::len(pre) > 0u { - p_t_s_r_actual_vector(cx, pre, true, s, b); - } - p_t_s_r_ellipses(cx, repeat_me, vec::len(pre), s, b); - - if vec::len(post) > 0u { - cx.span_unimpl(e.span, - "matching after `...` not yet supported"); - } - } - {pre: pre, rep: none, post: post} { - if post != [] { - cx.bug("elts_to_ell provided an invalid result"); - } - p_t_s_r_length(cx, vec::len(pre), false, s, b); - p_t_s_r_actual_vector(cx, pre, false, s, b); - } - } - } - /* FIXME: handle embedded types and blocks, at least */ - expr_mac(mac) { - p_t_s_r_mac(cx, mac, s, b); - } - _ { - fn select(cx: ext_ctxt, m: matchable, pat: @expr) -> - match_result { - ret alt m { - match_expr(e) { - if e == pat { some(leaf(match_exact)) } else { none } - } - _ { cx.bug("broken traversal in p_t_s_r") } - } - } - b.literal_ast_matchers += [bind select(cx, _, e)]; - } - } - } - _ { - cx.session().bug("undocumented invariant in p_t_s_rec"); - } - } -} - - -/* make a match more precise */ -fn specialize_match(m: matchable) -> matchable { - ret alt m { - match_expr(e) { - alt e.node { - expr_path(pth) { - alt path_to_ident(pth) { - some(id) { match_ident(respan(pth.span, id)) } - none { match_path(pth) } - } - } - _ { m } - } - } - _ { m } - } -} - -/* pattern_to_selectors helper functions */ -fn p_t_s_r_path(cx: ext_ctxt, p: @path, s: selector, b: binders) { - alt path_to_ident(p) { - some(p_id) { - fn select(cx: ext_ctxt, m: matchable) -> match_result { - ret alt m { - match_expr(e) { some(leaf(specialize_match(m))) } - _ { cx.bug("broken traversal in p_t_s_r") } - } - } - if b.real_binders.contains_key(p_id) { - cx.span_fatal(p.span, "duplicate binding identifier"); - } - b.real_binders.insert(p_id, compose_sels(s, bind select(cx, _))); - } - none { } - } -} - -fn block_to_ident(blk: blk_) -> option<ident> { - if vec::len(blk.stmts) != 0u { ret none; } - ret alt blk.expr { - some(expr) { - alt expr.node { expr_path(pth) { path_to_ident(pth) } _ { none } } - } - none { none } - } -} - -fn p_t_s_r_mac(cx: ext_ctxt, mac: ast::mac, s: selector, b: binders) { - fn select_pt_1(cx: ext_ctxt, m: matchable, - fn_m: fn(ast::mac) -> match_result) -> match_result { - ret alt m { - match_expr(e) { - alt e.node { expr_mac(mac) { fn_m(mac) } _ { none } } - } - _ { cx.bug("broken traversal in p_t_s_r") } - } - } - fn no_des(cx: ext_ctxt, sp: span, syn: str) -> ! { - cx.span_fatal(sp, "destructuring " + syn + " is not yet supported"); - } - alt mac.node { - ast::mac_ellipsis { cx.span_fatal(mac.span, "misused `...`"); } - ast::mac_invoc(_, _, _) { no_des(cx, mac.span, "macro calls"); } - ast::mac_embed_type(ty) { - alt ty.node { - ast::ty_path(pth, _) { - alt path_to_ident(pth) { - some(id) { - /* look for an embedded type */ - fn select_pt_2(m: ast::mac) -> match_result { - ret alt m.node { - ast::mac_embed_type(t) { some(leaf(match_ty(t))) } - _ { none } - } - } - let final_step = bind select_pt_1(cx, _, select_pt_2); - b.real_binders.insert(id, compose_sels(s, final_step)); - } - none { no_des(cx, pth.span, "under `#<>`"); } - } - } - _ { no_des(cx, ty.span, "under `#<>`"); } - } - } - ast::mac_embed_block(blk) { - alt block_to_ident(blk.node) { - some(id) { - fn select_pt_2(m: ast::mac) -> match_result { - ret alt m.node { - ast::mac_embed_block(blk) { - some(leaf(match_block(blk))) - } - _ { none } - } - } - let final_step = bind select_pt_1(cx, _, select_pt_2); - b.real_binders.insert(id, compose_sels(s, final_step)); - } - none { no_des(cx, blk.span, "under `#{}`"); } - } - } - ast::mac_aq(_,_) { no_des(cx, mac.span, "antiquotes"); } - ast::mac_var(_) { no_des(cx, mac.span, "antiquote variables"); } - } -} - -fn p_t_s_r_ellipses(cx: ext_ctxt, repeat_me: @expr, offset: uint, s: selector, - b: binders) { - fn select(cx: ext_ctxt, repeat_me: @expr, offset: uint, m: matchable) -> - match_result { - ret alt m { - match_expr(e) { - alt e.node { - expr_vec(arg_elts, _) { - let elts = []; - let idx = offset; - while idx < vec::len(arg_elts) { - elts += [leaf(match_expr(arg_elts[idx]))]; - idx += 1u; - } - - // using repeat_me.span is a little wacky, but the - // error we want to report is one in the macro def - some(seq(@elts, repeat_me.span)) - } - _ { none } - } - } - _ { cx.bug("broken traversal in p_t_s_r") } - } - } - p_t_s_rec(cx, match_expr(repeat_me), - compose_sels(s, bind select(cx, repeat_me, offset, _)), b); -} - - -fn p_t_s_r_length(cx: ext_ctxt, len: uint, at_least: bool, s: selector, - b: binders) { - fn len_select(_cx: ext_ctxt, m: matchable, at_least: bool, len: uint) -> - match_result { - ret alt m { - match_expr(e) { - alt e.node { - expr_vec(arg_elts, _) { - let actual_len = vec::len(arg_elts); - if at_least && actual_len >= len || actual_len == len { - some(leaf(match_exact)) - } else { none } - } - _ { none } - } - } - _ { none } - } - } - b.literal_ast_matchers += - [compose_sels(s, bind len_select(cx, _, at_least, len))]; -} - -fn p_t_s_r_actual_vector(cx: ext_ctxt, elts: [@expr], _repeat_after: bool, - s: selector, b: binders) { - let idx: uint = 0u; - while idx < vec::len(elts) { - fn select(cx: ext_ctxt, m: matchable, idx: uint) -> match_result { - ret alt m { - match_expr(e) { - alt e.node { - expr_vec(arg_elts, _) { - some(leaf(match_expr(arg_elts[idx]))) - } - _ { none } - } - } - _ { cx.bug("broken traversal in p_t_s_r") } - } - } - p_t_s_rec(cx, match_expr(elts[idx]), - compose_sels(s, bind select(cx, _, idx)), b); - idx += 1u; - } -} - -fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> base::macro_def { - let arg = get_mac_arg(cx,sp,arg); - let args: [@ast::expr] = - alt arg.node { - ast::expr_vec(elts, _) { elts } - _ { - cx.span_fatal(sp, - "#macro requires arguments of the form `[...]`.") - } - }; - - let macro_name: option<str> = none; - let clauses: [@clause] = []; - for arg: @expr in args { - alt arg.node { - expr_vec(elts, mutbl) { - if vec::len(elts) != 2u { - cx.span_fatal((*arg).span, - "extension clause must consist of [" + - "macro invocation, expansion body]"); - } - - - alt elts[0u].node { - expr_mac(mac) { - alt mac.node { - mac_invoc(pth, invoc_arg, body) { - alt path_to_ident(pth) { - some(id) { - alt macro_name { - none { macro_name = some(id); } - some(other_id) { - if id != other_id { - cx.span_fatal(pth.span, - "macro name must be " + - "consistent"); - } - } - } - } - none { - cx.span_fatal(pth.span, - "macro name must not be a path"); - } - } - clauses += - [@{params: pattern_to_selectors - (cx, get_mac_arg(cx,mac.span,invoc_arg)), - body: elts[1u]}]; - - // FIXME: check duplicates (or just simplify - // the macro arg situation) - } - _ { - cx.span_bug(mac.span, "undocumented invariant in \ - add_extension"); - } - } - } - _ { - cx.span_fatal(elts[0u].span, - "extension clause must" + - " start with a macro invocation."); - } - } - } - _ { - cx.span_fatal((*arg).span, - "extension must be [clause, " + " ...]"); - } - } - } - - let ext = bind generic_extension(_, _, _, _, clauses); - - ret {ident: - alt macro_name { - some(id) { id } - none { - cx.span_fatal(sp, - "macro definition must have " + - "at least one clause") - } - }, - ext: normal({expander: ext, span: some(arg.span)})}; - - fn generic_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body, clauses: [@clause]) -> @expr { - let arg = get_mac_arg(cx,sp,arg); - for c: @clause in clauses { - alt use_selectors_to_bind(c.params, arg) { - some(bindings) { ret transcribe(cx, bindings, c.body); } - none { cont; } - } - } - cx.span_fatal(sp, "no clauses match macro invocation"); - } -} - - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs deleted file mode 100644 index 7ceae548769..00000000000 --- a/src/comp/syntax/fold.rs +++ /dev/null @@ -1,761 +0,0 @@ -import syntax::codemap::span; -import ast::*; - -export ast_fold_precursor; -export ast_fold; -export default_ast_fold; -export make_fold; -export noop_fold_crate; -export noop_fold_item; -export noop_fold_expr; -export noop_fold_pat; -export noop_fold_mod; -export noop_fold_ty; -export wrap; - -type ast_fold = @mutable a_f; - -// We may eventually want to be able to fold over type parameters, too - -type ast_fold_precursor = - //unlike the others, item_ is non-trivial - {fold_crate: fn@(crate_, span, ast_fold) -> (crate_, span), - fold_crate_directive: fn@(crate_directive_, span, - ast_fold) -> (crate_directive_, span), - fold_view_item: fn@(view_item_, ast_fold) -> view_item_, - fold_native_item: fn@(&&@native_item, ast_fold) -> @native_item, - fold_item: fn@(&&@item, ast_fold) -> @item, - fold_class_item: fn@(&&@class_item, ast_fold) -> @class_item, - fold_item_underscore: fn@(item_, ast_fold) -> item_, - fold_method: fn@(&&@method, ast_fold) -> @method, - fold_block: fn@(blk_, span, ast_fold) -> (blk_, span), - fold_stmt: fn@(stmt_, span, ast_fold) -> (stmt_, span), - fold_arm: fn@(arm, ast_fold) -> arm, - fold_pat: fn@(pat_, span, ast_fold) -> (pat_, span), - fold_decl: fn@(decl_, span, ast_fold) -> (decl_, span), - fold_expr: fn@(expr_, span, ast_fold) -> (expr_, span), - fold_ty: fn@(ty_, span, ast_fold) -> (ty_, span), - fold_constr: fn@(ast::constr_, span, ast_fold) -> (constr_, span), - fold_mod: fn@(_mod, ast_fold) -> _mod, - fold_native_mod: fn@(native_mod, ast_fold) -> native_mod, - fold_variant: fn@(variant_, span, ast_fold) -> (variant_, span), - fold_ident: fn@(&&ident, ast_fold) -> ident, - fold_path: fn@(path_, span, ast_fold) -> (path_, span), - fold_local: fn@(local_, span, ast_fold) -> (local_, span), - map_exprs: fn@(fn@(&&@expr) -> @expr, [@expr]) -> [@expr], - new_id: fn@(node_id) -> node_id, - new_span: fn@(span) -> span}; - -type a_f = - {fold_crate: fn@(crate) -> crate, - fold_crate_directive: fn@(&&@crate_directive) -> @crate_directive, - fold_view_item: fn@(&&@view_item) -> @view_item, - fold_native_item: fn@(&&@native_item) -> @native_item, - fold_item: fn@(&&@item) -> @item, - fold_class_item: fn@(&&@class_item) -> @class_item, - fold_item_underscore: fn@(item_) -> item_, - fold_method: fn@(&&@method) -> @method, - fold_block: fn@(blk) -> blk, - fold_stmt: fn@(&&@stmt) -> @stmt, - fold_arm: fn@(arm) -> arm, - fold_pat: fn@(&&@pat) -> @pat, - fold_decl: fn@(&&@decl) -> @decl, - fold_expr: fn@(&&@expr) -> @expr, - fold_ty: fn@(&&@ty) -> @ty, - fold_constr: fn@(&&@constr) -> @constr, - fold_mod: fn@(_mod) -> _mod, - fold_native_mod: fn@(native_mod) -> native_mod, - fold_variant: fn@(variant) -> variant, - fold_ident: fn@(&&ident) -> ident, - fold_path: fn@(&&@path) -> @path, - fold_local: fn@(&&@local) -> @local, - map_exprs: fn@(fn@(&&@expr) -> @expr, [@expr]) -> [@expr], - new_id: fn@(node_id) -> node_id, - new_span: fn@(span) -> span}; - - -//fn nf_dummy<T>(&T node) -> T { fail; } -fn nf_crate_dummy(_c: crate) -> crate { fail; } -fn nf_crate_directive_dummy(&&_c: @crate_directive) -> @crate_directive { - fail; -} -fn nf_view_item_dummy(&&_v: @view_item) -> @view_item { fail; } -fn nf_native_item_dummy(&&_n: @native_item) -> @native_item { fail; } -fn nf_item_dummy(&&_i: @item) -> @item { fail; } -fn nf_class_item_dummy(&&_ci: @class_item) -> @class_item { fail; } -fn nf_item_underscore_dummy(_i: item_) -> item_ { fail; } -fn nf_method_dummy(&&_m: @method) -> @method { fail; } -fn nf_blk_dummy(_b: blk) -> blk { fail; } -fn nf_stmt_dummy(&&_s: @stmt) -> @stmt { fail; } -fn nf_arm_dummy(_a: arm) -> arm { fail; } -fn nf_pat_dummy(&&_p: @pat) -> @pat { fail; } -fn nf_decl_dummy(&&_d: @decl) -> @decl { fail; } -fn nf_expr_dummy(&&_e: @expr) -> @expr { fail; } -fn nf_ty_dummy(&&_t: @ty) -> @ty { fail; } -fn nf_constr_dummy(&&_c: @constr) -> @constr { fail; } -fn nf_mod_dummy(_m: _mod) -> _mod { fail; } -fn nf_native_mod_dummy(_n: native_mod) -> native_mod { fail; } -fn nf_variant_dummy(_v: variant) -> variant { fail; } -fn nf_ident_dummy(&&_i: ident) -> ident { fail; } -fn nf_path_dummy(&&_p: @path) -> @path { fail; } -fn nf_local_dummy(&&_o: @local) -> @local { fail; } - -/* some little folds that probably aren't useful to have in ast_fold itself*/ - -//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive -fn fold_meta_item_(&&mi: @meta_item, fld: ast_fold) -> @meta_item { - ret @{node: - alt mi.node { - meta_word(id) { meta_word(fld.fold_ident(id)) } - meta_list(id, mis) { - let fold_meta_item = bind fold_meta_item_(_, fld); - meta_list(id, vec::map(mis, fold_meta_item)) - } - meta_name_value(id, s) { - meta_name_value(fld.fold_ident(id), s) - } - }, - span: mi.span}; -} -//used in noop_fold_item and noop_fold_crate -fn fold_attribute_(at: attribute, fmi: fn@(&&@meta_item) -> @meta_item) -> - attribute { - ret {node: {style: at.node.style, value: *fmi(@at.node.value)}, - span: at.span}; -} -//used in noop_fold_native_item and noop_fold_fn_decl -fn fold_arg_(a: arg, fld: ast_fold) -> arg { - ret {mode: a.mode, - ty: fld.fold_ty(a.ty), - ident: fld.fold_ident(a.ident), - id: fld.new_id(a.id)}; -} -//used in noop_fold_expr, and possibly elsewhere in the future -fn fold_mac_(m: mac, fld: ast_fold) -> mac { - ret {node: - alt m.node { - mac_invoc(pth, arg, body) { - mac_invoc(fld.fold_path(pth), - // FIXME: bind should work, but causes a crash - option::map(arg) {|arg| fld.fold_expr(arg)}, - body) - } - mac_embed_type(ty) { mac_embed_type(fld.fold_ty(ty)) } - mac_embed_block(blk) { mac_embed_block(fld.fold_block(blk)) } - mac_ellipsis { mac_ellipsis } - mac_aq(_,_) { /* fixme */ m.node } - mac_var(_) { /* fixme */ m.node } - }, - span: m.span}; -} - -fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl { - ret {inputs: vec::map(decl.inputs, bind fold_arg_(_, fld)), - output: fld.fold_ty(decl.output), - purity: decl.purity, - cf: decl.cf, - constraints: vec::map(decl.constraints, fld.fold_constr)} -} - -fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound { - alt tpb { - bound_copy | bound_send { tpb } - bound_iface(ty) { bound_iface(fld.fold_ty(ty)) } - } -} - -fn fold_ty_param(tp: ty_param, fld: ast_fold) -> ty_param { - {ident: tp.ident, - id: fld.new_id(tp.id), - bounds: @vec::map(*tp.bounds, fold_ty_param_bound(_, fld))} -} - -fn fold_ty_params(tps: [ty_param], fld: ast_fold) -> [ty_param] { - vec::map(tps, fold_ty_param(_, fld)) -} - -fn noop_fold_crate(c: crate_, fld: ast_fold) -> crate_ { - let fold_meta_item = bind fold_meta_item_(_, fld); - let fold_attribute = bind fold_attribute_(_, fold_meta_item); - - ret {directives: vec::map(c.directives, fld.fold_crate_directive), - module: fld.fold_mod(c.module), - attrs: vec::map(c.attrs, fold_attribute), - config: vec::map(c.config, fold_meta_item)}; -} - -fn noop_fold_crate_directive(cd: crate_directive_, fld: ast_fold) -> - crate_directive_ { - ret alt cd { - cdir_src_mod(id, attrs) { - cdir_src_mod(fld.fold_ident(id), attrs) - } - cdir_dir_mod(id, cds, attrs) { - cdir_dir_mod(fld.fold_ident(id), - vec::map(cds, fld.fold_crate_directive), attrs) - } - cdir_view_item(vi) { cdir_view_item(fld.fold_view_item(vi)) } - cdir_syntax(_) { cd } - } -} - -fn noop_fold_view_item(vi: view_item_, _fld: ast_fold) -> view_item_ { - ret vi; -} - - -fn noop_fold_native_item(&&ni: @native_item, fld: ast_fold) -> @native_item { - let fold_arg = bind fold_arg_(_, fld); - let fold_meta_item = bind fold_meta_item_(_, fld); - let fold_attribute = bind fold_attribute_(_, fold_meta_item); - - ret @{ident: fld.fold_ident(ni.ident), - attrs: vec::map(ni.attrs, fold_attribute), - node: - alt ni.node { - native_item_fn(fdec, typms) { - native_item_fn({inputs: vec::map(fdec.inputs, fold_arg), - output: fld.fold_ty(fdec.output), - purity: fdec.purity, - cf: fdec.cf, - constraints: - vec::map(fdec.constraints, - fld.fold_constr)}, - fold_ty_params(typms, fld)) - } - }, - id: fld.new_id(ni.id), - span: fld.new_span(ni.span)}; -} - -fn noop_fold_item(&&i: @item, fld: ast_fold) -> @item { - let fold_meta_item = bind fold_meta_item_(_, fld); - let fold_attribute = bind fold_attribute_(_, fold_meta_item); - - ret @{ident: fld.fold_ident(i.ident), - attrs: vec::map(i.attrs, fold_attribute), - id: fld.new_id(i.id), - node: fld.fold_item_underscore(i.node), - span: fld.new_span(i.span)}; -} - -fn noop_fold_class_item(&&ci: @class_item, fld: ast_fold) - -> @class_item { - @{node: { - privacy:ci.node.privacy, - decl: - alt ci.node.decl { - instance_var(ident, t, cm, id) { - instance_var(ident, fld.fold_ty(t), cm, id) - } - class_method(i) { class_method(fld.fold_item(i)) } - }}, - span: ci.span} -} - -fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ { - ret alt i { - item_const(t, e) { item_const(fld.fold_ty(t), fld.fold_expr(e)) } - item_fn(decl, typms, body) { - item_fn(fold_fn_decl(decl, fld), - fold_ty_params(typms, fld), - fld.fold_block(body)) - } - item_mod(m) { item_mod(fld.fold_mod(m)) } - item_native_mod(nm) { item_native_mod(fld.fold_native_mod(nm)) } - item_ty(t, typms) { item_ty(fld.fold_ty(t), - fold_ty_params(typms, fld)) } - item_enum(variants, typms) { - item_enum(vec::map(variants, fld.fold_variant), - fold_ty_params(typms, fld)) - } - item_class(typms, items, id, ctor_decl, ctor_body) { - item_class(fold_ty_params(typms, fld), - vec::map(items, fld.fold_class_item), - id, - fold_fn_decl(ctor_decl, fld), - fld.fold_block(ctor_body)) - } - item_impl(tps, ifce, ty, methods) { - item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty), - vec::map(methods, fld.fold_method)) - } - item_iface(tps, methods) { item_iface(tps, methods) } - item_res(decl, typms, body, did, cid) { - item_res(fold_fn_decl(decl, fld), - fold_ty_params(typms, fld), - fld.fold_block(body), - did, - cid) - } - }; -} - -fn noop_fold_method(&&m: @method, fld: ast_fold) -> @method { - ret @{ident: fld.fold_ident(m.ident), - attrs: m.attrs, - tps: fold_ty_params(m.tps, fld), - decl: fold_fn_decl(m.decl, fld), - body: fld.fold_block(m.body), - id: fld.new_id(m.id), - span: fld.new_span(m.span)}; -} - - -fn noop_fold_block(b: blk_, fld: ast_fold) -> blk_ { - ret {view_items: vec::map(b.view_items, fld.fold_view_item), - stmts: vec::map(b.stmts, fld.fold_stmt), - expr: option::map(b.expr, fld.fold_expr), - id: fld.new_id(b.id), - rules: b.rules}; -} - -fn noop_fold_stmt(s: stmt_, fld: ast_fold) -> stmt_ { - ret alt s { - stmt_decl(d, nid) { stmt_decl(fld.fold_decl(d), fld.new_id(nid)) } - stmt_expr(e, nid) { stmt_expr(fld.fold_expr(e), fld.new_id(nid)) } - stmt_semi(e, nid) { stmt_semi(fld.fold_expr(e), fld.new_id(nid)) } - }; -} - -fn noop_fold_arm(a: arm, fld: ast_fold) -> arm { - ret {pats: vec::map(a.pats, fld.fold_pat), - guard: option::map(a.guard, fld.fold_expr), - body: fld.fold_block(a.body)}; -} - -fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ { - ret alt p { - pat_wild { p } - pat_ident(pth, sub) { - pat_ident(fld.fold_path(pth), option::map(sub, fld.fold_pat)) - } - pat_lit(_) { p } - pat_enum(pth, pats) { - pat_enum(fld.fold_path(pth), vec::map(pats, fld.fold_pat)) - } - pat_rec(fields, etc) { - let fs = []; - for f: ast::field_pat in fields { - fs += [{ident: f.ident, pat: fld.fold_pat(f.pat)}]; - } - pat_rec(fs, etc) - } - pat_tup(elts) { pat_tup(vec::map(elts, fld.fold_pat)) } - pat_box(inner) { pat_box(fld.fold_pat(inner)) } - pat_uniq(inner) { pat_uniq(fld.fold_pat(inner)) } - pat_range(_, _) { p } - }; -} - -fn noop_fold_decl(d: decl_, fld: ast_fold) -> decl_ { - alt d { - decl_local(ls) { decl_local(vec::map(ls, fld.fold_local)) } - decl_item(it) { decl_item(fld.fold_item(it)) } - } -} - -fn wrap<T>(f: fn@(T, ast_fold) -> T) - -> fn@(T, span, ast_fold) -> (T, span) -{ - ret fn@(x: T, s: span, fld: ast_fold) -> (T, span) { - (f(x, fld), s) - } -} - -fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { - fn fold_field_(field: field, fld: ast_fold) -> field { - ret {node: - {mutbl: field.node.mutbl, - ident: fld.fold_ident(field.node.ident), - expr: fld.fold_expr(field.node.expr)}, - span: field.span}; - } - let fold_field = bind fold_field_(_, fld); - - let fold_mac = bind fold_mac_(_, fld); - - ret alt e { - expr_vec(exprs, mutt) { - expr_vec(fld.map_exprs(fld.fold_expr, exprs), mutt) - } - expr_rec(fields, maybe_expr) { - expr_rec(vec::map(fields, fold_field), - option::map(maybe_expr, fld.fold_expr)) - } - expr_tup(elts) { expr_tup(vec::map(elts, fld.fold_expr)) } - expr_call(f, args, blk) { - expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args), - blk) - } - expr_bind(f, args) { - let opt_map_se = bind option::map(_, fld.fold_expr); - expr_bind(fld.fold_expr(f), vec::map(args, opt_map_se)) - } - expr_binary(binop, lhs, rhs) { - expr_binary(binop, fld.fold_expr(lhs), fld.fold_expr(rhs)) - } - expr_unary(binop, ohs) { expr_unary(binop, fld.fold_expr(ohs)) } - expr_lit(_) { e } - expr_cast(expr, ty) { expr_cast(fld.fold_expr(expr), ty) } - expr_if(cond, tr, fl) { - expr_if(fld.fold_expr(cond), fld.fold_block(tr), - option::map(fl, fld.fold_expr)) - } - expr_while(cond, body) { - expr_while(fld.fold_expr(cond), fld.fold_block(body)) - } - expr_for(decl, expr, blk) { - expr_for(fld.fold_local(decl), fld.fold_expr(expr), - fld.fold_block(blk)) - } - expr_do_while(blk, expr) { - expr_do_while(fld.fold_block(blk), fld.fold_expr(expr)) - } - expr_alt(expr, arms, mode) { - expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm), mode) - } - expr_fn(proto, decl, body, captures) { - expr_fn(proto, fold_fn_decl(decl, fld), - fld.fold_block(body), captures) - } - expr_fn_block(decl, body) { - expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body)) - } - expr_block(blk) { expr_block(fld.fold_block(blk)) } - expr_move(el, er) { - expr_move(fld.fold_expr(el), fld.fold_expr(er)) - } - expr_copy(e) { expr_copy(fld.fold_expr(e)) } - expr_assign(el, er) { - expr_assign(fld.fold_expr(el), fld.fold_expr(er)) - } - expr_swap(el, er) { - expr_swap(fld.fold_expr(el), fld.fold_expr(er)) - } - expr_assign_op(op, el, er) { - expr_assign_op(op, fld.fold_expr(el), fld.fold_expr(er)) - } - expr_field(el, id, tys) { - expr_field(fld.fold_expr(el), fld.fold_ident(id), - vec::map(tys, fld.fold_ty)) - } - expr_index(el, er) { - expr_index(fld.fold_expr(el), fld.fold_expr(er)) - } - expr_path(pth) { expr_path(fld.fold_path(pth)) } - expr_fail(e) { expr_fail(option::map(e, fld.fold_expr)) } - expr_break | expr_cont { e } - expr_ret(e) { expr_ret(option::map(e, fld.fold_expr)) } - expr_be(e) { expr_be(fld.fold_expr(e)) } - expr_log(i, lv, e) { expr_log(i, fld.fold_expr(lv), - fld.fold_expr(e)) } - expr_assert(e) { expr_assert(fld.fold_expr(e)) } - expr_check(m, e) { expr_check(m, fld.fold_expr(e)) } - expr_if_check(cond, tr, fl) { - expr_if_check(fld.fold_expr(cond), fld.fold_block(tr), - option::map(fl, fld.fold_expr)) - } - expr_mac(mac) { expr_mac(fold_mac(mac)) } - } -} - -fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ { - let fold_mac = bind fold_mac_(_, fld); - fn fold_mt(mt: mt, fld: ast_fold) -> mt { - {ty: fld.fold_ty(mt.ty), mutbl: mt.mutbl} - } - fn fold_field(f: ty_field, fld: ast_fold) -> ty_field { - {node: {ident: fld.fold_ident(f.node.ident), - mt: fold_mt(f.node.mt, fld)}, - span: fld.new_span(f.span)} - } - alt t { - ty_nil | ty_bot {t} - ty_box(mt) {ty_box(fold_mt(mt, fld))} - ty_uniq(mt) {ty_uniq(fold_mt(mt, fld))} - ty_vec(mt) {ty_vec(fold_mt(mt, fld))} - ty_ptr(mt) {ty_ptr(fold_mt(mt, fld))} - ty_rec(fields) {ty_rec(vec::map(fields) {|f| fold_field(f, fld)})} - ty_fn(proto, decl) {ty_fn(proto, fold_fn_decl(decl, fld))} - ty_tup(tys) {ty_tup(vec::map(tys) {|ty| fld.fold_ty(ty)})} - ty_path(path, id) {ty_path(fld.fold_path(path), fld.new_id(id))} - // FIXME: constrs likely needs to be folded... - ty_constr(ty, constrs) {ty_constr(fld.fold_ty(ty), constrs)} - ty_mac(mac) {ty_mac(fold_mac(mac))} - ty_infer {t} - } -} - -fn noop_fold_constr(c: constr_, fld: ast_fold) -> constr_ { - {path: fld.fold_path(c.path), args: c.args, id: fld.new_id(c.id)} -} - -// ...nor do modules -fn noop_fold_mod(m: _mod, fld: ast_fold) -> _mod { - ret {view_items: vec::map(m.view_items, fld.fold_view_item), - items: vec::map(m.items, fld.fold_item)}; -} - -fn noop_fold_native_mod(nm: native_mod, fld: ast_fold) -> native_mod { - ret {view_items: vec::map(nm.view_items, fld.fold_view_item), - items: vec::map(nm.items, fld.fold_native_item)} -} - -fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ { - fn fold_variant_arg_(va: variant_arg, fld: ast_fold) -> variant_arg { - ret {ty: fld.fold_ty(va.ty), id: fld.new_id(va.id)}; - } - let fold_variant_arg = bind fold_variant_arg_(_, fld); - let args = vec::map(v.args, fold_variant_arg); - - let fold_meta_item = bind fold_meta_item_(_, fld); - let fold_attribute = bind fold_attribute_(_, fold_meta_item); - let attrs = vec::map(v.attrs, fold_attribute); - - let de = alt v.disr_expr { - some(e) {some(fld.fold_expr(e))} - none {none} - }; - ret {name: v.name, - attrs: attrs, - args: args, id: fld.new_id(v.id), - disr_expr: de}; -} - -fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident { ret i; } - -fn noop_fold_path(&&p: path_, fld: ast_fold) -> path_ { - ret {global: p.global, - idents: vec::map(p.idents, fld.fold_ident), - types: vec::map(p.types, fld.fold_ty)}; -} - -fn noop_fold_local(l: local_, fld: ast_fold) -> local_ { - ret {is_mutbl: l.is_mutbl, - ty: fld.fold_ty(l.ty), - pat: fld.fold_pat(l.pat), - init: - alt l.init { - option::none::<initializer> { l.init } - option::some::<initializer>(init) { - option::some::<initializer>({op: init.op, - expr: fld.fold_expr(init.expr)}) - } - }, - id: fld.new_id(l.id)}; -} - -/* temporarily eta-expand because of a compiler bug with using `fn<T>` as a - value */ -fn noop_map_exprs(f: fn@(&&@expr) -> @expr, es: [@expr]) -> [@expr] { - ret vec::map(es, f); -} - -fn noop_id(i: node_id) -> node_id { ret i; } - -fn noop_span(sp: span) -> span { ret sp; } - - -fn default_ast_fold() -> @ast_fold_precursor { - ret @{fold_crate: wrap(noop_fold_crate), - fold_crate_directive: wrap(noop_fold_crate_directive), - fold_view_item: noop_fold_view_item, - fold_native_item: noop_fold_native_item, - fold_item: noop_fold_item, - fold_class_item: noop_fold_class_item, - fold_item_underscore: noop_fold_item_underscore, - fold_method: noop_fold_method, - fold_block: wrap(noop_fold_block), - fold_stmt: wrap(noop_fold_stmt), - fold_arm: noop_fold_arm, - fold_pat: wrap(noop_fold_pat), - fold_decl: wrap(noop_fold_decl), - fold_expr: wrap(noop_fold_expr), - fold_ty: wrap(noop_fold_ty), - fold_constr: wrap(noop_fold_constr), - fold_mod: noop_fold_mod, - fold_native_mod: noop_fold_native_mod, - fold_variant: wrap(noop_fold_variant), - fold_ident: noop_fold_ident, - fold_path: wrap(noop_fold_path), - fold_local: wrap(noop_fold_local), - map_exprs: noop_map_exprs, - new_id: noop_id, - new_span: noop_span}; -} - -fn make_fold(afp: ast_fold_precursor) -> ast_fold { - // FIXME: Have to bind all the bare functions into shared functions - // because @mutable is invariant with respect to its contents - let result: ast_fold = - @mutable {fold_crate: bind nf_crate_dummy(_), - fold_crate_directive: bind nf_crate_directive_dummy(_), - fold_view_item: bind nf_view_item_dummy(_), - fold_native_item: bind nf_native_item_dummy(_), - fold_item: bind nf_item_dummy(_), - fold_class_item: bind nf_class_item_dummy(_), - fold_item_underscore: bind nf_item_underscore_dummy(_), - fold_method: bind nf_method_dummy(_), - fold_block: bind nf_blk_dummy(_), - fold_stmt: bind nf_stmt_dummy(_), - fold_arm: bind nf_arm_dummy(_), - fold_pat: bind nf_pat_dummy(_), - fold_decl: bind nf_decl_dummy(_), - fold_expr: bind nf_expr_dummy(_), - fold_ty: bind nf_ty_dummy(_), - fold_constr: bind nf_constr_dummy(_), - fold_mod: bind nf_mod_dummy(_), - fold_native_mod: bind nf_native_mod_dummy(_), - fold_variant: bind nf_variant_dummy(_), - fold_ident: bind nf_ident_dummy(_), - fold_path: bind nf_path_dummy(_), - fold_local: bind nf_local_dummy(_), - map_exprs: bind noop_map_exprs(_, _), - new_id: bind noop_id(_), - new_span: bind noop_span(_)}; - - /* naturally, a macro to write these would be nice */ - fn f_crate(afp: ast_fold_precursor, f: ast_fold, c: crate) -> crate { - let (n, s) = afp.fold_crate(c.node, c.span, f); - ret {node: n, span: afp.new_span(s)}; - } - fn f_crate_directive(afp: ast_fold_precursor, f: ast_fold, - &&c: @crate_directive) -> @crate_directive { - let (n, s) = afp.fold_crate_directive(c.node, c.span, f); - ret @{node: n, - span: afp.new_span(s)}; - } - fn f_view_item(afp: ast_fold_precursor, f: ast_fold, &&x: @view_item) -> - @view_item { - ret @{node: afp.fold_view_item(x.node, f), - span: afp.new_span(x.span)}; - } - fn f_native_item(afp: ast_fold_precursor, f: ast_fold, &&x: @native_item) - -> @native_item { - ret afp.fold_native_item(x, f); - } - fn f_item(afp: ast_fold_precursor, f: ast_fold, &&i: @item) -> @item { - ret afp.fold_item(i, f); - } - fn f_class_item(afp: ast_fold_precursor, f: ast_fold, - &&ci: @class_item) -> @class_item { - @{node: - {privacy:ci.node.privacy, - decl: - alt ci.node.decl { - instance_var(nm, t, mt, id) { - instance_var(nm, f_ty(afp, f, t), - mt, id) - } - class_method(i) { - class_method(afp.fold_item(i, f)) - } - }}, span: afp.new_span(ci.span)} - } - fn f_item_underscore(afp: ast_fold_precursor, f: ast_fold, i: item_) -> - item_ { - ret afp.fold_item_underscore(i, f); - } - fn f_method(afp: ast_fold_precursor, f: ast_fold, &&x: @method) - -> @method { - ret afp.fold_method(x, f); - } - fn f_block(afp: ast_fold_precursor, f: ast_fold, x: blk) -> blk { - let (n, s) = afp.fold_block(x.node, x.span, f); - ret {node: n, span: afp.new_span(s)}; - } - fn f_stmt(afp: ast_fold_precursor, f: ast_fold, &&x: @stmt) -> @stmt { - let (n, s) = afp.fold_stmt(x.node, x.span, f); - ret @{node: n, span: afp.new_span(s)}; - } - fn f_arm(afp: ast_fold_precursor, f: ast_fold, x: arm) -> arm { - ret afp.fold_arm(x, f); - } - fn f_pat(afp: ast_fold_precursor, f: ast_fold, &&x: @pat) -> @pat { - let (n, s) = afp.fold_pat(x.node, x.span, f); - ret @{id: afp.new_id(x.id), - node: n, - span: afp.new_span(s)}; - } - fn f_decl(afp: ast_fold_precursor, f: ast_fold, &&x: @decl) -> @decl { - let (n, s) = afp.fold_decl(x.node, x.span, f); - ret @{node: n, span: afp.new_span(s)}; - } - fn f_expr(afp: ast_fold_precursor, f: ast_fold, &&x: @expr) -> @expr { - let (n, s) = afp.fold_expr(x.node, x.span, f); - ret @{id: afp.new_id(x.id), - node: n, - span: afp.new_span(s)}; - } - fn f_ty(afp: ast_fold_precursor, f: ast_fold, &&x: @ty) -> @ty { - let (n, s) = afp.fold_ty(x.node, x.span, f); - ret @{node: n, span: afp.new_span(s)}; - } - fn f_constr(afp: ast_fold_precursor, f: ast_fold, &&x: @ast::constr) -> - @ast::constr { - let (n, s) = afp.fold_constr(x.node, x.span, f); - ret @{node: n, span: afp.new_span(s)}; - } - fn f_mod(afp: ast_fold_precursor, f: ast_fold, x: _mod) -> _mod { - ret afp.fold_mod(x, f); - } - fn f_native_mod(afp: ast_fold_precursor, f: ast_fold, x: native_mod) -> - native_mod { - ret afp.fold_native_mod(x, f); - } - fn f_variant(afp: ast_fold_precursor, f: ast_fold, x: variant) -> - variant { - let (n, s) = afp.fold_variant(x.node, x.span, f); - ret {node: n, span: afp.new_span(s)}; - } - fn f_ident(afp: ast_fold_precursor, f: ast_fold, &&x: ident) -> ident { - ret afp.fold_ident(x, f); - } - fn f_path(afp: ast_fold_precursor, f: ast_fold, &&x: @path) -> @path { - let (n, s) = afp.fold_path(x.node, x.span, f); - ret @{node: n, span: afp.new_span(s)}; - } - fn f_local(afp: ast_fold_precursor, f: ast_fold, &&x: @local) -> @local { - let (n, s) = afp.fold_local(x.node, x.span, f); - ret @{node: n, span: afp.new_span(s)}; - } - - *result = - {fold_crate: bind f_crate(afp, result, _), - fold_crate_directive: bind f_crate_directive(afp, result, _), - fold_view_item: bind f_view_item(afp, result, _), - fold_native_item: bind f_native_item(afp, result, _), - fold_item: bind f_item(afp, result, _), - fold_class_item: bind f_class_item(afp, result, _), - fold_item_underscore: bind f_item_underscore(afp, result, _), - fold_method: bind f_method(afp, result, _), - fold_block: bind f_block(afp, result, _), - fold_stmt: bind f_stmt(afp, result, _), - fold_arm: bind f_arm(afp, result, _), - fold_pat: bind f_pat(afp, result, _), - fold_decl: bind f_decl(afp, result, _), - fold_expr: bind f_expr(afp, result, _), - fold_ty: bind f_ty(afp, result, _), - fold_constr: bind f_constr(afp, result, _), - fold_mod: bind f_mod(afp, result, _), - fold_native_mod: bind f_native_mod(afp, result, _), - fold_variant: bind f_variant(afp, result, _), - fold_ident: bind f_ident(afp, result, _), - fold_path: bind f_path(afp, result, _), - fold_local: bind f_local(afp, result, _), - map_exprs: afp.map_exprs, - new_id: afp.new_id, - new_span: afp.new_span}; - ret result; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/parse/eval.rs b/src/comp/syntax/parse/eval.rs deleted file mode 100644 index 06f26905550..00000000000 --- a/src/comp/syntax/parse/eval.rs +++ /dev/null @@ -1,150 +0,0 @@ - -import front::attr; -import std::{io, fs}; -import syntax::ast; -import syntax::parse::token; -import syntax::parse::parser::{parser, new_parser_from_file, - parse_inner_attrs_and_next, - parse_mod_items, SOURCE_FILE}; - -export eval_crate_directives_to_mod; - -type ctx = - @{p: parser, - sess: parser::parse_sess, - cfg: ast::crate_cfg}; - -fn eval_crate_directives(cx: ctx, cdirs: [@ast::crate_directive], prefix: str, - &view_items: [@ast::view_item], - &items: [@ast::item]) { - for sub_cdir: @ast::crate_directive in cdirs { - eval_crate_directive(cx, sub_cdir, prefix, view_items, items); - } -} - -fn eval_crate_directives_to_mod(cx: ctx, cdirs: [@ast::crate_directive], - prefix: str, suffix: option<str>) - -> (ast::_mod, [ast::attribute]) { - #debug("eval crate prefix: %s", prefix); - #debug("eval crate suffix: %s", - option::from_maybe("none", suffix)); - let (cview_items, citems, cattrs) - = parse_companion_mod(cx, prefix, suffix); - let view_items: [@ast::view_item] = []; - let items: [@ast::item] = []; - eval_crate_directives(cx, cdirs, prefix, view_items, items); - ret ({view_items: view_items + cview_items, - items: items + citems}, - cattrs); -} - -/* -The 'companion mod'. So .rc crates and directory mod crate directives define -modules but not a .rs file to fill those mods with stuff. The companion mod is -a convention for location a .rs file to go with them. For .rc files the -companion mod is a .rs file with the same name; for directory mods the -companion mod is a .rs file with the same name as the directory. - -We build the path to the companion mod by combining the prefix and the -optional suffix then adding the .rs extension. -*/ -fn parse_companion_mod(cx: ctx, prefix: str, suffix: option<str>) - -> ([@ast::view_item], [@ast::item], [ast::attribute]) { - - fn companion_file(prefix: str, suffix: option<str>) -> str { - ret alt suffix { - option::some(s) { fs::connect(prefix, s) } - option::none { prefix } - } + ".rs"; - } - - fn file_exists(path: str) -> bool { - // Crude, but there's no lib function for this and I'm not - // up to writing it just now - alt io::file_reader(path) { - result::ok(_) { true } - result::err(_) { false } - } - } - - let modpath = companion_file(prefix, suffix); - #debug("looking for companion mod %s", modpath); - if file_exists(modpath) { - #debug("found companion mod"); - let p0 = new_parser_from_file(cx.sess, cx.cfg, modpath, - SOURCE_FILE); - let inner_attrs = parse_inner_attrs_and_next(p0); - let first_item_outer_attrs = inner_attrs.next; - let m0 = parse_mod_items(p0, token::EOF, first_item_outer_attrs); - cx.sess.chpos = p0.reader.chpos; - cx.sess.byte_pos = cx.sess.byte_pos + p0.reader.pos; - ret (m0.view_items, m0.items, inner_attrs.inner); - } else { - ret ([], [], []); - } -} - -fn cdir_path_opt(id: str, attrs: [ast::attribute]) -> str { - alt attr::get_meta_item_value_str_by_name(attrs, "path") { - some(d) { - ret d; - } - none { ret id; } - } -} - -fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: str, - &view_items: [@ast::view_item], - &items: [@ast::item]) { - alt cdir.node { - ast::cdir_src_mod(id, attrs) { - let file_path = cdir_path_opt(id + ".rs", attrs); - let full_path = - if std::fs::path_is_absolute(file_path) { - file_path - } else { prefix + std::fs::path_sep() + file_path }; - let p0 = - new_parser_from_file(cx.sess, cx.cfg, full_path, SOURCE_FILE); - let inner_attrs = parse_inner_attrs_and_next(p0); - let mod_attrs = attrs + inner_attrs.inner; - let first_item_outer_attrs = inner_attrs.next; - let m0 = parse_mod_items(p0, token::EOF, first_item_outer_attrs); - - let i = - syntax::parse::parser::mk_item(p0, cdir.span.lo, cdir.span.hi, id, - ast::item_mod(m0), mod_attrs); - // Thread defids, chpos and byte_pos through the parsers - cx.sess.chpos = p0.reader.chpos; - cx.sess.byte_pos = cx.sess.byte_pos + p0.reader.pos; - items += [i]; - } - ast::cdir_dir_mod(id, cdirs, attrs) { - let path = cdir_path_opt(id, attrs); - let full_path = - if std::fs::path_is_absolute(path) { - path - } else { prefix + std::fs::path_sep() + path }; - let (m0, a0) = eval_crate_directives_to_mod( - cx, cdirs, full_path, none); - let i = - @{ident: id, - attrs: attrs + a0, - id: cx.sess.next_id, - node: ast::item_mod(m0), - span: cdir.span}; - cx.sess.next_id += 1; - items += [i]; - } - ast::cdir_view_item(vi) { view_items += [vi]; } - ast::cdir_syntax(pth) { } - } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/parse/lexer.rs b/src/comp/syntax/parse/lexer.rs deleted file mode 100644 index 3350d7a7c95..00000000000 --- a/src/comp/syntax/parse/lexer.rs +++ /dev/null @@ -1,748 +0,0 @@ - -import std::io; -import io::reader_util; -import util::interner; -import util::interner::intern; -import driver::diagnostic; - -type reader = @{ - cm: codemap::codemap, - span_diagnostic: diagnostic::span_handler, - src: @str, - len: uint, - mutable col: uint, - mutable pos: uint, - mutable curr: char, - mutable chpos: uint, - mutable strs: [str], - filemap: codemap::filemap, - interner: @interner::interner<str> -}; - -impl reader for reader { - fn is_eof() -> bool { self.curr == -1 as char } - fn get_str_from(start: uint) -> str unsafe { - // I'm pretty skeptical about this subtraction. What if there's a - // multi-byte character before the mark? - ret str::slice(*self.src, start - 1u, self.pos - 1u); - } - fn next() -> char { - if self.pos < self.len { - ret str::char_at(*self.src, self.pos); - } else { ret -1 as char; } - } - fn bump() { - if self.pos < self.len { - self.col += 1u; - self.chpos += 1u; - if self.curr == '\n' { - codemap::next_line(self.filemap, self.chpos, self.pos + - self.filemap.start_pos.byte); - self.col = 0u; - } - let next = str::char_range_at(*self.src, self.pos); - self.pos = next.next; - self.curr = next.ch; - } else { - if (self.curr != -1 as char) { - self.col += 1u; - self.chpos += 1u; - self.curr = -1 as char; - } - } - } - fn fatal(m: str) -> ! { - self.span_diagnostic.span_fatal( - ast_util::mk_sp(self.chpos, self.chpos), - m) - } -} - -fn new_reader(cm: codemap::codemap, - span_diagnostic: diagnostic::span_handler, - filemap: codemap::filemap, - itr: @interner::interner<str>) -> reader { - let r = @{cm: cm, - span_diagnostic: span_diagnostic, - src: filemap.src, len: str::len(*filemap.src), - mutable col: 0u, mutable pos: 0u, mutable curr: -1 as char, - mutable chpos: filemap.start_pos.ch, mutable strs: [], - filemap: filemap, interner: itr}; - if r.pos < r.len { - let next = str::char_range_at(*r.src, r.pos); - r.pos = next.next; - r.curr = next.ch; - } - ret r; -} - -fn dec_digit_val(c: char) -> int { ret (c as int) - ('0' as int); } - -fn hex_digit_val(c: char) -> int { - if in_range(c, '0', '9') { ret (c as int) - ('0' as int); } - if in_range(c, 'a', 'f') { ret (c as int) - ('a' as int) + 10; } - if in_range(c, 'A', 'F') { ret (c as int) - ('A' as int) + 10; } - fail; -} - -fn bin_digit_value(c: char) -> int { if c == '0' { ret 0; } ret 1; } - -fn is_whitespace(c: char) -> bool { - ret c == ' ' || c == '\t' || c == '\r' || c == '\n'; -} - -fn may_begin_ident(c: char) -> bool { ret is_alpha(c) || c == '_'; } - -fn in_range(c: char, lo: char, hi: char) -> bool { ret lo <= c && c <= hi; } - -fn is_alpha(c: char) -> bool { - ret in_range(c, 'a', 'z') || in_range(c, 'A', 'Z'); -} - -fn is_dec_digit(c: char) -> bool { ret in_range(c, '0', '9'); } - -fn is_alnum(c: char) -> bool { ret is_alpha(c) || is_dec_digit(c); } - -fn is_hex_digit(c: char) -> bool { - ret in_range(c, '0', '9') || in_range(c, 'a', 'f') || - in_range(c, 'A', 'F'); -} - -fn is_bin_digit(c: char) -> bool { ret c == '0' || c == '1'; } - -fn consume_whitespace_and_comments(rdr: reader) { - while is_whitespace(rdr.curr) { rdr.bump(); } - be consume_any_line_comment(rdr); -} - -fn consume_any_line_comment(rdr: reader) { - if rdr.curr == '/' { - alt rdr.next() { - '/' { - while rdr.curr != '\n' && !rdr.is_eof() { rdr.bump(); } - // Restart whitespace munch. - - be consume_whitespace_and_comments(rdr); - } - '*' { rdr.bump(); rdr.bump(); be consume_block_comment(rdr); } - _ { ret; } - } - } -} - -fn consume_block_comment(rdr: reader) { - let level: int = 1; - while level > 0 { - if rdr.is_eof() { rdr.fatal("unterminated block comment"); } - if rdr.curr == '/' && rdr.next() == '*' { - rdr.bump(); - rdr.bump(); - level += 1; - } else { - if rdr.curr == '*' && rdr.next() == '/' { - rdr.bump(); - rdr.bump(); - level -= 1; - } else { rdr.bump(); } - } - } - // restart whitespace munch. - - be consume_whitespace_and_comments(rdr); -} - -fn scan_exponent(rdr: reader) -> option<str> { - let c = rdr.curr; - let rslt = ""; - if c == 'e' || c == 'E' { - str::push_char(rslt, c); - rdr.bump(); - c = rdr.curr; - if c == '-' || c == '+' { - str::push_char(rslt, c); - rdr.bump(); - } - let exponent = scan_digits(rdr, 10u); - if str::len(exponent) > 0u { - ret some(rslt + exponent); - } else { rdr.fatal("scan_exponent: bad fp literal"); } - } else { ret none::<str>; } -} - -fn scan_digits(rdr: reader, radix: uint) -> str { - let rslt = ""; - while true { - let c = rdr.curr; - if c == '_' { rdr.bump(); cont; } - alt char::to_digit(c, radix) { - some(d) { - str::push_char(rslt, c); - rdr.bump(); - } - _ { break; } - } - } - ret rslt; -} - -fn scan_number(c: char, rdr: reader) -> token::token { - let num_str, base = 10u, c = c, n = rdr.next(); - if c == '0' && n == 'x' { - rdr.bump(); - rdr.bump(); - base = 16u; - } else if c == '0' && n == 'b' { - rdr.bump(); - rdr.bump(); - base = 2u; - } - num_str = scan_digits(rdr, base); - c = rdr.curr; - n = rdr.next(); - if c == 'u' || c == 'i' { - let signed = c == 'i', tp = if signed { either::left(ast::ty_i) } - else { either::right(ast::ty_u) }; - rdr.bump(); - c = rdr.curr; - if c == '8' { - rdr.bump(); - tp = if signed { either::left(ast::ty_i8) } - else { either::right(ast::ty_u8) }; - } - n = rdr.next(); - if c == '1' && n == '6' { - rdr.bump(); - rdr.bump(); - tp = if signed { either::left(ast::ty_i16) } - else { either::right(ast::ty_u16) }; - } else if c == '3' && n == '2' { - rdr.bump(); - rdr.bump(); - tp = if signed { either::left(ast::ty_i32) } - else { either::right(ast::ty_u32) }; - } else if c == '6' && n == '4' { - rdr.bump(); - rdr.bump(); - tp = if signed { either::left(ast::ty_i64) } - else { either::right(ast::ty_u64) }; - } - if str::len(num_str) == 0u { - rdr.fatal("no valid digits found for number"); - } - let parsed = option::get(u64::from_str(num_str, base as u64)); - alt tp { - either::left(t) { ret token::LIT_INT(parsed as i64, t); } - either::right(t) { ret token::LIT_UINT(parsed, t); } - } - } - let is_float = false; - if rdr.curr == '.' && !(is_alpha(rdr.next()) || rdr.next() == '_') { - is_float = true; - rdr.bump(); - let dec_part = scan_digits(rdr, 10u); - num_str += "." + dec_part; - } - alt scan_exponent(rdr) { - some(s) { - is_float = true; - num_str += s; - } - none {} - } - if rdr.curr == 'f' { - rdr.bump(); - c = rdr.curr; - n = rdr.next(); - if c == '3' && n == '2' { - rdr.bump(); - rdr.bump(); - ret token::LIT_FLOAT(intern(*rdr.interner, num_str), - ast::ty_f32); - } else if c == '6' && n == '4' { - rdr.bump(); - rdr.bump(); - ret token::LIT_FLOAT(intern(*rdr.interner, num_str), - ast::ty_f64); - /* FIXME: if this is out of range for either a 32-bit or - 64-bit float, it won't be noticed till the back-end */ - } else { - is_float = true; - } - } - if is_float { - ret token::LIT_FLOAT(interner::intern(*rdr.interner, num_str), - ast::ty_f); - } else { - if str::len(num_str) == 0u { - rdr.fatal("no valid digits found for number"); - } - let parsed = option::get(u64::from_str(num_str, base as u64)); - ret token::LIT_INT(parsed as i64, ast::ty_i); - } -} - -fn scan_numeric_escape(rdr: reader, n_hex_digits: uint) -> char { - let accum_int = 0, i = n_hex_digits; - while i != 0u { - let n = rdr.curr; - rdr.bump(); - if !is_hex_digit(n) { - rdr.fatal(#fmt["illegal numeric character escape: %d", n as int]); - } - accum_int *= 16; - accum_int += hex_digit_val(n); - i -= 1u; - } - ret accum_int as char; -} - -fn next_token(rdr: reader) -> {tok: token::token, chpos: uint, bpos: uint} { - consume_whitespace_and_comments(rdr); - let start_chpos = rdr.chpos; - let start_bpos = rdr.pos; - let tok = if rdr.is_eof() { token::EOF } else { next_token_inner(rdr) }; - ret {tok: tok, chpos: start_chpos, bpos: start_bpos}; -} - -fn next_token_inner(rdr: reader) -> token::token { - let accum_str = ""; - let c = rdr.curr; - if (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == '_' - || (c > 'z' && char::is_XID_start(c)) { - while (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || c == '_' - || (c > 'z' && char::is_XID_continue(c)) { - str::push_char(accum_str, c); - rdr.bump(); - c = rdr.curr; - } - if str::eq(accum_str, "_") { ret token::UNDERSCORE; } - let is_mod_name = c == ':' && rdr.next() == ':'; - - // FIXME: perform NFKC normalization here. - ret token::IDENT(interner::intern::<str>(*rdr.interner, - accum_str), is_mod_name); - } - if is_dec_digit(c) { - ret scan_number(c, rdr); - } - fn binop(rdr: reader, op: token::binop) -> token::token { - rdr.bump(); - if rdr.curr == '=' { - rdr.bump(); - ret token::BINOPEQ(op); - } else { ret token::BINOP(op); } - } - alt c { - - - - - - // One-byte tokens. - ';' { rdr.bump(); ret token::SEMI; } - ',' { rdr.bump(); ret token::COMMA; } - '.' { - rdr.bump(); - if rdr.curr == '.' && rdr.next() == '.' { - rdr.bump(); - rdr.bump(); - ret token::ELLIPSIS; - } - ret token::DOT; - } - '(' { rdr.bump(); ret token::LPAREN; } - ')' { rdr.bump(); ret token::RPAREN; } - '{' { rdr.bump(); ret token::LBRACE; } - '}' { rdr.bump(); ret token::RBRACE; } - '[' { rdr.bump(); ret token::LBRACKET; } - ']' { rdr.bump(); ret token::RBRACKET; } - '@' { rdr.bump(); ret token::AT; } - '#' { - rdr.bump(); - if rdr.curr == '<' { rdr.bump(); ret token::POUND_LT; } - if rdr.curr == '{' { rdr.bump(); ret token::POUND_LBRACE; } - ret token::POUND; - } - '~' { rdr.bump(); ret token::TILDE; } - ':' { - rdr.bump(); - if rdr.curr == ':' { - rdr.bump(); - ret token::MOD_SEP; - } else { ret token::COLON; } - } - - '$' { - rdr.bump(); - if is_dec_digit(rdr.curr) { - let val = dec_digit_val(rdr.curr) as uint; - while is_dec_digit(rdr.next()) { - rdr.bump(); - val = val * 10u + (dec_digit_val(rdr.curr) as uint); - } - rdr.bump(); - ret token::DOLLAR_NUM(val); - } else if rdr.curr == '(' { - rdr.bump(); - ret token::DOLLAR_LPAREN; - } else { - rdr.fatal("expected digit"); - } - } - - - - - - // Multi-byte tokens. - '=' { - rdr.bump(); - if rdr.curr == '=' { - rdr.bump(); - ret token::EQEQ; - } else { ret token::EQ; } - } - '!' { - rdr.bump(); - if rdr.curr == '=' { - rdr.bump(); - ret token::NE; - } else { ret token::NOT; } - } - '<' { - rdr.bump(); - alt rdr.curr { - '=' { rdr.bump(); ret token::LE; } - '<' { ret binop(rdr, token::LSL); } - '-' { - rdr.bump(); - alt rdr.curr { - '>' { rdr.bump(); ret token::DARROW; } - _ { ret token::LARROW; } - } - } - _ { ret token::LT; } - } - } - '>' { - rdr.bump(); - alt rdr.curr { - '=' { rdr.bump(); ret token::GE; } - '>' { - if rdr.next() == '>' { - rdr.bump(); - ret binop(rdr, token::ASR); - } else { ret binop(rdr, token::LSR); } - } - _ { ret token::GT; } - } - } - '\'' { - rdr.bump(); - let c2 = rdr.curr; - rdr.bump(); - if c2 == '\\' { - let escaped = rdr.curr; - rdr.bump(); - alt escaped { - 'n' { c2 = '\n'; } - 'r' { c2 = '\r'; } - 't' { c2 = '\t'; } - '\\' { c2 = '\\'; } - '\'' { c2 = '\''; } - 'x' { c2 = scan_numeric_escape(rdr, 2u); } - 'u' { c2 = scan_numeric_escape(rdr, 4u); } - 'U' { c2 = scan_numeric_escape(rdr, 8u); } - c2 { - rdr.fatal(#fmt["unknown character escape: %d", c2 as int]); - } - } - } - if rdr.curr != '\'' { - rdr.fatal("unterminated character constant"); - } - rdr.bump(); // advance curr past token - ret token::LIT_INT(c2 as i64, ast::ty_char); - } - '"' { - let n = rdr.chpos; - rdr.bump(); - while rdr.curr != '"' { - if rdr.is_eof() { - rdr.fatal(#fmt["unterminated double quote string: %s", - rdr.get_str_from(n)]); - } - - let ch = rdr.curr; - rdr.bump(); - alt ch { - '\\' { - let escaped = rdr.curr; - rdr.bump(); - alt escaped { - 'n' { str::push_char(accum_str, '\n'); } - 'r' { str::push_char(accum_str, '\r'); } - 't' { str::push_char(accum_str, '\t'); } - '\\' { str::push_char(accum_str, '\\'); } - '"' { str::push_char(accum_str, '"'); } - '\n' { consume_whitespace(rdr); } - 'x' { - str::push_char(accum_str, scan_numeric_escape(rdr, 2u)); - } - 'u' { - str::push_char(accum_str, scan_numeric_escape(rdr, 4u)); - } - 'U' { - str::push_char(accum_str, scan_numeric_escape(rdr, 8u)); - } - c2 { - rdr.fatal(#fmt["unknown string escape: %d", c2 as int]); - } - } - } - _ { str::push_char(accum_str, ch); } - } - } - rdr.bump(); - ret token::LIT_STR(interner::intern::<str>(*rdr.interner, - accum_str)); - } - '-' { - if rdr.next() == '>' { - rdr.bump(); - rdr.bump(); - ret token::RARROW; - } else { ret binop(rdr, token::MINUS); } - } - '&' { - if rdr.next() == '&' { - rdr.bump(); - rdr.bump(); - ret token::ANDAND; - } else { ret binop(rdr, token::AND); } - } - '|' { - alt rdr.next() { - '|' { rdr.bump(); rdr.bump(); ret token::OROR; } - _ { ret binop(rdr, token::OR); } - } - } - '+' { ret binop(rdr, token::PLUS); } - '*' { ret binop(rdr, token::STAR); } - '/' { ret binop(rdr, token::SLASH); } - '^' { ret binop(rdr, token::CARET); } - '%' { ret binop(rdr, token::PERCENT); } - c { rdr.fatal(#fmt["unkown start of token: %d", c as int]); } - } -} - -enum cmnt_style { - isolated, // No code on either side of each line of the comment - trailing, // Code exists to the left of the comment - mixed, // Code before /* foo */ and after the comment - blank_line, // Just a manual blank line "\n\n", for layout -} - -type cmnt = {style: cmnt_style, lines: [str], pos: uint}; - -fn read_to_eol(rdr: reader) -> str { - let val = ""; - while rdr.curr != '\n' && !rdr.is_eof() { - str::push_char(val, rdr.curr); - rdr.bump(); - } - if rdr.curr == '\n' { rdr.bump(); } - ret val; -} - -fn read_one_line_comment(rdr: reader) -> str { - let val = read_to_eol(rdr); - assert (val[0] == '/' as u8 && val[1] == '/' as u8); - ret val; -} - -fn consume_whitespace(rdr: reader) { - while is_whitespace(rdr.curr) && !rdr.is_eof() { rdr.bump(); } -} - -fn consume_non_eol_whitespace(rdr: reader) { - while is_whitespace(rdr.curr) && rdr.curr != '\n' && !rdr.is_eof() { - rdr.bump(); - } -} - -fn push_blank_line_comment(rdr: reader, &comments: [cmnt]) { - #debug(">>> blank-line comment"); - let v: [str] = []; - comments += [{style: blank_line, lines: v, pos: rdr.chpos}]; -} - -fn consume_whitespace_counting_blank_lines(rdr: reader, &comments: [cmnt]) { - while is_whitespace(rdr.curr) && !rdr.is_eof() { - if rdr.col == 0u && rdr.curr == '\n' { - push_blank_line_comment(rdr, comments); - } - rdr.bump(); - } -} - -fn read_line_comments(rdr: reader, code_to_the_left: bool) -> cmnt { - #debug(">>> line comments"); - let p = rdr.chpos; - let lines: [str] = []; - while rdr.curr == '/' && rdr.next() == '/' { - let line = read_one_line_comment(rdr); - log(debug, line); - lines += [line]; - consume_non_eol_whitespace(rdr); - } - #debug("<<< line comments"); - ret {style: if code_to_the_left { trailing } else { isolated }, - lines: lines, - pos: p}; -} - -fn all_whitespace(s: str, begin: uint, end: uint) -> bool { - let i: uint = begin; - while i != end { if !is_whitespace(s[i] as char) { ret false; } i += 1u; } - ret true; -} - -fn trim_whitespace_prefix_and_push_line(&lines: [str], - s: str, col: uint) unsafe { - let s1; - if all_whitespace(s, 0u, col) { - if col < str::len(s) { - s1 = str::slice(s, col, str::len(s)); - } else { s1 = ""; } - } else { s1 = s; } - log(debug, "pushing line: " + s1); - lines += [s1]; -} - -fn read_block_comment(rdr: reader, code_to_the_left: bool) -> cmnt { - #debug(">>> block comment"); - let p = rdr.chpos; - let lines: [str] = []; - let col: uint = rdr.col; - rdr.bump(); - rdr.bump(); - let curr_line = "/*"; - let level: int = 1; - while level > 0 { - #debug("=== block comment level %d", level); - if rdr.is_eof() { rdr.fatal("unterminated block comment"); } - if rdr.curr == '\n' { - trim_whitespace_prefix_and_push_line(lines, curr_line, col); - curr_line = ""; - rdr.bump(); - } else { - str::push_char(curr_line, rdr.curr); - if rdr.curr == '/' && rdr.next() == '*' { - rdr.bump(); - rdr.bump(); - curr_line += "*"; - level += 1; - } else { - if rdr.curr == '*' && rdr.next() == '/' { - rdr.bump(); - rdr.bump(); - curr_line += "/"; - level -= 1; - } else { rdr.bump(); } - } - } - } - if str::len(curr_line) != 0u { - trim_whitespace_prefix_and_push_line(lines, curr_line, col); - } - let style = if code_to_the_left { trailing } else { isolated }; - consume_non_eol_whitespace(rdr); - if !rdr.is_eof() && rdr.curr != '\n' && vec::len(lines) == 1u { - style = mixed; - } - #debug("<<< block comment"); - ret {style: style, lines: lines, pos: p}; -} - -fn peeking_at_comment(rdr: reader) -> bool { - ret rdr.curr == '/' && rdr.next() == '/' || - rdr.curr == '/' && rdr.next() == '*'; -} - -fn consume_comment(rdr: reader, code_to_the_left: bool, &comments: [cmnt]) { - #debug(">>> consume comment"); - if rdr.curr == '/' && rdr.next() == '/' { - comments += [read_line_comments(rdr, code_to_the_left)]; - } else if rdr.curr == '/' && rdr.next() == '*' { - comments += [read_block_comment(rdr, code_to_the_left)]; - } else { fail; } - #debug("<<< consume comment"); -} - -fn is_lit(t: token::token) -> bool { - ret alt t { - token::LIT_INT(_, _) { true } - token::LIT_UINT(_, _) { true } - token::LIT_FLOAT(_, _) { true } - token::LIT_STR(_) { true } - token::LIT_BOOL(_) { true } - _ { false } - } -} - -type lit = {lit: str, pos: uint}; - -fn gather_comments_and_literals(cm: codemap::codemap, - span_diagnostic: diagnostic::span_handler, - path: str, - srdr: io::reader) -> - {cmnts: [cmnt], lits: [lit]} { - let src = @str::from_bytes(srdr.read_whole_stream()); - let itr = @interner::mk::<str>(str::hash, str::eq); - let rdr = new_reader(cm, span_diagnostic, - codemap::new_filemap(path, src, 0u, 0u), itr); - let comments: [cmnt] = []; - let literals: [lit] = []; - let first_read: bool = true; - while !rdr.is_eof() { - while true { - let code_to_the_left = !first_read; - consume_non_eol_whitespace(rdr); - if rdr.curr == '\n' { - code_to_the_left = false; - consume_whitespace_counting_blank_lines(rdr, comments); - } - while peeking_at_comment(rdr) { - consume_comment(rdr, code_to_the_left, comments); - consume_whitespace_counting_blank_lines(rdr, comments); - } - break; - } - let tok = next_token(rdr); - if is_lit(tok.tok) { - let s = rdr.get_str_from(tok.bpos); - literals += [{lit: s, pos: tok.chpos}]; - log(debug, "tok lit: " + s); - } else { - log(debug, "tok: " + token::to_str(rdr, tok.tok)); - } - first_read = false; - } - ret {cmnts: comments, lits: literals}; -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs deleted file mode 100644 index 5837baf1ff9..00000000000 --- a/src/comp/syntax/parse/parser.rs +++ /dev/null @@ -1,2747 +0,0 @@ -import std::{io, fs}; -import either::{left, right}; -import std::map::{hashmap, new_str_hash}; -import token::can_begin_expr; -import codemap::{span,fss_none}; -import util::interner; -import ast::{node_id, spanned}; -import ast_util::{mk_sp, ident_to_path}; -import front::attr; -import lexer::reader; -import driver::diagnostic; - -enum restriction { - UNRESTRICTED, - RESTRICT_STMT_EXPR, - RESTRICT_NO_CALL_EXPRS, - RESTRICT_NO_BAR_OP, -} - -enum file_type { CRATE_FILE, SOURCE_FILE, } - -type parse_sess = @{ - cm: codemap::codemap, - mutable next_id: node_id, - span_diagnostic: diagnostic::span_handler, - // these two must be kept up to date - mutable chpos: uint, - mutable byte_pos: uint -}; - -fn next_node_id(sess: parse_sess) -> node_id { - let rv = sess.next_id; - sess.next_id += 1; - // ID 0 is reserved for the crate and doesn't actually exist in the AST - assert rv != 0; - ret rv; -} - -type parser = @{ - sess: parse_sess, - cfg: ast::crate_cfg, - file_type: file_type, - mutable token: token::token, - mutable span: span, - mutable last_span: span, - mutable buffer: [{tok: token::token, span: span}], - mutable restriction: restriction, - reader: reader, - precs: @[op_spec], - bad_expr_words: hashmap<str, ()> -}; - -impl parser for parser { - fn bump() { - self.last_span = self.span; - if vec::len(self.buffer) == 0u { - let next = lexer::next_token(self.reader); - self.token = next.tok; - self.span = ast_util::mk_sp(next.chpos, self.reader.chpos); - } else { - let next = vec::pop(self.buffer); - self.token = next.tok; - self.span = next.span; - } - } - fn swap(next: token::token, lo: uint, hi: uint) { - self.token = next; - self.span = ast_util::mk_sp(lo, hi); - } - fn look_ahead(distance: uint) -> token::token { - while vec::len(self.buffer) < distance { - let next = lexer::next_token(self.reader); - let sp = ast_util::mk_sp(next.chpos, self.reader.chpos); - self.buffer = [{tok: next.tok, span: sp}] + self.buffer; - } - ret self.buffer[distance - 1u].tok; - } - fn fatal(m: str) -> ! { - self.sess.span_diagnostic.span_fatal(self.span, m) - } - fn span_fatal(sp: span, m: str) -> ! { - self.sess.span_diagnostic.span_fatal(sp, m) - } - fn warn(m: str) { - self.sess.span_diagnostic.span_warn(self.span, m) - } - fn get_str(i: token::str_num) -> str { - interner::get(*self.reader.interner, i) - } - fn get_id() -> node_id { next_node_id(self.sess) } -} - -fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str, - ftype: file_type) -> - parser { - let src = alt io::read_whole_file_str(path) { - result::ok(src) { - // FIXME: This copy is unfortunate - @src - } - result::err(e) { - sess.span_diagnostic.handler().fatal(e) - } - }; - let filemap = codemap::new_filemap(path, src, - sess.chpos, sess.byte_pos); - sess.cm.files += [filemap]; - let itr = @interner::mk(str::hash, str::eq); - let rdr = lexer::new_reader(sess.cm, sess.span_diagnostic, filemap, itr); - ret new_parser(sess, cfg, rdr, ftype); -} - -fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg, - name: str, ss: codemap::file_substr, - source: @str) -> parser { - let ftype = SOURCE_FILE; - let filemap = codemap::new_filemap_w_substr - (name, ss, source, sess.chpos, sess.byte_pos); - sess.cm.files += [filemap]; - let itr = @interner::mk(str::hash, str::eq); - let rdr = lexer::new_reader(sess.cm, sess.span_diagnostic, - filemap, itr); - ret new_parser(sess, cfg, rdr, ftype); -} - -fn new_parser(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, - ftype: file_type) -> parser { - let tok0 = lexer::next_token(rdr); - let span0 = ast_util::mk_sp(tok0.chpos, rdr.chpos); - @{sess: sess, - cfg: cfg, - file_type: ftype, - mutable token: tok0.tok, - mutable span: span0, - mutable last_span: span0, - mutable buffer: [], - mutable restriction: UNRESTRICTED, - reader: rdr, - precs: prec_table(), - bad_expr_words: bad_expr_word_table()} -} - -// These are the words that shouldn't be allowed as value identifiers, -// because, if used at the start of a line, they will cause the line to be -// interpreted as a specific kind of statement, which would be confusing. -fn bad_expr_word_table() -> hashmap<str, ()> { - let words = new_str_hash(); - for word in ["alt", "assert", "be", "break", "check", "claim", - "class", "const", "cont", "copy", "do", "else", "enum", - "export", "fail", "fn", "for", "if", "iface", "impl", - "import", "let", "log", "mod", "mutable", "native", "pure", - "resource", "ret", "trait", "type", "unchecked", "unsafe", - "while", "crust", "mut"] { - words.insert(word, ()); - } - words -} - -fn unexpected(p: parser, t: token::token) -> ! { - let s: str = "unexpected token: '" + token::to_str(p.reader, t) + - "'"; - p.fatal(s); -} - -fn expect(p: parser, t: token::token) { - if p.token == t { - p.bump(); - } else { - let s: str = "expecting '"; - s += token::to_str(p.reader, t); - s += "' but found '"; - s += token::to_str(p.reader, p.token); - p.fatal(s + "'"); - } -} - -fn expect_gt(p: parser) { - if p.token == token::GT { - p.bump(); - } else if p.token == token::BINOP(token::LSR) { - p.swap(token::GT, p.span.lo + 1u, p.span.hi); - } else if p.token == token::BINOP(token::ASR) { - p.swap(token::BINOP(token::LSR), p.span.lo + 1u, p.span.hi); - } else { - let s: str = "expecting "; - s += token::to_str(p.reader, token::GT); - s += ", found "; - s += token::to_str(p.reader, p.token); - p.fatal(s); - } -} - -fn spanned<T: copy>(lo: uint, hi: uint, node: T) -> spanned<T> { - ret {node: node, span: ast_util::mk_sp(lo, hi)}; -} - -fn parse_ident(p: parser) -> ast::ident { - alt p.token { - token::IDENT(i, _) { p.bump(); ret p.get_str(i); } - _ { p.fatal("expecting ident, found " - + token::to_str(p.reader, p.token)); } - } -} - -fn parse_path_list_ident(p: parser) -> ast::path_list_ident { - let lo = p.span.lo; - let ident = parse_ident(p); - let hi = p.span.hi; - ret spanned(lo, hi, {name: ident, id: p.get_id()}); -} - -fn parse_value_ident(p: parser) -> ast::ident { - check_bad_word(p); - ret parse_ident(p); -} - -fn eat(p: parser, tok: token::token) -> bool { - ret if p.token == tok { p.bump(); true } else { false }; -} - -fn is_word(p: parser, word: str) -> bool { - ret alt p.token { - token::IDENT(sid, false) { str::eq(word, p.get_str(sid)) } - _ { false } - }; -} - -fn eat_word(p: parser, word: str) -> bool { - alt p.token { - token::IDENT(sid, false) { - if str::eq(word, p.get_str(sid)) { - p.bump(); - ret true; - } else { ret false; } - } - _ { ret false; } - } -} - -fn expect_word(p: parser, word: str) { - if !eat_word(p, word) { - p.fatal("expecting " + word + ", found " + - token::to_str(p.reader, p.token)); - } -} - -fn check_bad_word(p: parser) { - alt p.token { - token::IDENT(sid, false) { - let w = p.get_str(sid); - if p.bad_expr_words.contains_key(w) { - p.fatal("found " + w + " in expression position"); - } - } - _ { } - } -} - -fn parse_ty_fn(p: parser) -> ast::fn_decl { - fn parse_fn_input_ty(p: parser) -> ast::arg { - let mode = parse_arg_mode(p); - let name = if is_plain_ident(p) && p.look_ahead(1u) == token::COLON { - let name = parse_value_ident(p); - p.bump(); - name - } else { "" }; - ret {mode: mode, ty: parse_ty(p, false), ident: name, id: p.get_id()}; - } - let inputs = - parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), - parse_fn_input_ty, p); - // FIXME: there's no syntax for this right now anyway - // auto constrs = parse_constrs(~[], p); - let constrs: [@ast::constr] = []; - let (ret_style, ret_ty) = parse_ret_ty(p); - ret {inputs: inputs.node, output: ret_ty, - purity: ast::impure_fn, cf: ret_style, - constraints: constrs}; -} - -fn parse_ty_methods(p: parser) -> [ast::ty_method] { - parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), {|p| - let attrs = parse_outer_attributes(p); - let flo = p.span.lo; - let pur = parse_fn_purity(p); - let ident = parse_method_name(p); - let tps = parse_ty_params(p); - let d = parse_ty_fn(p), fhi = p.last_span.hi; - expect(p, token::SEMI); - {ident: ident, attrs: attrs, decl: {purity: pur with d}, tps: tps, - span: ast_util::mk_sp(flo, fhi)} - }, p).node -} - -fn parse_mt(p: parser) -> ast::mt { - let mutbl = parse_mutability(p); - let t = parse_ty(p, false); - ret {ty: t, mutbl: mutbl}; -} - -fn parse_ty_field(p: parser) -> ast::ty_field { - let lo = p.span.lo; - let mutbl = parse_mutability(p); - let id = parse_ident(p); - expect(p, token::COLON); - let ty = parse_ty(p, false); - ret spanned(lo, ty.span.hi, {ident: id, mt: {ty: ty, mutbl: mutbl}}); -} - -// if i is the jth ident in args, return j -// otherwise, fail -fn ident_index(p: parser, args: [ast::arg], i: ast::ident) -> uint { - let j = 0u; - for a: ast::arg in args { if a.ident == i { ret j; } j += 1u; } - p.fatal("Unbound variable " + i + " in constraint arg"); -} - -fn parse_type_constr_arg(p: parser) -> @ast::ty_constr_arg { - let sp = p.span; - let carg = ast::carg_base; - expect(p, token::BINOP(token::STAR)); - if p.token == token::DOT { - // "*..." notation for record fields - p.bump(); - let pth = parse_path(p); - carg = ast::carg_ident(pth); - } - // No literals yet, I guess? - ret @{node: carg, span: sp}; -} - -fn parse_constr_arg(args: [ast::arg], p: parser) -> @ast::constr_arg { - let sp = p.span; - let carg = ast::carg_base; - if p.token == token::BINOP(token::STAR) { - p.bump(); - } else { - let i: ast::ident = parse_value_ident(p); - carg = ast::carg_ident(ident_index(p, args, i)); - } - ret @{node: carg, span: sp}; -} - -fn parse_ty_constr(fn_args: [ast::arg], p: parser) -> @ast::constr { - let lo = p.span.lo; - let path = parse_path(p); - let args: {node: [@ast::constr_arg], span: span} = - parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), - {|p| parse_constr_arg(fn_args, p)}, p); - ret @spanned(lo, args.span.hi, - {path: path, args: args.node, id: p.get_id()}); -} - -fn parse_constr_in_type(p: parser) -> @ast::ty_constr { - let lo = p.span.lo; - let path = parse_path(p); - let args: [@ast::ty_constr_arg] = - parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), - parse_type_constr_arg, p).node; - let hi = p.span.lo; - let tc: ast::ty_constr_ = {path: path, args: args, id: p.get_id()}; - ret @spanned(lo, hi, tc); -} - - -fn parse_constrs<T: copy>(pser: fn(parser) -> @ast::constr_general<T>, - p: parser) -> - [@ast::constr_general<T>] { - let constrs: [@ast::constr_general<T>] = []; - while true { - let constr = pser(p); - constrs += [constr]; - if p.token == token::COMMA { p.bump(); } else { break; } - } - constrs -} - -fn parse_type_constraints(p: parser) -> [@ast::ty_constr] { - ret parse_constrs(parse_constr_in_type, p); -} - -fn parse_ty_postfix(orig_t: ast::ty_, p: parser, colons_before_params: bool, - lo: uint) -> @ast::ty { - if colons_before_params && p.token == token::MOD_SEP { - p.bump(); - expect(p, token::LT); - } else if !colons_before_params && p.token == token::LT { - p.bump(); - } else { ret @spanned(lo, p.last_span.hi, orig_t); } - - // If we're here, we have explicit type parameter instantiation. - let seq = parse_seq_to_gt(some(token::COMMA), {|p| parse_ty(p, false)}, - p); - - alt orig_t { - ast::ty_path(pth, ann) { - ret @spanned(lo, p.last_span.hi, - ast::ty_path(@spanned(lo, p.last_span.hi, - {global: pth.node.global, - idents: pth.node.idents, - types: seq}), ann)); - } - _ { p.fatal("type parameter instantiation only allowed for paths"); } - } -} - -fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) { - ret if eat(p, token::RARROW) { - let lo = p.span.lo; - if eat(p, token::NOT) { - (ast::noreturn, @spanned(lo, p.last_span.hi, ast::ty_bot)) - } else { (ast::return_val, parse_ty(p, false)) } - } else { - let pos = p.span.lo; - (ast::return_val, @spanned(pos, pos, ast::ty_nil)) - } -} - -fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty { - let lo = p.span.lo; - - alt have_dollar(p) { - some(e) {ret @spanned(lo, p.span.hi, - ast::ty_mac(spanned(lo, p.span.hi, e)))} - none {} - } - - let t = if p.token == token::LPAREN { - p.bump(); - if p.token == token::RPAREN { - p.bump(); - ast::ty_nil - } else { - let ts = [parse_ty(p, false)]; - while p.token == token::COMMA { - p.bump(); - ts += [parse_ty(p, false)]; - } - let t = if vec::len(ts) == 1u { ts[0].node } - else { ast::ty_tup(ts) }; - expect(p, token::RPAREN); - t - } - } else if p.token == token::AT { - p.bump(); - ast::ty_box(parse_mt(p)) - } else if p.token == token::TILDE { - p.bump(); - ast::ty_uniq(parse_mt(p)) - } else if p.token == token::BINOP(token::STAR) { - p.bump(); - ast::ty_ptr(parse_mt(p)) - } else if p.token == token::LBRACE { - let elems = - parse_seq(token::LBRACE, token::RBRACE, seq_sep_opt(token::COMMA), - parse_ty_field, p); - if vec::len(elems.node) == 0u { unexpected(p, token::RBRACE); } - let hi = elems.span.hi; - - let t = ast::ty_rec(elems.node); - if p.token == token::COLON { - p.bump(); - ast::ty_constr(@spanned(lo, hi, t), parse_type_constraints(p)) - } else { t } - } else if p.token == token::LBRACKET { - expect(p, token::LBRACKET); - let t = ast::ty_vec(parse_mt(p)); - expect(p, token::RBRACKET); - t - } else if eat_word(p, "fn") { - let proto = parse_fn_ty_proto(p); - alt proto { - ast::proto_bare { p.warn("fn is deprecated, use native fn"); } - _ { /* fallthrough */ } - } - ast::ty_fn(proto, parse_ty_fn(p)) - } else if eat_word(p, "native") { - expect_word(p, "fn"); - ast::ty_fn(ast::proto_bare, parse_ty_fn(p)) - } else if p.token == token::MOD_SEP || is_ident(p.token) { - let path = parse_path(p); - ast::ty_path(path, p.get_id()) - } else { p.fatal("expecting type"); }; - ret parse_ty_postfix(t, p, colons_before_params, lo); -} - -fn parse_arg_mode(p: parser) -> ast::mode { - if eat(p, token::BINOP(token::AND)) { - ast::expl(ast::by_mutbl_ref) - } else if eat(p, token::BINOP(token::MINUS)) { - ast::expl(ast::by_move) - } else if eat(p, token::ANDAND) { - ast::expl(ast::by_ref) - } else if eat(p, token::BINOP(token::PLUS)) { - if eat(p, token::BINOP(token::PLUS)) { - ast::expl(ast::by_val) - } else { - ast::expl(ast::by_copy) - } - } else { ast::infer(p.get_id()) } -} - -fn parse_arg(p: parser) -> ast::arg { - let m = parse_arg_mode(p); - let i = parse_value_ident(p); - expect(p, token::COLON); - let t = parse_ty(p, false); - ret {mode: m, ty: t, ident: i, id: p.get_id()}; -} - -fn parse_fn_block_arg(p: parser) -> ast::arg { - let m = parse_arg_mode(p); - let i = parse_value_ident(p); - let t = if eat(p, token::COLON) { - parse_ty(p, false) - } else { - @spanned(p.span.lo, p.span.hi, ast::ty_infer) - }; - ret {mode: m, ty: t, ident: i, id: p.get_id()}; -} - -fn parse_seq_to_before_gt<T: copy>(sep: option<token::token>, - f: fn(parser) -> T, - p: parser) -> [T] { - let first = true; - let v = []; - while p.token != token::GT && p.token != token::BINOP(token::LSR) && - p.token != token::BINOP(token::ASR) { - alt sep { - some(t) { if first { first = false; } else { expect(p, t); } } - _ { } - } - v += [f(p)]; - } - - ret v; -} - -fn parse_seq_to_gt<T: copy>(sep: option<token::token>, - f: fn(parser) -> T, p: parser) -> [T] { - let v = parse_seq_to_before_gt(sep, f, p); - expect_gt(p); - - ret v; -} - -fn parse_seq_lt_gt<T: copy>(sep: option<token::token>, - f: fn(parser) -> T, - p: parser) -> spanned<[T]> { - let lo = p.span.lo; - expect(p, token::LT); - let result = parse_seq_to_before_gt::<T>(sep, f, p); - let hi = p.span.hi; - expect_gt(p); - ret spanned(lo, hi, result); -} - -fn parse_seq_to_end<T: copy>(ket: token::token, sep: seq_sep, - f: fn(parser) -> T, p: parser) -> [T] { - let val = parse_seq_to_before_end(ket, sep, f, p); - p.bump(); - ret val; -} - -type seq_sep = { - sep: option<token::token>, - trailing_opt: bool // is trailing separator optional? -}; - -fn seq_sep(t: token::token) -> seq_sep { - ret {sep: option::some(t), trailing_opt: false}; -} -fn seq_sep_opt(t: token::token) -> seq_sep { - ret {sep: option::some(t), trailing_opt: true}; -} -fn seq_sep_none() -> seq_sep { - ret {sep: option::none, trailing_opt: false}; -} - -fn parse_seq_to_before_end<T: copy>(ket: token::token, - sep: seq_sep, - f: fn(parser) -> T, p: parser) -> [T] { - let first: bool = true; - let v: [T] = []; - while p.token != ket { - alt sep.sep { - some(t) { if first { first = false; } else { expect(p, t); } } - _ { } - } - if sep.trailing_opt && p.token == ket { break; } - v += [f(p)]; - } - ret v; -} - - -fn parse_seq<T: copy>(bra: token::token, ket: token::token, - sep: seq_sep, f: fn(parser) -> T, - p: parser) -> spanned<[T]> { - let lo = p.span.lo; - expect(p, bra); - let result = parse_seq_to_before_end::<T>(ket, sep, f, p); - let hi = p.span.hi; - p.bump(); - ret spanned(lo, hi, result); -} - -fn have_dollar(p: parser) -> option::t<ast::mac_> { - alt p.token { - token::DOLLAR_NUM(num) { - p.bump(); - some(ast::mac_var(num)) - } - token::DOLLAR_LPAREN { - let lo = p.span.lo; - p.bump(); - let e = parse_expr(p); - expect(p, token::RPAREN); - let hi = p.last_span.hi; - some(ast::mac_aq(ast_util::mk_sp(lo,hi), e)) - } - _ {none} - } -} - -fn lit_from_token(p: parser, tok: token::token) -> ast::lit_ { - alt tok { - token::LIT_INT(i, it) { ast::lit_int(i, it) } - token::LIT_UINT(u, ut) { ast::lit_uint(u, ut) } - token::LIT_FLOAT(s, ft) { ast::lit_float(p.get_str(s), ft) } - token::LIT_STR(s) { ast::lit_str(p.get_str(s)) } - token::LPAREN { expect(p, token::RPAREN); ast::lit_nil } - _ { unexpected(p, tok); } - } -} - -fn parse_lit(p: parser) -> ast::lit { - let sp = p.span; - let lit = if eat_word(p, "true") { - ast::lit_bool(true) - } else if eat_word(p, "false") { - ast::lit_bool(false) - } else { - let tok = p.token; - p.bump(); - lit_from_token(p, tok) - }; - ret {node: lit, span: sp}; -} - -fn is_ident(t: token::token) -> bool { - alt t { token::IDENT(_, _) { ret true; } _ { } } - ret false; -} - -fn is_plain_ident(p: parser) -> bool { - ret alt p.token { token::IDENT(_, false) { true } _ { false } }; -} - -fn parse_path(p: parser) -> @ast::path { - let lo = p.span.lo; - let global = eat(p, token::MOD_SEP), ids = [parse_ident(p)]; - while p.look_ahead(1u) != token::LT && eat(p, token::MOD_SEP) { - ids += [parse_ident(p)]; - } - ret @spanned(lo, p.last_span.hi, - {global: global, idents: ids, types: []}); -} - -fn parse_value_path(p: parser) -> @ast::path { - let pt = parse_path(p); - let last_word = pt.node.idents[vec::len(pt.node.idents)-1u]; - if p.bad_expr_words.contains_key(last_word) { - p.fatal("found " + last_word + " in expression position"); - } - pt -} - -fn parse_path_and_ty_param_substs(p: parser, colons: bool) -> @ast::path { - let lo = p.span.lo; - let path = parse_path(p); - let b = if colons { - eat(p, token::MOD_SEP) - } else { - p.token == token::LT - }; - if b { - let seq = parse_seq_lt_gt(some(token::COMMA), - {|p| parse_ty(p, false)}, p); - @spanned(lo, seq.span.hi, {types: seq.node with path.node}) - } else { path } -} - -fn parse_mutability(p: parser) -> ast::mutability { - if eat_word(p, "mutable") { - ast::m_mutbl - } else if eat_word(p, "mut") { - ast::m_mutbl - } else if eat_word(p, "const") { - ast::m_const - } else { - ast::m_imm - } -} - -fn parse_field(p: parser, sep: token::token) -> ast::field { - let lo = p.span.lo; - let m = parse_mutability(p); - let i = parse_ident(p); - expect(p, sep); - let e = parse_expr(p); - ret spanned(lo, e.span.hi, {mutbl: m, ident: i, expr: e}); -} - -fn mk_expr(p: parser, lo: uint, hi: uint, node: ast::expr_) -> @ast::expr { - ret @{id: p.get_id(), node: node, span: ast_util::mk_sp(lo, hi)}; -} - -fn mk_mac_expr(p: parser, lo: uint, hi: uint, m: ast::mac_) -> @ast::expr { - ret @{id: p.get_id(), - node: ast::expr_mac({node: m, span: ast_util::mk_sp(lo, hi)}), - span: ast_util::mk_sp(lo, hi)}; -} - -fn is_bar(t: token::token) -> bool { - alt t { token::BINOP(token::OR) | token::OROR { true } _ { false } } -} - -fn mk_lit_u32(p: parser, i: u32) -> @ast::expr { - let span = p.span; - let lv_lit = @{node: ast::lit_uint(i as u64, ast::ty_u32), - span: span}; - - ret @{id: p.get_id(), node: ast::expr_lit(lv_lit), span: span}; -} - -// We don't allow single-entry tuples in the true AST; that indicates a -// parenthesized expression. However, we preserve them temporarily while -// parsing because `(while{...})+3` parses differently from `while{...}+3`. -// -// To reflect the fact that the @ast::expr is not a true expr that should be -// part of the AST, we wrap such expressions in the pexpr enum. They -// can then be converted to true expressions by a call to `to_expr()`. -enum pexpr { - pexpr(@ast::expr), -} - -fn mk_pexpr(p: parser, lo: uint, hi: uint, node: ast::expr_) -> pexpr { - ret pexpr(mk_expr(p, lo, hi, node)); -} - -fn to_expr(e: pexpr) -> @ast::expr { - alt e.node { - ast::expr_tup(es) if vec::len(es) == 1u { es[0u] } - _ { *e } - } -} - -fn parse_bottom_expr(p: parser) -> pexpr { - let lo = p.span.lo; - let hi = p.span.hi; - - let ex: ast::expr_; - - alt have_dollar(p) { - some(x) {ret pexpr(mk_mac_expr(p, lo, p.span.hi, x));} - _ {} - } - - if p.token == token::LPAREN { - p.bump(); - if p.token == token::RPAREN { - hi = p.span.hi; - p.bump(); - let lit = @spanned(lo, hi, ast::lit_nil); - ret mk_pexpr(p, lo, hi, ast::expr_lit(lit)); - } - let es = [parse_expr(p)]; - while p.token == token::COMMA { p.bump(); es += [parse_expr(p)]; } - hi = p.span.hi; - expect(p, token::RPAREN); - - // Note: we retain the expr_tup() even for simple - // parenthesized expressions, but only for a "little while". - // This is so that wrappers around parse_bottom_expr() - // can tell whether the expression was parenthesized or not, - // which affects expr_is_complete(). - ret mk_pexpr(p, lo, hi, ast::expr_tup(es)); - } else if p.token == token::LBRACE { - p.bump(); - if is_word(p, "mut") || is_word(p, "mutable") || - is_plain_ident(p) && p.look_ahead(1u) == token::COLON { - let fields = [parse_field(p, token::COLON)]; - let base = none; - while p.token != token::RBRACE { - if eat_word(p, "with") { base = some(parse_expr(p)); break; } - expect(p, token::COMMA); - if p.token == token::RBRACE { - // record ends by an optional trailing comma - break; - } - fields += [parse_field(p, token::COLON)]; - } - hi = p.span.hi; - expect(p, token::RBRACE); - ex = ast::expr_rec(fields, base); - } else if is_bar(p.token) { - ret pexpr(parse_fn_block_expr(p)); - } else { - let blk = parse_block_tail(p, lo, ast::default_blk); - ret mk_pexpr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); - } - } else if eat_word(p, "if") { - ret pexpr(parse_if_expr(p)); - } else if eat_word(p, "for") { - ret pexpr(parse_for_expr(p)); - } else if eat_word(p, "while") { - ret pexpr(parse_while_expr(p)); - } else if eat_word(p, "do") { - ret pexpr(parse_do_while_expr(p)); - } else if eat_word(p, "alt") { - ret pexpr(parse_alt_expr(p)); - } else if eat_word(p, "fn") { - let proto = parse_fn_ty_proto(p); - alt proto { - ast::proto_bare { p.fatal("fn expr are deprecated, use fn@"); } - ast::proto_any { p.fatal("fn* cannot be used in an expression"); } - _ { /* fallthrough */ } - } - ret pexpr(parse_fn_expr(p, proto)); - } else if eat_word(p, "unchecked") { - ret pexpr(parse_block_expr(p, lo, ast::unchecked_blk)); - } else if eat_word(p, "unsafe") { - ret pexpr(parse_block_expr(p, lo, ast::unsafe_blk)); - } else if p.token == token::LBRACKET { - p.bump(); - let mutbl = parse_mutability(p); - let es = - parse_seq_to_end(token::RBRACKET, seq_sep(token::COMMA), - parse_expr, p); - ex = ast::expr_vec(es, mutbl); - } else if p.token == token::POUND_LT { - p.bump(); - let ty = parse_ty(p, false); - expect(p, token::GT); - - /* hack: early return to take advantage of specialized function */ - ret pexpr(mk_mac_expr(p, lo, p.span.hi, - ast::mac_embed_type(ty))); - } else if p.token == token::POUND_LBRACE { - p.bump(); - let blk = ast::mac_embed_block( - parse_block_tail(p, lo, ast::default_blk)); - ret pexpr(mk_mac_expr(p, lo, p.span.hi, blk)); - } else if p.token == token::ELLIPSIS { - p.bump(); - ret pexpr(mk_mac_expr(p, lo, p.span.hi, ast::mac_ellipsis)); - } else if eat_word(p, "bind") { - let e = parse_expr_res(p, RESTRICT_NO_CALL_EXPRS); - let es = - parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), - parse_expr_or_hole, p); - hi = es.span.hi; - ex = ast::expr_bind(e, es.node); - } else if p.token == token::POUND { - let ex_ext = parse_syntax_ext(p); - hi = ex_ext.span.hi; - ex = ex_ext.node; - } else if eat_word(p, "fail") { - if can_begin_expr(p.token) { - let e = parse_expr(p); - hi = e.span.hi; - ex = ast::expr_fail(some(e)); - } else { ex = ast::expr_fail(none); } - } else if eat_word(p, "log") { - expect(p, token::LPAREN); - let lvl = parse_expr(p); - expect(p, token::COMMA); - let e = parse_expr(p); - ex = ast::expr_log(2, lvl, e); - hi = p.span.hi; - expect(p, token::RPAREN); - } else if eat_word(p, "assert") { - let e = parse_expr(p); - ex = ast::expr_assert(e); - hi = e.span.hi; - } else if eat_word(p, "check") { - /* Should be a predicate (pure boolean function) applied to - arguments that are all either slot variables or literals. - but the typechecker enforces that. */ - let e = parse_expr(p); - hi = e.span.hi; - ex = ast::expr_check(ast::checked_expr, e); - } else if eat_word(p, "claim") { - /* Same rules as check, except that if check-claims - is enabled (a command-line flag), then the parser turns - claims into check */ - - let e = parse_expr(p); - hi = e.span.hi; - ex = ast::expr_check(ast::claimed_expr, e); - } else if eat_word(p, "ret") { - if can_begin_expr(p.token) { - let e = parse_expr(p); - hi = e.span.hi; - ex = ast::expr_ret(some(e)); - } else { ex = ast::expr_ret(none); } - } else if eat_word(p, "break") { - ex = ast::expr_break; - hi = p.span.hi; - } else if eat_word(p, "cont") { - ex = ast::expr_cont; - hi = p.span.hi; - } else if eat_word(p, "be") { - let e = parse_expr(p); - - // FIXME: Is this the right place for this check? - if /*check*/ast_util::is_call_expr(e) { - hi = e.span.hi; - ex = ast::expr_be(e); - } else { p.fatal("Non-call expression in tail call"); } - } else if eat_word(p, "copy") { - let e = parse_expr(p); - ex = ast::expr_copy(e); - hi = e.span.hi; - } else if p.token == token::MOD_SEP || - is_ident(p.token) && !is_word(p, "true") && - !is_word(p, "false") { - check_bad_word(p); - let pth = parse_path_and_ty_param_substs(p, true); - hi = pth.span.hi; - ex = ast::expr_path(pth); - } else { - let lit = parse_lit(p); - hi = lit.span.hi; - ex = ast::expr_lit(@lit); - } - ret mk_pexpr(p, lo, hi, ex); -} - -fn parse_block_expr(p: parser, - lo: uint, - blk_mode: ast::blk_check_mode) -> @ast::expr { - expect(p, token::LBRACE); - let blk = parse_block_tail(p, lo, blk_mode); - ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); -} - -fn parse_syntax_ext(p: parser) -> @ast::expr { - let lo = p.span.lo; - expect(p, token::POUND); - ret parse_syntax_ext_naked(p, lo); -} - -fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr { - alt p.token { - token::IDENT(_, _) {} - _ { p.fatal("expected a syntax expander name"); } - } - let pth = parse_path(p); - //temporary for a backwards-compatible cycle: - let sep = seq_sep(token::COMMA); - let e = none; - if (p.token == token::LPAREN || p.token == token::LBRACKET) { - let es = - if p.token == token::LPAREN { - parse_seq(token::LPAREN, token::RPAREN, - sep, parse_expr, p) - } else { - parse_seq(token::LBRACKET, token::RBRACKET, - sep, parse_expr, p) - }; - let hi = es.span.hi; - e = some(mk_expr(p, es.span.lo, hi, - ast::expr_vec(es.node, ast::m_imm))); - } - let b = none; - if p.token == token::LBRACE { - p.bump(); - let lo = p.span.lo; - let depth = 1u; - while (depth > 0u) { - alt (p.token) { - token::LBRACE {depth += 1u;} - token::RBRACE {depth -= 1u;} - token::EOF {p.fatal("unexpected EOF in macro body");} - _ {} - } - p.bump(); - } - let hi = p.last_span.lo; - b = some({span: mk_sp(lo,hi)}); - } - ret mk_mac_expr(p, lo, p.span.hi, ast::mac_invoc(pth, e, b)); -} - -fn parse_dot_or_call_expr(p: parser) -> pexpr { - let b = parse_bottom_expr(p); - parse_dot_or_call_expr_with(p, b) -} - -fn permits_call(p: parser) -> bool { - ret p.restriction != RESTRICT_NO_CALL_EXPRS; -} - -fn parse_dot_or_call_expr_with(p: parser, e0: pexpr) -> pexpr { - let e = e0; - let lo = e.span.lo; - let hi = e.span.hi; - while true { - // expr.f - if eat(p, token::DOT) { - alt p.token { - token::IDENT(i, _) { - hi = p.span.hi; - p.bump(); - let tys = if eat(p, token::MOD_SEP) { - expect(p, token::LT); - parse_seq_to_gt(some(token::COMMA), - {|p| parse_ty(p, false)}, p) - } else { [] }; - e = mk_pexpr(p, lo, hi, - ast::expr_field(to_expr(e), - p.get_str(i), - tys)); - } - t { unexpected(p, t); } - } - cont; - } - if expr_is_complete(p, e) { break; } - alt p.token { - // expr(...) - token::LPAREN if permits_call(p) { - let es_opt = - parse_seq(token::LPAREN, token::RPAREN, - seq_sep(token::COMMA), parse_expr_or_hole, p); - hi = es_opt.span.hi; - - let nd = - if vec::any(es_opt.node, {|e| option::is_none(e) }) { - ast::expr_bind(to_expr(e), es_opt.node) - } else { - let es = vec::map(es_opt.node) {|e| option::get(e) }; - ast::expr_call(to_expr(e), es, false) - }; - e = mk_pexpr(p, lo, hi, nd); - } - - // expr {|| ... } - token::LBRACE if is_bar(p.look_ahead(1u)) && permits_call(p) { - p.bump(); - let blk = parse_fn_block_expr(p); - alt e.node { - ast::expr_call(f, args, false) { - e = pexpr(@{node: ast::expr_call(f, args + [blk], true) - with *to_expr(e)}); - } - _ { - e = mk_pexpr(p, lo, p.last_span.hi, - ast::expr_call(to_expr(e), [blk], true)); - } - } - } - - // expr[...] - token::LBRACKET { - p.bump(); - let ix = parse_expr(p); - hi = ix.span.hi; - expect(p, token::RBRACKET); - p.get_id(); // see ast_util::op_expr_callee_id - e = mk_pexpr(p, lo, hi, ast::expr_index(to_expr(e), ix)); - } - - _ { ret e; } - } - } - ret e; -} - -fn parse_prefix_expr(p: parser) -> pexpr { - let lo = p.span.lo; - let hi = p.span.hi; - - let ex; - alt p.token { - token::NOT { - p.bump(); - let e = to_expr(parse_prefix_expr(p)); - hi = e.span.hi; - p.get_id(); // see ast_util::op_expr_callee_id - ex = ast::expr_unary(ast::not, e); - } - token::BINOP(b) { - alt b { - token::MINUS { - p.bump(); - let e = to_expr(parse_prefix_expr(p)); - hi = e.span.hi; - p.get_id(); // see ast_util::op_expr_callee_id - ex = ast::expr_unary(ast::neg, e); - } - token::STAR { - p.bump(); - let e = to_expr(parse_prefix_expr(p)); - hi = e.span.hi; - ex = ast::expr_unary(ast::deref, e); - } - _ { ret parse_dot_or_call_expr(p); } - } - } - token::AT { - p.bump(); - let m = parse_mutability(p); - let e = to_expr(parse_prefix_expr(p)); - hi = e.span.hi; - ex = ast::expr_unary(ast::box(m), e); - } - token::TILDE { - p.bump(); - let m = parse_mutability(p); - let e = to_expr(parse_prefix_expr(p)); - hi = e.span.hi; - ex = ast::expr_unary(ast::uniq(m), e); - } - _ { ret parse_dot_or_call_expr(p); } - } - ret mk_pexpr(p, lo, hi, ex); -} - -type op_spec = {tok: token::token, op: ast::binop, prec: int}; - - -// FIXME make this a const, don't store it in parser state -fn prec_table() -> @[op_spec] { - ret @[// 'as' sits between here with 12 - {tok: token::BINOP(token::STAR), op: ast::mul, prec: 11}, - {tok: token::BINOP(token::SLASH), op: ast::div, prec: 11}, - {tok: token::BINOP(token::PERCENT), op: ast::rem, prec: 11}, - {tok: token::BINOP(token::PLUS), op: ast::add, prec: 10}, - {tok: token::BINOP(token::MINUS), op: ast::subtract, prec: 10}, - {tok: token::BINOP(token::LSL), op: ast::lsl, prec: 9}, - {tok: token::BINOP(token::LSR), op: ast::lsr, prec: 9}, - {tok: token::BINOP(token::ASR), op: ast::asr, prec: 9}, - {tok: token::BINOP(token::AND), op: ast::bitand, prec: 8}, - {tok: token::BINOP(token::CARET), op: ast::bitxor, prec: 7}, - {tok: token::BINOP(token::OR), op: ast::bitor, prec: 6}, - {tok: token::LT, op: ast::lt, prec: 4}, - {tok: token::LE, op: ast::le, prec: 4}, - {tok: token::GE, op: ast::ge, prec: 4}, - {tok: token::GT, op: ast::gt, prec: 4}, - {tok: token::EQEQ, op: ast::eq, prec: 3}, - {tok: token::NE, op: ast::ne, prec: 3}, - {tok: token::ANDAND, op: ast::and, prec: 2}, - {tok: token::OROR, op: ast::or, prec: 1}]; -} - -fn parse_binops(p: parser) -> @ast::expr { - ret parse_more_binops(p, parse_prefix_expr(p), 0); -} - -const unop_prec: int = 100; - -const as_prec: int = 12; - -fn parse_more_binops(p: parser, plhs: pexpr, min_prec: int) -> - @ast::expr { - let lhs = to_expr(plhs); - if expr_is_complete(p, plhs) { ret lhs; } - let peeked = p.token; - if peeked == token::BINOP(token::OR) && - p.restriction == RESTRICT_NO_BAR_OP { ret lhs; } - for cur: op_spec in *p.precs { - if cur.prec > min_prec && cur.tok == peeked { - p.bump(); - let expr = parse_prefix_expr(p); - let rhs = parse_more_binops(p, expr, cur.prec); - p.get_id(); // see ast_util::op_expr_callee_id - let bin = mk_pexpr(p, lhs.span.lo, rhs.span.hi, - ast::expr_binary(cur.op, lhs, rhs)); - ret parse_more_binops(p, bin, min_prec); - } - } - if as_prec > min_prec && eat_word(p, "as") { - let rhs = parse_ty(p, true); - let _as = - mk_pexpr(p, lhs.span.lo, rhs.span.hi, ast::expr_cast(lhs, rhs)); - ret parse_more_binops(p, _as, min_prec); - } - ret lhs; -} - -fn parse_assign_expr(p: parser) -> @ast::expr { - let lo = p.span.lo; - let lhs = parse_binops(p); - alt p.token { - token::EQ { - p.bump(); - let rhs = parse_expr(p); - ret mk_expr(p, lo, rhs.span.hi, ast::expr_assign(lhs, rhs)); - } - token::BINOPEQ(op) { - p.bump(); - let rhs = parse_expr(p); - let aop = ast::add; - alt op { - token::PLUS { aop = ast::add; } - token::MINUS { aop = ast::subtract; } - token::STAR { aop = ast::mul; } - token::SLASH { aop = ast::div; } - token::PERCENT { aop = ast::rem; } - token::CARET { aop = ast::bitxor; } - token::AND { aop = ast::bitand; } - token::OR { aop = ast::bitor; } - token::LSL { aop = ast::lsl; } - token::LSR { aop = ast::lsr; } - token::ASR { aop = ast::asr; } - } - p.get_id(); // see ast_util::op_expr_callee_id - ret mk_expr(p, lo, rhs.span.hi, ast::expr_assign_op(aop, lhs, rhs)); - } - token::LARROW { - p.bump(); - let rhs = parse_expr(p); - ret mk_expr(p, lo, rhs.span.hi, ast::expr_move(lhs, rhs)); - } - token::DARROW { - p.bump(); - let rhs = parse_expr(p); - ret mk_expr(p, lo, rhs.span.hi, ast::expr_swap(lhs, rhs)); - } - _ {/* fall through */ } - } - ret lhs; -} - -fn parse_if_expr_1(p: parser) -> - {cond: @ast::expr, - then: ast::blk, - els: option<@ast::expr>, - lo: uint, - hi: uint} { - let lo = p.last_span.lo; - let cond = parse_expr(p); - let thn = parse_block(p); - let els: option<@ast::expr> = none; - let hi = thn.span.hi; - if eat_word(p, "else") { - let elexpr = parse_else_expr(p); - els = some(elexpr); - hi = elexpr.span.hi; - } - ret {cond: cond, then: thn, els: els, lo: lo, hi: hi}; -} - -fn parse_if_expr(p: parser) -> @ast::expr { - if eat_word(p, "check") { - let q = parse_if_expr_1(p); - ret mk_expr(p, q.lo, q.hi, ast::expr_if_check(q.cond, q.then, q.els)); - } else { - let q = parse_if_expr_1(p); - ret mk_expr(p, q.lo, q.hi, ast::expr_if(q.cond, q.then, q.els)); - } -} - -// Parses: -// -// CC := [copy ID*; move ID*] -// -// where any part is optional and trailing ; is permitted. -fn parse_capture_clause(p: parser) -> @ast::capture_clause { - fn expect_opt_trailing_semi(p: parser) { - if !eat(p, token::SEMI) { - if p.token != token::RBRACKET { - p.fatal("expecting ; or ]"); - } - } - } - - fn eat_ident_list(p: parser) -> [@ast::capture_item] { - let res = []; - while true { - alt p.token { - token::IDENT(_, _) { - let id = p.get_id(); - let sp = ast_util::mk_sp(p.span.lo, p.span.hi); - let ident = parse_ident(p); - res += [@{id:id, name:ident, span:sp}]; - if !eat(p, token::COMMA) { - ret res; - } - } - - _ { ret res; } - } - } - std::util::unreachable(); - } - - let copies = []; - let moves = []; - - if eat(p, token::LBRACKET) { - while !eat(p, token::RBRACKET) { - if eat_word(p, "copy") { - copies += eat_ident_list(p); - expect_opt_trailing_semi(p); - } else if eat_word(p, "move") { - moves += eat_ident_list(p); - expect_opt_trailing_semi(p); - } else { - let s: str = "expecting send, copy, or move clause"; - p.fatal(s); - } - } - } - - ret @{copies: copies, moves: moves}; -} - -fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr { - let lo = p.last_span.lo; - let capture_clause = parse_capture_clause(p); - let decl = parse_fn_decl(p, ast::impure_fn); - let body = parse_block(p); - ret mk_expr(p, lo, body.span.hi, - ast::expr_fn(proto, decl, body, capture_clause)); -} - -fn parse_fn_block_expr(p: parser) -> @ast::expr { - let lo = p.last_span.lo; - let decl = parse_fn_block_decl(p); - let body = parse_block_tail(p, lo, ast::default_blk); - ret mk_expr(p, lo, body.span.hi, ast::expr_fn_block(decl, body)); -} - -fn parse_else_expr(p: parser) -> @ast::expr { - if eat_word(p, "if") { - ret parse_if_expr(p); - } else { - let blk = parse_block(p); - ret mk_expr(p, blk.span.lo, blk.span.hi, ast::expr_block(blk)); - } -} - -fn parse_for_expr(p: parser) -> @ast::expr { - let lo = p.last_span.lo; - let decl = parse_local(p, false, false); - expect_word(p, "in"); - let seq = parse_expr(p); - let body = parse_block_no_value(p); - let hi = body.span.hi; - ret mk_expr(p, lo, hi, ast::expr_for(decl, seq, body)); -} - -fn parse_while_expr(p: parser) -> @ast::expr { - let lo = p.last_span.lo; - let cond = parse_expr(p); - let body = parse_block_no_value(p); - let hi = body.span.hi; - ret mk_expr(p, lo, hi, ast::expr_while(cond, body)); -} - -fn parse_do_while_expr(p: parser) -> @ast::expr { - let lo = p.last_span.lo; - let body = parse_block_no_value(p); - expect_word(p, "while"); - let cond = parse_expr(p); - let hi = cond.span.hi; - ret mk_expr(p, lo, hi, ast::expr_do_while(body, cond)); -} - -fn parse_alt_expr(p: parser) -> @ast::expr { - let lo = p.last_span.lo; - let mode = if eat_word(p, "check") { ast::alt_check } - else { ast::alt_exhaustive }; - let discriminant = parse_expr(p); - expect(p, token::LBRACE); - let arms: [ast::arm] = []; - while p.token != token::RBRACE { - let pats = parse_pats(p); - let guard = none; - if eat_word(p, "if") { guard = some(parse_expr(p)); } - let blk = parse_block(p); - arms += [{pats: pats, guard: guard, body: blk}]; - } - let hi = p.span.hi; - p.bump(); - ret mk_expr(p, lo, hi, ast::expr_alt(discriminant, arms, mode)); -} - -fn parse_expr(p: parser) -> @ast::expr { - ret parse_expr_res(p, UNRESTRICTED); -} - -fn parse_expr_or_hole(p: parser) -> option<@ast::expr> { - alt p.token { - token::UNDERSCORE { p.bump(); ret none; } - _ { ret some(parse_expr(p)); } - } -} - -fn parse_expr_res(p: parser, r: restriction) -> @ast::expr { - let old = p.restriction; - p.restriction = r; - let e = parse_assign_expr(p); - p.restriction = old; - ret e; -} - -fn parse_initializer(p: parser) -> option<ast::initializer> { - alt p.token { - token::EQ { - p.bump(); - ret some({op: ast::init_assign, expr: parse_expr(p)}); - } - token::LARROW { - p.bump(); - ret some({op: ast::init_move, expr: parse_expr(p)}); - } - // Now that the the channel is the first argument to receive, - // combining it with an initializer doesn't really make sense. - // case (token::RECV) { - // p.bump(); - // ret some(rec(op = ast::init_recv, - // expr = parse_expr(p))); - // } - _ { - ret none; - } - } -} - -fn parse_pats(p: parser) -> [@ast::pat] { - let pats = []; - while true { - pats += [parse_pat(p)]; - if p.token == token::BINOP(token::OR) { p.bump(); } else { break; } - } - ret pats; -} - -fn parse_pat(p: parser) -> @ast::pat { - let lo = p.span.lo; - let hi = p.span.hi; - let pat; - alt p.token { - token::UNDERSCORE { p.bump(); pat = ast::pat_wild; } - token::AT { - p.bump(); - let sub = parse_pat(p); - pat = ast::pat_box(sub); - hi = sub.span.hi; - } - token::TILDE { - p.bump(); - let sub = parse_pat(p); - pat = ast::pat_uniq(sub); - hi = sub.span.hi; - } - token::LBRACE { - p.bump(); - let fields = []; - let etc = false; - let first = true; - while p.token != token::RBRACE { - if first { first = false; } else { expect(p, token::COMMA); } - - if p.token == token::UNDERSCORE { - p.bump(); - if p.token != token::RBRACE { - p.fatal("expecting }, found " + - token::to_str(p.reader, p.token)); - } - etc = true; - break; - } - - let lo1 = p.last_span.lo; - let fieldname = parse_ident(p); - let hi1 = p.last_span.lo; - let fieldpath = ast_util::ident_to_path(ast_util::mk_sp(lo1, hi1), - fieldname); - let subpat; - if p.token == token::COLON { - p.bump(); - subpat = parse_pat(p); - } else { - if p.bad_expr_words.contains_key(fieldname) { - p.fatal("found " + fieldname + " in binding position"); - } - subpat = @{id: p.get_id(), - node: ast::pat_ident(fieldpath, none), - span: ast_util::mk_sp(lo, hi)}; - } - fields += [{ident: fieldname, pat: subpat}]; - } - hi = p.span.hi; - p.bump(); - pat = ast::pat_rec(fields, etc); - } - token::LPAREN { - p.bump(); - if p.token == token::RPAREN { - hi = p.span.hi; - p.bump(); - let lit = @{node: ast::lit_nil, span: ast_util::mk_sp(lo, hi)}; - let expr = mk_expr(p, lo, hi, ast::expr_lit(lit)); - pat = ast::pat_lit(expr); - } else { - let fields = [parse_pat(p)]; - while p.token == token::COMMA { - p.bump(); - fields += [parse_pat(p)]; - } - if vec::len(fields) == 1u { expect(p, token::COMMA); } - hi = p.span.hi; - expect(p, token::RPAREN); - pat = ast::pat_tup(fields); - } - } - tok { - if !is_ident(tok) || is_word(p, "true") || is_word(p, "false") { - let val = parse_expr_res(p, RESTRICT_NO_BAR_OP); - if eat_word(p, "to") { - let end = parse_expr_res(p, RESTRICT_NO_BAR_OP); - hi = end.span.hi; - pat = ast::pat_range(val, end); - } else { - hi = val.span.hi; - pat = ast::pat_lit(val); - } - } else if is_plain_ident(p) && - alt p.look_ahead(1u) { - token::LPAREN | token::LBRACKET | token::LT { false } - _ { true } - } { - let name = parse_value_path(p); - let sub = if eat(p, token::AT) { some(parse_pat(p)) } - else { none }; - pat = ast::pat_ident(name, sub); - } else { - let enum_path = parse_path_and_ty_param_substs(p, true); - hi = enum_path.span.hi; - let args: [@ast::pat]; - alt p.token { - token::LPAREN { - let a = - parse_seq(token::LPAREN, token::RPAREN, - seq_sep(token::COMMA), parse_pat, p); - args = a.node; - hi = a.span.hi; - } - _ { args = []; } - } - // at this point, we're not sure whether it's a enum or a bind - if vec::len(args) == 0u && - vec::len(enum_path.node.idents) == 1u { - pat = ast::pat_ident(enum_path, none); - } - else { - pat = ast::pat_enum(enum_path, args); - } - } - } - } - ret @{id: p.get_id(), node: pat, span: ast_util::mk_sp(lo, hi)}; -} - -fn parse_local(p: parser, is_mutbl: bool, - allow_init: bool) -> @ast::local { - let lo = p.span.lo; - let pat = parse_pat(p); - let ty = @spanned(lo, lo, ast::ty_infer); - if eat(p, token::COLON) { ty = parse_ty(p, false); } - let init = if allow_init { parse_initializer(p) } else { none }; - ret @spanned(lo, p.last_span.hi, - {is_mutbl: is_mutbl, ty: ty, pat: pat, - init: init, id: p.get_id()}); -} - -fn parse_let(p: parser) -> @ast::decl { - let is_mutbl = eat_word(p, "mut"); - let lo = p.span.lo; - let locals = [parse_local(p, is_mutbl, true)]; - while eat(p, token::COMMA) { - locals += [parse_local(p, is_mutbl, true)]; - } - ret @spanned(lo, p.last_span.hi, ast::decl_local(locals)); -} - -fn parse_instance_var(p:parser) -> ast::class_member { - let is_mutbl = ast::class_immutable; - expect_word(p, "let"); - if eat_word(p, "mut") || eat_word(p, "mutable") { - is_mutbl = ast::class_mutable; - } - if !is_plain_ident(p) { - p.fatal("expecting ident"); - } - let name = parse_ident(p); - expect(p, token::COLON); - let ty = parse_ty(p, false); - ret ast::instance_var(name, ty, is_mutbl, p.get_id()); -} - -fn parse_stmt(p: parser, first_item_attrs: [ast::attribute]) -> @ast::stmt { - fn check_expected_item(p: parser, current_attrs: [ast::attribute]) { - // If we have attributes then we should have an item - if vec::is_not_empty(current_attrs) { - p.fatal("expected item"); - } - } - - let lo = p.span.lo; - if is_word(p, "let") { - check_expected_item(p, first_item_attrs); - expect_word(p, "let"); - let decl = parse_let(p); - ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_id())); - } else { - let item_attrs; - alt parse_outer_attrs_or_ext(p, first_item_attrs) { - none { item_attrs = []; } - some(left(attrs)) { item_attrs = attrs; } - some(right(ext)) { - ret @spanned(lo, ext.span.hi, ast::stmt_expr(ext, p.get_id())); - } - } - - let item_attrs = first_item_attrs + item_attrs; - - alt parse_item(p, item_attrs) { - some(i) { - let hi = i.span.hi; - let decl = @spanned(lo, hi, ast::decl_item(i)); - ret @spanned(lo, hi, ast::stmt_decl(decl, p.get_id())); - } - none() { /* fallthrough */ } - } - - check_expected_item(p, item_attrs); - - // Remainder are line-expr stmts. - let e = parse_expr_res(p, RESTRICT_STMT_EXPR); - ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_id())); - } -} - -fn expr_is_complete(p: parser, e: pexpr) -> bool { - log(debug, ("expr_is_complete", p.restriction, - print::pprust::expr_to_str(*e), - expr_requires_semi_to_be_stmt(*e))); - ret p.restriction == RESTRICT_STMT_EXPR && - !expr_requires_semi_to_be_stmt(*e); -} - -fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool { - alt e.node { - ast::expr_if(_, _, _) | ast::expr_if_check(_, _, _) - | ast::expr_alt(_, _, _) | ast::expr_block(_) - | ast::expr_do_while(_, _) | ast::expr_while(_, _) - | ast::expr_for(_, _, _) - | ast::expr_call(_, _, true) { - false - } - _ { true } - } -} - -fn stmt_ends_with_semi(stmt: ast::stmt) -> bool { - alt stmt.node { - ast::stmt_decl(d, _) { - ret alt d.node { - ast::decl_local(_) { true } - ast::decl_item(_) { false } - } - } - ast::stmt_expr(e, _) { - ret expr_requires_semi_to_be_stmt(e); - } - ast::stmt_semi(e, _) { - ret false; - } - } -} - -fn parse_block(p: parser) -> ast::blk { - let (attrs, blk) = parse_inner_attrs_and_block(p, false); - assert vec::is_empty(attrs); - ret blk; -} - -fn parse_inner_attrs_and_block( - p: parser, parse_attrs: bool) -> ([ast::attribute], ast::blk) { - - fn maybe_parse_inner_attrs_and_next( - p: parser, parse_attrs: bool) -> - {inner: [ast::attribute], next: [ast::attribute]} { - if parse_attrs { - parse_inner_attrs_and_next(p) - } else { - {inner: [], next: []} - } - } - - let lo = p.span.lo; - if eat_word(p, "unchecked") { - expect(p, token::LBRACE); - let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs); - ret (inner, parse_block_tail_(p, lo, ast::unchecked_blk, next)); - } else if eat_word(p, "unsafe") { - expect(p, token::LBRACE); - let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs); - ret (inner, parse_block_tail_(p, lo, ast::unsafe_blk, next)); - } else { - expect(p, token::LBRACE); - let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs); - ret (inner, parse_block_tail_(p, lo, ast::default_blk, next)); - } -} - -fn parse_block_no_value(p: parser) -> ast::blk { - // We parse blocks that cannot have a value the same as any other block; - // the type checker will make sure that the tail expression (if any) has - // unit type. - ret parse_block(p); -} - -// Precondition: already parsed the '{' or '#{' -// I guess that also means "already parsed the 'impure'" if -// necessary, and this should take a qualifier. -// some blocks start with "#{"... -fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk { - parse_block_tail_(p, lo, s, []) -} - -fn parse_block_tail_(p: parser, lo: uint, s: ast::blk_check_mode, - first_item_attrs: [ast::attribute]) -> ast::blk { - let stmts = []; - let expr = none; - let view_items = maybe_parse_view_import_only(p, first_item_attrs); - let initial_attrs = first_item_attrs; - - if p.token == token::RBRACE && !vec::is_empty(initial_attrs) { - p.fatal("expected item"); - } - - while p.token != token::RBRACE { - alt p.token { - token::SEMI { - p.bump(); // empty - } - _ { - let stmt = parse_stmt(p, initial_attrs); - initial_attrs = []; - alt stmt.node { - ast::stmt_expr(e, stmt_id) { // Expression without semicolon: - alt p.token { - token::SEMI { - p.bump(); - stmts += [@{node: ast::stmt_semi(e, stmt_id) with *stmt}]; - } - token::RBRACE { - expr = some(e); - } - t { - if stmt_ends_with_semi(*stmt) { - p.fatal("expected ';' or '}' after expression but \ - found '" + token::to_str(p.reader, t) + - "'"); - } - stmts += [stmt]; - } - } - } - - _ { // All other kinds of statements: - stmts += [stmt]; - - if stmt_ends_with_semi(*stmt) { - expect(p, token::SEMI); - } - } - } - } - } - } - let hi = p.span.hi; - p.bump(); - let bloc = {view_items: view_items, stmts: stmts, expr: expr, - id: p.get_id(), rules: s}; - ret spanned(lo, hi, bloc); -} - -fn parse_ty_param(p: parser) -> ast::ty_param { - let bounds = []; - let ident = parse_ident(p); - if eat(p, token::COLON) { - while p.token != token::COMMA && p.token != token::GT { - if eat_word(p, "send") { bounds += [ast::bound_send]; } - else if eat_word(p, "copy") { bounds += [ast::bound_copy]; } - else { bounds += [ast::bound_iface(parse_ty(p, false))]; } - } - } - ret {ident: ident, id: p.get_id(), bounds: @bounds}; -} - -fn parse_ty_params(p: parser) -> [ast::ty_param] { - if eat(p, token::LT) { - parse_seq_to_gt(some(token::COMMA), parse_ty_param, p) - } else { [] } -} - -fn parse_fn_decl(p: parser, purity: ast::purity) - -> ast::fn_decl { - let inputs: ast::spanned<[ast::arg]> = - parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), - parse_arg, p); - // Use the args list to translate each bound variable - // mentioned in a constraint to an arg index. - // Seems weird to do this in the parser, but I'm not sure how else to. - let constrs = []; - if p.token == token::COLON { - p.bump(); - constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p); - } - let (ret_style, ret_ty) = parse_ret_ty(p); - ret {inputs: inputs.node, - output: ret_ty, - purity: purity, - cf: ret_style, - constraints: constrs}; -} - -fn parse_fn_block_decl(p: parser) -> ast::fn_decl { - let inputs = if eat(p, token::OROR) { - [] - } else { - parse_seq(token::BINOP(token::OR), - token::BINOP(token::OR), - seq_sep(token::COMMA), - parse_fn_block_arg, p).node - }; - let output = if eat(p, token::RARROW) { - parse_ty(p, false) - } else { - @spanned(p.span.lo, p.span.hi, ast::ty_infer) - }; - ret {inputs: inputs, - output: output, - purity: ast::impure_fn, - cf: ast::return_val, - constraints: []}; -} - -fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} { - let id = parse_value_ident(p); - let ty_params = parse_ty_params(p); - ret {ident: id, tps: ty_params}; -} - -fn mk_item(p: parser, lo: uint, hi: uint, ident: ast::ident, node: ast::item_, - attrs: [ast::attribute]) -> @ast::item { - ret @{ident: ident, - attrs: attrs, - id: p.get_id(), - node: node, - span: ast_util::mk_sp(lo, hi)}; -} - -fn parse_item_fn(p: parser, purity: ast::purity, - attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - let t = parse_fn_header(p); - let decl = parse_fn_decl(p, purity); - let (inner_attrs, body) = parse_inner_attrs_and_block(p, true); - let attrs = attrs + inner_attrs; - ret mk_item(p, lo, body.span.hi, t.ident, - ast::item_fn(decl, t.tps, body), attrs); -} - -fn parse_method_name(p: parser) -> ast::ident { - alt p.token { - token::BINOP(op) { p.bump(); token::binop_to_str(op) } - token::NOT { p.bump(); "!" } - token::LBRACKET { p.bump(); expect(p, token::RBRACKET); "[]" } - _ { - let id = parse_value_ident(p); - if id == "unary" && eat(p, token::BINOP(token::MINUS)) { "unary-" } - else { id } - } - } -} - -fn parse_method(p: parser) -> @ast::method { - let attrs = parse_outer_attributes(p); - let lo = p.span.lo, pur = parse_fn_purity(p); - let ident = parse_method_name(p); - let tps = parse_ty_params(p); - let decl = parse_fn_decl(p, pur); - let (inner_attrs, body) = parse_inner_attrs_and_block(p, true); - let attrs = attrs + inner_attrs; - @{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body, - id: p.get_id(), span: ast_util::mk_sp(lo, body.span.hi)} -} - -fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo, ident = parse_ident(p), - tps = parse_ty_params(p), meths = parse_ty_methods(p); - ret mk_item(p, lo, p.last_span.hi, ident, - ast::item_iface(tps, meths), attrs); -} - -// Parses three variants (with the initial params always optional): -// impl <T: copy> of to_str for [T] { ... } -// impl name<T> of to_str for [T] { ... } -// impl name<T> for [T] { ... } -fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty { - @{node: ast::ty_path(pt, p.get_id()), span: pt.span} - } - let (ident, tps) = if !is_word(p, "of") { - if p.token == token::LT { (none, parse_ty_params(p)) } - else { (some(parse_ident(p)), parse_ty_params(p)) } - } else { (none, []) }; - let ifce = if eat_word(p, "of") { - let path = parse_path_and_ty_param_substs(p, false); - if option::is_none(ident) { - ident = some(path.node.idents[vec::len(path.node.idents) - 1u]); - } - some(wrap_path(p, path)) - } else { none }; - let ident = alt ident { - some(name) { name } - none { expect_word(p, "of"); fail; } - }; - expect_word(p, "for"); - let ty = parse_ty(p, false), meths = []; - expect(p, token::LBRACE); - while !eat(p, token::RBRACE) { meths += [parse_method(p)]; } - ret mk_item(p, lo, p.last_span.hi, ident, - ast::item_impl(tps, ifce, ty, meths), attrs); -} - -fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - let ident = parse_value_ident(p); - let ty_params = parse_ty_params(p); - expect(p, token::LPAREN); - let arg_ident = parse_value_ident(p); - expect(p, token::COLON); - let t = parse_ty(p, false); - expect(p, token::RPAREN); - let dtor = parse_block_no_value(p); - let decl = - {inputs: - [{mode: ast::expl(ast::by_ref), ty: t, - ident: arg_ident, id: p.get_id()}], - output: @spanned(lo, lo, ast::ty_nil), - purity: ast::impure_fn, - cf: ast::return_val, - constraints: []}; - ret mk_item(p, lo, dtor.span.hi, ident, - ast::item_res(decl, ty_params, dtor, p.get_id(), p.get_id()), - attrs); -} - -fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - let class_name = parse_value_ident(p); - let class_path = ident_to_path(p.last_span, class_name); - let ty_params = parse_ty_params(p); - expect(p, token::LBRACE); - let items: [@ast::class_item] = []; - let ctor_id = p.get_id(); - let the_ctor : option<(ast::fn_decl, ast::blk)> = none; - while p.token != token::RBRACE { - alt parse_class_item(p, class_path) { - ctor_decl(a_fn_decl, blk) { - the_ctor = some((a_fn_decl, blk)); - } - plain_decl(a_decl) { - items += [@{node: {privacy: ast::pub, decl: a_decl}, - span: p.last_span}]; - } - priv_decls(some_decls) { - items += vec::map(some_decls, {|d| - @{node: {privacy: ast::priv, decl: d}, - span: p.last_span}}); - } - } - } - p.bump(); - alt the_ctor { - some((ct_d, ct_b)) { ret mk_item(p, lo, p.last_span.hi, class_name, - ast::item_class(ty_params, items, ctor_id, ct_d, ct_b), attrs); } - /* - Is it strange for the parser to check this? - */ - none { /* parse error */ fail "Class with no ctor"; } - } -} - -// lets us identify the constructor declaration at -// parse time -// we don't really want just the fn_decl... -enum class_contents { ctor_decl(ast::fn_decl, ast::blk), - // assumed to be public - plain_decl(ast::class_member), - // contents of a priv section -- - // parse_class_item ensures that - // none of these are a ctor decl - priv_decls([ast::class_member])} - - fn parse_class_item(p:parser, class_name:@ast::path) -> class_contents { - if eat_word(p, "new") { - // Can ctors have attrs? - // result type is always the type of the class - let decl_ = parse_fn_decl(p, ast::impure_fn); - let decl = {output: @{node: ast::ty_path(class_name, p.get_id()), - span: decl_.output.span} - with decl_}; - let body = parse_block(p); - ret ctor_decl(decl, body); - } - // FIXME: refactor - else if eat_word(p, "priv") { - expect(p, token::LBRACE); - let results = []; - while p.token != token::RBRACE { - alt parse_item(p, []) { - some(i) { - results += [ast::class_method(i)]; - } - _ { - let a_var = parse_instance_var(p); - expect(p, token::SEMI); - results += [a_var]; - } - } - } - p.bump(); - ret priv_decls(results); - } - else { - // Probably need to parse attrs - alt parse_item(p, []) { - some(i) { - ret plain_decl(ast::class_method(i)); - } - _ { - let a_var = parse_instance_var(p); - expect(p, token::SEMI); - ret plain_decl(a_var); - } - } - } -} - -fn parse_mod_items(p: parser, term: token::token, - first_item_attrs: [ast::attribute]) -> ast::_mod { - // Shouldn't be any view items since we've already parsed an item attr - let view_items = maybe_parse_view(p, first_item_attrs); - let items: [@ast::item] = []; - let initial_attrs = first_item_attrs; - while p.token != term { - let attrs = initial_attrs + parse_outer_attributes(p); - #debug["parse_mod_items: parse_item(attrs=%?)", attrs]; - alt parse_item(p, attrs) { - some(i) { items += [i]; } - _ { - p.fatal("expected item but found '" + - token::to_str(p.reader, p.token) + "'"); - } - } - #debug["parse_mod_items: attrs=%?", attrs]; - initial_attrs = []; - } - - if vec::is_not_empty(initial_attrs) { - // We parsed attributes for the first item but didn't find the item - p.fatal("expected item"); - } - - ret {view_items: view_items, items: items}; -} - -fn parse_item_const(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - let id = parse_value_ident(p); - expect(p, token::COLON); - let ty = parse_ty(p, false); - expect(p, token::EQ); - let e = parse_expr(p); - let hi = p.span.hi; - expect(p, token::SEMI); - ret mk_item(p, lo, hi, id, ast::item_const(ty, e), attrs); -} - -fn parse_item_mod(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - let id = parse_ident(p); - expect(p, token::LBRACE); - let inner_attrs = parse_inner_attrs_and_next(p); - let first_item_outer_attrs = inner_attrs.next; - let m = parse_mod_items(p, token::RBRACE, first_item_outer_attrs); - let hi = p.span.hi; - expect(p, token::RBRACE); - ret mk_item(p, lo, hi, id, ast::item_mod(m), attrs + inner_attrs.inner); -} - -fn parse_item_native_fn(p: parser, attrs: [ast::attribute], - purity: ast::purity) -> @ast::native_item { - let lo = p.last_span.lo; - let t = parse_fn_header(p); - let decl = parse_fn_decl(p, purity); - let hi = p.span.hi; - expect(p, token::SEMI); - ret @{ident: t.ident, - attrs: attrs, - node: ast::native_item_fn(decl, t.tps), - id: p.get_id(), - span: ast_util::mk_sp(lo, hi)}; -} - -fn parse_fn_purity(p: parser) -> ast::purity { - if eat_word(p, "fn") { ast::impure_fn } - else if eat_word(p, "pure") { expect_word(p, "fn"); ast::pure_fn } - else if eat_word(p, "unsafe") { expect_word(p, "fn"); ast::unsafe_fn } - else { unexpected(p, p.token); } -} - -fn parse_native_item(p: parser, attrs: [ast::attribute]) -> - @ast::native_item { - parse_item_native_fn(p, attrs, parse_fn_purity(p)) -} - -fn parse_native_mod_items(p: parser, first_item_attrs: [ast::attribute]) -> - ast::native_mod { - // Shouldn't be any view items since we've already parsed an item attr - let view_items = - if vec::len(first_item_attrs) == 0u { - parse_native_view(p) - } else { [] }; - let items: [@ast::native_item] = []; - let initial_attrs = first_item_attrs; - while p.token != token::RBRACE { - let attrs = initial_attrs + parse_outer_attributes(p); - initial_attrs = []; - items += [parse_native_item(p, attrs)]; - } - ret {view_items: view_items, - items: items}; -} - -fn parse_item_native_mod(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - expect_word(p, "mod"); - let id = parse_ident(p); - expect(p, token::LBRACE); - let more_attrs = parse_inner_attrs_and_next(p); - let inner_attrs = more_attrs.inner; - let first_item_outer_attrs = more_attrs.next; - let m = parse_native_mod_items(p, first_item_outer_attrs); - let hi = p.span.hi; - expect(p, token::RBRACE); - ret mk_item(p, lo, hi, id, ast::item_native_mod(m), attrs + inner_attrs); -} - -fn parse_type_decl(p: parser) -> {lo: uint, ident: ast::ident} { - let lo = p.last_span.lo; - let id = parse_ident(p); - ret {lo: lo, ident: id}; -} - -fn parse_item_type(p: parser, attrs: [ast::attribute]) -> @ast::item { - let t = parse_type_decl(p); - let tps = parse_ty_params(p); - expect(p, token::EQ); - let ty = parse_ty(p, false); - let hi = p.span.hi; - expect(p, token::SEMI); - ret mk_item(p, t.lo, hi, t.ident, ast::item_ty(ty, tps), attrs); -} - -fn parse_item_enum(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo; - let id = parse_ident(p); - let ty_params = parse_ty_params(p); - let variants: [ast::variant] = []; - // Newtype syntax - if p.token == token::EQ { - if p.bad_expr_words.contains_key(id) { - p.fatal("found " + id + " in enum constructor position"); - } - p.bump(); - let ty = parse_ty(p, false); - expect(p, token::SEMI); - let variant = - spanned(ty.span.lo, ty.span.hi, - {name: id, - attrs: [], - args: [{ty: ty, id: p.get_id()}], - id: p.get_id(), - disr_expr: none}); - ret mk_item(p, lo, ty.span.hi, id, - ast::item_enum([variant], ty_params), attrs); - } - expect(p, token::LBRACE); - - let all_nullary = true, have_disr = false; - - while p.token != token::RBRACE { - let variant_attrs = parse_outer_attributes(p); - let vlo = p.span.lo; - let ident = parse_value_ident(p); - let args = [], disr_expr = none; - if p.token == token::LPAREN { - all_nullary = false; - let arg_tys = parse_seq(token::LPAREN, token::RPAREN, - seq_sep(token::COMMA), - {|p| parse_ty(p, false)}, p); - for ty in arg_tys.node { - args += [{ty: ty, id: p.get_id()}]; - } - } else if eat(p, token::EQ) { - have_disr = true; - disr_expr = some(parse_expr(p)); - } - - let vr = {name: ident, attrs: variant_attrs, - args: args, id: p.get_id(), - disr_expr: disr_expr}; - variants += [spanned(vlo, p.last_span.hi, vr)]; - - if !eat(p, token::COMMA) { break; } - } - expect(p, token::RBRACE); - if (have_disr && !all_nullary) { - p.fatal("discriminator values can only be used with a c-like enum"); - } - ret mk_item(p, lo, p.last_span.hi, id, - ast::item_enum(variants, ty_params), attrs); -} - -fn parse_fn_ty_proto(p: parser) -> ast::proto { - alt p.token { - token::AT { - p.bump(); - ast::proto_box - } - token::TILDE { - p.bump(); - ast::proto_uniq - } - token::BINOP(token::AND) { - p.bump(); - ast::proto_block - } - _ { - ast::proto_any - } - } -} - -fn fn_expr_lookahead(tok: token::token) -> bool { - alt tok { - token::LPAREN | token::AT | token::TILDE | token::BINOP(_) { - true - } - _ { - false - } - } -} - -fn parse_item(p: parser, attrs: [ast::attribute]) -> option<@ast::item> { - if eat_word(p, "const") { - ret some(parse_item_const(p, attrs)); - } else if is_word(p, "fn") && !fn_expr_lookahead(p.look_ahead(1u)) { - p.bump(); - ret some(parse_item_fn(p, ast::impure_fn, attrs)); - } else if eat_word(p, "pure") { - expect_word(p, "fn"); - ret some(parse_item_fn(p, ast::pure_fn, attrs)); - } else if is_word(p, "unsafe") && p.look_ahead(1u) != token::LBRACE { - p.bump(); - expect_word(p, "fn"); - ret some(parse_item_fn(p, ast::unsafe_fn, attrs)); - } else if eat_word(p, "crust") { - expect_word(p, "fn"); - ret some(parse_item_fn(p, ast::crust_fn, attrs)); - } else if eat_word(p, "mod") { - ret some(parse_item_mod(p, attrs)); - } else if eat_word(p, "native") { - ret some(parse_item_native_mod(p, attrs)); - } if eat_word(p, "type") { - ret some(parse_item_type(p, attrs)); - } else if eat_word(p, "enum") { - ret some(parse_item_enum(p, attrs)); - } else if eat_word(p, "iface") { - ret some(parse_item_iface(p, attrs)); - } else if eat_word(p, "impl") { - ret some(parse_item_impl(p, attrs)); - } else if eat_word(p, "resource") { - ret some(parse_item_res(p, attrs)); - } else if eat_word(p, "class") { - ret some(parse_item_class(p, attrs)); - } -else { ret none; } -} - -// A type to distingush between the parsing of item attributes or syntax -// extensions, which both begin with token.POUND -type attr_or_ext = option<either::t<[ast::attribute], @ast::expr>>; - -fn parse_outer_attrs_or_ext( - p: parser, - first_item_attrs: [ast::attribute]) -> attr_or_ext { - let expect_item_next = vec::is_not_empty(first_item_attrs); - if p.token == token::POUND { - let lo = p.span.lo; - if p.look_ahead(1u) == token::LBRACKET { - p.bump(); - let first_attr = parse_attribute_naked(p, ast::attr_outer, lo); - ret some(left([first_attr] + parse_outer_attributes(p))); - } else if !(p.look_ahead(1u) == token::LT - || p.look_ahead(1u) == token::LBRACKET - || expect_item_next) { - p.bump(); - ret some(right(parse_syntax_ext_naked(p, lo))); - } else { ret none; } - } else { ret none; } -} - -// Parse attributes that appear before an item -fn parse_outer_attributes(p: parser) -> [ast::attribute] { - let attrs: [ast::attribute] = []; - while p.token == token::POUND { - attrs += [parse_attribute(p, ast::attr_outer)]; - } - ret attrs; -} - -fn parse_attribute(p: parser, style: ast::attr_style) -> ast::attribute { - let lo = p.span.lo; - expect(p, token::POUND); - ret parse_attribute_naked(p, style, lo); -} - -fn parse_attribute_naked(p: parser, style: ast::attr_style, lo: uint) -> - ast::attribute { - expect(p, token::LBRACKET); - let meta_item = parse_meta_item(p); - expect(p, token::RBRACKET); - let hi = p.span.hi; - ret spanned(lo, hi, {style: style, value: *meta_item}); -} - -// Parse attributes that appear after the opening of an item, each terminated -// by a semicolon. In addition to a vector of inner attributes, this function -// also returns a vector that may contain the first outer attribute of the -// next item (since we can't know whether the attribute is an inner attribute -// of the containing item or an outer attribute of the first contained item -// until we see the semi). -fn parse_inner_attrs_and_next(p: parser) -> - {inner: [ast::attribute], next: [ast::attribute]} { - let inner_attrs: [ast::attribute] = []; - let next_outer_attrs: [ast::attribute] = []; - while p.token == token::POUND { - if p.look_ahead(1u) != token::LBRACKET { - // This is an extension - break; - } - let attr = parse_attribute(p, ast::attr_inner); - if p.token == token::SEMI { - p.bump(); - inner_attrs += [attr]; - } else { - // It's not really an inner attribute - let outer_attr = - spanned(attr.span.lo, attr.span.hi, - {style: ast::attr_outer, value: attr.node.value}); - next_outer_attrs += [outer_attr]; - break; - } - } - ret {inner: inner_attrs, next: next_outer_attrs}; -} - -fn parse_meta_item(p: parser) -> @ast::meta_item { - let lo = p.span.lo; - let ident = parse_ident(p); - alt p.token { - token::EQ { - p.bump(); - let lit = parse_lit(p); - let hi = p.span.hi; - ret @spanned(lo, hi, ast::meta_name_value(ident, lit)); - } - token::LPAREN { - let inner_items = parse_meta_seq(p); - let hi = p.span.hi; - ret @spanned(lo, hi, ast::meta_list(ident, inner_items)); - } - _ { - let hi = p.span.hi; - ret @spanned(lo, hi, ast::meta_word(ident)); - } - } -} - -fn parse_meta_seq(p: parser) -> [@ast::meta_item] { - ret parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), - parse_meta_item, p).node; -} - -fn parse_optional_meta(p: parser) -> [@ast::meta_item] { - alt p.token { token::LPAREN { ret parse_meta_seq(p); } _ { ret []; } } -} - -fn parse_use(p: parser) -> ast::view_item_ { - let ident = parse_ident(p); - let metadata = parse_optional_meta(p); - ret ast::view_item_use(ident, metadata, p.get_id()); -} - -fn parse_view_path(p: parser) -> @ast::view_path { - let lo = p.span.lo; - let first_ident = parse_ident(p); - let path = [first_ident]; - #debug("parsed view_path: %s", first_ident); - alt p.token { - token::EQ { - // x = foo::bar - p.bump(); - path = [parse_ident(p)]; - while p.token == token::MOD_SEP { - p.bump(); - let id = parse_ident(p); - path += [id]; - } - let hi = p.span.hi; - ret @spanned(lo, hi, - ast::view_path_simple(first_ident, - @path, p.get_id())); - } - - token::MOD_SEP { - // foo::bar or foo::{a,b,c} or foo::* - while p.token == token::MOD_SEP { - p.bump(); - - alt p.token { - - token::IDENT(i, _) { - p.bump(); - path += [p.get_str(i)]; - } - - // foo::bar::{a,b,c} - token::LBRACE { - let idents = - parse_seq(token::LBRACE, token::RBRACE, - seq_sep(token::COMMA), - parse_path_list_ident, p).node; - let hi = p.span.hi; - ret @spanned(lo, hi, - ast::view_path_list(@path, idents, - p.get_id())); - } - - // foo::bar::* - token::BINOP(token::STAR) { - p.bump(); - let hi = p.span.hi; - ret @spanned(lo, hi, - ast::view_path_glob(@path, - p.get_id())); - } - - _ { break; } - } - } - } - _ { } - } - let hi = p.span.hi; - let last = path[vec::len(path) - 1u]; - ret @spanned(lo, hi, - ast::view_path_simple(last, @path, - p.get_id())); -} - -fn parse_view_paths(p: parser) -> [@ast::view_path] { - let vp = [parse_view_path(p)]; - while p.token == token::COMMA { - p.bump(); - vp += [parse_view_path(p)]; - } - ret vp; -} - -fn parse_view_item(p: parser) -> @ast::view_item { - let lo = p.span.lo; - let the_item = - if eat_word(p, "use") { - parse_use(p) - } else if eat_word(p, "import") { - ast::view_item_import(parse_view_paths(p)) - } else if eat_word(p, "export") { - ast::view_item_export(parse_view_paths(p)) - } else { - fail - }; - let hi = p.span.lo; - expect(p, token::SEMI); - ret @spanned(lo, hi, the_item); -} - -fn is_view_item(p: parser) -> bool { - alt p.token { - token::IDENT(sid, false) { - let st = p.get_str(sid); - ret str::eq(st, "use") || str::eq(st, "import") || - str::eq(st, "export"); - } - _ { ret false; } - } -} - -fn maybe_parse_view( - p: parser, - first_item_attrs: [ast::attribute]) -> [@ast::view_item] { - - maybe_parse_view_while(p, first_item_attrs, is_view_item) -} - -fn maybe_parse_view_import_only( - p: parser, - first_item_attrs: [ast::attribute]) -> [@ast::view_item] { - - maybe_parse_view_while(p, first_item_attrs, bind is_word(_, "import")) -} - -fn maybe_parse_view_while( - p: parser, - first_item_attrs: [ast::attribute], - f: fn@(parser) -> bool) -> [@ast::view_item] { - - if vec::len(first_item_attrs) == 0u { - let items = []; - while f(p) { items += [parse_view_item(p)]; } - ret items; - } else { - // Shouldn't be any view items since we've already parsed an item attr - ret []; - } -} - -fn parse_native_view(p: parser) -> [@ast::view_item] { - maybe_parse_view_while(p, [], is_view_item) -} - -fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg, - sess: parse_sess) -> @ast::crate { - let p = new_parser_from_file(sess, cfg, input, SOURCE_FILE); - let r = parse_crate_mod(p, cfg); - sess.chpos = p.reader.chpos; - sess.byte_pos = sess.byte_pos + p.reader.pos; - ret r; -} - - -fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg, - sess: parse_sess) -> @ast::expr { - let p = new_parser_from_source_str(sess, cfg, name, fss_none, source); - let r = parse_expr(p); - sess.chpos = p.reader.chpos; - sess.byte_pos = sess.byte_pos + p.reader.pos; - ret r; -} - -fn parse_from_source_str<T>(f: fn (p: parser) -> T, - name: str, ss: codemap::file_substr, - source: @str, cfg: ast::crate_cfg, - sess: parse_sess) - -> T -{ - let p = new_parser_from_source_str(sess, cfg, name, ss, source); - let r = f(p); - if !p.reader.is_eof() { - p.reader.fatal("expected end-of-string"); - } - sess.chpos = p.reader.chpos; - sess.byte_pos = sess.byte_pos + p.reader.pos; - ret r; -} - -fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg, - sess: parse_sess) -> @ast::crate { - let p = new_parser_from_source_str(sess, cfg, name, fss_none, source); - let r = parse_crate_mod(p, cfg); - sess.chpos = p.reader.chpos; - sess.byte_pos = sess.byte_pos + p.reader.pos; - ret r; -} - -// Parses a source module as a crate -fn parse_crate_mod(p: parser, _cfg: ast::crate_cfg) -> @ast::crate { - let lo = p.span.lo; - let crate_attrs = parse_inner_attrs_and_next(p); - let first_item_outer_attrs = crate_attrs.next; - let m = parse_mod_items(p, token::EOF, first_item_outer_attrs); - ret @spanned(lo, p.span.lo, - {directives: [], - module: m, - attrs: crate_attrs.inner, - config: p.cfg}); -} - -fn parse_str(p: parser) -> str { - alt p.token { - token::LIT_STR(s) { p.bump(); p.get_str(s) } - _ { - p.fatal("expected string literal") - } - } -} - -// Logic for parsing crate files (.rc) -// -// Each crate file is a sequence of directives. -// -// Each directive imperatively extends its environment with 0 or more items. -fn parse_crate_directive(p: parser, first_outer_attr: [ast::attribute]) -> - ast::crate_directive { - - // Collect the next attributes - let outer_attrs = first_outer_attr + parse_outer_attributes(p); - // In a crate file outer attributes are only going to apply to mods - let expect_mod = vec::len(outer_attrs) > 0u; - - let lo = p.span.lo; - if expect_mod || is_word(p, "mod") { - expect_word(p, "mod"); - let id = parse_ident(p); - alt p.token { - // mod x = "foo.rs"; - token::SEMI { - let hi = p.span.hi; - p.bump(); - ret spanned(lo, hi, ast::cdir_src_mod(id, outer_attrs)); - } - // mod x = "foo_dir" { ...directives... } - token::LBRACE { - p.bump(); - let inner_attrs = parse_inner_attrs_and_next(p); - let mod_attrs = outer_attrs + inner_attrs.inner; - let next_outer_attr = inner_attrs.next; - let cdirs = - parse_crate_directives(p, token::RBRACE, next_outer_attr); - let hi = p.span.hi; - expect(p, token::RBRACE); - ret spanned(lo, hi, - ast::cdir_dir_mod(id, cdirs, mod_attrs)); - } - t { unexpected(p, t); } - } - } else if is_view_item(p) { - let vi = parse_view_item(p); - ret spanned(lo, vi.span.hi, ast::cdir_view_item(vi)); - } else { ret p.fatal("expected crate directive"); } -} - -fn parse_crate_directives(p: parser, term: token::token, - first_outer_attr: [ast::attribute]) -> - [@ast::crate_directive] { - - // This is pretty ugly. If we have an outer attribute then we can't accept - // seeing the terminator next, so if we do see it then fail the same way - // parse_crate_directive would - if vec::len(first_outer_attr) > 0u && p.token == term { - expect_word(p, "mod"); - } - - let cdirs: [@ast::crate_directive] = []; - let first_outer_attr = first_outer_attr; - while p.token != term { - let cdir = @parse_crate_directive(p, first_outer_attr); - cdirs += [cdir]; - first_outer_attr = []; - } - ret cdirs; -} - -fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg, - sess: parse_sess) -> @ast::crate { - let p = new_parser_from_file(sess, cfg, input, CRATE_FILE); - let lo = p.span.lo; - let prefix = std::fs::dirname(p.reader.filemap.name); - let leading_attrs = parse_inner_attrs_and_next(p); - let crate_attrs = leading_attrs.inner; - let first_cdir_attr = leading_attrs.next; - let cdirs = parse_crate_directives(p, token::EOF, first_cdir_attr); - sess.chpos = p.reader.chpos; - sess.byte_pos = sess.byte_pos + p.reader.pos; - let cx = - @{p: p, - sess: sess, - cfg: p.cfg}; - let (companionmod, _) = fs::splitext(fs::basename(input)); - let (m, attrs) = eval::eval_crate_directives_to_mod( - cx, cdirs, prefix, option::some(companionmod)); - let hi = p.span.hi; - expect(p, token::EOF); - ret @spanned(lo, hi, - {directives: cdirs, - module: m, - attrs: crate_attrs + attrs, - config: p.cfg}); -} - -fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) -> - @ast::crate { - if str::ends_with(input, ".rc") { - parse_crate_from_crate_file(input, cfg, sess) - } else if str::ends_with(input, ".rs") { - parse_crate_from_source_file(input, cfg, sess) - } else { - sess.span_diagnostic.handler().fatal("unknown input file type: " + - input) - } -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/parse/token.rs b/src/comp/syntax/parse/token.rs deleted file mode 100644 index 60949f7793c..00000000000 --- a/src/comp/syntax/parse/token.rs +++ /dev/null @@ -1,199 +0,0 @@ - -import util::interner; -import lexer::reader; - -type str_num = uint; - -enum binop { - PLUS, - MINUS, - STAR, - SLASH, - PERCENT, - CARET, - AND, - OR, - LSL, - LSR, - ASR, -} - -enum token { - /* Expression-operator symbols. */ - EQ, - LT, - LE, - EQEQ, - NE, - GE, - GT, - ANDAND, - OROR, - NOT, - TILDE, - BINOP(binop), - BINOPEQ(binop), - - /* Structural symbols */ - AT, - DOT, - ELLIPSIS, - COMMA, - SEMI, - COLON, - MOD_SEP, - RARROW, - LARROW, - DARROW, - LPAREN, - RPAREN, - LBRACKET, - RBRACKET, - LBRACE, - RBRACE, - POUND, - POUND_LBRACE, - POUND_LT, - - DOLLAR_LPAREN, - DOLLAR_NUM(uint), - - /* Literals */ - LIT_INT(i64, ast::int_ty), - LIT_UINT(u64, ast::uint_ty), - LIT_FLOAT(str_num, ast::float_ty), - LIT_STR(str_num), - LIT_BOOL(bool), - - /* Name components */ - IDENT(str_num, bool), - IDX(int), - UNDERSCORE, - BRACEQUOTE(str_num), - EOF, - -} - -fn binop_to_str(o: binop) -> str { - alt o { - PLUS { ret "+"; } - MINUS { ret "-"; } - STAR { ret "*"; } - SLASH { ret "/"; } - PERCENT { ret "%"; } - CARET { ret "^"; } - AND { ret "&"; } - OR { ret "|"; } - LSL { ret "<<"; } - LSR { ret ">>"; } - ASR { ret ">>>"; } - } -} - -fn to_str(r: reader, t: token) -> str { - alt t { - EQ { ret "="; } - LT { ret "<"; } - LE { ret "<="; } - EQEQ { ret "=="; } - NE { ret "!="; } - GE { ret ">="; } - GT { ret ">"; } - NOT { ret "!"; } - TILDE { ret "~"; } - OROR { ret "||"; } - ANDAND { ret "&&"; } - BINOP(op) { ret binop_to_str(op); } - BINOPEQ(op) { ret binop_to_str(op) + "="; } - - /* Structural symbols */ - AT { - ret "@"; - } - DOT { ret "."; } - ELLIPSIS { ret "..."; } - COMMA { ret ","; } - SEMI { ret ";"; } - COLON { ret ":"; } - MOD_SEP { ret "::"; } - RARROW { ret "->"; } - LARROW { ret "<-"; } - DARROW { ret "<->"; } - LPAREN { ret "("; } - RPAREN { ret ")"; } - LBRACKET { ret "["; } - RBRACKET { ret "]"; } - LBRACE { ret "{"; } - RBRACE { ret "}"; } - POUND { ret "#"; } - POUND_LBRACE { ret "#{"; } - POUND_LT { ret "#<"; } - - DOLLAR_LPAREN { ret "$("; } - DOLLAR_NUM(u) { - ret "$" + uint::to_str(u as uint, 10u); - } - - /* Literals */ - LIT_INT(c, ast::ty_char) { - // FIXME: escape. - let tmp = "'"; - str::push_char(tmp, c as char); - str::push_char(tmp, '\''); - ret tmp; - } - LIT_INT(i, t) { - ret int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t); - } - LIT_UINT(u, t) { - ret uint::to_str(u as uint, 10u) + ast_util::uint_ty_to_str(t); - } - LIT_FLOAT(s, t) { - ret interner::get::<str>(*r.interner, s) + - ast_util::float_ty_to_str(t); - } - LIT_STR(s) { // FIXME: escape. - ret "\"" + interner::get::<str>(*r.interner, s) + "\""; - } - LIT_BOOL(b) { if b { ret "true"; } else { ret "false"; } } - - /* Name components */ - IDENT(s, _) { - ret interner::get::<str>(*r.interner, s); - } - IDX(i) { ret "_" + int::to_str(i, 10u); } - UNDERSCORE { ret "_"; } - BRACEQUOTE(_) { ret "<bracequote>"; } - EOF { ret "<eof>"; } - } -} - - -pure fn can_begin_expr(t: token) -> bool { - alt t { - LPAREN { true } - LBRACE { true } - LBRACKET { true } - IDENT(_, _) { true } - UNDERSCORE { true } - TILDE { true } - LIT_INT(_, _) { true } - LIT_UINT(_, _) { true } - LIT_FLOAT(_, _) { true } - LIT_STR(_) { true } - POUND { true } - AT { true } - NOT { true } - BINOP(MINUS) { true } - BINOP(STAR) { true } - MOD_SEP { true } - _ { false } - } -} - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/syntax/print/pp.rs b/src/comp/syntax/print/pp.rs deleted file mode 100644 index 0b55bb8c356..00000000000 --- a/src/comp/syntax/print/pp.rs +++ /dev/null @@ -1,526 +0,0 @@ - -import std::io; -import io::writer_util; - -/* - * This pretty-printer is a direct reimplementation of Philip Karlton's - * Mesa pretty-printer, as described in appendix A of - * - * STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen. - * Stanford Department of Computer Science, 1979. - * - * The algorithm's aim is to break a stream into as few lines as possible - * while respecting the indentation-consistency requirements of the enclosing - * block, and avoiding breaking at silly places on block boundaries, for - * example, between "x" and ")" in "x)". - * - * I am implementing this algorithm because it comes with 20 pages of - * documentation explaining its theory, and because it addresses the set of - * concerns I've seen other pretty-printers fall down on. Weirdly. Even though - * it's 32 years old and not written in Haskell. What can I say? - * - * Despite some redundancies and quirks in the way it's implemented in that - * paper, I've opted to keep the implementation here as similar as I can, - * changing only what was blatantly wrong, a typo, or sufficiently - * non-idiomatic rust that it really stuck out. - * - * In particular you'll see a certain amount of churn related to INTEGER vs. - * CARDINAL in the Mesa implementation. Mesa apparently interconverts the two - * somewhat readily? In any case, I've used uint for indices-in-buffers and - * ints for character-sizes-and-indentation-offsets. This respects the need - * for ints to "go negative" while carrying a pending-calculation balance, and - * helps differentiate all the numbers flying around internally (slightly). - * - * I also inverted the indentation arithmetic used in the print stack, since - * the Mesa implementation (somewhat randomly) stores the offset on the print - * stack in terms of margin-col rather than col itself. I store col. - * - * I also implemented a small change in the STRING token, in that I store an - * explicit length for the string. For most tokens this is just the length of - * the accompanying string. But it's necessary to permit it to differ, for - * encoding things that are supposed to "go on their own line" -- certain - * classes of comment and blank-line -- where relying on adjacent - * hardbreak-like BREAK tokens with long blankness indication doesn't actually - * work. To see why, consider when there is a "thing that should be on its own - * line" between two long blocks, say functions. If you put a hardbreak after - * each function (or before each) and the breaking algorithm decides to break - * there anyways (because the functions themselves are long) you wind up with - * extra blank lines. If you don't put hardbreaks you can wind up with the - * "thing which should be on its own line" not getting its own line in the - * rare case of "really small functions" or such. This re-occurs with comments - * and explicit blank lines. So in those cases we use a string with a payload - * we want isolated to a line and an explicit length that's huge, surrounded - * by two zero-length breaks. The algorithm will try its best to fit it on a - * line (which it can't) and so naturally place the content on its own line to - * avoid combining it with other lines and making matters even worse. - */ -enum breaks { consistent, inconsistent, } - -type break_t = {offset: int, blank_space: int}; - -type begin_t = {offset: int, breaks: breaks}; - -enum token { STRING(str, int), BREAK(break_t), BEGIN(begin_t), END, EOF, } - -fn tok_str(t: token) -> str { - alt t { - STRING(s, len) { ret #fmt["STR(%s,%d)", s, len]; } - BREAK(_) { ret "BREAK"; } - BEGIN(_) { ret "BEGIN"; } - END { ret "END"; } - EOF { ret "EOF"; } - } -} - -fn buf_str(toks: [mutable token], szs: [mutable int], left: uint, right: uint, - lim: uint) -> str { - let n = vec::len(toks); - assert (n == vec::len(szs)); - let i = left; - let L = lim; - let s = "["; - while i != right && L != 0u { - L -= 1u; - if i != left { s += ", "; } - s += #fmt["%d=%s", szs[i], tok_str(toks[i])]; - i += 1u; - i %= n; - } - s += "]"; - ret s; -} - -enum print_stack_break { fits, broken(breaks), } - -type print_stack_elt = {offset: int, pbreak: print_stack_break}; - -const size_infinity: int = 0xffff; - -fn mk_printer(out: io::writer, linewidth: uint) -> printer { - // Yes 3, it makes the ring buffers big enough to never - // fall behind. - let n: uint = 3u * linewidth; - #debug("mk_printer %u", linewidth); - let token: [mutable token] = vec::to_mut(vec::init_elt(n, EOF)); - let size: [mutable int] = vec::to_mut(vec::init_elt(n, 0)); - let scan_stack: [mutable uint] = vec::to_mut(vec::init_elt(n, 0u)); - let print_stack: [print_stack_elt] = []; - @{out: out, - buf_len: n, - mutable margin: linewidth as int, - mutable space: linewidth as int, - mutable left: 0u, - mutable right: 0u, - mutable token: token, - mutable size: size, - mutable left_total: 0, - mutable right_total: 0, - mutable scan_stack: scan_stack, - mutable scan_stack_empty: true, - mutable top: 0u, - mutable bottom: 0u, - mutable print_stack: print_stack, - mutable pending_indentation: 0} -} - - -/* - * In case you do not have the paper, here is an explanation of what's going - * on. - * - * There is a stream of input tokens flowing through this printer. - * - * The printer buffers up to 3N tokens inside itself, where N is linewidth. - * Yes, linewidth is chars and tokens are multi-char, but in the worst - * case every token worth buffering is 1 char long, so it's ok. - * - * Tokens are STRING, BREAK, and BEGIN/END to delimit blocks. - * - * BEGIN tokens can carry an offset, saying "how far to indent when you break - * inside here", as well as a flag indicating "consistent" or "inconsistent" - * breaking. Consistent breaking means that after the first break, no attempt - * will be made to flow subsequent breaks together onto lines. Inconsistent - * is the opposite. Inconsistent breaking example would be, say: - * - * foo(hello, there, good, friends) - * - * breaking inconsistently to become - * - * foo(hello, there - * good, friends); - * - * whereas a consistent breaking would yield: - * - * foo(hello, - * there - * good, - * friends); - * - * That is, in the consistent-break blocks we value vertical alignment - * more than the ability to cram stuff onto a line. But in all cases if it - * can make a block a one-liner, it'll do so. - * - * Carrying on with high-level logic: - * - * The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and - * 'right' indices denote the active portion of the ring buffer as well as - * describing hypothetical points-in-the-infinite-stream at most 3N tokens - * apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch - * between using 'left' and 'right' terms to denote the wrapepd-to-ring-buffer - * and point-in-infinite-stream senses freely. - * - * There is a parallel ring buffer, 'size', that holds the calculated size of - * each token. Why calculated? Because for BEGIN/END pairs, the "size" - * includes everything betwen the pair. That is, the "size" of BEGIN is - * actually the sum of the sizes of everything between BEGIN and the paired - * END that follows. Since that is arbitrarily far in the future, 'size' is - * being rewritten regularly while the printer runs; in fact most of the - * machinery is here to work out 'size' entries on the fly (and give up when - * they're so obviously over-long that "infinity" is a good enough - * approximation for purposes of line breaking). - * - * The "input side" of the printer is managed as an abstract process called - * SCAN, which uses 'scan_stack', 'scan_stack_empty', 'top' and 'bottom', to - * manage calculating 'size'. SCAN is, in other words, the process of - * calculating 'size' entries. - * - * The "output side" of the printer is managed by an abstract process called - * PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to - * do with each token/size pair it consumes as it goes. It's trying to consume - * the entire buffered window, but can't output anything until the size is >= - * 0 (sizes are set to negative while they're pending calculation). - * - * So SCAN takeks input and buffers tokens and pending calculations, while - * PRINT gobbles up completed calculations and tokens from the buffer. The - * theory is that the two can never get more than 3N tokens apart, because - * once there's "obviously" too much data to fit on a line, in a size - * calculation, SCAN will write "infinity" to the size and let PRINT consume - * it. - * - * In this implementation (following the paper, again) the SCAN process is - * the method called 'pretty_print', and the 'PRINT' process is the method - * called 'print'. - */ -type printer = @{ - out: io::writer, - buf_len: uint, - mutable margin: int, // width of lines we're constrained to - mutable space: int, // number of spaces left on line - mutable left: uint, // index of left side of input stream - mutable right: uint, // index of right side of input stream - mutable token: [mutable token], // ring-buffr stream goes through - mutable size: [mutable int], // ring-buffer of calculated sizes - mutable left_total: int, // running size of stream "...left" - mutable right_total: int, // running size of stream "...right" - // pseudo-stack, really a ring too. Holds the - // primary-ring-buffers index of the BEGIN that started the - // current block, possibly with the most recent BREAK after that - // BEGIN (if there is any) on top of it. Stuff is flushed off the - // bottom as it becomes irrelevant due to the primary ring-buffer - // advancing. - mutable scan_stack: [mutable uint], - mutable scan_stack_empty: bool, // top==bottom disambiguator - mutable top: uint, // index of top of scan_stack - mutable bottom: uint, // index of bottom of scan_stack - // stack of blocks-in-progress being flushed by print - mutable print_stack: [print_stack_elt], - // buffered indentation to avoid writing trailing whitespace - mutable pending_indentation: int -}; - -impl printer for printer { - fn last_token() -> token { self.token[self.right] } - // be very careful with this! - fn replace_last_token(t: token) { self.token[self.right] = t; } - fn pretty_print(t: token) { - #debug("pp [%u,%u]", self.left, self.right); - alt t { - EOF { - if !self.scan_stack_empty { - self.check_stack(0); - self.advance_left(self.token[self.left], - self.size[self.left]); - } - self.indent(0); - } - BEGIN(b) { - if self.scan_stack_empty { - self.left_total = 1; - self.right_total = 1; - self.left = 0u; - self.right = 0u; - } else { self.advance_right(); } - #debug("pp BEGIN/buffer [%u,%u]", self.left, self.right); - self.token[self.right] = t; - self.size[self.right] = -self.right_total; - self.scan_push(self.right); - } - END { - if self.scan_stack_empty { - #debug("pp END/print [%u,%u]", self.left, self.right); - self.print(t, 0); - } else { - #debug("pp END/buffer [%u,%u]", self.left, self.right); - self.advance_right(); - self.token[self.right] = t; - self.size[self.right] = -1; - self.scan_push(self.right); - } - } - BREAK(b) { - if self.scan_stack_empty { - self.left_total = 1; - self.right_total = 1; - self.left = 0u; - self.right = 0u; - } else { self.advance_right(); } - #debug("pp BREAK/buffer [%u,%u]", self.left, self.right); - self.check_stack(0); - self.scan_push(self.right); - self.token[self.right] = t; - self.size[self.right] = -self.right_total; - self.right_total += b.blank_space; - } - STRING(s, len) { - if self.scan_stack_empty { - #debug("pp STRING/print [%u,%u]", self.left, self.right); - self.print(t, len); - } else { - #debug("pp STRING/buffer [%u,%u]", self.left, self.right); - self.advance_right(); - self.token[self.right] = t; - self.size[self.right] = len; - self.right_total += len; - self.check_stream(); - } - } - } - } - fn check_stream() { - #debug("check_stream [%u, %u] with left_total=%d, right_total=%d", - self.left, self.right, self.left_total, self.right_total); - if self.right_total - self.left_total > self.space { - #debug("scan window is %d, longer than space on line (%d)", - self.right_total - self.left_total, self.space); - if !self.scan_stack_empty { - if self.left == self.scan_stack[self.bottom] { - #debug("setting %u to infinity and popping", self.left); - self.size[self.scan_pop_bottom()] = size_infinity; - } - } - self.advance_left(self.token[self.left], self.size[self.left]); - if self.left != self.right { self.check_stream(); } - } - } - fn scan_push(x: uint) { - #debug("scan_push %u", x); - if self.scan_stack_empty { - self.scan_stack_empty = false; - } else { - self.top += 1u; - self.top %= self.buf_len; - assert (self.top != self.bottom); - } - self.scan_stack[self.top] = x; - } - fn scan_pop() -> uint { - assert (!self.scan_stack_empty); - let x = self.scan_stack[self.top]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { self.top += self.buf_len - 1u; self.top %= self.buf_len; } - ret x; - } - fn scan_top() -> uint { - assert (!self.scan_stack_empty); - ret self.scan_stack[self.top]; - } - fn scan_pop_bottom() -> uint { - assert (!self.scan_stack_empty); - let x = self.scan_stack[self.bottom]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { self.bottom += 1u; self.bottom %= self.buf_len; } - ret x; - } - fn advance_right() { - self.right += 1u; - self.right %= self.buf_len; - assert (self.right != self.left); - } - fn advance_left(x: token, L: int) { - #debug("advnce_left [%u,%u], sizeof(%u)=%d", self.left, self.right, - self.left, L); - if L >= 0 { - self.print(x, L); - alt x { - BREAK(b) { self.left_total += b.blank_space; } - STRING(_, len) { assert (len == L); self.left_total += len; } - _ { } - } - if self.left != self.right { - self.left += 1u; - self.left %= self.buf_len; - self.advance_left(self.token[self.left], - self.size[self.left]); - } - } - } - fn check_stack(k: int) { - if !self.scan_stack_empty { - let x = self.scan_top(); - alt self.token[x] { - BEGIN(b) { - if k > 0 { - self.size[self.scan_pop()] = self.size[x] + - self.right_total; - self.check_stack(k - 1); - } - } - END { - // paper says + not =, but that makes no sense. - self.size[self.scan_pop()] = 1; - self.check_stack(k + 1); - } - _ { - self.size[self.scan_pop()] = self.size[x] + self.right_total; - if k > 0 { self.check_stack(k); } - } - } - } - } - fn print_newline(amount: int) { - #debug("NEWLINE %d", amount); - self.out.write_str("\n"); - self.pending_indentation = 0; - self.indent(amount); - } - fn indent(amount: int) { - #debug("INDENT %d", amount); - self.pending_indentation += amount; - } - fn get_top() -> print_stack_elt { - let n = vec::len(self.print_stack); - let top: print_stack_elt = {offset: 0, pbreak: broken(inconsistent)}; - if n != 0u { top = self.print_stack[n - 1u]; } - ret top; - } - fn write_str(s: str) { - while self.pending_indentation > 0 { - self.out.write_str(" "); - self.pending_indentation -= 1; - } - self.out.write_str(s); - } - fn print(x: token, L: int) { - #debug("print %s %d (remaining line space=%d)", tok_str(x), L, - self.space); - log(debug, buf_str(self.token, self.size, self.left, self.right, 6u)); - alt x { - BEGIN(b) { - if L > self.space { - let col = self.margin - self.space + b.offset; - #debug("print BEGIN -> push broken block at col %d", col); - self.print_stack += [{offset: col, pbreak: broken(b.breaks)}]; - } else { - #debug("print BEGIN -> push fitting block"); - self.print_stack += [{offset: 0, pbreak: fits}]; - } - } - END { - #debug("print END -> pop END"); - assert (vec::len(self.print_stack) != 0u); - vec::pop(self.print_stack); - } - BREAK(b) { - let top = self.get_top(); - alt top.pbreak { - fits { - #debug("print BREAK in fitting block"); - self.space -= b.blank_space; - self.indent(b.blank_space); - } - broken(consistent) { - #debug("print BREAK in consistent block"); - self.print_newline(top.offset + b.offset); - self.space = self.margin - (top.offset + b.offset); - } - broken(inconsistent) { - if L > self.space { - #debug("print BREAK w/ newline in inconsistent"); - self.print_newline(top.offset + b.offset); - self.space = self.margin - (top.offset + b.offset); - } else { - #debug("print BREAK w/o newline in inconsistent"); - self.indent(b.blank_space); - self.space -= b.blank_space; - } - } - } - } - STRING(s, len) { - #debug("print STRING"); - assert (L == len); - // assert L <= space; - self.space -= len; - self.write_str(s); - } - EOF { - // EOF should never get here. - fail; - } - } - } -} - -// Convenience functions to talk to the printer. -fn box(p: printer, indent: uint, b: breaks) { - p.pretty_print(BEGIN({offset: indent as int, breaks: b})); -} - -fn ibox(p: printer, indent: uint) { box(p, indent, inconsistent); } - -fn cbox(p: printer, indent: uint) { box(p, indent, consistent); } - -fn break_offset(p: printer, n: uint, off: int) { - p.pretty_print(BREAK({offset: off, blank_space: n as int})); -} - -fn end(p: printer) { p.pretty_print(END); } - -fn eof(p: printer) { p.pretty_print(EOF); } - -fn word(p: printer, wrd: str) { - p.pretty_print(STRING(wrd, str::len(wrd) as int)); -} - -fn huge_word(p: printer, wrd: str) { - p.pretty_print(STRING(wrd, size_infinity)); -} - -fn zero_word(p: printer, wrd: str) { p.pretty_print(STRING(wrd, 0)); } - -fn spaces(p: printer, n: uint) { break_offset(p, n, 0); } - -fn zerobreak(p: printer) { spaces(p, 0u); } - -fn space(p: printer) { spaces(p, 1u); } - -fn hardbreak(p: printer) { spaces(p, size_infinity as uint); } - -fn hardbreak_tok_offset(off: int) -> token { - ret BREAK({offset: off, blank_space: size_infinity}); -} - -fn hardbreak_tok() -> token { ret hardbreak_tok_offset(0); } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs deleted file mode 100644 index 5f92b5d5beb..00000000000 --- a/src/comp/syntax/print/pprust.rs +++ /dev/null @@ -1,1793 +0,0 @@ - -import std::io; -import parse::lexer; -import syntax::codemap::codemap; -import pp::{break_offset, word, printer, - space, zerobreak, hardbreak, breaks, consistent, - inconsistent, eof}; -import driver::diagnostic; - -// The ps is stored here to prevent recursive type. -enum ann_node { - node_block(ps, ast::blk), - node_item(ps, @ast::item), - node_expr(ps, @ast::expr), - node_pat(ps, @ast::pat), -} -type pp_ann = {pre: fn@(ann_node), post: fn@(ann_node)}; - -fn no_ann() -> pp_ann { - fn ignore(_node: ann_node) { } - ret {pre: ignore, post: ignore}; -} - -type ps = - @{s: pp::printer, - cm: option<codemap>, - comments: option<[lexer::cmnt]>, - literals: option<[lexer::lit]>, - mutable cur_cmnt: uint, - mutable cur_lit: uint, - mutable boxes: [pp::breaks], - ann: pp_ann}; - -fn ibox(s: ps, u: uint) { s.boxes += [pp::inconsistent]; pp::ibox(s.s, u); } - -fn end(s: ps) { vec::pop(s.boxes); pp::end(s.s); } - -fn rust_printer(writer: io::writer) -> ps { - let boxes: [pp::breaks] = []; - ret @{s: pp::mk_printer(writer, default_columns), - cm: none::<codemap>, - comments: none::<[lexer::cmnt]>, - literals: none::<[lexer::lit]>, - mutable cur_cmnt: 0u, - mutable cur_lit: 0u, - mutable boxes: boxes, - ann: no_ann()}; -} - -const indent_unit: uint = 4u; -const alt_indent_unit: uint = 2u; - -const default_columns: uint = 78u; - -// Requires you to pass an input filename and reader so that -// it can scan the input text for comments and literals to -// copy forward. -fn print_crate(cm: codemap, span_diagnostic: diagnostic::span_handler, - crate: @ast::crate, filename: str, in: io::reader, - out: io::writer, ann: pp_ann) { - let boxes: [pp::breaks] = []; - let r = lexer::gather_comments_and_literals(cm, span_diagnostic, filename, - in); - let s = - @{s: pp::mk_printer(out, default_columns), - cm: some(cm), - comments: some(r.cmnts), - literals: some(r.lits), - mutable cur_cmnt: 0u, - mutable cur_lit: 0u, - mutable boxes: boxes, - ann: ann}; - print_crate_(s, crate); -} - -fn print_crate_(s: ps, &&crate: @ast::crate) { - print_mod(s, crate.node.module, crate.node.attrs); - print_remaining_comments(s); - eof(s.s); -} - -fn ty_to_str(ty: @ast::ty) -> str { be to_str(ty, print_type); } - -fn pat_to_str(pat: @ast::pat) -> str { be to_str(pat, print_pat); } - -fn expr_to_str(e: @ast::expr) -> str { be to_str(e, print_expr); } - -fn stmt_to_str(s: ast::stmt) -> str { be to_str(s, print_stmt); } - -fn item_to_str(i: @ast::item) -> str { be to_str(i, print_item); } - -fn attr_to_str(i: ast::attribute) -> str { be to_str(i, print_attribute); } - -fn typarams_to_str(tps: [ast::ty_param]) -> str { - be to_str(tps, print_type_params) -} - -fn path_to_str(&&p: @ast::path) -> str { - be to_str(p, bind print_path(_, _, false)); -} - -fn fun_to_str(decl: ast::fn_decl, name: ast::ident, - params: [ast::ty_param]) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - print_fn(s, decl, name, params); - end(s); // Close the head box - end(s); // Close the outer box - eof(s.s); - io::mem_buffer_str(buffer) -} - -#[test] -fn test_fun_to_str() { - let decl: ast::fn_decl = { - inputs: [], - output: @ast_util::respan(ast_util::dummy_sp(), ast::ty_nil), - purity: ast::impure_fn, - cf: ast::return_val, - constraints: [] - }; - assert fun_to_str(decl, "a", []) == "fn a()"; -} - -fn res_to_str(decl: ast::fn_decl, name: ast::ident, - params: [ast::ty_param]) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - print_res(s, decl, name, params); - end(s); // Close the head box - end(s); // Close the outer box - eof(s.s); - io::mem_buffer_str(buffer) -} - -#[test] -fn test_res_to_str() { - let decl: ast::fn_decl = { - inputs: [{ - mode: ast::expl(ast::by_val), - ty: @ast_util::respan(ast_util::dummy_sp(), ast::ty_nil), - ident: "b", - id: 0 - }], - output: @ast_util::respan(ast_util::dummy_sp(), ast::ty_nil), - purity: ast::impure_fn, - cf: ast::return_val, - constraints: [] - }; - assert res_to_str(decl, "a", []) == "resource a(b: ())"; -} - -fn block_to_str(blk: ast::blk) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-ibox, will be closed by print-block after { - ibox(s, 0u); - print_block(s, blk); - eof(s.s); - io::mem_buffer_str(buffer) -} - -fn meta_item_to_str(mi: ast::meta_item) -> str { - ret to_str(@mi, print_meta_item); -} - -fn attribute_to_str(attr: ast::attribute) -> str { - be to_str(attr, print_attribute); -} - -fn variant_to_str(var: ast::variant) -> str { - be to_str(var, print_variant); -} - -#[test] -fn test_variant_to_str() { - let var = ast_util::respan(ast_util::dummy_sp(), { - name: "principle_skinner", - attrs: [], - args: [], - id: 0, - disr_expr: none - }); - - let varstr = variant_to_str(var); - assert varstr == "principle_skinner"; -} - -fn cbox(s: ps, u: uint) { s.boxes += [pp::consistent]; pp::cbox(s.s, u); } - -fn box(s: ps, u: uint, b: pp::breaks) { s.boxes += [b]; pp::box(s.s, u, b); } - -fn nbsp(s: ps) { word(s.s, " "); } - -fn word_nbsp(s: ps, w: str) { word(s.s, w); nbsp(s); } - -fn word_space(s: ps, w: str) { word(s.s, w); space(s.s); } - -fn popen(s: ps) { word(s.s, "("); } - -fn pclose(s: ps) { word(s.s, ")"); } - -fn head(s: ps, w: str) { - // outer-box is consistent - cbox(s, indent_unit); - // head-box is inconsistent - ibox(s, str::len(w) + 1u); - // keyword that starts the head - word_nbsp(s, w); -} - -fn bopen(s: ps) { - word(s.s, "{"); - end(s); // close the head-box -} - -fn bclose_(s: ps, span: codemap::span, indented: uint) { - maybe_print_comment(s, span.hi); - break_offset_if_not_bol(s, 1u, -(indented as int)); - word(s.s, "}"); - end(s); // close the outer-box -} -fn bclose(s: ps, span: codemap::span) { bclose_(s, span, indent_unit); } - -fn is_begin(s: ps) -> bool { - alt s.s.last_token() { pp::BEGIN(_) { true } _ { false } } -} - -fn is_end(s: ps) -> bool { - alt s.s.last_token() { pp::END { true } _ { false } } -} - -fn is_bol(s: ps) -> bool { - ret s.s.last_token() == pp::EOF || - s.s.last_token() == pp::hardbreak_tok(); -} - -fn hardbreak_if_not_bol(s: ps) { if !is_bol(s) { hardbreak(s.s); } } -fn space_if_not_bol(s: ps) { if !is_bol(s) { space(s.s); } } -fn break_offset_if_not_bol(s: ps, n: uint, off: int) { - if !is_bol(s) { - break_offset(s.s, n, off); - } else { - if off != 0 && s.s.last_token() == pp::hardbreak_tok() { - // We do something pretty sketchy here: tuck the nonzero - // offset-adjustment we were going to deposit along with the - // break into the previous hardbreak. - s.s.replace_last_token(pp::hardbreak_tok_offset(off)); - } - } -} - -// Synthesizes a comment that was not textually present in the original source -// file. -fn synth_comment(s: ps, text: str) { - word(s.s, "/*"); - space(s.s); - word(s.s, text); - space(s.s); - word(s.s, "*/"); -} - -fn commasep<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN)) { - box(s, 0u, b); - let first = true; - for elt: IN in elts { - if first { first = false; } else { word_space(s, ","); } - op(s, elt); - } - end(s); -} - - -fn commasep_cmnt<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN), - get_span: fn(IN) -> codemap::span) { - box(s, 0u, b); - let len = vec::len::<IN>(elts); - let i = 0u; - for elt: IN in elts { - maybe_print_comment(s, get_span(elt).hi); - op(s, elt); - i += 1u; - if i < len { - word(s.s, ","); - maybe_print_trailing_comment(s, get_span(elt), - some(get_span(elts[i]).hi)); - space_if_not_bol(s); - } - } - end(s); -} - -fn commasep_exprs(s: ps, b: breaks, exprs: [@ast::expr]) { - fn expr_span(&&expr: @ast::expr) -> codemap::span { ret expr.span; } - commasep_cmnt(s, b, exprs, print_expr, expr_span); -} - -fn print_mod(s: ps, _mod: ast::_mod, attrs: [ast::attribute]) { - print_inner_attributes(s, attrs); - for vitem: @ast::view_item in _mod.view_items { - print_view_item(s, vitem); - } - for item: @ast::item in _mod.items { print_item(s, item); } -} - -fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) { - print_inner_attributes(s, attrs); - for vitem: @ast::view_item in nmod.view_items { - print_view_item(s, vitem); - } - for item: @ast::native_item in nmod.items { print_native_item(s, item); } -} - -fn print_type(s: ps, &&ty: @ast::ty) { - maybe_print_comment(s, ty.span.lo); - ibox(s, 0u); - alt ty.node { - ast::ty_nil { word(s.s, "()"); } - ast::ty_bot { word(s.s, "!"); } - ast::ty_box(mt) { word(s.s, "@"); print_mt(s, mt); } - ast::ty_uniq(mt) { word(s.s, "~"); print_mt(s, mt); } - ast::ty_vec(mt) { - word(s.s, "["); - alt mt.mutbl { - ast::m_mutbl { word_space(s, "mut"); } - ast::m_const { word_space(s, "const"); } - ast::m_imm { } - } - print_type(s, mt.ty); - word(s.s, "]"); - } - ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); } - ast::ty_rec(fields) { - word(s.s, "{"); - fn print_field(s: ps, f: ast::ty_field) { - cbox(s, indent_unit); - print_mutability(s, f.node.mt.mutbl); - word(s.s, f.node.ident); - word_space(s, ":"); - print_type(s, f.node.mt.ty); - end(s); - } - fn get_span(f: ast::ty_field) -> codemap::span { ret f.span; } - commasep_cmnt(s, consistent, fields, print_field, get_span); - word(s.s, ",}"); - } - ast::ty_tup(elts) { - popen(s); - commasep(s, inconsistent, elts, print_type); - pclose(s); - } - ast::ty_fn(proto, d) { - print_ty_fn(s, some(proto), d, none, none); - } - ast::ty_path(path, _) { print_path(s, path, false); } - ast::ty_constr(t, cs) { - print_type(s, t); - space(s.s); - word(s.s, constrs_str(cs, ty_constr_to_str)); - } - ast::ty_mac(_) { - fail "print_type doesn't know how to print a ty_mac"; - } - ast::ty_infer { - fail "print_type shouldn't see a ty_infer"; - } - - } - end(s); -} - -fn print_native_item(s: ps, item: @ast::native_item) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, item.span.lo); - print_outer_attributes(s, item.attrs); - alt item.node { - ast::native_item_fn(decl, typarams) { - print_fn(s, decl, item.ident, typarams); - end(s); // end head-ibox - word(s.s, ";"); - end(s); // end the outer fn box - } - } -} - -fn print_item(s: ps, &&item: @ast::item) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, item.span.lo); - print_outer_attributes(s, item.attrs); - let ann_node = node_item(s, item); - s.ann.pre(ann_node); - alt item.node { - ast::item_const(ty, expr) { - head(s, "const"); - word_space(s, item.ident + ":"); - print_type(s, ty); - space(s.s); - end(s); // end the head-ibox - - word_space(s, "="); - print_expr(s, expr); - word(s.s, ";"); - end(s); // end the outer cbox - - } - ast::item_fn(decl, typarams, body) { - print_fn(s, decl, item.ident, typarams); - word(s.s, " "); - print_block_with_attrs(s, body, item.attrs); - } - ast::item_mod(_mod) { - head(s, "mod"); - word_nbsp(s, item.ident); - bopen(s); - print_mod(s, _mod, item.attrs); - bclose(s, item.span); - } - ast::item_native_mod(nmod) { - head(s, "native"); - word_nbsp(s, "mod"); - word_nbsp(s, item.ident); - bopen(s); - print_native_mod(s, nmod, item.attrs); - bclose(s, item.span); - } - ast::item_ty(ty, params) { - ibox(s, indent_unit); - ibox(s, 0u); - word_nbsp(s, "type"); - word(s.s, item.ident); - print_type_params(s, params); - end(s); // end the inner ibox - - space(s.s); - word_space(s, "="); - print_type(s, ty); - word(s.s, ";"); - end(s); // end the outer ibox - } - ast::item_enum(variants, params) { - let newtype = - vec::len(variants) == 1u && - str::eq(item.ident, variants[0].node.name) && - vec::len(variants[0].node.args) == 1u; - if newtype { - ibox(s, indent_unit); - word_space(s, "enum"); - } else { head(s, "enum"); } - word(s.s, item.ident); - print_type_params(s, params); - space(s.s); - if newtype { - word_space(s, "="); - print_type(s, variants[0].node.args[0].ty); - word(s.s, ";"); - end(s); - } else { - bopen(s); - for v: ast::variant in variants { - space_if_not_bol(s); - maybe_print_comment(s, v.span.lo); - print_outer_attributes(s, v.node.attrs); - ibox(s, indent_unit); - print_variant(s, v); - word(s.s, ","); - end(s); - maybe_print_trailing_comment(s, v.span, none::<uint>); - } - bclose(s, item.span); - } - } - ast::item_class(tps,items,_,ctor_decl,ctor_body) { - head(s, "class"); - word_nbsp(s, item.ident); - print_type_params(s, tps); - bopen(s); - hardbreak_if_not_bol(s); - head(s, "new"); - print_fn_args_and_ret(s, ctor_decl); - space(s.s); - print_block(s, ctor_body); - for ci in items { - /* - FIXME: collect all private items and print them - in a single "priv" section - */ - hardbreak_if_not_bol(s); - alt ci.node.privacy { - ast::priv { - head(s, "priv"); - bopen(s); - hardbreak_if_not_bol(s); - } - _ {} - } - alt ci.node.decl { - ast::instance_var(nm, t, mt, _) { - word_nbsp(s, "let"); - alt mt { - ast::class_mutable { word_nbsp(s, "mutable"); } - _ {} - } - word(s.s, nm); - word_nbsp(s, ":"); - print_type(s, t); - word(s.s, ";"); - } - ast::class_method(i) { - print_item(s, i); - } - } - alt ci.node.privacy { - ast::priv { bclose(s, ci.span); } - _ {} - } - } - } - ast::item_impl(tps, ifce, ty, methods) { - head(s, "impl"); - word(s.s, item.ident); - print_type_params(s, tps); - space(s.s); - alt ifce { - some(ty) { - word_nbsp(s, "of"); - print_type(s, ty); - space(s.s); - } - _ {} - } - word_nbsp(s, "for"); - print_type(s, ty); - space(s.s); - bopen(s); - for meth in methods { - hardbreak_if_not_bol(s); - maybe_print_comment(s, meth.span.lo); - print_outer_attributes(s, meth.attrs); - print_fn(s, meth.decl, meth.ident, meth.tps); - word(s.s, " "); - print_block_with_attrs(s, meth.body, meth.attrs); - } - bclose(s, item.span); - } - ast::item_iface(tps, methods) { - head(s, "iface"); - word(s.s, item.ident); - print_type_params(s, tps); - word(s.s, " "); - bopen(s); - for meth in methods { print_ty_method(s, meth); } - bclose(s, item.span); - } - ast::item_res(decl, tps, body, dt_id, ct_id) { - print_res(s, decl, item.ident, tps); - print_block(s, body); - } - } - s.ann.post(ann_node); -} - -fn print_res(s: ps, decl: ast::fn_decl, name: ast::ident, - typarams: [ast::ty_param]) { - head(s, "resource"); - word(s.s, name); - print_type_params(s, typarams); - popen(s); - word_space(s, decl.inputs[0].ident + ":"); - print_type(s, decl.inputs[0].ty); - pclose(s); - space(s.s); -} - -fn print_variant(s: ps, v: ast::variant) { - word(s.s, v.node.name); - if vec::len(v.node.args) > 0u { - popen(s); - fn print_variant_arg(s: ps, arg: ast::variant_arg) { - print_type(s, arg.ty); - } - commasep(s, consistent, v.node.args, print_variant_arg); - pclose(s); - } - alt v.node.disr_expr { - some(d) { - space(s.s); - word_space(s, "="); - print_expr(s, d); - } - _ {} - } -} - -fn print_ty_method(s: ps, m: ast::ty_method) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, m.span.lo); - print_outer_attributes(s, m.attrs); - print_ty_fn(s, none, m.decl, some(m.ident), some(m.tps)); - word(s.s, ";"); -} - -fn print_outer_attributes(s: ps, attrs: [ast::attribute]) { - let count = 0; - for attr: ast::attribute in attrs { - alt attr.node.style { - ast::attr_outer { print_attribute(s, attr); count += 1; } - _ {/* fallthrough */ } - } - } - if count > 0 { hardbreak_if_not_bol(s); } -} - -fn print_inner_attributes(s: ps, attrs: [ast::attribute]) { - let count = 0; - for attr: ast::attribute in attrs { - alt attr.node.style { - ast::attr_inner { - print_attribute(s, attr); - word(s.s, ";"); - count += 1; - } - _ {/* fallthrough */ } - } - } - if count > 0 { hardbreak_if_not_bol(s); } -} - -fn print_attribute(s: ps, attr: ast::attribute) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, attr.span.lo); - word(s.s, "#["); - print_meta_item(s, @attr.node.value); - word(s.s, "]"); -} - - -fn print_stmt(s: ps, st: ast::stmt) { - maybe_print_comment(s, st.span.lo); - alt st.node { - ast::stmt_decl(decl, _) { - print_decl(s, decl); - } - ast::stmt_expr(expr, _) { - space_if_not_bol(s); - print_expr(s, expr); - } - ast::stmt_semi(expr, _) { - space_if_not_bol(s); - print_expr(s, expr); - word(s.s, ";"); - } - } - if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); } - maybe_print_trailing_comment(s, st.span, none::<uint>); -} - -fn print_block(s: ps, blk: ast::blk) { - print_possibly_embedded_block(s, blk, block_normal, indent_unit); -} - -fn print_block_with_attrs(s: ps, blk: ast::blk, attrs: [ast::attribute]) { - print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs); -} - -enum embed_type { block_macro, block_block_fn, block_normal, } - -fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type, - indented: uint) { - print_possibly_embedded_block_( - s, blk, embedded, indented, []); -} - -fn print_possibly_embedded_block_(s: ps, blk: ast::blk, embedded: embed_type, - indented: uint, attrs: [ast::attribute]) { - alt blk.node.rules { - ast::unchecked_blk { word(s.s, "unchecked"); } - ast::unsafe_blk { word(s.s, "unsafe"); } - ast::default_blk { } - } - maybe_print_comment(s, blk.span.lo); - let ann_node = node_block(s, blk); - s.ann.pre(ann_node); - alt embedded { - block_macro { word(s.s, "#{"); end(s); } - block_block_fn { end(s); } - block_normal { bopen(s); } - } - - print_inner_attributes(s, attrs); - - for vi in blk.node.view_items { print_view_item(s, vi); } - for st: @ast::stmt in blk.node.stmts { - print_stmt(s, *st); - } - alt blk.node.expr { - some(expr) { - space_if_not_bol(s); - print_expr(s, expr); - maybe_print_trailing_comment(s, expr.span, some(blk.span.hi)); - } - _ { } - } - bclose_(s, blk.span, indented); - s.ann.post(ann_node); -} - -// ret and fail, without arguments cannot appear is the discriminant of if, -// alt, do, & while unambiguously without being parenthesized -fn print_maybe_parens_discrim(s: ps, e: @ast::expr) { - let disambig = alt e.node { - ast::expr_ret(none) | ast::expr_fail(none) { true } - _ { false } - }; - if disambig { popen(s); } - print_expr(s, e); - if disambig { pclose(s); } -} - -fn print_if(s: ps, test: @ast::expr, blk: ast::blk, - elseopt: option<@ast::expr>, chk: bool) { - head(s, "if"); - if chk { word_nbsp(s, "check"); } - print_maybe_parens_discrim(s, test); - space(s.s); - print_block(s, blk); - fn do_else(s: ps, els: option<@ast::expr>) { - alt els { - some(_else) { - alt _else.node { - // "another else-if" - ast::expr_if(i, t, e) { - cbox(s, indent_unit - 1u); - ibox(s, 0u); - word(s.s, " else if "); - print_maybe_parens_discrim(s, i); - space(s.s); - print_block(s, t); - do_else(s, e); - } - // "final else" - ast::expr_block(b) { - cbox(s, indent_unit - 1u); - ibox(s, 0u); - word(s.s, " else "); - print_block(s, b); - } - // BLEAH, constraints would be great here - _ { - fail "print_if saw if with weird alternative"; - } - } - } - _ {/* fall through */ } - } - } - do_else(s, elseopt); -} - -fn print_mac(s: ps, m: ast::mac) { - alt m.node { - ast::mac_invoc(path, arg, body) { - word(s.s, "#"); - print_path(s, path, false); - alt arg { - some(@{node: ast::expr_vec(_, _), _}) { } - _ { word(s.s, " "); } - } - option::may(arg, bind print_expr(s, _)); - // FIXME: extension 'body' - } - ast::mac_embed_type(ty) { - word(s.s, "#<"); - print_type(s, ty); - word(s.s, ">"); - } - ast::mac_embed_block(blk) { - print_possibly_embedded_block(s, blk, block_normal, indent_unit); - } - ast::mac_ellipsis { word(s.s, "..."); } - ast::mac_var(v) { word(s.s, #fmt("$%u", v)); } - _ { /* fixme */ } - } -} - -fn print_expr(s: ps, &&expr: @ast::expr) { - maybe_print_comment(s, expr.span.lo); - ibox(s, indent_unit); - let ann_node = node_expr(s, expr); - s.ann.pre(ann_node); - alt expr.node { - ast::expr_vec(exprs, mutbl) { - ibox(s, indent_unit); - word(s.s, "["); - if mutbl == ast::m_mutbl { - word(s.s, "mutable"); - if vec::len(exprs) > 0u { nbsp(s); } - } - commasep_exprs(s, inconsistent, exprs); - word(s.s, "]"); - end(s); - } - ast::expr_rec(fields, wth) { - fn print_field(s: ps, field: ast::field) { - ibox(s, indent_unit); - if field.node.mutbl == ast::m_mutbl { word_nbsp(s, "mutable"); } - word(s.s, field.node.ident); - word_space(s, ":"); - print_expr(s, field.node.expr); - end(s); - } - fn get_span(field: ast::field) -> codemap::span { ret field.span; } - word(s.s, "{"); - commasep_cmnt(s, consistent, fields, print_field, get_span); - alt wth { - some(expr) { - if vec::len(fields) > 0u { space(s.s); } - ibox(s, indent_unit); - word_space(s, "with"); - print_expr(s, expr); - end(s); - } - _ { word(s.s, ","); } - } - word(s.s, "}"); - } - ast::expr_tup(exprs) { - popen(s); - commasep_exprs(s, inconsistent, exprs); - pclose(s); - } - ast::expr_call(func, args, has_block) { - print_expr_parens_if_not_bot(s, func); - let base_args = args, blk = none; - if has_block { blk = some(vec::pop(base_args)); } - if !has_block || vec::len(base_args) > 0u { - popen(s); - commasep_exprs(s, inconsistent, base_args); - pclose(s); - } - if has_block { - nbsp(s); - print_expr(s, option::get(blk)); - } - } - ast::expr_bind(func, args) { - fn print_opt(s: ps, expr: option<@ast::expr>) { - alt expr { - some(expr) { print_expr(s, expr); } - _ { word(s.s, "_"); } - } - } - - // "bind" keyword is only needed if there are no "_" arguments. - if !vec::any(args) {|arg| option::is_none(arg) } { - word_nbsp(s, "bind"); - } - - print_expr(s, func); - popen(s); - commasep(s, inconsistent, args, print_opt); - pclose(s); - } - ast::expr_binary(op, lhs, rhs) { - let prec = operator_prec(op); - print_op_maybe_parens(s, lhs, prec); - space(s.s); - word_space(s, ast_util::binop_to_str(op)); - print_op_maybe_parens(s, rhs, prec + 1); - } - ast::expr_unary(op, expr) { - word(s.s, ast_util::unop_to_str(op)); - print_op_maybe_parens(s, expr, parse::parser::unop_prec); - } - ast::expr_lit(lit) { print_literal(s, lit); } - ast::expr_cast(expr, ty) { - print_op_maybe_parens(s, expr, parse::parser::as_prec); - space(s.s); - word_space(s, "as"); - print_type(s, ty); - } - ast::expr_if(test, blk, elseopt) { - print_if(s, test, blk, elseopt, false); - } - ast::expr_if_check(test, blk, elseopt) { - print_if(s, test, blk, elseopt, true); - } - ast::expr_while(test, blk) { - head(s, "while"); - print_maybe_parens_discrim(s, test); - space(s.s); - print_block(s, blk); - } - ast::expr_for(decl, expr, blk) { - head(s, "for"); - print_for_decl(s, decl, expr); - space(s.s); - print_block(s, blk); - } - ast::expr_do_while(blk, expr) { - head(s, "do"); - space(s.s); - print_block(s, blk); - space(s.s); - word_space(s, "while"); - print_expr(s, expr); - } - ast::expr_alt(expr, arms, mode) { - cbox(s, alt_indent_unit); - ibox(s, 4u); - word_nbsp(s, "alt"); - if mode == ast::alt_check { word_nbsp(s, "check"); } - print_maybe_parens_discrim(s, expr); - space(s.s); - bopen(s); - for arm: ast::arm in arms { - space(s.s); - cbox(s, alt_indent_unit); - ibox(s, 0u); - let first = true; - for p: @ast::pat in arm.pats { - if first { - first = false; - } else { space(s.s); word_space(s, "|"); } - print_pat(s, p); - } - space(s.s); - alt arm.guard { - some(e) { word_space(s, "if"); print_expr(s, e); space(s.s); } - none { } - } - print_possibly_embedded_block(s, arm.body, block_normal, - alt_indent_unit); - } - bclose_(s, expr.span, alt_indent_unit); - } - ast::expr_fn(proto, decl, body, cap_clause) { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block at start - ibox(s, 0u); - word(s.s, proto_to_str(proto)); - print_cap_clause(s, *cap_clause); - print_fn_args_and_ret(s, decl); - space(s.s); - print_block(s, body); - } - ast::expr_fn_block(decl, body) { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block at start - ibox(s, 0u); - word(s.s, "{"); - print_fn_block_args(s, decl); - print_possibly_embedded_block(s, body, block_block_fn, indent_unit); - } - ast::expr_block(blk) { - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-box, will be closed by print-block after { - ibox(s, 0u); - print_block(s, blk); - } - ast::expr_copy(e) { word_space(s, "copy"); print_expr(s, e); } - ast::expr_move(lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word_space(s, "<-"); - print_expr(s, rhs); - } - ast::expr_assign(lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word_space(s, "="); - print_expr(s, rhs); - } - ast::expr_swap(lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word_space(s, "<->"); - print_expr(s, rhs); - } - ast::expr_assign_op(op, lhs, rhs) { - print_expr(s, lhs); - space(s.s); - word(s.s, ast_util::binop_to_str(op)); - word_space(s, "="); - print_expr(s, rhs); - } - ast::expr_field(expr, id, tys) { - // Deal with '10.x' - if ends_in_lit_int(expr) { - popen(s); print_expr(s, expr); pclose(s); - } else { - print_expr_parens_if_not_bot(s, expr); - } - word(s.s, "."); - word(s.s, id); - if vec::len(tys) > 0u { - word(s.s, "::<"); - commasep(s, inconsistent, tys, print_type); - word(s.s, ">"); - } - } - ast::expr_index(expr, index) { - print_expr_parens_if_not_bot(s, expr); - word(s.s, "["); - print_expr(s, index); - word(s.s, "]"); - } - ast::expr_path(path) { print_path(s, path, true); } - ast::expr_fail(maybe_fail_val) { - word(s.s, "fail"); - alt maybe_fail_val { - some(expr) { word(s.s, " "); print_expr(s, expr); } - _ { } - } - } - ast::expr_break { word(s.s, "break"); } - ast::expr_cont { word(s.s, "cont"); } - ast::expr_ret(result) { - word(s.s, "ret"); - alt result { - some(expr) { word(s.s, " "); print_expr(s, expr); } - _ { } - } - } - ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); } - ast::expr_log(lvl, lexp, expr) { - alt check lvl { - 1 { word_nbsp(s, "log"); print_expr(s, expr); } - 0 { word_nbsp(s, "log_err"); print_expr(s, expr); } - 2 { - word_nbsp(s, "log"); - popen(s); - print_expr(s, lexp); - word(s.s, ","); - space_if_not_bol(s); - print_expr(s, expr); - pclose(s); - } - } - } - ast::expr_check(m, expr) { - alt m { - ast::claimed_expr { word_nbsp(s, "claim"); } - ast::checked_expr { word_nbsp(s, "check"); } - } - popen(s); - print_expr(s, expr); - pclose(s); - } - ast::expr_assert(expr) { - word_nbsp(s, "assert"); - print_expr(s, expr); - } - ast::expr_mac(m) { print_mac(s, m); } - } - s.ann.post(ann_node); - end(s); -} - -fn print_expr_parens_if_not_bot(s: ps, ex: @ast::expr) { - let parens = alt ex.node { - ast::expr_fail(_) | ast::expr_ret(_) | - ast::expr_binary(_, _, _) | ast::expr_unary(_, _) | - ast::expr_move(_, _) | ast::expr_copy(_) | - ast::expr_assign(_, _) | ast::expr_be(_) | - ast::expr_assign_op(_, _, _) | ast::expr_swap(_, _) | - ast::expr_log(_, _, _) | ast::expr_assert(_) | - ast::expr_call(_, _, true) | - ast::expr_check(_, _) { true } - _ { false } - }; - if parens { popen(s); } - print_expr(s, ex); - if parens { pclose(s); } -} - -fn print_local_decl(s: ps, loc: @ast::local) { - print_pat(s, loc.node.pat); - alt loc.node.ty.node { - ast::ty_infer { } - _ { word_space(s, ":"); print_type(s, loc.node.ty); } - } -} - -fn print_decl(s: ps, decl: @ast::decl) { - maybe_print_comment(s, decl.span.lo); - alt decl.node { - ast::decl_local(locs) { - space_if_not_bol(s); - ibox(s, indent_unit); - word_nbsp(s, "let"); - fn print_local(s: ps, &&loc: @ast::local) { - ibox(s, indent_unit); - print_local_decl(s, loc); - end(s); - alt loc.node.init { - some(init) { - nbsp(s); - alt init.op { - ast::init_assign { word_space(s, "="); } - ast::init_move { word_space(s, "<-"); } - } - print_expr(s, init.expr); - } - _ { } - } - } - commasep(s, consistent, locs, print_local); - end(s); - } - ast::decl_item(item) { print_item(s, item); } - } -} - -fn print_ident(s: ps, ident: ast::ident) { word(s.s, ident); } - -fn print_for_decl(s: ps, loc: @ast::local, coll: @ast::expr) { - print_local_decl(s, loc); - space(s.s); - word_space(s, "in"); - print_expr(s, coll); -} - -fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) { - maybe_print_comment(s, path.span.lo); - if path.node.global { word(s.s, "::"); } - let first = true; - for id: ast::ident in path.node.idents { - if first { first = false; } else { word(s.s, "::"); } - word(s.s, id); - } - if vec::len(path.node.types) > 0u { - if colons_before_params { word(s.s, "::"); } - word(s.s, "<"); - commasep(s, inconsistent, path.node.types, print_type); - word(s.s, ">"); - } -} - -fn print_pat(s: ps, &&pat: @ast::pat) { - maybe_print_comment(s, pat.span.lo); - let ann_node = node_pat(s, pat); - s.ann.pre(ann_node); - /* Pat isn't normalized, but the beauty of it - is that it doesn't matter */ - alt pat.node { - ast::pat_wild { word(s.s, "_"); } - ast::pat_ident(path, sub) { - print_path(s, path, true); - alt sub { - some(p) { word(s.s, "@"); print_pat(s, p); } - _ {} - } - } - ast::pat_enum(path, args) { - print_path(s, path, true); - if vec::len(args) > 0u { - popen(s); - commasep(s, inconsistent, args, print_pat); - pclose(s); - } else { } - } - ast::pat_rec(fields, etc) { - word(s.s, "{"); - fn print_field(s: ps, f: ast::field_pat) { - cbox(s, indent_unit); - word(s.s, f.ident); - word_space(s, ":"); - print_pat(s, f.pat); - end(s); - } - fn get_span(f: ast::field_pat) -> codemap::span { ret f.pat.span; } - commasep_cmnt(s, consistent, fields, print_field, get_span); - if etc { - if vec::len(fields) != 0u { word_space(s, ","); } - word(s.s, "_"); - } - word(s.s, "}"); - } - ast::pat_tup(elts) { - popen(s); - commasep(s, inconsistent, elts, print_pat); - pclose(s); - } - ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); } - ast::pat_uniq(inner) { word(s.s, "~"); print_pat(s, inner); } - ast::pat_lit(e) { print_expr(s, e); } - ast::pat_range(begin, end) { - print_expr(s, begin); - space(s.s); - word_space(s, "to"); - print_expr(s, end); - } - } - s.ann.post(ann_node); -} - -fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident, - typarams: [ast::ty_param]) { - alt decl.purity { - ast::impure_fn { head(s, "fn"); } - ast::unsafe_fn { head(s, "unsafe fn"); } - ast::pure_fn { head(s, "pure fn"); } - ast::crust_fn { head(s, "crust fn"); } - } - word(s.s, name); - print_type_params(s, typarams); - print_fn_args_and_ret(s, decl); -} - -fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) { - fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) { - word(s.s, cap_item.name); - } - - let has_copies = vec::is_not_empty(cap_clause.copies); - let has_moves = vec::is_not_empty(cap_clause.moves); - if !has_copies && !has_moves { ret; } - - word(s.s, "["); - - if has_copies { - word_nbsp(s, "copy"); - commasep(s, inconsistent, cap_clause.copies, print_cap_item); - if has_moves { - word_space(s, ";"); - } - } - - if has_moves { - word_nbsp(s, "move"); - commasep(s, inconsistent, cap_clause.moves, print_cap_item); - } - - word(s.s, "]"); -} - -fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) { - popen(s); - fn print_arg(s: ps, x: ast::arg) { - ibox(s, indent_unit); - print_arg_mode(s, x.mode); - word_space(s, x.ident + ":"); - print_type(s, x.ty); - end(s); - } - commasep(s, inconsistent, decl.inputs, print_arg); - pclose(s); - word(s.s, constrs_str(decl.constraints, {|c| - ast_fn_constr_to_str(decl, c) - })); - - maybe_print_comment(s, decl.output.span.lo); - if decl.output.node != ast::ty_nil { - space_if_not_bol(s); - word_space(s, "->"); - print_type(s, decl.output); - } -} - -fn print_fn_block_args(s: ps, decl: ast::fn_decl) { - word(s.s, "|"); - fn print_arg(s: ps, x: ast::arg) { - ibox(s, indent_unit); - print_arg_mode(s, x.mode); - word(s.s, x.ident); - end(s); - } - commasep(s, inconsistent, decl.inputs, print_arg); - word(s.s, "|"); - if decl.output.node != ast::ty_infer { - space_if_not_bol(s); - word_space(s, "->"); - print_type(s, decl.output); - } - maybe_print_comment(s, decl.output.span.lo); -} - -fn mode_to_str(m: ast::mode) -> str { - alt m { - ast::expl(ast::by_mutbl_ref) { "&" } - ast::expl(ast::by_move) { "-" } - ast::expl(ast::by_ref) { "&&" } - ast::expl(ast::by_val) { "++" } - ast::expl(ast::by_copy) { "+" } - ast::infer(_) { "" } - } -} - -fn print_arg_mode(s: ps, m: ast::mode) { - let ms = mode_to_str(m); - if ms != "" { word(s.s, ms); } -} - -fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) { - if vec::len(*bounds) > 0u { - word(s.s, ":"); - for bound in *bounds { - nbsp(s); - alt bound { - ast::bound_copy { word(s.s, "copy"); } - ast::bound_send { word(s.s, "send"); } - ast::bound_iface(t) { print_type(s, t); } - } - } - } -} - -fn print_type_params(s: ps, &¶ms: [ast::ty_param]) { - if vec::len(params) > 0u { - word(s.s, "<"); - fn printParam(s: ps, param: ast::ty_param) { - word(s.s, param.ident); - print_bounds(s, param.bounds); - } - commasep(s, inconsistent, params, printParam); - word(s.s, ">"); - } -} - -fn print_meta_item(s: ps, &&item: @ast::meta_item) { - ibox(s, indent_unit); - alt item.node { - ast::meta_word(name) { word(s.s, name); } - ast::meta_name_value(name, value) { - word_space(s, name); - word_space(s, "="); - print_literal(s, @value); - } - ast::meta_list(name, items) { - word(s.s, name); - popen(s); - commasep(s, consistent, items, print_meta_item); - pclose(s); - } - } - end(s); -} - -fn print_simple_path(s: ps, path: ast::simple_path) { - let first = true; - for id in path { - if first { first = false; } else { word(s.s, "::"); } - word(s.s, id); - } -} - -fn print_view_path(s: ps, &&vp: @ast::view_path) { - alt vp.node { - ast::view_path_simple(ident, path, _) { - if path[vec::len(*path)-1u] != ident { - word_space(s, ident); - word_space(s, "="); - } - print_simple_path(s, *path); - } - - ast::view_path_glob(path, _) { - print_simple_path(s, *path); - word(s.s, "::*"); - } - - ast::view_path_list(path, idents, _) { - print_simple_path(s, *path); - word(s.s, "::{"); - commasep(s, inconsistent, idents) {|s, w| - word(s.s, w.node.name) - } - word(s.s, "}"); - } - } -} - -fn print_view_paths(s: ps, vps: [@ast::view_path]) { - commasep(s, inconsistent, vps, print_view_path); -} - -fn print_view_item(s: ps, item: @ast::view_item) { - hardbreak_if_not_bol(s); - maybe_print_comment(s, item.span.lo); - alt item.node { - ast::view_item_use(id, mta, _) { - head(s, "use"); - word(s.s, id); - if vec::len(mta) > 0u { - popen(s); - commasep(s, consistent, mta, print_meta_item); - pclose(s); - } - } - - ast::view_item_import(vps) { - head(s, "import"); - print_view_paths(s, vps); - } - - ast::view_item_export(vps) { - head(s, "export"); - print_view_paths(s, vps); - } - } - word(s.s, ";"); - end(s); // end inner head-block - end(s); // end outer head-block -} - - -// FIXME: The fact that this builds up the table anew for every call is -// not good. Eventually, table should be a const. -fn operator_prec(op: ast::binop) -> int { - for spec: parse::parser::op_spec in *parse::parser::prec_table() { - if spec.op == op { ret spec.prec; } - } - fail; -} - -fn need_parens(expr: @ast::expr, outer_prec: int) -> bool { - alt expr.node { - ast::expr_binary(op, _, _) { operator_prec(op) < outer_prec } - ast::expr_cast(_, _) { parse::parser::as_prec < outer_prec } - // This may be too conservative in some cases - ast::expr_assign(_, _) { true } - ast::expr_move(_, _) { true } - ast::expr_swap(_, _) { true } - ast::expr_assign_op(_, _, _) { true } - ast::expr_ret(_) { true } - ast::expr_be(_) { true } - ast::expr_assert(_) { true } - ast::expr_check(_, _) { true } - ast::expr_log(_, _, _) { true } - _ { !parse::parser::expr_requires_semi_to_be_stmt(expr) } - } -} - -fn print_op_maybe_parens(s: ps, expr: @ast::expr, outer_prec: int) { - let add_them = need_parens(expr, outer_prec); - if add_them { popen(s); } - print_expr(s, expr); - if add_them { pclose(s); } -} - -fn print_mutability(s: ps, mutbl: ast::mutability) { - alt mutbl { - ast::m_mutbl { word_nbsp(s, "mutable"); } - ast::m_const { word_nbsp(s, "const"); } - ast::m_imm {/* nothing */ } - } -} - -fn print_mt(s: ps, mt: ast::mt) { - print_mutability(s, mt.mutbl); - print_type(s, mt.ty); -} - -fn print_ty_fn(s: ps, opt_proto: option<ast::proto>, - decl: ast::fn_decl, id: option<ast::ident>, - tps: option<[ast::ty_param]>) { - ibox(s, indent_unit); - word(s.s, opt_proto_to_str(opt_proto)); - alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } } - alt tps { some(tps) { print_type_params(s, tps); } _ { } } - zerobreak(s.s); - popen(s); - fn print_arg(s: ps, input: ast::arg) { - print_arg_mode(s, input.mode); - if str::len(input.ident) > 0u { - word_space(s, input.ident + ":"); - } - print_type(s, input.ty); - } - commasep(s, inconsistent, decl.inputs, print_arg); - pclose(s); - maybe_print_comment(s, decl.output.span.lo); - if decl.output.node != ast::ty_nil { - space_if_not_bol(s); - ibox(s, indent_unit); - word_space(s, "->"); - if decl.cf == ast::noreturn { word_nbsp(s, "!"); } - else { print_type(s, decl.output); } - end(s); - } - word(s.s, constrs_str(decl.constraints, ast_ty_fn_constr_to_str)); - end(s); -} - -fn maybe_print_trailing_comment(s: ps, span: codemap::span, - next_pos: option<uint>) { - let cm; - alt s.cm { some(ccm) { cm = ccm; } _ { ret; } } - alt next_comment(s) { - some(cmnt) { - if cmnt.style != lexer::trailing { ret; } - let span_line = codemap::lookup_char_pos(cm, span.hi); - let comment_line = codemap::lookup_char_pos(cm, cmnt.pos); - let next = cmnt.pos + 1u; - alt next_pos { none { } some(p) { next = p; } } - if span.hi < cmnt.pos && cmnt.pos < next && - span_line.line == comment_line.line { - print_comment(s, cmnt); - s.cur_cmnt += 1u; - } - } - _ { } - } -} - -fn print_remaining_comments(s: ps) { - // If there aren't any remaining comments, then we need to manually - // make sure there is a line break at the end. - if option::is_none(next_comment(s)) { hardbreak(s.s); } - while true { - alt next_comment(s) { - some(cmnt) { print_comment(s, cmnt); s.cur_cmnt += 1u; } - _ { break; } - } - } -} - -fn in_cbox(s: ps) -> bool { - let len = vec::len(s.boxes); - if len == 0u { ret false; } - ret s.boxes[len - 1u] == pp::consistent; -} - -fn print_literal(s: ps, &&lit: @ast::lit) { - maybe_print_comment(s, lit.span.lo); - alt next_lit(s, lit.span.lo) { - some(lt) { - word(s.s, lt.lit); - ret; - } - _ {} - } - alt lit.node { - ast::lit_str(st) { print_string(s, st); } - ast::lit_int(ch, ast::ty_char) { - word(s.s, "'" + escape_str(str::from_char(ch as char), '\'') + "'"); - } - ast::lit_int(i, t) { - if i < 0_i64 { - word(s.s, - "-" + u64::to_str(-i as u64, 10u) - + ast_util::int_ty_to_str(t)); - } else { - word(s.s, - u64::to_str(i as u64, 10u) - + ast_util::int_ty_to_str(t)); - } - } - ast::lit_uint(u, t) { - word(s.s, - u64::to_str(u, 10u) - + ast_util::uint_ty_to_str(t)); - } - ast::lit_float(f, t) { - word(s.s, f + ast_util::float_ty_to_str(t)); - } - ast::lit_nil { word(s.s, "()"); } - ast::lit_bool(val) { - if val { word(s.s, "true"); } else { word(s.s, "false"); } - } - } -} - -fn lit_to_str(l: @ast::lit) -> str { be to_str(l, print_literal); } - -fn next_lit(s: ps, pos: uint) -> option<lexer::lit> { - alt s.literals { - some(lits) { - while s.cur_lit < vec::len(lits) { - let lt = lits[s.cur_lit]; - if lt.pos > pos { ret none; } - s.cur_lit += 1u; - if lt.pos == pos { ret some(lt); } - } - ret none; - } - _ { ret none; } - } -} - -fn maybe_print_comment(s: ps, pos: uint) { - while true { - alt next_comment(s) { - some(cmnt) { - if cmnt.pos < pos { - print_comment(s, cmnt); - s.cur_cmnt += 1u; - } else { break; } - } - _ { break; } - } - } -} - -fn print_comment(s: ps, cmnt: lexer::cmnt) { - alt cmnt.style { - lexer::mixed { - assert (vec::len(cmnt.lines) == 1u); - zerobreak(s.s); - word(s.s, cmnt.lines[0]); - zerobreak(s.s); - } - lexer::isolated { - pprust::hardbreak_if_not_bol(s); - for line: str in cmnt.lines { - // Don't print empty lines because they will end up as trailing - // whitespace - if str::is_not_empty(line) { word(s.s, line); } - hardbreak(s.s); - } - } - lexer::trailing { - word(s.s, " "); - if vec::len(cmnt.lines) == 1u { - word(s.s, cmnt.lines[0]); - hardbreak(s.s); - } else { - ibox(s, 0u); - for line: str in cmnt.lines { - if str::is_not_empty(line) { word(s.s, line); } - hardbreak(s.s); - } - end(s); - } - } - lexer::blank_line { - // We need to do at least one, possibly two hardbreaks. - let is_semi = - alt s.s.last_token() { - pp::STRING(s, _) { s == ";" } - _ { false } - }; - if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); } - hardbreak(s.s); - } - } -} - -fn print_string(s: ps, st: str) { - word(s.s, "\""); - word(s.s, escape_str(st, '"')); - word(s.s, "\""); -} - -fn escape_str(st: str, to_escape: char) -> str { - let out: str = ""; - let len = str::len(st); - let i = 0u; - while i < len { - alt st[i] as char { - '\n' { out += "\\n"; } - '\t' { out += "\\t"; } - '\r' { out += "\\r"; } - '\\' { out += "\\\\"; } - cur { - if cur == to_escape { out += "\\"; } - // FIXME some (or all?) non-ascii things should be escaped - - str::push_char(out, cur); - } - } - i += 1u; - } - ret out; -} - -fn to_str<T>(t: T, f: fn@(ps, T)) -> str { - let buffer = io::mk_mem_buffer(); - let s = rust_printer(io::mem_buffer_writer(buffer)); - f(s, t); - eof(s.s); - io::mem_buffer_str(buffer) -} - -fn next_comment(s: ps) -> option<lexer::cmnt> { - alt s.comments { - some(cmnts) { - if s.cur_cmnt < vec::len(cmnts) { - ret some(cmnts[s.cur_cmnt]); - } else { ret none::<lexer::cmnt>; } - } - _ { ret none::<lexer::cmnt>; } - } -} - -fn constr_args_to_str<T>(f: fn@(T) -> str, args: [@ast::sp_constr_arg<T>]) -> - str { - let comma = false; - let s = "("; - for a: @ast::sp_constr_arg<T> in args { - if comma { s += ", "; } else { comma = true; } - s += constr_arg_to_str::<T>(f, a.node); - } - s += ")"; - ret s; -} - -fn constr_arg_to_str<T>(f: fn@(T) -> str, c: ast::constr_arg_general_<T>) -> - str { - alt c { - ast::carg_base { ret "*"; } - ast::carg_ident(i) { ret f(i); } - ast::carg_lit(l) { ret lit_to_str(l); } - } -} - -// needed b/c constr_args_to_str needs -// something that takes an alias -// (argh) -fn uint_to_str(&&i: uint) -> str { ret uint::str(i); } - -fn ast_ty_fn_constr_to_str(&&c: @ast::constr) -> str { - ret path_to_str(c.node.path) + - constr_args_to_str(uint_to_str, c.node.args); -} - -fn ast_fn_constr_to_str(decl: ast::fn_decl, &&c: @ast::constr) -> str { - let arg_to_str = bind fn_arg_idx_to_str(decl, _); - ret path_to_str(c.node.path) + - constr_args_to_str(arg_to_str, c.node.args); -} - -fn ty_constr_to_str(&&c: @ast::ty_constr) -> str { - fn ty_constr_path_to_str(&&p: @ast::path) -> str { "*." + path_to_str(p) } - - ret path_to_str(c.node.path) + - constr_args_to_str::<@ast::path>(ty_constr_path_to_str, - c.node.args); -} - -fn constrs_str<T>(constrs: [T], elt: fn(T) -> str) -> str { - let s = "", colon = true; - for c in constrs { - if colon { s += " : "; colon = false; } else { s += ", "; } - s += elt(c); - } - ret s; -} - -fn fn_arg_idx_to_str(decl: ast::fn_decl, &&idx: uint) -> str { - decl.inputs[idx].ident -} - -fn opt_proto_to_str(opt_p: option<ast::proto>) -> str { - alt opt_p { - none { "fn" } - some(p) { proto_to_str(p) } - } -} - -fn proto_to_str(p: ast::proto) -> str { - ret alt p { - ast::proto_bare { "native fn" } - ast::proto_any { "fn" } - ast::proto_block { "fn&" } - ast::proto_uniq { "fn~" } - ast::proto_box { "fn@" } - }; -} - -fn ends_in_lit_int(ex: @ast::expr) -> bool { - alt ex.node { - ast::expr_lit(@{node: ast::lit_int(_, ast::ty_i), _}) { true } - ast::expr_binary(_, _, sub) | ast::expr_unary(_, sub) | - ast::expr_move(_, sub) | ast::expr_copy(sub) | - ast::expr_assign(_, sub) | ast::expr_be(sub) | - ast::expr_assign_op(_, _, sub) | ast::expr_swap(_, sub) | - ast::expr_log(_, _, sub) | ast::expr_assert(sub) | - ast::expr_check(_, sub) { ends_in_lit_int(sub) } - ast::expr_fail(osub) | ast::expr_ret(osub) { - alt osub { - some(ex) { ends_in_lit_int(ex) } - _ { false } - } - } - _ { false } - } -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/syntax/util/interner.rs b/src/comp/syntax/util/interner.rs deleted file mode 100644 index c7f0d7ecb99..00000000000 --- a/src/comp/syntax/util/interner.rs +++ /dev/null @@ -1,39 +0,0 @@ -// An "interner" is a data structure that associates values with uint tags and -// allows bidirectional lookup; i.e. given a value, one can easily find the -// type, and vice versa. -import std::map; -import std::map::{hashmap, hashfn, eqfn}; - -type interner<T> = - {map: hashmap<T, uint>, - mutable vect: [T], - hasher: hashfn<T>, - eqer: eqfn<T>}; - -fn mk<T: copy>(hasher: hashfn<T>, eqer: eqfn<T>) -> interner<T> { - let m = map::mk_hashmap::<T, uint>(hasher, eqer); - ret {map: m, mutable vect: [], hasher: hasher, eqer: eqer}; -} - -fn intern<T: copy>(itr: interner<T>, val: T) -> uint { - alt itr.map.find(val) { - some(idx) { ret idx; } - none { - let new_idx = vec::len::<T>(itr.vect); - itr.map.insert(val, new_idx); - itr.vect += [val]; - ret new_idx; - } - } -} - -// |get| isn't "pure" in the traditional sense, because it can go from -// failing to returning a value as items are interned. But for typestate, -// where we first check a pred and then rely on it, ceasing to fail is ok. -pure fn get<T: copy>(itr: interner<T>, idx: uint) -> T { - unchecked { - itr.vect[idx] - } -} - -fn len<T>(itr: interner<T>) -> uint { ret vec::len(itr.vect); } diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs deleted file mode 100644 index 55958abd7af..00000000000 --- a/src/comp/syntax/visit.rs +++ /dev/null @@ -1,546 +0,0 @@ - -import ast::*; -import codemap::span; - -// Context-passing AST walker. Each overridden visit method has full control -// over what happens with its node, it can do its own traversal of the node's -// children (potentially passing in different contexts to each), call -// visit::visit_* to apply the default traversal algorithm (again, it can -// override the context), or prevent deeper traversal by doing nothing. - -// Our typesystem doesn't do circular types, so the visitor record can not -// hold functions that take visitors. A vt enum is used to break the cycle. -enum vt<E> { mk_vt(visitor<E>), } - -enum fn_kind { - fk_item_fn(ident, [ty_param]), //< an item declared with fn() - fk_method(ident, [ty_param]), - fk_res(ident, [ty_param]), - fk_anon(proto), //< an anonymous function like fn@(...) - fk_fn_block, //< a block {||...} -} - -fn name_of_fn(fk: fn_kind) -> ident { - alt fk { - fk_item_fn(name, _) | fk_method(name, _) | fk_res(name, _) { name } - fk_anon(_) | fk_fn_block { "anon" } - } -} - -fn tps_of_fn(fk: fn_kind) -> [ty_param] { - alt fk { - fk_item_fn(_, tps) | fk_method(_, tps) | fk_res(_, tps) { tps } - fk_anon(_) | fk_fn_block { [] } - } -} - -type visitor<E> = - // takes the components so that one function can be - // generic over constr and ty_constr - @{visit_mod: fn@(_mod, span, node_id, E, vt<E>), - visit_view_item: fn@(@view_item, E, vt<E>), - visit_native_item: fn@(@native_item, E, vt<E>), - visit_item: fn@(@item, E, vt<E>), - visit_local: fn@(@local, E, vt<E>), - visit_block: fn@(ast::blk, E, vt<E>), - visit_stmt: fn@(@stmt, E, vt<E>), - visit_arm: fn@(arm, E, vt<E>), - visit_pat: fn@(@pat, E, vt<E>), - visit_decl: fn@(@decl, E, vt<E>), - visit_expr: fn@(@expr, E, vt<E>), - visit_ty: fn@(@ty, E, vt<E>), - visit_ty_params: fn@([ty_param], E, vt<E>), - visit_constr: fn@(@path, span, node_id, E, vt<E>), - visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>), - visit_class_item: fn@(span, privacy, class_member, E, vt<E>)}; - -fn default_visitor<E>() -> visitor<E> { - ret @{visit_mod: bind visit_mod::<E>(_, _, _, _, _), - visit_view_item: bind visit_view_item::<E>(_, _, _), - visit_native_item: bind visit_native_item::<E>(_, _, _), - visit_item: bind visit_item::<E>(_, _, _), - visit_local: bind visit_local::<E>(_, _, _), - visit_block: bind visit_block::<E>(_, _, _), - visit_stmt: bind visit_stmt::<E>(_, _, _), - visit_arm: bind visit_arm::<E>(_, _, _), - visit_pat: bind visit_pat::<E>(_, _, _), - visit_decl: bind visit_decl::<E>(_, _, _), - visit_expr: bind visit_expr::<E>(_, _, _), - visit_ty: bind skip_ty::<E>(_, _, _), - visit_ty_params: bind visit_ty_params::<E>(_, _, _), - visit_constr: bind visit_constr::<E>(_, _, _, _, _), - visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _), - visit_class_item: bind visit_class_item::<E>(_,_,_,_,_)}; -} - -fn visit_crate<E>(c: crate, e: E, v: vt<E>) { - v.visit_mod(c.node.module, c.span, crate_node_id, e, v); -} - -fn visit_crate_directive<E>(cd: @crate_directive, e: E, v: vt<E>) { - alt cd.node { - cdir_src_mod(_, _) { } - cdir_dir_mod(_, cdirs, _) { - for cdir: @crate_directive in cdirs { - visit_crate_directive(cdir, e, v); - } - } - cdir_view_item(vi) { v.visit_view_item(vi, e, v); } - cdir_syntax(_) { } - } -} - -fn visit_mod<E>(m: _mod, _sp: span, _id: node_id, e: E, v: vt<E>) { - for vi: @view_item in m.view_items { v.visit_view_item(vi, e, v); } - for i: @item in m.items { v.visit_item(i, e, v); } -} - -fn visit_view_item<E>(_vi: @view_item, _e: E, _v: vt<E>) { } - -fn visit_local<E>(loc: @local, e: E, v: vt<E>) { - v.visit_pat(loc.node.pat, e, v); - v.visit_ty(loc.node.ty, e, v); - alt loc.node.init { none { } some(i) { v.visit_expr(i.expr, e, v); } } -} - -fn visit_item<E>(i: @item, e: E, v: vt<E>) { - alt i.node { - item_const(t, ex) { v.visit_ty(t, e, v); v.visit_expr(ex, e, v); } - item_fn(decl, tp, body) { - v.visit_fn(fk_item_fn(i.ident, tp), decl, body, i.span, i.id, e, v); - } - item_mod(m) { v.visit_mod(m, i.span, i.id, e, v); } - item_native_mod(nm) { - for vi: @view_item in nm.view_items { v.visit_view_item(vi, e, v); } - for ni: @native_item in nm.items { v.visit_native_item(ni, e, v); } - } - item_ty(t, tps) { v.visit_ty(t, e, v); v.visit_ty_params(tps, e, v); } - item_res(decl, tps, body, dtor_id, _) { - v.visit_fn(fk_res(i.ident, tps), decl, body, i.span, - dtor_id, e, v); - } - item_enum(variants, tps) { - v.visit_ty_params(tps, e, v); - for vr: variant in variants { - for va: variant_arg in vr.node.args { v.visit_ty(va.ty, e, v); } - } - } - item_impl(tps, ifce, ty, methods) { - v.visit_ty_params(tps, e, v); - alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} } - v.visit_ty(ty, e, v); - for m in methods { - visit_method_helper(m, e, v) - } - } - item_class(tps, members, _, ctor_decl, ctor_blk) { - v.visit_ty_params(tps, e, v); - for m in members { - v.visit_class_item(m.span, m.node.privacy, m.node.decl, e, v); - } - visit_fn_decl(ctor_decl, e, v); - v.visit_block(ctor_blk, e, v); - } - item_iface(tps, methods) { - v.visit_ty_params(tps, e, v); - for m in methods { - for a in m.decl.inputs { v.visit_ty(a.ty, e, v); } - v.visit_ty(m.decl.output, e, v); - } - } - } -} - -fn visit_class_item<E>(_s: span, _p: privacy, cm: class_member, - e:E, v:vt<E>) { - alt cm { - instance_var(ident, t, mt, id) { - v.visit_ty(t, e, v); - } - class_method(i) { - v.visit_item(i, e, v); - } - } -} - -fn skip_ty<E>(_t: @ty, _e: E, _v: vt<E>) {} - -fn visit_ty<E>(t: @ty, e: E, v: vt<E>) { - alt t.node { - ty_box(mt) { v.visit_ty(mt.ty, e, v); } - ty_uniq(mt) { v.visit_ty(mt.ty, e, v); } - ty_vec(mt) { v.visit_ty(mt.ty, e, v); } - ty_ptr(mt) { v.visit_ty(mt.ty, e, v); } - ty_rec(flds) { - for f: ty_field in flds { v.visit_ty(f.node.mt.ty, e, v); } - } - ty_tup(ts) { for tt in ts { v.visit_ty(tt, e, v); } } - ty_fn(_, decl) { - for a in decl.inputs { v.visit_ty(a.ty, e, v); } - for c: @constr in decl.constraints { - v.visit_constr(c.node.path, c.span, c.node.id, e, v); - } - v.visit_ty(decl.output, e, v); - } - ty_path(p, _) { visit_path(p, e, v); } - ty_constr(t, cs) { - v.visit_ty(t, e, v); - for tc: @spanned<constr_general_<@path, node_id>> in cs { - v.visit_constr(tc.node.path, tc.span, tc.node.id, e, v); - } - } - _ {} - } -} - -fn visit_constr<E>(_operator: @path, _sp: span, _id: node_id, _e: E, - _v: vt<E>) { - // default -} - -fn visit_path<E>(p: @path, e: E, v: vt<E>) { - for tp: @ty in p.node.types { v.visit_ty(tp, e, v); } -} - -fn visit_pat<E>(p: @pat, e: E, v: vt<E>) { - alt p.node { - pat_enum(path, children) { - visit_path(path, e, v); - for child: @pat in children { v.visit_pat(child, e, v); } - } - pat_rec(fields, _) { - for f: field_pat in fields { v.visit_pat(f.pat, e, v); } - } - pat_tup(elts) { for elt in elts { v.visit_pat(elt, e, v); } } - pat_box(inner) | pat_uniq(inner) { - v.visit_pat(inner, e, v); - } - pat_ident(path, inner) { - visit_path(path, e, v); - option::may(inner, {|subpat| v.visit_pat(subpat, e, v)}); - } - _ { } - } -} - -fn visit_native_item<E>(ni: @native_item, e: E, v: vt<E>) { - alt ni.node { - native_item_fn(fd, tps) { - v.visit_ty_params(tps, e, v); - visit_fn_decl(fd, e, v); - } - } -} - -fn visit_ty_params<E>(tps: [ty_param], e: E, v: vt<E>) { - for tp in tps { - for bound in *tp.bounds { - alt bound { - bound_iface(t) { v.visit_ty(t, e, v); } - _ {} - } - } - } -} - -fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) { - for a: arg in fd.inputs { v.visit_ty(a.ty, e, v); } - for c: @constr in fd.constraints { - v.visit_constr(c.node.path, c.span, c.node.id, e, v); - } - v.visit_ty(fd.output, e, v); -} - -// Note: there is no visit_method() method in the visitor, instead override -// visit_fn() and check for fk_method(). I named this visit_method_helper() -// because it is not a default impl of any method, though I doubt that really -// clarifies anything. - Niko -fn visit_method_helper<E>(m: @method, e: E, v: vt<E>) { - v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span, - m.id, e, v); -} - -fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span, - _id: node_id, e: E, v: vt<E>) { - visit_fn_decl(decl, e, v); - v.visit_ty_params(tps_of_fn(fk), e, v); - v.visit_block(body, e, v); -} - -fn visit_block<E>(b: ast::blk, e: E, v: vt<E>) { - for vi in b.node.view_items { v.visit_view_item(vi, e, v); } - for s in b.node.stmts { v.visit_stmt(s, e, v); } - visit_expr_opt(b.node.expr, e, v); -} - -fn visit_stmt<E>(s: @stmt, e: E, v: vt<E>) { - alt s.node { - stmt_decl(d, _) { v.visit_decl(d, e, v); } - stmt_expr(ex, _) { v.visit_expr(ex, e, v); } - stmt_semi(ex, _) { v.visit_expr(ex, e, v); } - } -} - -fn visit_decl<E>(d: @decl, e: E, v: vt<E>) { - alt d.node { - decl_local(locs) { - for loc in locs { v.visit_local(loc, e, v); } - } - decl_item(it) { v.visit_item(it, e, v); } - } -} - -fn visit_expr_opt<E>(eo: option<@expr>, e: E, v: vt<E>) { - alt eo { none { } some(ex) { v.visit_expr(ex, e, v); } } -} - -fn visit_exprs<E>(exprs: [@expr], e: E, v: vt<E>) { - for ex: @expr in exprs { v.visit_expr(ex, e, v); } -} - -fn visit_mac<E>(m: mac, e: E, v: vt<E>) { - alt m.node { - ast::mac_invoc(pth, arg, body) { - option::map(arg) {|arg| visit_expr(arg, e, v)}; } - ast::mac_embed_type(ty) { v.visit_ty(ty, e, v); } - ast::mac_embed_block(blk) { v.visit_block(blk, e, v); } - ast::mac_ellipsis { } - ast::mac_aq(_, e) { /* FIXME: maybe visit */ } - ast::mac_var(_) { } - } -} - -fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) { - alt ex.node { - expr_vec(es, _) { visit_exprs(es, e, v); } - expr_rec(flds, base) { - for f: field in flds { v.visit_expr(f.node.expr, e, v); } - visit_expr_opt(base, e, v); - } - expr_tup(elts) { for el in elts { v.visit_expr(el, e, v); } } - expr_call(callee, args, _) { - visit_exprs(args, e, v); - v.visit_expr(callee, e, v); - } - expr_bind(callee, args) { - v.visit_expr(callee, e, v); - for eo: option<@expr> in args { visit_expr_opt(eo, e, v); } - } - expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); } - expr_unary(_, a) { v.visit_expr(a, e, v); } - expr_lit(_) { } - expr_cast(x, t) { v.visit_expr(x, e, v); v.visit_ty(t, e, v); } - expr_if(x, b, eo) { - v.visit_expr(x, e, v); - v.visit_block(b, e, v); - visit_expr_opt(eo, e, v); - } - expr_if_check(x, b, eo) { - v.visit_expr(x, e, v); - v.visit_block(b, e, v); - visit_expr_opt(eo, e, v); - } - expr_while(x, b) { v.visit_expr(x, e, v); v.visit_block(b, e, v); } - expr_for(dcl, x, b) { - v.visit_local(dcl, e, v); - v.visit_expr(x, e, v); - v.visit_block(b, e, v); - } - expr_do_while(b, x) { v.visit_block(b, e, v); v.visit_expr(x, e, v); } - expr_alt(x, arms, _) { - v.visit_expr(x, e, v); - for a: arm in arms { v.visit_arm(a, e, v); } - } - expr_fn(proto, decl, body, _) { - v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v); - } - expr_fn_block(decl, body) { - v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v); - } - expr_block(b) { v.visit_block(b, e, v); } - expr_assign(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); } - expr_copy(a) { v.visit_expr(a, e, v); } - expr_move(a, b) { v.visit_expr(b, e, v); v.visit_expr(a, e, v); } - expr_swap(a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); } - expr_assign_op(_, a, b) { - v.visit_expr(b, e, v); - v.visit_expr(a, e, v); - } - expr_field(x, _, tys) { - v.visit_expr(x, e, v); - for tp in tys { v.visit_ty(tp, e, v); } - } - expr_index(a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); } - expr_path(p) { visit_path(p, e, v); } - expr_fail(eo) { visit_expr_opt(eo, e, v); } - expr_break { } - expr_cont { } - expr_ret(eo) { visit_expr_opt(eo, e, v); } - expr_be(x) { v.visit_expr(x, e, v); } - expr_log(_, lv, x) { - v.visit_expr(lv, e, v); - v.visit_expr(x, e, v); - } - expr_check(_, x) { v.visit_expr(x, e, v); } - expr_assert(x) { v.visit_expr(x, e, v); } - expr_mac(mac) { visit_mac(mac, e, v); } - } -} - -fn visit_arm<E>(a: arm, e: E, v: vt<E>) { - for p: @pat in a.pats { v.visit_pat(p, e, v); } - visit_expr_opt(a.guard, e, v); - v.visit_block(a.body, e, v); -} - -// Simpler, non-context passing interface. Always walks the whole tree, simply -// calls the given functions on the nodes. - -type simple_visitor = - // takes the components so that one function can be - // generic over constr and ty_constr - @{visit_mod: fn@(_mod, span, node_id), - visit_view_item: fn@(@view_item), - visit_native_item: fn@(@native_item), - visit_item: fn@(@item), - visit_local: fn@(@local), - visit_block: fn@(ast::blk), - visit_stmt: fn@(@stmt), - visit_arm: fn@(arm), - visit_pat: fn@(@pat), - visit_decl: fn@(@decl), - visit_expr: fn@(@expr), - visit_ty: fn@(@ty), - visit_ty_params: fn@([ty_param]), - visit_constr: fn@(@path, span, node_id), - visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id), - visit_class_item: fn@(span, privacy, class_member)}; - -fn simple_ignore_ty(_t: @ty) {} - -fn default_simple_visitor() -> simple_visitor { - ret @{visit_mod: fn@(_m: _mod, _sp: span, _id: node_id) { }, - visit_view_item: fn@(_vi: @view_item) { }, - visit_native_item: fn@(_ni: @native_item) { }, - visit_item: fn@(_i: @item) { }, - visit_local: fn@(_l: @local) { }, - visit_block: fn@(_b: ast::blk) { }, - visit_stmt: fn@(_s: @stmt) { }, - visit_arm: fn@(_a: arm) { }, - visit_pat: fn@(_p: @pat) { }, - visit_decl: fn@(_d: @decl) { }, - visit_expr: fn@(_e: @expr) { }, - visit_ty: simple_ignore_ty, - visit_ty_params: fn@(_ps: [ty_param]) {}, - visit_constr: fn@(_p: @path, _sp: span, _id: node_id) { }, - visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span, - _id: node_id) { }, - visit_class_item: fn@(_s: span, _p: privacy, _c: class_member) {} - }; -} - -fn mk_simple_visitor(v: simple_visitor) -> vt<()> { - fn v_mod(f: fn@(_mod, span, node_id), m: _mod, sp: span, id: node_id, - &&e: (), v: vt<()>) { - f(m, sp, id); - visit_mod(m, sp, id, e, v); - } - fn v_view_item(f: fn@(@view_item), vi: @view_item, &&e: (), v: vt<()>) { - f(vi); - visit_view_item(vi, e, v); - } - fn v_native_item(f: fn@(@native_item), ni: @native_item, &&e: (), - v: vt<()>) { - f(ni); - visit_native_item(ni, e, v); - } - fn v_item(f: fn@(@item), i: @item, &&e: (), v: vt<()>) { - f(i); - visit_item(i, e, v); - } - fn v_local(f: fn@(@local), l: @local, &&e: (), v: vt<()>) { - f(l); - visit_local(l, e, v); - } - fn v_block(f: fn@(ast::blk), bl: ast::blk, &&e: (), v: vt<()>) { - f(bl); - visit_block(bl, e, v); - } - fn v_stmt(f: fn@(@stmt), st: @stmt, &&e: (), v: vt<()>) { - f(st); - visit_stmt(st, e, v); - } - fn v_arm(f: fn@(arm), a: arm, &&e: (), v: vt<()>) { - f(a); - visit_arm(a, e, v); - } - fn v_pat(f: fn@(@pat), p: @pat, &&e: (), v: vt<()>) { - f(p); - visit_pat(p, e, v); - } - fn v_decl(f: fn@(@decl), d: @decl, &&e: (), v: vt<()>) { - f(d); - visit_decl(d, e, v); - } - fn v_expr(f: fn@(@expr), ex: @expr, &&e: (), v: vt<()>) { - f(ex); - visit_expr(ex, e, v); - } - fn v_ty(f: fn@(@ty), ty: @ty, &&e: (), v: vt<()>) { - f(ty); - visit_ty(ty, e, v); - } - fn v_ty_params(f: fn@([ty_param]), ps: [ty_param], &&e: (), v: vt<()>) { - f(ps); - visit_ty_params(ps, e, v); - } - fn v_constr(f: fn@(@path, span, node_id), pt: @path, sp: span, - id: node_id, &&e: (), v: vt<()>) { - f(pt, sp, id); - visit_constr(pt, sp, id, e, v); - } - fn v_fn(f: fn@(fn_kind, fn_decl, blk, span, node_id), - fk: fn_kind, decl: fn_decl, body: blk, sp: span, - id: node_id, &&e: (), v: vt<()>) { - f(fk, decl, body, sp, id); - visit_fn(fk, decl, body, sp, id, e, v); - } - let visit_ty = if v.visit_ty == simple_ignore_ty { - bind skip_ty(_, _, _) - } else { - bind v_ty(v.visit_ty, _, _, _) - }; - fn v_class_item(f: fn@(span, privacy, class_member), - s:span, p:privacy, cm: class_member, &&e: (), - v: vt<()>) { - f(s, p, cm); - visit_class_item(s, p, cm, e, v); - } - ret mk_vt(@{visit_mod: bind v_mod(v.visit_mod, _, _, _, _, _), - visit_view_item: bind v_view_item(v.visit_view_item, _, _, _), - visit_native_item: - bind v_native_item(v.visit_native_item, _, _, _), - visit_item: bind v_item(v.visit_item, _, _, _), - visit_local: bind v_local(v.visit_local, _, _, _), - visit_block: bind v_block(v.visit_block, _, _, _), - visit_stmt: bind v_stmt(v.visit_stmt, _, _, _), - visit_arm: bind v_arm(v.visit_arm, _, _, _), - visit_pat: bind v_pat(v.visit_pat, _, _, _), - visit_decl: bind v_decl(v.visit_decl, _, _, _), - visit_expr: bind v_expr(v.visit_expr, _, _, _), - visit_ty: visit_ty, - visit_ty_params: bind v_ty_params(v.visit_ty_params, _, _, _), - visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _), - visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _), - visit_class_item: bind v_class_item(v.visit_class_item, _, _, - _, _, _) - }); -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs deleted file mode 100644 index 87a1f6145d6..00000000000 --- a/src/comp/util/common.rs +++ /dev/null @@ -1,103 +0,0 @@ -import math::{max, min}; -import std::map::hashmap; -import syntax::ast; -import ast::{ty, pat}; -import syntax::codemap::{span}; -import syntax::visit; -import syntax::print; - -type flag = hashmap<str, ()>; - -fn def_eq(a: ast::def_id, b: ast::def_id) -> bool { - ret a.crate == b.crate && a.node == b.node; -} - -fn hash_def(d: ast::def_id) -> uint { - let h = 5381u; - h = (h << 5u) + h ^ (d.crate as uint); - h = (h << 5u) + h ^ (d.node as uint); - ret h; -} - -fn new_def_hash<V: copy>() -> std::map::hashmap<ast::def_id, V> { - let hasher: std::map::hashfn<ast::def_id> = hash_def; - let eqer: std::map::eqfn<ast::def_id> = def_eq; - ret std::map::mk_hashmap::<ast::def_id, V>(hasher, eqer); -} - -fn field_expr(f: ast::field) -> @ast::expr { ret f.node.expr; } - -fn field_exprs(fields: [ast::field]) -> [@ast::expr] { - let es = []; - for f: ast::field in fields { es += [f.node.expr]; } - ret es; -} - -fn log_expr(e: ast::expr) { - log(debug, print::pprust::expr_to_str(@e)); -} - -fn log_expr_err(e: ast::expr) { - log(error, print::pprust::expr_to_str(@e)); -} - -fn log_ty_err(t: @ty) { - log(error, print::pprust::ty_to_str(t)); -} - -fn log_pat_err(p: @pat) { - log(error, print::pprust::pat_to_str(p)); -} - -fn log_block(b: ast::blk) { - log(debug, print::pprust::block_to_str(b)); -} - -fn log_block_err(b: ast::blk) { - log(error, print::pprust::block_to_str(b)); -} - -fn log_item_err(i: @ast::item) { - log(error, print::pprust::item_to_str(i)); -} -fn log_stmt(st: ast::stmt) { - log(debug, print::pprust::stmt_to_str(st)); -} - -fn log_stmt_err(st: ast::stmt) { - log(error, print::pprust::stmt_to_str(st)); -} - -fn has_nonlocal_exits(b: ast::blk) -> bool { - let has_exits = @mutable false; - fn visit_expr(flag: @mutable bool, e: @ast::expr) { - alt e.node { - ast::expr_break { *flag = true; } - ast::expr_cont { *flag = true; } - _ { } - } - } - let v = - visit::mk_simple_visitor(@{visit_expr: bind visit_expr(has_exits, _) - with *visit::default_simple_visitor()}); - visit::visit_block(b, (), v); - ret *has_exits; -} - -fn local_rhs_span(l: @ast::local, def: span) -> span { - alt l.node.init { some(i) { ret i.expr.span; } _ { ret def; } } -} - -fn is_main_name(path: middle::ast_map::path) -> bool { - option::get(vec::last(path)) == middle::ast_map::path_name("main") -} - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/comp/util/filesearch.rs b/src/comp/util/filesearch.rs deleted file mode 100644 index 3e23e09f8ea..00000000000 --- a/src/comp/util/filesearch.rs +++ /dev/null @@ -1,174 +0,0 @@ -// A module for searching for libraries -// FIXME: I'm not happy how this module turned out. Should probably -// just be folded into cstore. - -import std::{fs, os, generic_os}; - -export filesearch; -export mk_filesearch; -export pick; -export pick_file; -export search; -export relative_target_lib_path; -export get_cargo_sysroot; -export get_cargo_root; -export get_cargo_root_nearest; -export libdir; - -type pick<T> = fn(path: fs::path) -> option<T>; - -fn pick_file(file: fs::path, path: fs::path) -> option<fs::path> { - if fs::basename(path) == file { option::some(path) } - else { option::none } -} - -iface filesearch { - fn sysroot() -> fs::path; - fn lib_search_paths() -> [fs::path]; - fn get_target_lib_path() -> fs::path; - fn get_target_lib_file_path(file: fs::path) -> fs::path; -} - -fn mk_filesearch(maybe_sysroot: option<fs::path>, - target_triple: str, - addl_lib_search_paths: [fs::path]) -> filesearch { - type filesearch_impl = {sysroot: fs::path, - addl_lib_search_paths: [fs::path], - target_triple: str}; - impl of filesearch for filesearch_impl { - fn sysroot() -> fs::path { self.sysroot } - fn lib_search_paths() -> [fs::path] { - self.addl_lib_search_paths - + [make_target_lib_path(self.sysroot, self.target_triple)] - + alt get_cargo_lib_path_nearest() { - result::ok(p) { [p] } - result::err(p) { [] } - } - + alt get_cargo_lib_path() { - result::ok(p) { [p] } - result::err(p) { [] } - } - } - fn get_target_lib_path() -> fs::path { - make_target_lib_path(self.sysroot, self.target_triple) - } - fn get_target_lib_file_path(file: fs::path) -> fs::path { - fs::connect(self.get_target_lib_path(), file) - } - } - - let sysroot = get_sysroot(maybe_sysroot); - #debug("using sysroot = %s", sysroot); - {sysroot: sysroot, - addl_lib_search_paths: addl_lib_search_paths, - target_triple: target_triple} as filesearch -} - -// FIXME #1001: This can't be an obj method -fn search<T: copy>(filesearch: filesearch, pick: pick<T>) -> option<T> { - for lib_search_path in filesearch.lib_search_paths() { - #debug("searching %s", lib_search_path); - for path in fs::list_dir(lib_search_path) { - #debug("testing %s", path); - let maybe_picked = pick(path); - if option::is_some(maybe_picked) { - #debug("picked %s", path); - ret maybe_picked; - } else { - #debug("rejected %s", path); - } - } - } - ret option::none; -} - -fn relative_target_lib_path(target_triple: str) -> [fs::path] { - [libdir(), "rustc", target_triple, libdir()] -} - -fn make_target_lib_path(sysroot: fs::path, - target_triple: str) -> fs::path { - let path = [sysroot] + relative_target_lib_path(target_triple); - let path = fs::connect_many(path); - ret path; -} - -fn get_default_sysroot() -> fs::path { - alt os::get_exe_path() { - option::some(p) { fs::normalize(fs::connect(p, "..")) } - option::none { - fail "can't determine value for sysroot"; - } - } -} - -fn get_sysroot(maybe_sysroot: option<fs::path>) -> fs::path { - alt maybe_sysroot { - option::some(sr) { sr } - option::none { get_default_sysroot() } - } -} - -fn get_cargo_sysroot() -> result::t<fs::path, str> { - let path = [get_default_sysroot(), libdir(), "cargo"]; - result::ok(fs::connect_many(path)) -} - -fn get_cargo_root() -> result::t<fs::path, str> { - alt generic_os::getenv("CARGO_ROOT") { - some(_p) { result::ok(_p) } - none { - alt fs::homedir() { - some(_q) { result::ok(fs::connect(_q, ".cargo")) } - none { result::err("no CARGO_ROOT or home directory") } - } - } - } -} - -fn get_cargo_root_nearest() -> result::t<fs::path, str> { - result::chain(get_cargo_root()) { |p| - let cwd = os::getcwd(); - let dirname = fs::dirname(cwd); - let dirpath = fs::split(dirname); - let cwd_cargo = fs::connect(cwd, ".cargo"); - let par_cargo = fs::connect(dirname, ".cargo"); - - if fs::path_is_dir(cwd_cargo) || cwd_cargo == p { - ret result::ok(cwd_cargo); - } - - while vec::is_not_empty(dirpath) && par_cargo != p { - if fs::path_is_dir(par_cargo) { - ret result::ok(par_cargo); - } - vec::pop(dirpath); - dirname = fs::dirname(dirname); - par_cargo = fs::connect(dirname, ".cargo"); - } - - result::ok(cwd_cargo) - } -} - -fn get_cargo_lib_path() -> result::t<fs::path, str> { - result::chain(get_cargo_root()) { |p| - result::ok(fs::connect(p, libdir())) - } -} - -fn get_cargo_lib_path_nearest() -> result::t<fs::path, str> { - result::chain(get_cargo_root_nearest()) { |p| - result::ok(fs::connect(p, libdir())) - } -} - -// The name of the directory rustc expects libraries to be located. -// On Unix should be "lib", on windows "bin" -fn libdir() -> str { - let libdir = #env("CFG_LIBDIR"); - if str::is_empty(libdir) { - fail "rustc compiled without CFG_LIBDIR environment variable"; - } - libdir -} diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs deleted file mode 100644 index 0ed630629b7..00000000000 --- a/src/comp/util/ppaux.rs +++ /dev/null @@ -1,165 +0,0 @@ -import middle::ty; -import middle::ty::*; -import metadata::encoder; -import syntax::print::pprust; -import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str, - mode_to_str}; -import syntax::{ast, ast_util}; -import middle::ast_map; -import driver::session::session; - -fn ty_to_str(cx: ctxt, typ: t) -> str { - fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) -> - str { - let {mode, ty} = input; - let modestr = alt canon_mode(cx, mode) { - ast::infer(_) { "" } - ast::expl(m) { - if !ty::type_has_vars(ty) && - m == ty::default_arg_mode_for_ty(ty) { - "" - } else { - mode_to_str(ast::expl(m)) - } - } - }; - modestr + ty_to_str(cx, ty) - } - fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option<ast::ident>, - inputs: [arg], output: t, cf: ast::ret_style, - constrs: [@constr]) -> str { - let s = proto_to_str(proto); - alt ident { some(i) { s += " "; s += i; } _ { } } - s += "("; - let strs = []; - for a: arg in inputs { strs += [fn_input_to_str(cx, a)]; } - s += str::connect(strs, ", "); - s += ")"; - if ty::get(output).struct != ty_nil { - s += " -> "; - alt cf { - ast::noreturn { s += "!"; } - ast::return_val { s += ty_to_str(cx, output); } - } - } - s += constrs_str(constrs); - ret s; - } - fn method_to_str(cx: ctxt, m: method) -> str { - ret fn_to_str(cx, m.fty.proto, some(m.ident), m.fty.inputs, - m.fty.output, m.fty.ret_style, m.fty.constraints) + ";"; - } - fn field_to_str(cx: ctxt, f: field) -> str { - ret f.ident + ": " + mt_to_str(cx, f.mt); - } - fn mt_to_str(cx: ctxt, m: mt) -> str { - let mstr = alt m.mutbl { - ast::m_mutbl { "mut " } - ast::m_imm { "" } - ast::m_const { "const " } - }; - ret mstr + ty_to_str(cx, m.ty); - } - fn parameterized(cx: ctxt, base: str, tps: [ty::t]) -> str { - if vec::len(tps) > 0u { - let strs = vec::map(tps, {|t| ty_to_str(cx, t)}); - #fmt["%s<%s>", base, str::connect(strs, ",")] - } else { - base - } - } - - // if there is an id, print that instead of the structural type: - alt ty::type_def_id(typ) { - some(def_id) { - let cs = ast_map::path_to_str(ty::item_path(cx, def_id)); - ret alt ty::get(typ).struct { - ty_enum(_, tps) | ty_res(_, _, tps) { parameterized(cx, cs, tps) } - _ { cs } - }; - } - none { /* fallthrough */} - } - - // pretty print the structural type representation: - ret alt ty::get(typ).struct { - ty_nil { "()" } - ty_bot { "_|_" } - ty_bool { "bool" } - ty_int(ast::ty_i) { "int" } - ty_int(ast::ty_char) { "char" } - ty_int(t) { ast_util::int_ty_to_str(t) } - ty_uint(ast::ty_u) { "uint" } - ty_uint(t) { ast_util::uint_ty_to_str(t) } - ty_float(ast::ty_f) { "float" } - ty_float(t) { ast_util::float_ty_to_str(t) } - ty_str { "str" } - ty_box(tm) { "@" + mt_to_str(cx, tm) } - ty_uniq(tm) { "~" + mt_to_str(cx, tm) } - ty_ptr(tm) { "*" + mt_to_str(cx, tm) } - ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" } - ty_type { "type" } - ty_rec(elems) { - let strs: [str] = []; - for fld: field in elems { strs += [field_to_str(cx, fld)]; } - "{" + str::connect(strs, ",") + "}" - } - ty_tup(elems) { - let strs = []; - for elem in elems { strs += [ty_to_str(cx, elem)]; } - "(" + str::connect(strs, ",") + ")" - } - ty_fn(f) { - fn_to_str(cx, f.proto, none, f.inputs, f.output, f.ret_style, - f.constraints) - } - ty_var(v) { "<T" + int::str(v) + ">" } - ty_param(id, _) { - "'" + str::from_bytes([('a' as u8) + (id as u8)]) - } - ty_enum(did, tps) | ty_res(did, _, tps) | ty_class(did, tps) { - // Not sure why, but under some circumstances enum or resource types - // do not have an associated id. I didn't investigate enough to know - // if there is a good reason for this. - Niko, 2012-02-10 - let path = ty::item_path(cx, did); - let base = ast_map::path_to_str(path); - parameterized(cx, base, tps) - } - _ { ty_to_short_str(cx, typ) } - } -} - -fn ty_to_short_str(cx: ctxt, typ: t) -> str { - let s = encoder::encoded_ty(cx, typ); - if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); } - ret s; -} - -fn constr_to_str(c: @constr) -> str { - ret path_to_str(c.node.path) + - pprust::constr_args_to_str(pprust::uint_to_str, c.node.args); -} - -fn constrs_str(constrs: [@constr]) -> str { - let s = ""; - let colon = true; - for c: @constr in constrs { - if colon { s += " : "; colon = false; } else { s += ", "; } - s += constr_to_str(c); - } - ret s; -} - -fn ty_constr_to_str<Q>(c: @ast::spanned<ast::constr_general_<@ast::path, Q>>) - -> str { - ret path_to_str(c.node.path) + - constr_args_to_str::<@ast::path>(path_to_str, c.node.args); -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: |
