DEFAULT_HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}"
-CFG_SELF=$(echo $0 | tr '\\' '/')
-CFG_SRC_DIR="$(dirname $CFG_SELF)/"
-CFG_BUILD_DIR="$(echo $PWD | tr '\\' '/')/"
+CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
+CFG_BUILD_DIR="$(pwd)/"
+CFG_SELF=${CFG_SRC_DIR}$(basename $0)
CFG_CONFIGURE_ARGS="$@"
OPTIONS=""
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ]
then
cd ${CFG_SRC_DIR}
+
msg "git: submodule sync"
- "${CFG_GIT}" submodule sync --quiet
- SUBMODULES=$("${CFG_GIT}" submodule status | awk '{print $2}')
- for s in $SUBMODULES
- do
- msg "git: submodule status ${s}"
- status=$("${CFG_GIT}" submodule status ${s} | awk '{print $1}')
- case ${status} in
- -*)
- msg "${s} is not initialized, initializing"
- "${CFG_GIT}" submodule init --quiet ${s}
- need_ok "git failed"
- msg "${s} updating"
- "${CFG_GIT}" submodule update --quiet ${s}
- need_ok "git failed"
- ;;
- +*)
- msg "${s} is not up to date, updating"
- "${CFG_GIT}" submodule update --quiet ${s}
- need_ok "git failed"
- ;;
- *)
- msg "${s} is clean"
- ;;
- esac
- done
+ "${CFG_GIT}" submodule --quiet sync
+
+ # NB: this is just for the sake of getting the submodule SHA1 values
+ # and status written into the build log.
+ msg "git: submodule status"
+ "${CFG_GIT}" submodule status --recursive
+
+ msg "git: submodule update"
+ "${CFG_GIT}" submodule --quiet update --init --recursive
+ need_ok "git failed"
+
+ msg "git: submodule clobber"
+ "${CFG_GIT}" submodule --quiet foreach --recursive git clean -dxf
+ need_ok "git failed"
+ "${CFG_GIT}" submodule --quiet foreach --recursive git checkout .
+ need_ok "git failed"
+
cd ${CFG_BUILD_DIR}
fi
tidy:
@$(call E, check: formatting)
$(Q)find $(S)src -name '*.r[sc]' \
+ | grep '^$(S)src/test' -v \
| xargs -n 10 python $(S)src/etc/tidy.py
$(Q)find $(S)src/etc -name '*.py' \
| xargs -n 10 python $(S)src/etc/tidy.py
report_err("trailing whitespace")
line_len = len(line)-2 if autocrlf else len(line)-1
- # Along long lines if they are part of an expected error message
- # in a test, which is denoted with "//!":
- if line_len > cols and "//!" not in line:
+ if line_len > cols:
report_err("line longer than %d chars" % cols)
except UnicodeDecodeError, e:
report_err("UTF-8 decoding error " + str(e))
}
}
+fn getenv(n: str) -> option<str> {
+ global_env::getenv(n)
+}
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
-fn getenv(n: str) -> option<str> unsafe {
- let s = as_c_charp(n, libc::getenv);
- ret if unsafe::reinterpret_cast(s) == 0 {
- option::none::<str>
- } else {
- let s = unsafe::reinterpret_cast(s);
- option::some::<str>(str::unsafe::from_buf(s))
- };
+fn setenv(n: str, v: str) {
+ global_env::setenv(n, v)
}
-#[cfg(target_os = "win32")]
-fn getenv(n: str) -> option<str> unsafe {
- import libc::types::os::arch::extra::*;
- import libc::funcs::extra::kernel32::*;
- import win32::*;
- as_utf16_p(n) {|u|
- fill_utf16_buf_and_decode() {|buf, sz|
- GetEnvironmentVariableW(u, buf, sz)
- }
+mod global_env {
+ #[doc = "Internal module for serializing access to getenv/setenv"];
+
+ export getenv;
+ export setenv;
+
+ native mod rustrt {
+ fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
}
-}
+ enum msg {
+ msg_getenv(str, comm::chan<option<str>>),
+ msg_setenv(str, str, comm::chan<()>)
+ }
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
-fn setenv(n: str, v: str) {
+ fn getenv(n: str) -> option<str> {
+ let env_ch = get_global_env_chan();
+ let po = comm::port();
+ comm::send(env_ch, msg_getenv(n, comm::chan(po)));
+ comm::recv(po)
+ }
- // FIXME: remove this when export globs work properly.
- import libc::funcs::posix01::unistd::setenv;
- as_c_charp(n) {|nbuf|
- as_c_charp(v) {|vbuf|
- setenv(nbuf, vbuf, 1i32);
+ fn setenv(n: str, v: str) {
+ let env_ch = get_global_env_chan();
+ let po = comm::port();
+ comm::send(env_ch, msg_setenv(n, v, comm::chan(po)));
+ comm::recv(po)
+ }
+
+ fn get_global_env_chan() -> comm::chan<msg> {
+ let global_ptr = rustrt::rust_global_env_chan_ptr();
+ let builder_fn = {||
+ let builder = task::builder();
+ task::unsupervise(builder);
+ task::set_opts(builder, {
+ sched: some({
+ mode: task::single_threaded,
+ // FIXME: This would be a good place to use
+ // a very small native stack
+ native_stack_size: none
+ })
+ with task::get_opts(builder)
+ });
+ builder
+ };
+ unsafe {
+ priv::chan_from_global_ptr(
+ global_ptr, builder_fn, global_env_task)
}
}
-}
+ fn global_env_task(msg_po: comm::port<msg>) unsafe {
+ priv::weaken_task {|weak_po|
+ loop {
+ alt comm::select2(msg_po, weak_po) {
+ either::left(msg_getenv(n, resp_ch)) {
+ comm::send(resp_ch, impl::getenv(n))
+ }
+ either::left(msg_setenv(n, v, resp_ch)) {
+ comm::send(resp_ch, impl::setenv(n, v))
+ }
+ either::right(_) {
+ break;
+ }
+ }
+ }
+ }
+ }
-#[cfg(target_os = "win32")]
-fn setenv(n: str, v: str) {
- // FIXME: remove imports when export globs work properly.
- import libc::funcs::extra::kernel32::*;
- import win32::*;
- as_utf16_p(n) {|nbuf|
- as_utf16_p(v) {|vbuf|
- SetEnvironmentVariableW(nbuf, vbuf);
+ mod impl {
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_os = "macos")]
+ #[cfg(target_os = "freebsd")]
+ fn getenv(n: str) -> option<str> unsafe {
+ let s = str::as_c_str(n, libc::getenv);
+ ret if unsafe::reinterpret_cast(s) == 0 {
+ option::none::<str>
+ } else {
+ let s = unsafe::reinterpret_cast(s);
+ option::some::<str>(str::unsafe::from_buf(s))
+ };
+ }
+
+ #[cfg(target_os = "win32")]
+ fn getenv(n: str) -> option<str> unsafe {
+ import libc::types::os::arch::extra::*;
+ import libc::funcs::extra::kernel32::*;
+ import win32::*;
+ as_utf16_p(n) {|u|
+ fill_utf16_buf_and_decode() {|buf, sz|
+ GetEnvironmentVariableW(u, buf, sz)
+ }
+ }
+ }
+
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_os = "macos")]
+ #[cfg(target_os = "freebsd")]
+ fn setenv(n: str, v: str) {
+
+ // FIXME: remove this when export globs work properly.
+ import libc::funcs::posix01::unistd::setenv;
+ str::as_c_str(n) {|nbuf|
+ str::as_c_str(v) {|vbuf|
+ setenv(nbuf, vbuf, 1i32);
+ }
+ }
+ }
+
+
+ #[cfg(target_os = "win32")]
+ fn setenv(n: str, v: str) {
+ // FIXME: remove imports when export globs work properly.
+ import libc::funcs::extra::kernel32::*;
+ import win32::*;
+ as_utf16_p(n) {|nbuf|
+ as_utf16_p(v) {|vbuf|
+ SetEnvironmentVariableW(nbuf, vbuf);
+ }
+ }
}
+
}
}
-
fn fdopen(fd: c_int) -> *FILE {
ret as_c_charp("r") {|modebuf|
libc::fdopen(fd, modebuf)
}
#[test]
- #[ignore(reason = "fails periodically on mac")]
fn test_setenv() {
let n = make_rand_name();
setenv(n, "VALUE");
}
#[test]
- #[ignore(reason = "fails periodically on mac")]
fn test_setenv_overwrite() {
let n = make_rand_name();
setenv(n, "1");
// Windows GetEnvironmentVariable requires some extra work to make sure
// the buffer the variable is copied into is the right size
#[test]
- #[ignore(reason = "fails periodically on mac")]
fn test_getenv_big() {
let mut s = "";
let mut i = 0;
fn rust_task_unweaken(ch: rust_port_id);
}
-type global_ptr<T: send> = *libc::uintptr_t;
+type global_ptr = *libc::uintptr_t;
#[doc = "
Atomically gets a channel from a pointer to a pointer-sized memory location
task to receive from it.
"]
unsafe fn chan_from_global_ptr<T: send>(
- global: global_ptr<T>,
+ global: global_ptr,
builder: fn() -> task::builder,
f: fn~(comm::port<T>)
) -> comm::chan<T> {
#[inline(always)]
unsafe fn form_slice<T,U>(p: *T, len: uint, f: fn([T]/&) -> U) -> U {
let pair = (p, len * sys::size_of::<T>());
- let v : *([T]/&) = ::unsafe::reinterpret_cast(ptr::addr_of(pair));
+ // FIXME: should use &blk not &static here, but a snapshot is req'd
+ let v : *([T]/&static) =
+ ::unsafe::reinterpret_cast(ptr::addr_of(pair));
f(*v)
}
}
type region = {id: node_id, node: region_};
#[auto_serialize]
-enum region_ {
- re_anon,
- re_named(ident),
- re_static
-}
+enum region_ { re_anon, re_named(ident) }
#[auto_serialize]
enum ty_ {
}
fn ice_msg(msg: str) -> str {
- #fmt["internal compiler error %s", msg]
+ #fmt["internal compiler error: %s", msg]
}
fn mk_span_handler(handler: handler, cm: codemap::codemap) -> span_handler {
parser {
let src = alt io::read_whole_file_str(path) {
result::ok(src) {
- // FIXME: This copy is unfortunate
+ // FIXME: This copy is unfortunate (#2319)
@src
}
result::err(e) {
fn region_from_name(p: parser, s: option<str>) -> @ast::region {
let r = alt s {
- some (string) {
- // FIXME: To be consistent with our type resolution, the
- // static region should probably be resolved during type
- // checking, not in the parser. (Issue #2256)
- if string == "static" {
- ast::re_static
- } else {
- ast::re_named(string)
- }
- }
+ some (string) { ast::re_named(string) }
none { ast::re_anon }
};
fn print_region(s: ps, region: @ast::region) {
alt region.node {
ast::re_anon { word_space(s, "&"); }
- ast::re_static { word_space(s, "&static"); }
ast::re_named(name) {
word(s.s, "&");
word_space(s, name);
mod tests {
import task;
- // FIXME #2160: These tests are all run in the same task because
- // getenv/setenv interacts poorly with threads on OS X
#[test]
- fn test_all() {
- test_get_time();
- test_precise_time();
- test_at_utc();
- test_at();
- test_to_timespec();
- test_conversions();
- test_strptime();
- test_ctime();
- test_strftime();
- }
-
fn test_get_time() {
const some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
const some_future_date: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
}
}
+ #[test]
fn test_precise_time() {
let s0 = precise_time_s();
let ns1 = precise_time_ns();
assert ns2 >= ns1;
}
+ #[test]
fn test_at_utc() {
os::setenv("TZ", "America/Los_Angeles");
assert utc.tm_nsec == 54321_i32;
}
+ #[test]
fn test_at() {
os::setenv("TZ", "America/Los_Angeles");
assert local.tm_nsec == 54321_i32;
}
+ #[test]
fn test_to_timespec() {
os::setenv("TZ", "America/Los_Angeles");
assert utc.to_local().to_timespec() == time;
}
+ #[test]
fn test_conversions() {
os::setenv("TZ", "America/Los_Angeles");
assert utc.to_local().to_utc() == utc;
}
+ #[test]
fn test_strptime() {
os::setenv("TZ", "America/Los_Angeles");
assert test("%", "%%");
}
+ #[test]
fn test_ctime() {
os::setenv("TZ", "America/Los_Angeles");
assert local.ctime() == "Fri Feb 13 15:31:30 2009";
}
+ #[test]
fn test_strftime() {
os::setenv("TZ", "America/Los_Angeles");
let timer_ptr = ptr::addr_of(timer);
let hl_loop = uv::global_loop::get();
uv::hl::interact(hl_loop) {|loop_ptr|
- uv::hl::ref(hl_loop, timer_ptr);
let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
if (init_result == 0i32) {
let start_result = uv::ll::timer_start(
comm::recv(timer_done_po);
// notify the caller immediately
comm::send(ch, copy(val));
- // then clean up our handle
- uv::hl::unref_and_close(hl_loop, timer_ptr,
- delayed_send_close_cb);
// uv_close for this timer has been processed
comm::recv(timer_done_po);
}
let stop_result = uv::ll::timer_stop(handle);
if (stop_result == 0i32) {
comm::send(timer_done_ch, ());
+ uv::ll::close(handle, delayed_send_close_cb);
}
else {
let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
#[cfg(test)]
mod test {
#[test]
- #[ignore]
- fn test_timer_simple_sleep_test() {
+ fn test_gl_timer_simple_sleep_test() {
sleep(1u);
}
#[test]
- #[ignore]
- fn test_timer_recv_timeout_before_time_passes() {
+ fn test_gl_timer_sleep_stress1() {
+ iter::repeat(500u) {||
+ sleep(1u);
+ }
+ }
+
+ #[test]
+ fn test_gl_timer_sleep_stress2() {
+ let po = comm::port();
+ let ch = comm::chan(po);
+
+ let repeat = 100u;
+ let spec = {
+
+ [(1u, 100u),
+ (10u, 10u),
+ (100u, 2u)]
+
+ };
+
+ iter::repeat(repeat) {||
+
+ for spec.each {|spec|
+ let (times, maxms) = spec;
+ task::spawn {||
+ import rand::*;
+ let rng = rng();
+ iter::repeat(times) {||
+ sleep(rng.next() as uint % maxms);
+ }
+ comm::send(ch, ());
+ }
+ }
+ }
+
+ iter::repeat(repeat * spec.len()) {||
+ comm::recv(po)
+ }
+ }
+
+ #[test]
+ fn test_gl_timer_recv_timeout_before_time_passes() {
let expected = rand::rng().gen_str(16u);
let test_po = comm::port::<str>();
let test_ch = comm::chan(test_po);
}
#[test]
- #[ignore]
- fn test_timer_recv_timeout_after_time_passes() {
+ fn test_gl_timer_recv_timeout_after_time_passes() {
let expected = rand::rng().gen_str(16u);
let fail_msg = rand::rng().gen_str(16u);
let test_po = comm::port::<str>();
import hl = uv_hl;
import get_gl = get;
-export get, get_single_task_gl, get_monitor_task_gl;
+export get, get_monitor_task_gl;
native mod rustrt {
fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t;
- fn rust_uv_get_kernel_monitor_global_chan_ptr() -> *libc::uintptr_t;
- fn rust_uv_get_kernel_global_async_handle() -> *libc::uintptr_t;
- fn rust_compare_and_swap_ptr(address: *libc::uintptr_t,
- oldval: libc::uintptr_t,
- newval: libc::uintptr_t) -> bool;
}
#[doc ="
Race-free helper to get access to a global task where a libuv
loop is running.
-Use `uv::hl::interact`, `uv::hl::ref`, `uv::hl::unref` and
-uv `uv::hl::unref_and_close` to do operations against the global
+Use `uv::hl::interact` to do operations against the global
loop that this function returns.
# Return
ret get_monitor_task_gl();
}
-// WARNING: USE ONLY ONE get_*_task_gl fn in the scope of a process lifetime.
#[doc(hidden)]
fn get_monitor_task_gl() -> hl::high_level_loop {
- let monitor_loop_chan =
- rustrt::rust_uv_get_kernel_monitor_global_chan_ptr();
- ret spawn_global_weak_task(
- monitor_loop_chan,
- {|weak_exit_po, msg_po, loop_ptr, first_msg|
- log(debug, "monitor gl: entering inner loop");
- unsafe {
- monitor_task_loop_body(weak_exit_po, msg_po, loop_ptr,
- copy(first_msg))
- }
- },
- {|msg_ch|
- hl::monitor_task_loop({op_chan: msg_ch})
- });
-}
-
-// WARNING: USE ONLY ONE get_*_task_gl fn in the scope of a process lifetime.
-#[doc(hidden)]
-fn get_single_task_gl() -> hl::high_level_loop {
- let global_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr();
- ret spawn_global_weak_task(
- global_loop_chan_ptr,
- {|weak_exit_po, msg_po, loop_ptr, first_msg|
- log(debug, "single-task gl: about to enter inner loop");
- unsafe {
- single_task_loop_body(weak_exit_po, msg_po, loop_ptr,
- copy(first_msg))
- }
- },
- {|msg_ch|
- log(debug, "after priv::chan_from_global_ptr");
- unsafe {
- let handle = get_global_async_handle_native_representation()
- as **ll::uv_async_t;
- hl::single_task_loop(
- { async_handle: handle, op_chan: msg_ch })
- }
- }
- );
-}
-
-// INTERNAL API
-
-fn spawn_global_weak_task(
- global_loop_chan_ptr: *libc::uintptr_t,
- weak_task_body_cb: fn~(
- comm::port<()>,
- comm::port<hl::high_level_msg>,
- *libc::c_void,
- hl::high_level_msg) -> bool,
- after_task_spawn_cb: fn~(comm::chan<hl::high_level_msg>)
- -> hl::high_level_loop) -> hl::high_level_loop {
+ let monitor_loop_chan_ptr =
+ rustrt::rust_uv_get_kernel_global_chan_ptr();
log(debug, #fmt("ENTERING global_loop::get() loop chan: %?",
- global_loop_chan_ptr));
-
+ monitor_loop_chan_ptr));
let builder_fn = {||
let builder = task::builder();
let opts = {
};
unsafe {
log(debug, "before priv::chan_from_global_ptr");
- let msg_ch = priv::chan_from_global_ptr::<hl::high_level_msg>(
- global_loop_chan_ptr,
- builder_fn) {|port|
-
- // the actual body of our global loop lives here
- log(debug, "initialized global port task!");
- log(debug, "GLOBAL initialized global port task!");
- outer_global_loop_body(port, weak_task_body_cb);
+ type hl_loop_req_ch = comm::chan<hl::high_level_loop>;
+ let msg_ch = priv::chan_from_global_ptr::<hl_loop_req_ch>(
+ monitor_loop_chan_ptr,
+ builder_fn) {|msg_po|
+ log(debug, "global monitor task starting");
+ priv::weaken_task() {|weak_exit_po|
+ log(debug, "global monitor task is now weak");
+ let hl_loop_data = spawn_libuv_weak_task();
+ let hl_loop = alt hl_loop_data {
+ (async, msg_ch) {
+ hl::simple_task_loop({async_handle:async, op_chan:msg_ch})
+ }
+ };
+ loop {
+ log(debug, "in outer_loop...");
+ let continue = either::either(
+ {|weak_exit|
+ // all normal tasks have ended, tell the
+ // libuv loop to tear_down, then exit
+ log(debug, #fmt("weak_exit_po recv'd msg: %?",
+ weak_exit));
+ let ( a, loop_msg_ch )= hl_loop_data;
+ comm::send(loop_msg_ch, hl::teardown_loop);
+ ll::async_send(a);
+ false
+ }, {|fetch_ch|
+ log(debug, #fmt("hl_loop req recv'd: %?",
+ fetch_ch));
+ comm::send(fetch_ch, copy(hl_loop));
+ true
+ }, comm::select2(weak_exit_po, msg_po));
+ if !continue { break; }
+ }
+ log(debug, "global monitor task is leaving weakend state");
+ };
+ log(debug, "global monitor task exiting");
};
- ret after_task_spawn_cb(msg_ch);
+ // once we have a chan to the monitor loop, we ask it for
+ // the libuv loop's async handle
+ let fetch_po = comm::port::<hl::high_level_loop>();
+ let fetch_ch = comm::chan(fetch_po);
+ comm::send(msg_ch, fetch_ch);
+ comm::recv(fetch_po)
}
}
-unsafe fn outer_global_loop_body(
- msg_po: comm::port<hl::high_level_msg>,
- weak_task_body_cb: fn~(
- comm::port<()>,
- comm::port<hl::high_level_msg>,
- *libc::c_void,
- hl::high_level_msg) -> bool) {
- // we're going to use a single libuv-generated loop ptr
- // for the duration of the process
- let loop_ptr = ll::loop_new();
+unsafe fn spawn_libuv_weak_task() -> (*ll::uv_async_t,
+ comm::chan<hl::high_level_msg>){
+ let exit_po = comm::port::<(*ll::uv_async_t,
+ comm::chan<hl::high_level_msg>)>();
+ let exit_ch = comm::chan(exit_po);
- // data structure for loop goes here..
-
- // immediately weaken the task this is running in.
- priv::weaken_task() {|weak_exit_po|
- // when we first enter this loop, we're going
- // to wait on stand-by to receive a request to
- // fire-up the libuv loop
- let mut continue = true;
- while continue {
- log(debug, "in outer_loop...");
- continue = either::either(
- {|left_val|
- // bail out..
- // if we catch this msg at this point,
- // we should just be able to exit because
- // the loop isn't active
- log(debug, #fmt("weak_exit_po recv'd msg: %?",
- left_val));
- false
- }, {|right_val|
- weak_task_body_cb(weak_exit_po, msg_po, loop_ptr,
- right_val)
- }, comm::select2(weak_exit_po, msg_po));
- log(debug,#fmt("GLOBAL LOOP EXITED, WAITING TO RESTART? %?",
- continue));
- }
- };
-
- ll::loop_delete(loop_ptr);
-}
-
-unsafe fn monitor_task_loop_body(weak_exit_po_in: comm::port<()>,
- msg_po_in: comm::port<hl::high_level_msg>,
- loop_ptr: *libc::c_void,
- -first_interaction: hl::high_level_msg) -> bool {
- // resend the msg to be handled in the select2 loop below..
- comm::send(comm::chan(msg_po_in), first_interaction);
-
- // our async_handle
- let async_handle_po = comm::port::<*ll::uv_async_t>();
- let async_handle_ch = comm::chan(async_handle_po);
-
- // the msg_po that libuv will be receiving on..
- let loop_msg_po = comm::port::<hl::high_level_msg>();
- let loop_msg_po_ptr = ptr::addr_of(loop_msg_po);
- let loop_msg_ch = comm::chan(loop_msg_po);
-
- // the question of whether unsupervising this will even do any
- // good is there.. but since this'll go into blocking in libuv with
- // a quickness.. any errors that occur (including inside crust) will
- // be segfaults.. so yeah.
task::spawn_sched(task::manual_threads(1u)) {||
- let loop_msg_po_in = *loop_msg_po_ptr;
- hl::run_high_level_loop(
- loop_ptr,
- loop_msg_po_in, // here the loop gets handed a different message
- // port, as we'll be receiving all of the messages
- // initially and then passing them on..
- // before_run
- {|async_handle|
- log(debug,#fmt("monitor gl: before_run: async_handle %?",
- async_handle));
- // when this is ran, our async_handle is set up, so let's
- // do an async_send with it.. letting the loop know, once it
- // starts, that is has work
- ll::async_send(async_handle);
- comm::send(async_handle_ch, copy(async_handle));
- },
- // before_msg_drain
- {|async_handle|
- log(debug,#fmt("monitor gl: b4_msg_drain: async_handle %?",
- async_handle));
- true
- },
- // before_tear_down
- {|async_handle|
- log(debug,#fmt("monitor gl: b4_tear_down: async_handle %?",
- async_handle));
- });
+ log(debug, "entering global libuv task");
+ let loop_ptr = ll::loop_new();
+ priv::weaken_task() {|weak_exit_po|
+ log(debug, #fmt("global libuv task is now weak %?",
+ weak_exit_po));
+ let loop_msg_po = comm::port::<hl::high_level_msg>();
+ let loop_msg_ch = comm::chan(loop_msg_po);
+ hl::run_high_level_loop(
+ loop_ptr,
+ loop_msg_po,
+ // before_run
+ {|async_handle|
+ log(debug,#fmt("global libuv: before_run %?",
+ async_handle));
+ let out_data = (async_handle, loop_msg_ch);
+ comm::send(exit_ch, out_data);
+ },
+ // before_msg_process
+ {|async_handle, loop_active|
+ log(debug,#fmt("global libuv: before_msg_drain %? %?",
+ async_handle, loop_active));
+ true
+ },
+ // before_tear_down
+ {|async_handle|
+ log(debug,#fmt("libuv task: before_tear_down %?",
+ async_handle));
+ }
+ );
+ log(debug, "global libuv task is leaving weakened state");
+ };
+ ll::loop_delete(loop_ptr);
+ log(debug, "global libuv task exiting");
};
- // our loop is set up, so let's emit the handle back out to our users..
- let async_handle = comm::recv(async_handle_po);
- // supposed to return a bool to indicate to the enclosing loop whether
- // it should continue or not..
- let mut continue_inner_loop = true;
- let mut didnt_get_hl_bailout = true;
- while continue_inner_loop {
- log(debug, "monitor task inner loop.. about to block on select2");
- continue_inner_loop = either::either(
- {|left_val|
- // bail out..
- log(debug, #fmt("monitor inner weak_exit_po recv'd msg: %?",
- left_val));
- // TODO: make loop bail out
- didnt_get_hl_bailout = false;
- false
- }, {|right_val|
- // wake up our inner loop and pass it a msg..
- comm::send(loop_msg_ch, copy(right_val));
- ll::async_send(async_handle);
- true
- }, comm::select2(weak_exit_po_in, msg_po_in)
- )
- }
- didnt_get_hl_bailout
-}
-
-unsafe fn single_task_loop_body(weak_exit_po_in: comm::port<()>,
- msg_po_in: comm::port<hl::high_level_msg>,
- loop_ptr: *libc::c_void,
- -first_interaction: hl::high_level_msg) -> bool {
- // resend the msg
- comm::send(comm::chan(msg_po_in), first_interaction);
-
- // black magic
- let weak_exit_po_ptr = ptr::addr_of(weak_exit_po_in);
- hl::run_high_level_loop(
- loop_ptr,
- msg_po_in,
- // before_run
- {|async_handle|
- log(debug,#fmt("global_loop before_run: async_handle %?",
- async_handle));
- // set the handle as the global
- set_global_async_handle(0u as *ll::uv_async_t,
- async_handle);
- // when this is ran, our async_handle is set up, so let's
- // do an async_send with it
- ll::async_send(async_handle);
- },
- // before_msg_drain
- {|async_handle|
- log(debug,#fmt("global_loop before_msg_drain: async_handle %?",
- async_handle));
- let weak_exit_po = *weak_exit_po_ptr;
- if(comm::peek(weak_exit_po)) {
- // if this is true, immediately bail and return false, causing
- // the libuv loop to start tearing down
- log(debug,"got weak_exit meg inside libuv loop");
- comm::recv(weak_exit_po);
- false
- }
- // if no weak_exit_po msg is received, then we'll let the
- // loop continue
- else {
- true
- }
- },
- // before_tear_down
- {|async_handle|
- log(debug,#fmt("global_loop before_tear_down: async_handle %?",
- async_handle));
- set_global_async_handle(async_handle,
- 0 as *ll::uv_async_t);
- });
- // supposed to return a bool to indicate to the enclosing loop whether
- // it should continue or not..
- ret true;
-}
-
-unsafe fn get_global_async_handle_native_representation()
- -> *libc::uintptr_t {
- ret rustrt::rust_uv_get_kernel_global_async_handle();
-}
-
-unsafe fn get_global_async_handle() -> *ll::uv_async_t {
- ret (*get_global_async_handle_native_representation()) as *ll::uv_async_t;
-}
-
-unsafe fn set_global_async_handle(old: *ll::uv_async_t,
- new_ptr: *ll::uv_async_t) {
- rustrt::rust_compare_and_swap_ptr(
- get_global_async_handle_native_representation(),
- old as libc::uintptr_t,
- new_ptr as libc::uintptr_t);
+ comm::recv(exit_po)
}
#[cfg(test)]
let hl_loop = get_gl();
hl::interact(hl_loop) {|loop_ptr|
log(debug, "closing timer");
- //ll::close(timer_ptr as *libc::c_void, simple_timer_close_cb);
- hl::unref_and_close(hl_loop, timer_ptr, simple_timer_close_cb);
+ ll::close(timer_ptr, simple_timer_close_cb);
log(debug, "about to deref exit_ch_ptr");
log(debug, "after msg sent on deref'd exit_ch");
};
log(debug, "user code inside interact loop!!!");
let init_status = ll::timer_init(loop_ptr, timer_ptr);
if(init_status == 0i32) {
- hl::ref(hl_loop, timer_ptr);
ll::set_data_for_uv_handle(
timer_ptr as *libc::c_void,
exit_ch_ptr as *libc::c_void);
comm::recv(exit_po);
log(debug, "global_loop timer test: msg recv on exit_po, done..");
}
+
#[test]
- #[ignore]
- fn test_uv_global_loop_high_level_global_timer() unsafe {
+ fn test_gl_uv_global_loop_high_level_global_timer() unsafe {
let hl_loop = get_gl();
+ let exit_po = comm::port::<()>();
+ let exit_ch = comm::chan(exit_po);
task::spawn_sched(task::manual_threads(1u), {||
impl_uv_hl_simple_timer(hl_loop);
+ comm::send(exit_ch, ());
});
impl_uv_hl_simple_timer(hl_loop);
+ comm::recv(exit_po);
+ }
+
+ // keeping this test ignored until some kind of stress-test-harness
+ // is set up for the build bots
+ #[test]
+ #[ignore]
+ fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe {
+ let hl_loop = get_gl();
+ let exit_po = comm::port::<()>();
+ let exit_ch = comm::chan(exit_po);
+ let cycles = 5000u;
+ iter::repeat(cycles) {||
+ task::spawn_sched(task::manual_threads(1u), {||
+ impl_uv_hl_simple_timer(hl_loop);
+ comm::send(exit_ch, ());
+ });
+ };
+ iter::repeat(cycles) {||
+ comm::recv(exit_po);
+ };
+ log(debug, "test_stress_gl_uv_global_loop_high_level_global_timer"+
+ " exiting sucessfully!");
}
}
\ No newline at end of file
libuv functionality.
"];
-export high_level_loop, hl_loop_ext, high_level_msg;
-export run_high_level_loop, interact, ref, unref, unref_and_close;
+export high_level_loop, high_level_msg;
+export run_high_level_loop, interact;
import ll = uv_ll;
#[doc = "
Used to abstract-away direct interaction with a libuv loop.
-
-# Arguments
-
-* async_handle - a pointer to a pointer to a uv_async_t struct used to 'poke'
-the C uv loop to process any pending callbacks
-
-* op_chan - a channel used to send function callbacks to be processed
-by the C uv loop
"]
enum high_level_loop {
+ #[doc="
+ `high_level_loop` variant that carries a `comm::chan` and
+ a `*ll::uv_async_t`.
+ "]
simple_task_loop({
async_handle: *ll::uv_async_t,
op_chan: comm::chan<high_level_msg>
- }),
- single_task_loop({
- async_handle: **ll::uv_async_t,
- op_chan: comm::chan<high_level_msg>
- }),
- monitor_task_loop({
- op_chan: comm::chan<high_level_msg>
})
}
-impl hl_loop_ext for high_level_loop {
- fn async_handle() -> **ll::uv_async_t {
- alt self {
- single_task_loop({async_handle, op_chan}) {
- ret async_handle;
- }
- _ {
- fail "variant of hl::high_level_loop that doesn't include" +
- "an async_handle field";
- }
- }
- }
- fn op_chan() -> comm::chan<high_level_msg> {
- alt self {
- single_task_loop({async_handle, op_chan}) {
- ret op_chan;
- }
- monitor_task_loop({op_chan}) {
- ret op_chan;
- }
- simple_task_loop({async_handle, op_chan}) {
- ret op_chan;
- }
- }
- }
-}
-
#[doc="
Represents the range of interactions with a `high_level_loop`
"]
enum high_level_msg {
interaction (fn~(*libc::c_void)),
- ref_handle (*libc::c_void),
- manual_unref_handle (*libc::c_void, option<*u8>),
- tear_down
+ #[doc="
+For use in libraries that roll their own `high_level_loop` (like
+`std::uv::global_loop`)
+
+Is used to signal to the loop that it should close the internally-held
+async handle and do a sanity check to make sure that all other handles are
+closed, causing a failure otherwise. This should not be sent/used from
+'normal' user code.
+ "]
+ teardown_loop
}
#[doc = "
-Given a vanilla `uv_loop_t*`
+Useful for anyone who wants to roll their own `high_level_loop`.
# Arguments
* loop_ptr - a pointer to a currently unused libuv loop. Its `data` field
will be overwritten before the loop begins
-must be a pointer to a clean rust `uv_async_t` record
-* msg_po - an active port that receives `high_level_msg`s
-* before_run - a unique closure that is invoked after `uv_async_init` is
-called on the `async_handle` passed into this callback, just before `uv_run`
-is called on the provided `loop_ptr`
-* before_msg_drain - a unique closure that is invoked every time the loop is
-awoken, but before the port pointed to in the `msg_po` argument is drained
+* msg_po - an active port that receives `high_level_msg`s. You can distribute
+a paired channel to users, along with the `async_handle` returned in the
+following callback (combine them to make a `hl::simpler_task_loop` varient
+of `hl::high_level_loop`)
+* before_run - a unique closure that is invoked before `uv_run()` is called
+on the provided `loop_ptr`. An `async_handle` is passed in which will be
+live for the duration of the loop. You can distribute this to users so that
+they can interact with the loop safely.
+* before_msg_process - a unique closure that is invoked at least once when
+the loop is woken up, and once more for every message that is drained from
+the loop's msg port
* before_tear_down - called just before the loop invokes `uv_close()` on the
provided `async_handle`. `uv_run` should return shortly after
"]
unsafe fn run_high_level_loop(loop_ptr: *libc::c_void,
msg_po: comm::port<high_level_msg>,
before_run: fn~(*ll::uv_async_t),
- before_msg_drain: fn~(*ll::uv_async_t) -> bool,
+ before_msg_process:
+ fn~(*ll::uv_async_t, bool) -> bool,
before_tear_down: fn~(*ll::uv_async_t)) {
// set up the special async handle we'll use to allow multi-task
// communication with this loop
let data: hl_loop_data = default_gl_data({
async_handle: async_handle,
mut active: true,
- before_msg_drain: before_msg_drain,
+ before_msg_process: before_msg_process,
before_tear_down: before_tear_down,
- msg_po_ptr: ptr::addr_of(msg_po),
- mut refd_handles: [mut],
- mut unrefd_handles: [mut]
+ msg_po_ptr: ptr::addr_of(msg_po)
});
let data_ptr = ptr::addr_of(data);
ll::set_data_for_uv_handle(async_handle, data_ptr);
The primary way to do operations again a running `high_level_loop` that
doesn't involve creating a uv handle via `safe_handle`
+# Warning
+
+This function is the only safe way to interact with _any_ `high_level_loop`.
+Using functions in the `uv::ll` module outside of the `cb` passed into
+this function is _very dangerous_.
+
# Arguments
-* a_loop - a `high_level_loop` that you want to do operations against
+* hl_loop - a `uv::hl::high_level_loop` that you want to do operations against
* cb - a function callback to be processed on the running loop's
-thread. The only parameter is an opaque pointer to the running
-uv_loop_t. In the context of this callback, it is safe to use this pointer
-to do various uv_* API calls. _DO NOT_ send this pointer out via ports/chans
+thread. The only parameter passed in is an opaque pointer representing the
+running `uv_loop_t*`. In the context of this callback, it is safe to use
+this pointer to do various uv_* API calls contained within the `uv::ll`
+module. It is not safe to send the `loop_ptr` param to this callback out
+via ports/chans.
"]
-unsafe fn interact(a_loop: high_level_loop,
+unsafe fn interact(hl_loop: high_level_loop,
-cb: fn~(*libc::c_void)) {
- send_high_level_msg(a_loop, interaction(cb));
-}
-
-iface uv_handle_manager<T> {
- fn init() -> T;
-}
-
-type safe_handle_fields<T> = {
- hl_loop: high_level_loop,
- handle: T,
- close_cb: *u8
-};
-
-/*fn safe_handle<T>(a_loop: high_level_loop,
- handle_val: T,
- handle_init_cb: fn~(*libc::c_void, *T),
- close_cb: *u8) {
-
-resource safe_handle_container<T>(handle_fields: safe_handle_fields<T>) {
-}
-}*/
-
-
-#[doc="
-Needs to be encapsulated within `safe_handle`
-"]
-fn ref<T>(hl_loop: high_level_loop, handle: *T) unsafe {
- send_high_level_msg(hl_loop, ref_handle(handle as *libc::c_void));
-}
-#[doc="
-Needs to be encapsulated within `safe_handle`
-"]
-fn unref<T>(hl_loop: high_level_loop, handle: *T) unsafe {
- send_high_level_msg(hl_loop, manual_unref_handle(handle as *libc::c_void,
- none));
-}
-fn unref_and_close<T>(hl_loop: high_level_loop, handle: *T, cb: *u8) unsafe {
- send_high_level_msg(hl_loop, manual_unref_handle(handle as *libc::c_void,
- some(cb)));
+ send_high_level_msg(hl_loop, interaction(cb));
}
// INTERNAL API
default_gl_data({
async_handle: *ll::uv_async_t,
mut active: bool,
- before_msg_drain: fn~(*ll::uv_async_t) -> bool,
+ before_msg_process: fn~(*ll::uv_async_t, bool) -> bool,
before_tear_down: fn~(*ll::uv_async_t),
- msg_po_ptr: *comm::port<high_level_msg>,
- mut refd_handles: [mut *libc::c_void],
- mut unrefd_handles: [mut *libc::c_void]})
+ msg_po_ptr: *comm::port<high_level_msg>})
}
unsafe fn send_high_level_msg(hl_loop: high_level_loop,
- -msg: high_level_msg) unsafe {
- comm::send(hl_loop.op_chan(), msg);
+ -msg: high_level_msg) {
+ let op_chan = alt hl_loop{simple_task_loop({async_handle, op_chan}){
+ op_chan}};
+ comm::send(op_chan, msg);
// if the global async handle == 0, then that means
// the loop isn't active, so we don't need to wake it up,
// (the loop's enclosing task should be blocking on a message
// receive on this port)
alt hl_loop {
- single_task_loop({async_handle, op_chan}) {
- if ((*async_handle) != 0 as *ll::uv_async_t) {
- log(debug,"global async handle != 0, waking up loop..");
- ll::async_send((*async_handle));
- }
- else {
- log(debug,"GLOBAL ASYNC handle == 0");
- }
- }
simple_task_loop({async_handle, op_chan}) {
log(debug,"simple async handle != 0, waking up loop..");
ll::async_send((async_handle));
}
- _ {}
}
}
// data member
crust fn high_level_wake_up_cb(async_handle: *ll::uv_async_t,
status: int) unsafe {
- // nothing here, yet.
log(debug, #fmt("high_level_wake_up_cb crust.. handle: %? status: %?",
async_handle, status));
let loop_ptr = ll::get_loop_for_uv_handle(async_handle);
let data = ll::get_data_for_uv_handle(async_handle) as *hl_loop_data;
- // we check to see if the loop is "active" (the loop is set to
- // active = false the first time we realize we need to 'tear down',
- // set subsequent calls to the global async handle may be triggered
- // before all of the uv_close() calls are processed and loop exits
- // on its own. So if the loop isn't active, we won't run the user's
- // on_wake callback (and, consequently, let messages pile up, probably
- // in the loops msg_po)
- if (*data).active {
- log(debug, "before on_wake");
- let mut do_msg_drain = (*data).before_msg_drain(async_handle);
- let mut continue = true;
- if do_msg_drain {
- let msg_po = *((*data).msg_po_ptr);
- if comm::peek(msg_po) {
- // if this is true, we'll iterate over the
- // msgs waiting in msg_po until there's no more
- log(debug,"got msg_po");
- while(continue) {
- log(debug,"before alt'ing on high_level_msg");
- alt comm::recv(msg_po) {
+ alt (*data).active {
+ true {
+ let msg_po = *((*data).msg_po_ptr);
+ alt comm::peek(msg_po) {
+ true {
+ loop {
+ let msg = comm::recv(msg_po);
+ alt (*data).active {
+ true {
+ alt msg {
interaction(cb) {
- log(debug,"got interaction, before cb..");
- // call it..
+ (*data).before_msg_process(async_handle,
+ (*data).active);
cb(loop_ptr);
- log(debug,"after calling cb");
- }
- ref_handle(handle) {
- high_level_ref(data, handle);
}
- manual_unref_handle(handle, user_close_cb) {
- high_level_unref(data, handle, true, user_close_cb);
- }
- tear_down {
- log(debug,"incoming hl_msg: got tear_down");
+ teardown_loop {
+ begin_teardown(data);
}
}
- continue = comm::peek(msg_po);
+ }
+ false {
+ // drop msg ?
+ }
}
+ if !comm::peek(msg_po) { break; }
}
- else {
- log(debug, "in hl wake_cb, no pending messages");
- }
- }
- log(debug, #fmt("after on_wake, continue? %?", continue));
- if !do_msg_drain {
- high_level_tear_down(data);
+ }
+ false {
+ // no pending msgs
+ }
}
+ }
+ false {
+ // loop not active
+ }
}
}
crust fn tear_down_close_cb(handle: *ll::uv_async_t) unsafe {
- log(debug, #fmt("tear_down_close_cb called, closing handle at %?",
- handle));
- let data = ll::get_data_for_uv_handle(handle) as *hl_loop_data;
- if vec::len((*data).refd_handles) > 0u {
- fail "Didn't unref all high-level handles";
- }
+ let loop_ptr = ll::get_loop_for_uv_handle(handle);
+ let loop_refs = ll::loop_refcount(loop_ptr);
+ log(debug, #fmt("tear_down_close_cb called, closing handle at %? refs %?",
+ handle, loop_refs));
+ assert loop_refs == 1i32;
}
-fn high_level_tear_down(data: *hl_loop_data) unsafe {
+fn begin_teardown(data: *hl_loop_data) unsafe {
log(debug, "high_level_tear_down() called, close async_handle");
// call user-suppled before_tear_down cb
let async_handle = (*data).async_handle;
ll::close(async_handle as *libc::c_void, tear_down_close_cb);
}
-unsafe fn high_level_ref(data: *hl_loop_data, handle: *libc::c_void) {
- log(debug,"incoming hl_msg: got ..ref_handle");
- let mut refd_handles = (*data).refd_handles;
- let mut unrefd_handles = (*data).unrefd_handles;
- let handle_already_refd = refd_handles.contains(handle);
- if handle_already_refd {
- fail "attempt to do a high-level ref an already ref'd handle";
- }
- let handle_already_unrefd = unrefd_handles.contains(handle);
- // if we are ref'ing a handle (by ptr) that was already unref'd,
- // probably
- if handle_already_unrefd {
- let last_idx = vec::len(unrefd_handles) - 1u;
- let handle_idx = vec::position_elem(unrefd_handles, handle);
- alt handle_idx {
- none {
- fail "trying to remove handle that isn't in unrefd_handles";
- }
- some(idx) {
- unrefd_handles[idx] <-> unrefd_handles[last_idx];
- vec::pop(unrefd_handles);
- }
- }
- (*data).unrefd_handles = unrefd_handles;
- }
- refd_handles += [handle];
- (*data).refd_handles = refd_handles;
-}
-
-unsafe fn high_level_unref(data: *hl_loop_data, handle: *libc::c_void,
- manual_unref: bool, user_close_cb: option<*u8>) {
- log(debug,"incoming hl_msg: got auto_unref_handle");
- let mut refd_handles = (*data).refd_handles;
- let mut unrefd_handles = (*data).unrefd_handles;
- log(debug, #fmt("refs: %?, unrefs %? handle %?", vec::len(refd_handles),
- vec::len(unrefd_handles), handle));
- let handle_already_refd = refd_handles.contains(handle);
- if !handle_already_refd {
- fail "attempting to high-level unref an untracked handle";
- }
- let double_unref = unrefd_handles.contains(handle);
- if double_unref {
- log(debug, "double unref encountered");
- if manual_unref {
- // will allow a user to manual unref, but only signal
- // a fail when a double-unref is caused by a user
- fail "attempting to high-level unref an unrefd handle";
- }
- else {
- log(debug, "not failing...");
- }
- }
- else {
- log(debug, "attempting to unref handle");
- alt user_close_cb {
- some(cb) {
- ll::close(handle, cb);
- }
- none { }
- }
- let last_idx = vec::len(refd_handles) - 1u;
- let handle_idx = vec::position_elem(refd_handles, handle);
- alt handle_idx {
- none {
- fail "trying to remove handle that isn't in refd_handles";
- }
- some(idx) {
- refd_handles[idx] <-> refd_handles[last_idx];
- vec::pop(refd_handles);
- }
- }
- (*data).refd_handles = refd_handles;
- unrefd_handles += [handle];
- (*data).unrefd_handles = unrefd_handles;
- if vec::len(refd_handles) == 0u {
- log(debug, "0 referenced handles, start loop teardown");
- high_level_tear_down(data);
- }
- else {
- log(debug, "more than 0 referenced handles");
- }
- }
-
-}
#[cfg(test)]
mod test {
crust fn async_close_cb(handle: *ll::uv_async_t) unsafe {
log(debug, #fmt("async_handle_cb handle %? status %?",handle,status));
let hl_loop = (*(ll::get_data_for_uv_handle(handle)
as *ah_data)).hl_loop;
- unref_and_close(hl_loop, handle, async_close_cb);
+ ll::close(handle, async_close_cb);
}
type ah_data = {
hl_loop: high_level_loop,
};
let ah_data_ptr = ptr::addr_of(ah_data);
interact(hl_loop) {|loop_ptr|
- ref(hl_loop, ah_ptr);
ll::async_init(loop_ptr, ah_ptr, async_handle_cb);
ll::set_data_for_uv_handle(ah_ptr, ah_data_ptr as *libc::c_void);
ll::async_send(ah_ptr);
}));
},
// before_msg_drain
- {|async_handle|
- log(debug,#fmt("hltest before_msg_drain: async_handle %?",
- async_handle));
+ {|async_handle, status|
+ log(debug,#fmt("hltest before_msg_drain: handle %? %?",
+ async_handle, status));
true
},
// before_tear_down
}
#[test]
- #[ignore]
fn test_uv_hl_async() unsafe {
let exit_po = comm::port::<()>();
let exit_ch = comm::chan(exit_po);
// under race-condition type situations.. this ensures that the loop
// lives until, at least, all of the impl_uv_hl_async() runs have been
// called, at least.
- let lifetime_handle = ll::async_t();
- let lifetime_handle_ptr = ptr::addr_of(lifetime_handle);
- interact(hl_loop) {|loop_ptr|
- ref(hl_loop, lifetime_handle_ptr);
- ll::async_init(loop_ptr, lifetime_handle_ptr,
- lifetime_async_callback);
- };
-
+ let work_exit_po = comm::port::<()>();
+ let work_exit_ch = comm::chan(work_exit_po);
iter::repeat(7u) {||
task::spawn_sched(task::manual_threads(1u), {||
impl_uv_hl_async(hl_loop);
+ comm::send(work_exit_ch, ());
});
};
- impl_uv_hl_async(hl_loop);
- impl_uv_hl_async(hl_loop);
- impl_uv_hl_async(hl_loop);
- interact(hl_loop) {|loop_ptr|
- ll::close(lifetime_handle_ptr, lifetime_handle_close);
- unref(hl_loop, lifetime_handle_ptr);
- log(debug, "close and unref lifetime handle");
+ iter::repeat(7u) {||
+ comm::recv(work_exit_po);
};
+ log(debug, "sending teardown_loop msg..");
+ // the teardown msg usually comes, in the case of the global loop,
+ // as a result of receiving a msg on the weaken_task port. but,
+ // anyone rolling their own high_level_loop can decide when to
+ // send the msg. it's assert and barf, though, if all of your
+ // handles aren't uv_close'd first
+ alt hl_loop {
+ simple_task_loop({async_handle, op_chan}) {
+ comm::send(op_chan, teardown_loop);
+ ll::async_send(async_handle);
+ }
+ }
comm::recv(exit_po);
+ log(debug, "after recv on exit_po.. exiting..");
}
}
native mod rustrt {
fn rust_uv_loop_new() -> *libc::c_void;
fn rust_uv_loop_delete(lp: *libc::c_void);
+ fn rust_uv_loop_refcount(loop_ptr: *libc::c_void) -> libc::c_int;
fn rust_uv_run(loop_handle: *libc::c_void);
fn rust_uv_close(handle: *libc::c_void, cb: *u8);
fn rust_uv_async_send(handle: *uv_async_t);
rustrt::rust_uv_loop_delete(loop_handle);
}
+unsafe fn loop_refcount(loop_ptr: *libc::c_void) -> libc::c_int {
+ ret rustrt::rust_uv_loop_refcount(loop_ptr);
+}
+
unsafe fn run(loop_handle: *libc::c_void) {
rustrt::rust_uv_run(loop_handle);
}
-Subproject commit 8b035b5fe83ca15df171e581681bbc9cbd7e2ae0
+Subproject commit 3a57b672f89adcb2d2d06adc564dc15ca4e276d6
task->kernel->unweaken_task(chan);
}
+extern "C" CDECL uintptr_t*
+rust_global_env_chan_ptr() {
+ rust_task *task = rust_get_current_task();
+ return task->kernel->get_global_env_chan();
+}
+
//
// Local Variables:
// mode: C++
sched_reaper(this),
osmain_driver(NULL),
non_weak_tasks(0),
+ global_loop_chan(0),
+ global_env_chan(0),
env(env)
+
{
- // set up storage of pointers needed to
- // access the global loop.
- global_loop_chan = 0;
- async_handle_inner = (uintptr_t)0;
- global_async_handle = &async_handle_inner;
- *global_async_handle = (uintptr_t)0;
// Create the single threaded scheduler that will run on the platform's
// main thread
// Used to communicate with the process-side, global libuv loop
uintptr_t global_loop_chan;
- uintptr_t async_handle_inner;
- uintptr_t* global_async_handle;
+ // Used to serialize access to getenv/setenv
+ uintptr_t global_env_chan;
public:
struct rust_env *env;
bool send_to_port(rust_port_id chan, void *sptr);
uintptr_t* get_global_loop() { return &global_loop_chan; }
- uintptr_t* get_global_async_handle() { return global_async_handle; }
+ uintptr_t* get_global_env_chan() { return &global_env_chan; }
};
template <typename T> struct kernel_owned {
uv_loop_delete(loop);
}
+extern "C" int
+rust_uv_loop_refcount(uv_loop_t* loop) {
+ return uv_loop_refcount(loop);
+}
+
extern "C" void
rust_uv_loop_set_data(uv_loop_t* loop, void* data) {
loop->data = data;
LOG(task, stdlib,"global loop val: %lu", (unsigned long int)*result);
return result;
}
-
-extern "C" uintptr_t*
-rust_uv_get_kernel_monitor_global_chan_ptr() {
- return rust_uv_get_kernel_global_chan_ptr();
-}
-
-extern "C" uintptr_t*
-rust_uv_get_kernel_global_async_handle() {
- return rust_get_current_task()->kernel->get_global_async_handle();
-}
upcall_reset_stack_limit
rust_uv_loop_new
rust_uv_loop_delete
+rust_uv_loop_refcount
rust_uv_loop_set_data
rust_uv_bind_op_cb
rust_uv_stop_op_cb
rust_uv_get_base_from_buf
rust_uv_get_len_from_buf
rust_uv_get_kernel_global_chan_ptr
-rust_uv_get_kernel_monitor_global_chan_ptr
-rust_uv_get_kernel_global_async_handle
rust_dbg_lock_create
rust_dbg_lock_destroy
rust_dbg_lock_lock
rust_dbg_lock_signal
rust_dbg_call
rust_osmain_sched_id
-rust_compare_and_swap_ptr
\ No newline at end of file
+rust_compare_and_swap_ptr
+rust_global_env_chan_ptr
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);
+
+ for [
+
+ "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"
+
+ ].each {|note|
+ diagnostic::emit(none, note, diagnostic::note)
+ }
}
// Fail so the process returns a failure code
fail;
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
+ option::none::<()>
} else {
#debug("%s is a candidate", path);
alt get_metadata_section(sess, path) {
option::some(cvec) {
if !crate_matches(cvec, metas, hash) {
#debug("skipping %s, metadata doesn't match", path);
- option::none
+ option::none::<()>
} else {
#debug("found %s with matching metadata", path);
matches += [{ident: path, data: cvec}];
- option::none
+ option::none::<()>
}
}
_ {
#debug("could not load metadata for %s", path);
- option::none
+ option::none::<()>
}
}
}
result += [(cnum, cm.data, def)];
} else {
if cm.cnum_map.contains_key(def.crate) {
- // This reexport is itself a reexport from anther crate
+ // This reexport is itself a reexport from another 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)];
// [B]. Deep resolution, on the other hand, would yield [int].
//
// But there is one more knob: the force_vars variable controls the
-// behavior in the face of unconstrained variables. If we have A, B
-// and only the constraint that A <: B, then the result is [_|_] if
-// force_vars is true and [B] otherwise. We use force_vars == true
-// when resolving types after typeck, but false otherwise (for
-// example, when pretty-printing them for errors).
+// behavior in the face of unconstrained variables. If it is true,
+// then unconstrained variables result in an error.
type resolve_state = @{
infcx: infer_ctxt,
let r1 = alt bounds {
{ ub:_, lb:some(t) } { self.resolve_region(t) }
{ ub:some(t), lb:_ } { self.resolve_region(t) }
- { ub:none, lb:none } if self.force_vars { ty::re_static }
- { ub:none, lb:none } { ty::re_var(rid) }
+ { ub:none, lb:none } {
+ if self.force_vars {
+ self.err = some(unresolved_region(rid));
+ }
+ ty::re_var(rid)
+ }
};
vec::pop(self.r_seen);
ret r1;
{ ub:_, lb:some(t) } if !type_is_bot(t) { self.resolve1(t) }
{ ub:some(t), lb:_ } { self.resolve1(t) }
{ ub:_, lb:some(t) } { self.resolve1(t) }
- { ub:none, lb:none } if self.force_vars { ty::mk_bot(tcx) }
- { ub:none, lb:none } { ty::mk_var(tcx, vid) }
+ { ub:none, lb:none } {
+ if self.force_vars {
+ self.err = some(unresolved_ty(vid));
+ }
+ ty::mk_var(tcx, vid)
+ }
};
vec::pop(self.v_seen);
ret t1;
import ty::{kind, kind_copyable, kind_sendable, kind_noncopyable};
import driver::session::session;
import std::map::hashmap;
+import syntax::print::pprust::expr_to_str;
// Kind analysis pass. There are three kinds:
//
}
fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
+ #debug["kind::check_expr(%s)", expr_to_str(e)];
alt e.node {
expr_assign(_, ex) | expr_assign_op(_, _, ex) |
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
}
}
}
- found_something |= lookup_glob_any(e, _mod, vi.span, ident,
- export_id);
+ /*
+ This code previously used bitwise or (|=) but that was wrong,
+ because we need or to be lazy here. If something was already
+ found, we don't want to call lookup_glob_any (see #2316 for
+ what happens if we do)
+ */
+ found_something = found_something ||
+ lookup_glob_any(e, _mod, vi.span, ident, export_id);
if !found_something {
e.sess.span_warn(vi.span,
#fmt("exported item %s is not defined", ident));
export expr_is_lval;
export field_ty;
export fold_ty, fold_sty_to_ty, fold_region, fold_regions, fold_ty_var;
-export fold_regions_and_ty;
+export fold_regions_and_ty, walk_regions_and_ty;
export field;
export field_idx;
export get_field;
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_var, mk_var, type_is_var;
export ty_self, mk_self;
export region, bound_region;
export get, type_has_params, type_has_vars, type_has_regions;
}
}
+fn walk_regions_and_ty(
+ cx: ctxt,
+ ty: t,
+ walkr: fn(r: region),
+ walkt: fn(t: t) -> bool) {
+
+ if (walkt(ty)) {
+ fold_regions_and_ty(
+ cx, ty,
+ { |r| walkr(r); r },
+ { |t| walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t },
+ { |t| walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t });
+ }
+}
+
fn fold_regions_and_ty(
cx: ctxt,
ty: t,
fn type_is_bot(ty: t) -> bool { get(ty).struct == ty_bot }
+fn type_is_var(ty: t) -> bool {
+ alt get(ty).struct {
+ ty_var(_) { true }
+ _ { false }
+ }
+}
+
fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool }
fn type_is_structural(ty: t) -> bool {
ty_var_counter: @mut uint,
region_var_counter: @mut uint,
+ mut blocks: [ast::node_id], // stack of blocks in scope, may be empty
in_scope_regions: isr_alist,
// While type checking a function, the intermediate types for the
// Type tests
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
- alt infer::resolve_shallow(fcx.infcx, tp, true) {
- // note: the bot type doesn't count as resolved; it's what we use when
- // there is no information about a variable.
- result::ok(t_s) if !ty::type_is_bot(t_s) { ret t_s; }
+ alt infer::resolve_shallow(fcx.infcx, tp, false) {
+ result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
_ {
fcx.ccx.tcx.sess.span_fatal
(sp, "the type of this value must be known in this context");
ast::vstore_uniq { ty::vstore_uniq }
ast::vstore_box { ty::vstore_box }
ast::vstore_slice(r) {
- ty::vstore_slice(ast_region_to_region(fcx, fcx, e.span, r))
+ alt fcx.block_region() {
+ result::ok(b_r) {
+ let rscope = in_anon_rscope(fcx, b_r);
+ ty::vstore_slice(ast_region_to_region(fcx, rscope, e.span, r))
+ }
+ result::err(msg) {
+ fcx.ccx.tcx.sess.span_err(e.span, msg);
+ ty::vstore_slice(ty::re_static)
+ }
+ }
}
}
}
fn anon_region() -> result<ty::region, str> {
result::err("region types are not allowed here")
}
- fn named_region(_id: str) -> result<ty::region, str> {
- result::err("region types are not allowed here")
+ fn named_region(id: str) -> result<ty::region, str> {
+ if id == "static" { result::ok(ty::re_static) }
+ else { result::err("only the static region is allowed here") }
}
}
impl of region_scope for type_rscope {
fn anon_region() -> result<ty::region, str> {
alt *self {
- ast::rp_self {
- result::ok(ty::re_bound(ty::br_self))
- }
+ ast::rp_self { result::ok(ty::re_bound(ty::br_self)) }
ast::rp_none {
result::err("to use region types here, the containing type \
must be declared with a region bound")
}
}
fn named_region(id: str) -> result<ty::region, str> {
- if id == "self" {
- self.anon_region()
- } else {
- result::err("named regions other than `self` are not \
- allowed as part of a type declaration")
+ empty_rscope.named_region(id).chain_err { |_e|
+ if id == "self" { self.anon_region() }
+ else {
+ result::err("named regions other than `self` are not \
+ allowed as part of a type declaration")
+ }
}
}
}
result::ok(self.next_region_var())
}
fn named_region(id: str) -> result<ty::region, str> {
- alt self.in_scope_regions.find(ty::br_named(id)) {
- some(r) { result::ok(r) }
- none {
- result::err(#fmt["named region `%s` not in scope here", id])
- }
+ empty_rscope.named_region(id).chain_err { |_e|
+ alt self.in_scope_regions.find(ty::br_named(id)) {
+ some(r) { result::ok(r) }
+ none if id == "blk" { self.block_region() }
+ none {
+ result::err(#fmt["named region `%s` not in scope here", id])
+ }
+ }
}
}
}
let res = alt a_r.node {
ast::re_anon { rscope.anon_region() }
ast::re_named(id) { rscope.named_region(id) }
- ast::re_static { result::ok(ty::re_static) }
};
get_region_reporting_err(self.tcx(), span, res)
ret typ;
}
+fn check_bounds_are_used(ccx: @crate_ctxt,
+ span: span,
+ tps: [ast::ty_param],
+ rp: ast::region_param,
+ ty: ty::t) {
+ let mut r_used = alt rp {
+ ast::rp_self { false }
+ ast::rp_none { true }
+ };
+
+ if tps.len() == 0u && r_used { ret; }
+ let tps_used = vec::to_mut(vec::from_elem(tps.len(), false));
+
+ ty::walk_regions_and_ty(
+ ccx.tcx, ty,
+ { |r|
+ alt r {
+ ty::re_bound(_) { r_used = true; }
+ _ { }
+ }
+ },
+ { |t|
+ alt ty::get(t).struct {
+ ty::ty_param(idx, _) { tps_used[idx] = true; }
+ _ { }
+ }
+ true
+ });
+
+ if !r_used {
+ ccx.tcx.sess.span_err(
+ span, "lifetime `self` unused inside \
+ reference-parameterized type.");
+ }
+
+ for tps_used.eachi { |i, b|
+ if !b {
+ ccx.tcx.sess.span_err(
+ span, #fmt["Type parameter %s is unused.", tps[i].ident]);
+ }
+ }
+}
+
fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
-> ty::ty_param_bounds_and_ty {
};
{bounds: ty_param_bounds(ccx, tps), rp: rp, ty: ty}
};
+
+ check_bounds_are_used(ccx, t.span, tps, rp, tpt.ty);
+
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
fn ty_to_str(t: ty::t) -> str {
ty_to_str(self.ccx.tcx, resolve_type_vars_if_possible(self, t))
}
+ fn block_region() -> result<ty::region, str> {
+ alt vec::last_opt(self.blocks) {
+ some(bid) { result::ok(ty::re_scope(bid)) }
+ none { result::err("no block is in scope here") }
+ }
+ }
fn write_ty(node_id: ast::node_id, ty: ty::t) {
#debug["write_ty(%d, %s) in fcx %s",
node_id, ty_to_str(self.tcx(), ty), self.tag()];
-> option<O> {
alt expected {
some(t) {
- alt infer::resolve_shallow(fcx.infcx, t, true) {
+ alt infer::resolve_shallow(fcx.infcx, t, false) {
result::ok(t) { unpack(ty::get(t).struct) }
_ { none }
}
ast::unsafe_blk { @{purity: ast::unsafe_fn with *fcx0} }
ast::default_blk { fcx0 }
};
+ vec::push(fcx.blocks, blk.node.id);
let mut bot = false;
let mut warned = false;
for blk.node.stmts.each {|s|
if bot {
fcx.write_bot(blk.node.id);
}
+ vec::pop(fcx.blocks);
ret bot;
}
locals: int_hash(),
ty_var_counter: @mut 0u,
region_var_counter: @mut 0u,
+ mut blocks: [],
in_scope_regions: @nil,
node_types: smallintmap::mk(),
node_type_substs: map::int_hash(),
locals: int_hash(),
ty_var_counter: @mut 0u,
region_var_counter: @mut 0u,
+ mut blocks: [],
in_scope_regions: @nil,
node_types: smallintmap::mk(),
node_type_substs: map::int_hash(),
locals: locals,
ty_var_counter: tvc,
region_var_counter: rvc,
+ mut blocks: [],
in_scope_regions: isr,
node_types: node_types,
node_type_substs: node_type_substs,
visit::visit_pat(p, e, v);
};
+ let visit_block = fn@(b: ast::blk, &&e: (), v: visit::vt<()>) {
+ vec::push(fcx.blocks, b.node.id);
+ visit::visit_block(b, e, v);
+ vec::pop(fcx.blocks);
+ };
+
// 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_fn(_fk: visit::fn_kind, _decl: ast::fn_decl,
+ _body: ast::blk, _sp: span,
+ _id: ast::node_id, &&_t: (), _v: visit::vt<()>) {
}
- fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { }
+ fn visit_item(_i: @ast::item, &&_e: (), _v: visit::vt<()>) { }
- let visit =
- @{visit_local: visit_local,
- visit_pat: visit_pat,
- visit_fn: bind visit_fn(_, _, _, _, _, _, _),
- visit_item: bind visit_item(_, _, _)
- with *visit::default_visitor()};
+ let visit = visit::mk_vt(@{visit_local: visit_local,
+ visit_pat: visit_pat,
+ visit_fn: visit_fn,
+ visit_item: visit_item,
+ visit_block: visit_block
+ with *visit::default_visitor()});
- visit::visit_block(body, (), visit::mk_vt(visit));
+ visit.visit_block(body, (), visit);
}
}
const Target *TheTarget = TargetRegistry::lookupTarget(triple, Err);
std::string FeaturesStr;
std::string Trip(triple);
- std::string CPUStr = llvm::sys::getHostCPUName();
+ std::string CPUStr("generic");
TargetMachine *Target =
TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr,
Options, Reloc::PIC_,
--- /dev/null
+enum cat {
+ tabby, calico, tortoiseshell
+}
--- /dev/null
+use issue_2316_a;
+
+mod cloth {
+
+import issue_2316_a::*;
+
+export calico, gingham, flannel;
+export fabric;
+
+enum fabric {
+ gingham, flannel, calico
+}
+
+}
+
+
--- /dev/null
+// Issue #1763 - infer types correctly
+
+type actor<T> = { //! ERROR Type parameter T is unused.
+ unused: bool
+};
+
+fn main() {}
fn main(s: [str]) {
- let a = [];
+ let a: [int] = [];
vec::each(a) { |x| //! ERROR in function `anon`, not all control paths
} //! ERROR see function return type of `bool`
}
--- /dev/null
+type foo/& = {f: int}; //! ERROR lifetime `self` unused
+
+fn main() {}
\ No newline at end of file
--- /dev/null
+fn foo(cond: bool) {
+ let x = 5;
+ let mut y: &blk.int = &x;
+
+ let mut z: &blk.int;
+ if cond {
+ z = &x;
+ } else {
+ let w: &blk.int = &x;
+ z = w; //! ERROR mismatched types
+ }
+}
+
+fn main() {
+}
\ No newline at end of file
--- /dev/null
+// xfail-test
+
+const c_x: &blk.int = 22; //! ERROR only the static region is allowed here
+const c_y: &static.int = &22; //! ERROR only the static region is allowed here
+
+fn main() {
+}
\ No newline at end of file
x: &self.uint
};
-type item_ty_yes2/& = {
+type item_ty_yes2/& = { //! ERROR lifetime `self` unused inside reference-parameterized type
x: &foo.uint //! ERROR named regions other than `self` are not allowed as part of a type declaration
};
--- /dev/null
+// xfail-test
+
+fn foo(cond: bool) {
+ // Here we will infer a type that uses the
+ // region of the if stmt then block, but in the scope:
+ let mut x; //! ERROR foo
+
+ if cond {
+ x = [1,2,3]/&blk;
+ }
+}
+
+fn main() {}
\ No newline at end of file
--- /dev/null
+// xfail-test
+
+fn foo(cond: bool) {
+ // Here we will infer a type that uses the
+ // region of the if stmt then block:
+ let mut x; //! ERROR foo
+
+ if cond {
+ x = &3;
+ }
+}
+
+fn main() {}
\ No newline at end of file
+++ /dev/null
-// xfail-pretty
-
-fn id(x: bool) -> bool { x }
-
-fn call_id() {
- let c <- fail;
- id(c); //! WARNING unreachable statement
-}
-
-fn call_id_3() { id(ret) && id(ret); }
- //!^ ERROR the type of this value must be known
-
-fn main() {
-}
log(debug, data);
fail;
}
-type _chan<T> = int;
+
+enum _chan<T> = int;
// Tests that "log(debug, message);" is flagged as using
// message after the send deinitializes it
--- /dev/null
+fn main() {
+ let _foo = []; //! ERROR unconstrained type
+}
type task_id = int;
type port_id = int;
-type chan_t<T: send> = {task: task_id, port: port_id};
+enum chan_t<T: send> = {task: task_id, port: port_id};
fn send<T: send>(ch: chan_t<T>, -data: T) { fail; }
+++ /dev/null
-// Issue #1763 - infer types correctly
-// error-pattern:explicit failure
-
-type actor<T> = {
- unused: bool
-};
-
-fn act2<T>() -> actor<T> {
- fail;
-}
-
-fn main() {
- let a: actor<int> = act2();
-}
// error-pattern:get called on error result: "kitty"
fn main() {
- log(error, result::get(result::err("kitty")));
+ log(error, result::get(result::err::<int,str>("kitty")));
}
\ No newline at end of file
+// xfail-test
+
// xfail-fast
// aux-build:cci_class_6.rs
use cci_class_6;
--- /dev/null
+// xfail-fast - check-fast doesn't understand aux-build
+// aux-build:issue_2316_a.rs
+// aux-build:issue_2316_b.rs
+
+use issue_2316_b;
+import issue_2316_b::cloth;
+
+fn main() {
+ let _c: cloth::fabric = cloth::calico;
+}
\ No newline at end of file
--- /dev/null
+use rustc;
+import rustc::middle::ty;
+fn main() {
+ let _t: ty::sty = rustc::middle::ty::ty_nil;
+}
fn main() {
assert [1u, 3u].to_vec() == [1u, 3u];
- assert [].to_vec() == [];
- assert none.to_vec() == [];
+ let e: [uint] = [];
+ assert e.to_vec() == [];
+ assert none::<uint>.to_vec() == [];
assert some(1u).to_vec() == [1u];
assert some(2u).to_vec() == [2u];
}
\ No newline at end of file
};
fn alloc(_bcx : &a.arena) -> &a.bcx unsafe {
- ret unsafe::reinterpret_cast(libc::malloc(sys::size_of::<bcx>()));
+ ret unsafe::reinterpret_cast(libc::malloc(sys::size_of::<bcx/&blk>()));
}
fn h(bcx : &a.bcx) -> &a.bcx {
--- /dev/null
+// xfail-pretty
+
+fn id(x: bool) -> bool { x }
+
+fn call_id() {
+ let c <- fail;
+ id(c); //! WARNING unreachable statement
+}
+
+fn call_id_3() { id(ret) && id(ret); }
+
+fn main() {
+}
+++ /dev/null
-// xfail-pretty
-
-fn id(x: bool) -> bool { x }
-
-fn call_id() {
- let c <- fail;
- id(c);
-}
-
-fn call_id_2() { id(true) && id(ret); }
-
-fn call_id_4() { while id(ret) { } }
-
-fn bind_id_1() { bind id(fail); }
-
-fn bind_id_2() { bind id(ret); }
-
-fn fail_fail() { fail fail; }
-
-fn log_fail() { log(error, fail); }
-
-fn log_ret() { log(error, ret); }
-
-fn log_break() { loop { log(error, break); } }
-
-fn log_cont() { do { log(error, cont); } while false }
-
-fn ret_ret() -> int { ret 3 + (ret 2); }
-
-fn ret_guard() {
- alt check 2 {
- x if (ret) { x; }
- }
-}
-
-fn rec_ret() { let _r: {c: int} = {c: ret}; }
-
-fn vec_ret() { let _v: [int] = [1, 2, ret, 4]; }
-
-fn fail_then_concat() {
- let mut x = [], y = [3];
- fail;
- x += y;
- "good" + "bye";
-}
-
-fn main() {
- // Call the functions that don't fail.
- rec_ret();
- vec_ret();
- ret_ret();
- log_ret();
- call_id_2();
- call_id_4();
- bind_id_2();
- ret_guard();
-}
+++ /dev/null
-fn main() {
- // We will infer this to have the type vec[bot]
- let _foo = [];
-}
// Just a grab bag of stuff that you wouldn't want to actually write.
-fn strange() -> bool { let _x = ret true; }
+fn strange() -> bool { let _x: bool = ret true; }
fn funny() {
fn f(_x: ()) { }
while (ret) {
if (ret) {
alt (ret) {
- _ {
+ 1 {
if (ret) {
ret
} else {
ret
}
}
+ _ { ret }
};
} else if (ret) {
ret;
pure fn p() -> bool { true }
let _a = (assert (true)) == (check (p()));
let _c = (check (p())) == ();
- let _b = (log(debug, 0) == (ret 0u));
+ let _b: bool = (log(debug, 0) == (ret 0u));
}
fn angrydome() {