diff --git a/src/etc/tidy.py b/src/etc/tidy.py index e866d80062d51..65737c53e613f 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -23,6 +23,11 @@ def report_error_name_no(name, no, s): def report_err(s): report_error_name_no(fileinput.filename(), fileinput.filelineno(), s) +def report_warn(s): + print("%s:%d: %s" % (fileinput.filename(), + fileinput.filelineno(), + s)) + def do_license_check(name, contents): if not check_license(name, contents): report_error_name_no(name, 1, "incorrect license") @@ -44,6 +49,9 @@ def do_license_check(name, contents): report_err("FIXME without issue number") if line.find("TODO") != -1: report_err("TODO is deprecated; use FIXME") + idx = line.find("// NOTE") + if idx != -1: + report_warn("NOTE:" + line[idx + len("// NOTE"):]) if (line.find('\t') != -1 and fileinput.filename().find("Makefile") == -1): report_err("tab character") diff --git a/src/libcargo/cargo.rc b/src/libcargo/cargo.rc index efbb9a929d2df..c11e1ec010f3f 100644 --- a/src/libcargo/cargo.rc +++ b/src/libcargo/cargo.rc @@ -35,6 +35,7 @@ #[allow(non_camel_case_types)]; #[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; +#[allow(deprecated_self)]; extern mod core(vers = "0.6"); extern mod std(vers = "0.6"); diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f7a65ed1fe442..1ac0bf4c0c5c0 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -52,6 +52,7 @@ Implicitly, all crates behave as if they included the following prologue: #[warn(deprecated_pattern)]; #[warn(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; +#[allow(deprecated_self)]; /* The Prelude. */ diff --git a/src/libcore/gc.rs b/src/libcore/gc.rs index 698e264b57a65..181a9d0888d43 100644 --- a/src/libcore/gc.rs +++ b/src/libcore/gc.rs @@ -40,6 +40,7 @@ with destructors. #[forbid(deprecated_pattern)]; use cast; +use container::{Container, Mutable, Map, Set}; use io; use libc::{size_t, uintptr_t}; use option::{None, Option, Some}; diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index ab1c9832d460e..a22b21a1e2acf 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -16,7 +16,6 @@ use cmp::Eq; use hash::Hash; -use prelude::*; use to_bytes::IterBytes; /// Open addressing with linear probing. @@ -36,13 +35,13 @@ pub mod linear { const INITIAL_CAPACITY: uint = 32u; // 2^5 - struct Bucket { + struct Bucket { hash: uint, key: K, value: V, } - pub struct LinearMap { + pub struct LinearMap { k0: u64, k1: u64, resize_at: uint, @@ -424,7 +423,7 @@ pub mod linear { pure fn ne(&self, other: &LinearMap) -> bool { !self.eq(other) } } - pub struct LinearSet { + pub struct LinearSet { priv map: LinearMap } @@ -479,6 +478,7 @@ pub mod linear { #[test] pub mod test { + use container::{Container, Mutable, Map, Set}; use option::{None, Some}; use hashmap::linear::LinearMap; use hashmap::linear; diff --git a/src/libcore/io.rs b/src/libcore/io.rs index fedcb9511960e..933c38b5499b5 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -1111,7 +1111,7 @@ pub mod fsync { // Artifacts that need to fsync on destruction - pub struct Res { + pub struct Res { arg: Arg, } diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index ecd48fe16bc35..a1107d49c0ec1 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -1123,10 +1123,23 @@ pub mod funcs { unsafe fn strerror(n: c_int) -> *c_char; unsafe fn strtok(s: *c_char, t: *c_char) -> *c_char; unsafe fn strxfrm(s: *c_char, ct: *c_char, n: size_t) -> size_t; + + // These are fine to execute on the Rust stack. They must be, in + // fact, because LLVM generates calls to them! + #[rust_stack] + #[inline(always)] unsafe fn memcpy(s: *c_void, ct: *c_void, n: size_t) -> *c_void; + #[rust_stack] + #[inline(always)] unsafe fn memmove(s: *c_void, ct: *c_void, n: size_t) -> *c_void; + #[rust_stack] + #[inline(always)] unsafe fn memcmp(cx: *c_void, ct: *c_void, n: size_t) -> c_int; + #[rust_stack] + #[inline(always)] unsafe fn memchr(cx: *c_void, c: c_int, n: size_t) -> *c_void; + #[rust_stack] + #[inline(always)] unsafe fn memset(s: *c_void, c: c_int, n: size_t) -> *c_void; } } diff --git a/src/libcore/num.rs b/src/libcore/num.rs index 4c2daa458a48d..6eb22e53a2413 100644 --- a/src/libcore/num.rs +++ b/src/libcore/num.rs @@ -23,6 +23,11 @@ pub trait Num { static pure fn from_int(n: int) -> self; } +pub trait IntConvertible { + pure fn to_int(&self) -> int; + static pure fn from_int(n: int) -> self; +} + pub trait Zero { static pure fn zero() -> self; } diff --git a/src/libcore/oldcomm.rs b/src/libcore/oldcomm.rs index c221df293dcdb..1473aa6da0782 100644 --- a/src/libcore/oldcomm.rs +++ b/src/libcore/oldcomm.rs @@ -68,7 +68,7 @@ use vec; * transmitted. If a port value is copied, both copies refer to the same * port. Ports may be associated with multiple `chan`s. */ -pub enum Port { +pub enum Port { Port_(@PortPtr) } @@ -84,7 +84,7 @@ pub enum Port { * data will be silently dropped. Channels may be duplicated and * themselves transmitted over other channels. */ -pub enum Chan { +pub enum Chan { Chan_(port_id) } @@ -120,7 +120,7 @@ pub fn listen(f: fn(Chan) -> U) -> U { f(po.chan()) } -struct PortPtr { +struct PortPtr { po: *rust_port, drop { unsafe { @@ -238,7 +238,7 @@ fn peek_chan(ch: Chan) -> bool { } /// Receive on a raw port pointer -fn recv_(p: *rust_port) -> T { +fn recv_(p: *rust_port) -> T { unsafe { let yield = 0; let yieldp = ptr::addr_of(&yield); diff --git a/src/libcore/os.rs b/src/libcore/os.rs index cf86f45379ca2..6f568e9b2a708 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -141,169 +141,101 @@ pub mod win32 { } } -pub fn getenv(n: &str) -> Option<~str> { - global_env::getenv(n) -} +/* +Accessing environment variables is not generally threadsafe. +This uses a per-runtime lock to serialize access. +XXX: It would probably be appropriate to make this a real global +*/ +fn with_env_lock(f: &fn() -> T) -> T { + use private::global::global_data_clone_create; + use private::{Exclusive, exclusive}; + + struct SharedValue(()); + type ValueMutex = Exclusive; + fn key(_: ValueMutex) { } -pub fn setenv(n: &str, v: &str) { - global_env::setenv(n, v) -} + unsafe { + let lock: ValueMutex = global_data_clone_create(key, || { + ~exclusive(SharedValue(())) + }); -pub fn env() -> ~[(~str,~str)] { - global_env::env() + lock.with_imm(|_| f() ) + } } -mod global_env { - //! Internal module for serializing access to getenv/setenv - use either; - use libc; - use oldcomm; - use option::Option; - use private; - use str; - use task; - +pub fn env() -> ~[(~str,~str)] { extern mod rustrt { - unsafe fn rust_global_env_chan_ptr() -> *libc::uintptr_t; - } - - enum Msg { - MsgGetEnv(~str, oldcomm::Chan>), - MsgSetEnv(~str, ~str, oldcomm::Chan<()>), - MsgEnv(oldcomm::Chan<~[(~str,~str)]>) - } - - pub fn getenv(n: &str) -> Option<~str> { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgGetEnv(str::from_slice(n), - oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - pub fn setenv(n: &str, v: &str) { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgSetEnv(str::from_slice(n), - str::from_slice(v), - oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - pub fn env() -> ~[(~str,~str)] { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgEnv(oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - fn get_global_env_chan() -> oldcomm::Chan { - unsafe { - let global_ptr = rustrt::rust_global_env_chan_ptr(); - private::chan_from_global_ptr(global_ptr, || { - // FIXME (#2621): This would be a good place to use a very - // small foreign stack - task::task().sched_mode(task::SingleThreaded).unlinked() - }, global_env_task) - } + unsafe fn rust_env_pairs() -> ~[~str]; } - fn global_env_task(msg_po: oldcomm::Port) { - unsafe { - do private::weaken_task |weak_po| { - loop { - match oldcomm::select2(msg_po, weak_po) { - either::Left(MsgGetEnv(ref n, resp_ch)) => { - oldcomm::send(resp_ch, impl_::getenv(*n)) - } - either::Left(MsgSetEnv(ref n, ref v, resp_ch)) => { - oldcomm::send(resp_ch, impl_::setenv(*n, *v)) - } - either::Left(MsgEnv(resp_ch)) => { - oldcomm::send(resp_ch, impl_::env()) - } - either::Right(_) => break - } - } + unsafe { + do with_env_lock { + let mut pairs = ~[]; + for vec::each(rustrt::rust_env_pairs()) |p| { + let vs = str::splitn_char(*p, '=', 1u); + assert vec::len(vs) == 2u; + pairs.push((copy vs[0], copy vs[1])); } + move pairs } } +} - mod impl_ { - use cast; - use libc; - use option::Option; - use option; - use ptr; - use str; - use vec; - - extern mod rustrt { - unsafe fn rust_env_pairs() -> ~[~str]; - } - - pub fn env() -> ~[(~str,~str)] { - unsafe { - let mut pairs = ~[]; - for vec::each(rustrt::rust_env_pairs()) |p| { - let vs = str::splitn_char(*p, '=', 1u); - assert vec::len(vs) == 2u; - pairs.push((copy vs[0], copy vs[1])); - } - move pairs - } - } - - #[cfg(unix)] - pub fn getenv(n: &str) -> Option<~str> { - unsafe { - let s = str::as_c_str(n, |s| libc::getenv(s)); - return if ptr::null::() == cast::reinterpret_cast(&s) { - option::None::<~str> - } else { - let s = cast::reinterpret_cast(&s); - option::Some::<~str>(str::raw::from_buf(s)) - }; +#[cfg(unix)] +pub fn getenv(n: &str) -> Option<~str> { + unsafe { + do with_env_lock { + let s = str::as_c_str(n, |s| libc::getenv(s)); + if ptr::null::() == cast::reinterpret_cast(&s) { + option::None::<~str> + } else { + let s = cast::reinterpret_cast(&s); + option::Some::<~str>(str::raw::from_buf(s)) } } + } +} - #[cfg(windows)] - pub fn getenv(n: &str) -> Option<~str> { - unsafe { - use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; - do as_utf16_p(n) |u| { - do fill_utf16_buf_and_decode() |buf, sz| { - libc::GetEnvironmentVariableW(u, buf, sz) - } +#[cfg(windows)] +pub fn getenv(n: &str) -> Option<~str> { + unsafe { + do with_env_lock { + use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; + do as_utf16_p(n) |u| { + do fill_utf16_buf_and_decode() |buf, sz| { + libc::GetEnvironmentVariableW(u, buf, sz) } } } + } +} - #[cfg(unix)] - pub fn setenv(n: &str, v: &str) { - unsafe { - do str::as_c_str(n) |nbuf| { - do str::as_c_str(v) |vbuf| { - libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); - } +#[cfg(unix)] +pub fn setenv(n: &str, v: &str) { + unsafe { + do with_env_lock { + do str::as_c_str(n) |nbuf| { + do str::as_c_str(v) |vbuf| { + libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); } } } + } +} - #[cfg(windows)] - pub fn setenv(n: &str, v: &str) { - unsafe { - use os::win32::as_utf16_p; - do as_utf16_p(n) |nbuf| { - do as_utf16_p(v) |vbuf| { - libc::SetEnvironmentVariableW(nbuf, vbuf); - } +#[cfg(windows)] +pub fn setenv(n: &str, v: &str) { + unsafe { + do with_env_lock { + use os::win32::as_utf16_p; + do as_utf16_p(n) |nbuf| { + do as_utf16_p(v) |vbuf| { + libc::SetEnvironmentVariableW(nbuf, vbuf); } } } - } } diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 0ef30668dbce1..20a2cadaa2bd5 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -93,10 +93,9 @@ use either::{Either, Left, Right}; use kinds::Owned; use libc; use option; -use option::unwrap; +use option::{None, Option, Some, unwrap}; use pipes; use ptr; -use prelude::*; use private; use task; use vec; @@ -149,7 +148,7 @@ type Buffer = { #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] -pub struct Buffer { +pub struct Buffer { header: BufferHeader, data: T, } @@ -210,10 +209,18 @@ impl PacketHeader { } #[doc(hidden)] +#[cfg(stage0)] pub struct Packet { header: PacketHeader, mut payload: Option, } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub struct Packet { + header: PacketHeader, + mut payload: Option, +} #[doc(hidden)] pub trait HasBuffer { @@ -254,12 +261,11 @@ fn unibuffer() -> ~Buffer> { } move b } - #[doc(hidden)] #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] -fn unibuffer() -> ~Buffer> { +fn unibuffer() -> ~Buffer> { let b = ~Buffer { header: BufferHeader(), data: Packet { @@ -275,6 +281,7 @@ fn unibuffer() -> ~Buffer> { } #[doc(hidden)] +#[cfg(stage0)] pub fn packet() -> *Packet { let b = unibuffer(); let p = ptr::addr_of(&(b.data)); @@ -282,6 +289,16 @@ pub fn packet() -> *Packet { unsafe { forget(move b) } p } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn packet() -> *Packet { + let b = unibuffer(); + let p = ptr::addr_of(&(b.data)); + // We'll take over memory management from here. + unsafe { forget(move b) } + p +} #[doc(hidden)] pub fn entangle_buffer( @@ -385,11 +402,19 @@ fn swap_state_rel(dst: &mut State, src: State) -> State { } #[doc(hidden)] +#[cfg(stage0)] pub unsafe fn get_buffer(p: *PacketHeader) -> ~Buffer { transmute((*p).buf_header()) } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub unsafe fn get_buffer(p: *PacketHeader) -> ~Buffer { + transmute((*p).buf_header()) +} // This could probably be done with SharedMutableState to avoid move_it!(). +#[cfg(stage0)] struct BufferResource { buffer: ~Buffer, @@ -411,7 +436,31 @@ struct BufferResource { } } } +#[cfg(stage1)] +#[cfg(stage2)] +struct BufferResource { + buffer: ~Buffer, + + drop { + unsafe { + let b = move_it!(self.buffer); + //let p = ptr::addr_of(*b); + //error!("drop %?", p); + let old_count = atomic_sub_rel(&mut b.header.ref_count, 1); + //let old_count = atomic_xchng_rel(b.header.ref_count, 0); + if old_count == 1 { + // The new count is 0. + + // go go gadget drop glue + } + else { + forget(move b) + } + } + } +} +#[cfg(stage0)] fn BufferResource(b: ~Buffer) -> BufferResource { //let p = ptr::addr_of(*b); //error!("take %?", p); @@ -422,8 +471,21 @@ fn BufferResource(b: ~Buffer) -> BufferResource { buffer: move b } } +#[cfg(stage1)] +#[cfg(stage2)] +fn BufferResource(b: ~Buffer) -> BufferResource { + //let p = ptr::addr_of(*b); + //error!("take %?", p); + atomic_add_acq(&mut b.header.ref_count, 1); + + BufferResource { + // tjc: ???? + buffer: move b + } +} #[doc(hidden)] +#[cfg(stage0)] pub fn send(p: SendPacketBuffered, payload: T) -> bool { let header = p.header(); @@ -465,6 +527,49 @@ pub fn send(p: SendPacketBuffered, } } } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn send(p: SendPacketBuffered, payload: T) -> bool { + let header = p.header(); + let p_ = p.unwrap(); + let p = unsafe { &*p_ }; + assert ptr::addr_of(&(p.header)) == header; + assert p.payload.is_none(); + p.payload = move Some(move payload); + let old_state = swap_state_rel(&mut p.header.state, Full); + match old_state { + Empty => { + // Yay, fastpath. + + // The receiver will eventually clean this up. + //unsafe { forget(p); } + return true; + } + Full => fail ~"duplicate send", + Blocked => { + debug!("waking up task for %?", p_); + let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); + if !old_task.is_null() { + unsafe { + rustrt::task_signal_event( + old_task, + ptr::addr_of(&(p.header)) as *libc::c_void); + rustrt::rust_task_deref(old_task); + } + } + + // The receiver will eventually clean this up. + //unsafe { forget(p); } + return true; + } + Terminated => { + // The receiver will never receive this. Rely on drop_glue + // to clean everything up. + return false; + } + } +} /** Receives a message from a pipe. @@ -810,13 +915,24 @@ pub fn select(endpoints: ~[RecvPacketBuffered]) message. */ +#[cfg(stage0)] pub type SendPacket = SendPacketBuffered>; +#[cfg(stage1)] +#[cfg(stage2)] +pub type SendPacket = SendPacketBuffered>; #[doc(hidden)] +#[cfg(stage0)] pub fn SendPacket(p: *Packet) -> SendPacket { SendPacketBuffered(p) } +#[cfg(stage1)] +#[cfg(stage2)] +pub fn SendPacket(p: *Packet) -> SendPacket { + SendPacketBuffered(p) +} +#[cfg(stage0)] pub struct SendPacketBuffered { mut p: Option<*Packet>, mut buffer: Option>, @@ -835,7 +951,31 @@ pub struct SendPacketBuffered { // } else { "some" }); } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub struct SendPacketBuffered { + mut p: Option<*Packet>, + mut buffer: Option>, +} +impl SendPacketBuffered : ::ops::Drop { + fn finalize(&self) { + //if self.p != none { + // debug!("drop send %?", option::get(self.p)); + //} + if self.p != None { + let mut p = None; + p <-> self.p; + sender_terminate(option::unwrap(move p)) + } + //unsafe { error!("send_drop: %?", + // if self.buffer == none { + // "none" + // } else { "some" }); } + } +} + +#[cfg(stage0)] pub fn SendPacketBuffered(p: *Packet) -> SendPacketBuffered { //debug!("take send %?", p); @@ -847,8 +987,50 @@ pub fn SendPacketBuffered(p: *Packet) } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub fn SendPacketBuffered(p: *Packet) + -> SendPacketBuffered { + //debug!("take send %?", p); + SendPacketBuffered { + p: Some(p), + buffer: unsafe { + Some(BufferResource( + get_buffer(ptr::addr_of(&((*p).header))))) + } + } +} -impl SendPacketBuffered { +#[cfg(stage0)] +impl SendPacketBuffered { + fn unwrap() -> *Packet { + let mut p = None; + p <-> self.p; + option::unwrap(move p) + } + + pure fn header() -> *PacketHeader { + match self.p { + Some(packet) => unsafe { + let packet = &*packet; + let header = ptr::addr_of(&(packet.header)); + //forget(packet); + header + }, + None => fail ~"packet already consumed" + } + } + + fn reuse_buffer() -> BufferResource { + //error!("send reuse_buffer"); + let mut tmp = None; + tmp <-> self.buffer; + option::unwrap(move tmp) + } +} +#[cfg(stage1)] +#[cfg(stage2)] +impl SendPacketBuffered { fn unwrap() -> *Packet { let mut p = None; p <-> self.p; @@ -877,13 +1059,25 @@ impl SendPacketBuffered { /// Represents the receive end of a pipe. It can receive exactly one /// message. +#[cfg(stage0)] pub type RecvPacket = RecvPacketBuffered>; +#[cfg(stage1)] +#[cfg(stage2)] +pub type RecvPacket = RecvPacketBuffered>; #[doc(hidden)] +#[cfg(stage0)] pub fn RecvPacket(p: *Packet) -> RecvPacket { RecvPacketBuffered(p) } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn RecvPacket(p: *Packet) -> RecvPacket { + RecvPacketBuffered(p) +} +#[cfg(stage0)] pub struct RecvPacketBuffered { mut p: Option<*Packet>, mut buffer: Option>, @@ -902,6 +1096,29 @@ pub struct RecvPacketBuffered { // } else { "some" }); } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub struct RecvPacketBuffered { + mut p: Option<*Packet>, + mut buffer: Option>, +} + +impl RecvPacketBuffered : ::ops::Drop { + fn finalize(&self) { + //if self.p != none { + // debug!("drop recv %?", option::get(self.p)); + //} + if self.p != None { + let mut p = None; + p <-> self.p; + receiver_terminate(option::unwrap(move p)) + } + //unsafe { error!("recv_drop: %?", + // if self.buffer == none { + // "none" + // } else { "some" }); } + } +} impl RecvPacketBuffered { fn unwrap() -> *Packet { @@ -932,6 +1149,7 @@ impl RecvPacketBuffered : Selectable { } } +#[cfg(stage0)] pub fn RecvPacketBuffered(p: *Packet) -> RecvPacketBuffered { //debug!("take recv %?", p); @@ -943,12 +1161,33 @@ pub fn RecvPacketBuffered(p: *Packet) } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub fn RecvPacketBuffered(p: *Packet) + -> RecvPacketBuffered { + //debug!("take recv %?", p); + RecvPacketBuffered { + p: Some(p), + buffer: unsafe { + Some(BufferResource( + get_buffer(ptr::addr_of(&((*p).header))))) + } + } +} #[doc(hidden)] +#[cfg(stage0)] pub fn entangle() -> (SendPacket, RecvPacket) { let p = packet(); (SendPacket(p), RecvPacket(p)) } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn entangle() -> (SendPacket, RecvPacket) { + let p = packet(); + (SendPacket(p), RecvPacket(p)) +} /** Spawn a task to provide a service. @@ -1040,24 +1279,50 @@ pub trait Peekable { } #[doc(hidden)] +#[cfg(stage0)] struct Chan_ { - mut endp: Option>, + mut endp: Option> +} +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +struct Chan_ { + mut endp: Option> } /// An endpoint that can send many messages. +#[cfg(stage0)] pub enum Chan { Chan_(Chan_) } +#[cfg(stage1)] +#[cfg(stage2)] +pub enum Chan { + Chan_(Chan_) +} #[doc(hidden)] +#[cfg(stage0)] struct Port_ { mut endp: Option>, } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +struct Port_ { + mut endp: Option>, +} /// An endpoint that can receive many messages. +#[cfg(stage0)] pub enum Port { Port_(Port_) } +#[cfg(stage1)] +#[cfg(stage2)] +pub enum Port { + Port_(Port_) +} /** Creates a `(chan, port)` pair. @@ -1143,9 +1408,15 @@ impl Port: Selectable { } /// Treat many ports as one. +#[cfg(stage0)] pub struct PortSet { mut ports: ~[pipes::Port], } +#[cfg(stage1)] +#[cfg(stage2)] +pub struct PortSet { + mut ports: ~[pipes::Port], +} pub fn PortSet() -> PortSet{ PortSet { @@ -1208,7 +1479,11 @@ impl PortSet : Peekable { } /// A channel that can be shared between many senders. +#[cfg(stage0)] pub type SharedChan = private::Exclusive>; +#[cfg(stage1)] +#[cfg(stage2)] +pub type SharedChan = private::Exclusive>; impl SharedChan: GenericChan { fn send(x: T) { @@ -1276,9 +1551,17 @@ proto! oneshot ( ) /// The send end of a oneshot pipe. +#[cfg(stage0)] pub type ChanOne = oneshot::client::Oneshot; +#[cfg(stage1)] +#[cfg(stage2)] +pub type ChanOne = oneshot::client::Oneshot; /// The receive end of a oneshot pipe. +#[cfg(stage0)] pub type PortOne = oneshot::server::Oneshot; +#[cfg(stage1)] +#[cfg(stage2)] +pub type PortOne = oneshot::server::Oneshot; /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. pub fn oneshot() -> (PortOne, ChanOne) { @@ -1286,6 +1569,16 @@ pub fn oneshot() -> (PortOne, ChanOne) { (port, chan) } +impl PortOne { + fn recv(self) -> T { recv_one(self) } + fn try_recv(self) -> Option { try_recv_one(self) } +} + +impl ChanOne { + fn send(self, data: T) { send_one(self, data) } + fn try_send(self, data: T) -> bool { try_send_one(self, data) } +} + /** * Receive a message from a oneshot pipe, failing if the connection was * closed. diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 72aa828ff12a7..d3813d1ae852e 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -35,6 +35,8 @@ pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; pub use vec::{OwnedVector, OwnedCopyableVector}; pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; +pub use container::{Container, Mutable, Map, Set}; +pub use pipes::{GenericChan, GenericPort}; pub use num::Num; pub use ptr::Ptr; diff --git a/src/libcore/private.rs b/src/libcore/private.rs index ad27729cc9fa6..b6ac711d7649c 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -18,7 +18,6 @@ use cast; use iter; use libc; -use oldcomm; use option; use pipes; use prelude::*; @@ -28,10 +27,17 @@ use task; use task::{TaskBuilder, atomically}; use uint; +#[path = "private/at_exit.rs"] +pub mod at_exit; +#[path = "private/global.rs"] +pub mod global; +#[path = "private/finally.rs"] +pub mod finally; +#[path = "private/weak_task.rs"] +pub mod weak_task; + extern mod rustrt { #[legacy_exports]; - unsafe fn rust_task_weaken(ch: rust_port_id); - unsafe fn rust_task_unweaken(ch: rust_port_id); unsafe fn rust_create_little_lock() -> rust_little_lock; unsafe fn rust_destroy_little_lock(lock: rust_little_lock); @@ -87,11 +93,6 @@ fn test_run_in_bare_thread() { } } -#[allow(non_camel_case_types)] // runtime type -type rust_port_id = uint; - -type GlobalPtr = *libc::uintptr_t; - fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { unsafe { let old = rusti::atomic_cxchg(address, oldval, newval); @@ -99,255 +100,6 @@ fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { } } -/** - * Atomically gets a channel from a pointer to a pointer-sized memory location - * or, if no channel exists creates and installs a new channel and sets up a - * new task to receive from it. - */ -pub unsafe fn chan_from_global_ptr( - global: GlobalPtr, - task_fn: fn() -> task::TaskBuilder, - f: fn~(oldcomm::Port) -) -> oldcomm::Chan { - - enum Msg { - Proceed, - Abort - } - - log(debug,~"ENTERING chan_from_global_ptr, before is_prob_zero check"); - let is_probably_zero = *global == 0u; - log(debug,~"after is_prob_zero check"); - if is_probably_zero { - log(debug,~"is probably zero..."); - // There's no global channel. We must make it - - let (setup1_po, setup1_ch) = pipes::stream(); - let (setup2_po, setup2_ch) = pipes::stream(); - - // FIXME #4422: Ugly type inference hint - let setup2_po: pipes::Port = setup2_po; - - do task_fn().spawn |move f, move setup1_ch, move setup2_po| { - let po = oldcomm::Port::(); - let ch = oldcomm::Chan(&po); - setup1_ch.send(ch); - - // Wait to hear if we are the official instance of - // this global task - match setup2_po.recv() { - Proceed => f(move po), - Abort => () - } - }; - - log(debug,~"before setup recv.."); - // This is the proposed global channel - let ch = setup1_po.recv(); - // 0 is our sentinal value. It is not a valid channel - assert *ch != 0; - - // Install the channel - log(debug,~"BEFORE COMPARE AND SWAP"); - let swapped = compare_and_swap( - cast::reinterpret_cast(&global), - 0, cast::reinterpret_cast(&ch)); - log(debug,fmt!("AFTER .. swapped? %?", swapped)); - - if swapped { - // Success! - setup2_ch.send(Proceed); - ch - } else { - // Somebody else got in before we did - setup2_ch.send(Abort); - cast::reinterpret_cast(&*global) - } - } else { - log(debug, ~"global != 0"); - cast::reinterpret_cast(&*global) - } -} - -#[test] -pub fn test_from_global_chan1() { - - // This is unreadable, right? - - // The global channel - let globchan = 0; - let globchanp = ptr::addr_of(&globchan); - - // Create the global channel, attached to a new task - let ch = unsafe { - do chan_from_global_ptr(globchanp, task::task) |po| { - let ch = oldcomm::recv(po); - oldcomm::send(ch, true); - let ch = oldcomm::recv(po); - oldcomm::send(ch, true); - } - }; - // Talk to it - let po = oldcomm::Port(); - oldcomm::send(ch, oldcomm::Chan(&po)); - assert oldcomm::recv(po) == true; - - // This one just reuses the previous channel - let ch = unsafe { - do chan_from_global_ptr(globchanp, task::task) |po| { - let ch = oldcomm::recv(po); - oldcomm::send(ch, false); - } - }; - - // Talk to the original global task - let po = oldcomm::Port(); - oldcomm::send(ch, oldcomm::Chan(&po)); - assert oldcomm::recv(po) == true; -} - -#[test] -pub fn test_from_global_chan2() { - - for iter::repeat(100) { - // The global channel - let globchan = 0; - let globchanp = ptr::addr_of(&globchan); - - let resultpo = oldcomm::Port(); - let resultch = oldcomm::Chan(&resultpo); - - // Spawn a bunch of tasks that all want to compete to - // create the global channel - for uint::range(0, 10) |i| { - do task::spawn { - let ch = unsafe { - do chan_from_global_ptr( - globchanp, task::task) |po| { - - for uint::range(0, 10) |_j| { - let ch = oldcomm::recv(po); - oldcomm::send(ch, {i}); - } - } - }; - let po = oldcomm::Port(); - oldcomm::send(ch, oldcomm::Chan(&po)); - // We are The winner if our version of the - // task was installed - let winner = oldcomm::recv(po); - oldcomm::send(resultch, winner == i); - } - } - // There should be only one winner - let mut winners = 0u; - for uint::range(0u, 10u) |_i| { - let res = oldcomm::recv(resultpo); - if res { winners += 1u }; - } - assert winners == 1u; - } -} - -/** - * Convert the current task to a 'weak' task temporarily - * - * As a weak task it will not be counted towards the runtime's set - * of live tasks. When there are no more outstanding live (non-weak) tasks - * the runtime will send an exit message on the provided channel. - * - * This function is super-unsafe. Do not use. - * - * # Safety notes - * - * * Weak tasks must either die on their own or exit upon receipt of - * the exit message. Failure to do so will cause the runtime to never - * exit - * * Tasks must not call `weaken_task` multiple times. This will - * break the kernel's accounting of live tasks. - * * Weak tasks must not be supervised. A supervised task keeps - * a reference to its parent, so the parent will not die. - */ -pub unsafe fn weaken_task(f: fn(oldcomm::Port<()>)) { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); - unsafe { - rustrt::rust_task_weaken(cast::reinterpret_cast(&ch)); - } - let _unweaken = Unweaken(ch); - f(po); - - struct Unweaken { - ch: oldcomm::Chan<()>, - drop { - unsafe { - rustrt::rust_task_unweaken(cast::reinterpret_cast(&self.ch)); - } - } - } - - fn Unweaken(ch: oldcomm::Chan<()>) -> Unweaken { - Unweaken { - ch: ch - } - } -} - -#[test] -pub fn test_weaken_task_then_unweaken() { - do task::try { - unsafe { - do weaken_task |_po| { - } - } - }; -} - -#[test] -pub fn test_weaken_task_wait() { - do task::spawn_unlinked { - unsafe { - do weaken_task |po| { - oldcomm::recv(po); - } - } - } -} - -#[test] -pub fn test_weaken_task_stress() { - // Create a bunch of weak tasks - for iter::repeat(100u) { - do task::spawn { - unsafe { - do weaken_task |_po| { - } - } - } - do task::spawn_unlinked { - unsafe { - do weaken_task |po| { - // Wait for it to tell us to die - oldcomm::recv(po); - } - } - } - } -} - -#[test] -#[ignore(cfg(windows))] -pub fn test_weaken_task_fail() { - let res = do task::try { - unsafe { - do weaken_task |_po| { - fail; - } - } - }; - assert result::is_err(&res); -} - /**************************************************************************** * Shared state & exclusive ARC ****************************************************************************/ @@ -486,7 +238,7 @@ pub unsafe fn unwrap_shared_mutable_state(rc: SharedMutableState) * Data races between tasks can result in crashes and, with sufficient * cleverness, arbitrary type coercion. */ -pub type SharedMutableState = ArcDestruct; +pub type SharedMutableState = ArcDestruct; pub unsafe fn shared_mutable_state(data: T) -> SharedMutableState { @@ -533,6 +285,14 @@ pub unsafe fn clone_shared_mutable_state(rc: &SharedMutableState) ArcDestruct((*rc).data) } +impl SharedMutableState: Clone { + fn clone(&self) -> SharedMutableState { + unsafe { + clone_shared_mutable_state(self) + } + } +} + /****************************************************************************/ #[allow(non_camel_case_types)] // runtime type @@ -581,11 +341,11 @@ impl LittleLock { } } -struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } +struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } /** * An arc over mutable data that is protected by a lock. For library use only. */ -pub struct Exclusive { x: SharedMutableState> } +pub struct Exclusive { x: SharedMutableState> } pub fn exclusive(user_data: T) -> Exclusive { let data = ExData { diff --git a/src/libcore/private/at_exit.rs b/src/libcore/private/at_exit.rs new file mode 100644 index 0000000000000..a87301dbe07bb --- /dev/null +++ b/src/libcore/private/at_exit.rs @@ -0,0 +1,98 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys; +use cast; +use ptr; +use task; +use uint; +use vec; +use rand; +use libc::{c_void, size_t}; + +/** +Register a function to be run during runtime shutdown. + +After all non-weak tasks have exited, registered exit functions will +execute, in random order, on the primary scheduler. Each function runs +in its own unsupervised task. +*/ +pub fn at_exit(f: ~fn()) { + unsafe { + let runner: &fn(*ExitFunctions) = exit_runner; + let runner_pair: sys::Closure = cast::transmute(runner); + let runner_ptr = runner_pair.code; + let runner_ptr = cast::transmute(runner_ptr); + rustrt::rust_register_exit_function(runner_ptr, ~f); + } +} + +// NB: The double pointer indirection here is because ~fn() is a fat +// pointer and due to FFI problems I am more comfortable making the +// interface use a normal pointer +extern mod rustrt { + fn rust_register_exit_function(runner: *c_void, f: ~~fn()); +} + +struct ExitFunctions { + // The number of exit functions + count: size_t, + // The buffer of exit functions + start: *~~fn() +} + +fn exit_runner(exit_fns: *ExitFunctions) { + let exit_fns = unsafe { &*exit_fns }; + let count = (*exit_fns).count; + let start = (*exit_fns).start; + + // NB: from_buf memcpys from the source, which will + // give us ownership of the array of functions + let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; + // Let's not make any promises about execution order + rand::Rng().shuffle_mut(exit_fns_vec); + + debug!("running %u exit functions", exit_fns_vec.len()); + + while !exit_fns_vec.is_empty() { + match exit_fns_vec.pop() { + ~f => { + task::task().supervised().spawn(f); + } + } + } +} + +#[abi = "rust-intrinsic"] +pub extern mod rusti { + fn move_val_init(dst: &mut T, -src: T); + fn init() -> T; +} + +#[test] +fn test_at_exit() { + let i = 10; + do at_exit { + debug!("at_exit1"); + assert i == 10; + } +} + +#[test] +fn test_at_exit_many() { + let i = 10; + for uint::range(20, 100) |j| { + do at_exit { + debug!("at_exit2"); + assert i == 10; + assert j > i; + } + } +} \ No newline at end of file diff --git a/src/libcore/private/finally.rs b/src/libcore/private/finally.rs new file mode 100644 index 0000000000000..66e23ff433602 --- /dev/null +++ b/src/libcore/private/finally.rs @@ -0,0 +1,98 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +The Finally trait provides a method, `finally` on +stack closures that emulates Java-style try/finally blocks. + +# Example + +~~~ +do || { + ... +}.finally { + alway_run_this(); +} +~~~ +*/ + +use ops::Drop; +use task::{spawn, failing}; + +pub trait Finally { + fn finally(&self, +dtor: &fn()) -> T; +} + +impl &fn() -> T: Finally { + // XXX: Should not require a mode here + fn finally(&self, +dtor: &fn()) -> T { + let _d = Finallyalizer { + dtor: dtor + }; + + (*self)() + } +} + +struct Finallyalizer { + dtor: &fn() +} + +impl Finallyalizer: Drop { + fn finalize(&self) { + (self.dtor)(); + } +} + +#[test] +fn test_success() { + let mut i = 0; + do (|| { + i = 10; + }).finally { + assert !failing(); + assert i == 10; + i = 20; + } + assert i == 20; +} + +#[test] +#[ignore(cfg(windows))] +#[should_fail] +fn test_fail() { + let mut i = 0; + do (|| { + i = 10; + fail; + }).finally { + assert failing(); + assert i == 10; + } +} + +#[test] +fn test_retval() { + let i = do (fn&() -> int { + 10 + }).finally { }; + assert i == 10; +} + +#[test] +fn test_compact() { + // XXX Should be able to use a fn item instead + // of a closure for do_some_fallible_work, + // but it's a type error. + let do_some_fallible_work: &fn() = || { }; + fn but_always_run_this_function() { } + do_some_fallible_work.finally( + but_always_run_this_function); +} \ No newline at end of file diff --git a/src/libcore/private/global.rs b/src/libcore/private/global.rs new file mode 100644 index 0000000000000..ee20fb665bea6 --- /dev/null +++ b/src/libcore/private/global.rs @@ -0,0 +1,296 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Global data + +An interface for creating and retrieving values with global +(per-runtime) scope. + +Global values are stored in a map and protected by a single global +mutex. Operations are provided for accessing and cloning the value +under the mutex. + +Because all globals go through a single mutex, they should be used +sparingly. The interface is intended to be used with clonable, +atomically reference counted synchronization types, like ARCs, in +which case the value should be cached locally whenever possible to +avoid hitting the mutex. +*/ + +use cast::{transmute, reinterpret_cast}; +use clone::Clone; +use kinds::Owned; +use libc::{c_void, uintptr_t}; +use option::{Option, Some, None}; +use ops::Drop; +use pipes; +use private::{Exclusive, exclusive}; +use private::{SharedMutableState, shared_mutable_state}; +use private::{get_shared_immutable_state}; +use private::at_exit::at_exit; +use hashmap::linear::LinearMap; +use sys::Closure; +use task::spawn; +use uint; + +pub type GlobalDataKey = &fn(v: T); + +pub unsafe fn global_data_clone_create( + key: GlobalDataKey, create: &fn() -> ~T) -> T { + /*! + * Clone a global value or, if it has not been created, + * first construct the value then return a clone. + * + * # Safety note + * + * Both the clone operation and the constructor are + * called while the global lock is held. Recursive + * use of the global interface in either of these + * operations will result in deadlock. + */ + global_data_clone_create_(key_ptr(key), create) +} + +unsafe fn global_data_clone_create_( + key: uint, create: &fn() -> ~T) -> T { + + let mut clone_value: Option = None; + do global_data_modify_(key) |value: Option<~T>| { + match value { + None => { + let value = create(); + clone_value = Some(value.clone()); + Some(value) + } + Some(value) => { + clone_value = Some(value.clone()); + Some(value) + } + } + } + return clone_value.unwrap(); +} + +unsafe fn global_data_modify( + key: GlobalDataKey, op: &fn(Option<~T>) -> Option<~T>) { + + global_data_modify_(key_ptr(key), op) +} + +unsafe fn global_data_modify_( + key: uint, op: &fn(Option<~T>) -> Option<~T>) { + + let mut old_dtor = None; + do get_global_state().with |gs| { + let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) { + Some((ptr, dtor)) => { + let value: ~T = transmute(ptr); + (op(Some(value)), Some(dtor)) + } + None => { + (op(None), None) + } + }; + match maybe_new_value { + Some(value) => { + let data: *c_void = transmute(value); + let dtor: ~fn() = match maybe_dtor { + Some(dtor) => dtor, + None => { + let dtor: ~fn() = || unsafe { + let _destroy_value: ~T = transmute(data); + }; + dtor + } + }; + let value = (data, dtor); + gs.map.insert(key, value); + } + None => { + match maybe_dtor { + Some(dtor) => old_dtor = Some(dtor), + None => () + } + } + } + } +} + +pub unsafe fn global_data_clone( + key: GlobalDataKey) -> Option { + let mut maybe_clone: Option = None; + do global_data_modify(key) |current| { + match ¤t { + &Some(~ref value) => { + maybe_clone = Some(value.clone()); + } + &None => () + } + current + } + return maybe_clone; +} + +// GlobalState is a map from keys to unique pointers and a +// destructor. Keys are pointers derived from the type of the +// global value. There is a single GlobalState instance per runtime. +struct GlobalState { + map: LinearMap +} + +impl GlobalState: Drop { + fn finalize(&self) { + for self.map.each_value |v| { + match v { + &(_, ref dtor) => (*dtor)() + } + } + } +} + +fn get_global_state() -> Exclusive { + + const POISON: int = -1; + + // XXX: Doing atomic_cxchg to initialize the global state + // lazily, which wouldn't be necessary with a runtime written + // in Rust + let global_ptr = unsafe { rust_get_global_data_ptr() }; + + if unsafe { *global_ptr } == 0 { + // Global state doesn't exist yet, probably + + // The global state object + let state = GlobalState { + map: LinearMap::new() + }; + + // It's under a reference-counted mutex + let state = ~exclusive(state); + + // Convert it to an integer + let state_ptr: &Exclusive = state; + let state_i: int = unsafe { transmute(state_ptr) }; + + // Swap our structure into the global pointer + let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) }; + + // Sanity check that we're not trying to reinitialize after shutdown + assert prev_i != POISON; + + if prev_i == 0 { + // Successfully installed the global pointer + + // Take a handle to return + let clone = state.clone(); + + // Install a runtime exit function to destroy the global object + do at_exit { + // Poison the global pointer + let prev_i = unsafe { + atomic_cxchg(&mut *global_ptr, state_i, POISON) + }; + assert prev_i == state_i; + + // Capture the global state object in the at_exit closure + // so that it is destroyed at the right time + let _capture_global_state = &state; + }; + return clone; + } else { + // Somebody else initialized the globals first + let state: &Exclusive = unsafe { transmute(prev_i) }; + return state.clone(); + } + } else { + let state: &Exclusive = unsafe { + transmute(*global_ptr) + }; + return state.clone(); + } +} + +fn key_ptr(key: GlobalDataKey) -> uint { + unsafe { + let closure: Closure = reinterpret_cast(&key); + return transmute(closure.code); + } +} + +extern { + fn rust_get_global_data_ptr() -> *mut int; +} + +#[abi = "rust-intrinsic"] +extern { + fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int; +} + +#[test] +fn test_clone_rc() { + type MyType = SharedMutableState; + + fn key(_v: SharedMutableState) { } + + for uint::range(0, 100) |_| { + do spawn { + unsafe { + let val = do global_data_clone_create(key) { + ~shared_mutable_state(10) + }; + + assert get_shared_immutable_state(&val) == &10; + } + } + } +} + +#[test] +fn test_modify() { + type MyType = SharedMutableState; + + fn key(_v: SharedMutableState) { } + + unsafe { + do global_data_modify(key) |v| { + match v { + None => { + unsafe { + Some(~shared_mutable_state(10)) + } + } + _ => fail + } + } + + do global_data_modify(key) |v| { + match v { + Some(sms) => { + let v = get_shared_immutable_state(sms); + assert *v == 10; + None + }, + _ => fail + } + } + + do global_data_modify(key) |v| { + match v { + None => { + unsafe { + Some(~shared_mutable_state(10)) + } + } + _ => fail + } + } + } +} diff --git a/src/libcore/private/weak_task.rs b/src/libcore/private/weak_task.rs new file mode 100644 index 0000000000000..573a3e54b444b --- /dev/null +++ b/src/libcore/private/weak_task.rs @@ -0,0 +1,207 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Weak tasks + +Weak tasks are a runtime feature for building global services that +do not keep the runtime alive. Normally the runtime exits when all +tasks exits, but if a task is weak then the runtime may exit while +it is running, sending a notification to the task that the runtime +is trying to shut down. +*/ + +use option::{Some, None, swap_unwrap}; +use private::at_exit::at_exit; +use private::global::global_data_clone_create; +use private::finally::Finally; +use pipes::{Port, Chan, SharedChan, GenericSmartChan, stream}; +use task::{Task, task, spawn}; +use task::rt::{task_id, get_task_id}; +use hashmap::linear::LinearMap; +use ops::Drop; + +type ShutdownMsg = (); + +// XXX: This could be a PortOne but I've experienced bugginess +// with oneshot pipes and try_send +pub unsafe fn weaken_task(f: &fn(Port)) { + let service = global_data_clone_create(global_data_key, + create_global_service); + let (shutdown_port, shutdown_chan) = stream::(); + let shutdown_port = ~mut Some(shutdown_port); + let task = get_task_id(); + // Expect the weak task service to be alive + assert service.try_send(RegisterWeakTask(task, shutdown_chan)); + unsafe { rust_inc_weak_task_count(); } + do fn&() { + let shutdown_port = swap_unwrap(&mut *shutdown_port); + f(shutdown_port) + }.finally || { + unsafe { rust_dec_weak_task_count(); } + // Service my have already exited + service.send(UnregisterWeakTask(task)); + } +} + +type WeakTaskService = SharedChan; +type TaskHandle = task_id; + +fn global_data_key(_v: WeakTaskService) { } + +enum ServiceMsg { + RegisterWeakTask(TaskHandle, Chan), + UnregisterWeakTask(TaskHandle), + Shutdown +} + +fn create_global_service() -> ~WeakTaskService { + + debug!("creating global weak task service"); + let (port, chan) = stream::(); + let port = ~mut Some(port); + let chan = SharedChan(chan); + let chan_clone = chan.clone(); + + do task().unlinked().spawn { + debug!("running global weak task service"); + let port = swap_unwrap(&mut *port); + let port = ~mut Some(port); + do fn&() { + let port = swap_unwrap(&mut *port); + // The weak task service is itself a weak task + debug!("weakening the weak service task"); + unsafe { rust_inc_weak_task_count(); } + run_weak_task_service(port); + }.finally { + debug!("unweakening the weak service task"); + unsafe { rust_dec_weak_task_count(); } + } + } + + do at_exit { + debug!("shutting down weak task service"); + chan.send(Shutdown); + } + + return ~chan_clone; +} + +fn run_weak_task_service(port: Port) { + + let mut shutdown_map = LinearMap::new(); + + loop { + match port.recv() { + RegisterWeakTask(task, shutdown_chan) => { + let previously_unregistered = + shutdown_map.insert(task, shutdown_chan); + assert previously_unregistered; + } + UnregisterWeakTask(task) => { + match shutdown_map.pop(&task) { + Some(shutdown_chan) => { + // Oneshot pipes must send, even though + // nobody will receive this + shutdown_chan.send(()); + } + None => fail + } + } + Shutdown => break + } + } + + do shutdown_map.consume |_, shutdown_chan| { + // Weak task may have already exited + shutdown_chan.send(()); + } +} + +extern { + unsafe fn rust_inc_weak_task_count(); + unsafe fn rust_dec_weak_task_count(); +} + +#[test] +fn test_simple() { + let (port, chan) = stream(); + do spawn { + unsafe { + do weaken_task |_signal| { + } + } + chan.send(()); + } + port.recv(); +} + +#[test] +fn test_weak_weak() { + let (port, chan) = stream(); + do spawn { + unsafe { + do weaken_task |_signal| { + } + do weaken_task |_signal| { + } + } + chan.send(()); + } + port.recv(); +} + +#[test] +fn test_wait_for_signal() { + do spawn { + unsafe { + do weaken_task |signal| { + signal.recv(); + } + } + } +} + +#[test] +fn test_wait_for_signal_many() { + use uint; + for uint::range(0, 100) |_| { + do spawn { + unsafe { + do weaken_task |signal| { + signal.recv(); + } + } + } + } +} + +#[test] +fn test_select_stream_and_oneshot() { + use pipes::select2i; + use either::{Left, Right}; + + let (port, chan) = stream(); + let (waitport, waitchan) = stream(); + do spawn { + unsafe { + do weaken_task |signal| { + match select2i(&port, &signal) { + Left(*) => (), + Right(*) => fail + } + } + } + waitchan.send(()); + } + chan.send(()); + waitport.recv(); +} + diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f059c119f4989..dd5c4143b6d7a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -116,9 +116,16 @@ pub pure fn is_not_null(ptr: *const T) -> bool { !is_null(ptr) } * and destination may overlap. */ #[inline(always)] +#[cfg(target_word_size = "32")] pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { let n = count * sys::size_of::(); - libc_::memmove(dst as *mut c_void, src as *c_void, n as size_t); + memmove32(dst as *mut u8, src as *u8, n as u32); +} +#[inline(always)] +#[cfg(target_word_size = "64")] +pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { + let n = count * sys::size_of::(); + memmove64(dst as *mut u8, src as *u8, n as u64); } #[inline(always)] @@ -183,6 +190,23 @@ pub trait Ptr { pure fn offset(count: uint) -> self; } +#[cfg(stage0)] +unsafe fn memmove32(dst: *mut u8, src: *const u8, count: u32) { + libc::memmove(dst as *c_void, src as *c_void, count as size_t); +} +#[cfg(stage0)] +unsafe fn memmove64(dst: *mut u8, src: *const u8, count: u64) { + libc::memmove(dst as *c_void, src as *c_void, count as size_t); +} + +#[abi="rust-intrinsic"] +#[cfg(stage1)] +#[cfg(stage2)] +pub extern { + fn memmove32(dst: *mut u8, src: *u8, size: u32); + fn memmove64(dst: *mut u8, src: *u8, size: u64); +} + /// Extension methods for immutable pointers impl *T: Ptr { /// Returns true if the pointer is equal to the null pointer. diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 55eb53bc0266a..94fc9e37a7519 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -41,7 +41,7 @@ pub fn align(size: uint, align: uint) -> uint { } /// Adaptor to wrap around visitors implementing MovePtr. -pub struct MovePtrAdaptor { +pub struct MovePtrAdaptor { inner: V } pub fn MovePtrAdaptor(v: V) -> MovePtrAdaptor { @@ -75,6 +75,7 @@ impl MovePtrAdaptor { } /// Abstract type-directed pointer-movement using the MovePtr trait +#[cfg(stage0)] impl MovePtrAdaptor: TyVisitor { fn visit_bot() -> bool { self.align_to::<()>(); @@ -325,7 +326,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_enter_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_class(n_fields: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_class(n_fields, sz, align) { return false; @@ -343,7 +345,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_leave_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_class(n_fields: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_class(n_fields, sz, align) { return false; } @@ -394,7 +397,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_enter_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_enter_enum(n_variants: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; @@ -433,7 +437,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_leave_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_leave_enum(n_variants: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; } @@ -494,3 +499,430 @@ impl MovePtrAdaptor: TyVisitor { true } } + +/// Abstract type-directed pointer-movement using the MovePtr trait +#[cfg(stage1)] +#[cfg(stage2)] +impl MovePtrAdaptor: TyVisitor { + fn visit_bot(&self) -> bool { + self.align_to::<()>(); + if ! self.inner.visit_bot() { return false; } + self.bump_past::<()>(); + true + } + + fn visit_nil(&self) -> bool { + self.align_to::<()>(); + if ! self.inner.visit_nil() { return false; } + self.bump_past::<()>(); + true + } + + fn visit_bool(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_bool() { return false; } + self.bump_past::(); + true + } + + fn visit_int(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_int() { return false; } + self.bump_past::(); + true + } + + fn visit_i8(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i8() { return false; } + self.bump_past::(); + true + } + + fn visit_i16(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i16() { return false; } + self.bump_past::(); + true + } + + fn visit_i32(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i32() { return false; } + self.bump_past::(); + true + } + + fn visit_i64(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i64() { return false; } + self.bump_past::(); + true + } + + fn visit_uint(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_uint() { return false; } + self.bump_past::(); + true + } + + fn visit_u8(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u8() { return false; } + self.bump_past::(); + true + } + + fn visit_u16(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u16() { return false; } + self.bump_past::(); + true + } + + fn visit_u32(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u32() { return false; } + self.bump_past::(); + true + } + + fn visit_u64(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u64() { return false; } + self.bump_past::(); + true + } + + fn visit_float(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_float() { return false; } + self.bump_past::(); + true + } + + fn visit_f32(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_f32() { return false; } + self.bump_past::(); + true + } + + fn visit_f64(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_f64() { return false; } + self.bump_past::(); + true + } + + fn visit_char(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_char() { return false; } + self.bump_past::(); + true + } + + fn visit_str(&self) -> bool { + self.align_to::<~str>(); + if ! self.inner.visit_str() { return false; } + self.bump_past::<~str>(); + true + } + + fn visit_estr_box(&self) -> bool { + self.align_to::<@str>(); + if ! self.inner.visit_estr_box() { return false; } + self.bump_past::<@str>(); + true + } + + fn visit_estr_uniq(&self) -> bool { + self.align_to::<~str>(); + if ! self.inner.visit_estr_uniq() { return false; } + self.bump_past::<~str>(); + true + } + + fn visit_estr_slice(&self) -> bool { + self.align_to::<&static/str>(); + if ! self.inner.visit_estr_slice() { return false; } + self.bump_past::<&static/str>(); + true + } + + fn visit_estr_fixed(&self, n: uint, + sz: uint, + align: uint) -> bool { + self.align(align); + if ! self.inner.visit_estr_fixed(n, sz, align) { return false; } + self.bump(sz); + true + } + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<@u8>(); + if ! self.inner.visit_box(mtbl, inner) { return false; } + self.bump_past::<@u8>(); + true + } + + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<~u8>(); + if ! self.inner.visit_uniq(mtbl, inner) { return false; } + self.bump_past::<~u8>(); + true + } + + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<*u8>(); + if ! self.inner.visit_ptr(mtbl, inner) { return false; } + self.bump_past::<*u8>(); + true + } + + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<&static/u8>(); + if ! self.inner.visit_rptr(mtbl, inner) { return false; } + self.bump_past::<&static/u8>(); + true + } + + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::(); + if ! self.inner.visit_vec(mtbl, inner) { return false; } + true + } + + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<~[u8]>(); + if ! self.inner.visit_vec(mtbl, inner) { return false; } + self.bump_past::<~[u8]>(); + true + } + + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<@[u8]>(); + if ! self.inner.visit_evec_box(mtbl, inner) { return false; } + self.bump_past::<@[u8]>(); + true + } + + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<~[u8]>(); + if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; } + self.bump_past::<~[u8]>(); + true + } + + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<&static/[u8]>(); + if ! self.inner.visit_evec_slice(mtbl, inner) { return false; } + self.bump_past::<&static/[u8]>(); + true + } + + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, + mtbl: uint, inner: *TyDesc) -> bool { + self.align(align); + if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) { + return false; + } + self.bump(sz); + true + } + + fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { + self.align(align); + if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; } + true + } + + fn visit_rec_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_rec_field(i, name, mtbl, inner) { + return false; + } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { + if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; } + true + } + + fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { + self.align(align); + if ! self.inner.visit_enter_class(n_fields, sz, align) { + return false; + } + true + } + + fn visit_class_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_class_field(i, name, mtbl, inner) { + return false; + } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { + if ! self.inner.visit_leave_class(n_fields, sz, align) { + return false; + } + true + } + + fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { + self.align(align); + if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; } + true + } + + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_tup_field(i, inner) { return false; } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { + if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; } + true + } + + fn visit_enter_fn(&self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool { + if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) { + return false + } + true + } + + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool { + if ! self.inner.visit_fn_input(i, mode, inner) { return false; } + true + } + + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool { + if ! self.inner.visit_fn_output(retstyle, inner) { return false; } + true + } + + fn visit_leave_fn(&self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool { + if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) { + return false; + } + true + } + + fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { + self.align(align); + if ! self.inner.visit_enter_enum(n_variants, sz, align) { + return false; + } + true + } + + fn visit_enter_enum_variant(&self, variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + self.inner.push_ptr(); + if ! self.inner.visit_enter_enum_variant(variant, disr_val, + n_fields, name) { + return false; + } + true + } + + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_enum_variant_field(i, inner) { return false; } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_enum_variant(&self, variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + if ! self.inner.visit_leave_enum_variant(variant, disr_val, + n_fields, name) { + return false; + } + self.inner.pop_ptr(); + true + } + + fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { + if ! self.inner.visit_leave_enum(n_variants, sz, align) { + return false; + } + self.bump(sz); + true + } + + fn visit_trait(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_trait() { return false; } + self.bump_past::(); + true + } + + fn visit_var(&self) -> bool { + if ! self.inner.visit_var() { return false; } + true + } + + fn visit_var_integral(&self) -> bool { + if ! self.inner.visit_var_integral() { return false; } + true + } + + fn visit_param(&self, i: uint) -> bool { + if ! self.inner.visit_param(i) { return false; } + true + } + + fn visit_self(&self) -> bool { + self.align_to::<&static/u8>(); + if ! self.inner.visit_self() { return false; } + self.align_to::<&static/u8>(); + true + } + + fn visit_type(&self) -> bool { + if ! self.inner.visit_type() { return false; } + true + } + + fn visit_opaque_box(&self) -> bool { + self.align_to::<@u8>(); + if ! self.inner.visit_opaque_box() { return false; } + self.bump_past::<@u8>(); + true + } + + fn visit_constr(&self, inner: *TyDesc) -> bool { + if ! self.inner.visit_constr(inner) { return false; } + true + } + + fn visit_closure_ptr(&self, ck: uint) -> bool { + self.align_to::(); + if ! self.inner.visit_closure_ptr(ck) { return false; } + self.bump_past::(); + true + } +} diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 4d4970eada805..75a572fa46444 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -265,6 +265,7 @@ impl ReprVisitor { } +#[cfg(stage0)] impl ReprVisitor : TyVisitor { fn visit_bot() -> bool { self.writer.write_str("!"); @@ -559,6 +560,310 @@ impl ReprVisitor : TyVisitor { fn visit_closure_ptr(_ck: uint) -> bool { true } } +#[cfg(stage1)] +#[cfg(stage2)] +impl ReprVisitor : TyVisitor { + fn visit_bot(&self) -> bool { + self.writer.write_str("!"); + true + } + fn visit_nil(&self) -> bool { self.write::<()>() } + fn visit_bool(&self) -> bool { self.write::() } + fn visit_int(&self) -> bool { self.write::() } + fn visit_i8(&self) -> bool { self.write::() } + fn visit_i16(&self) -> bool { self.write::() } + fn visit_i32(&self) -> bool { self.write::() } + fn visit_i64(&self) -> bool { self.write::() } + + fn visit_uint(&self) -> bool { self.write::() } + fn visit_u8(&self) -> bool { self.write::() } + fn visit_u16(&self) -> bool { self.write::() } + fn visit_u32(&self) -> bool { self.write::() } + fn visit_u64(&self) -> bool { self.write::() } + + fn visit_float(&self) -> bool { self.write::() } + fn visit_f32(&self) -> bool { self.write::() } + fn visit_f64(&self) -> bool { self.write::() } + + fn visit_char(&self) -> bool { + do self.get:: |&ch| { + self.writer.write_char('\''); + self.writer.write_escaped_char(ch); + self.writer.write_char('\''); + } + } + + // Type no longer exists, vestigial function. + fn visit_str(&self) -> bool { fail; } + + fn visit_estr_box(&self) -> bool { + do self.get::<@str> |s| { + self.writer.write_char('@'); + self.write_escaped_slice(*s); + } + } + fn visit_estr_uniq(&self) -> bool { + do self.get::<~str> |s| { + self.writer.write_char('~'); + self.write_escaped_slice(*s); + } + } + fn visit_estr_slice(&self) -> bool { + do self.get::<&str> |s| { + self.write_escaped_slice(*s); + } + } + + // Type no longer exists, vestigial function. + fn visit_estr_fixed(&self, _n: uint, _sz: uint, + _align: uint) -> bool { fail; } + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.writer.write_char('@'); + self.write_mut_qualifier(mtbl); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + self.visit_ptr_inner(p, inner); + } + } + + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.writer.write_char('~'); + self.write_mut_qualifier(mtbl); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + self.visit_ptr_inner(p, inner); + } + } + + fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { + do self.get::<*c_void> |p| { + self.writer.write_str(fmt!("(0x%x as *())", + *p as uint)); + } + } + + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.writer.write_char('&'); + self.write_mut_qualifier(mtbl); + do self.get::<*c_void> |p| { + self.visit_ptr_inner(*p, inner); + } + } + + // Type no longer exists, vestigial function. + fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail; } + + + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get:: |b| { + self.write_unboxed_vec_repr(mtbl, b, inner); + } + } + + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get::<&VecRepr> |b| { + self.writer.write_char('@'); + self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + } + } + + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get::<&VecRepr> |b| { + self.writer.write_char('~'); + self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + } + } + + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get:: |s| { + self.writer.write_char('&'); + self.write_vec_range(mtbl, s.data, s.len, inner); + } + } + + fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint, + mtbl: uint, inner: *TyDesc) -> bool { + do self.get:: |b| { + self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner); + } + } + + fn visit_enter_rec(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('{'); + true + } + + fn visit_rec_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + if i != 0 { + self.writer.write_str(", "); + } + self.write_mut_qualifier(mtbl); + self.writer.write_str(name); + self.writer.write_str(": "); + self.visit_inner(inner); + true + } + + fn visit_leave_rec(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('}'); + true + } + + fn visit_enter_class(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('{'); + true + } + fn visit_class_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + if i != 0 { + self.writer.write_str(", "); + } + self.write_mut_qualifier(mtbl); + self.writer.write_str(name); + self.writer.write_str(": "); + self.visit_inner(inner); + true + } + fn visit_leave_class(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('}'); + true + } + + fn visit_enter_tup(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('('); + true + } + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { + if i != 0 { + self.writer.write_str(", "); + } + self.visit_inner(inner); + true + } + fn visit_leave_tup(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char(')'); + true + } + + fn visit_enter_enum(&self, n_variants: uint, + _sz: uint, _align: uint) -> bool { + if n_variants == 1 { + self.var_stk.push(Degenerate) + } else { + self.var_stk.push(TagMatch) + } + true + } + + fn visit_enter_enum_variant(&self, _variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + let mut write = false; + match self.var_stk.pop() { + Degenerate => { + write = true; + self.var_stk.push(Degenerate); + } + TagMatch | TagMismatch => { + do self.get::() |t| { + if disr_val == *t { + write = true; + self.var_stk.push(TagMatch); + } else { + self.var_stk.push(TagMismatch); + } + }; + self.bump_past::(); + } + } + + if write { + self.writer.write_str(name); + if n_fields > 0 { + self.writer.write_char('('); + } + } + true + } + + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { + match self.var_stk.last() { + Degenerate | TagMatch => { + if i != 0 { + self.writer.write_str(", "); + } + if ! self.visit_inner(inner) { + return false; + } + } + TagMismatch => () + } + true + } + + fn visit_leave_enum_variant(&self, _variant: uint, + _disr_val: int, + n_fields: uint, + _name: &str) -> bool { + match self.var_stk.last() { + Degenerate | TagMatch => { + if n_fields > 0 { + self.writer.write_char(')'); + } + } + TagMismatch => () + } + true + } + + fn visit_leave_enum(&self, _n_variants: uint, + _sz: uint, _align: uint) -> bool { + self.var_stk.pop(); + true + } + + fn visit_enter_fn(&self, _purity: uint, _proto: uint, + _n_inputs: uint, _retstyle: uint) -> bool { true } + fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_leave_fn(&self, _purity: uint, _proto: uint, + _n_inputs: uint, _retstyle: uint) -> bool { true } + + + fn visit_trait(&self) -> bool { true } + fn visit_var(&self) -> bool { true } + fn visit_var_integral(&self) -> bool { true } + fn visit_param(&self, _i: uint) -> bool { true } + fn visit_self(&self) -> bool { true } + fn visit_type(&self) -> bool { true } + + fn visit_opaque_box(&self) -> bool { + self.writer.write_char('@'); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + self.visit_ptr_inner(p, b.header.type_desc); + } + } + + // Type no longer exists, vestigial function. + fn visit_constr(&self, _inner: *TyDesc) -> bool { fail; } + + fn visit_closure_ptr(&self, _ck: uint) -> bool { true } +} + pub fn write_repr(writer: @Writer, object: &T) { unsafe { let ptr = ptr::to_unsafe_ptr(object) as *c_void; diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 8960d40b85a24..eeae7f5b291a0 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -17,7 +17,7 @@ use io; use io::ReaderUtil; use libc; use libc::{pid_t, c_void, c_int}; -use oldcomm; +use pipes::{stream, SharedChan}; use option::{Some, None}; use os; use prelude::*; @@ -336,22 +336,23 @@ pub fn program_output(prog: &str, args: &[~str]) -> // in parallel so we don't deadlock while blocking on one // or the other. FIXME (#2625): Surely there's a much more // clever way to do this. - let p = oldcomm::Port(); - let ch = oldcomm::Chan(&p); + let (p, ch) = stream(); + let ch = SharedChan(ch); + let ch_clone = ch.clone(); do task::spawn_sched(task::SingleThreaded) { let errput = readclose(pipe_err.in); - oldcomm::send(ch, (2, move errput)); + ch.send((2, move errput)); }; do task::spawn_sched(task::SingleThreaded) { let output = readclose(pipe_out.in); - oldcomm::send(ch, (1, move output)); + ch_clone.send((1, move output)); }; let status = run::waitpid(pid); let mut errs = ~""; let mut outs = ~""; let mut count = 2; while count > 0 { - let stream = oldcomm::recv(p); + let stream = p.recv(); match stream { (1, copy s) => { outs = move s; diff --git a/src/libcore/task/local_data.rs b/src/libcore/task/local_data.rs index 05a4e35b249e4..42765ef139ff5 100644 --- a/src/libcore/task/local_data.rs +++ b/src/libcore/task/local_data.rs @@ -45,7 +45,7 @@ use task; * * These two cases aside, the interface is safe. */ -pub type LocalDataKey = &fn(v: @T); +pub type LocalDataKey = &fn(v: @T); /** * Remove a task-local data value from the table, returning the diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index a4d99bf5db4a6..9ddafee693898 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -43,16 +43,15 @@ use cmp; use cmp::Eq; use iter; use libc; -use oldcomm; use option; use result::Result; -use pipes::{stream, Chan, Port}; +use pipes::{stream, Chan, GenericChan, GenericPort, Port, SharedChan}; use pipes; use prelude::*; use ptr; use result; use task::local_data_priv::{local_get, local_set}; -use task::rt::{task_id, rust_task}; +use task::rt::{task_id, sched_id, rust_task}; use task; use util; use util::replace; @@ -62,6 +61,12 @@ pub mod local_data; pub mod rt; pub mod spawn; +/// A handle to a scheduler +#[deriving_eq] +pub enum Scheduler { + SchedulerHandle(sched_id) +} + /// A handle to a task #[deriving_eq] pub enum Task { @@ -95,7 +100,21 @@ impl TaskResult : Eq { } /// Scheduler modes +#[deriving_eq] pub enum SchedMode { + /// Run task on the default scheduler + DefaultScheduler, + /// Run task on the current scheduler + CurrentScheduler, + /// Run task on a specific scheduler + ExistingScheduler(Scheduler), + /** + * Tasks are scheduled on the main OS thread + * + * The main OS thread is the thread used to launch the runtime which, + * in most cases, is the process's initial thread as created by the OS. + */ + PlatformThread, /// All tasks run in the same OS thread SingleThreaded, /// Tasks are distributed among available CPUs @@ -104,53 +123,6 @@ pub enum SchedMode { ThreadPerTask, /// Tasks are distributed among a fixed number of OS threads ManualThreads(uint), - /** - * Tasks are scheduled on the main OS thread - * - * The main OS thread is the thread used to launch the runtime which, - * in most cases, is the process's initial thread as created by the OS. - */ - PlatformThread -} - -impl SchedMode : cmp::Eq { - pure fn eq(&self, other: &SchedMode) -> bool { - match (*self) { - SingleThreaded => { - match (*other) { - SingleThreaded => true, - _ => false - } - } - ThreadPerCore => { - match (*other) { - ThreadPerCore => true, - _ => false - } - } - ThreadPerTask => { - match (*other) { - ThreadPerTask => true, - _ => false - } - } - ManualThreads(e0a) => { - match (*other) { - ManualThreads(e0b) => e0a == e0b, - _ => false - } - } - PlatformThread => { - match (*other) { - PlatformThread => true, - _ => false - } - } - } - } - pure fn ne(&self, other: &SchedMode) -> bool { - !(*self).eq(other) - } } /** @@ -204,7 +176,7 @@ pub struct TaskOpts { linked: bool, supervised: bool, mut notify_chan: Option>, - sched: Option, + sched: SchedOpts } /** @@ -369,11 +341,8 @@ impl TaskBuilder { opts: TaskOpts { linked: self.opts.linked, supervised: self.opts.supervised, - notify_chan: notify_chan, - sched: Some(SchedOpts { - mode: mode, - foreign_stack_size: None, - }) + notify_chan: move notify_chan, + sched: SchedOpts { mode: mode, foreign_stack_size: None} }, can_not_copy: None, .. self.consume() @@ -457,18 +426,17 @@ impl TaskBuilder { * Fails if a future_result was already set for this task. */ fn try(f: fn~() -> T) -> Result { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::(); let mut result = None; let fr_task_builder = self.future_result(|+r| { result = Some(move r); }); - do fr_task_builder.spawn |move f| { - oldcomm::send(ch, f()); + do fr_task_builder.spawn |move f, move ch| { + ch.send(f()); } match option::unwrap(move result).recv() { - Success => result::Ok(oldcomm::recv(po)), + Success => result::Ok(po.recv()), Failure => result::Err(()) } } @@ -489,7 +457,10 @@ pub fn default_task_opts() -> TaskOpts { linked: true, supervised: false, notify_chan: None, - sched: None + sched: SchedOpts { + mode: DefaultScheduler, + foreign_stack_size: None + } } } @@ -542,10 +513,9 @@ pub fn spawn_with(arg: A, f: fn~(v: A)) { pub fn spawn_sched(mode: SchedMode, f: fn~()) { /*! - * Creates a new scheduler and executes a task on it - * - * Tasks subsequently spawned by that task will also execute on - * the new scheduler. When there are no more tasks to execute the + * Creates a new task on a new or existing scheduler + + * When there are no more tasks to execute the * scheduler terminates. * * # Failure @@ -599,6 +569,10 @@ pub fn get_task() -> Task { } } +pub fn get_scheduler() -> Scheduler { + SchedulerHandle(unsafe { rt::rust_get_sched_id() }) +} + /** * Temporarily make the task unkillable * @@ -711,17 +685,18 @@ fn test_cant_dup_task_builder() { #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); + let ch = SharedChan(ch); do spawn_unlinked { + let ch = ch.clone(); do spawn_unlinked { // Give middle task a chance to fail-but-not-kill-us. for iter::repeat(16) { task::yield(); } - oldcomm::send(ch, ()); // If killed first, grandparent hangs. + ch.send(()); // If killed first, grandparent hangs. } fail; // Shouldn't kill either (grand)parent or (grand)child. } - oldcomm::recv(po); + po.recv(); } #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails @@ -741,8 +716,7 @@ fn test_spawn_unlinked_sup_fail_down() { #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_up() { // child fails; parent fails - let po = oldcomm::Port::<()>(); - let _ch = oldcomm::Chan(&po); + let (po, _ch) = stream::<()>(); // Unidirectional "parenting" shouldn't override bidirectional linked. // We have to cheat with opts - the interface doesn't support them because // they don't make sense (redundant with task().supervised()). @@ -760,7 +734,7 @@ fn test_spawn_linked_sup_fail_up() { // child fails; parent fails .. b0 }; do b1.spawn { fail; } - oldcomm::recv(po); // We should get punted awake + po.recv(); // We should get punted awake } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_down() { // parent fails; child fails @@ -784,11 +758,10 @@ fn test_spawn_linked_sup_fail_down() { // parent fails; child fails } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails - let po = oldcomm::Port::<()>(); - let _ch = oldcomm::Chan(&po); + let (po, _ch) = stream::<()>(); // Default options are to spawn linked & unsupervised. do spawn { fail; } - oldcomm::recv(po); // We should get punted awake + po.recv(); // We should get punted awake } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails @@ -856,27 +829,25 @@ fn test_spawn_linked_sup_propagate_sibling() { #[test] fn test_run_basic() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::<()>(); do task().spawn { - oldcomm::send(ch, ()); + ch.send(()); } - oldcomm::recv(po); + po.recv(); } #[test] fn test_add_wrapper() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::<()>(); let b0 = task(); let b1 = do b0.add_wrapper |body| { fn~(move body) { body(); - oldcomm::send(ch, ()); + ch.send(()); } }; do b1.spawn { } - oldcomm::recv(po); + po.recv(); } #[test] @@ -929,52 +900,46 @@ fn test_spawn_sched_no_threads() { #[test] fn test_spawn_sched() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::<()>(); + let ch = SharedChan(ch); - fn f(i: int, ch: oldcomm::Chan<()>) { - unsafe { - let parent_sched_id = rt::rust_get_sched_id(); + fn f(i: int, ch: SharedChan<()>) { + let parent_sched_id = unsafe { rt::rust_get_sched_id() }; - do spawn_sched(SingleThreaded) { - unsafe { - let child_sched_id = rt::rust_get_sched_id(); - assert parent_sched_id != child_sched_id; - - if (i == 0) { - oldcomm::send(ch, ()); - } else { - f(i - 1, ch); - } - } - }; - } + do spawn_sched(SingleThreaded) { + let child_sched_id = unsafe { rt::rust_get_sched_id() }; + assert parent_sched_id != child_sched_id; + + if (i == 0) { + ch.send(()); + } else { + f(i - 1, ch.clone()); + } + }; } f(10, ch); - oldcomm::recv(po); + po.recv(); } #[test] -fn test_spawn_sched_childs_on_same_sched() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); +fn test_spawn_sched_childs_on_default_sched() { + let (po, ch) = stream(); + + // Assuming tests run on the default scheduler + let default_id = unsafe { rt::rust_get_sched_id() }; do spawn_sched(SingleThreaded) { - unsafe { - let parent_sched_id = rt::rust_get_sched_id(); - do spawn { - unsafe { - let child_sched_id = rt::rust_get_sched_id(); - // This should be on the same scheduler - assert parent_sched_id == child_sched_id; - oldcomm::send(ch, ()); - } - }; - } + let parent_sched_id = unsafe { rt::rust_get_sched_id() }; + do spawn { + let child_sched_id = unsafe { rt::rust_get_sched_id() }; + assert parent_sched_id != child_sched_id; + assert child_sched_id == default_id; + ch.send(()); + }; }; - oldcomm::recv(po); + po.recv(); } #[nolink] @@ -996,10 +961,8 @@ fn test_spawn_sched_blocking() { // without affecting other schedulers for iter::repeat(20u) { - let start_po = oldcomm::Port(); - let start_ch = oldcomm::Chan(&start_po); - let fin_po = oldcomm::Port(); - let fin_ch = oldcomm::Chan(&fin_po); + let (start_po, start_ch) = stream(); + let (fin_po, fin_ch) = stream(); let lock = testrt::rust_dbg_lock_create(); @@ -1007,44 +970,42 @@ fn test_spawn_sched_blocking() { unsafe { testrt::rust_dbg_lock_lock(lock); - oldcomm::send(start_ch, ()); + start_ch.send(()); // Block the scheduler thread testrt::rust_dbg_lock_wait(lock); testrt::rust_dbg_lock_unlock(lock); - oldcomm::send(fin_ch, ()); + fin_ch.send(()); } }; // Wait until the other task has its lock - oldcomm::recv(start_po); + start_po.recv(); - fn pingpong(po: oldcomm::Port, ch: oldcomm::Chan) { + fn pingpong(po: &Port, ch: &Chan) { let mut val = 20; while val > 0 { - val = oldcomm::recv(po); - oldcomm::send(ch, val - 1); + val = po.recv(); + ch.send(val - 1); } } - let setup_po = oldcomm::Port(); - let setup_ch = oldcomm::Chan(&setup_po); - let parent_po = oldcomm::Port(); - let parent_ch = oldcomm::Chan(&parent_po); + let (setup_po, setup_ch) = stream(); + let (parent_po, parent_ch) = stream(); do spawn { - let child_po = oldcomm::Port(); - oldcomm::send(setup_ch, oldcomm::Chan(&child_po)); - pingpong(child_po, parent_ch); + let (child_po, child_ch) = stream(); + setup_ch.send(child_ch); + pingpong(&child_po, &parent_ch); }; - let child_ch = oldcomm::recv(setup_po); - oldcomm::send(child_ch, 20); - pingpong(parent_po, child_ch); + let child_ch = setup_po.recv(); + child_ch.send(20); + pingpong(&parent_po, &child_ch); testrt::rust_dbg_lock_lock(lock); testrt::rust_dbg_lock_signal(lock); testrt::rust_dbg_lock_unlock(lock); - oldcomm::recv(fin_po); + fin_po.recv(); testrt::rust_dbg_lock_destroy(lock); } } @@ -1052,18 +1013,17 @@ fn test_spawn_sched_blocking() { #[cfg(test)] fn avoid_copying_the_body(spawnfn: fn(v: fn~())) { - let p = oldcomm::Port::(); - let ch = oldcomm::Chan(&p); + let (p, ch) = stream::(); let x = ~1; let x_in_parent = ptr::addr_of(&(*x)) as uint; do spawnfn |move x| { let x_in_child = ptr::addr_of(&(*x)) as uint; - oldcomm::send(ch, x_in_child); + ch.send(x_in_child); } - let x_in_child = oldcomm::recv(p); + let x_in_child = p.recv(); assert x_in_parent == x_in_child; } @@ -1101,20 +1061,18 @@ fn test_avoid_copying_the_body_unlinked() { #[test] fn test_platform_thread() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); do task().sched_mode(PlatformThread).spawn { - oldcomm::send(ch, ()); + ch.send(()); } - oldcomm::recv(po); + po.recv(); } #[test] #[ignore(cfg(windows))] #[should_fail] fn test_unkillable() { - let po = oldcomm::Port(); - let ch = po.chan(); + let (po, ch) = stream(); // We want to do this after failing do spawn_unlinked { @@ -1242,7 +1200,7 @@ fn test_spawn_thread_on_demand() { let (port2, chan2) = pipes::stream(); - do spawn() |move chan2| { + do spawn_sched(CurrentScheduler) |move chan2| { chan2.send(()); } diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index edeacb31e1d09..3db6fa00f16dd 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -74,9 +74,10 @@ #[warn(deprecated_mode)]; use cast; +use container::Map; use oldcomm; use option; -use pipes::{Chan, Port}; +use pipes::{Chan, GenericChan, GenericPort, Port, stream}; use pipes; use prelude::*; use private; @@ -88,6 +89,7 @@ use task::rt::rust_closure; use task::rt; use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded}; use task::{Success, TaskOpts, TaskResult, ThreadPerCore, ThreadPerTask}; +use task::{ExistingScheduler, SchedulerHandle}; use task::{default_task_opts, unkillable}; use uint; use util; @@ -536,9 +538,9 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { // Agh. Get move-mode items into the closure. FIXME (#2829) let (child_tg, ancestors, f) = option::swap_unwrap(child_data); // Create child task. - let new_task = match opts.sched { - None => rt::new_task(), - Some(sched_opts) => new_task_in_new_sched(sched_opts) + let new_task = match opts.sched.mode { + DefaultScheduler => rt::new_task(), + _ => new_task_in_sched(opts.sched) }; assert !new_task.is_null(); // Getting killed after here would leak the task. @@ -642,31 +644,35 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { } } - fn new_task_in_new_sched(opts: SchedOpts) -> *rust_task { - unsafe { - if opts.foreign_stack_size != None { - fail ~"foreign_stack_size scheduler option unimplemented"; - } + fn new_task_in_sched(opts: SchedOpts) -> *rust_task { + if opts.foreign_stack_size != None { + fail ~"foreign_stack_size scheduler option unimplemented"; + } - let num_threads = match opts.mode { - SingleThreaded => 1u, - ThreadPerCore => rt::rust_num_threads(), - ThreadPerTask => { - fail ~"ThreadPerTask scheduling mode unimplemented" - } - ManualThreads(threads) => { - if threads == 0u { - fail ~"can not create a scheduler with no threads"; - } - threads - } - PlatformThread => 0u /* Won't be used */ - }; + let num_threads = match opts.mode { + DefaultScheduler + | CurrentScheduler + | ExistingScheduler(*) + | PlatformThread => 0u, /* Won't be used */ + SingleThreaded => 1u, + ThreadPerCore => unsafe { rt::rust_num_threads() }, + ThreadPerTask => { + fail ~"ThreadPerTask scheduling mode unimplemented" + } + ManualThreads(threads) => { + if threads == 0u { + fail ~"can not create a scheduler with no threads"; + } + threads + } + }; - let sched_id = if opts.mode != PlatformThread { - rt::rust_new_sched(num_threads) - } else { - rt::rust_osmain_sched_id() + unsafe { + let sched_id = match opts.mode { + CurrentScheduler => rt::rust_get_sched_id(), + ExistingScheduler(SchedulerHandle(id)) => id, + PlatformThread => rt::rust_osmain_sched_id(), + _ => rt::rust_new_sched(num_threads) }; rt::rust_new_task_in_sched(sched_id) } @@ -675,12 +681,11 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { #[test] fn test_spawn_raw_simple() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); do spawn_raw(default_task_opts()) { - oldcomm::send(ch, ()); + ch.send(()); } - oldcomm::recv(po); + po.recv(); } #[test] diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index e9d60d0f26923..9707ed8459a40 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -266,6 +266,7 @@ pub pure fn slice(v: &[const T], start: uint, end: uint) -> ~[T] { } /// Return a slice that points into another slice. +#[inline(always)] pub pure fn view(v: &r/[T], start: uint, end: uint) -> &r/[T] { assert (start <= end); assert (end <= len(v)); @@ -279,6 +280,7 @@ pub pure fn view(v: &r/[T], start: uint, end: uint) -> &r/[T] { } /// Return a slice that points into another slice. +#[inline(always)] pub pure fn mut_view(v: &r/[mut T], start: uint, end: uint) -> &r/[mut T] { assert (start <= end); assert (end <= len(v)); @@ -292,6 +294,7 @@ pub pure fn mut_view(v: &r/[mut T], start: uint, end: uint) -> &r/[mut T] { } /// Return a slice that points into another slice. +#[inline(always)] pub pure fn const_view(v: &r/[const T], start: uint, end: uint) -> &r/[const T] { assert (start <= end); @@ -305,6 +308,8 @@ pub pure fn const_view(v: &r/[const T], start: uint, } } +/// Copies + /// Split the vector `v` by applying each element against the predicate `f`. pub fn split(v: &[T], f: fn(t: &T) -> bool) -> ~[~[T]] { let ln = len(v); @@ -2127,6 +2132,7 @@ pub mod raw { * Copies `count` bytes from `src` to `dst`. The source and destination * may overlap. */ + #[inline(always)] pub unsafe fn copy_memory(dst: &[mut T], src: &[const T], count: uint) { assert dst.len() >= count; @@ -2193,6 +2199,7 @@ pub mod bytes { * Copies `count` bytes from `src` to `dst`. The source and destination * may overlap. */ + #[inline(always)] pub fn copy_memory(dst: &[mut u8], src: &[const u8], count: uint) { // Bound checks are done at vec::raw::copy_memory. unsafe { vec::raw::copy_memory(dst, src, count) } diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs index 6657e6fcf0fee..5ccac6f091acc 100644 --- a/src/librustc/front/intrinsic.rs +++ b/src/librustc/front/intrinsic.rs @@ -31,97 +31,97 @@ mod intrinsic { }; trait TyVisitor { - fn visit_bot() -> bool; - fn visit_nil() -> bool; - fn visit_bool() -> bool; - - fn visit_int() -> bool; - fn visit_i8() -> bool; - fn visit_i16() -> bool; - fn visit_i32() -> bool; - fn visit_i64() -> bool; - - fn visit_uint() -> bool; - fn visit_u8() -> bool; - fn visit_u16() -> bool; - fn visit_u32() -> bool; - fn visit_u64() -> bool; - - fn visit_float() -> bool; - fn visit_f32() -> bool; - fn visit_f64() -> bool; - - fn visit_char() -> bool; - fn visit_str() -> bool; - - fn visit_estr_box() -> bool; - fn visit_estr_uniq() -> bool; - fn visit_estr_slice() -> bool; - fn visit_estr_fixed(n: uint, sz: uint, align: uint) -> bool; - - fn visit_box(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_uniq(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_ptr(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_rptr(mtbl: uint, inner: *TyDesc) -> bool; - - fn visit_vec(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_unboxed_vec(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_box(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_uniq(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_slice(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_fixed(n: uint, sz: uint, align: uint, + fn visit_bot(&self) -> bool; + fn visit_nil(&self) -> bool; + fn visit_bool(&self) -> bool; + + fn visit_int(&self) -> bool; + fn visit_i8(&self) -> bool; + fn visit_i16(&self) -> bool; + fn visit_i32(&self) -> bool; + fn visit_i64(&self) -> bool; + + fn visit_uint(&self) -> bool; + fn visit_u8(&self) -> bool; + fn visit_u16(&self) -> bool; + fn visit_u32(&self) -> bool; + fn visit_u64(&self) -> bool; + + fn visit_float(&self) -> bool; + fn visit_f32(&self) -> bool; + fn visit_f64(&self) -> bool; + + fn visit_char(&self) -> bool; + fn visit_str(&self) -> bool; + + fn visit_estr_box(&self) -> bool; + fn visit_estr_uniq(&self) -> bool; + fn visit_estr_slice(&self) -> bool; + fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool; + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool; + + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_enter_rec(n_fields: uint, + fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_rec_field(i: uint, name: &str, + fn visit_rec_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_rec(n_fields: uint, + fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_enter_class(n_fields: uint, + fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_class_field(i: uint, name: &str, + fn visit_class_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_class(n_fields: uint, + fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_enter_tup(n_fields: uint, + fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_tup_field(i: uint, inner: *TyDesc) -> bool; - fn visit_leave_tup(n_fields: uint, + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool; + fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_enter_enum(n_variants: uint, + fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) -> bool; - fn visit_enter_enum_variant(variant: uint, + fn visit_enter_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool; - fn visit_enum_variant_field(i: uint, inner: *TyDesc) -> bool; - fn visit_leave_enum_variant(variant: uint, + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool; + fn visit_leave_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool; - fn visit_leave_enum(n_variants: uint, + fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) -> bool; - fn visit_enter_fn(purity: uint, proto: uint, + fn visit_enter_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool; - fn visit_fn_input(i: uint, mode: uint, inner: *TyDesc) -> bool; - fn visit_fn_output(retstyle: uint, inner: *TyDesc) -> bool; - fn visit_leave_fn(purity: uint, proto: uint, + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool; + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool; + fn visit_leave_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool; - fn visit_trait() -> bool; - fn visit_var() -> bool; - fn visit_var_integral() -> bool; - fn visit_param(i: uint) -> bool; - fn visit_self() -> bool; - fn visit_type() -> bool; - fn visit_opaque_box() -> bool; - fn visit_constr(inner: *TyDesc) -> bool; - fn visit_closure_ptr(ck: uint) -> bool; + fn visit_trait(&self) -> bool; + fn visit_var(&self) -> bool; + fn visit_var_integral(&self) -> bool; + fn visit_param(&self, i: uint) -> bool; + fn visit_self(&self) -> bool; + fn visit_type(&self) -> bool; + fn visit_opaque_box(&self) -> bool; + fn visit_constr(&self, inner: *TyDesc) -> bool; + fn visit_closure_ptr(&self, ck: uint) -> bool; } #[abi = "rust-intrinsic"] diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 79ce755137efc..399184ea8a586 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -37,6 +37,7 @@ use core::to_bytes::IterBytes; use core::uint; use core::vec; use std::map::HashMap; +use std::serialize::Encodable; use std::{ebml, map}; use std; use syntax::ast::*; diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 6a09ae14d01dc..787a1d3c906c2 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -17,7 +17,8 @@ use core::prelude::*; use middle::ty; -use middle::ty::{FnTyBase, FnMeta, FnSig}; +use middle::ty::{FnTyBase, FnMeta, FnSig, arg, creader_cache_key, field}; +use middle::ty::{substs}; use core::io; use core::str; @@ -174,9 +175,11 @@ fn parse_substs(st: @pstate, conv: conv_did) -> ty::substs { while peek(st) != ']' { params.push(parse_ty(st, conv)); } st.pos = st.pos + 1u; - return {self_r: self_r, - self_ty: self_ty, - tps: params}; + return substs { + self_r: self_r, + self_ty: self_ty, + tps: params + }; } fn parse_bound_region(st: @pstate) -> ty::bound_region { @@ -308,7 +311,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { let mut fields: ~[ty::field] = ~[]; while peek(st) != ']' { let name = st.tcx.sess.ident_of(parse_str(st, '=')); - fields.push({ident: name, mt: parse_mt(st, conv)}); + fields.push(ty::field { ident: name, mt: parse_mt(st, conv) }); } st.pos = st.pos + 1u; return ty::mk_rec(st.tcx, fields); @@ -323,9 +326,6 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { 'f' => { parse_ty_rust_fn(st, conv) } - 'X' => { - return ty::mk_var(st.tcx, ty::TyVid(parse_int(st) as uint)); - } 'Y' => return ty::mk_type(st.tcx), 'C' => { let proto = parse_proto(st); @@ -336,12 +336,13 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { assert (next(st) == ':'); let len = parse_hex(st); assert (next(st) == '#'); - match st.tcx.rcache.find({cnum: st.crate, pos: pos, len: len}) { + let key = creader_cache_key { cnum: st.crate, pos: pos, len: len }; + match st.tcx.rcache.find(key) { Some(tt) => return tt, None => { let ps = @{pos: pos ,.. copy *st}; let tt = parse_ty(ps, conv); - st.tcx.rcache.insert({cnum: st.crate, pos: pos, len: len}, tt); + st.tcx.rcache.insert(key, tt); return tt; } } @@ -424,8 +425,7 @@ fn parse_onceness(c: char) -> ast::Onceness { } fn parse_arg(st: @pstate, conv: conv_did) -> ty::arg { - {mode: parse_mode(st), - ty: parse_ty(st, conv)} + ty::arg { mode: parse_mode(st), ty: parse_ty(st, conv) } } fn parse_mode(st: @pstate) -> ast::mode { @@ -449,7 +449,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy { let mut inputs: ~[ty::arg] = ~[]; while peek(st) != ']' { let mode = parse_mode(st); - inputs.push({mode: mode, ty: parse_ty(st, conv)}); + inputs.push(ty::arg { mode: mode, ty: parse_ty(st, conv) }); } st.pos += 1u; // eat the ']' let ret_ty = parse_ty(st, conv); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 154fb8d2de85a..04e833d812bd7 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -13,8 +13,8 @@ use core::prelude::*; +use middle::ty::{Vid, param_ty}; use middle::ty; -use middle::ty::Vid; use core::io::WriterUtil; use core::io; @@ -298,21 +298,10 @@ fn enc_sty(w: io::Writer, cx: @ctxt, +st: ty::sty) { ty::ty_fn(ref f) => { enc_ty_fn(w, cx, (*f)); } - ty::ty_infer(ty::TyVar(id)) => { - w.write_char('X'); - w.write_uint(id.to_uint()); - } - ty::ty_infer(ty::IntVar(id)) => { - w.write_char('X'); - w.write_char('I'); - w.write_uint(id.to_uint()); - } - ty::ty_infer(ty::FloatVar(id)) => { - w.write_char('X'); - w.write_char('F'); - w.write_uint(id.to_uint()); + ty::ty_infer(_) => { + cx.diag.handler().bug(~"Cannot encode inference variable types"); } - ty::ty_param({idx: id, def_id: did}) => { + ty::ty_param(param_ty {idx: id, def_id: did}) => { w.write_char('p'); w.write_str((cx.ds)(did)); w.write_char('|'); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index ff5854322f456..bdb889b68f116 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -20,7 +20,7 @@ use core::prelude::*; use middle::borrowck::{Loan, bckerr, borrowck_ctxt, cmt, inherent_mutability}; -use middle::borrowck::{req_maps, save_and_restore}; +use middle::borrowck::{req_maps, root_map_key, save_and_restore}; use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref}; use middle::mem_categorization::{cat_local, cat_rvalue, cat_self}; use middle::mem_categorization::{cat_special, gc_ptr, loan_path, lp_arg}; @@ -396,7 +396,10 @@ impl check_loan_ctxt { match ptr_kind { gc_ptr(ast::m_mutbl) => { - let key = { id: base.id, derefs: deref_count }; + let key = root_map_key { + id: base.id, + derefs: deref_count + }; self.bccx.write_guard_map.insert(key, ()); } _ => {} diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 967b1681b1bfb..6f913f99e11fd 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -19,7 +19,8 @@ use core::prelude::*; use middle::borrowck::preserve::{preserve_condition, pc_ok, pc_if_pure}; -use middle::borrowck::{Loan, bckres, borrowck_ctxt, err_mutbl, req_maps}; +use middle::borrowck::{Loan, bckerr, bckres, borrowck_ctxt, err_mutbl}; +use middle::borrowck::{req_maps}; use middle::mem_categorization::{cat_binding, cat_discr, cmt, comp_variant}; use middle::mem_categorization::{mem_categorization_ctxt}; use middle::mem_categorization::{opt_deref_kind}; @@ -452,8 +453,7 @@ impl gather_loan_ctxt { debug!("required is const or they are the same"); Ok(pc_ok) } else { - let e = {cmt: cmt, - code: err_mutbl(req_mutbl)}; + let e = bckerr { cmt: cmt, code: err_mutbl(req_mutbl) }; if req_mutbl == m_imm { // if this is an @mut box, then it's generally OK to borrow as // &imm; this will result in a write guard @@ -591,11 +591,53 @@ impl gather_loan_ctxt { } } + ast::pat_vec(_, Some(tail_pat)) => { + // The `tail_pat` here creates a slice into the + // original vector. This is effectively a borrow of + // the elements of the vector being matched. + + let tail_ty = self.tcx().ty(tail_pat); + let (tail_mutbl, tail_r) = + self.vec_slice_info(tail_pat, tail_ty); + let mcx = self.bccx.mc_ctxt(); + let cmt_index = mcx.cat_index(tail_pat, cmt); + self.guarantee_valid(cmt_index, tail_mutbl, tail_r); + } + _ => {} } } } + fn vec_slice_info(&self, + pat: @ast::pat, + tail_ty: ty::t) -> (ast::mutability, ty::Region) + { + /*! + * + * In a pattern like [a, b, ..c], normally `c` has slice type, + * but if you have [a, b, ..ref c], then the type of `ref c` + * will be `&&[]`, so to extract the slice details we have + * to recurse through rptrs. + */ + + match ty::get(tail_ty).sty { + ty::ty_evec(tail_mt, ty::vstore_slice(tail_r)) => { + (tail_mt.mutbl, tail_r) + } + + ty::ty_rptr(_, ref mt) => { + self.vec_slice_info(pat, mt.ty) + } + + _ => { + self.tcx().sess.span_bug( + pat.span, + fmt!("Type of tail pattern is not a slice")); + } + } + } + fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool { pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) } diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index 1b274a5241c67..48cc0502f6c87 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -8,13 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +The `Loan` module deals with borrows of *uniquely mutable* data. We +say that data is uniquely mutable if the current activation (stack +frame) controls the only mutable reference to the data. The most +common way that this can occur is if the current activation owns the +data being borrowed, but it can also occur with `&mut` pointers. The +primary characteristic of uniquely mutable data is that, at any given +time, there is at most one path that can be used to mutate it, and +that path is only accessible from the top stack frame. + +Given that some data found at a path P is being borrowed to a borrowed +pointer with mutability M and lifetime L, the job of the code in this +module is to compute the set of *loans* that are necessary to ensure +that (1) the data found at P outlives L and that (2) if M is mutable +then the path P will not be modified directly or indirectly except +through that pointer. A *loan* is the combination of a path P_L, a +mutability M_L, and a lifetime L_L where: + +- The path P_L indicates what data has been lent. +- The mutability M_L indicates the access rights on the data: + - const: the data cannot be moved + - immutable/mutable: the data cannot be moved or mutated +- The lifetime L_L indicates the *scope* of the loan. + +XXX --- much more needed, don't have time to write this all up now + +*/ + // ---------------------------------------------------------------------- // Loan(Ex, M, S) = Ls holds if ToAddr(Ex) will remain valid for the entirety // of the scope S, presuming that the returned set of loans `Ls` are honored. use core::prelude::*; -use middle::borrowck::{Loan, bckres, borrowck_ctxt, cmt, err_mutbl}; +use middle::borrowck::{Loan, bckerr, bckres, borrowck_ctxt, cmt, err_mutbl}; use middle::borrowck::{err_out_of_scope}; use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp}; use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self}; @@ -39,7 +68,7 @@ impl borrowck_ctxt { scope_region: scope_region, loans: ~[] }; - match lc.loan(cmt, mutbl) { + match lc.loan(cmt, mutbl, true) { Err(ref e) => Err((*e)), Ok(()) => { let LoanContext {loans, _} = move lc; @@ -62,46 +91,25 @@ struct LoanContext { impl LoanContext { fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - fn issue_loan(&self, - cmt: cmt, - scope_ub: ty::Region, - req_mutbl: ast::mutability) -> bckres<()> { - if self.bccx.is_subregion_of(self.scope_region, scope_ub) { - match req_mutbl { - m_mutbl => { - // We do not allow non-mutable data to be loaned - // out as mutable under any circumstances. - if cmt.mutbl != m_mutbl { - return Err({cmt:cmt, - code:err_mutbl(req_mutbl)}); - } - } - m_const | m_imm => { - // However, mutable data can be loaned out as - // immutable (and any data as const). The - // `check_loans` pass will then guarantee that no - // writes occur for the duration of the loan. - } - } - - self.loans.push(Loan { - // Note: cmt.lp must be Some(_) because otherwise this - // loan process does not apply at all. - lp: cmt.lp.get(), - cmt: cmt, - mutbl: req_mutbl - }); - return Ok(()); - } else { - // The loan being requested lives longer than the data - // being loaned out! - return Err({cmt:cmt, - code:err_out_of_scope(scope_ub, - self.scope_region)}); - } - } + fn loan(&self, + cmt: cmt, + req_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> + { + /*! + * + * The main routine. + * + * # Parameters + * + * - `cmt`: the categorization of the data being borrowed + * - `req_mutbl`: the mutability of the borrowed pointer + * that was created + * - `owns_lent_data`: indicates whether `cmt` owns the + * data that is being lent. See + * discussion in `issue_loan()`. + */ - fn loan(&self, cmt: cmt, req_mutbl: ast::mutability) -> bckres<()> { debug!("loan(%s, %s)", self.bccx.cmt_to_repr(cmt), self.bccx.mut_to_str(req_mutbl)); @@ -123,13 +131,14 @@ impl LoanContext { } cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => { let local_scope_id = self.tcx().region_map.get(local_id); - self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl) + self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl, + owns_lent_data) } cat_stack_upvar(cmt) => { - self.loan(cmt, req_mutbl) // NDM correct? + self.loan(cmt, req_mutbl, owns_lent_data) } cat_discr(base, _) => { - self.loan(base, req_mutbl) + self.loan(base, req_mutbl, owns_lent_data) } cat_comp(cmt_base, comp_field(_, m)) | cat_comp(cmt_base, comp_index(_, m)) => { @@ -139,36 +148,41 @@ impl LoanContext { // that case, it must also be embedded in an immutable // location, or else the whole structure could be // overwritten and the component along with it. - self.loan_stable_comp(cmt, cmt_base, req_mutbl, m) + self.loan_stable_comp(cmt, cmt_base, req_mutbl, m, + owns_lent_data) } cat_comp(cmt_base, comp_tuple) | cat_comp(cmt_base, comp_anon_field) => { // As above. - self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm) + self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm, + owns_lent_data) } cat_comp(cmt_base, comp_variant(enum_did)) => { // For enums, the memory is unstable if there are multiple // variants, because if the enum value is overwritten then // the memory changes type. if ty::enum_is_univariant(self.bccx.tcx, enum_did) { - self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm) + self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm, + owns_lent_data) } else { - self.loan_unstable_deref(cmt, cmt_base, req_mutbl) + self.loan_unstable_deref(cmt, cmt_base, req_mutbl, + owns_lent_data) } } cat_deref(cmt_base, _, uniq_ptr) => { // For unique pointers, the memory being pointed out is // unstable because if the unique pointer is overwritten // then the memory is freed. - self.loan_unstable_deref(cmt, cmt_base, req_mutbl) + self.loan_unstable_deref(cmt, cmt_base, req_mutbl, + owns_lent_data) } cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => { // Mutable data can be loaned out as immutable or const. We must // loan out the base as well as the main memory. For example, // if someone borrows `*b`, we want to borrow `b` as immutable // as well. - do self.loan(cmt_base, m_imm).chain |_| { - self.issue_loan(cmt, region, m_const) + do self.loan(cmt_base, m_imm, false).chain |_| { + self.issue_loan(cmt, region, m_const, owns_lent_data) } } cat_deref(_, _, unsafe_ptr) | @@ -189,7 +203,8 @@ impl LoanContext { cmt: cmt, cmt_base: cmt, req_mutbl: ast::mutability, - comp_mutbl: ast::mutability) -> bckres<()> { + comp_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> { // Determine the mutability that the base component must have, // given the required mutability of the pointer (`req_mutbl`) // and the declared mutability of the component (`comp_mutbl`). @@ -243,10 +258,11 @@ impl LoanContext { (m_const, _) => m_const // (5) }; - do self.loan(cmt_base, base_mutbl).chain |_ok| { + do self.loan(cmt_base, base_mutbl, owns_lent_data).chain |_ok| { // can use static for the scope because the base // determines the lifetime, ultimately - self.issue_loan(cmt, ty::re_static, req_mutbl) + self.issue_loan(cmt, ty::re_static, req_mutbl, + owns_lent_data) } } @@ -256,13 +272,72 @@ impl LoanContext { fn loan_unstable_deref(&self, cmt: cmt, cmt_base: cmt, - req_mutbl: ast::mutability) -> bckres<()> { + req_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> + { // Variant components: the base must be immutable, because // if it is overwritten, the types of the embedded data // could change. - do self.loan(cmt_base, m_imm).chain |_| { + do self.loan(cmt_base, m_imm, owns_lent_data).chain |_| { // can use static, as in loan_stable_comp() - self.issue_loan(cmt, ty::re_static, req_mutbl) + self.issue_loan(cmt, ty::re_static, req_mutbl, + owns_lent_data) + } + } + + fn issue_loan(&self, + cmt: cmt, + scope_ub: ty::Region, + req_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> + { + // Subtle: the `scope_ub` is the maximal lifetime of `cmt`. + // Therefore, if `cmt` owns the data being lent, then the + // scope of the loan must be less than `scope_ub`, or else the + // data would be freed while the loan is active. + // + // However, if `cmt` does *not* own the data being lent, then + // it is ok if `cmt` goes out of scope during the loan. This + // can occur when you have an `&mut` parameter that is being + // reborrowed. + + if !owns_lent_data || + self.bccx.is_subregion_of(self.scope_region, scope_ub) + { + match req_mutbl { + m_mutbl => { + // We do not allow non-mutable data to be loaned + // out as mutable under any circumstances. + if cmt.mutbl != m_mutbl { + return Err(bckerr { + cmt:cmt, + code:err_mutbl(req_mutbl) + }); + } + } + m_const | m_imm => { + // However, mutable data can be loaned out as + // immutable (and any data as const). The + // `check_loans` pass will then guarantee that no + // writes occur for the duration of the loan. + } + } + + self.loans.push(Loan { + // Note: cmt.lp must be Some(_) because otherwise this + // loan process does not apply at all. + lp: cmt.lp.get(), + cmt: cmt, + mutbl: req_mutbl + }); + return Ok(()); + } else { + // The loan being requested lives longer than the data + // being loaned out! + return Err(bckerr { + cmt:cmt, + code:err_out_of_scope(scope_ub, self.scope_region) + }); } } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 35c1c96befae5..2afdcc9d47d53 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -344,7 +344,11 @@ type root_map = HashMap; // if you have an expression `x.f` and x has type ~@T, we could add an // entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}` // to refer to the deref of the unique pointer, and so on. -type root_map_key = {id: ast::node_id, derefs: uint}; +#[deriving_eq] +struct root_map_key { + id: ast::node_id, + derefs: uint +} // set of ids of local vars / formal arguments that are modified / moved. // this is used in trans for optimization purposes. @@ -411,13 +415,10 @@ impl bckerr_code : cmp::Eq { // Combination of an error code and the categorization of the expression // that caused it -type bckerr = {cmt: cmt, code: bckerr_code}; - -impl bckerr : cmp::Eq { - pure fn eq(&self, other: &bckerr) -> bool { - (*self).cmt == (*other).cmt && (*self).code == (*other).code - } - pure fn ne(&self, other: &bckerr) -> bool { !(*self).eq(other) } +#[deriving_eq] +struct bckerr { + cmt: cmt, + code: bckerr_code } // shorthand for something that fails with `bckerr` or succeeds with `T` @@ -446,15 +447,6 @@ fn save_and_restore(save_and_restore_t: &mut T, f: fn() -> U) -> U { /// Creates and returns a new root_map -impl root_map_key : cmp::Eq { - pure fn eq(&self, other: &root_map_key) -> bool { - (*self).id == (*other).id && (*self).derefs == (*other).derefs - } - pure fn ne(&self, other: &root_map_key) -> bool { - ! ((*self) == (*other)) - } -} - impl root_map_key : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f); @@ -501,12 +493,16 @@ impl borrowck_ctxt { } fn cat_discr(cmt: cmt, match_id: ast::node_id) -> cmt { - return @{cat:cat_discr(cmt, match_id),.. *cmt}; + return @cmt_ { cat: cat_discr(cmt, match_id),.. *cmt }; + } + + fn mc_ctxt() -> mem_categorization_ctxt { + mem_categorization_ctxt {tcx: self.tcx, + method_map: self.method_map} } fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; + let mc = self.mc_ctxt(); mc.cat_pattern(cmt, pat, op); } diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs index 5916588a9a2bb..5edfd294d8477 100644 --- a/src/librustc/middle/borrowck/preserve.rs +++ b/src/librustc/middle/borrowck/preserve.rs @@ -18,7 +18,7 @@ use core::prelude::*; use middle::borrowck::{RootInfo, bckerr, bckerr_code, bckres, borrowck_ctxt}; use middle::borrowck::{cmt, err_mut_uniq, err_mut_variant}; use middle::borrowck::{err_out_of_root_scope, err_out_of_scope}; -use middle::borrowck::{err_root_not_permitted}; +use middle::borrowck::{err_root_not_permitted, root_map_key}; use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref}; use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special}; use middle::mem_categorization::{cat_stack_upvar, comp_field, comp_index}; @@ -291,7 +291,7 @@ priv impl &preserve_ctxt { Ok(pc_ok) => { match cmt_base.mutbl { m_mutbl | m_const => { - Ok(pc_if_pure({cmt:cmt, code:code})) + Ok(pc_if_pure(bckerr { cmt: cmt, code: code })) } m_imm => { Ok(pc_ok) @@ -318,8 +318,10 @@ priv impl &preserve_ctxt { if self.bccx.is_subregion_of(self.scope_region, scope_ub) { Ok(pc_ok) } else { - Err({cmt:cmt, code:err_out_of_scope(scope_ub, - self.scope_region)}) + Err(bckerr { + cmt:cmt, + code:err_out_of_scope(scope_ub, self.scope_region) + }) } } @@ -345,7 +347,7 @@ priv impl &preserve_ctxt { // would be sort of pointless to avoid rooting the inner // box by rooting an outer box, as it would just keep more // memory live than necessary, so we set root_ub to none. - return Err({cmt:cmt, code:err_root_not_permitted}); + return Err(bckerr { cmt: cmt, code: err_root_not_permitted }); } let root_region = ty::re_scope(self.root_ub); @@ -359,7 +361,7 @@ priv impl &preserve_ctxt { derefs, scope_id, self.root_ub); if self.bccx.is_subregion_of(self.scope_region, root_region) { debug!("Elected to root"); - let rk = {id: base.id, derefs: derefs}; + let rk = root_map_key { id: base.id, derefs: derefs }; // This code could potentially lead cause boxes to be frozen // for longer than necessarily at runtime. It prevents an // ICE in trans; the fundamental problem is that it's hard @@ -389,17 +391,20 @@ priv impl &preserve_ctxt { return Ok(pc_ok); } else { debug!("Unable to root"); - return Err({cmt:cmt, - code:err_out_of_root_scope(root_region, - self.scope_region)}); + return Err(bckerr { + cmt: cmt, + code: err_out_of_root_scope(root_region, + self.scope_region) + }); } } // we won't be able to root long enough _ => { - return Err({cmt:cmt, - code:err_out_of_root_scope(root_region, - self.scope_region)}); + return Err(bckerr { + cmt:cmt, + code:err_out_of_root_scope(root_region, self.scope_region) + }); } } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 515666445e3aa..9b4911d9fbea7 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -233,7 +233,7 @@ fn get_lint_dict() -> lint_dict { (~"deprecated_self", @{lint: deprecated_self, desc: "warn about deprecated uses of `self`", - default: allow}), + default: warn}), /* FIXME(#3266)--make liveness warnings lintable (~"unused_variable", @@ -631,13 +631,18 @@ fn check_item_deprecated_self(cx: ty::ctxt, item: @ast::item) { fn maybe_warn(cx: ty::ctxt, item: @ast::item, self_ty: ast::self_ty) { - cx.sess.span_lint( - deprecated_self, - item.id, - item.id, - self_ty.span, - ~"this method form is deprecated; use an explicit `self` \ - parameter or mark the method as static"); + match self_ty.node { + ast::sty_by_ref => { + cx.sess.span_lint( + deprecated_self, + item.id, + item.id, + self_ty.span, + ~"this method form is deprecated; use an explicit `self` \ + parameter or mark the method as static"); + } + _ => {} + } } match /*bad*/copy item.node { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 909d1f95fde4b..9ea03440ad6b4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -111,27 +111,20 @@ enum special_kind { // a complete categorization of a value indicating where it originated // and how it is located, as well as the mutability of the memory in // which the value is stored. -type cmt_ = {id: ast::node_id, // id of expr/pat producing this value - span: span, // span of same expr/pat - cat: categorization, // categorization of expr - lp: Option<@loan_path>, // loan path for expr, if any - mutbl: ast::mutability, // mutability of expr as lvalue - ty: ty::t}; // type of the expr +// +// note: cmt stands for "categorized mutable type". +#[deriving_eq] +struct cmt_ { + id: ast::node_id, // id of expr/pat producing this value + span: span, // span of same expr/pat + cat: categorization, // categorization of expr + lp: Option<@loan_path>, // loan path for expr, if any + mutbl: ast::mutability, // mutability of expr as lvalue + ty: ty::t // type of the expr +} type cmt = @cmt_; -impl cmt_ : cmp::Eq { - pure fn eq(&self, other: &cmt_) -> bool { - (*self).id == (*other).id && - (*self).span == (*other).span && - (*self).cat == (*other).cat && - (*self).lp == (*other).lp && - (*self).mutbl == (*other).mutbl && - (*self).ty == (*other).ty - } - pure fn ne(&self, other: &cmt_) -> bool { !(*self).eq(other) } -} - // a loan path is like a category, but it exists only when the data is // interior to the stack frame. loan paths are used as the key to a // map indicating what is borrowed at any point in time. @@ -421,9 +414,14 @@ impl &mem_categorization_ctxt { ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | ast::def_label(_) | ast::def_self_ty(*) => { - @{id:id, span:span, - cat:cat_special(sk_static_item), lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_special(sk_static_item), + lp:None, + mutbl:m_imm, + ty:expr_ty + } } ast::def_arg(vid, mode, mutbl) => { @@ -449,9 +447,14 @@ impl &mem_categorization_ctxt { None } }; - @{id:id, span:span, - cat:cat_arg(vid), lp:lp, - mutbl:m, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_arg(vid), + lp:lp, + mutbl:m, + ty:expr_ty + } } ast::def_self(self_id, is_implicit) => { @@ -464,9 +467,14 @@ impl &mem_categorization_ctxt { loan_path = Some(@lp_self); }; - @{id:id, span:span, - cat:cat, lp:loan_path, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat, + lp:loan_path, + mutbl:m_imm, + ty:expr_ty + } } ast::def_upvar(_, inner, fn_node_id, _) => { @@ -475,15 +483,25 @@ impl &mem_categorization_ctxt { match proto { ast::ProtoBorrowed => { let upcmt = self.cat_def(id, span, expr_ty, *inner); - @{id:id, span:span, - cat:cat_stack_upvar(upcmt), lp:upcmt.lp, - mutbl:upcmt.mutbl, ty:upcmt.ty} + @cmt_ { + id:id, + span:span, + cat:cat_stack_upvar(upcmt), + lp:upcmt.lp, + mutbl:upcmt.mutbl, + ty:upcmt.ty + } } ast::ProtoUniq | ast::ProtoBox => { // FIXME #2152 allow mutation of moved upvars - @{id:id, span:span, - cat:cat_special(sk_heap_upvar), lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_special(sk_heap_upvar), + lp:None, + mutbl:m_imm, + ty:expr_ty + } } ast::ProtoBare => { self.tcx.sess.span_bug( @@ -495,16 +513,26 @@ impl &mem_categorization_ctxt { ast::def_local(vid, mutbl) => { let m = if mutbl {m_mutbl} else {m_imm}; - @{id:id, span:span, - cat:cat_local(vid), lp:Some(@lp_local(vid)), - mutbl:m, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_local(vid), + lp:Some(@lp_local(vid)), + mutbl:m, + ty:expr_ty + } } ast::def_binding(vid, _) => { // by-value/by-ref bindings are local variables - @{id:id, span:span, - cat:cat_local(vid), lp:Some(@lp_local(vid)), - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_local(vid), + lp:Some(@lp_local(vid)), + mutbl:m_imm, + ty:expr_ty + } } } } @@ -512,17 +540,25 @@ impl &mem_categorization_ctxt { fn cat_variant(arg: N, enum_did: ast::def_id, cmt: cmt) -> cmt { - @{id: arg.id(), span: arg.span(), - cat: cat_comp(cmt, comp_variant(enum_did)), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ), - mutbl: cmt.mutbl, // imm iff in an immutable context - ty: self.tcx.ty(arg)} + @cmt_ { + id: arg.id(), + span: arg.span(), + cat: cat_comp(cmt, comp_variant(enum_did)), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(arg) + } } - fn cat_rvalue(expr: @ast::expr, expr_ty: ty::t) -> cmt { - @{id:expr.id, span:expr.span, - cat:cat_rvalue, lp:None, - mutbl:m_imm, ty:expr_ty} + fn cat_rvalue(elt: N, expr_ty: ty::t) -> cmt { + @cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_rvalue, + lp:None, + mutbl:m_imm, + ty:expr_ty + } } /// inherited mutability: used in cases where the mutability of a @@ -557,9 +593,14 @@ impl &mem_categorization_ctxt { let m = self.inherited_mutability(base_cmt.mutbl, f_mutbl); let f_comp = comp_field(f_name, f_mutbl); let lp = base_cmt.lp.map(|lp| @lp_comp(*lp, f_comp) ); - @{id: node.id(), span: node.span(), - cat: cat_comp(base_cmt, f_comp), lp:lp, - mutbl: m, ty: self.tcx.ty(node)} + @cmt_ { + id: node.id(), + span: node.span(), + cat: cat_comp(base_cmt, f_comp), + lp:lp, + mutbl: m, + ty: self.tcx.ty(node) + } } fn cat_deref_fn(node: N, @@ -626,27 +667,37 @@ impl &mem_categorization_ctxt { } }; - @{id:node.id(), span:node.span(), - cat:cat_deref(base_cmt, deref_cnt, ptr), lp:lp, - mutbl:m, ty:mt.ty} + @cmt_ { + id:node.id(), + span:node.span(), + cat:cat_deref(base_cmt, deref_cnt, ptr), + lp:lp, + mutbl:m, + ty:mt.ty + } } deref_comp(comp) => { let lp = base_cmt.lp.map(|l| @lp_comp(*l, comp) ); let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); - @{id:node.id(), span:node.span(), - cat:cat_comp(base_cmt, comp), lp:lp, - mutbl:m, ty:mt.ty} + @cmt_ { + id:node.id(), + span:node.span(), + cat:cat_comp(base_cmt, comp), + lp:lp, + mutbl:m, + ty:mt.ty + } } } } - fn cat_index(expr: @ast::expr, base_cmt: cmt) -> cmt { + fn cat_index(elt: N, base_cmt: cmt) -> cmt { let mt = match ty::index(self.tcx, base_cmt.ty) { Some(mt) => mt, None => { self.tcx.sess.span_bug( - expr.span, + elt.span(), fmt!("Explicit index of non-index type `%s`", ty_to_str(self.tcx, base_cmt.ty))); } @@ -673,56 +724,77 @@ impl &mem_categorization_ctxt { }; // (c) the deref is explicit in the resulting cmt - let deref_cmt = @{id:expr.id, span:expr.span, - cat:cat_deref(base_cmt, 0u, ptr), lp:deref_lp, - mutbl:m, ty:mt.ty}; + let deref_cmt = @cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_deref(base_cmt, 0u, ptr), + lp:deref_lp, + mutbl:m, + ty:mt.ty + }; - comp(expr, deref_cmt, base_cmt.ty, m, mt.ty) + comp(elt, deref_cmt, base_cmt.ty, m, mt.ty) } deref_comp(_) => { // fixed-length vectors have no deref let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); - comp(expr, base_cmt, base_cmt.ty, m, mt.ty) + comp(elt, base_cmt, base_cmt.ty, m, mt.ty) } }; - fn comp(expr: @ast::expr, of_cmt: cmt, - vect: ty::t, mutbl: ast::mutability, ty: ty::t) -> cmt { + fn comp(elt: N, of_cmt: cmt, + vect: ty::t, mutbl: ast::mutability, + ty: ty::t) -> cmt + { let comp = comp_index(vect, mutbl); let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) ); - @{id:expr.id, span:expr.span, - cat:cat_comp(of_cmt, comp), lp:index_lp, - mutbl:mutbl, ty:ty} + @cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_comp(of_cmt, comp), + lp:index_lp, + mutbl:mutbl, + ty:ty + } } } fn cat_tuple_elt(elt: N, cmt: cmt) -> cmt { - @{id: elt.id(), span: elt.span(), - cat: cat_comp(cmt, comp_tuple), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ), - mutbl: cmt.mutbl, // imm iff in an immutable context - ty: self.tcx.ty(elt)} + @cmt_ { + id: elt.id(), + span: elt.span(), + cat: cat_comp(cmt, comp_tuple), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(elt) + } } fn cat_anon_struct_field(elt: N, cmt: cmt) -> cmt { - @{id: elt.id(), span: elt.span(), - cat: cat_comp(cmt, comp_anon_field), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), - mutbl: cmt.mutbl, // imm iff in an immutable context - ty: self.tcx.ty(elt)} + @cmt_ { + id: elt.id(), + span: elt.span(), + cat: cat_comp(cmt, comp_anon_field), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(elt) + } } fn cat_method_ref(expr: @ast::expr, expr_ty: ty::t) -> cmt { - @{id:expr.id, span:expr.span, - cat:cat_special(sk_method), lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:expr.id, + span:expr.span, + cat:cat_special(sk_method), + lp:None, + mutbl:m_imm, + ty:expr_ty + } } fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) { - op(cmt, pat); - // Here, `cmt` is the categorization for the value being // matched and pat is the pattern it is being matched against. // @@ -757,13 +829,15 @@ impl &mem_categorization_ctxt { // and the id of `local(x)->@->@` is the id of the `y` pattern. - let _i = indenter(); let tcx = self.tcx; debug!("cat_pattern: id=%d pat=%s cmt=%s", pat.id, pprust::pat_to_str(pat, tcx.sess.intr()), self.cmt_to_repr(cmt)); + let _i = indenter(); + + op(cmt, pat); - match /*bad*/copy pat.node { + match pat.node { ast::pat_wild => { // _ } @@ -771,7 +845,7 @@ impl &mem_categorization_ctxt { ast::pat_enum(_, None) => { // variant(*) } - ast::pat_enum(_, Some(subpats)) => { + ast::pat_enum(_, Some(ref subpats)) => { match self.tcx.def_map.find(pat.id) { Some(ast::def_variant(enum_did, _)) => { // variant(x, y, z) @@ -803,15 +877,8 @@ impl &mem_categorization_ctxt { // nullary variant or identifier: ignore } - ast::pat_rec(field_pats, _) => { - // {f1: p1, ..., fN: pN} - for field_pats.each |fp| { - let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id); - self.cat_pattern(cmt_field, fp.pat, op); - } - } - - ast::pat_struct(_, field_pats, _) => { + ast::pat_rec(ref field_pats, _) | + ast::pat_struct(_, ref field_pats, _) => { // {f1: p1, ..., fN: pN} for field_pats.each |fp| { let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id); @@ -819,7 +886,7 @@ impl &mem_categorization_ctxt { } } - ast::pat_tup(subpats) => { + ast::pat_tup(ref subpats) => { // (p1, ..., pN) for subpats.each |subpat| { let subcmt = self.cat_tuple_elt(*subpat, cmt); @@ -834,7 +901,20 @@ impl &mem_categorization_ctxt { self.cat_pattern(subcmt, subpat, op); } - ast::pat_vec(*) | ast::pat_lit(_) | ast::pat_range(_, _) => { + ast::pat_vec(ref pats, opt_tail_pat) => { + for pats.each |pat| { + let elt_cmt = self.cat_index(*pat, cmt); + self.cat_pattern(elt_cmt, *pat, op); + } + + for opt_tail_pat.each |tail_pat| { + let tail_ty = self.tcx.ty(*tail_pat); + let tail_cmt = self.cat_rvalue(*tail_pat, tail_ty); + self.cat_pattern(tail_cmt, *tail_pat, op); + } + } + + ast::pat_lit(_) | ast::pat_range(_, _) => { /*always ok*/ } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index dd355f6df702c..ac3a16b07a0b1 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -397,17 +397,15 @@ fn resolve_crate(sess: Session, def_map: resolve::DefMap, // dependencies until a fixed point is reached. type region_paramd_items = HashMap; -type region_dep = {ambient_variance: region_variance, id: ast::node_id}; -type dep_map = HashMap>; -impl region_dep : cmp::Eq { - pure fn eq(&self, other: ®ion_dep) -> bool { - (*self).ambient_variance == (*other).ambient_variance && - (*self).id == (*other).id - } - pure fn ne(&self, other: ®ion_dep) -> bool { !(*self).eq(other) } +#[deriving_eq] +struct region_dep { + ambient_variance: region_variance, + id: ast::node_id } +type dep_map = HashMap>; + type determine_rp_ctxt_ = { sess: Session, ast_map: ast_map::map, @@ -511,7 +509,10 @@ impl determine_rp_ctxt { vec } }; - let dep = {ambient_variance: self.ambient_variance, id: self.item_id}; + let dep = region_dep { + ambient_variance: self.ambient_variance, + id: self.item_id + }; if !vec.contains(&dep) { vec.push(dep); } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 68198ae3f3fc9..60ed64b1c1d5e 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -25,6 +25,7 @@ use core::str; use core::vec; use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk, capture_clause}; +use syntax::ast::{bind_by_value, bind_infer, bind_by_ref, bind_by_move}; use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding}; use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; @@ -4521,6 +4522,10 @@ impl Resolver { struct or enum variant", self.session.str_of(ident)); + self.enforce_default_binding_mode( + pattern, + binding_mode, + "an enum variant"); self.record_def(pattern.id, def); } FoundStructOrEnumVariant(_) => { @@ -4537,6 +4542,10 @@ impl Resolver { constant", self.session.str_of(ident)); + self.enforce_default_binding_mode( + pattern, + binding_mode, + "a constant"); self.record_def(pattern.id, def); } FoundConst(_) => { @@ -5371,6 +5380,32 @@ impl Resolver { self.def_map.insert(node_id, def); } + fn enforce_default_binding_mode(pat: @pat, + pat_binding_mode: binding_mode, + descr: &str) { + match pat_binding_mode { + bind_infer => {} + bind_by_value => { + self.session.span_err( + pat.span, + fmt!("cannot use `copy` binding mode with %s", + descr)); + } + bind_by_move => { + self.session.span_err( + pat.span, + fmt!("cannot use `move` binding mode with %s", + descr)); + } + bind_by_ref(*) => { + self.session.span_err( + pat.span, + fmt!("cannot use `ref` binding mode with %s", + descr)); + } + } + } + // // main function checking // diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index db266464860c3..084f0ba421e08 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -910,7 +910,8 @@ fn root_pats_as_necessary(bcx: block, for vec::each(m) |br| { let pat_id = br.pats[col].id; - match bcx.ccx().maps.root_map.find({id:pat_id, derefs:0u}) { + let key = root_map_key {id: pat_id, derefs: 0u }; + match bcx.ccx().maps.root_map.find(key) { None => (), Some(root_info) => { // Note: the scope_id will always be the id of the match. See diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 3bf1547a7d942..e9f83e25f5590 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -61,6 +61,7 @@ use middle::trans::reachable; use middle::trans::shape::*; use middle::trans::tvec; use middle::trans::type_of::*; +use middle::ty::arg; use util::common::indenter; use util::ppaux::{ty_to_str, ty_to_short_str}; use util::ppaux; @@ -2198,9 +2199,12 @@ fn create_main_wrapper(ccx: @crate_ctxt, _sp: span, main_llfn: ValueRef) { fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef) -> ValueRef { let unit_ty = ty::mk_estr(ccx.tcx, ty::vstore_uniq); let vecarg_ty: ty::arg = - {mode: ast::expl(ast::by_val), - ty: ty::mk_evec(ccx.tcx, ty::mt {ty: unit_ty, mutbl: ast::m_imm}, - ty::vstore_uniq)}; + arg { + mode: ast::expl(ast::by_val), + ty: ty::mk_evec(ccx.tcx, + ty::mt {ty: unit_ty, mutbl: ast::m_imm}, + ty::vstore_uniq) + }; let nt = ty::mk_nil(ccx.tcx); let llfty = type_of_fn(ccx, ~[vecarg_ty], nt); let llfdecl = decl_fn(ccx.llmod, ~"_rust_main", @@ -2589,9 +2593,15 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { T_void())); let memcpy32 = decl_cdecl_fn(llmod, ~"llvm.memcpy.p0i8.p0i8.i32", - T_fn(T_memcpy32_args, T_void())); + T_fn(copy T_memcpy32_args, T_void())); let memcpy64 = decl_cdecl_fn(llmod, ~"llvm.memcpy.p0i8.p0i8.i64", + T_fn(copy T_memcpy64_args, T_void())); + let memmove32 = + decl_cdecl_fn(llmod, ~"llvm.memmove.p0i8.p0i8.i32", + T_fn(T_memcpy32_args, T_void())); + let memmove64 = + decl_cdecl_fn(llmod, ~"llvm.memmove.p0i8.p0i8.i64", T_fn(T_memcpy64_args, T_void())); let memset32 = decl_cdecl_fn(llmod, ~"llvm.memset.p0i8.i32", @@ -2700,6 +2710,8 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { intrinsics.insert(~"llvm.gcread", gcread); intrinsics.insert(~"llvm.memcpy.p0i8.p0i8.i32", memcpy32); intrinsics.insert(~"llvm.memcpy.p0i8.p0i8.i64", memcpy64); + 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); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 0128876a898f5..3babfbd8285fd 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -39,6 +39,7 @@ use middle::trans::reachable; use middle::trans::shape; use middle::trans::type_of; use middle::trans::type_use; +use middle::ty::substs; use middle::ty; use middle::typeck; use util::ppaux::{expr_repr, ty_to_str}; @@ -1459,9 +1460,11 @@ fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, } fn dummy_substs(+tps: ~[ty::t]) -> ty::substs { - {self_r: Some(ty::re_bound(ty::br_self)), - self_ty: None, - tps: tps} + substs { + self_r: Some(ty::re_bound(ty::br_self)), + self_ty: None, + tps: tps + } } fn struct_field(index: uint) -> [uint * 3] { diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 8c024b364c328..94145be2a1e31 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -98,7 +98,7 @@ use core::prelude::*; use lib::llvm::ValueRef; -use middle::borrowck::RootInfo; +use middle::borrowck::{RootInfo, root_map_key}; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::common::*; @@ -652,7 +652,7 @@ impl Datum { // root the autoderef'd value, if necessary: // // (Note: root'd values are always boxes) - let key = {id:expr_id, derefs:derefs}; + let key = root_map_key { id: expr_id, derefs: derefs }; let bcx = match ccx.maps.root_map.find(key) { None => bcx, Some(root_info) => self.root(bcx, root_info) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ea9ddc2e5d0c7..24d8e94abbdba 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -114,6 +114,7 @@ lvalues are *never* stored by value. use core::prelude::*; use lib::llvm::ValueRef; +use middle::borrowck::root_map_key; use middle::resolve; use middle::trans::base::*; use middle::trans::callee::{AutorefArg, DoAutorefArg, DontAutorefArg}; @@ -757,7 +758,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { // If the lvalue must remain rooted, create a scratch datum, copy // the lvalue in there, and then arrange for it to be cleaned up // at the end of the scope with id `scope_id`: - let root_key = {id:expr.id, derefs:0u}; + let root_key = root_map_key { id: expr.id, derefs: 0u }; for bcx.ccx().maps.root_map.find(root_key).each |&root_info| { bcx = unrooted_datum.root(bcx, root_info); } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index ac641222b3c29..46ab560e1b67a 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -31,7 +31,7 @@ use middle::trans::machine; use middle::trans::shape; use middle::trans::type_of::*; use middle::trans::type_of; -use middle::ty::{FnTyBase, FnMeta, FnSig}; +use middle::ty::{FnTyBase, FnMeta, FnSig, arg}; use util::ppaux::ty_to_str; use core::libc::c_uint; @@ -546,8 +546,8 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item, onceness: ast::Many, region: ty::re_bound(ty::br_anon(0)), bounds: @~[]}, - sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val), - ty: star_u8}], + sig: FnSig {inputs: ~[arg {mode: ast::expl(ast::by_val), + ty: star_u8}], output: ty::mk_nil(bcx.tcx())} }); let datum = Datum {val: get_param(decl, first_real_arg), @@ -568,6 +568,24 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item, T_ptr(T_nil())); Store(bcx, morestack_addr, fcx.llretptr); } + ~"memmove32" => { + let dst_ptr = get_param(decl, first_real_arg); + let src_ptr = get_param(decl, first_real_arg + 1); + let size = get_param(decl, first_real_arg + 2); + let align = C_i32(1); + let volatile = C_bool(false); + let llfn = bcx.ccx().intrinsics.get(~"llvm.memmove.p0i8.p0i8.i32"); + Call(bcx, llfn, ~[dst_ptr, src_ptr, size, align, volatile]); + } + ~"memmove64" => { + let dst_ptr = get_param(decl, first_real_arg); + let src_ptr = get_param(decl, first_real_arg + 1); + let size = get_param(decl, first_real_arg + 2); + let align = C_i32(1); + let volatile = C_bool(false); + let llfn = bcx.ccx().intrinsics.get(~"llvm.memmove.p0i8.p0i8.i64"); + Call(bcx, llfn, ~[dst_ptr, src_ptr, size, align, volatile]); + } ~"sqrtf32" => { let x = get_param(decl, first_real_arg); let sqrtf = ccx.intrinsics.get(~"llvm.sqrt.f32"); diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 5c0498d5a1470..7af3b7a06834a 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -13,6 +13,7 @@ use middle::trans::common::*; use middle::trans::type_of; +use middle::ty::field; use middle::ty; use syntax::parse::token::special_idents; @@ -44,13 +45,17 @@ pub fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t { ty::ty_struct(did, ref substs) => { let simpl_fields = (if ty::ty_dtor(tcx, did).is_present() { // remember the drop flag - ~[{ident: special_idents::dtor, - mt: ty::mt {ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl}}] } + ~[field { + ident: special_idents::dtor, + mt: ty::mt {ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl} + }] } else { ~[] }) + do ty::lookup_struct_fields(tcx, did).map |f| { let t = ty::lookup_field_type(tcx, did, f.id, substs); - {ident: f.ident, - mt: ty::mt {ty: simplify_type(tcx, t), mutbl: ast::m_const}} + field { + ident: f.ident, + mt: ty::mt {ty: simplify_type(tcx, t), mutbl: ast::m_const + }} }; ty::mk_rec(tcx, simpl_fields) } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 7eccf97f76c31..a90c25abf3dd6 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -28,6 +28,7 @@ use middle::trans::glue; use middle::trans::inline; use middle::trans::monomorphize; use middle::trans::type_of::*; +use middle::ty::arg; use middle::typeck; use util::ppaux::{ty_to_str, tys_to_str}; @@ -154,8 +155,10 @@ fn trans_self_arg(bcx: block, let mut temp_cleanups = ~[]; // Compute the mode and type of self. - let self_arg = {mode: mentry.self_arg.mode, - ty: monomorphize_type(bcx, mentry.self_arg.ty)}; + let self_arg = arg { + mode: mentry.self_arg.mode, + ty: monomorphize_type(bcx, mentry.self_arg.ty) + }; let result = trans_arg_expr(bcx, self_arg, base, &mut temp_cleanups, None, DontAutorefArg); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 39ab5735dee3f..ba9ff3a4f98bb 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -105,7 +105,8 @@ impl reflector { mth_idx, v, ty::vstore_box, - ast::sty_by_ref), + ast::sty_region( + ast::m_imm)), ArgVals(args), SaveIn(scratch.val), DontAutorefArg); let result = scratch.to_value_llval(bcx); let next_bcx = sub_block(bcx, ~"next"); diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index ba1901f215c57..1ef5abe8ee683 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -129,6 +129,8 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint) ~"visit_tydesc" | ~"forget" | ~"addr_of" | ~"frame_address" | ~"morestack_addr" => 0, + ~"memmove32" | ~"memmove64" => 0, + ~"sqrtf32" | ~"sqrtf64" | ~"powif32" | ~"powif64" | ~"sinf32" | ~"sinf64" | ~"cosf32" | ~"cosf64" | ~"powf32" | ~"powf64" | ~"expf32" | ~"expf64" | diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c82825795869a..1bdaa984914db 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -55,7 +55,7 @@ export ProvidedMethodSource; export ProvidedMethodInfo; export ProvidedMethodsMap; export InstantiatedTraitRef; -export TyVid, IntVid, FloatVid, FnVid, RegionVid, Vid; +export TyVid, IntVid, FloatVid, RegionVid, Vid; export br_hashmap; export is_instantiable; export node_id_to_type; @@ -119,6 +119,7 @@ export ty_opaque_box, mk_opaque_box; export ty_float, mk_float, mk_mach_float, type_is_fp; export ty_fn, FnTy, FnTyBase, FnMeta, FnSig, mk_fn; export ty_fn_proto, ty_fn_purity, ty_fn_ret, tys_in_fn_sig; +export ty_vstore; export replace_fn_return_type; export ty_int, mk_int, mk_mach_int, mk_char; export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64; @@ -214,7 +215,7 @@ export ty_sort_str; export normalize_ty; export to_str; export bound_const; -export terr_no_integral_type, terr_no_floating_point_type; +export terr_int_mismatch, terr_float_mismatch, terr_sigil_mismatch; export terr_ty_param_size, terr_self_substs; export terr_in_field, terr_record_fields, terr_vstores_differ, terr_arg_count; export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size; @@ -240,14 +241,24 @@ export AutoRef; export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn; export iter_bound_traits_and_supertraits; export count_traits_and_supertraits; +export IntVarValue, IntType, UintType; +export creader_cache_key; // 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}; +#[deriving_eq] +struct arg { + mode: ast::mode, + ty: t +} -type field = {ident: ast::ident, mt: mt}; +#[deriving_eq] +struct field { + ident: ast::ident, + mt: mt +} type param_bounds = @~[param_bound]; @@ -290,35 +301,38 @@ pub enum ValueMode { // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. -type creader_cache_key = {cnum: int, pos: uint, len: uint}; -type creader_cache = HashMap; - -impl creader_cache_key : cmp::Eq { - pure fn eq(&self, other: &creader_cache_key) -> bool { - (*self).cnum == (*other).cnum && - (*self).pos == (*other).pos && - (*self).len == (*other).len - } - pure fn ne(&self, other: &creader_cache_key) -> bool { - !((*self) == (*other)) - } +#[deriving_eq] +struct creader_cache_key { + cnum: int, + pos: uint, + len: uint } +type creader_cache = HashMap; + impl creader_cache_key : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.cnum, &self.pos, &self.len, lsb0, f); } } -type intern_key = {sty: *sty, o_def_id: Option}; +struct intern_key { + sty: *sty, + o_def_id: Option +} +// NB: Do not replace this with #[deriving_eq]. The automatically-derived +// implementation will not recurse through sty and you will get stack +// exhaustion. impl intern_key : cmp::Eq { pure fn eq(&self, other: &intern_key) -> bool { unsafe { *self.sty == *other.sty && self.o_def_id == other.o_def_id } } - pure fn ne(&self, other: &intern_key) -> bool { !(*self).eq(other) } + pure fn ne(&self, other: &intern_key) -> bool { + !self.eq(other) + } } impl intern_key : to_bytes::IterBytes { @@ -554,7 +568,7 @@ struct FnSig { * by the meta information because, in some cases, the * meta information is inferred. */ #[deriving_eq] -struct FnTyBase { +struct FnTyBase { meta: M, // Either FnMeta or FnVid sig: FnSig // Types of arguments/return type } @@ -567,13 +581,10 @@ impl FnTyBase : to_bytes::IterBytes { type FnTy = FnTyBase; -type param_ty = {idx: uint, def_id: def_id}; - -impl param_ty : cmp::Eq { - pure fn eq(&self, other: ¶m_ty) -> bool { - (*self).idx == (*other).idx && (*self).def_id == (*other).def_id - } - pure fn ne(&self, other: ¶m_ty) -> bool { !(*self).eq(other) } +#[deriving_eq] +struct param_ty { + idx: uint, + def_id: def_id } impl param_ty : to_bytes::IterBytes { @@ -659,11 +670,12 @@ type opt_region = Option; * - `self_ty` is the type to which `self` should be remapped, if any. The * `self` type is rather funny in that it can only appear on traits and is * always substituted away to the implementing type for a trait. */ -type substs = { +#[deriving_eq] +struct substs { self_r: opt_region, self_ty: Option, tps: ~[t] -}; +} // NB: If you change this, you'll probably want to change the corresponding // AST structure in libsyntax/ast.rs as well. @@ -702,6 +714,12 @@ enum sty { ty_unboxed_vec(mt), } +#[deriving_eq] +enum IntVarValue { + IntType(ast::int_ty), + UintType(ast::uint_ty), +} + enum terr_vstore_kind { terr_vec, terr_str, terr_fn, terr_trait } @@ -739,8 +757,8 @@ enum type_err { terr_sorts(expected_found), terr_self_substs, terr_integer_as_char, - terr_no_integral_type, - terr_no_floating_point_type, + terr_int_mismatch(expected_found), + terr_float_mismatch(expected_found) } enum param_bound { @@ -751,10 +769,16 @@ enum param_bound { bound_trait(t), } +#[deriving_eq] enum TyVid = uint; + +#[deriving_eq] enum IntVid = uint; + +#[deriving_eq] enum FloatVid = uint; -enum FnVid = uint; + +#[deriving_eq] #[auto_encode] #[auto_decode] enum RegionVid = uint; @@ -850,14 +874,6 @@ impl FloatVid: ToStr { pure fn to_str() -> ~str { fmt!("", self.to_uint()) } } -impl FnVid: Vid { - pure fn to_uint() -> uint { *self } -} - -impl FnVid: ToStr { - pure fn to_str() -> ~str { fmt!("", self.to_uint()) } -} - impl RegionVid: Vid { pure fn to_uint() -> uint { *self } } @@ -883,33 +899,36 @@ impl InferTy: ToStr { } } -impl RegionVid : to_bytes::IterBytes { - pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) +impl IntVarValue : ToStr { + pure fn to_str() -> ~str { + match self { + IntType(ref v) => v.to_str(), + UintType(ref v) => v.to_str(), + } } } impl TyVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } impl IntVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } impl FloatVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } -impl FnVid : to_bytes::IterBytes { +impl RegionVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } @@ -1035,7 +1054,7 @@ 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) -> t { - let key = {sty: to_unsafe_ptr(&st), o_def_id: o_def_id}; + let key = intern_key { sty: to_unsafe_ptr(&st), o_def_id: o_def_id }; match cx.interner.find(key) { Some(t) => unsafe { return cast::reinterpret_cast(&t); }, _ => () @@ -1094,7 +1113,7 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option) -> t { let t = @{sty: move st, id: cx.next_id, flags: flags, o_def_id: o_def_id}; - let key = {sty: to_unsafe_ptr(&t.sty), o_def_id: o_def_id}; + let key = intern_key {sty: to_unsafe_ptr(&t.sty), o_def_id: o_def_id}; cx.interner.insert(move key, t); cx.next_id += 1u; @@ -1227,7 +1246,7 @@ fn mk_infer(cx: ctxt, +it: InferTy) -> t { mk_t(cx, ty_infer(it)) } fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) } fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { - mk_t(cx, ty_param({idx: n, def_id: k})) + mk_t(cx, ty_param(param_ty { idx: n, def_id: k })) } fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) } @@ -1343,7 +1362,7 @@ fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: fn(t) -> t) -> t { fn fold_sig(sig: &FnSig, fldop: fn(t) -> t) -> FnSig { let args = do sig.inputs.map |arg| { - { mode: arg.mode, ty: fldop(arg.ty) } + arg { mode: arg.mode, ty: fldop(arg.ty) } }; FnSig { @@ -1354,9 +1373,9 @@ fn fold_sig(sig: &FnSig, fldop: fn(t) -> t) -> FnSig { fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty { fn fold_substs(substs: &substs, fldop: fn(t) -> t) -> substs { - {self_r: substs.self_r, - self_ty: substs.self_ty.map(|t| fldop(*t)), - tps: substs.tps.map(|t| fldop(*t))} + substs {self_r: substs.self_r, + self_ty: substs.self_ty.map(|t| fldop(*t)), + tps: substs.tps.map(|t| fldop(*t))} } match /*bad*/copy *sty { @@ -1384,8 +1403,8 @@ fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty { ty_rec(fields) => { let new_fields = do vec::map(fields) |fl| { let new_ty = fldop(fl.mt.ty); - let new_mt = mt {ty: new_ty, mutbl: fl.mt.mutbl}; - {ident: fl.ident, mt: new_mt} + let new_mt = mt { ty: new_ty, mutbl: fl.mt.mutbl }; + field { ident: fl.ident, mt: new_mt } }; ty_rec(new_fields) } @@ -1442,11 +1461,13 @@ fn fold_regions_and_ty( fn fold_substs( substs: &substs, fldr: fn(r: Region) -> Region, - fldt: fn(t: t) -> t) -> substs - { - {self_r: substs.self_r.map(|r| fldr(*r)), - self_ty: substs.self_ty.map(|t| fldt(*t)), - tps: substs.tps.map(|t| fldt(*t))} + fldt: fn(t: t) -> t) + -> substs { + substs { + self_r: substs.self_r.map(|r| fldr(*r)), + self_ty: substs.self_ty.map(|t| fldt(*t)), + tps: substs.tps.map(|t| fldt(*t)) + } } let tb = ty::get(ty); @@ -1662,7 +1683,7 @@ fn subst(cx: ctxt, // Performs substitutions on a set of substitutions (result = sup(sub)) to // yield a new set of substitutions. This is used in trait inheritance. fn subst_substs(cx: ctxt, sup: &substs, sub: &substs) -> substs { - { + substs { self_r: sup.self_r, self_ty: sup.self_ty.map(|typ| subst(cx, sub, *typ)), tps: sup.tps.map(|typ| subst(cx, sub, *typ)) @@ -3005,10 +3026,20 @@ fn is_fn_ty(fty: t) -> bool { } } +pure fn ty_vstore(ty: t) -> vstore { + match get(ty).sty { + ty_evec(_, vstore) => vstore, + ty_estr(vstore) => vstore, + ref s => fail fmt!("ty_vstore() called on invalid sty: %?", s) + } +} + fn ty_region(ty: t) -> Region { match get(ty).sty { ty_rptr(r, _) => r, - ref s => fail fmt!("ty_region() invoked on non-rptr: %?", (*s)) + ty_evec(_, vstore_slice(r)) => r, + ty_estr(vstore_slice(r)) => r, + ref s => fail fmt!("ty_region() invoked on in appropriate ty: %?", (*s)) } } @@ -3564,17 +3595,18 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { terr_self_substs => { ~"inconsistent self substitution" // XXX this is more of a bug } - terr_no_integral_type => { - ~"couldn't determine an appropriate integral type for integer \ - literal" - } terr_integer_as_char => { - ~"integer literals can't be inferred to char type \ - (try an explicit cast)" + fmt!("expected an integral type but found char") + } + terr_int_mismatch(ref values) => { + fmt!("expected %s but found %s", + values.expected.to_str(), + values.found.to_str()) } - terr_no_floating_point_type => { - ~"couldn't determine an appropriate floating point type for \ - floating point literal" + terr_float_mismatch(ref values) => { + fmt!("expected %s but found %s", + values.expected.to_str(), + values.found.to_str()) } } } @@ -4132,7 +4164,7 @@ fn struct_item_fields(cx:ctxt, do lookup_struct_fields(cx, did).map |f| { // consider all instance vars mut, because the // constructor may mutate all vars - { + field { ident: f.ident, mt: mt { ty: lookup_field_type(cx, did, f.id, substs), @@ -4261,9 +4293,11 @@ fn normalize_ty(cx: ctxt, t: t) -> t { Some(_) => // Use re_static since trans doesn't care about regions mk_enum(cx, did, - {self_r: Some(ty::re_static), - self_ty: None, - tps: /*bad*/copy (*r).tps}), + substs { + self_r: Some(ty::re_static), + self_ty: None, + tps: /*bad*/copy (*r).tps + }), None => t }, @@ -4272,9 +4306,9 @@ fn normalize_ty(cx: ctxt, t: t) -> t { match (*r).self_r { Some(_) => // Ditto. - mk_struct(cx, did, {self_r: Some(ty::re_static), - self_ty: None, - tps: /*bad*/copy (*r).tps}), + mk_struct(cx, did, substs {self_r: Some(ty::re_static), + self_ty: None, + tps: /*bad*/copy (*r).tps}), None => t }, @@ -4394,20 +4428,6 @@ impl mt : cmp::Eq { pure fn ne(&self, other: &mt) -> bool { !(*self).eq(other) } } -impl arg : cmp::Eq { - pure fn eq(&self, other: &arg) -> bool { - (*self).mode == (*other).mode && (*self).ty == (*other).ty - } - pure fn ne(&self, other: &arg) -> bool { !(*self).eq(other) } -} - -impl field : cmp::Eq { - pure fn eq(&self, other: &field) -> bool { - (*self).ident == (*other).ident && (*self).mt == (*other).mt - } - pure fn ne(&self, other: &field) -> bool { !(*self).eq(other) } -} - impl vstore : cmp::Eq { pure fn eq(&self, other: &vstore) -> bool { match (*self) { @@ -4440,31 +4460,6 @@ impl vstore : cmp::Eq { pure fn ne(&self, other: &vstore) -> bool { !(*self).eq(other) } } -impl TyVid : cmp::Eq { - pure fn eq(&self, other: &TyVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &TyVid) -> bool { *(*self) != *(*other) } -} - -impl IntVid : cmp::Eq { - pure fn eq(&self, other: &IntVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &IntVid) -> bool { *(*self) != *(*other) } -} - -impl FloatVid : cmp::Eq { - pure fn eq(&self, other: &FloatVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &FloatVid) -> bool { *(*self) != *(*other) } -} - -impl FnVid : cmp::Eq { - pure fn eq(&self, other: &FnVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &FnVid) -> bool { *(*self) != *(*other) } -} - -impl RegionVid : cmp::Eq { - pure fn eq(&self, other: &RegionVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &RegionVid) -> bool { *(*self) != *(*other) } -} - impl Region : cmp::Eq { pure fn eq(&self, other: &Region) -> bool { match (*self) { @@ -4541,15 +4536,6 @@ impl bound_region : cmp::Eq { pure fn ne(&self, other: &bound_region) -> bool { !(*self).eq(other) } } -impl substs : cmp::Eq { - pure fn eq(&self, other: &substs) -> bool { - (*self).self_r == (*other).self_r && - (*self).self_ty == (*other).self_ty && - (*self).tps == (*other).tps - } - pure fn ne(&self, other: &substs) -> bool { !(*self).eq(other) } -} - impl sty : cmp::Eq { pure fn eq(&self, other: &sty) -> bool { match (/*bad*/copy *self) { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 7e1c5f54134e1..e845904956d95 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -55,7 +55,8 @@ use core::prelude::*; use middle::pat_util::pat_id_map; -use middle::ty::{FnTyBase, FnMeta, FnSig, ty_param_substs_and_ty}; +use middle::ty::{FnTyBase, FnMeta, FnSig, arg, field, substs}; +use middle::ty::{ty_param_substs_and_ty}; use middle::ty; use middle::typeck::check::fn_ctxt; use middle::typeck::collect; @@ -151,7 +152,7 @@ fn ast_path_to_substs_and_ty( } let tps = path.types.map(|a_t| ast_ty_to_ty(self, rscope, *a_t)); - let substs = {self_r:self_r, self_ty:None, tps:tps}; + let substs = substs {self_r:self_r, self_ty:None, tps:tps}; let ty = ty::subst(tcx, &substs, decl_ty); {substs: substs, ty: ty} } @@ -315,7 +316,7 @@ fn ast_ty_to_ty( ast::ty_rec(ref fields) => { let flds = do (*fields).map |f| { let tm = ast_mt_to_mt(self, rscope, f.node.mt); - {ident: f.node.ident, mt: tm} + field {ident: f.node.ident, mt: tm} }; ty::mk_rec(tcx, flds) } @@ -447,7 +448,7 @@ fn ty_of_arg( } }; - {mode: mode, ty: ty} + arg {mode: mode, ty: ty} } type expected_tys = Option<{inputs: ~[ty::arg], diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 2e82d531e1559..ebfce27a4c8bb 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -15,7 +15,7 @@ use middle::pat_util::{pat_is_variant_or_struct}; use middle::ty; use middle::typeck::check::demand; use middle::typeck::check::{check_block, check_expr_has_type, fn_ctxt}; -use middle::typeck::check::{instantiate_path, lookup_def, lookup_local}; +use middle::typeck::check::{instantiate_path, lookup_def}; use middle::typeck::check::{structure_of, valid_range_bounds}; use middle::typeck::require_same_types; @@ -365,8 +365,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.write_ty(pat.id, const_tpt.ty); } ast::pat_ident(bm, name, sub) if pat_is_binding(tcx.def_map, pat) => { - let vid = lookup_local(fcx, pat.span, pat.id); - let mut typ = ty::mk_var(tcx, vid); + let typ = fcx.local_ty(pat.span, pat.id); match bm { ast::bind_by_ref(mutbl) => { @@ -389,8 +388,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { let canon_id = pcx.map.get(ast_util::path_to_ident(name)); if canon_id != pat.id { - let tv_id = lookup_local(fcx, pat.span, canon_id); - let ct = ty::mk_var(tcx, tv_id); + let ct = fcx.local_ty(pat.span, canon_id); demand::eqtype(fcx, pat.span, ct, typ); } fcx.write_ty(pat.id, typ); diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index e4b232500bbf7..c8a644fef101c 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -49,8 +49,11 @@ fn eqtype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) { } } -// Checks that the type `actual` can be assigned to `expected`. -fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) { +// Checks that the type `actual` can be coerced to `expected`. +fn coerce(fcx: @fn_ctxt, + sp: span, + expected: ty::t, + expr: @ast::expr) { let expr_ty = fcx.expr_ty(expr); match fcx.mk_assignty(expr, expr_ty, expected) { result::Ok(()) => { /* ok */ } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 7ef6ae598803e..543adbd53aac8 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -295,7 +295,11 @@ impl LookupContext { let self_did = self.fcx.self_info.expect( ~"self_impl_def_id is undefined (`self` may not \ be in scope here").def_id; - let substs = {self_r: None, self_ty: None, tps: ~[]}; + let substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; self.push_inherent_candidates_from_self( self_ty, self_did, &substs); } @@ -392,7 +396,10 @@ impl LookupContext { // impl or class (where the self type is not permitted), // or from a trait type (in which case methods that refer // to self are not permitted). - let init_substs = {self_ty: Some(rcvr_ty), ..init_substs}; + let init_substs = substs { + self_ty: Some(rcvr_ty), + ..init_substs + }; worklist.push((init_trait_ty, init_substs)); @@ -416,7 +423,10 @@ impl LookupContext { &init_substs); // Again replacing the self type - let new_substs = {self_ty: Some(rcvr_ty), ..new_substs}; + let new_substs = substs { + self_ty: Some(rcvr_ty), + ..new_substs + }; worklist.push((supertrait.tpt.ty, new_substs)); } @@ -506,7 +516,10 @@ impl LookupContext { // `trait_ty` for `self` here, because it allows the compiler // to soldier on. An error will be reported should this // candidate be selected if the method refers to `self`. - let rcvr_substs = {self_ty: Some(self_ty), ../*bad*/copy *substs}; + let rcvr_substs = substs { + self_ty: Some(self_ty), + ../*bad*/copy *substs + }; let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method(method.self_ty, @@ -537,7 +550,10 @@ impl LookupContext { } let method = &methods[index]; - let rcvr_substs = { self_ty: Some(self_ty), ../*bad*/copy *substs }; + let rcvr_substs = substs { + self_ty: Some(self_ty), + ../*bad*/copy *substs + }; let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method( method.self_ty, @@ -628,7 +644,11 @@ impl LookupContext { candidate"); // XXX: Needs to support generics. - let dummy_substs = { self_r: None, self_ty: None, tps: ~[] }; + let dummy_substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; let (impl_ty, impl_substs) = self.create_rcvr_ty_and_substs_for_method( provided_method_info.method_info.self_type, @@ -673,11 +693,13 @@ impl LookupContext { move self_substs } sty_region(_) => { - {self_r: - Some(self.infcx().next_region_var( - self.expr.span, - self.expr.id)), - ..self_substs} + substs { + self_r: + Some(self.infcx().next_region_var( + self.expr.span, + self.expr.id)), + ..self_substs + } } } }; @@ -700,6 +722,8 @@ impl LookupContext { autoderefs: uint) -> Option { + let (self_ty, autoadjust) = + self.consider_reborrow(self_ty, autoderefs); match self.search_for_method(self_ty) { None => None, Some(move mme) => { @@ -707,13 +731,64 @@ impl LookupContext { adjustment (%u) to %d", autoderefs, self.self_expr.id); - self.fcx.write_autoderef_adjustment( - self.self_expr.id, autoderefs); + self.fcx.write_adjustment(self.self_expr.id, @autoadjust); Some(mme) } } } + fn consider_reborrow(&self, + self_ty: ty::t, + autoderefs: uint) -> (ty::t, ty::AutoAdjustment) + { + /*! + * + * In the event that we are invoking a method with a receiver + * of a linear borrowed type like `&mut T` or `&[mut T]`, + * we will "reborrow" the receiver implicitly. For example, if + * you have a call `r.inc()` and where `r` has type `&mut T`, + * then we treat that like `(&mut *r).inc()`. This avoids + * consuming the original pointer. + * + * You might think that this would be a natural byproduct of + * the auto-deref/auto-ref process. This is true for `@mut T` + * but not for an `&mut T` receiver. With `@mut T`, we would + * begin by testing for methods with a self type `@mut T`, + * then autoderef to `T`, then autoref to `&mut T`. But with + * an `&mut T` receiver the process begins with `&mut T`, only + * without any autoadjustments. + */ + + let tcx = self.tcx(); + return match ty::get(self_ty).sty { + ty::ty_rptr(_, self_mt) if self_mt.mutbl == m_mutbl => { + let region = self.infcx().next_region_var(self.expr.span, + self.expr.id); + (ty::mk_rptr(tcx, region, self_mt), + ty::AutoAdjustment { + autoderefs: autoderefs+1, + autoref: Some(ty::AutoRef {kind: AutoPtr, + region: region, + mutbl: self_mt.mutbl})}) + } + ty::ty_evec(self_mt, vstore_slice(_)) + if self_mt.mutbl == m_mutbl => { + let region = self.infcx().next_region_var(self.expr.span, + self.expr.id); + (ty::mk_evec(tcx, self_mt, vstore_slice(region)), + ty::AutoAdjustment { + autoderefs: autoderefs, + autoref: Some(ty::AutoRef {kind: AutoBorrowVec, + region: region, + mutbl: self_mt.mutbl})}) + } + _ => { + (self_ty, ty::AutoAdjustment {autoderefs: autoderefs, + autoref: None}) + } + }; + } + fn search_for_autosliced_method( &self, self_ty: ty::t, @@ -729,6 +804,7 @@ impl LookupContext { match ty::get(self_ty).sty { ty_evec(mt, vstore_box) | ty_evec(mt, vstore_uniq) | + ty_evec(mt, vstore_slice(_)) | // NDM(#3148) ty_evec(mt, vstore_fixed(_)) => { // First try to borrow to a slice let entry = self.search_for_some_kind_of_autorefd_method( @@ -1004,7 +1080,7 @@ impl LookupContext { // Construct the full set of type parameters for the method, // which is equal to the class tps + the method tps. - let all_substs = { + let all_substs = substs { tps: vec::append(/*bad*/copy candidate.rcvr_substs.tps, m_substs), ../*bad*/copy candidate.rcvr_substs @@ -1012,7 +1088,7 @@ impl LookupContext { self.fcx.write_ty_substs(self.callee_id, fty, all_substs); method_map_entry { - self_arg: { + self_arg: arg { mode: ast::expl(candidate.self_mode), ty: candidate.rcvr_ty, }, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 43f609dd2f0a3..c4440b8941131 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -84,7 +84,7 @@ use middle::pat_util::pat_id_map; use middle::pat_util; use middle::ty::{TyVid, Vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; -use middle::ty::{re_bound, br_cap_avoid}; +use middle::ty::{re_bound, br_cap_avoid, substs, arg, param_ty}; use middle::ty; use middle::typeck::astconv::{ast_conv, ast_path_to_ty}; use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty}; @@ -105,7 +105,7 @@ use middle::typeck::{isr_alist, lookup_def_ccx, method_map_entry}; use middle::typeck::{method_origin, method_self, method_trait, no_params}; use middle::typeck::{require_same_types}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_to_str, expr_repr}; +use util::ppaux::{bound_region_to_str, expr_repr, pat_repr}; use util::ppaux; use core::either; @@ -127,7 +127,6 @@ use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; use syntax::parse::token::special_idents; -use syntax::print::pprust::{expr_to_str, pat_to_str}; use syntax::print::pprust; use syntax::visit; use syntax; @@ -140,7 +139,6 @@ export regionck; export demand; export method; export fn_ctxt; -export lookup_local; export impl_self_ty; export DerefArgs; export DontDerefArgs; @@ -190,7 +188,7 @@ type self_info = { /// share the inherited fields. struct inherited { infcx: @infer::InferCtxt, - locals: HashMap, + locals: HashMap, node_types: HashMap, node_type_substs: HashMap, adjustments: HashMap @@ -377,8 +375,7 @@ fn check_fn(ccx: @crate_ctxt, } }; - // XXX: Bad copy. - gather_locals(fcx, decl, body, copy arg_tys, self_info); + gather_locals(fcx, decl, body, arg_tys, self_info); check_block(fcx, body); // We unify the tail expr's type with the @@ -415,30 +412,31 @@ fn check_fn(ccx: @crate_ctxt, fn gather_locals(fcx: @fn_ctxt, decl: &ast::fn_decl, body: ast::blk, - arg_tys: ~[ty::t], + arg_tys: &[ty::t], self_info: Option) { let tcx = fcx.ccx.tcx; - let assign = fn@(span: span, nid: ast::node_id, - ty_opt: Option) { - let var_id = fcx.infcx().next_ty_var_id(); - fcx.inh.locals.insert(nid, var_id); + let assign = fn@(nid: ast::node_id, ty_opt: Option) { match ty_opt { - None => {/* nothing to do */ } + None => { + // infer the variable's type + let var_id = fcx.infcx().next_ty_var_id(); + let var_ty = ty::mk_var(fcx.tcx(), var_id); + fcx.inh.locals.insert(nid, var_ty); + } Some(typ) => { - infer::mk_eqty(fcx.infcx(), false, span, - ty::mk_var(tcx, var_id), typ); + // take type that the user specified + fcx.inh.locals.insert(nid, typ); } } }; // Add the self parameter for self_info.each |self_info| { - assign(self_info.explicit_self.span, - self_info.self_id, - Some(self_info.self_ty)); + assign(self_info.self_id, Some(self_info.self_ty)); debug!("self is assigned to %s", - fcx.inh.locals.get(self_info.self_id).to_str()); + fcx.infcx().ty_to_str( + fcx.inh.locals.get(self_info.self_id))); } // Add formal parameters. @@ -446,7 +444,7 @@ fn check_fn(ccx: @crate_ctxt, // Create type variables for each argument. do pat_util::pat_bindings(tcx.def_map, input.pat) |_bm, pat_id, _sp, _path| { - assign(input.ty.span, pat_id, None); + assign(pat_id, None); } // Check the pattern. @@ -467,10 +465,11 @@ fn check_fn(ccx: @crate_ctxt, ast::ty_infer => None, _ => Some(fcx.to_ty(local.node.ty)) }; - assign(local.span, local.node.id, o_ty); - debug!("Local variable %s is assigned to %s", - pat_to_str(local.node.pat, tcx.sess.intr()), - fcx.inh.locals.get(local.node.id).to_str()); + assign(local.node.id, o_ty); + debug!("Local variable %s is assigned type %s", + fcx.pat_to_str(local.node.pat), + fcx.infcx().ty_to_str( + fcx.inh.locals.get(local.node.id))); visit::visit_local(local, e, v); }; @@ -479,10 +478,11 @@ fn check_fn(ccx: @crate_ctxt, match p.node { ast::pat_ident(_, path, _) if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => { - assign(p.span, p.id, None); + assign(p.id, None); debug!("Pattern binding %s is assigned to %s", tcx.sess.str_of(path.idents[0]), - fcx.inh.locals.get(p.id).to_str()); + fcx.infcx().ty_to_str( + fcx.inh.locals.get(p.id))); } _ => {} } @@ -695,6 +695,17 @@ impl @fn_ctxt: region_scope { impl @fn_ctxt { fn tag() -> ~str { fmt!("%x", ptr::addr_of(&(*self)) as uint) } + fn local_ty(span: span, nid: ast::node_id) -> ty::t { + match self.inh.locals.find(nid) { + Some(t) => t, + None => { + self.tcx().sess.span_bug( + span, + fmt!("No type for local variable %?", nid)); + } + } + } + fn expr_to_str(expr: @ast::expr) -> ~str { fmt!("expr(%?:%s)", expr.id, pprust::expr_to_str(expr, self.tcx().sess.intr())) @@ -756,6 +767,10 @@ impl @fn_ctxt { expr_repr(self.tcx(), expr) } + fn pat_to_str(pat: @ast::pat) -> ~str { + pat_repr(self.tcx(), pat) + } + fn expr_ty(ex: @ast::expr) -> ty::t { match self.inh.node_types.find(ex.id) { Some(t) => t, @@ -809,7 +824,7 @@ impl @fn_ctxt { fn mk_assignty(expr: @ast::expr, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - match infer::mk_assignty(self.infcx(), false, expr.span, sub, sup) { + match infer::mk_coercety(self.infcx(), false, expr.span, sub, sup) { Ok(None) => result::Ok(()), Err(ref e) => result::Err((*e)), Ok(Some(adjustment)) => { @@ -820,7 +835,7 @@ impl @fn_ctxt { } fn can_mk_assignty(sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::can_mk_assignty(self.infcx(), sub, sup) + infer::can_mk_coercety(self.infcx(), sub, sup) } fn mk_eqty(a_is_expected: bool, span: span, @@ -983,12 +998,12 @@ fn check_expr_has_type( } } -fn check_expr_assignable_to_type( +fn check_expr_coercable_to_type( fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { do check_expr_with_unifier(fcx, expr, Some(expected)) { - demand::assign(fcx, expr.span, expected, expr) + demand::coerce(fcx, expr.span, expected, expr) } } @@ -1044,9 +1059,11 @@ pub fn impl_self_ty(vcx: &VtableContext, {n_tps: ts.len(), region_param: region_param, raw_ty: ty::mk_struct(tcx, local_def(class_id), - {self_r: rscope::bound_self_region(region_param), - self_ty: None, - tps: ty::ty_params_to_tys(tcx, /*bad*/copy *ts)})} + substs { + self_r: rscope::bound_self_region(region_param), + self_ty: None, + tps: ty::ty_params_to_tys(tcx, /*bad*/copy *ts) + })} } _ => { tcx.sess.bug(~"impl_self_ty: unbound item or item that \ doesn't have a self_ty"); } @@ -1066,7 +1083,7 @@ pub fn impl_self_ty(vcx: &VtableContext, }; let tps = vcx.infcx.next_ty_vars(n_tps); - let substs = {self_r: self_r, self_ty: None, tps: tps}; + let substs = substs { self_r: self_r, self_ty: None, tps: tps }; let substd_ty = ty::subst(tcx, &substs, raw_ty); {substs: substs, ty: substd_ty} } @@ -1222,7 +1239,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, } // mismatch error happens in here - bot |= check_expr_assignable_to_type( + bot |= check_expr_coercable_to_type( fcx, *arg, formal_ty); } @@ -1240,7 +1257,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, -> bool { let mut bot = check_expr(fcx, lhs); let lhs_type = fcx.expr_ty(lhs); - bot |= check_expr_assignable_to_type(fcx, rhs, lhs_type); + bot |= check_expr_has_type(fcx, rhs, lhs_type); fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx)); return bot; } @@ -1356,10 +1373,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, 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); - demand::suptype(fcx, local.span, - ty::mk_var(fcx.ccx.tcx, locid), - element_ty); + let local_ty = fcx.local_ty(local.span, local.node.id); + demand::suptype(fcx, local.span, local_ty, element_ty); let bot = check_decl_local(fcx, local); check_block_no_value(fcx, body); fcx.write_nil(node_id); @@ -1600,7 +1615,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let fty = ty::mk_fn(tcx, copy fn_ty); debug!("check_expr_fn_with_unifier %s fty=%s", - expr_to_str(expr, tcx.sess.intr()), + fcx.expr_to_str(expr), fcx.infcx().ty_to_str(fty)); fcx.write_ty(expr.id, fty); @@ -1736,7 +1751,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, ty::lookup_field_type( tcx, class_id, field_id, substitutions); bot |= - check_expr_assignable_to_type( + check_expr_coercable_to_type( fcx, field.node.expr, expected_field_type); @@ -1801,7 +1816,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let self_region = bound_self_region(region_parameterized); - raw_type = ty::mk_struct(tcx, class_id, { + raw_type = ty::mk_struct(tcx, class_id, substs { self_r: self_region, self_ty: None, tps: ty::ty_params_to_tys( @@ -1827,7 +1842,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, span, ty::re_scope(id)); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); - let substitutions = { + let substitutions = substs { self_r: self_region, self_ty: None, tps: type_parameters @@ -1884,7 +1899,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let self_region = bound_self_region(region_parameterized); - raw_type = ty::mk_enum(tcx, enum_id, { + raw_type = ty::mk_enum(tcx, enum_id, substs { self_r: self_region, self_ty: None, tps: ty::ty_params_to_tys( @@ -1910,7 +1925,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, span, ty::re_scope(id)); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); - let substitutions = { + let substitutions = substs { self_r: self_region, self_ty: None, tps: type_parameters @@ -2421,7 +2436,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let expr_mt = ty::mt {ty: expr_t, mutbl: f.node.mutbl}; // for the most precise error message, // should be f.node.expr.span, not f.span - respan(f.node.expr.span, {ident: f.node.ident, mt: expr_mt}) + respan(f.node.expr.span, field {ident: f.node.ident, mt: expr_mt}) }); match base { None => { @@ -2548,15 +2563,15 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, init: @ast::expr) -> bool { - let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.span, nid)); - return check_expr_assignable_to_type(fcx, init, lty); + let local_ty = fcx.local_ty(init.span, nid); + return check_expr_coercable_to_type(fcx, init, local_ty); } fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let mut bot = false; let tcx = fcx.ccx.tcx; - let t = ty::mk_var(tcx, fcx.inh.locals.get(local.node.id)); + let t = fcx.local_ty(local.span, local.node.id); fcx.write_ty(local.node.id, t); match local.node.init { @@ -2713,7 +2728,7 @@ fn check_enum_variants(ccx: @crate_ctxt, do v.node.disr_expr.iter |e_ref| { let e = *e_ref; debug!("disr expr, checking %s", - expr_to_str(e, ccx.tcx.sess.intr())); + pprust::expr_to_str(e, ccx.tcx.sess.intr())); let declty = ty::mk_int(ccx.tcx); let fcx = blank_fn_ctxt(ccx, rty, e.id); check_const_with_ty(fcx, e.span, e, declty); @@ -2816,17 +2831,6 @@ fn check_enum_variants(ccx: @crate_ctxt, check_instantiable(ccx.tcx, sp, id); } -pub fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> TyVid { - match fcx.inh.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 { lookup_def_ccx(fcx.ccx, sp, id) } @@ -2838,9 +2842,8 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> match defn { ast::def_arg(nid, _, _) | ast::def_local(nid, _) | ast::def_self(nid, _) | ast::def_binding(nid, _) => { - assert (fcx.inh.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - return no_params(typ); + let typ = fcx.local_ty(sp, nid); + return no_params(typ); } ast::def_fn(_, ast::extern_fn) => { // extern functions are just u8 pointers @@ -2950,7 +2953,7 @@ fn instantiate_path(fcx: @fn_ctxt, pth.types.map(|aty| fcx.to_ty(*aty)) }; - let substs = {self_r: self_r, self_ty: None, tps: tps}; + let substs = substs { self_r: self_r, self_ty: None, tps: tps }; fcx.write_ty_substs(node_id, tpt.ty, substs); debug!("<<<"); @@ -3049,7 +3052,7 @@ fn check_bounds_are_used(ccx: @crate_ctxt, |_r| {}, |t| { match ty::get(t).sty { - ty::ty_param({idx, _}) => { + ty::ty_param(param_ty {idx, _}) => { debug!("Found use of ty param #%u", idx); tps_used[idx] = true; } @@ -3072,7 +3075,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { ty::mk_param(ccx.tcx, n, local_def(0)) } fn arg(m: ast::rmode, ty: ty::t) -> ty::arg { - {mode: ast::expl(m), ty: ty} + arg {mode: ast::expl(m), ty: ty} } let tcx = ccx.tcx; let (n_tps, inputs, output) = match ccx.tcx.sess.str_of(it.ident) { @@ -3135,18 +3138,42 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { onceness: ast::Once, region: ty::re_bound(ty::br_anon(0)), bounds: @~[]}, - sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val), - ty: ty::mk_imm_ptr( - ccx.tcx, - ty::mk_mach_uint(ccx.tcx, ast::ty_u8)) - }], - output: ty::mk_nil(ccx.tcx)} + sig: FnSig { + inputs: ~[arg { + mode: ast::expl(ast::by_val), + ty: ty::mk_imm_ptr( + ccx.tcx, + ty::mk_mach_uint(ccx.tcx, ast::ty_u8)) + }], + output: ty::mk_nil(ccx.tcx)} }); (0u, ~[arg(ast::by_ref, fty)], ty::mk_nil(tcx)) } ~"morestack_addr" => { (0u, ~[], ty::mk_nil_ptr(tcx)) } + ~"memmove32" => { + (0, ~[arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl })), + arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_imm })), + arg(ast::by_copy, + ty::mk_u32(tcx))], + ty::mk_nil(tcx)) + } + ~"memmove64" => { + (0, ~[arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl })), + arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_imm })), + arg(ast::by_copy, + ty::mk_u64(tcx))], + ty::mk_nil(tcx)) + } ~"sqrtf32" => { (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], ty::mk_f32(tcx)) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 05f23bddb0860..43c1cb7816694 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -30,7 +30,7 @@ this point a bit better. use core::prelude::*; use middle::freevars::get_freevars; -use middle::pat_util::pat_bindings; +use middle::pat_util::{pat_bindings, pat_is_binding}; use middle::ty::{encl_region, re_scope}; use middle::ty::{ty_fn_proto, vstore_box, vstore_fixed, vstore_slice}; use middle::ty::{vstore_uniq}; @@ -73,35 +73,44 @@ fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region { } impl @rcx { - /// Try to resolve the type for the given node. - /// - /// Note one important point: we do not attempt to resolve *region - /// variables* here. This is because regionck is essentially adding - /// constraints to those region variables and so may yet influence - /// how they are resolved. - /// - /// Consider this silly example: - /// - /// fn borrow(x: &int) -> &int {x} - /// fn foo(x: @int) -> int { /* block: B */ - /// let b = borrow(x); /* region: */ - /// *b - /// } - /// - /// Here, the region of `b` will be ``. `` is constrainted - /// to be some subregion of the block B and some superregion of - /// the call. If we forced it now, we'd choose the smaller region - /// (the call). But that would make the *b illegal. Since we don't - /// resolve, the type of b will be `&.int` and then `*b` will require - /// that `` be bigger than the let and the `*b` expression, so we - /// will effectively resolve `` to be the block B. - fn resolve_type(unresolved_ty: ty::t) -> fres { - resolve_type(self.fcx.infcx(), unresolved_ty, - resolve_and_force_all_but_regions) + fn resolve_type(unresolved_ty: ty::t) -> ty::t { + /*! + * Try to resolve the type for the given node, returning + * t_err if an error results. Note that we never care + * about the details of the error, the same error will be + * detected and reported in the writeback phase. + * + * Note one important point: we do not attempt to resolve + * *region variables* here. This is because regionck is + * essentially adding constraints to those region variables + * and so may yet influence how they are resolved. + * + * Consider this silly example: + * + * fn borrow(x: &int) -> &int {x} + * fn foo(x: @int) -> int { // block: B + * let b = borrow(x); // region: + * *b + * } + * + * Here, the region of `b` will be ``. `` is + * constrainted to be some subregion of the block B and some + * superregion of the call. If we forced it now, we'd choose + * the smaller region (the call). But that would make the *b + * illegal. Since we don't resolve, the type of b will be + * `&.int` and then `*b` will require that `` be + * bigger than the let and the `*b` expression, so we will + * effectively resolve `` to be the block B. + */ + match resolve_type(self.fcx.infcx(), unresolved_ty, + resolve_and_force_all_but_regions) { + Ok(t) => t, + Err(_) => ty::mk_err(self.fcx.tcx()) + } } /// Try to resolve the type for the given node. - fn resolve_node_type(id: ast::node_id) -> fres { + fn resolve_node_type(id: ast::node_id) -> ty::t { self.resolve_type(self.fcx.node_ty(id)) } } @@ -170,8 +179,13 @@ fn visit_block(b: ast::blk, &&rcx: @rcx, v: rvt) { } fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { - debug!("visit_expr(e=%s)", - pprust::expr_to_str(expr, rcx.fcx.tcx().sess.intr())); + debug!("visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); + + for rcx.fcx.inh.adjustments.find(expr.id).each |adjustment| { + for adjustment.autoref.each |autoref| { + guarantor::for_autoref(rcx, expr, *adjustment, autoref); + } + } match /*bad*/copy expr.node { ast::expr_path(*) => { @@ -242,41 +256,35 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { // particular case. There is an extensive comment on the // function check_cast_for_escaping_regions() in kind.rs // explaining how it goes about doing that. - match rcx.resolve_node_type(expr.id) { - result::Err(_) => { return; /*typeck will fail anyhow*/ } - result::Ok(target_ty) => { - match ty::get(target_ty).sty { - ty::ty_trait(_, _, vstore_slice(trait_region)) => { - let source_ty = rcx.fcx.expr_ty(source); - constrain_regions_in_type(rcx, trait_region, - expr.span, source_ty); - } - _ => () - } + let target_ty = rcx.resolve_node_type(expr.id); + match ty::get(target_ty).sty { + ty::ty_trait(_, _, vstore_slice(trait_region)) => { + let source_ty = rcx.fcx.expr_ty(source); + constrain_regions_in_type(rcx, trait_region, + expr.span, source_ty); } - }; + _ => () + } } - ast::expr_addr_of(*) => { - // FIXME(#3148) -- in some cases, we need to capture a - // dependency between the regions found in operand the - // resulting region type. See #3148 for more details. + ast::expr_addr_of(_, base) => { + guarantor::for_addr_of(rcx, expr, base); + } + + ast::expr_match(discr, ref arms) => { + guarantor::for_match(rcx, discr, *arms); } ast::expr_fn(*) | ast::expr_fn_block(*) => { - match rcx.resolve_node_type(expr.id) { - result::Err(_) => return, // Typechecking will fail anyhow. - result::Ok(function_type) => { - match ty::get(function_type).sty { - ty::ty_fn(ref fn_ty) => { - if fn_ty.meta.proto == ast::ProtoBorrowed { - constrain_free_variables( - rcx, fn_ty.meta.region, expr); - } - } - _ => () + let function_type = rcx.resolve_node_type(expr.id); + match ty::get(function_type).sty { + ty::ty_fn(ref fn_ty) => { + if fn_ty.meta.proto == ast::ProtoBorrowed { + constrain_free_variables( + rcx, fn_ty.meta.region, expr); } } + _ => () } } @@ -405,15 +413,10 @@ fn constrain_regions_in_type_of_node( // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. - let ty = match rcx.resolve_node_type(id) { - result::Err(_) => return true, - result::Ok(ty) => ty - }; - + let ty = rcx.resolve_node_type(id); debug!("constrain_regions_in_type_of_node(\ ty=%s, id=%d, encl_region=%?)", ty_to_str(tcx, ty), id, encl_region); - constrain_regions_in_type(rcx, encl_region, span, ty) } @@ -477,3 +480,471 @@ fn constrain_regions_in_type( } } } + +mod guarantor { + /*! + * + * The routines in this module are aiming to deal with the case + * where a the contents of a borrowed pointer are re-borrowed. + * Imagine you have a borrowed pointer `b` with lifetime L1 and + * you have an expression `&*b`. The result of this borrow will + * be another borrowed pointer with lifetime L2 (which is an + * inference variable). The borrow checker is going to enforce + * the constraint that L2 < L1, because otherwise you are + * re-borrowing data for a lifetime larger than the original loan. + * However, without the routines in this module, the region + * inferencer would not know of this dependency and thus it might + * infer the lifetime of L2 to be greater than L1 (issue #3148). + * + * There are a number of troublesome scenarios in the test + * `region-dependent-addr-of.rs`, but here is one example: + * + * struct Foo { i: int } + * struct Bar { foo: Foo } + * fn get_i(x: &a/Bar) -> &a/int { + * let foo = &x.foo; // Lifetime L1 + * &foo.i // Lifetime L2 + * } + * + * Note that this comes up either with `&` expressions, `ref` + * bindings, and `autorefs`, which are the three ways to introduce + * a borrow. + * + * The key point here is that when you are borrowing a value that + * is "guaranteed" by a borrowed pointer, you must link the + * lifetime of that borrowed pointer (L1, here) to the lifetime of + * the borrow itself (L2). What do I mean by "guaranteed" by a + * borrowed pointer? I mean any data that is reached by first + * dereferencing a borrowed pointer and then either traversing + * interior offsets or owned pointers. We say that the guarantor + * of such data it the region of the borrowed pointer that was + * traversed. This is essentially the same as the ownership + * relation, except that a borrowed pointer never owns its + * contents. + * + * NB: I really wanted to use the `mem_categorization` code here + * but I cannot because final type resolution hasn't happened yet, + * and `mem_categorization` requires that all types be known. + * So this is very similar logic to what you would find there, + * but more special purpose. + */ + + use core::prelude::*; + use middle::typeck::check::regionck::{rcx, infallibly_mk_subr}; + use middle::ty; + use syntax::ast; + use syntax::codemap::span; + use util::ppaux::{ty_to_str}; + + pub fn for_addr_of(rcx: @rcx, expr: @ast::expr, base: @ast::expr) { + /*! + * + * Computes the guarantor for an expression `&base` and then + * ensures that the lifetime of the resulting pointer is linked + * to the lifetime of its guarantor (if any). + */ + + debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); + let _i = ::util::common::indenter(); + + let guarantor = guarantor(rcx, base); + link(rcx, expr.span, expr.id, guarantor); + } + + pub fn for_match(rcx: @rcx, discr: @ast::expr, arms: &[ast::arm]) { + /*! + * + * Computes the guarantors for any ref bindings in a match and + * then ensures that the lifetime of the resulting pointer is + * linked to the lifetime of its guarantor (if any). + */ + + let discr_guarantor = guarantor(rcx, discr); + for arms.each |arm| { + for arm.pats.each |pat| { + link_ref_bindings_in_pat(rcx, *pat, discr_guarantor); + } + } + } + + pub fn for_autoref(rcx: @rcx, + expr: @ast::expr, + adjustment: &ty::AutoAdjustment, + autoref: &ty::AutoRef) + { + /*! + * + * Computes the guarantor for an expression that has an + * autoref adjustment and links it to the lifetime of the + * autoref. This is only important when auto re-borrowing + * region pointers. + */ + + debug!("guarantor::for_autoref(expr=%s)", rcx.fcx.expr_to_str(expr)); + let _i = ::util::common::indenter(); + + let mut expr_ct = categorize_unadjusted(rcx, expr); + expr_ct = apply_autoderefs( + rcx, expr, adjustment.autoderefs, expr_ct); + for expr_ct.cat.guarantor.each |g| { + infallibly_mk_subr(rcx, true, expr.span, autoref.region, *g); + } + } + + fn link( + rcx: @rcx, + span: span, + id: ast::node_id, + guarantor: Option) + { + /*! + * + * Links the lifetime of the borrowed pointer resulting from a borrow + * to the lifetime of its guarantor (if any). + */ + + debug!("opt_constrain_region(id=%?, guarantor=%?)", id, guarantor); + + let bound = match guarantor { + None => { + // If guarantor is None, then the value being borrowed + // is not guaranteed by a region pointer, so there are + // no lifetimes to link. + return; + } + Some(r) => { r } + }; + + // this routine is used for the result of ref bindings and & + // expressions, both of which always yield a region variable, so + // mk_subr should never fail. + let rptr_ty = rcx.resolve_node_type(id); + if !ty::type_contains_err(rptr_ty) { + debug!("rptr_ty=%s", ty_to_str(rcx.fcx.ccx.tcx, rptr_ty)); + let r = ty::ty_region(rptr_ty); + infallibly_mk_subr(rcx, true, span, r, bound); + } + } + + /// Categorizes types based on what kind of pointer they are. + /// Note that we don't bother to distinguish between rptrs (&T) + /// and slices (&[T], &str)---they are all just `BorrowedPointer`. + enum PointerCategorization { + NotPointer, + OwnedPointer, + BorrowedPointer(ty::Region), + OtherPointer + } + + /// Guarantor of an expression paired with the + /// PointerCategorization` of its type. + struct ExprCategorization { + guarantor: Option, + pointer: PointerCategorization + } + + /// ExprCategorization paired with the full type of the expr + struct ExprCategorizationType { + cat: ExprCategorization, + ty: ty::t + } + + fn guarantor(rcx: @rcx, expr: @ast::expr) -> Option { + /*! + * + * Computes the guarantor of `expr`, or None if `expr` is + * not guaranteed by any region. Here `expr` is some expression + * whose address is being taken (e.g., there is an expression + * `&expr`). + */ + + debug!("guarantor(expr=%s)", rcx.fcx.expr_to_str(expr)); + match expr.node { + ast::expr_unary(ast::deref, b) => { + let cat = categorize(rcx, b); + guarantor_of_deref(&cat) + } + ast::expr_field(b, _, _) => { + categorize(rcx, b).guarantor + } + ast::expr_index(b, _) => { + let cat = categorize(rcx, b); + guarantor_of_deref(&cat) + } + + ast::expr_paren(e) => { + guarantor(rcx, e) + } + + ast::expr_path(*) => { + // Either a variable or constant and hence resides + // in constant memory or on the stack frame. Either way, + // not guaranteed by a region pointer. + None + } + + // All of these expressions are rvalues and hence their + // value is not guaranteed by a region pointer. + ast::expr_mac(*) | + ast::expr_lit(_) | + ast::expr_unary(*) | + ast::expr_addr_of(*) | + ast::expr_binary(*) | + ast::expr_vstore(*) | + ast::expr_break(*) | + ast::expr_again(*) | + ast::expr_ret(*) | + ast::expr_log(*) | + ast::expr_fail(*) | + ast::expr_assert(*) | + ast::expr_while(*) | + ast::expr_loop(*) | + ast::expr_assign(*) | + ast::expr_swap(*) | + ast::expr_assign_op(*) | + ast::expr_cast(*) | + ast::expr_call(*) | + ast::expr_method_call(*) | + ast::expr_rec(*) | + ast::expr_struct(*) | + ast::expr_tup(*) | + ast::expr_if(*) | + ast::expr_match(*) | + ast::expr_fn(*) | + ast::expr_fn_block(*) | + ast::expr_loop_body(*) | + ast::expr_do_body(*) | + ast::expr_block(*) | + ast::expr_copy(*) | + ast::expr_unary_move(*) | + ast::expr_repeat(*) | + ast::expr_vec(*) => { + assert !ty::expr_is_lval( + rcx.fcx.tcx(), rcx.fcx.ccx.method_map, expr); + None + } + } + } + + fn categorize(rcx: @rcx, expr: @ast::expr) -> ExprCategorization { + debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); + let _i = ::util::common::indenter(); + + let mut expr_ct = categorize_unadjusted(rcx, expr); + debug!("before adjustments, cat=%?", expr_ct.cat); + + for rcx.fcx.inh.adjustments.find(expr.id).each |adjustment| { + debug!("adjustment=%?", adjustment); + + expr_ct = apply_autoderefs( + rcx, expr, adjustment.autoderefs, expr_ct); + + for adjustment.autoref.each |autoref| { + // If there is an autoref, then the result of this + // expression will be some sort of borrowed pointer. + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = BorrowedPointer(autoref.region); + debug!("autoref, cat=%?", expr_ct.cat); + } + } + + debug!("result=%?", expr_ct.cat); + return expr_ct.cat; + } + + fn categorize_unadjusted(rcx: @rcx, + expr: @ast::expr) -> ExprCategorizationType { + debug!("categorize_unadjusted(expr=%s)", rcx.fcx.expr_to_str(expr)); + let _i = ::util::common::indenter(); + + let guarantor = { + if rcx.fcx.ccx.method_map.contains_key(expr.id) { + None + } else { + guarantor(rcx, expr) + } + }; + + let expr_ty = rcx.resolve_node_type(expr.id); + ExprCategorizationType { + cat: ExprCategorization { + guarantor: guarantor, + pointer: pointer_categorize(expr_ty) + }, + ty: expr_ty + } + } + + fn apply_autoderefs( + +rcx: @rcx, + +expr: @ast::expr, + +autoderefs: uint, + +ct: ExprCategorizationType) -> ExprCategorizationType + { + let mut ct = ct; + let tcx = rcx.fcx.ccx.tcx; + for uint::range(0, autoderefs) |_| { + ct.cat.guarantor = guarantor_of_deref(&ct.cat); + + match ty::deref(tcx, ct.ty, true) { + Some(mt) => { + ct.ty = mt.ty; + ct.cat.pointer = pointer_categorize(ct.ty); + } + None => { + tcx.sess.span_bug( + expr.span, + fmt!("Autoderef but type not derefable: %s", + ty_to_str(tcx, ct.ty))); + } + } + + debug!("autoderef, cat=%?", ct.cat); + } + return ct; + } + + fn pointer_categorize(ty: ty::t) -> PointerCategorization { + match ty::get(ty).sty { + ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) | + ty::ty_estr(ty::vstore_slice(r)) => { + BorrowedPointer(r) + } + ty::ty_uniq(*) | ty::ty_estr(ty::vstore_uniq) | + ty::ty_evec(_, ty::vstore_uniq) => { + OwnedPointer + } + ty::ty_box(*) | ty::ty_ptr(*) | + ty::ty_evec(_, ty::vstore_box) | + ty::ty_estr(ty::vstore_box) => { + OtherPointer + } + _ => { + NotPointer + } + } + } + + fn guarantor_of_deref(cat: &ExprCategorization) -> Option { + match cat.pointer { + NotPointer => cat.guarantor, + BorrowedPointer(r) => Some(r), + OwnedPointer => cat.guarantor, + OtherPointer => None + } + } + + fn link_ref_bindings_in_pat( + rcx: @rcx, + pat: @ast::pat, + guarantor: Option) + { + /*! + * + * Descends through the pattern, tracking the guarantor + * of the value being matched. When a ref binding is encountered, + * links the lifetime of that ref binding to the lifetime of + * the guarantor. We begin with the guarantor of the + * discriminant but of course as we go we may pass through + * other pointers. + */ + + debug!("link_ref_bindings_in_pat(pat=%s, guarantor=%?)", + rcx.fcx.pat_to_str(pat), guarantor); + let _i = ::util::common::indenter(); + + match pat.node { + ast::pat_wild => {} + ast::pat_ident(ast::bind_by_ref(_), _, opt_p) => { + link(rcx, pat.span, pat.id, guarantor); + + for opt_p.each |p| { + link_ref_bindings_in_pat(rcx, *p, guarantor); + } + } + ast::pat_ident(_, _, opt_p) => { + for opt_p.each |p| { + link_ref_bindings_in_pat(rcx, *p, guarantor); + } + } + ast::pat_enum(*) => {} + ast::pat_rec(ref fpats, _) | + ast::pat_struct(_, ref fpats, _) => { + for fpats.each |fpat| { + link_ref_bindings_in_pat(rcx, fpat.pat, guarantor); + } + } + ast::pat_tup(ref ps) => { + link_ref_bindings_in_pats(rcx, ps, guarantor) + } + ast::pat_box(p) => { + link_ref_bindings_in_pat(rcx, p, None) + } + ast::pat_uniq(p) => { + link_ref_bindings_in_pat(rcx, p, guarantor) + } + ast::pat_region(p) => { + let rptr_ty = rcx.resolve_node_type(pat.id); + if !ty::type_contains_err(rptr_ty) { + let r = ty::ty_region(rptr_ty); + link_ref_bindings_in_pat(rcx, p, Some(r)); + } + } + ast::pat_lit(*) => {} + ast::pat_range(*) => {} + ast::pat_vec(ref ps, ref opt_tail_pat) => { + let vec_ty = rcx.resolve_node_type(pat.id); + if !ty::type_contains_err(vec_ty) { + let vstore = ty::ty_vstore(vec_ty); + let guarantor1 = match vstore { + ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, + ty::vstore_slice(r) => Some(r), + ty::vstore_box => None + }; + + link_ref_bindings_in_pats(rcx, ps, guarantor1); + + for opt_tail_pat.each |p| { + link_ref_bindings_in_pat(rcx, *p, guarantor); + } + } + } + } + } + + fn link_ref_bindings_in_pats(rcx: @rcx, + pats: &~[@ast::pat], + guarantor: Option) + { + for pats.each |pat| { + link_ref_bindings_in_pat(rcx, *pat, guarantor); + } + } + +} + +fn infallibly_mk_subr(rcx: @rcx, + a_is_expected: bool, + span: span, + a: ty::Region, + b: ty::Region) +{ + /*! + * + * Constrains `a` to be a subregion of `b`. In many cases, we + * know that this can never yield an error due to the way that + * region inferencing works. Therefore just report a bug if we + * ever see `Err(_)`. + */ + + match rcx.fcx.mk_subr(a_is_expected, span, a, b) { + result::Ok(()) => {} + result::Err(e) => { + rcx.fcx.ccx.tcx.sess.span_bug( + span, + fmt!("Supposedly infallible attempt to \ + make %? < %? failed: %?", + a, b, e)); + } + } +} \ No newline at end of file diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 9d309d4996bdd..9f6cc6835b715 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -11,6 +11,7 @@ use core::prelude::*; use middle::resolve; +use middle::ty::{param_ty, substs}; use middle::ty; use middle::typeck::check::{fn_ctxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; @@ -103,7 +104,10 @@ fn lookup_vtables(vcx: &VtableContext, ppaux::ty_to_str(tcx, trait_ty), ty::substs_to_str(tcx, substs)); - let new_substs = {self_ty: Some(*ty), ../*bad*/copy *substs}; + let new_substs = substs { + self_ty: Some(*ty), + ../*bad*/copy *substs + }; let trait_ty = ty::subst(tcx, &new_substs, trait_ty); debug!("after subst: %?", @@ -189,7 +193,7 @@ fn lookup_vtable(vcx: &VtableContext, }; match ty::get(ty).sty { - ty::ty_param({idx: n, def_id: did}) => { + ty::ty_param(param_ty {idx: n, def_id: did}) => { let mut n_bound = 0; let bounds = tcx.ty_param_bounds.get(did.node); for ty::iter_bound_traits_and_supertraits( diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 1a665aa756611..c5374af2dd060 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -15,8 +15,9 @@ use core::prelude::*; use middle::pat_util; +use middle::ty::arg; use middle::ty; -use middle::typeck::check::{fn_ctxt, lookup_local, self_info}; +use middle::typeck::check::{fn_ctxt, self_info}; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::{resolve_type}; use middle::typeck::infer; @@ -65,7 +66,7 @@ fn resolve_method_map_entry(fcx: @fn_ctxt, sp: span, id: ast::node_id) fcx.ccx.method_map.insert( id, method_map_entry { - self_arg: {mode: mme.self_arg.mode, ty: *t}, + self_arg: arg {mode: mme.self_arg.mode, ty: *t}, .. *mme } ); @@ -216,8 +217,7 @@ fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) { } fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) { if !wbcx.success { return; } - let var_id = lookup_local(wbcx.fcx, l.span, l.node.id); - let var_ty = ty::mk_var(wbcx.fcx.tcx(), var_id); + let var_ty = wbcx.fcx.local_ty(l.span, l.node.id); match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) { Ok(lty) => { debug!("Type for local %s (id %d) resolved to %s", diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index b0c98cfa2b17e..4cd2eaaf003c9 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -25,8 +25,8 @@ use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get}; use middle::ty::{kind_can_be_copied, lookup_item_type, param_bounds, subst}; -use middle::ty::{t, ty_bool, ty_bot, ty_box, ty_enum, ty_err, ty_estr}; -use middle::ty::{ty_evec, ty_float, ty_fn, ty_infer, ty_int, ty_nil}; +use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err}; +use middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr}; use middle::ty::{ty_rec, ty_rptr, ty_self, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_type, ty_uint, ty_uniq}; @@ -34,6 +34,7 @@ use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext}; use middle::ty::{type_is_ty_var}; use middle::ty; use middle::typeck::crate_ctxt; +use middle::typeck::infer::combine::Combine; use middle::typeck::infer::{InferCtxt, can_mk_subty}; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar}; use middle::typeck::infer::{resolve_nested_tvar, resolve_type}; @@ -286,8 +287,8 @@ impl CoherenceChecker { } // Add the implementation to the mapping from implementation to base - // type def ID, if there is a base type for this implementation. - + // type def ID, if there is a base type for this implementation and + // the implementation does not have any associated traits. match get_base_type_def_id(self.inference_context, item.span, self_type.ty) { @@ -296,16 +297,19 @@ impl CoherenceChecker { } Some(base_type_def_id) => { // XXX: Gather up default methods? - let implementation; - match implementation_opt { - None => { - implementation = self.create_impl_from_item(item); - } - Some(copy existing_implementation) => { - implementation = existing_implementation; + if associated_traits.len() == 0 { + let implementation; + match implementation_opt { + None => { + implementation = self.create_impl_from_item(item); + } + Some(copy existing_implementation) => { + implementation = existing_implementation; + } } + self.add_inherent_method(base_type_def_id, + implementation); } - self.add_inherent_method(base_type_def_id, implementation); self.base_type_def_ids.insert(local_def(item.id), base_type_def_id); @@ -510,7 +514,7 @@ impl CoherenceChecker { let type_parameters = self.inference_context.next_ty_vars(bounds_count); - let substitutions = { + let substitutions = substs { self_r: self_region, self_ty: None, tps: type_parameters @@ -520,7 +524,8 @@ impl CoherenceChecker { polytype.ty); // Get our type parameters back. - let { self_r: _, self_ty: _, tps: type_parameters } = substitutions; + let substs { self_r: _, self_ty: _, tps: type_parameters } = + substitutions; UniversalQuantificationResult { monotype: monotype, @@ -597,6 +602,7 @@ impl CoherenceChecker { visit_mod(module_, item.span, item.id, (), visitor); } item_impl(_, opt_trait, _, _) => { + let mut ok = false; match self.base_type_def_ids.find( local_def(item.id)) { @@ -611,57 +617,50 @@ impl CoherenceChecker { // Record that this implementation is OK. self.privileged_implementations.insert (item.id, ()); - } else { - // This implementation is not in scope of - // its base type. This still might be OK - // if the traits are defined in the same - // crate. - - match opt_trait { - None => { - // There is no trait to implement, so - // this is an error. - - let session = - self.crate_context.tcx.sess; - session.span_err(item.span, - ~"cannot implement \ - inherent methods \ - for a type outside \ - the crate the type \ - was defined in; \ - define and \ - implement a trait \ - or new type \ - instead"); - } - _ => () - } - - do opt_trait.iter() |trait_ref| { - // This is OK if and only if the - // trait was defined in this - // crate. - - let trait_def_id = - self.trait_ref_to_trait_def_id( - *trait_ref); - - if trait_def_id.crate != local_crate { - let session = - self.crate_context.tcx.sess; - session.span_err(item.span, - ~"cannot \ - provide an \ - extension \ - implementa\ - tion \ - for a trait \ - not defined \ - in this \ - crate"); - } - } + ok = true; + } + } + } + + if !ok { + // This implementation is not in scope of its base + // type. This still might be OK if the trait is + // defined in the same crate. + + match opt_trait { + None => { + // There is no trait to implement, so + // this is an error. + + let session = self.crate_context.tcx.sess; + session.span_err(item.span, + ~"cannot implement \ + inherent methods for a \ + type outside the crate \ + the type was defined \ + in; define and \ + implement a trait or \ + new type instead"); + } + _ => () + } + + do opt_trait.iter() |trait_ref| { + // This is OK if and only if the trait was + // defined in this crate. + + let trait_def_id = + self.trait_ref_to_trait_def_id( + *trait_ref); + + if trait_def_id.crate != local_crate { + let session = self.crate_context.tcx.sess; + session.span_err(item.span, + ~"cannot provide an \ + extension \ + implementation for a \ + trait not defined in \ + this crate"); } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index ba34846ca97ce..8374a65f63c30 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -33,8 +33,8 @@ are represented as `ty_param()` instances. use core::prelude::*; use metadata::csearch; -use middle::ty::{FnMeta, FnSig, FnTyBase, InstantiatedTraitRef}; -use middle::ty::{ty_param_substs_and_ty}; +use middle::ty::{FnMeta, FnSig, FnTyBase, InstantiatedTraitRef, arg}; +use middle::ty::{substs, ty_param_substs_and_ty}; use middle::ty; use middle::typeck::astconv::{ast_conv, ty_of_fn_decl, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; @@ -75,7 +75,11 @@ fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) { for m.items.each |intrinsic_item| { let def_id = ast::def_id { crate: ast::local_crate, node: intrinsic_item.id }; - let substs = {self_r: None, self_ty: None, tps: ~[]}; + let substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; match intrinsic_item.node { ast::item_trait(*) => { @@ -164,7 +168,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt, let rs = type_rscope(rp); let args = args.map(|va| { let arg_ty = ccx.to_ty(rs, va.ty); - {mode: ast::expl(ast::by_copy), ty: arg_ty} + arg { mode: ast::expl(ast::by_copy), ty: arg_ty } }); result_ty = Some(ty::mk_fn(tcx, FnTyBase { meta: FnMeta {purity: ast::pure_fn, @@ -195,8 +199,9 @@ fn get_enum_variant_types(ccx: @crate_ctxt, variant.node.id); // Compute the ctor arg types from the struct fields let struct_fields = do struct_def.fields.map |struct_field| { - {mode: ast::expl(ast::by_val), - ty: ty::node_id_to_type(ccx.tcx, (*struct_field).node.id) + arg { + mode: ast::expl(ast::by_val), + ty: ty::node_id_to_type(ccx.tcx, struct_field.node.id) } }; result_ty = Some(ty::mk_fn(tcx, FnTyBase { @@ -265,8 +270,11 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id, trait_ty: ty::t) { ty::mk_param(ccx.tcx, i + 1, dummy_defid) }; - let substs = { self_r: None, self_ty: Some(self_param), - tps: non_shifted_trait_tps + shifted_method_tps }; + let substs = substs { + self_r: None, + self_ty: Some(self_param), + tps: non_shifted_trait_tps + shifted_method_tps + }; let ty = ty::subst(ccx.tcx, &substs, ty::mk_fn(ccx.tcx, /*bad*/copy m.fty)); @@ -462,7 +470,7 @@ fn compare_impl_method(tcx: ty::ctxt, }; let trait_tps = trait_substs.tps.map( |t| replace_bound_self(tcx, *t, dummy_self_r)); - let substs = { + let substs = substs { self_r: Some(dummy_self_r), self_ty: Some(self_ty), tps: vec::append(trait_tps, dummy_tps) @@ -590,6 +598,20 @@ fn convert_methods(ccx: @crate_ctxt, } } +fn ensure_no_ty_param_bounds(ccx: @crate_ctxt, + span: span, + ty_params: &[ast::ty_param], + thing: &static/str) { + for ty_params.each |ty_param| { + if ty_param.bounds.len() > 0 { + ccx.tcx.sess.span_err( + span, + fmt!("trait bounds are not allowed in %s definitions", + thing)); + } + } +} + fn convert(ccx: @crate_ctxt, it: @ast::item) { let tcx = ccx.tcx; let rp = tcx.region_paramd_items.find(it.id); @@ -599,6 +621,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { // These don't define types. ast::item_foreign_mod(_) | ast::item_mod(_) => {} ast::item_enum(ref enum_definition, ref ty_params) => { + ensure_no_ty_param_bounds(ccx, it.span, *ty_params, "enumeration"); let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); get_enum_variant_types(ccx, @@ -636,6 +659,8 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { let _ = convert_methods(ccx, provided_methods, rp, bounds); } ast::item_struct(struct_def, tps) => { + ensure_no_ty_param_bounds(ccx, it.span, tps, "structure"); + // Write the class type let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); @@ -643,6 +668,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { convert_struct(ccx, rp, struct_def, tps, tpt, it.id); } + ast::item_ty(_, ref ty_params) => { + ensure_no_ty_param_bounds(ccx, it.span, *ty_params, "type"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + } _ => { // This call populates the type cache with the converted type // of the item in passing. All we have to do here is to write @@ -705,7 +735,7 @@ fn convert_struct(ccx: @crate_ctxt, }, sig: FnSig { inputs: do struct_def.fields.map |field| { - { + arg { mode: ast::expl(ast::by_copy), ty: ccx.tcx.tcache.get (local_def(field.node.id)).ty @@ -1002,5 +1032,8 @@ fn mk_substs(ccx: @crate_ctxt, -> {bounds: @~[ty::param_bounds], substs: ty::substs} { let {bounds, params} = mk_ty_params(ccx, atps); let self_r = rscope::bound_self_region(rp); - {bounds: bounds, substs: {self_r: self_r, self_ty: None, tps: params}} + { + bounds: bounds, + substs: substs { self_r: self_r, self_ty: None, tps: params } + } } diff --git a/src/librustc/middle/typeck/infer/assignment.rs b/src/librustc/middle/typeck/infer/assignment.rs deleted file mode 100644 index fef63cf9a42cc..0000000000000 --- a/src/librustc/middle/typeck/infer/assignment.rs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ______________________________________________________________________ -// Type assignment -// -// True if rvalues of type `a` can be assigned to lvalues of type `b`. -// This may cause borrowing to the region scope enclosing `a_node_id`. -// -// The strategy here is somewhat non-obvious. The problem is -// that the constraint we wish to contend with is not a subtyping -// constraint. Currently, for variables, we only track what it -// must be a subtype of, not what types it must be assignable to -// (or from). Possibly, we should track that, but I leave that -// refactoring for another day. -// -// Instead, we look at each variable involved and try to extract -// *some* sort of bound. Typically, the type a is the argument -// supplied to a call; it typically has a *lower bound* (which -// comes from having been assigned a value). What we'd actually -// *like* here is an upper-bound, but we generally don't have -// one. The type b is the expected type and it typically has a -// lower-bound too, which is good. -// -// The way we deal with the fact that we often don't have the -// bounds we need is to be a bit careful. We try to get *some* -// bound from each side, preferring the upper from a and the -// lower from b. If we fail to get a bound from both sides, then -// we just fall back to requiring that a <: b. -// -// Assuming we have a bound from both sides, we will then examine -// these bounds and see if they have the form (@M_a T_a, &rb.M_b T_b) -// (resp. ~M_a T_a, ~[M_a T_a], etc). If they do not, we fall back to -// subtyping. -// -// If they *do*, then we know that the two types could never be -// subtypes of one another. We will then construct a type @const T_b -// and ensure that type a is a subtype of that. This allows for the -// possibility of assigning from a type like (say) @~[mut T1] to a type -// &~[T2] where T1 <: T2. This might seem surprising, since the `@` -// points at mutable memory but the `&` points at immutable memory. -// This would in fact be unsound, except for the borrowck, which comes -// later and guarantees that such mutability conversions are safe. -// See borrowck for more details. Next we require that the region for -// the enclosing scope be a superregion of the region r. -// -// You might wonder why we don't make the type &e.const T_a where e is -// the enclosing region and check that &e.const T_a <: B. The reason -// is that the type of A is (generally) just a *lower-bound*, so this -// would be imposing that lower-bound also as the upper-bound on type -// A. But this upper-bound might be stricter than what is truly -// needed. - -use core::prelude::*; - -use middle::ty::TyVar; -use middle::ty; -use middle::typeck::infer::{ares, cres}; -use middle::typeck::infer::combine::CombineFields; -use middle::typeck::infer::sub::Sub; -use middle::typeck::infer::to_str::InferStr; -use util::common::{indent, indenter}; - -use core::option; -use syntax::ast::{m_const, m_imm, m_mutbl}; -use syntax::ast; - -fn to_ares(+c: cres) -> ares { - match c { - Ok(_) => Ok(None), - Err(ref e) => Err((*e)) - } -} - -// Note: Assign is not actually a combiner, in that it does not -// conform to the same interface, though it performs a similar -// function. -enum Assign = CombineFields; - -impl Assign { - fn tys(a: ty::t, b: ty::t) -> ares { - debug!("Assign.tys(%s => %s)", - a.inf_str(self.infcx), - b.inf_str(self.infcx)); - let _r = indenter(); - - debug!("Assign.tys: copying first type"); - let copy_a = copy ty::get(a).sty; - debug!("Assign.tys: copying second type"); - let copy_b = copy ty::get(b).sty; - debug!("Assign.tys: performing match"); - - let r = match (copy_a, copy_b) { - (ty::ty_bot, _) => { - Ok(None) - } - - (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { - let nde_a = self.infcx.get(&self.infcx.ty_var_bindings, a_id); - let nde_b = self.infcx.get(&self.infcx.ty_var_bindings, b_id); - let a_bounds = nde_a.possible_types; - let b_bounds = nde_b.possible_types; - - let a_bnd = option::or(a_bounds.ub, a_bounds.lb); - let b_bnd = option::or(b_bounds.lb, b_bounds.ub); - self.assign_tys_or_sub(a, b, a_bnd, b_bnd) - } - - (ty::ty_infer(TyVar(a_id)), _) => { - let nde_a = self.infcx.get(&self.infcx.ty_var_bindings, a_id); - let a_bounds = nde_a.possible_types; - - let a_bnd = option::or(a_bounds.ub, a_bounds.lb); - self.assign_tys_or_sub(a, b, a_bnd, Some(b)) - } - - (_, ty::ty_infer(TyVar(b_id))) => { - let nde_b = self.infcx.get(&self.infcx.ty_var_bindings, b_id); - let b_bounds = nde_b.possible_types; - - let b_bnd = option::or(b_bounds.lb, b_bounds.ub); - self.assign_tys_or_sub(a, b, Some(a), b_bnd) - } - - (_, _) => { - self.assign_tys_or_sub(a, b, Some(a), Some(b)) - } - }; - - debug!("Assign.tys end"); - - move r - } -} - -priv impl Assign { - fn assign_tys_or_sub( - a: ty::t, b: ty::t, - +a_bnd: Option, +b_bnd: Option) -> ares { - - debug!("Assign.assign_tys_or_sub(%s => %s, %s => %s)", - a.inf_str(self.infcx), b.inf_str(self.infcx), - a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx)); - let _r = indenter(); - - fn is_borrowable(v: ty::vstore) -> bool { - match v { - ty::vstore_fixed(_) | ty::vstore_uniq | ty::vstore_box => true, - ty::vstore_slice(_) => false - } - } - - fn borrowable_protos(a_p: ast::Proto, b_p: ast::Proto) -> bool { - match (a_p, b_p) { - (ast::ProtoBox, ast::ProtoBorrowed) => true, - (ast::ProtoUniq, ast::ProtoBorrowed) => true, - _ => false - } - } - - match (a_bnd, b_bnd) { - (Some(a_bnd), Some(b_bnd)) => { - match (/*bad*/copy ty::get(a_bnd).sty, - /*bad*/copy ty::get(b_bnd).sty) { - // check for a case where a non-region pointer (@, ~) is - // being assigned to a region pointer: - (ty::ty_box(_), ty::ty_rptr(r_b, mt_b)) => { - let nr_b = ty::mk_box(self.infcx.tcx, - ty::mt {ty: mt_b.ty, - mutbl: m_const}); - self.try_assign(1, ty::AutoPtr, - a, nr_b, - mt_b.mutbl, r_b) - } - (ty::ty_uniq(_), ty::ty_rptr(r_b, mt_b)) => { - let nr_b = ty::mk_uniq(self.infcx.tcx, - ty::mt {ty: mt_b.ty, - mutbl: m_const}); - self.try_assign(1, ty::AutoPtr, - a, nr_b, - mt_b.mutbl, r_b) - } - (ty::ty_estr(vs_a), - ty::ty_estr(ty::vstore_slice(r_b))) - if is_borrowable(vs_a) => { - let nr_b = ty::mk_estr(self.infcx.tcx, vs_a); - self.try_assign(0, ty::AutoBorrowVec, - a, nr_b, - m_imm, r_b) - } - - (ty::ty_evec(_, vs_a), - ty::ty_evec(mt_b, ty::vstore_slice(r_b))) - if is_borrowable(vs_a) => { - let nr_b = ty::mk_evec(self.infcx.tcx, - ty::mt {ty: mt_b.ty, - mutbl: m_const}, - vs_a); - self.try_assign(0, ty::AutoBorrowVec, - a, nr_b, - mt_b.mutbl, r_b) - } - - (ty::ty_fn(ref a_f), ty::ty_fn(ref b_f)) - if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => { - let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase { - meta: ty::FnMeta {proto: a_f.meta.proto, - ..b_f.meta}, - sig: copy b_f.sig - }); - self.try_assign(0, ty::AutoBorrowFn, - a, nr_b, m_imm, b_f.meta.region) - } - - (ty::ty_fn(ref a_f), ty::ty_fn(ref b_f)) - if a_f.meta.proto == ast::ProtoBare => { - let b1_f = ty::FnTyBase { - meta: ty::FnMeta {proto: ast::ProtoBare, - ..b_f.meta}, - sig: copy b_f.sig - }; - // Eventually we will need to add some sort of - // adjustment here so that trans can add an - // extra NULL env pointer: - to_ares(Sub(*self).fns(a_f, &b1_f)) - } - - // check for &T being assigned to *T: - (ty::ty_rptr(_, ref a_t), ty::ty_ptr(ref b_t)) => { - to_ares(Sub(*self).mts(*a_t, *b_t)) - } - - // otherwise, assignment follows normal subtype rules: - _ => { - to_ares(Sub(*self).tys(a, b)) - } - } - } - _ => { - // if insufficient bounds were available, just follow - // normal subtype rules: - to_ares(Sub(*self).tys(a, b)) - } - } - } - - /// Given an assignment from a type like `@a` to `&r_b/m nr_b`, - /// this function checks that `a <: nr_b`. In that case, the - /// assignment is permitted, so it constructs a fresh region - /// variable `r_a >= r_b` and returns a corresponding assignment - /// record. See the discussion at the top of this file for more - /// details. - fn try_assign(autoderefs: uint, - kind: ty::AutoRefKind, - a: ty::t, - nr_b: ty::t, - m: ast::mutability, - r_b: ty::Region) -> ares { - - debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)", - a.inf_str(self.infcx), - nr_b.inf_str(self.infcx), - m, - r_b.inf_str(self.infcx)); - - do indent { - let sub = Sub(*self); - do sub.tys(a, nr_b).chain |_t| { - let r_a = self.infcx.next_region_var_nb(self.span); - do sub.contraregions(r_a, r_b).chain |_r| { - Ok(Some(@ty::AutoAdjustment { - autoderefs: autoderefs, - autoref: Some(ty::AutoRef { - kind: kind, - region: r_a, - mutbl: m - }) - })) - } - } - } - } -} - diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs new file mode 100644 index 0000000000000..f0fe2deffdfa8 --- /dev/null +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -0,0 +1,377 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +# Type Coercion + +Under certain circumstances we will coerce from one type to another, +for example by auto-borrowing. This occurs in situations where the +compiler has a firm 'expected type' that was supplied from the user, +and where the actual type is similar to that expected type in purpose +but not in representation (so actual subtyping is inappropriate). + +## Reborrowing + +Note that if we are expecting a borrowed pointer, we will *reborrow* +even if the argument provided was already a borrowed pointer. This is +useful for freezing mut/const things (that is, when the expected is &T +but you have &const T or &mut T) and also for avoiding the linearity +of mut things (when the expected is &mut T and you have &mut T). See +the various `src/test/run-pass/coerce-reborrow-*.rs` tests for +examples of where this is useful. + +## Subtle note + +When deciding what type coercions to consider, we do not attempt to +resolve any type variables we may encounter. This is because `b` +represents the expected type "as the user wrote it", meaning that if +the user defined a generic function like + + fn foo(a: A, b: A) { ... } + +and then we wrote `foo(&1, @2)`, we will not auto-borrow +either argument. In older code we went to some lengths to +resolve the `b` variable, which could mean that we'd +auto-borrow later arguments but not earlier ones, which +seems very confusing. + +## Subtler note + +However, right now, if the user manually specifies the +values for the type variables, as so: + + foo::<&int>(@1, @2) + +then we *will* auto-borrow, because we can't distinguish this from a +function that declared `&int`. This is inconsistent but it's easiest +at the moment. The right thing to do, I think, is to consider the +*unsubstituted* type when deciding whether to auto-borrow, but the +*substituted* type when considering the bounds and so forth. But most +of our methods don't give access to the unsubstituted type, and +rightly so because they'd be error-prone. So maybe the thing to do is +to actually determine the kind of coercions that should occur +separately and pass them in. Or maybe it's ok as is. Anyway, it's +sort of a minor point so I've opted to leave it for later---after all +we may want to adjust precisely when coercions occur. + +*/ + +use core::prelude::*; + +use middle::ty::{TyVar, AutoPtr, AutoBorrowVec, AutoBorrowFn}; +use middle::ty::{AutoAdjustment, AutoRef}; +use middle::ty::{vstore_slice, vstore_box, vstore_uniq, vstore_fixed}; +use middle::ty::{FnMeta, FnTyBase, mt}; +use middle::ty; +use middle::typeck::infer::{CoerceResult, resolve_type}; +use middle::typeck::infer::combine::CombineFields; +use middle::typeck::infer::sub::Sub; +use middle::typeck::infer::to_str::InferStr; +use middle::typeck::infer::resolve::try_resolve_tvar_shallow; +use util::common::{indent, indenter}; + +use core::option; +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast; + +// Note: Coerce is not actually a combiner, in that it does not +// conform to the same interface, though it performs a similar +// function. +pub enum Coerce = CombineFields; + +impl Coerce { + fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult { + debug!("Coerce.tys(%s => %s)", + a.inf_str(self.infcx), + b.inf_str(self.infcx)); + let _indent = indenter(); + + // Examine the supertype and consider auto-borrowing. + // + // Note: does not attempt to resolve type variables we encounter. + // See above for details. + match ty::get(b).sty { + ty::ty_rptr(_, mt_b) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_pointer(a, sty_a, b, mt_b) + }; + } + + ty::ty_estr(vstore_slice(_)) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_string(a, sty_a, b) + }; + } + + ty::ty_evec(mt_b, vstore_slice(_)) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_vector(a, sty_a, b, mt_b) + }; + } + + ty::ty_fn(ref b_f) if b_f.meta.proto == ast::ProtoBorrowed => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_fn(a, sty_a, b) + }; + } + + ty::ty_ptr(_) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_unsafe_ptr(a, sty_a, b) + }; + } + + _ => {} + } + + do self.unpack_actual_value(a) |sty_a| { + match *sty_a { + ty::ty_fn(ref a_f) if a_f.meta.proto == ast::ProtoBare => { + // Bare functions are coercable to any closure type. + // + // FIXME(#3320) this should go away and be + // replaced with proper inference, got a patch + // underway - ndm + self.coerce_from_bare_fn(a, a_f, b) + } + _ => { + // Otherwise, just use subtyping rules. + self.subtype(a, b) + } + } + } + } + + fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult { + match Sub(**self).tys(a, b) { + Ok(_) => Ok(None), // No coercion required. + Err(ref e) => Err(*e) + } + } + + fn unpack_actual_value(&self, + a: ty::t, + f: &fn(&ty::sty) -> CoerceResult) -> CoerceResult + { + match resolve_type(self.infcx, a, try_resolve_tvar_shallow) { + Ok(t) => { + f(&ty::get(t).sty) + } + Err(e) => { + self.infcx.tcx.sess.span_bug( + self.span, + fmt!("Failed to resolve even without \ + any force options: %?", e)); + } + } + } + + fn coerce_borrowed_pointer(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t, + mt_b: ty::mt) -> CoerceResult + { + debug!("coerce_borrowed_pointer(a=%s, sty_a=%?, b=%s, mt_b=%?)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx), mt_b); + + // If we have a parameter of type `&M T_a` and the value + // provided is `expr`, we will be adding an implicit borrow, + // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore, + // to type check, we will construct the type that `&M*expr` would + // yield. + + let sub = Sub(**self); + let r_borrow = self.infcx.next_region_var_nb(self.span); + + let inner_ty = match *sty_a { + ty::ty_box(mt_a) => mt_a.ty, + ty::ty_uniq(mt_a) => mt_a.ty, + ty::ty_rptr(_, mt_a) => mt_a.ty, + _ => { + return self.subtype(a, b); + } + }; + + let a_borrowed = ty::mk_rptr(self.infcx.tcx, + r_borrow, + mt {ty: inner_ty, mutbl: mt_b.mutbl}); + if_ok!(sub.tys(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 1, + autoref: Some(AutoRef { + kind: AutoPtr, + region: r_borrow, + mutbl: mt_b.mutbl + }) + })) + } + + fn coerce_borrowed_string(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) -> CoerceResult + { + debug!("coerce_borrowed_string(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + match *sty_a { + ty::ty_estr(vstore_box) | + ty::ty_estr(vstore_uniq) => {} + _ => { + return self.subtype(a, b); + } + }; + + let r_a = self.infcx.next_region_var_nb(self.span); + let a_borrowed = ty::mk_estr(self.infcx.tcx, vstore_slice(r_a)); + if_ok!(self.subtype(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 0, + autoref: Some(AutoRef { + kind: AutoBorrowVec, + region: r_a, + mutbl: m_imm + }) + })) + } + + fn coerce_borrowed_vector(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t, + mt_b: ty::mt) -> CoerceResult + { + debug!("coerce_borrowed_vector(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + let sub = Sub(**self); + let r_borrow = self.infcx.next_region_var_nb(self.span); + let ty_inner = match *sty_a { + ty::ty_evec(mt, _) => mt.ty, + _ => { + return self.subtype(a, b); + } + }; + + let a_borrowed = ty::mk_evec(self.infcx.tcx, + mt {ty: ty_inner, mutbl: mt_b.mutbl}, + vstore_slice(r_borrow)); + if_ok!(sub.tys(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 0, + autoref: Some(AutoRef { + kind: AutoBorrowVec, + region: r_borrow, + mutbl: mt_b.mutbl + }) + })) + } + + fn coerce_borrowed_fn(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) -> CoerceResult + { + debug!("coerce_borrowed_fn(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + let fn_ty = match *sty_a { + ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBox => {f} + ty::ty_fn(ref f) if f.meta.proto == ast::ProtoUniq => {f} + ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBare => { + return self.coerce_from_bare_fn(a, f, b); + } + _ => { + return self.subtype(a, b); + } + }; + + let r_borrow = self.infcx.next_region_var_nb(self.span); + let meta = FnMeta {proto: ast::ProtoBorrowed, + region: r_borrow, + ..fn_ty.meta}; + let a_borrowed = ty::mk_fn(self.infcx.tcx, + FnTyBase {meta: meta, + sig: copy fn_ty.sig}); + + if_ok!(self.subtype(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 0, + autoref: Some(AutoRef { + kind: AutoBorrowFn, + region: r_borrow, + mutbl: m_imm + }) + })) + } + + fn coerce_from_bare_fn(&self, + a: ty::t, + fn_ty_a: &ty::FnTy, + b: ty::t) -> CoerceResult + { + do self.unpack_actual_value(b) |sty_b| { + self.coerce_from_bare_fn_post_unpack(a, fn_ty_a, b, sty_b) + } + } + + fn coerce_from_bare_fn_post_unpack(&self, + a: ty::t, + fn_ty_a: &ty::FnTy, + b: ty::t, + sty_b: &ty::sty) -> CoerceResult + { + debug!("coerce_from_bare_fn(a=%s, b=%s)", + a.inf_str(self.infcx), b.inf_str(self.infcx)); + + let fn_ty_b = match *sty_b { + ty::ty_fn(ref f) if f.meta.proto != ast::ProtoBare => {f} + _ => { + return self.subtype(a, b); + } + }; + + // for now, bare fn and closures have the same + // representation + let a_adapted = ty::mk_fn(self.infcx.tcx, + FnTyBase {meta: copy fn_ty_b.meta, + sig: copy fn_ty_a.sig}); + self.subtype(a_adapted, b) + } + + fn coerce_unsafe_ptr(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) -> CoerceResult + { + debug!("coerce_unsafe_ptr(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + let mt_a = match *sty_a { + ty::ty_rptr(_, mt) => mt, + _ => { + return self.subtype(a, b); + } + }; + + // borrowed pointers and unsafe pointers have the same + // representation, so just check that the types which they + // point at are compatible: + let a_unsafe = ty::mk_ptr(self.infcx.tcx, mt_a); + self.subtype(a_unsafe, b) + } +} diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index c5e99bc5c0362..d1c57a21a3b2f 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -57,6 +57,7 @@ use core::prelude::*; use middle::ty::{FloatVar, FnTyBase, FnMeta, FnSig, IntVar, TyVar}; +use middle::ty::{IntType, UintType, arg, substs}; use middle::ty; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; @@ -112,8 +113,8 @@ pub struct CombineFields { } fn expected_found( - self: &C, +a: T, +b: T) -> ty::expected_found { - + self: &C, +a: T, +b: T) -> ty::expected_found +{ if self.a_is_expected() { ty::expected_found {expected: move a, found: move b} } else { @@ -232,7 +233,11 @@ fn super_substs( do relate_region_param(self, did, a.self_r, b.self_r).chain |self_r| { - Ok({self_r: self_r, self_ty: self_ty, tps: /*bad*/copy tps}) + Ok(substs { + self_r: self_r, + self_ty: self_ty, + tps: /*bad*/copy tps + }) } } } @@ -294,7 +299,7 @@ fn super_flds( if a.ident == b.ident { self.mts(a.mt, b.mt) - .chain(|mt| Ok({ident: a.ident, mt: mt}) ) + .chain(|mt| Ok(ty::field {ident: a.ident, mt: mt}) ) .chain_err(|e| Err(ty::terr_in_field(@e, a.ident)) ) } else { Err(ty::terr_record_fields( @@ -316,7 +321,7 @@ fn super_args( do self.modes(a.mode, b.mode).chain |m| { do self.contratys(a.ty, b.ty).chain |t| { - Ok({mode: m, ty: t}) + Ok(arg {mode: m, ty: t}) } } } @@ -392,7 +397,7 @@ fn super_tys( self: &C, a: ty::t, b: ty::t) -> cres { let tcx = self.infcx().tcx; - match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) { + return match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) { // The "subtype" ought to be handling cases involving bot or var: (ty::ty_bot, _) | (_, ty::ty_bot) | @@ -405,53 +410,46 @@ fn super_tys( b.inf_str(self.infcx()))); } - // Relate integral variables to other types - (ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => { - if_ok!(self.infcx().simple_vars(&self.infcx().int_var_bindings, - ty::terr_no_integral_type, - a_id, b_id)); - Ok(a) - } - (ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) | - (ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => { - if v == ast::ty_char { - Err(ty::terr_integer_as_char) - } else { - if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings, - ty::terr_no_integral_type, - v_id, IntType(v))); - Ok(ty::mk_mach_int(tcx, v)) + // Relate integral variables to other types + (ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => { + if_ok!(self.infcx().simple_vars(self.a_is_expected(), + a_id, b_id)); + Ok(a) + } + (ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) => { + unify_integral_variable(self, self.a_is_expected(), + v_id, IntType(v)) + } + (ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => { + unify_integral_variable(self, !self.a_is_expected(), + v_id, IntType(v)) + } + (ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) => { + unify_integral_variable(self, self.a_is_expected(), + v_id, UintType(v)) + } + (ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => { + unify_integral_variable(self, !self.a_is_expected(), + v_id, UintType(v)) } - } - (ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) | - (ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => { - if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings, - ty::terr_no_integral_type, - v_id, UintType(v))); - Ok(ty::mk_mach_uint(tcx, v)) - } - // Relate floating-point variables to other types - (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => { - if_ok!(self.infcx().simple_vars(&self.infcx().float_var_bindings, - ty::terr_no_floating_point_type, - a_id, b_id)); - Ok(a) - } - (ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) | - (ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => { - if_ok!(self.infcx().simple_var_t(&self.infcx().float_var_bindings, - ty::terr_no_floating_point_type, - v_id, v)); - Ok(ty::mk_mach_float(tcx, v)) - } + // Relate floating-point variables to other types + (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => { + if_ok!(self.infcx().simple_vars(self.a_is_expected(), + a_id, b_id)); + Ok(a) + } + (ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) => { + unify_float_variable(self, self.a_is_expected(), v_id, v) + } + (ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => { + unify_float_variable(self, !self.a_is_expected(), v_id, v) + } (ty::ty_int(_), _) | (ty::ty_uint(_), _) | (ty::ty_float(_), _) => { - let as_ = /*bad*/copy ty::get(a).sty; - let bs = /*bad*/copy ty::get(b).sty; - if as_ == bs { + if ty::get(a).sty == ty::get(b).sty { Ok(a) } else { Err(ty::terr_sorts(expected_found(self, a, b))) @@ -516,11 +514,9 @@ fn super_tys( } (ty::ty_rptr(a_r, a_mt), ty::ty_rptr(b_r, b_mt)) => { - do self.contraregions(a_r, b_r).chain |r| { - do self.mts(a_mt, b_mt).chain |mt| { - Ok(ty::mk_rptr(tcx, r, mt)) - } - } + let r = if_ok!(self.contraregions(a_r, b_r)); + let mt = if_ok!(self.mts(a_mt, b_mt)); + Ok(ty::mk_rptr(tcx, r, mt)) } (ty::ty_evec(a_mt, vs_a), ty::ty_evec(b_mt, vs_b)) => { @@ -565,5 +561,34 @@ fn super_tys( } _ => Err(ty::terr_sorts(expected_found(self, a, b))) + }; + + fn unify_integral_variable( + self: &C, + vid_is_expected: bool, + vid: ty::IntVid, + val: ty::IntVarValue) -> cres + { + let tcx = self.infcx().tcx; + if val == IntType(ast::ty_char) { + Err(ty::terr_integer_as_char) + } else { + if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); + match val { + IntType(v) => Ok(ty::mk_mach_int(tcx, v)), + UintType(v) => Ok(ty::mk_mach_uint(tcx, v)) + } + } + } + + fn unify_float_variable( + self: &C, + vid_is_expected: bool, + vid: ty::FloatVid, + val: ast::float_ty) -> cres + { + let tcx = self.infcx().tcx; + if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); + Ok(ty::mk_mach_float(tcx, val)) } } diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 54638819f7ccc..6ae10b120fe72 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -89,9 +89,9 @@ impl FnMeta: LatticeValue { } impl CombineFields { - fn var_sub_var( + fn var_sub_var>>( &self, - vb: &ValsAndBindings>, +a_id: V, +b_id: V) -> ures { @@ -102,8 +102,8 @@ impl CombineFields { * top of infer.rs*/ // Need to make sub_id a subtype of sup_id. - let node_a = self.infcx.get(vb, a_id); - let node_b = self.infcx.get(vb, b_id); + let node_a = self.infcx.get(a_id); + let node_b = self.infcx.get(b_id); let a_id = node_a.root; let b_id = node_b.root; let a_bounds = node_a.possible_types; @@ -135,17 +135,17 @@ impl CombineFields { // A remains a subtype of B. Actually, there are other options, // but that's the route we choose to take. - self.infcx.unify(vb, &node_a, &node_b, |new_root, new_rank| { - self.set_var_to_merged_bounds(vb, new_root, + self.infcx.unify(&node_a, &node_b, |new_root, new_rank| { + self.set_var_to_merged_bounds(new_root, &a_bounds, &b_bounds, new_rank) }) } /// make variable a subtype of T - fn var_sub_t( + fn var_sub_t>>( &self, - vb: &ValsAndBindings>, +a_id: V, +b: T) -> ures { @@ -153,7 +153,7 @@ impl CombineFields { * * Make a variable (`a_id`) a subtype of the concrete type `b` */ - let node_a = self.infcx.get(vb, a_id); + let node_a = self.infcx.get(a_id); let a_id = node_a.root; let a_bounds = &node_a.possible_types; let b_bounds = &{lb: None, ub: Some(b)}; @@ -164,12 +164,12 @@ impl CombineFields { b.inf_str(self.infcx)); self.set_var_to_merged_bounds( - vb, a_id, a_bounds, b_bounds, node_a.rank) + a_id, a_bounds, b_bounds, node_a.rank) } - fn t_sub_var( + fn t_sub_var>>( &self, - vb: &ValsAndBindings>, +a: T, +b_id: V) -> ures { @@ -178,7 +178,7 @@ impl CombineFields { * Make a concrete type (`a`) a subtype of the variable `b_id` */ let a_bounds = &{lb: Some(a), ub: None}; - let node_b = self.infcx.get(vb, b_id); + let node_b = self.infcx.get(b_id); let b_id = node_b.root; let b_bounds = &node_b.possible_types; @@ -188,7 +188,7 @@ impl CombineFields { b_bounds.inf_str(self.infcx)); self.set_var_to_merged_bounds( - vb, b_id, a_bounds, b_bounds, node_b.rank) + b_id, a_bounds, b_bounds, node_b.rank) } fn merge_bnd( @@ -219,10 +219,9 @@ impl CombineFields { } } - fn set_var_to_merged_bounds( + fn set_var_to_merged_bounds>>( &self, - vb: &ValsAndBindings>, +v_id: V, a: &Bounds, b: &Bounds, @@ -278,7 +277,7 @@ impl CombineFields { // the new bounds must themselves // be relatable: let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub)); - self.infcx.set(vb, v_id, Root(bounds, rank)); + self.infcx.set(v_id, Root(bounds, rank)); uok() } @@ -369,8 +368,7 @@ fn super_lattice_tys( (_, ty::ty_bot) => { return self.ty_bot(a); } (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { - let r = if_ok!(lattice_vars(self, &self.infcx().ty_var_bindings, - a_id, b_id, + let r = if_ok!(lattice_vars(self, a_id, b_id, |x, y| self.tys(*x, *y))); return match r { VarResult(v) => Ok(ty::mk_var(tcx, v)), @@ -379,14 +377,12 @@ fn super_lattice_tys( } (ty::ty_infer(TyVar(a_id)), _) => { - return lattice_var_and_t(self, &self.infcx().ty_var_bindings, - a_id, &b, + return lattice_var_and_t(self, a_id, &b, |x, y| self.tys(*x, *y)); } (_, ty::ty_infer(TyVar(b_id))) => { - return lattice_var_and_t(self, &self.infcx().ty_var_bindings, - b_id, &a, + return lattice_var_and_t(self, b_id, &a, |x, y| self.tys(*x, *y)); } @@ -419,17 +415,16 @@ enum LatticeVarResult { * result is a variable. This is indicated with a `VarResult` * return. */ fn lattice_vars( + T:Copy InferStr LatticeValue, + V:Copy Eq ToStr Vid UnifyVid>>( self: &L, // defines whether we want LUB or GLB - vb: &ValsAndBindings>, // relevant variable bindings +a_vid: V, // first variable +b_vid: V, // second variable lattice_dir_op: LatticeDirOp) // LUB or GLB operation on types -> cres> { - let nde_a = self.infcx().get(vb, a_vid); - let nde_b = self.infcx().get(vb, b_vid); + let nde_a = self.infcx().get(a_vid); + let nde_b = self.infcx().get(b_vid); let a_vid = nde_a.root; let b_vid = nde_b.root; let a_bounds = &nde_a.possible_types; @@ -461,22 +456,21 @@ fn lattice_vars( + T:Copy InferStr LatticeValue, + V:Copy Eq ToStr Vid UnifyVid>>( self: &L, - vb: &ValsAndBindings>, +a_id: V, b: &T, lattice_dir_op: LatticeDirOp) -> cres { - let nde_a = self.infcx().get(vb, a_id); + let nde_a = self.infcx().get(a_id); let a_id = nde_a.root; let a_bounds = &nde_a.possible_types; @@ -501,7 +495,7 @@ fn lattice_var_and_t = Option; type Bounds = {lb: Bound, ub: Bound}; @@ -349,13 +348,7 @@ type Bounds = {lb: Bound, ub: Bound}; type cres = Result; // "combine result" type ures = cres<()>; // "unify result" type fres = Result; // "fixup result" -type ares = cres>; // "assignment result" - -#[deriving_eq] -enum IntVarValue { - IntType(ast::int_ty), - UintType(ast::uint_ty), -} +type CoerceResult = cres>; struct InferCtxt { tcx: ty::ctxt, @@ -364,22 +357,14 @@ struct InferCtxt { // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. ty_var_bindings: ValsAndBindings>, - - // Number of type variables created thus far. mut ty_var_counter: uint, - // The types that might instantiate an integral type variable are - // represented by an int_ty_set. + // Map from integral variable to the kind of integer it represents int_var_bindings: ValsAndBindings>, - - // Number of integral variables created thus far. mut int_var_counter: uint, - // The types that might instantiate a floating-point type variable are - // represented by an float_ty_set. + // Map from floating variable to the kind of float it represents float_var_bindings: ValsAndBindings>, - - // Number of floating-point variables created thus far. mut float_var_counter: uint, // For region variables. @@ -471,22 +456,23 @@ fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span, }.to_ures() } -fn mk_assignty(cx: @InferCtxt, a_is_expected: bool, span: span, - a: ty::t, b: ty::t) -> ares { - debug!("mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); +fn mk_coercety(cx: @InferCtxt, a_is_expected: bool, span: span, + a: ty::t, b: ty::t) -> CoerceResult +{ + debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { - Assign(cx.combine_fields(a_is_expected, span)).tys(a, b) + Coerce(cx.combine_fields(a_is_expected, span)).tys(a, b) } } } -fn can_mk_assignty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures { - debug!("can_mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); +fn can_mk_coercety(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures { + debug!("can_mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.probe { let span = ast_util::dummy_sp(); - Assign(cx.combine_fields(true, span)).tys(a, b) + Coerce(cx.combine_fields(true, span)).tys(a, b) } }.to_ures() } @@ -582,6 +568,7 @@ fn rollback_to( struct Snapshot { ty_var_bindings_len: uint, int_var_bindings_len: uint, + float_var_bindings_len: uint, region_vars_snapshot: uint, } @@ -607,6 +594,8 @@ impl @InferCtxt { self.ty_var_bindings.bindings.len(), int_var_bindings_len: self.int_var_bindings.bindings.len(), + float_var_bindings_len: + self.float_var_bindings.bindings.len(), region_vars_snapshot: self.region_vars.start_snapshot(), } @@ -616,9 +605,11 @@ impl @InferCtxt { debug!("rollback!"); rollback_to(&self.ty_var_bindings, snapshot.ty_var_bindings_len); - // FIXME(#3211) -- int_var not transactional + // FIXME(#3211) -- int_var and float_var not transactional //rollback_to(&self.int_var_bindings, // snapshot.int_var_bindings_len); + //rollback_to(&self.float_var_bindings, + // snapshot.float_var_bindings_len); self.region_vars.rollback_to(snapshot.region_vars_snapshot); } @@ -664,6 +655,16 @@ impl @InferCtxt { } } +fn next_simple_var( + +counter: &mut uint, + +bindings: &ValsAndBindings>) -> uint +{ + let id = *counter; + *counter += 1; + bindings.vals.insert(id, Root(None, 0)); + return id; +} + impl @InferCtxt { fn next_ty_var_id() -> TyVid { let id = self.ty_var_counter; @@ -682,11 +683,8 @@ impl @InferCtxt { } fn next_int_var_id() -> IntVid { - let id = self.int_var_counter; - self.int_var_counter += 1; - - self.int_var_bindings.vals.insert(id, Root(None, 0)); - return IntVid(id); + IntVid(next_simple_var(&mut self.int_var_counter, + &self.int_var_bindings)) } fn next_int_var() -> ty::t { @@ -694,11 +692,8 @@ impl @InferCtxt { } fn next_float_var_id() -> FloatVid { - let id = self.float_var_counter; - self.float_var_counter += 1; - - self.float_var_bindings.vals.insert(id, Root(None, 0)); - return FloatVid(id); + FloatVid(next_simple_var(&mut self.float_var_counter, + &self.float_var_bindings)) } fn next_float_var() -> ty::t { diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 23be3b208271c..b25c4db8a90b7 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -49,11 +49,10 @@ use core::prelude::*; use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; -use middle::ty::{type_is_bot}; +use middle::ty::{type_is_bot, IntType, UintType}; use middle::ty; use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt}; use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty}; -use middle::typeck::infer::{IntType, UintType}; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::Root; use util::common::{indent, indenter}; @@ -79,6 +78,7 @@ const force_all: uint = 0b1111100000; const not_regions: uint = !(force_rvar | resolve_rvar); +const try_resolve_tvar_shallow: uint = 0; const resolve_and_force_all_but_regions: uint = (resolve_all | force_all) & not_regions; @@ -219,7 +219,7 @@ impl ResolveState { // tend to carry more restrictions or higher // perf. penalties, so it pays to know more. - let nde = self.infcx.get(&self.infcx.ty_var_bindings, vid); + let nde = self.infcx.get(vid); let bounds = nde.possible_types; let t1 = match bounds { @@ -243,7 +243,7 @@ impl ResolveState { return ty::mk_int_var(self.infcx.tcx, vid); } - let node = self.infcx.get(&self.infcx.int_var_bindings, vid); + let node = self.infcx.get(vid); match node.possible_types { Some(IntType(t)) => ty::mk_mach_int(self.infcx.tcx, t), Some(UintType(t)) => ty::mk_mach_uint(self.infcx.tcx, t), @@ -251,9 +251,8 @@ impl ResolveState { if self.should(force_ivar) { // As a last resort, default to int. let ty = ty::mk_int(self.infcx.tcx); - self.infcx.set( - &self.infcx.int_var_bindings, vid, - Root(Some(IntType(ast::ty_i)), node.rank)); + self.infcx.set(vid, + Root(Some(IntType(ast::ty_i)), node.rank)); ty } else { ty::mk_int_var(self.infcx.tcx, vid) @@ -267,17 +266,14 @@ impl ResolveState { return ty::mk_float_var(self.infcx.tcx, vid); } - let node = self.infcx.get(&self.infcx.float_var_bindings, vid); + let node = self.infcx.get(vid); match node.possible_types { Some(t) => ty::mk_mach_float(self.infcx.tcx, t), None => { if self.should(force_fvar) { // As a last resort, default to float. let ty = ty::mk_float(self.infcx.tcx); - self.infcx.set( - &self.infcx.float_var_bindings, - vid, - Root(Some(ast::ty_f), node.rank)); + self.infcx.set(vid, Root(Some(ast::ty_f), node.rank)); ty } else { ty::mk_float_var(self.infcx.tcx, vid) diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index aa6721fb22983..4252580ac46cd 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -102,38 +102,31 @@ impl Sub: Combine { debug!("%s.tys(%s, %s)", self.tag(), a.inf_str(self.infcx), b.inf_str(self.infcx)); if a == b { return Ok(a); } - do indent { - match (ty::get(a).sty, ty::get(b).sty) { - (ty::ty_bot, _) => { - Ok(a) - } + let _indenter = indenter(); + match (ty::get(a).sty, ty::get(b).sty) { + (ty::ty_bot, _) => { + Ok(a) + } - (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { - do self.var_sub_var(&self.infcx.ty_var_bindings, - a_id, b_id).then { - Ok(a) - } - } - (ty::ty_infer(TyVar(a_id)), _) => { - do self.var_sub_t(&self.infcx.ty_var_bindings, - a_id, b).then { - Ok(a) - } - } - (_, ty::ty_infer(TyVar(b_id))) => { - do self.t_sub_var(&self.infcx.ty_var_bindings, - a, b_id).then { - Ok(a) - } - } + (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { + if_ok!(self.var_sub_var(a_id, b_id)); + Ok(a) + } + (ty::ty_infer(TyVar(a_id)), _) => { + if_ok!(self.var_sub_t(a_id, b)); + Ok(a) + } + (_, ty::ty_infer(TyVar(b_id))) => { + if_ok!(self.t_sub_var(a, b_id)); + Ok(a) + } - (_, ty::ty_bot) => { - Err(ty::terr_sorts(expected_found(&self, a, b))) - } + (_, ty::ty_bot) => { + Err(ty::terr_sorts(expected_found(&self, a, b))) + } - _ => { - super_tys(&self, a, b) - } + _ => { + super_tys(&self, a, b) } } } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 42f516fe6d880..a6d316db42872 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -10,10 +10,10 @@ use core::prelude::*; -use middle::ty::{FnMeta, FnTyBase, FnSig, FnVid, Vid}; +use middle::ty::{FnMeta, FnTyBase, FnSig, Vid}; +use middle::ty::{IntVarValue, IntType, UintType}; use middle::ty; use middle::typeck::infer::{Bound, Bounds}; -use middle::typeck::infer::{IntVarValue, IntType, UintType}; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::unify::{Redirect, Root, VarValue}; use util::ppaux::{mt_to_str, ty_to_str}; @@ -25,23 +25,23 @@ use core::uint; use core::str; pub trait InferStr { - fn inf_str(cx: @InferCtxt) -> ~str; + fn inf_str(&self, cx: &InferCtxt) -> ~str; } impl ty::t : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - ty_to_str(cx.tcx, self) + fn inf_str(&self, cx: &InferCtxt) -> ~str { + ty_to_str(cx.tcx, *self) } } impl FnMeta : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - fmt!("%?", self) + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + fmt!("%?", *self) } } impl FnSig : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { + fn inf_str(&self, cx: &InferCtxt) -> ~str { fmt!("(%s) -> %s", str::connect(self.inputs.map(|a| a.ty.inf_str(cx)), ", "), self.output.inf_str(cx)) @@ -49,26 +49,26 @@ impl FnSig : InferStr { } impl FnTyBase : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { + fn inf_str(&self, cx: &InferCtxt) -> ~str { fmt!("%s%s", self.meta.inf_str(cx), self.sig.inf_str(cx)) } } impl ty::mt : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - mt_to_str(cx.tcx, self) + fn inf_str(&self, cx: &InferCtxt) -> ~str { + mt_to_str(cx.tcx, *self) } } impl ty::Region : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - fmt!("%?", self) + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + fmt!("%?", *self) } } impl Bound : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - match self { + fn inf_str(&self, cx: &InferCtxt) -> ~str { + match *self { Some(ref v) => v.inf_str(cx), None => ~"none" } @@ -76,7 +76,7 @@ impl Bound : InferStr { } impl Bounds : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { + fn inf_str(&self, cx: &InferCtxt) -> ~str { fmt!("{%s <: %s}", self.lb.inf_str(cx), self.ub.inf_str(cx)) @@ -84,8 +84,8 @@ impl Bounds : InferStr { } impl VarValue : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - match self { + fn inf_str(&self, cx: &InferCtxt) -> ~str { + match *self { Redirect(ref vid) => fmt!("Redirect(%s)", vid.to_str()), Root(ref pt, rk) => fmt!("Root(%s, %s)", pt.inf_str(cx), uint::to_str(rk, 10u)) @@ -94,17 +94,13 @@ impl VarValue : InferStr { } impl IntVarValue : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - match self { - IntType(t) => ast_util::int_ty_to_str(t), - UintType(t) => ast_util::uint_ty_to_str(t) - } + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + self.to_str() } } impl ast::float_ty : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - ast_util::float_ty_to_str(self) + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + self.to_str() } } - diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 77bd46eea2dfd..b2b1188388f45 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -9,39 +9,43 @@ // except according to those terms. use core::prelude::*; +use core::result; +use std::smallintmap::SmallIntMap; -use middle::ty::Vid; +use middle::ty::{Vid, expected_found, IntVarValue}; use middle::ty; use middle::typeck::infer::{Bound, Bounds, cres, uok, ures}; use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::to_str::InferStr; +use syntax::ast; use util::common::{indent, indenter}; -use core::result; -use std::smallintmap::SmallIntMap; - enum VarValue { Redirect(V), Root(T, uint), } -struct ValsAndBindings { +struct ValsAndBindings { vals: SmallIntMap>, mut bindings: ~[(V, VarValue)], } -struct Node { +struct Node { root: V, possible_types: T, rank: uint, } -impl @InferCtxt { - fn get( - vb: &ValsAndBindings, - vid: V) - -> Node +trait UnifyVid { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings; +} + +impl InferCtxt { + fn get>( + &self, + +vid: V) -> Node { /*! * @@ -50,6 +54,7 @@ impl @InferCtxt { * http://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + let vb = UnifyVid::appropriate_vals_and_bindings(self); let vid_u = vid.to_uint(); match vb.vals.find(vid_u) { None => { @@ -57,9 +62,9 @@ impl @InferCtxt { } Some(ref var_val) => { match (*var_val) { - Redirect(ref vid) => { - let node = self.get(vb, (*vid)); - if node.root.ne(vid) { + Redirect(vid) => { + let node: Node = self.get(vid); + if node.root != vid { // Path compression vb.vals.insert(vid.to_uint(), Redirect(node.root)); } @@ -73,9 +78,9 @@ impl @InferCtxt { } } - fn set( - vb: &ValsAndBindings, - vid: V, + fn set>( + &self, + +vid: V, +new_v: VarValue) { /*! @@ -83,6 +88,7 @@ impl @InferCtxt { * Sets the value for `vid` to `new_v`. `vid` MUST be a root node! */ + let vb = UnifyVid::appropriate_vals_and_bindings(self); let old_v = vb.vals.get(vid.to_uint()); vb.bindings.push((vid, old_v)); vb.vals.insert(vid.to_uint(), new_v); @@ -91,8 +97,8 @@ impl @InferCtxt { vid.to_str(), old_v.inf_str(self), new_v.inf_str(self)); } - fn unify( - vb: &ValsAndBindings, + fn unify, R>( + &self, node_a: &Node, node_b: &Node, op: &fn(new_root: V, new_rank: uint) -> R @@ -108,17 +114,17 @@ impl @InferCtxt { if node_a.rank > node_b.rank { // a has greater rank, so a should become b's parent, // i.e., b should redirect to a. - self.set(vb, node_b.root, Redirect(node_a.root)); + self.set(node_b.root, Redirect(node_a.root)); op(node_a.root, node_a.rank) } else if node_a.rank < node_b.rank { // b has greater rank, so a should redirect to b. - self.set(vb, node_a.root, Redirect(node_b.root)); + self.set(node_a.root, Redirect(node_b.root)); op(node_b.root, node_b.rank) } else { // If equal, redirect one to the other and increment the // other's rank. assert node_a.rank == node_b.rank; - self.set(vb, node_b.root, Redirect(node_a.root)); + self.set(node_b.root, Redirect(node_a.root)); op(node_a.root, node_a.rank + 1) } } @@ -129,12 +135,30 @@ impl @InferCtxt { // Code to handle simple variables like ints, floats---anything that // doesn't have a subtyping relationship we need to worry about. -impl @InferCtxt { - fn simple_vars( - vb: &ValsAndBindings>, - err: ty::type_err, - a_id: V, - b_id: V) -> ures +trait SimplyUnifiable { + static fn to_type_err(expected_found) -> ty::type_err; +} + +fn mk_err(+a_is_expected: bool, + +a_t: T, + +b_t: T) -> ures +{ + if a_is_expected { + Err(SimplyUnifiable::to_type_err( + ty::expected_found {expected: a_t, found: b_t})) + } else { + Err(SimplyUnifiable::to_type_err( + ty::expected_found {expected: b_t, found: a_t})) + } +} + +impl InferCtxt { + fn simple_vars>>( + &self, + +a_is_expected: bool, + +a_id: V, + +b_id: V) -> ures { /*! * @@ -143,8 +167,8 @@ impl @InferCtxt { * have already been associated with a value, then those two * values must be the same. */ - let node_a = self.get(vb, a_id); - let node_b = self.get(vb, b_id); + let node_a = self.get(a_id); + let node_b = self.get(b_id); let a_id = node_a.root; let b_id = node_b.root; @@ -155,22 +179,24 @@ impl @InferCtxt { (&None, &None) => None, (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(*v), (&Some(ref v1), &Some(ref v2)) => { - if *v1 != *v2 { return Err(err); } + if *v1 != *v2 { + return mk_err(a_is_expected, *v1, *v2); + } Some(*v1) } }; - self.unify(vb, &node_a, &node_b, |new_root, new_rank| { - self.set(vb, new_root, Root(combined, new_rank)); + self.unify(&node_a, &node_b, |new_root, new_rank| { + self.set(new_root, Root(combined, new_rank)); }); return uok(); } - fn simple_var_t( - vb: &ValsAndBindings>, - err: ty::type_err, - a_id: V, - b: T) -> ures + fn simple_var_t>>( + +a_is_expected: bool, + +a_id: V, + +b: T) -> ures { /*! * @@ -179,19 +205,66 @@ impl @InferCtxt { * if `a_id` already has a value, it must be the same as * `b`. */ - let node_a = self.get(vb, a_id); + let node_a = self.get(a_id); let a_id = node_a.root; - if node_a.possible_types.is_none() { - self.set(vb, a_id, Root(Some(b), node_a.rank)); - return uok(); - } + match node_a.possible_types { + None => { + self.set(a_id, Root(Some(b), node_a.rank)); + return uok(); + } - if node_a.possible_types == Some(b) { - return uok(); + Some(ref a_t) => { + if *a_t == b { + return uok(); + } else { + return mk_err(a_is_expected, *a_t, b); + } + } } + } +} - return Err(err); +// ______________________________________________________________________ + +impl ty::TyVid : UnifyVid> { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings> + { + return &infcx.ty_var_bindings; + } +} + +impl ty::IntVid : UnifyVid> { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings> + { + return &infcx.int_var_bindings; + } +} + +impl IntVarValue : SimplyUnifiable { + static fn to_type_err(err: expected_found) + -> ty::type_err + { + return ty::terr_int_mismatch(err); } } +impl ty::FloatVid : UnifyVid> { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings> + { + return &infcx.float_var_bindings; + } +} + +impl ast::float_ty : SimplyUnifiable { + static fn to_type_err(err: expected_found) + -> ty::type_err + { + return ty::terr_float_mismatch(err); + } +} + + diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 818c6eb04ea88..4ebd0b33f038a 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -25,6 +25,7 @@ #[allow(non_camel_case_types)]; #[allow(deprecated_mode)]; #[warn(deprecated_pattern)]; +#[allow(deprecated_self)]; #[no_core]; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6b6912915fd25..fb9e0f36c2f25 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -17,7 +17,7 @@ use middle::ty::{bound_copy, bound_const, bound_durable, bound_owned, use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid, br_fresh}; use middle::ty::{ctxt, field, method}; -use middle::ty::{mt, t, param_bound}; +use middle::ty::{mt, t, param_bound, param_ty}; use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum}; @@ -270,6 +270,12 @@ fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str { pprust::expr_to_str(expr, cx.sess.intr())) } +fn pat_repr(cx: ctxt, pat: @ast::pat) -> ~str { + fmt!("pat(%d: %s)", + pat.id, + pprust::pat_to_str(pat, cx.sess.intr())) +} + fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { let tstrs = ts.map(|t| ty_to_str(cx, *t)); fmt!("(%s)", str::connect(tstrs, ", ")) @@ -286,9 +292,8 @@ fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { } 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; + fn fn_input_to_str(cx: ctxt, input: ty::arg) -> ~str { + let ty::arg {mode: mode, ty: ty} = input; let modestr = match canon_mode(cx, mode) { ast::infer(_) => ~"", ast::expl(m) => { @@ -417,7 +422,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str { } ty_infer(infer_ty) => infer_ty.to_str(), ty_err => ~"[type error]", - ty_param({idx: id, _}) => { + ty_param(param_ty {idx: id, _}) => { ~"'" + str::from_bytes(~[('a' as u8) + (id as u8)]) } ty_self => ~"self", diff --git a/src/librustdoc/astsrv.rs b/src/librustdoc/astsrv.rs index 99cf301f18248..bc332615eaa0e 100644 --- a/src/librustdoc/astsrv.rs +++ b/src/librustdoc/astsrv.rs @@ -155,9 +155,9 @@ fn build_error_handlers( codemap: @codemap::CodeMap ) -> ErrorHandlers { - type DiagnosticHandler = { + struct DiagnosticHandler { inner: diagnostic::handler, - }; + } impl DiagnosticHandler: diagnostic::handler { fn fatal(msg: &str) -> ! { self.inner.fatal(msg) } @@ -182,7 +182,7 @@ fn build_error_handlers( diagnostic::emit(cmsp, msg, lvl); }; let inner_handler = diagnostic::mk_handler(Some(emitter)); - let handler = { + let handler = DiagnosticHandler { inner: inner_handler, }; let span_handler = diagnostic::mk_span_handler( diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index 1ab3ce2d6f368..39a893a4076cb 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -69,9 +69,9 @@ fn fold_crate( attr_parser::parse_crate(attrs) }; - { - topmod: doc::ModDoc_({ - item: { + doc::CrateDoc { + topmod: doc::ModDoc_(doc::ModDoc_ { + item: doc::ItemDoc { name: option::get_or_default(attrs.name, doc.topmod.name()), .. doc.topmod.item }, @@ -103,7 +103,7 @@ fn fold_item( parse_item_attrs(srv, doc.id, attr_parser::parse_desc) }; - { + doc::ItemDoc { desc: desc, .. doc } @@ -162,7 +162,7 @@ fn fold_enum( let doc_id = doc.id(); let doc = fold::default_seq_fold_enum(fold, doc); - { + doc::EnumDoc { variants: do par::map(doc.variants) |variant| { let variant = *variant; let desc = do astsrv::exec(srv) |ctxt| { @@ -182,7 +182,7 @@ fn fold_enum( } }; - { + doc::VariantDoc { desc: desc, .. variant } @@ -211,7 +211,7 @@ fn fold_trait( let srv = fold.ctxt; let doc = fold::default_seq_fold_trait(fold, doc); - { + doc::TraitDoc { methods: merge_method_attrs(srv, doc.id(), doc.methods), .. doc } @@ -256,7 +256,7 @@ fn merge_method_attrs( assert doc.name == attrs.first(); let desc = attrs.second(); - { + doc::MethodDoc { desc: desc, ..*doc } @@ -287,7 +287,7 @@ fn fold_impl( let srv = fold.ctxt; let doc = fold::default_seq_fold_impl(fold, doc); - { + doc::ImplDoc { methods: merge_method_attrs(srv, doc.id(), doc.methods), .. doc } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ebd5c047df372..0ad048d49bb4c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -50,13 +50,13 @@ impl OutputStyle : cmp::Eq { } /// The configuration for a rustdoc session -pub type Config = { +pub struct Config { input_crate: Path, output_dir: Path, output_format: OutputFormat, output_style: OutputStyle, pandoc_cmd: Option<~str> -}; +} pub impl Config: Clone { fn clone(&self) -> Config { copy *self } @@ -95,7 +95,7 @@ pub fn usage() { } pub fn default_config(input_crate: &Path) -> Config { - { + Config { input_crate: *input_crate, output_dir: Path("."), output_format: PandocHtml, @@ -155,7 +155,7 @@ fn config_from_opts( let result = do result::chain(result) |config| { let output_dir = getopts::opt_maybe_str(matches, opt_output_dir()); let output_dir = output_dir.map(|s| Path(*s)); - result::Ok({ + result::Ok(Config { output_dir: output_dir.get_or_default(config.output_dir), .. config }) @@ -168,7 +168,7 @@ fn config_from_opts( do result::chain(parse_output_format(*output_format)) |output_format| { - result::Ok({ + result::Ok(Config { output_format: output_format, .. config }) @@ -182,7 +182,7 @@ fn config_from_opts( |output_style| { do result::chain(parse_output_style(*output_style)) |output_style| { - result::Ok({ + result::Ok(Config { output_style: output_style, .. config }) @@ -195,7 +195,7 @@ fn config_from_opts( let pandoc_cmd = maybe_find_pandoc( &config, pandoc_cmd, move program_output.take()); do result::chain(pandoc_cmd) |pandoc_cmd| { - result::Ok({ + result::Ok(Config { pandoc_cmd: pandoc_cmd, .. config }) diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index f53e0058b63be..93f4be10a5c36 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -51,7 +51,7 @@ pub fn run( fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { let doc = fold::default_seq_fold_item(fold, doc); - { + doc::ItemDoc { brief: extract(doc.desc), .. doc } @@ -60,8 +60,8 @@ fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { let doc =fold::default_seq_fold_trait(fold, doc); - { - methods: par::map(doc.methods, |doc| { + doc::TraitDoc { + methods: par::map(doc.methods, |doc| doc::MethodDoc { brief: extract(doc.desc), .. *doc }), @@ -72,8 +72,8 @@ fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { fn fold_impl(fold: &fold::Fold<()>, +doc: doc::ImplDoc) -> doc::ImplDoc { let doc =fold::default_seq_fold_impl(fold, doc); - { - methods: par::map(doc.methods, |doc| { + doc::ImplDoc { + methods: par::map(doc.methods, |doc| doc::MethodDoc { brief: extract(doc.desc), .. *doc }), diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs index 18742720b90c9..247694fb26a50 100644 --- a/src/librustdoc/doc.rs +++ b/src/librustdoc/doc.rs @@ -21,94 +21,47 @@ use core::vec; pub type AstId = int; -pub type Doc_ = { +#[deriving_eq] +pub struct Doc_ { pages: ~[Page] -}; - -impl Doc_ : cmp::Eq { - pure fn eq(&self, other: &Doc_) -> bool { - (*self).pages == (*other).pages - } - pure fn ne(&self, other: &Doc_) -> bool { !(*self).eq(other) } } +#[deriving_eq] pub enum Doc { Doc_(Doc_) } -impl Doc : cmp::Eq { - pure fn eq(&self, other: &Doc) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &Doc) -> bool { *(*self) != *(*other) } -} - +#[deriving_eq] pub enum Page { CratePage(CrateDoc), ItemPage(ItemTag) } -impl Page : cmp::Eq { - pure fn eq(&self, other: &Page) -> bool { - match (*self) { - CratePage(e0a) => { - match (*other) { - CratePage(e0b) => e0a == e0b, - _ => false - } - } - ItemPage(e0a) => { - match (*other) { - ItemPage(e0b) => e0a == e0b, - _ => false - } - } - } - } - pure fn ne(&self, other: &Page) -> bool { !(*self).eq(other) } -} - +#[deriving_eq] pub enum Implementation { Required, Provided, } -impl Implementation : cmp::Eq { - pure fn eq(&self, other: &Implementation) -> bool { - ((*self) as uint) == ((*other) as uint) - } - pure fn ne(&self, other: &Implementation) -> bool { !(*self).eq(other) } -} - - /** * Most rustdocs can be parsed into 'sections' according to their markdown * headers */ -pub type Section = { +#[deriving_eq] +pub struct Section { header: ~str, body: ~str -}; - -impl Section : cmp::Eq { - pure fn eq(&self, other: &Section) -> bool { - (*self).header == (*other).header && (*self).body == (*other).body - } - pure fn ne(&self, other: &Section) -> bool { !(*self).eq(other) } } // FIXME (#2596): We currently give topmod the name of the crate. There // would probably be fewer special cases if the crate had its own name // and topmod's name was the empty string. -pub type CrateDoc = { - topmod: ModDoc, -}; - -impl CrateDoc : cmp::Eq { - pure fn eq(&self, other: &CrateDoc) -> bool { - (*self).topmod == (*other).topmod - } - pure fn ne(&self, other: &CrateDoc) -> bool { !(*self).eq(other) } +#[deriving_eq] +pub struct CrateDoc { + topmod: ModDoc } +#[deriving_eq] pub enum ItemTag { ModTag(ModDoc), NmodTag(NmodDoc), @@ -121,69 +74,8 @@ pub enum ItemTag { StructTag(StructDoc) } -impl ItemTag : cmp::Eq { - pure fn eq(&self, other: &ItemTag) -> bool { - match (*self) { - ModTag(e0a) => { - match (*other) { - ModTag(e0b) => e0a == e0b, - _ => false - } - } - NmodTag(e0a) => { - match (*other) { - NmodTag(e0b) => e0a == e0b, - _ => false - } - } - ConstTag(e0a) => { - match (*other) { - ConstTag(e0b) => e0a == e0b, - _ => false - } - } - FnTag(e0a) => { - match (*other) { - FnTag(e0b) => e0a == e0b, - _ => false - } - } - EnumTag(e0a) => { - match (*other) { - EnumTag(e0b) => e0a == e0b, - _ => false - } - } - TraitTag(e0a) => { - match (*other) { - TraitTag(e0b) => e0a == e0b, - _ => false - } - } - ImplTag(e0a) => { - match (*other) { - ImplTag(e0b) => e0a == e0b, - _ => false - } - } - TyTag(e0a) => { - match (*other) { - TyTag(e0b) => e0a == e0b, - _ => false - } - } - StructTag(e0a) => { - match (*other) { - StructTag(e0b) => e0a == e0b, - _ => false - } - } - } - } - pure fn ne(&self, other: &ItemTag) -> bool { !(*self).eq(other) } -} - -pub type ItemDoc = { +#[deriving_eq] +pub struct ItemDoc { id: AstId, name: ~str, path: ~[~str], @@ -192,179 +84,86 @@ pub type ItemDoc = { sections: ~[Section], // Indicates that this node is a reexport of a different item reexport: bool -}; - -impl ItemDoc : cmp::Eq { - pure fn eq(&self, other: &ItemDoc) -> bool { - (*self).id == (*other).id && - (*self).name == (*other).name && - (*self).path == (*other).path && - (*self).brief == (*other).brief && - (*self).desc == (*other).desc && - (*self).sections == (*other).sections && - (*self).reexport == (*other).reexport - } - pure fn ne(&self, other: &ItemDoc) -> bool { !(*self).eq(other) } } -pub type SimpleItemDoc = { +#[deriving_eq] +pub struct SimpleItemDoc { item: ItemDoc, sig: Option<~str> -}; - -impl SimpleItemDoc : cmp::Eq { - pure fn eq(&self, other: &SimpleItemDoc) -> bool { - (*self).item == (*other).item && (*self).sig == (*other).sig - } - pure fn ne(&self, other: &SimpleItemDoc) -> bool { !(*self).eq(other) } } -pub type ModDoc_ = { +#[deriving_eq] +pub struct ModDoc_ { item: ItemDoc, items: ~[ItemTag], index: Option -}; - -impl ModDoc_ : cmp::Eq { - pure fn eq(&self, other: &ModDoc_) -> bool { - (*self).item == (*other).item && - (*self).items == (*other).items && - (*self).index == (*other).index - } - pure fn ne(&self, other: &ModDoc_) -> bool { !(*self).eq(other) } } +#[deriving_eq] pub enum ModDoc { ModDoc_(ModDoc_) } -impl ModDoc : cmp::Eq { - pure fn eq(&self, other: &ModDoc) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &ModDoc) -> bool { *(*self) != *(*other) } -} - -pub type NmodDoc = { +#[deriving_eq] +pub struct NmodDoc { item: ItemDoc, fns: ~[FnDoc], index: Option -}; - -impl NmodDoc : cmp::Eq { - pure fn eq(&self, other: &NmodDoc) -> bool { - (*self).item == (*other).item && - (*self).fns == (*other).fns && - (*self).index == (*other).index - } - pure fn ne(&self, other: &NmodDoc) -> bool { !(*self).eq(other) } } pub type ConstDoc = SimpleItemDoc; pub type FnDoc = SimpleItemDoc; -pub type EnumDoc = { +#[deriving_eq] +pub struct EnumDoc { item: ItemDoc, variants: ~[VariantDoc] -}; - -impl EnumDoc : cmp::Eq { - pure fn eq(&self, other: &EnumDoc) -> bool { - (*self).item == (*other).item && (*self).variants == (*other).variants - } - pure fn ne(&self, other: &EnumDoc) -> bool { !(*self).eq(other) } } -pub type VariantDoc = { +#[deriving_eq] +pub struct VariantDoc { name: ~str, desc: Option<~str>, sig: Option<~str> -}; - -impl VariantDoc : cmp::Eq { - pure fn eq(&self, other: &VariantDoc) -> bool { - (*self).name == (*other).name && - (*self).desc == (*other).desc && - (*self).sig == (*other).sig - } - pure fn ne(&self, other: &VariantDoc) -> bool { !(*self).eq(other) } } -pub type TraitDoc = { +#[deriving_eq] +pub struct TraitDoc { item: ItemDoc, methods: ~[MethodDoc] -}; - -impl TraitDoc : cmp::Eq { - pure fn eq(&self, other: &TraitDoc) -> bool { - (*self).item == (*other).item && (*self).methods == (*other).methods - } - pure fn ne(&self, other: &TraitDoc) -> bool { !(*self).eq(other) } } -pub type MethodDoc = { +#[deriving_eq] +pub struct MethodDoc { name: ~str, brief: Option<~str>, desc: Option<~str>, sections: ~[Section], sig: Option<~str>, implementation: Implementation, -}; - -impl MethodDoc : cmp::Eq { - pure fn eq(&self, other: &MethodDoc) -> bool { - (*self).name == (*other).name && - (*self).brief == (*other).brief && - (*self).desc == (*other).desc && - (*self).sections == (*other).sections && - (*self).sig == (*other).sig && - (*self).implementation == (*other).implementation - } - pure fn ne(&self, other: &MethodDoc) -> bool { !(*self).eq(other) } } -pub type ImplDoc = { +#[deriving_eq] +pub struct ImplDoc { item: ItemDoc, trait_types: ~[~str], self_ty: Option<~str>, methods: ~[MethodDoc] -}; - -impl ImplDoc : cmp::Eq { - pure fn eq(&self, other: &ImplDoc) -> bool { - (*self).item == (*other).item && - (*self).trait_types == (*other).trait_types && - (*self).self_ty == (*other).self_ty && - (*self).methods == (*other).methods - } - pure fn ne(&self, other: &ImplDoc) -> bool { !(*self).eq(other) } } pub type TyDoc = SimpleItemDoc; -pub type StructDoc = { +#[deriving_eq] +pub struct StructDoc { item: ItemDoc, fields: ~[~str], sig: Option<~str> -}; - -impl StructDoc : cmp::Eq { - pure fn eq(&self, other: &StructDoc) -> bool { - return (*self).item == other.item - && (*self).fields == other.fields - && (*self).sig == other.sig; - } - pure fn ne(&self, other: &StructDoc) -> bool { !(*self).eq(other) } } -pub type Index = { +#[deriving_eq] +pub struct Index { entries: ~[IndexEntry] -}; - -impl Index : cmp::Eq { - pure fn eq(&self, other: &Index) -> bool { - (*self).entries == (*other).entries - } - pure fn ne(&self, other: &Index) -> bool { !(*self).eq(other) } } /** @@ -377,21 +176,12 @@ impl Index : cmp::Eq { * * brief - The brief description * * link - A format-specific string representing the link target */ -pub type IndexEntry = { +#[deriving_eq] +pub struct IndexEntry { kind: ~str, name: ~str, brief: Option<~str>, link: ~str -}; - -impl IndexEntry : cmp::Eq { - pure fn eq(&self, other: &IndexEntry) -> bool { - (*self).kind == (*other).kind && - (*self).name == (*other).name && - (*self).brief == (*other).brief && - (*self).link == (*other).link - } - pure fn ne(&self, other: &IndexEntry) -> bool { !(*self).eq(other) } } impl Doc { @@ -411,7 +201,6 @@ impl Doc { /// Some helper methods on ModDoc, mostly for testing impl ModDoc { - fn mods() -> ~[ModDoc] { do vec::filter_map(self.items) |itemtag| { match *itemtag { diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index 444949cfb7f0c..93226cb5ed8c8 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -57,9 +57,9 @@ pub fn extract( crate: @ast::crate, +default_name: ~str ) -> doc::Doc { - doc::Doc_({ + doc::Doc_(doc::Doc_ { pages: ~[ - doc::CratePage({ + doc::CratePage(doc::CrateDoc { topmod: top_moddoc_from_crate(crate, default_name), }) ] @@ -75,7 +75,7 @@ fn top_moddoc_from_crate( } fn mk_itemdoc(id: ast::node_id, +name: ~str) -> doc::ItemDoc { - { + doc::ItemDoc { id: id, name: name, path: ~[], @@ -90,7 +90,7 @@ fn moddoc_from_mod( +itemdoc: doc::ItemDoc, module_: ast::_mod ) -> doc::ModDoc { - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: itemdoc, items: do vec::filter_map(module_.items) |item| { let ItemDoc = mk_itemdoc(item.id, to_str(item.ident)); @@ -161,7 +161,7 @@ fn nmoddoc_from_mod( ast::foreign_item_const(*) => {} // XXX: Not implemented. } } - { + doc:: NmodDoc { item: itemdoc, fns: fns, index: None @@ -169,14 +169,14 @@ fn nmoddoc_from_mod( } fn fndoc_from_fn(+itemdoc: doc::ItemDoc) -> doc::FnDoc { - { + doc::SimpleItemDoc { item: itemdoc, sig: None } } fn constdoc_from_const(+itemdoc: doc::ItemDoc) -> doc::ConstDoc { - { + doc::SimpleItemDoc { item: itemdoc, sig: None } @@ -193,7 +193,7 @@ fn enumdoc_from_enum( +itemdoc: doc::ItemDoc, +variants: ~[ast::variant] ) -> doc::EnumDoc { - { + doc::EnumDoc { item: itemdoc, variants: variantdocs_from_variants(variants) } @@ -206,8 +206,7 @@ fn variantdocs_from_variants( } fn variantdoc_from_variant(variant: &ast::variant) -> doc::VariantDoc { - - { + doc::VariantDoc { name: to_str(variant.node.name), desc: None, sig: None @@ -231,12 +230,12 @@ fn traitdoc_from_trait( +itemdoc: doc::ItemDoc, +methods: ~[ast::trait_method] ) -> doc::TraitDoc { - { + doc::TraitDoc { item: itemdoc, methods: do vec::map(methods) |method| { match *method { ast::required(ty_m) => { - { + doc::MethodDoc { name: to_str(ty_m.ident), brief: None, desc: None, @@ -246,7 +245,7 @@ fn traitdoc_from_trait( } } ast::provided(m) => { - { + doc::MethodDoc { name: to_str(m.ident), brief: None, desc: None, @@ -276,12 +275,12 @@ fn impldoc_from_impl( +itemdoc: doc::ItemDoc, methods: ~[@ast::method] ) -> doc::ImplDoc { - { + doc::ImplDoc { item: itemdoc, trait_types: ~[], self_ty: None, methods: do vec::map(methods) |method| { - { + doc::MethodDoc { name: to_str(method.ident), brief: None, desc: None, @@ -302,7 +301,7 @@ fn should_extract_impl_methods() { fn tydoc_from_ty( +itemdoc: doc::ItemDoc ) -> doc::TyDoc { - { + doc::SimpleItemDoc { item: itemdoc, sig: None } @@ -318,7 +317,7 @@ fn structdoc_from_struct( +itemdoc: doc::ItemDoc, struct_def: @ast::struct_def ) -> doc::StructDoc { - { + doc::StructDoc { item: itemdoc, fields: do struct_def.fields.map |field| { match field.node.kind { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 29c53e0af2555..f352ed7f7e7c3 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -158,7 +158,7 @@ pub fn default_par_fold(+ctxt: T) -> Fold { } pub fn default_seq_fold_doc(fold: &Fold, +doc: doc::Doc) -> doc::Doc { - doc::Doc_({ + doc::Doc_(doc::Doc_ { pages: do vec::map(doc.pages) |page| { match *page { doc::CratePage(doc) => { @@ -177,7 +177,7 @@ pub fn default_seq_fold_crate( fold: &Fold, +doc: doc::CrateDoc ) -> doc::CrateDoc { - { + doc::CrateDoc { topmod: (fold.fold_mod)(fold, doc.topmod) } } @@ -194,7 +194,7 @@ pub fn default_any_fold_mod( +doc: doc::ModDoc ) -> doc::ModDoc { let fold_copy = fold.clone(); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), items: par::map(doc.items, |ItemTag, move fold_copy| { fold_ItemTag(&fold_copy, *ItemTag) @@ -207,7 +207,7 @@ pub fn default_seq_fold_mod( fold: &Fold, +doc: doc::ModDoc ) -> doc::ModDoc { - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), items: vec::map(doc.items, |ItemTag| { fold_ItemTag(fold, *ItemTag) @@ -221,7 +221,7 @@ pub fn default_par_fold_mod( +doc: doc::ModDoc ) -> doc::ModDoc { let fold_copy = fold.clone(); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), items: par::map(doc.items, |ItemTag, move fold_copy| { fold_ItemTag(&fold_copy, *ItemTag) @@ -235,7 +235,7 @@ pub fn default_any_fold_nmod( +doc: doc::NmodDoc ) -> doc::NmodDoc { let fold_copy = fold.clone(); - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), fns: par::map(doc.fns, |FnDoc, move fold_copy| { (fold_copy.fold_fn)(&fold_copy, *FnDoc) @@ -248,7 +248,7 @@ pub fn default_seq_fold_nmod( fold: &Fold, +doc: doc::NmodDoc ) -> doc::NmodDoc { - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), fns: vec::map(doc.fns, |FnDoc| { (fold.fold_fn)(fold, *FnDoc) @@ -262,7 +262,7 @@ pub fn default_par_fold_nmod( +doc: doc::NmodDoc ) -> doc::NmodDoc { let fold_copy = fold.clone(); - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), fns: par::map(doc.fns, |FnDoc, move fold_copy| { (fold_copy.fold_fn)(&fold_copy, *FnDoc) @@ -307,7 +307,7 @@ pub fn default_seq_fold_fn( fold: &Fold, +doc: doc::FnDoc ) -> doc::FnDoc { - { + doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -317,7 +317,7 @@ pub fn default_seq_fold_const( fold: &Fold, +doc: doc::ConstDoc ) -> doc::ConstDoc { - { + doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -327,7 +327,7 @@ pub fn default_seq_fold_enum( fold: &Fold, +doc: doc::EnumDoc ) -> doc::EnumDoc { - { + doc::EnumDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -337,7 +337,7 @@ pub fn default_seq_fold_trait( fold: &Fold, +doc: doc::TraitDoc ) -> doc::TraitDoc { - { + doc::TraitDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -347,7 +347,7 @@ pub fn default_seq_fold_impl( fold: &Fold, +doc: doc::ImplDoc ) -> doc::ImplDoc { - { + doc::ImplDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -357,7 +357,7 @@ pub fn default_seq_fold_type( fold: &Fold, +doc: doc::TyDoc ) -> doc::TyDoc { - { + doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -367,7 +367,7 @@ pub fn default_seq_fold_struct( fold: &Fold, +doc: doc::StructDoc ) -> doc::StructDoc { - { + doc::StructDoc { item: (fold.fold_item)(fold, doc.item), .. doc } diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs index 1f4e1be62fc3b..b0b4278a91e0a 100644 --- a/src/librustdoc/markdown_index_pass.rs +++ b/src/librustdoc/markdown_index_pass.rs @@ -54,7 +54,7 @@ fn fold_mod( let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { index: Some(build_mod_index(doc, fold.ctxt)), .. *doc }) @@ -67,7 +67,7 @@ fn fold_nmod( let doc = fold::default_any_fold_nmod(fold, doc); - { + doc::NmodDoc { index: Some(build_nmod_index(doc, fold.ctxt)), .. doc } @@ -77,7 +77,7 @@ fn build_mod_index( +doc: doc::ModDoc, +config: config::Config ) -> doc::Index { - { + doc::Index { entries: par::map(doc.items, |doc| { item_to_entry(*doc, config) }) @@ -88,7 +88,7 @@ fn build_nmod_index( +doc: doc::NmodDoc, +config: config::Config ) -> doc::Index { - { + doc::Index { entries: par::map(doc.fns, |doc| { item_to_entry(doc::FnTag(*doc), config) }) @@ -109,7 +109,7 @@ fn item_to_entry( } }; - { + doc::IndexEntry { kind: markdown_pass::header_kind(doc), name: markdown_pass::header_name(doc), brief: doc.brief(), diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs index 2629d45635e0b..d121d7e847893 100644 --- a/src/librustdoc/page_pass.rs +++ b/src/librustdoc/page_pass.rs @@ -76,7 +76,7 @@ fn make_doc_from_pages(page_port: PagePort) -> doc::Doc { break; } } - doc::Doc_({ + doc::Doc_(doc::Doc_ { pages: pages }) } @@ -100,7 +100,7 @@ fn fold_crate( let doc = fold::default_seq_fold_crate(fold, doc); - let page = doc::CratePage({ + let page = doc::CratePage(doc::CrateDoc { topmod: strip_mod(doc.topmod), .. doc }); @@ -128,7 +128,7 @@ fn fold_mod( } fn strip_mod(doc: doc::ModDoc) -> doc::ModDoc { - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: do doc.items.filtered |item| { match *item { doc::ModTag(_) => false, diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs index 48ed187877126..bc69ea7ed5a8d 100644 --- a/src/librustdoc/path_pass.rs +++ b/src/librustdoc/path_pass.rs @@ -54,7 +54,7 @@ fn run(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc { } fn fold_item(fold: &fold::Fold, +doc: doc::ItemDoc) -> doc::ItemDoc { - { + doc::ItemDoc { path: fold.ctxt.path, .. doc } @@ -68,7 +68,7 @@ fn fold_mod(fold: &fold::Fold, +doc: doc::ModDoc) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); if !is_topmod { fold.ctxt.path.pop(); } - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), .. *doc }) @@ -79,7 +79,7 @@ fn fold_nmod(fold: &fold::Fold, +doc: doc::NmodDoc) -> doc::NmodDoc { let doc = fold::default_seq_fold_nmod(fold, doc); fold.ctxt.path.pop(); - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), .. doc } diff --git a/src/librustdoc/prune_hidden_pass.rs b/src/librustdoc/prune_hidden_pass.rs index 3a924e3bddf69..c3d31d4a5b0ad 100644 --- a/src/librustdoc/prune_hidden_pass.rs +++ b/src/librustdoc/prune_hidden_pass.rs @@ -42,7 +42,7 @@ fn fold_mod( ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: do doc.items.filtered |ItemTag| { !is_hidden(fold.ctxt, ItemTag.item()) }, diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index 3b11437acebaf..a18530a74603a 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -48,7 +48,7 @@ fn fold_mod( ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: doc.items.filtered(|ItemTag| { is_visible(fold.ctxt, ItemTag.item()) }), diff --git a/src/librustdoc/rustdoc.rc b/src/librustdoc/rustdoc.rc index 77ed564aab471..c756bbe82492e 100644 --- a/src/librustdoc/rustdoc.rc +++ b/src/librustdoc/rustdoc.rc @@ -26,6 +26,7 @@ #[allow(non_implicitly_copyable_typarams)]; #[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; +#[allow(deprecated_self)]; extern mod core(vers = "0.6"); extern mod std(vers = "0.6"); diff --git a/src/librustdoc/sectionalize_pass.rs b/src/librustdoc/sectionalize_pass.rs index eeadd82371fd9..706aecf49b95b 100644 --- a/src/librustdoc/sectionalize_pass.rs +++ b/src/librustdoc/sectionalize_pass.rs @@ -46,7 +46,7 @@ fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { let doc = fold::default_seq_fold_item(fold, doc); let (desc, sections) = sectionalize(doc.desc); - { + doc::ItemDoc { desc: desc, sections: sections, .. doc @@ -56,11 +56,11 @@ fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { let doc = fold::default_seq_fold_trait(fold, doc); - { + doc::TraitDoc { methods: do par::map(doc.methods) |method| { let (desc, sections) = sectionalize(method.desc); - { + doc::MethodDoc { desc: desc, sections: sections, .. *method @@ -73,11 +73,11 @@ fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { fn fold_impl(fold: &fold::Fold<()>, +doc: doc::ImplDoc) -> doc::ImplDoc { let doc = fold::default_seq_fold_impl(fold, doc); - { + doc::ImplDoc { methods: do par::map(doc.methods) |method| { let (desc, sections) = sectionalize(method.desc); - { + doc::MethodDoc { desc: desc, sections: sections, .. *method @@ -121,7 +121,7 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { if current_section.is_some() { sections += ~[current_section.get()]; } - current_section = Some({ + current_section = Some(doc::Section { header: header, body: ~"" }); @@ -129,7 +129,7 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { None => { match copy current_section { Some(section) => { - current_section = Some({ + current_section = Some(doc::Section { body: section.body + ~"\n" + *line, .. section }); diff --git a/src/librustdoc/sort_pass.rs b/src/librustdoc/sort_pass.rs index b3ecb8173fee7..42759be68ad32 100644 --- a/src/librustdoc/sort_pass.rs +++ b/src/librustdoc/sort_pass.rs @@ -55,7 +55,7 @@ fn fold_mod( +doc: doc::ModDoc ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: sort::merge_sort(doc.items, fold.ctxt.op), .. *doc }) diff --git a/src/librustdoc/text_pass.rs b/src/librustdoc/text_pass.rs index 5627bfead9f45..fb55641b764f4 100644 --- a/src/librustdoc/text_pass.rs +++ b/src/librustdoc/text_pass.rs @@ -62,7 +62,7 @@ fn fold_item( ) -> doc::ItemDoc { let doc = fold::default_seq_fold_item(fold, doc); - { + doc::ItemDoc { brief: maybe_apply_op(fold.ctxt, doc.brief), desc: maybe_apply_op(fold.ctxt, doc.desc), sections: apply_to_sections(fold.ctxt, doc.sections), @@ -74,7 +74,7 @@ fn apply_to_sections( op: NominalOp, sections: ~[doc::Section] ) -> ~[doc::Section] { - par::map(sections, |section, copy op| { + par::map(sections, |section, copy op| doc::Section { header: (op.op)(section.header), body: (op.op)(section.body) }) @@ -86,9 +86,9 @@ fn fold_enum( let doc = fold::default_seq_fold_enum(fold, doc); let fold_copy = copy *fold; - { + doc::EnumDoc { variants: do par::map(doc.variants) |variant, copy fold_copy| { - { + doc::VariantDoc { desc: maybe_apply_op(fold_copy.ctxt, variant.desc), .. *variant } @@ -103,7 +103,7 @@ fn fold_trait( ) -> doc::TraitDoc { let doc = fold::default_seq_fold_trait(fold, doc); - { + doc::TraitDoc { methods: apply_to_methods(fold.ctxt, doc.methods), .. doc } @@ -114,7 +114,7 @@ fn apply_to_methods( docs: ~[doc::MethodDoc] ) -> ~[doc::MethodDoc] { do par::map(docs) |doc, copy op| { - { + doc::MethodDoc { brief: maybe_apply_op(op, doc.brief), desc: maybe_apply_op(op, doc.desc), sections: apply_to_sections(op, doc.sections), @@ -129,7 +129,7 @@ fn fold_impl( ) -> doc::ImplDoc { let doc = fold::default_seq_fold_impl(fold, doc); - { + doc::ImplDoc { methods: apply_to_methods(fold.ctxt, doc.methods), .. doc } diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 5d92ed14c18df..3b9991d18274e 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -59,7 +59,7 @@ fn fold_fn( let srv = fold.ctxt; - { + doc::SimpleItemDoc { sig: get_fn_sig(srv, doc.id()), .. doc } @@ -101,7 +101,7 @@ fn fold_const( ) -> doc::ConstDoc { let srv = fold.ctxt; - { + doc::SimpleItemDoc { sig: Some(do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get(doc.id()) { ast_map::node_item(@ast::item { @@ -129,7 +129,7 @@ fn fold_enum( let doc_id = doc.id(); let srv = fold.ctxt; - { + doc::EnumDoc { variants: do par::map(doc.variants) |variant| { let variant = *variant; let sig = do astsrv::exec(srv) |ctxt| { @@ -148,7 +148,7 @@ fn fold_enum( } }; - { + doc::VariantDoc { sig: Some(sig), .. variant } @@ -167,7 +167,7 @@ fn fold_trait( fold: &fold::Fold, +doc: doc::TraitDoc ) -> doc::TraitDoc { - { + doc::TraitDoc { methods: merge_methods(fold.ctxt, doc.id(), doc.methods), .. doc } @@ -179,7 +179,7 @@ fn merge_methods( docs: ~[doc::MethodDoc] ) -> ~[doc::MethodDoc] { do par::map(docs) |doc| { - { + doc::MethodDoc { sig: get_method_sig(srv, item_id, doc.name), .. *doc } @@ -276,7 +276,7 @@ fn fold_impl( } }; - { + doc::ImplDoc { trait_types: trait_types, self_ty: self_ty, methods: merge_methods(fold.ctxt, doc.id(), doc.methods), @@ -316,7 +316,7 @@ fn fold_type( let srv = fold.ctxt; - { + doc::SimpleItemDoc { sig: do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get(doc.id()) { ast_map::node_item(@ast::item { @@ -349,7 +349,7 @@ fn fold_struct( ) -> doc::StructDoc { let srv = fold.ctxt; - { + doc::StructDoc { sig: do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get(doc.id()) { ast_map::node_item(item, _) => { diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 0c40fe283af0b..edffa32e501ee 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -79,7 +79,7 @@ impl &Condvar { ****************************************************************************/ /// An atomically reference counted wrapper for shared immutable state. -struct ARC { x: SharedMutableState } +struct ARC { x: SharedMutableState } /// Create an atomically reference counted wrapper. pub fn ARC(data: T) -> ARC { @@ -130,9 +130,9 @@ impl ARC: Clone { ****************************************************************************/ #[doc(hidden)] -struct MutexARCInner { lock: Mutex, failed: bool, data: T } +struct MutexARCInner { lock: Mutex, failed: bool, data: T } /// An ARC with mutable data protected by a blocking mutex. -struct MutexARC { x: SharedMutableState> } +struct MutexARC { x: SharedMutableState> } /// Create a mutex-protected ARC with the supplied data. pub fn MutexARC(user_data: T) -> MutexARC { @@ -267,14 +267,14 @@ fn PoisonOnFail(failed: &r/mut bool) -> PoisonOnFail { ****************************************************************************/ #[doc(hidden)] -struct RWARCInner { lock: RWlock, failed: bool, data: T } +struct RWARCInner { lock: RWlock, failed: bool, data: T } /** * A dual-mode ARC protected by a reader-writer lock. The data can be accessed * mutably or immutably, and immutably-accessing tasks may run concurrently. * * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested. */ -struct RWARC { +struct RWARC { x: SharedMutableState>, mut cant_nest: () } @@ -426,10 +426,10 @@ fn borrow_rwlock(state: &r/mut RWARCInner) -> &r/RWlock { // FIXME (#3154) ice with struct/& prevents these from being structs. /// The "write permission" token used for RWARC.write_downgrade(). -pub enum RWWriteMode = +pub enum RWWriteMode = (&mut T, sync::RWlockWriteMode, PoisonOnFail); /// The "read permission" token used for RWARC.write_downgrade(). -pub enum RWReadMode = (&T, sync::RWlockReadMode); +pub enum RWReadMode = (&T, sync::RWlockReadMode); impl &RWWriteMode { /// Access the pre-downgrade RWARC in write mode. diff --git a/src/libstd/bigint.rs b/src/libstd/bigint.rs index fc7834291267b..4283a7e402bce 100644 --- a/src/libstd/bigint.rs +++ b/src/libstd/bigint.rs @@ -17,7 +17,7 @@ A BigInt is a combination of BigUint and Sign. */ use core::cmp::{Eq, Ord}; -use core::num::{Num, Zero, One}; +use core::num::{IntConvertible, Zero, One}; use core::*; /** @@ -121,7 +121,7 @@ impl BigUint : One { static pub pure fn one() -> BigUint { BigUint::new(~[1]) } } -impl BigUint : Num { +impl BigUint : Add { pure fn add(&self, other: &BigUint) -> BigUint { let new_len = uint::max(self.data.len(), other.data.len()); @@ -138,7 +138,9 @@ impl BigUint : Num { if carry == 0 { return BigUint::new(sum) }; return BigUint::new(sum + [carry]); } +} +impl BigUint : Sub { pure fn sub(&self, other: &BigUint) -> BigUint { let new_len = uint::max(self.data.len(), other.data.len()); @@ -161,7 +163,9 @@ impl BigUint : Num { assert borrow == 0; // <=> assert (self >= other); return BigUint::new(diff); } +} +impl BigUint : Mul { pure fn mul(&self, other: &BigUint) -> BigUint { if self.is_zero() || other.is_zero() { return Zero::zero(); } @@ -224,18 +228,27 @@ impl BigUint : Num { } } } +} +impl BigUint : Div { pure fn div(&self, other: &BigUint) -> BigUint { let (d, _) = self.divmod(other); return d; } +} + +impl BigUint : Modulo { pure fn modulo(&self, other: &BigUint) -> BigUint { let (_, m) = self.divmod(other); return m; } +} +impl BigUint : Neg { pure fn neg(&self) -> BigUint { fail } +} +impl BigUint : IntConvertible { pure fn to_int(&self) -> int { uint::min(self.to_uint(), int::max_value as uint) as int } @@ -625,7 +638,7 @@ impl BigInt : One { } } -impl BigInt : Num { +impl BigInt : Add { pure fn add(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => copy *other, @@ -637,6 +650,9 @@ impl BigInt : Num { (Minus, Minus) => -((-self) + (-*other)) } } +} + +impl BigInt : Sub { pure fn sub(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => -other, @@ -654,6 +670,9 @@ impl BigInt : Num { (Minus, Minus) => (-other) - (-*self) } } +} + +impl BigInt : Mul { pure fn mul(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) | (_, Zero) => Zero::zero(), @@ -665,18 +684,29 @@ impl BigInt : Num { } } } +} + +impl BigInt : Div { pure fn div(&self, other: &BigInt) -> BigInt { let (d, _) = self.divmod(other); return d; } +} + +impl BigInt : Modulo { pure fn modulo(&self, other: &BigInt) -> BigInt { let (_, m) = self.divmod(other); return m; } +} + +impl BigInt : Neg { pure fn neg(&self) -> BigInt { BigInt::from_biguint(self.sign.neg(), copy self.data) } +} +impl BigInt : IntConvertible { pure fn to_int(&self) -> int { match self.sign { Plus => uint::min(self.to_uint(), int::max_value as uint) as int, @@ -834,7 +864,7 @@ pub impl BigInt { mod biguint_tests { use core::*; - use core::num::{Num, Zero, One}; + use num::{IntConvertible, Zero, One}; use super::{BigInt, BigUint, BigDigit}; #[test] @@ -974,7 +1004,7 @@ mod biguint_tests { fn test_convert_int() { fn check(v: ~[BigDigit], i: int) { let b = BigUint::new(v); - assert b == Num::from_int(i); + assert b == IntConvertible::from_int(i); assert b.to_int() == i; } @@ -1244,7 +1274,7 @@ mod bigint_tests { use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; use core::*; - use core::num::{Num, Zero, One}; + use core::num::{IntConvertible, Zero, One}; #[test] fn test_from_biguint() { @@ -1303,7 +1333,7 @@ mod bigint_tests { #[test] fn test_convert_int() { fn check(b: BigInt, i: int) { - assert b == Num::from_int(i); + assert b == IntConvertible::from_int(i); assert b.to_int() == i; } @@ -1563,7 +1593,8 @@ mod bigint_tests { #[test] fn test_to_str_radix() { fn check(n: int, ans: &str) { - assert ans == Num::from_int::(n).to_str_radix(10); + assert ans == IntConvertible::from_int::( + n).to_str_radix(10); } check(10, "10"); check(1, "1"); @@ -1576,7 +1607,7 @@ mod bigint_tests { #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { - let ans = ans.map(|&n| Num::from_int(n)); + let ans = ans.map(|&n| IntConvertible::from_int(n)); assert BigInt::from_str_radix(s, 10) == ans; } check("10", Some(10)); diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 3118a0c1ba545..16e8b63da8174 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -23,7 +23,14 @@ use core::pipes; use core::prelude::*; /// An extension of `pipes::stream` that allows both sending and receiving. -pub struct DuplexStream { +#[cfg(stage0)] +pub struct DuplexStream { + priv chan: Chan, + priv port: Port, +} +#[cfg(stage1)] +#[cfg(stage2)] +pub struct DuplexStream { priv chan: Chan, priv port: Port, } diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index b4217dfb39d4a..2abd59523a104 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -249,69 +249,19 @@ mod tests { assert deq.get(3) == d; } + #[deriving_eq] enum Taggy { One(int), Two(int, int), Three(int, int, int), } + #[deriving_eq] enum Taggypar { Onepar(int), Twopar(int, int), Threepar(int, int, int), } + #[deriving_eq] struct RecCy { x: int, y: int, - t: Taggy, - } - - impl Taggy : Eq { - pure fn eq(&self, other: &Taggy) -> bool { - match (*self) { - One(a1) => match (*other) { - One(b1) => return a1 == b1, - _ => return false - }, - Two(a1, a2) => match (*other) { - Two(b1, b2) => return a1 == b1 && a2 == b2, - _ => return false - }, - Three(a1, a2, a3) => match (*other) { - Three(b1, b2, b3) => return a1 == b1 && a2 == b2 && a3 == b3, - _ => return false - } - } - } - pure fn ne(&self, other: &Taggy) -> bool { !(*self).eq(other) } - } - - impl Taggypar : Eq { - //let eq4: EqFn> = |x,y| taggypareq::(x, y); - pure fn eq(&self, other: &Taggypar) -> bool { - match (*self) { - Onepar::(a1) => match (*other) { - Onepar::(b1) => return a1 == b1, - _ => return false - }, - Twopar::(a1, a2) => match (*other) { - Twopar::(b1, b2) => return a1 == b1 && a2 == b2, - _ => return false - }, - Threepar::(a1, a2, a3) => match (*other) { - Threepar::(b1, b2, b3) => { - return a1 == b1 && a2 == b2 && a3 == b3 - } - _ => return false - } - } - } - pure fn ne(&self, other: &Taggypar) -> bool { - !(*self).eq(other) - } - } - - impl RecCy : Eq { - pure fn eq(&self, other: &RecCy) -> bool { - return (*self).x == (*other).x && (*self).y == (*other).y && - (*self).t == (*other).t; - } - pure fn ne(&self, other: &RecCy) -> bool { !(*self).eq(other) } + t: Taggy } #[test] diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index dc379cec21b59..f93705c0c62b6 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -676,6 +676,7 @@ pub mod writer { mod tests { use ebml::reader; use ebml::writer; + use serialize::Encodable; use serialize; use core::io; diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index ea7b2442bb919..bd684baf6b300 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -63,7 +63,7 @@ and an `Unflattener` that converts the bytes to a value. Create using the constructors in the `serial` and `pod` modules. */ -pub struct FlatPort, P: BytePort> { +pub struct FlatPort { unflattener: U, byte_port: P } @@ -74,7 +74,7 @@ byte vectors, and a `ByteChan` that transmits the bytes. Create using the constructors in the `serial` and `pod` modules. */ -pub struct FlatChan, C: ByteChan> { +pub struct FlatChan { flattener: F, byte_chan: C } @@ -181,14 +181,12 @@ pub mod pod { use core::pipes; use core::prelude::*; - pub type ReaderPort = + pub type ReaderPort = FlatPort, ReaderBytePort>; - pub type WriterChan = + pub type WriterChan = FlatChan, WriterByteChan>; - pub type PipePort = - FlatPort, PipeBytePort>; - pub type PipeChan = - FlatChan, PipeByteChan>; + pub type PipePort = FlatPort, PipeBytePort>; + pub type PipeChan = FlatChan, PipeByteChan>; /// Create a `FlatPort` from a `Reader` pub fn reader_port( @@ -352,11 +350,11 @@ pub mod flatteners { // FIXME #4074: Copy + Owned != POD - pub struct PodUnflattener { + pub struct PodUnflattener { bogus: () } - pub struct PodFlattener { + pub struct PodFlattener { bogus: () } @@ -398,14 +396,13 @@ pub mod flatteners { pub type DeserializeBuffer = ~fn(buf: &[u8]) -> T; - pub struct DeserializingUnflattener> { + pub struct DeserializingUnflattener { deserialize_buffer: DeserializeBuffer } pub type SerializeValue = ~fn(val: &T) -> ~[u8]; - pub struct SerializingFlattener> { + pub struct SerializingFlattener { serialize_value: SerializeValue } @@ -518,11 +515,11 @@ pub mod bytepipes { use core::pipes; use core::prelude::*; - pub struct ReaderBytePort { + pub struct ReaderBytePort { reader: R } - pub struct WriterByteChan { + pub struct WriterByteChan { writer: W } @@ -767,9 +764,9 @@ mod test { test_some_tcp_stream(reader_port, writer_chan, 9667); } - type ReaderPortFactory> = + type ReaderPortFactory = ~fn(TcpSocketBuf) -> FlatPort>; - type WriterChanFactory> = + type WriterChanFactory = ~fn(TcpSocketBuf) -> FlatChan>; fn test_some_tcp_stream, F: Flattener>( @@ -792,7 +789,6 @@ mod test { let (finish_port, finish_chan) = pipes::stream(); let addr = ip::v4::parse_addr("127.0.0.1"); - let iotask = uv::global_loop::get(); let begin_connect_chan = Cell(move begin_connect_chan); let accept_chan = Cell(move accept_chan); @@ -800,6 +796,7 @@ mod test { // The server task do task::spawn |copy addr, move begin_connect_chan, move accept_chan| { + let iotask = &uv::global_loop::get(); let begin_connect_chan = begin_connect_chan.take(); let accept_chan = accept_chan.take(); let listen_res = do tcp::listen( @@ -831,6 +828,7 @@ mod test { begin_connect_port.recv(); debug!("connecting"); + let iotask = &uv::global_loop::get(); let connect_result = tcp::connect(copy addr, port, iotask); assert connect_result.is_ok(); let sock = result::unwrap(move connect_result); @@ -892,7 +890,7 @@ mod test { use core::sys; use core::task; - type PortLoader = + type PortLoader

= ~fn(~[u8]) -> FlatPort, P>; fn reader_port_loader(bytes: ~[u8] diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 45d467095fb85..1361d8647b574 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -15,6 +15,7 @@ //! json serialization +use serialize::Encodable; use serialize; use sort::Sort; diff --git a/src/libstd/map.rs b/src/libstd/map.rs index 3c890ef06541f..2fa2825eb4cd7 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -24,11 +24,11 @@ use core::uint; use core::vec; /// A convenience type to treat a hashmap as a set -pub type Set = HashMap; +pub type Set = HashMap; -pub type HashMap = chained::T; +pub type HashMap = chained::T; -pub trait Map { +pub trait StdMap { /// Return the number of elements in the map pure fn size() -> uint; @@ -124,7 +124,7 @@ pub mod util { // FIXME (#2344): package this up and export it as a datatype usable for // external code that doesn't want to pay the cost of a box. pub mod chained { - use map::{Map, util}; + use map::{StdMap, util}; use core::io; use core::ops; @@ -142,12 +142,12 @@ pub mod chained { mut next: Option<@Entry> } - struct HashMap_ { + struct HashMap_ { mut count: uint, mut chains: ~[mut Option<@Entry>] } - pub type T = @HashMap_; + pub type T = @HashMap_; enum SearchResult { NotFound, @@ -239,7 +239,7 @@ pub mod chained { } } - impl T: Map { + impl T: StdMap { pure fn size() -> uint { self.count } pure fn contains_key(k: K) -> bool { diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 84c3b75564984..72e58cbd5d368 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -114,7 +114,7 @@ enum IpGetAddrErr { * a vector of `ip_addr` results, in the case of success, or an error * object in the case of failure */ -pub fn get_addr(node: &str, iotask: iotask) +pub fn get_addr(node: &str, iotask: &iotask) -> result::Result<~[IpAddr], IpGetAddrErr> { do oldcomm::listen |output_ch| { do str::as_buf(node) |node_ptr, len| { @@ -419,7 +419,7 @@ mod test { #[ignore(reason = "valgrind says it's leaky")] fn test_ip_get_addr() { let localhost_name = ~"localhost"; - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let ga_result = get_addr(localhost_name, iotask); if result::is_err(&ga_result) { fail ~"got err result from net::ip::get_addr();" @@ -445,7 +445,7 @@ mod test { #[ignore(reason = "valgrind says it's leaky")] fn test_ip_get_addr_bad_input() { let localhost_name = ~"sjkl234m,./sdf"; - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let ga_result = get_addr(localhost_name, iotask); assert result::is_err(&ga_result); } diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 3e9a9756a81c6..24396eebbbe15 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -143,7 +143,7 @@ pub enum TcpConnectErrData { * `net::tcp::tcp_connect_err_data` instance will be returned */ pub fn connect(input_ip: ip::IpAddr, port: uint, - iotask: IoTask) + iotask: &IoTask) -> result::Result { unsafe { let result_po = oldcomm::Port::(); @@ -166,106 +166,116 @@ pub fn connect(input_ip: ip::IpAddr, port: uint, ip::Ipv4(_) => { false } ip::Ipv6(_) => { true } }, - iotask: iotask + iotask: iotask.clone() }; let socket_data_ptr = ptr::addr_of(&(*socket_data)); log(debug, fmt!("tcp_connect result_ch %?", conn_data.result_ch)); // get an unsafe representation of our stream_handle_ptr that // we can send into the interact cb to be handled in libuv.. log(debug, fmt!("stream_handle_ptr outside interact %?", - stream_handle_ptr)); + stream_handle_ptr)); do iotask::interact(iotask) |move input_ip, loop_ptr| { unsafe { log(debug, ~"in interact cb for tcp client connect.."); log(debug, fmt!("stream_handle_ptr in interact %?", - stream_handle_ptr)); + stream_handle_ptr)); match uv::ll::tcp_init( loop_ptr, stream_handle_ptr) { - 0i32 => { - log(debug, ~"tcp_init successful"); - log(debug, ~"dealing w/ ipv4 connection.."); - let connect_req_ptr = - ptr::addr_of(&((*socket_data_ptr).connect_req)); - let addr_str = ip::format_addr(&input_ip); - let connect_result = match input_ip { - ip::Ipv4(ref addr) => { - // have to "recreate" the sockaddr_in/6 - // since the ip_addr discards the port - // info.. should probably add an additional - // rust type that actually is closer to - // what the libuv API expects (ip str + port num) - log(debug, fmt!("addr: %?", addr)); - let in_addr = uv::ll::ip4_addr(addr_str, port as int); - uv::ll::tcp_connect( - connect_req_ptr, - stream_handle_ptr, - ptr::addr_of(&in_addr), - tcp_connect_on_connect_cb) - } - ip::Ipv6(ref addr) => { - log(debug, fmt!("addr: %?", addr)); - let in_addr = uv::ll::ip6_addr(addr_str, port as int); - uv::ll::tcp_connect6( - connect_req_ptr, - stream_handle_ptr, - ptr::addr_of(&in_addr), - tcp_connect_on_connect_cb) - } - }; - match connect_result { - 0i32 => { - log(debug, ~"tcp_connect successful"); - // reusable data that we'll have for the - // duration.. - uv::ll::set_data_for_uv_handle(stream_handle_ptr, - socket_data_ptr as - *libc::c_void); - // just so the connect_cb can send the - // outcome.. - uv::ll::set_data_for_req(connect_req_ptr, - conn_data_ptr); - log(debug, ~"leaving tcp_connect interact cb..."); - // let tcp_connect_on_connect_cb send on - // the result_ch, now.. - } - _ => { - // immediate connect failure.. probably a garbage - // ip or somesuch + 0i32 => { + log(debug, ~"tcp_init successful"); + log(debug, ~"dealing w/ ipv4 connection.."); + let connect_req_ptr = + ptr::addr_of(&((*socket_data_ptr).connect_req)); + let addr_str = ip::format_addr(&input_ip); + let connect_result = match input_ip { + ip::Ipv4(ref addr) => { + // have to "recreate" the + // sockaddr_in/6 since the ip_addr + // discards the port info.. should + // probably add an additional rust + // type that actually is closer to + // what the libuv API expects (ip str + // + port num) + log(debug, fmt!("addr: %?", addr)); + let in_addr = uv::ll::ip4_addr(addr_str, + port as int); + uv::ll::tcp_connect( + connect_req_ptr, + stream_handle_ptr, + ptr::addr_of(&in_addr), + tcp_connect_on_connect_cb) + } + ip::Ipv6(ref addr) => { + log(debug, fmt!("addr: %?", addr)); + let in_addr = uv::ll::ip6_addr(addr_str, + port as int); + uv::ll::tcp_connect6( + connect_req_ptr, + stream_handle_ptr, + ptr::addr_of(&in_addr), + tcp_connect_on_connect_cb) + } + }; + match connect_result { + 0i32 => { + log(debug, ~"tcp_connect successful"); + // reusable data that we'll have for the + // duration.. + uv::ll::set_data_for_uv_handle( + stream_handle_ptr, + socket_data_ptr as + *libc::c_void); + // just so the connect_cb can send the + // outcome.. + uv::ll::set_data_for_req(connect_req_ptr, + conn_data_ptr); + log(debug, + ~"leaving tcp_connect interact cb..."); + // let tcp_connect_on_connect_cb send on + // the result_ch, now.. + } + _ => { + // immediate connect + // failure.. probably a garbage ip or + // somesuch + let err_data = + uv::ll::get_last_err_data(loop_ptr); + oldcomm::send((*conn_data_ptr).result_ch, + ConnFailure(err_data)); + uv::ll::set_data_for_uv_handle( + stream_handle_ptr, + conn_data_ptr); + uv::ll::close(stream_handle_ptr, + stream_error_close_cb); + } + } + } + _ => { + // failure to create a tcp handle let err_data = uv::ll::get_last_err_data(loop_ptr); oldcomm::send((*conn_data_ptr).result_ch, - ConnFailure(err_data)); - uv::ll::set_data_for_uv_handle(stream_handle_ptr, - conn_data_ptr); - uv::ll::close(stream_handle_ptr, - stream_error_close_cb); - } + ConnFailure(err_data)); } - } - _ => { - // failure to create a tcp handle - let err_data = uv::ll::get_last_err_data(loop_ptr); - oldcomm::send((*conn_data_ptr).result_ch, - ConnFailure(err_data)); - } } } - }; + } match oldcomm::recv(result_po) { - ConnSuccess => { - log(debug, ~"tcp::connect - received success on result_po"); - result::Ok(TcpSocket(socket_data)) - } - ConnFailure(ref err_data) => { - oldcomm::recv(closed_signal_po); - log(debug, ~"tcp::connect - received failure on result_po"); - // still have to free the malloc'd stream handle.. - rustrt::rust_uv_current_kernel_free(stream_handle_ptr - as *libc::c_void); - let tcp_conn_err = match err_data.err_name { - ~"ECONNREFUSED" => ConnectionRefused, - _ => GenericConnectErr(err_data.err_name, err_data.err_msg) - }; - result::Err(tcp_conn_err) - } + ConnSuccess => { + log(debug, ~"tcp::connect - received success on result_po"); + result::Ok(TcpSocket(socket_data)) + } + ConnFailure(ref err_data) => { + oldcomm::recv(closed_signal_po); + log(debug, ~"tcp::connect - received failure on result_po"); + // still have to free the malloc'd stream handle.. + rustrt::rust_uv_current_kernel_free(stream_handle_ptr + as *libc::c_void); + let tcp_conn_err = match err_data.err_name { + ~"ECONNREFUSED" => ConnectionRefused, + _ => GenericConnectErr(err_data.err_name, + err_data.err_msg) + }; + result::Err(tcp_conn_err) + } } } } @@ -506,71 +516,79 @@ fn read_future(sock: &TcpSocket, timeout_msecs: uint) pub fn accept(new_conn: TcpNewConnection) -> result::Result { unsafe { - match new_conn { - NewTcpConn(server_handle_ptr) => { - let server_data_ptr = uv::ll::get_data_for_uv_handle( - server_handle_ptr) as *TcpListenFcData; - let reader_po = oldcomm::Port(); - let iotask = (*server_data_ptr).iotask; - let stream_handle_ptr = malloc_uv_tcp_t(); - *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = uv::ll::tcp_t(); - let client_socket_data = @TcpSocketData { - reader_po: reader_po, - reader_ch: oldcomm::Chan(&reader_po), - stream_handle_ptr : stream_handle_ptr, - connect_req : uv::ll::connect_t(), - write_req : uv::ll::write_t(), - ipv6: (*server_data_ptr).ipv6, - iotask : iotask - }; - let client_socket_data_ptr = ptr::addr_of(&(*client_socket_data)); - let client_stream_handle_ptr = - (*client_socket_data_ptr).stream_handle_ptr; - - let result_po = oldcomm::Port::>(); - let result_ch = oldcomm::Chan(&result_po); - - // UNSAFE LIBUV INTERACTION BEGIN - // .. normally this happens within the context of - // a call to uv::hl::interact.. but we're breaking - // the rules here because this always has to be - // called within the context of a listen() new_connect_cb - // callback (or it will likely fail and drown your cat) - log(debug, ~"in interact cb for tcp::accept"); - let loop_ptr = uv::ll::get_loop_for_uv_handle( - server_handle_ptr); - match uv::ll::tcp_init(loop_ptr, client_stream_handle_ptr) { - 0i32 => { - log(debug, ~"uv_tcp_init successful for client stream"); - match uv::ll::accept( - server_handle_ptr as *libc::c_void, - client_stream_handle_ptr as *libc::c_void) { - 0i32 => { - log(debug, ~"successfully accepted client connection"); - uv::ll::set_data_for_uv_handle(client_stream_handle_ptr, - client_socket_data_ptr - as *libc::c_void); - oldcomm::send(result_ch, None); - } - _ => { - log(debug, ~"failed to accept client conn"); - oldcomm::send(result_ch, Some( - uv::ll::get_last_err_data(loop_ptr).to_tcp_err())); - } + match new_conn{ + NewTcpConn(server_handle_ptr) => { + let server_data_ptr = uv::ll::get_data_for_uv_handle( + server_handle_ptr) as *TcpListenFcData; + let reader_po = oldcomm::Port(); + let iotask = &(*server_data_ptr).iotask; + let stream_handle_ptr = malloc_uv_tcp_t(); + *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = + uv::ll::tcp_t(); + let client_socket_data: @TcpSocketData = @TcpSocketData { + reader_po: reader_po, + reader_ch: oldcomm::Chan(&reader_po), + stream_handle_ptr : stream_handle_ptr, + connect_req : uv::ll::connect_t(), + write_req : uv::ll::write_t(), + ipv6: (*server_data_ptr).ipv6, + iotask : iotask.clone() + }; + let client_socket_data_ptr = ptr::addr_of( + &(*client_socket_data)); + let client_stream_handle_ptr = + (*client_socket_data_ptr).stream_handle_ptr; + + let result_po = oldcomm::Port::>(); + let result_ch = oldcomm::Chan(&result_po); + + // UNSAFE LIBUV INTERACTION BEGIN + // .. normally this happens within the context of + // a call to uv::hl::interact.. but we're breaking + // the rules here because this always has to be + // called within the context of a listen() new_connect_cb + // callback (or it will likely fail and drown your cat) + log(debug, ~"in interact cb for tcp::accept"); + let loop_ptr = uv::ll::get_loop_for_uv_handle( + server_handle_ptr); + match uv::ll::tcp_init(loop_ptr, client_stream_handle_ptr) { + 0i32 => { + log(debug, ~"uv_tcp_init successful for \ + client stream"); + match uv::ll::accept( + server_handle_ptr as *libc::c_void, + client_stream_handle_ptr as *libc::c_void) { + 0i32 => { + log(debug, + ~"successfully accepted client \ + connection"); + uv::ll::set_data_for_uv_handle( + client_stream_handle_ptr, + client_socket_data_ptr + as *libc::c_void); + oldcomm::send(result_ch, None); + } + _ => { + log(debug, ~"failed to accept client conn"); + oldcomm::send(result_ch, Some( + uv::ll::get_last_err_data( + loop_ptr).to_tcp_err())); + } + } + } + _ => { + log(debug, ~"failed to accept client stream"); + oldcomm::send(result_ch, Some( + uv::ll::get_last_err_data( + loop_ptr).to_tcp_err())); + } + } + // UNSAFE LIBUV INTERACTION END + match oldcomm::recv(result_po) { + Some(copy err_data) => result::Err(err_data), + None => result::Ok(TcpSocket(client_socket_data)) } - } - _ => { - log(debug, ~"failed to init client stream"); - oldcomm::send(result_ch, Some( - uv::ll::get_last_err_data(loop_ptr).to_tcp_err())); - } - } - // UNSAFE LIBUV INTERACTION END - match oldcomm::recv(result_po) { - Some(copy err_data) => result::Err(err_data), - None => result::Ok(TcpSocket(client_socket_data)) } - } } } } @@ -604,30 +622,27 @@ pub fn accept(new_conn: TcpNewConnection) * of listen exiting because of an error */ pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint, - iotask: IoTask, - on_establish_cb: fn~(oldcomm::Chan>), - new_connect_cb: fn~(TcpNewConnection, - oldcomm::Chan>)) + iotask: &IoTask, + on_establish_cb: fn~(oldcomm::Chan>), + new_connect_cb: fn~(TcpNewConnection, + oldcomm::Chan>)) -> result::Result<(), TcpListenErrData> { - unsafe { - do listen_common(move host_ip, port, backlog, iotask, - move on_establish_cb) - // on_connect_cb - |move new_connect_cb, handle| { - unsafe { - let server_data_ptr = - uv::ll::get_data_for_uv_handle(handle) - as *TcpListenFcData; - let new_conn = NewTcpConn(handle); - let kill_ch = (*server_data_ptr).kill_ch; - new_connect_cb(new_conn, kill_ch); - } - } + do listen_common(move host_ip, port, backlog, iotask, + move on_establish_cb) + // on_connect_cb + |move new_connect_cb, handle| { + unsafe { + let server_data_ptr = uv::ll::get_data_for_uv_handle(handle) + as *TcpListenFcData; + let new_conn = NewTcpConn(handle); + let kill_ch = (*server_data_ptr).kill_ch; + new_connect_cb(new_conn, kill_ch); + } } } fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, - iotask: IoTask, + iotask: &IoTask, on_establish_cb: fn~(oldcomm::Chan>), on_connect_cb: fn~(*uv::ll::uv_tcp_t)) -> result::Result<(), TcpListenErrData> { @@ -637,12 +652,12 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, let kill_ch = oldcomm::Chan(&kill_po); let server_stream = uv::ll::tcp_t(); let server_stream_ptr = ptr::addr_of(&server_stream); - let server_data = { + let server_data: TcpListenFcData = TcpListenFcData { server_stream_ptr: server_stream_ptr, stream_closed_ch: oldcomm::Chan(&stream_closed_po), kill_ch: kill_ch, on_connect_cb: move on_connect_cb, - iotask: iotask, + iotask: iotask.clone(), ipv6: match &host_ip { &ip::Ipv4(_) => { false } &ip::Ipv6(_) => { true } @@ -662,114 +677,123 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, do iotask::interact(iotask) |move loc_ip, loop_ptr| { unsafe { match uv::ll::tcp_init(loop_ptr, server_stream_ptr) { - 0i32 => { - uv::ll::set_data_for_uv_handle( - server_stream_ptr, - server_data_ptr); - let addr_str = ip::format_addr(&loc_ip); - let bind_result = match loc_ip { - ip::Ipv4(ref addr) => { - log(debug, fmt!("addr: %?", addr)); - let in_addr = uv::ll::ip4_addr(addr_str, - port as int); - uv::ll::tcp_bind(server_stream_ptr, - ptr::addr_of(&in_addr)) - } - ip::Ipv6(ref addr) => { - log(debug, fmt!("addr: %?", addr)); - let in_addr = uv::ll::ip6_addr(addr_str, - port as int); - uv::ll::tcp_bind6(server_stream_ptr, - ptr::addr_of(&in_addr)) - } - }; - match bind_result { - 0i32 => { - match uv::ll::listen(server_stream_ptr, - backlog as libc::c_int, - tcp_lfc_on_connection_cb) { - 0i32 => oldcomm::send(setup_ch, None), - _ => { - log(debug, ~"failure to uv_listen()"); - let err_data = uv::ll::get_last_err_data( - loop_ptr); - oldcomm::send(setup_ch, Some(err_data)); - } + 0i32 => { + uv::ll::set_data_for_uv_handle( + server_stream_ptr, + server_data_ptr); + let addr_str = ip::format_addr(&loc_ip); + let bind_result = match loc_ip { + ip::Ipv4(ref addr) => { + log(debug, fmt!("addr: %?", addr)); + let in_addr = uv::ll::ip4_addr( + addr_str, + port as int); + uv::ll::tcp_bind(server_stream_ptr, + ptr::addr_of(&in_addr)) + } + ip::Ipv6(ref addr) => { + log(debug, fmt!("addr: %?", addr)); + let in_addr = uv::ll::ip6_addr( + addr_str, + port as int); + uv::ll::tcp_bind6(server_stream_ptr, + ptr::addr_of(&in_addr)) + } + }; + match bind_result { + 0i32 => { + match uv::ll::listen( + server_stream_ptr, + backlog as libc::c_int, + tcp_lfc_on_connection_cb) { + 0i32 => oldcomm::send(setup_ch, None), + _ => { + log(debug, + ~"failure to uv_tcp_init"); + let err_data = + uv::ll::get_last_err_data( + loop_ptr); + oldcomm::send(setup_ch, + Some(err_data)); + } + } + } + _ => { + log(debug, ~"failure to uv_tcp_bind"); + let err_data = uv::ll::get_last_err_data( + loop_ptr); + oldcomm::send(setup_ch, Some(err_data)); + } } - } - _ => { + } + _ => { log(debug, ~"failure to uv_tcp_bind"); let err_data = uv::ll::get_last_err_data( loop_ptr); oldcomm::send(setup_ch, Some(err_data)); - } } - } - _ => { - log(debug, ~"failure to uv_tcp_init"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - oldcomm::send(setup_ch, Some(err_data)); - } } - }; + } } setup_ch.recv() }; match setup_result { - Some(ref err_data) => { - do iotask::interact(iotask) |loop_ptr| { - unsafe { - log(debug, - fmt!("tcp::listen post-kill recv hl interact %?", - loop_ptr)); - (*server_data_ptr).active = false; - uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); + Some(ref err_data) => { + do iotask::interact(iotask) |loop_ptr| { + unsafe { + log(debug, + fmt!("tcp::listen post-kill recv hl interact %?", + loop_ptr)); + (*server_data_ptr).active = false; + uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); + } + }; + stream_closed_po.recv(); + match err_data.err_name { + ~"EACCES" => { + log(debug, ~"Got EACCES error"); + result::Err(AccessDenied) + } + ~"EADDRINUSE" => { + log(debug, ~"Got EADDRINUSE error"); + result::Err(AddressInUse) + } + _ => { + log(debug, fmt!("Got '%s' '%s' libuv error", + err_data.err_name, err_data.err_msg)); + result::Err( + GenericListenErr(err_data.err_name, + err_data.err_msg)) + } } - }; - stream_closed_po.recv(); - match err_data.err_name { - ~"EACCES" => { - log(debug, ~"Got EACCES error"); - result::Err(AccessDenied) - } - ~"EADDRINUSE" => { - log(debug, ~"Got EADDRINUSE error"); - result::Err(AddressInUse) - } - _ => { - log(debug, fmt!("Got '%s' '%s' libuv error", - err_data.err_name, err_data.err_msg)); - result::Err( - GenericListenErr(err_data.err_name, err_data.err_msg)) - } } - } - None => { - on_establish_cb(kill_ch); - let kill_result = oldcomm::recv(kill_po); - do iotask::interact(iotask) |loop_ptr| { - unsafe { - log(debug, - fmt!("tcp::listen post-kill recv hl interact %?", - loop_ptr)); - (*server_data_ptr).active = false; - uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); + None => { + on_establish_cb(kill_ch); + let kill_result = oldcomm::recv(kill_po); + do iotask::interact(iotask) |loop_ptr| { + unsafe { + log(debug, + fmt!("tcp::listen post-kill recv hl interact %?", + loop_ptr)); + (*server_data_ptr).active = false; + uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); + } + }; + stream_closed_po.recv(); + match kill_result { + // some failure post bind/listen + Some(ref err_data) => result::Err(GenericListenErr( + err_data.err_name, + err_data.err_msg)), + // clean exit + None => result::Ok(()) } - }; - stream_closed_po.recv(); - match kill_result { - // some failure post bind/listen - Some(ref err_data) => result::Err(GenericListenErr( - err_data.err_name, - err_data.err_msg)), - // clean exit - None => result::Ok(()) } - } } } } + /** * Convert a `net::tcp::tcp_socket` to a `net::tcp::tcp_socket_buf`. * @@ -936,11 +960,11 @@ fn tear_down_socket_data(socket_data: @TcpSocketData) { }; let close_data_ptr = ptr::addr_of(&close_data); let stream_handle_ptr = (*socket_data).stream_handle_ptr; - do iotask::interact((*socket_data).iotask) |loop_ptr| { + do iotask::interact(&(*socket_data).iotask) |loop_ptr| { unsafe { log(debug, fmt!("interact dtor for tcp_socket stream %? loop %?", - stream_handle_ptr, loop_ptr)); + stream_handle_ptr, loop_ptr)); uv::ll::set_data_for_uv_handle(stream_handle_ptr, close_data_ptr); uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb); @@ -950,7 +974,7 @@ fn tear_down_socket_data(socket_data: @TcpSocketData) { //the line below will most likely crash //log(debug, fmt!("about to free socket_data at %?", socket_data)); rustrt::rust_uv_current_kernel_free(stream_handle_ptr - as *libc::c_void); + as *libc::c_void); log(debug, ~"exiting dtor for tcp_socket"); } } @@ -962,7 +986,7 @@ fn read_common_impl(socket_data: *TcpSocketData, timeout_msecs: uint) use timer; log(debug, ~"starting tcp::read"); - let iotask = (*socket_data).iotask; + let iotask = &(*socket_data).iotask; let rs_result = read_start_common_impl(socket_data); if result::is_err(&rs_result) { let err_data = result::get_err(&rs_result); @@ -972,26 +996,26 @@ fn read_common_impl(socket_data: *TcpSocketData, timeout_msecs: uint) log(debug, ~"tcp::read before recv_timeout"); let read_result = if timeout_msecs > 0u { timer::recv_timeout( - iotask, timeout_msecs, result::get(&rs_result)) + iotask, timeout_msecs, result::get(&rs_result)) } else { Some(oldcomm::recv(result::get(&rs_result))) }; log(debug, ~"tcp::read after recv_timeout"); match move read_result { - None => { - log(debug, ~"tcp::read: timed out.."); - let err_data = TcpErrData { - err_name: ~"TIMEOUT", - err_msg: ~"req timed out" - }; - read_stop_common_impl(socket_data); - result::Err(err_data) - } - Some(move data_result) => { - log(debug, ~"tcp::read got data"); - read_stop_common_impl(socket_data); - data_result - } + None => { + log(debug, ~"tcp::read: timed out.."); + let err_data = TcpErrData { + err_name: ~"TIMEOUT", + err_msg: ~"req timed out" + }; + read_stop_common_impl(socket_data); + result::Err(err_data) + } + Some(move data_result) => { + log(debug, ~"tcp::read got data"); + read_stop_common_impl(socket_data); + data_result + } } } } @@ -1004,27 +1028,26 @@ fn read_stop_common_impl(socket_data: *TcpSocketData) -> let stream_handle_ptr = (*socket_data).stream_handle_ptr; let stop_po = oldcomm::Port::>(); let stop_ch = oldcomm::Chan(&stop_po); - do iotask::interact((*socket_data).iotask) |loop_ptr| { + do iotask::interact(&(*socket_data).iotask) |loop_ptr| { unsafe { log(debug, ~"in interact cb for tcp::read_stop"); - match uv::ll::read_stop(stream_handle_ptr as - *uv::ll::uv_stream_t) { - 0i32 => { - log(debug, ~"successfully called uv_read_stop"); - oldcomm::send(stop_ch, None); - } - _ => { - log(debug, ~"failure in calling uv_read_stop"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - oldcomm::send(stop_ch, Some(err_data.to_tcp_err())); - } + match uv::ll::read_stop(stream_handle_ptr + as *uv::ll::uv_stream_t) { + 0i32 => { + log(debug, ~"successfully called uv_read_stop"); + oldcomm::send(stop_ch, None); + } + _ => { + log(debug, ~"failure in calling uv_read_stop"); + let err_data = uv::ll::get_last_err_data(loop_ptr); + oldcomm::send(stop_ch, Some(err_data.to_tcp_err())); + } } } - }; - + } match oldcomm::recv(stop_po) { - Some(move err_data) => Err(err_data), - None => Ok(()) + Some(move err_data) => Err(err_data), + None => Ok(()) } } } @@ -1038,29 +1061,29 @@ fn read_start_common_impl(socket_data: *TcpSocketData) let start_po = oldcomm::Port::>(); let start_ch = oldcomm::Chan(&start_po); log(debug, ~"in tcp::read_start before interact loop"); - do iotask::interact((*socket_data).iotask) |loop_ptr| { + do iotask::interact(&(*socket_data).iotask) |loop_ptr| { unsafe { - log(debug, - fmt!("in tcp::read_start interact cb %?", loop_ptr)); - match uv::ll::read_start(stream_handle_ptr as - *uv::ll::uv_stream_t, + log(debug, fmt!("in tcp::read_start interact cb %?", + loop_ptr)); + match uv::ll::read_start(stream_handle_ptr + as *uv::ll::uv_stream_t, on_alloc_cb, on_tcp_read_cb) { - 0i32 => { - log(debug, ~"success doing uv_read_start"); - oldcomm::send(start_ch, None); - } - _ => { - log(debug, ~"error attempting uv_read_start"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - oldcomm::send(start_ch, Some(err_data)); - } + 0i32 => { + log(debug, ~"success doing uv_read_start"); + oldcomm::send(start_ch, None); + } + _ => { + log(debug, ~"error attempting uv_read_start"); + let err_data = uv::ll::get_last_err_data(loop_ptr); + oldcomm::send(start_ch, Some(err_data)); + } } } - }; + } match oldcomm::recv(start_po) { - Some(ref err_data) => result::Err(err_data.to_tcp_err()), - None => result::Ok((*socket_data).reader_po) + Some(ref err_data) => result::Err(err_data.to_tcp_err()), + None => result::Ok((*socket_data).reader_po) } } } @@ -1084,27 +1107,28 @@ fn write_common_impl(socket_data_ptr: *TcpSocketData, result_ch: oldcomm::Chan(&result_po) }; let write_data_ptr = ptr::addr_of(&write_data); - do iotask::interact((*socket_data_ptr).iotask) |loop_ptr| { + do iotask::interact(&(*socket_data_ptr).iotask) |loop_ptr| { unsafe { log(debug, fmt!("in interact cb for tcp::write %?", loop_ptr)); match uv::ll::write(write_req_ptr, - stream_handle_ptr, - write_buf_vec_ptr, - tcp_write_complete_cb) { - 0i32 => { - log(debug, ~"uv_write() invoked successfully"); - uv::ll::set_data_for_req(write_req_ptr, write_data_ptr); - } - _ => { - log(debug, ~"error invoking uv_write()"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - oldcomm::send((*write_data_ptr).result_ch, - TcpWriteError(err_data.to_tcp_err())); - } + stream_handle_ptr, + write_buf_vec_ptr, + tcp_write_complete_cb) { + 0i32 => { + log(debug, ~"uv_write() invoked successfully"); + uv::ll::set_data_for_req(write_req_ptr, + write_data_ptr); + } + _ => { + log(debug, ~"error invoking uv_write()"); + let err_data = uv::ll::get_last_err_data(loop_ptr); + oldcomm::send((*write_data_ptr).result_ch, + TcpWriteError(err_data.to_tcp_err())); + } } } - }; + } // FIXME (#2656): Instead of passing unsafe pointers to local data, // and waiting here for the write to complete, we should transfer // ownership of everything to the I/O task and let it deal with the @@ -1473,7 +1497,7 @@ pub mod test { } } pub fn impl_gl_tcp_ipv4_server_and_client() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8888u; let expected_req = ~"ping"; @@ -1485,6 +1509,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1493,7 +1518,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1519,7 +1544,7 @@ pub mod test { assert str::contains(actual_resp, expected_resp); } pub fn impl_gl_tcp_ipv4_get_peer_addr() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8887u; let expected_resp = ~"pong"; @@ -1530,6 +1555,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1538,7 +1564,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1549,10 +1575,11 @@ pub mod test { let server_ip_addr = ip::v4::parse_addr(server_ip); let iotask = uv::global_loop::get(); let connect_result = connect(move server_ip_addr, server_port, - iotask); + &iotask); let sock = result::unwrap(move connect_result); + debug!("testing peer address"); // This is what we are actually testing! assert net::ip::format_addr(&sock.get_peer_addr()) == ~"127.0.0.1"; @@ -1561,12 +1588,14 @@ pub mod test { // Fulfill the protocol the test server expects let resp_bytes = str::to_bytes(~"ping"); tcp_write_single(&sock, resp_bytes); + debug!("message sent"); let read_result = sock.read(0u); client_ch.send(str::from_bytes(read_result.get())); + debug!("result read"); }; } pub fn impl_gl_tcp_ipv4_client_error_connection_refused() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8889u; let expected_req = ~"ping"; @@ -1586,7 +1615,7 @@ pub mod test { } } pub fn impl_gl_tcp_ipv4_server_address_in_use() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8890u; let expected_req = ~"ping"; @@ -1598,6 +1627,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1606,7 +1636,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1637,7 +1667,7 @@ pub mod test { } } pub fn impl_gl_tcp_ipv4_server_access_denied() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 80u; // this one should fail.. @@ -1657,7 +1687,7 @@ pub mod test { } pub fn impl_gl_tcp_ipv4_server_client_reader_writer() { - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8891u; let expected_req = ~"ping"; @@ -1669,6 +1699,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let iotask_clone = iotask.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1677,7 +1708,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - iotask) + &iotask_clone) }; server_result_ch.send(actual_req); }; @@ -1708,7 +1739,7 @@ pub mod test { pub fn impl_tcp_socket_impl_reader_handles_eof() { use core::io::{Reader,ReaderUtil}; - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 10041u; let expected_req = ~"GET /"; @@ -1720,6 +1751,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1728,7 +1760,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1768,7 +1800,7 @@ pub mod test { fn run_tcp_test_server(server_ip: &str, server_port: uint, resp: ~str, server_ch: oldcomm::Chan<~str>, cont_ch: oldcomm::Chan<()>, - iotask: IoTask) -> ~str { + iotask: &IoTask) -> ~str { let server_ip_addr = ip::v4::parse_addr(server_ip); let listen_result = listen(move server_ip_addr, server_port, 128, iotask, @@ -1855,7 +1887,7 @@ pub mod test { } fn run_tcp_test_server_fail(server_ip: &str, server_port: uint, - iotask: IoTask) -> TcpListenErrData { + iotask: &IoTask) -> TcpListenErrData { let server_ip_addr = ip::v4::parse_addr(server_ip); let listen_result = listen(move server_ip_addr, server_port, 128, iotask, @@ -1879,7 +1911,7 @@ pub mod test { fn run_tcp_test_client(server_ip: &str, server_port: uint, resp: &str, client_ch: oldcomm::Chan<~str>, - iotask: IoTask) -> result::Result<~str, + iotask: &IoTask) -> result::Result<~str, TcpConnectErrData> { let server_ip_addr = ip::v4::parse_addr(server_ip); diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 01b62797a8d76..59ba9ad61540d 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -22,7 +22,7 @@ extern "C" mod rusti { fn init() -> T; } -pub struct PriorityQueue { +pub struct PriorityQueue { priv data: ~[T], } diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index feabb678d6686..f17fce28ea93b 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -15,7 +15,7 @@ #[forbid(deprecated_mode)]; use map; -use map::Map; +use map::StdMap; use core::dvec::DVec; use core::ops; @@ -25,11 +25,11 @@ use core::prelude::*; // FIXME (#2347): Should not be @; there's a bug somewhere in rustc that // requires this to be. -struct SmallIntMap_ { +struct SmallIntMap_ { v: DVec>, } -pub enum SmallIntMap { +pub enum SmallIntMap { SmallIntMap_(@SmallIntMap_) } @@ -81,7 +81,7 @@ pub pure fn contains_key(self: SmallIntMap, key: uint) -> bool { } /// Implements the map::map interface for smallintmap -impl SmallIntMap: map::Map { +impl SmallIntMap: map::StdMap { pure fn size() -> uint { let mut sz = 0u; for self.v.each |item| { @@ -165,8 +165,8 @@ impl SmallIntMap: ops::Index { } /// Cast the given smallintmap to a map::map -pub fn as_map(s: SmallIntMap) -> map::Map { - s as map::Map:: +pub fn as_map(s: SmallIntMap) -> map::StdMap { + s as map::StdMap:: } #[cfg(test)] diff --git a/src/libstd/std.rc b/src/libstd/std.rc index eea9bd0a40f7a..f75715cfd6d90 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -32,6 +32,7 @@ not required in or otherwise suitable for the core library. // that can't be silenced otherwise. Most every module is set to forbid #[allow(deprecated_mode)]; #[forbid(deprecated_pattern)]; +#[allow(deprecated_self)]; #[no_core]; diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index 03ef98d09c5c0..6ded82d5ae4c4 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -83,7 +83,7 @@ struct SemInner { blocked: Q } #[doc(hidden)] -enum Sem = Exclusive>; +enum Sem = Exclusive>; #[doc(hidden)] fn new_sem(count: int, q: Q) -> Sem { @@ -167,7 +167,7 @@ impl &Sem<~[mut Waitqueue]> { #[doc(hidden)] type SemRelease = SemReleaseGeneric<()>; type SemAndSignalRelease = SemReleaseGeneric<~[mut Waitqueue]>; -struct SemReleaseGeneric { sem: &Sem } +struct SemReleaseGeneric { sem: &Sem } impl SemReleaseGeneric : Drop { fn finalize(&self) { diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index d0ca133b39e4a..c06d56165c8cc 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -39,7 +39,7 @@ use core; * * ch - a channel of type T to send a `val` on * * val - a value of type T to send over the provided `ch` */ -pub fn delayed_send(iotask: IoTask, +pub fn delayed_send(iotask: &IoTask, msecs: uint, ch: oldcomm::Chan, val: T) { @@ -92,7 +92,7 @@ pub fn delayed_send(iotask: IoTask, * * `iotask` - a `uv::iotask` that the tcp request will run on * * msecs - an amount of time, in milliseconds, for the current task to block */ -pub fn sleep(iotask: IoTask, msecs: uint) { +pub fn sleep(iotask: &IoTask, msecs: uint) { let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); delayed_send(iotask, msecs, exit_ch, ()); @@ -119,7 +119,7 @@ pub fn sleep(iotask: IoTask, msecs: uint) { * on the provided port in the allotted timeout period, then the result will * be a `Some(T)`. If not, then `None` will be returned. */ -pub fn recv_timeout(iotask: IoTask, +pub fn recv_timeout(iotask: &IoTask, msecs: uint, wait_po: oldcomm::Port) -> Option { @@ -183,13 +183,13 @@ mod test { #[test] fn test_gl_timer_simple_sleep_test() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); sleep(hl_loop, 1u); } #[test] fn test_gl_timer_sleep_stress1() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); for iter::repeat(50u) { sleep(hl_loop, 1u); } @@ -199,7 +199,7 @@ mod test { fn test_gl_timer_sleep_stress2() { let po = oldcomm::Port(); let ch = oldcomm::Chan(&po); - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let repeat = 20u; let spec = { @@ -214,11 +214,12 @@ mod test { for spec.each |spec| { let (times, maxms) = *spec; + let hl_loop_clone = hl_loop.clone(); do task::spawn { use rand::*; let rng = Rng(); for iter::repeat(times) { - sleep(hl_loop, rng.next() as uint % maxms); + sleep(&hl_loop_clone, rng.next() as uint % maxms); } oldcomm::send(ch, ()); } @@ -277,12 +278,12 @@ mod test { let expected = rand::Rng().gen_str(16u); let test_po = oldcomm::Port::<~str>(); let test_ch = oldcomm::Chan(&test_po); - + let hl_loop_clone = hl_loop.clone(); do task::spawn() { - delayed_send(hl_loop, 50u, test_ch, expected); + delayed_send(&hl_loop_clone, 50u, test_ch, expected); }; - match recv_timeout(hl_loop, 1u, test_po) { + match recv_timeout(&hl_loop, 1u, test_po) { None => successes += 1, _ => failures += 1 }; diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 36d919494f13d..5d0c83859f0a5 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -39,7 +39,7 @@ use core::prelude::*; // * symmetric difference: ^ // These would be convenient since the methods work like `each` -pub struct TreeMap { +pub struct TreeMap { priv root: Option<~TreeNode>, priv length: uint } @@ -167,7 +167,7 @@ impl TreeMap { } /// Lazy forward iterator over a map -pub struct TreeMapIterator { +pub struct TreeMapIterator { priv stack: ~[&~TreeNode], priv node: &Option<~TreeNode>, priv current: Option<&~TreeNode> @@ -205,7 +205,7 @@ impl TreeMapIterator { } } -pub struct TreeSet { +pub struct TreeSet { priv map: TreeMap } @@ -472,7 +472,7 @@ impl TreeSet { } /// Lazy forward iterator over a set -pub struct TreeSetIterator { +pub struct TreeSetIterator { priv iter: TreeMapIterator } @@ -494,7 +494,7 @@ impl TreeSetIterator { // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. -struct TreeNode { +struct TreeNode { key: K, value: V, left: Option<~TreeNode>, diff --git a/src/libstd/uv_global_loop.rs b/src/libstd/uv_global_loop.rs index 3a2c3b7c135e0..8ae3e24abee40 100644 --- a/src/libstd/uv_global_loop.rs +++ b/src/libstd/uv_global_loop.rs @@ -19,16 +19,16 @@ use uv_iotask::{IoTask, spawn_iotask}; use core::either::{Left, Right}; use core::libc; -use core::oldcomm::{Port, Chan, select2, listen}; -use core::private::{chan_from_global_ptr, weaken_task}; +use core::pipes::{Port, Chan, SharedChan, select2i}; +use core::private::global::{global_data_clone_create, + global_data_clone}; +use core::private::weak_task::weaken_task; use core::str; -use core::task::TaskBuilder; +use core::task::{task, SingleThreaded, spawn}; use core::task; use core::vec; - -extern mod rustrt { - unsafe fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t; -} +use core::clone::Clone; +use core::option::{Some, None}; /** * Race-free helper to get access to a global task where a libuv @@ -48,69 +48,64 @@ pub fn get() -> IoTask { #[doc(hidden)] fn get_monitor_task_gl() -> IoTask { - unsafe { - let monitor_loop_chan_ptr = - rustrt::rust_uv_get_kernel_global_chan_ptr(); - - debug!("ENTERING global_loop::get() loop chan: %?", - monitor_loop_chan_ptr); - - debug!("before priv::chan_from_global_ptr"); - type MonChan = Chan; - - let monitor_ch = - do chan_from_global_ptr::(monitor_loop_chan_ptr, - || { - task::task().sched_mode - (task::SingleThreaded) - .unlinked() - }) |msg_po| { - unsafe { - debug!("global monitor task starting"); - - // As a weak task the runtime will notify us when to exit - do weaken_task() |weak_exit_po| { - debug!("global monitor task is now weak"); - let hl_loop = spawn_loop(); - loop { - debug!("in outer_loop..."); - match select2(weak_exit_po, msg_po) { - Left(weak_exit) => { - // all normal tasks have ended, tell the - // libuv loop to tear_down, then exit - debug!("weak_exit_po recv'd msg: %?", weak_exit); - iotask::exit(hl_loop); - break; - } - Right(fetch_ch) => { - debug!("hl_loop req recv'd: %?", fetch_ch); - fetch_ch.send(hl_loop); - } - } + + type MonChan = Chan; + + struct GlobalIoTask(IoTask); + + impl GlobalIoTask: Clone { + fn clone(&self) -> GlobalIoTask { + GlobalIoTask((**self).clone()) + } + } + + fn key(_: GlobalIoTask) { } + + match unsafe { global_data_clone(key) } { + Some(GlobalIoTask(iotask)) => iotask, + None => { + let iotask: IoTask = spawn_loop(); + let mut installed = false; + let final_iotask = unsafe { + do global_data_clone_create(key) { + installed = true; + ~GlobalIoTask(iotask.clone()) + } + }; + if installed { + do task().unlinked().spawn() { + unsafe { + debug!("global monitor task starting"); + // As a weak task the runtime will notify us + // when to exit + do weaken_task |weak_exit_po| { + debug!("global monitor task is weak"); + weak_exit_po.recv(); + iotask::exit(&iotask); + debug!("global monitor task is unweak"); + }; + debug!("global monitor task exiting"); } - debug!("global monitor task is leaving weakend state"); - }; - debug!("global monitor task exiting"); + } + } else { + iotask::exit(&iotask); } - }; - // once we have a chan to the monitor loop, we ask it for - // the libuv loop's async handle - do listen |fetch_ch| { - monitor_ch.send(fetch_ch); - fetch_ch.recv() + match final_iotask { + GlobalIoTask(iotask) => iotask + } } } } fn spawn_loop() -> IoTask { - let builder = do task::task().add_wrapper |task_body| { + let builder = do task().add_wrapper |task_body| { fn~(move task_body) { // The I/O loop task also needs to be weak so it doesn't keep // the runtime alive unsafe { - do weaken_task |weak_exit_po| { - debug!("global libuv task is now weak %?", weak_exit_po); + do weaken_task |_| { + debug!("global libuv task is now weak"); task_body(); // We don't wait for the exit message on weak_exit_po @@ -122,6 +117,7 @@ fn spawn_loop() -> IoTask { } } }; + let builder = builder.unlinked(); spawn_iotask(move builder) } @@ -135,16 +131,18 @@ mod test { use core::iter; use core::libc; - use core::oldcomm; use core::ptr; use core::task; + use core::cast::transmute; + use core::libc::c_void; + use core::pipes::{stream, SharedChan, Chan}; extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) { unsafe { let exit_ch_ptr = ll::get_data_for_uv_handle( - timer_ptr as *libc::c_void) as *oldcomm::Chan; - let exit_ch = *exit_ch_ptr; - oldcomm::send(exit_ch, true); + timer_ptr as *libc::c_void); + let exit_ch = transmute::<*c_void, ~Chan>(exit_ch_ptr); + exit_ch.send(true); log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?", exit_ch_ptr)); @@ -155,26 +153,25 @@ mod test { unsafe { log(debug, ~"in simple timer cb"); ll::timer_stop(timer_ptr); - let hl_loop = get_gl(); + let hl_loop = &get_gl(); do iotask::interact(hl_loop) |_loop_ptr| { + log(debug, ~"closing timer"); unsafe { - log(debug, ~"closing timer"); 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, ~"about to deref exit_ch_ptr"); + log(debug, ~"after msg sent on deref'd exit_ch"); }; log(debug, ~"exiting simple timer cb"); } } - fn impl_uv_hl_simple_timer(iotask: IoTask) { + fn impl_uv_hl_simple_timer(iotask: &IoTask) { unsafe { - let exit_po = oldcomm::Port::(); - let exit_ch = oldcomm::Chan(&exit_po); - let exit_ch_ptr = ptr::addr_of(&exit_ch); + let (exit_po, exit_ch) = stream::(); + let exit_ch_ptr: *libc::c_void = transmute(~exit_ch); log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?", - exit_ch_ptr)); + exit_ch_ptr)); let timer_handle = ll::timer_t(); let timer_ptr = ptr::addr_of(&timer_handle); do iotask::interact(iotask) |loop_ptr| { @@ -184,20 +181,22 @@ mod test { if(init_status == 0i32) { ll::set_data_for_uv_handle( timer_ptr as *libc::c_void, - exit_ch_ptr as *libc::c_void); + exit_ch_ptr); let start_status = ll::timer_start(timer_ptr, simple_timer_cb, - 1u, - 0u); - if start_status != 0 { + 1u, 0u); + if(start_status == 0i32) { + } + else { fail ~"failure on ll::timer_start()"; } - } else { + } + else { fail ~"failure on ll::timer_init()"; } } }; - oldcomm::recv(exit_po); + exit_po.recv(); log(debug, ~"global_loop timer test: msg recv on exit_po, done.."); } @@ -205,17 +204,15 @@ mod test { #[test] fn test_gl_uv_global_loop_high_level_global_timer() { - unsafe { - let hl_loop = get_gl(); - let exit_po = oldcomm::Port::<()>(); - let exit_ch = oldcomm::Chan(&exit_po); - task::spawn_sched(task::ManualThreads(1u), || { - impl_uv_hl_simple_timer(hl_loop); - oldcomm::send(exit_ch, ()); - }); + let hl_loop = &get_gl(); + let (exit_po, exit_ch) = stream::<()>(); + task::spawn_sched(task::ManualThreads(1u), || { + let hl_loop = &get_gl(); impl_uv_hl_simple_timer(hl_loop); - oldcomm::recv(exit_po); - } + exit_ch.send(()); + }); + impl_uv_hl_simple_timer(hl_loop); + exit_po.recv(); } // keeping this test ignored until some kind of stress-test-harness @@ -223,23 +220,21 @@ mod test { #[test] #[ignore] fn test_stress_gl_uv_global_loop_high_level_global_timer() { - unsafe { - let hl_loop = get_gl(); - let exit_po = oldcomm::Port::<()>(); - let exit_ch = oldcomm::Chan(&exit_po); - let cycles = 5000u; - for iter::repeat(cycles) { - task::spawn_sched(task::ManualThreads(1u), || { - impl_uv_hl_simple_timer(hl_loop); - oldcomm::send(exit_ch, ()); - }); - }; - for iter::repeat(cycles) { - oldcomm::recv(exit_po); - }; - log(debug, - ~"test_stress_gl_uv_global_loop_high_level_global_timer"+ - ~" exiting sucessfully!"); - } + let (exit_po, exit_ch) = stream::<()>(); + let exit_ch = SharedChan(exit_ch); + let cycles = 5000u; + for iter::repeat(cycles) { + let exit_ch_clone = exit_ch.clone(); + task::spawn_sched(task::ManualThreads(1u), || { + let hl_loop = &get_gl(); + impl_uv_hl_simple_timer(hl_loop); + exit_ch_clone.send(()); + }); + }; + for iter::repeat(cycles) { + exit_po.recv(); + }; + log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+ + ~" exiting sucessfully!"); } } diff --git a/src/libstd/uv_iotask.rs b/src/libstd/uv_iotask.rs index 0a3d64a02a4ea..dc0092aadfaf2 100644 --- a/src/libstd/uv_iotask.rs +++ b/src/libstd/uv_iotask.rs @@ -20,7 +20,7 @@ use ll = uv_ll; use core::libc::c_void; use core::libc; -use core::oldcomm::{Port, Chan, listen}; +use core::pipes::{stream, Port, Chan, SharedChan}; use core::prelude::*; use core::ptr::addr_of; use core::task::TaskBuilder; @@ -30,22 +30,30 @@ use core::task; pub enum IoTask { IoTask_({ async_handle: *ll::uv_async_t, - op_chan: Chan + op_chan: SharedChan }) } +impl IoTask: Clone { + fn clone(&self) -> IoTask { + IoTask_({ + async_handle: self.async_handle, + op_chan: self.op_chan.clone() + }) + } +} + pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask { - do listen |iotask_ch| { + let (iotask_port, iotask_chan) = stream(); - do task.sched_mode(task::SingleThreaded).spawn { - debug!("entering libuv task"); - run_loop(iotask_ch); - debug!("libuv task exiting"); - }; + do task.sched_mode(task::SingleThreaded).spawn { + debug!("entering libuv task"); + run_loop(&iotask_chan); + debug!("libuv task exiting"); + }; - iotask_ch.recv() - } + iotask_port.recv() } @@ -71,7 +79,7 @@ pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask { * module. It is not safe to send the `loop_ptr` param to this callback out * via ports/chans. */ -pub unsafe fn interact(iotask: IoTask, +pub unsafe fn interact(iotask: &IoTask, cb: fn~(*c_void)) { send_msg(iotask, Interaction(move cb)); } @@ -83,7 +91,7 @@ pub unsafe fn interact(iotask: IoTask, * async handle and do a sanity check to make sure that all other handles are * closed, causing a failure otherwise. */ -pub fn exit(iotask: IoTask) { +pub fn exit(iotask: &IoTask) { unsafe { send_msg(iotask, TeardownLoop); } @@ -98,8 +106,10 @@ enum IoTaskMsg { } /// Run the loop and begin handling messages -fn run_loop(iotask_ch: Chan) { +fn run_loop(iotask_ch: &Chan) { + unsafe { + debug!("creating loop"); let loop_ptr = ll::loop_new(); // set up the special async handle we'll use to allow multi-task @@ -110,10 +120,12 @@ fn run_loop(iotask_ch: Chan) { // associate the async handle with the loop ll::async_init(loop_ptr, async_handle, wake_up_cb); + let (msg_po, msg_ch) = stream::(); + // initialize our loop data and store it in the loop - let data = IoTaskLoopData { + let data: IoTaskLoopData = IoTaskLoopData { async_handle: async_handle, - msg_po: Port() + msg_po: msg_po }; ll::set_data_for_uv_handle(async_handle, addr_of(&data)); @@ -121,7 +133,7 @@ fn run_loop(iotask_ch: Chan) { // while we dwell in the I/O loop let iotask = IoTask_({ async_handle: async_handle, - op_chan: data.msg_po.chan() + op_chan: SharedChan(msg_ch) }); iotask_ch.send(iotask); @@ -139,9 +151,10 @@ struct IoTaskLoopData { msg_po: Port, } -fn send_msg(iotask: IoTask, msg: IoTaskMsg) { +fn send_msg(iotask: &IoTask, + msg: IoTaskMsg) { + iotask.op_chan.send(move msg); unsafe { - iotask.op_chan.send(move msg); ll::async_send(iotask.async_handle); } } @@ -149,19 +162,20 @@ fn send_msg(iotask: IoTask, msg: IoTaskMsg) { /// Dispatch all pending messages extern fn wake_up_cb(async_handle: *ll::uv_async_t, status: int) { - unsafe { - log(debug, fmt!("wake_up_cb extern.. handle: %? status: %?", - async_handle, status)); + log(debug, fmt!("wake_up_cb extern.. handle: %? status: %?", + async_handle, status)); + + unsafe { let loop_ptr = ll::get_loop_for_uv_handle(async_handle); - let data = ll::get_data_for_uv_handle(async_handle) - as *IoTaskLoopData; - let msg_po = (*data).msg_po; + let data = + ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData; + let msg_po = &(*data).msg_po; while msg_po.peek() { match msg_po.recv() { - Interaction(ref cb) => (*cb)(loop_ptr), - TeardownLoop => begin_teardown(data) + Interaction(ref cb) => (*cb)(loop_ptr), + TeardownLoop => begin_teardown(data) } } } @@ -216,27 +230,32 @@ mod test { } struct AhData { iotask: IoTask, - exit_ch: oldcomm::Chan<()>, + exit_ch: oldcomm::Chan<()> } - fn impl_uv_iotask_async(iotask: IoTask) { + fn impl_uv_iotask_async(iotask: &IoTask) { unsafe { let async_handle = ll::async_t(); let ah_ptr = ptr::addr_of(&async_handle); let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); - let ah_data = { - iotask: iotask, + let ah_data = AhData { + iotask: iotask.clone(), exit_ch: exit_ch }; - let ah_data_ptr = ptr::addr_of(&ah_data); + let ah_data_ptr: *AhData = unsafe { + ptr::to_unsafe_ptr(&ah_data) + }; + debug!("about to interact"); do interact(iotask) |loop_ptr| { unsafe { + debug!("interacting"); 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::set_data_for_uv_handle( + ah_ptr, ah_data_ptr as *libc::c_void); ll::async_send(ah_ptr); } }; + debug!("waiting for async close"); oldcomm::recv(exit_po); } } @@ -244,13 +263,13 @@ mod test { // this fn documents the bear minimum neccesary to roll your own // high_level_loop unsafe fn spawn_test_loop(exit_ch: oldcomm::Chan<()>) -> IoTask { - let iotask_port = oldcomm::Port::(); - let iotask_ch = oldcomm::Chan(&iotask_port); + let (iotask_port, iotask_ch) = stream::(); do task::spawn_sched(task::ManualThreads(1u)) { - run_loop(iotask_ch); + debug!("about to run a test loop"); + run_loop(&iotask_ch); exit_ch.send(()); }; - return oldcomm::recv(iotask_port); + return iotask_port.recv(); } extern fn lifetime_handle_close(handle: *libc::c_void) { @@ -270,23 +289,30 @@ mod test { unsafe { let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); - let iotask = spawn_test_loop(exit_ch); + let iotask = &spawn_test_loop(exit_ch); + + debug!("spawned iotask"); // using this handle to manage the lifetime of the - // high_level_loop, as it will exit the first time one of the - // impl_uv_hl_async() is cleaned up with no one ref'd handles on - // the loop (Which can happen 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. + // high_level_loop, as it will exit the first time one of + // the impl_uv_hl_async() is cleaned up with no one ref'd + // handles on the loop (Which can happen 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 work_exit_po = oldcomm::Port::<()>(); let work_exit_ch = oldcomm::Chan(&work_exit_po); for iter::repeat(7u) { + let iotask_clone = iotask.clone(); do task::spawn_sched(task::ManualThreads(1u)) { - impl_uv_iotask_async(iotask); + debug!("async"); + impl_uv_iotask_async(&iotask_clone); + debug!("done async"); oldcomm::send(work_exit_ch, ()); }; }; for iter::repeat(7u) { + debug!("waiting"); oldcomm::recv(work_exit_po); }; log(debug, ~"sending teardown_loop msg.."); diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index fbd695aee762c..79a22f34d31f9 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -223,10 +223,17 @@ struct Exec { discovered_outputs: WorkMap } +#[cfg(stage0)] struct Work { prep: @Mut, res: Option>> } +#[cfg(stage1)] +#[cfg(stage2)] +struct Work { + prep: @Mut, + res: Option>> +} fn json_encode>(t: &T) -> ~str { do io::with_str_writer |wr| { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 65216e55493ce..502a372b330c3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -973,6 +973,12 @@ enum trait_method { #[auto_decode] enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, } +impl int_ty : ToStr { + pure fn to_str() -> ~str { + ::ast_util::int_ty_to_str(self) + } +} + impl int_ty : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) @@ -1003,6 +1009,12 @@ impl int_ty : cmp::Eq { #[auto_decode] enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, } +impl uint_ty : ToStr { + pure fn to_str() -> ~str { + ::ast_util::uint_ty_to_str(self) + } +} + impl uint_ty : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) @@ -1031,6 +1043,12 @@ impl uint_ty : cmp::Eq { #[auto_decode] enum float_ty { ty_f, ty_f32, ty_f64, } +impl float_ty : ToStr { + pure fn to_str() -> ~str { + ::ast_util::float_ty_to_str(self) + } +} + impl float_ty : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index ddd0f846f9d6c..201d53c0c3f36 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -12,7 +12,7 @@ use core::prelude::*; use ast::*; use ast; -use ast_util::{path_to_ident, stmt_id}; +use ast_util::{inlined_item_utils, path_to_ident, stmt_id}; use ast_util; use attr; use codemap; diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 23ea27e7c5cfc..7b134a8db2424 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -376,7 +376,7 @@ pure fn struct_field_visibility(field: ast::struct_field) -> visibility { } } -trait inlined_item_utils { +pub trait inlined_item_utils { fn ident() -> ident; fn id() -> ast::node_id; fn accept(e: E, v: visit::vt); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 7a7c2312f5640..7e3cbd18f5273 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -33,7 +33,7 @@ use core::uint; use core::vec; use std::serialize::{Encodable, Decodable, Encoder, Decoder}; -trait Pos { +pub trait Pos { static pure fn from_uint(n: uint) -> self; pure fn to_uint(&self) -> uint; } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 6112313cf4808..4c0cc161fdd03 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -10,7 +10,7 @@ use core::prelude::*; -use codemap::span; +use codemap::{Pos, span}; use codemap; use core::cmp; diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 77f230311358e..1bb516e831fd5 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -879,7 +879,7 @@ fn ser_variant( let pat_node = if pats.is_empty() { ast::pat_ident( - ast::bind_by_ref(ast::m_imm), + ast::bind_infer, cx.path(span, ~[v_name]), None ) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5a8a1d8753dee..5ff6953960619 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -267,8 +267,14 @@ fn mk_pat(cx: ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat { @ast::pat { id: cx.next_id(), node: pat, span: span } } fn mk_pat_ident(cx: ext_ctxt, span: span, ident: ast::ident) -> @ast::pat { + mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_value) +} +fn mk_pat_ident_with_binding_mode(cx: ext_ctxt, + span: span, + ident: ast::ident, + bm: ast::binding_mode) -> @ast::pat { let path = mk_raw_path(span, ~[ ident ]); - let pat = ast::pat_ident(ast::bind_by_value, path, None); + let pat = ast::pat_ident(bm, path, None); mk_pat(cx, span, move pat) } fn mk_pat_enum(cx: ext_ctxt, diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs index d7059fc197783..d542b104e541e 100644 --- a/src/libsyntax/ext/deriving.rs +++ b/src/libsyntax/ext/deriving.rs @@ -363,7 +363,8 @@ fn create_enum_variant_pattern(cx: ext_ctxt, match variant.node.kind { tuple_variant_kind(ref variant_args) => { if variant_args.len() == 0 { - return build::mk_pat_ident(cx, span, variant_ident); + return build::mk_pat_ident_with_binding_mode( + cx, span, variant_ident, ast::bind_infer); } let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index 343ce4b039b51..0433aab51fc3e 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -66,7 +66,7 @@ impl @ast::path: append_types { } } -trait ext_ctxt_ast_builder { +pub trait ext_ctxt_ast_builder { fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound]) -> ast::ty_param; fn arg(name: ident, ty: @ast::Ty) -> ast::arg; @@ -110,6 +110,7 @@ trait ext_ctxt_ast_builder { fn ty_option(ty: @ast::Ty) -> @ast::Ty; fn ty_infer() -> @ast::Ty; fn ty_nil_ast_builder() -> @ast::Ty; + fn strip_bounds(bounds: &[ast::ty_param]) -> ~[ast::ty_param]; } impl ext_ctxt: ext_ctxt_ast_builder { @@ -370,6 +371,12 @@ impl ext_ctxt: ext_ctxt_ast_builder { } } + fn strip_bounds(bounds: &[ast::ty_param]) -> ~[ast::ty_param] { + do bounds.map |ty_param| { + ast::ty_param { bounds: @~[], ..copy *ty_param } + } + } + fn item_ty_poly(name: ident, span: span, ty: @ast::Ty, diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs index 8eef065395e06..f91ec1ea48f85 100644 --- a/src/libsyntax/ext/pipes/mod.rs +++ b/src/libsyntax/ext/pipes/mod.rs @@ -49,6 +49,7 @@ use codemap::span; use ext::base; use ext::base::ext_ctxt; use ext::pipes::parse_proto::proto_parser; +use ext::pipes::pipec::gen_init; use ext::pipes::proto::{visit, protocol}; use parse::lexer::{new_tt_reader, reader}; use parse::parser::Parser; diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index e53057cb312e3..e7a8cbb9891f8 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -13,7 +13,8 @@ use ast::ident; use ast_util::dummy_sp; use ext::base::ext_ctxt; -use ext::pipes::ast_builder::{append_types, path, path_global}; +use ext::pipes::ast_builder::{append_types, ext_ctxt_ast_builder, path}; +use ext::pipes::ast_builder::{path_global}; use ext::pipes::proto::*; use ext::quote::rt::*; use parse::*; @@ -35,7 +36,7 @@ trait to_type_decls { fn to_endpoint_decls(cx: ext_ctxt, dir: direction) -> ~[@ast::item]; } -trait gen_init { +pub trait gen_init { fn gen_init(cx: ext_ctxt) -> @ast::item; fn compile(cx: ext_ctxt) -> @ast::item; fn buffer_ty_path(cx: ext_ctxt) -> @ast::Ty; @@ -247,7 +248,7 @@ impl state: to_type_decls { ast::enum_def(enum_def_ { variants: items_msg, common: None }), - self.ty_params + cx.strip_bounds(self.ty_params) ) ] } @@ -280,7 +281,7 @@ impl state: to_type_decls { self.data_name()], dummy_sp()) .add_tys(cx.ty_vars_global(self.ty_params))))), - self.ty_params)); + cx.strip_bounds(self.ty_params))); } else { items.push( @@ -298,7 +299,7 @@ impl state: to_type_decls { dummy_sp()) .add_tys(cx.ty_vars_global(self.ty_params))), self.proto.buffer_ty_path(cx)])), - self.ty_params)); + cx.strip_bounds(self.ty_params))); }; items } @@ -416,7 +417,7 @@ impl protocol: gen_init { cx.ident_of(~"__Buffer"), dummy_sp(), cx.ty_rec(fields), - params) + cx.strip_bounds(params)) } fn compile(cx: ext_ctxt) -> @ast::item { diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 26638cd8cd64f..9d24b3db72437 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -13,7 +13,7 @@ use core::prelude::*; use ast; use codemap::span; use ext::base::ext_ctxt; -use ext::pipes::ast_builder::{path, append_types}; +use ext::pipes::ast_builder::{append_types, ext_ctxt_ast_builder, path}; use core::cmp; use core::dvec::DVec; diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 3354d015476e5..7605e01fbf024 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -10,7 +10,7 @@ use ast; use attr; -use codemap::{span, BytePos}; +use codemap::{BytePos, Pos, span}; use ext::base::ext_ctxt; use ext::base; use ext::build; diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 3ade0bf86b122..4ecbbdc9760ba 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -9,7 +9,7 @@ // except according to those terms. use codemap; -use codemap::{span, Loc, FileMap}; +use codemap::{FileMap, Loc, Pos, span}; use ext::base::*; use ext::base; use ext::build::{mk_base_vec_e, mk_uint, mk_u8, mk_base_str}; diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 66c3111b30960..fbe258852e273 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -11,7 +11,7 @@ use core::prelude::*; use ast; -use codemap::{BytePos, CharPos, CodeMap, FileMap}; +use codemap::{BytePos, CharPos, CodeMap, FileMap, Pos}; use diagnostic; use parse::lexer::{is_whitespace, get_str_from, reader}; use parse::lexer::{string_reader, bump, is_eof, nextch}; diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 1574a037a4638..5a0f40f3c12f5 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -12,7 +12,7 @@ use core::prelude::*; use ast; use ast_util; -use codemap::{span, CodeMap, CharPos, BytePos}; +use codemap::{BytePos, CharPos, CodeMap, Pos, span}; use codemap; use diagnostic::span_handler; use ext::tt::transcribe::{tt_next_token}; diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 67f6c4bed3f95..86dea693f8af6 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -33,6 +33,7 @@ use core::str; use core::to_bytes; /// The specific types of unsupported syntax +#[deriving_eq] pub enum ObsoleteSyntax { ObsoleteLowerCaseKindBounds, ObsoleteLet, @@ -45,16 +46,8 @@ pub enum ObsoleteSyntax { ObsoleteModeInFnType, ObsoleteMoveInit, ObsoleteBinaryMove, - ObsoleteUnsafeBlock -} - -impl ObsoleteSyntax : cmp::Eq { - pure fn eq(&self, other: &ObsoleteSyntax) -> bool { - (*self) as uint == (*other) as uint - } - pure fn ne(&self, other: &ObsoleteSyntax) -> bool { - !(*self).eq(other) - } + ObsoleteUnsafeBlock, + ObsoleteUnenforcedBound } impl ObsoleteSyntax: to_bytes::IterBytes { @@ -123,6 +116,11 @@ impl Parser { ObsoleteUnsafeBlock => ( "non-standalone unsafe block", "use an inner `unsafe { ... }` block instead" + ), + ObsoleteUnenforcedBound => ( + "unenforced type parameter bound", + "use trait bounds on the functions that take the type as \ + arguments, not on the types themselves" ) }; diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 0777269f8f7fc..bccff550a435f 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -23,6 +23,7 @@ #[allow(non_camel_case_types)]; #[allow(deprecated_mode)]; #[warn(deprecated_pattern)]; +#[allow(deprecated_self)]; #[no_core]; diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index e4a09c3c349b8..9de875485db53 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -18,7 +18,7 @@ use core::dvec::DVec; use std::map::HashMap; use std::map; -type hash_interner = +type hash_interner = {map: HashMap, vect: DVec}; diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index f21a7441640c0..803da32cbc8ac 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -43,8 +43,8 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { rust_kernel *kernel = new rust_kernel(env); - // Create the main scheduler and the main task - rust_sched_id sched_id = kernel->create_scheduler(env->num_sched_threads); + // Create the main task + rust_sched_id sched_id = kernel->main_sched_id(); rust_scheduler *sched = kernel->get_scheduler_by_id(sched_id); assert(sched != NULL); rust_task *root_task = sched->create_task(NULL, "main"); diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index de69272aca174..4fcfc11b32568 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -652,7 +652,10 @@ new_task_common(rust_scheduler *sched, rust_task *parent) { extern "C" CDECL rust_task* new_task() { rust_task *task = rust_get_current_task(); - return new_task_common(task->sched, task); + rust_sched_id sched_id = task->kernel->main_sched_id(); + rust_scheduler *sched = task->kernel->get_scheduler_by_id(sched_id); + assert(sched != NULL && "should always have a main scheduler"); + return new_task_common(sched, task); } extern "C" CDECL rust_task* @@ -855,24 +858,6 @@ rust_compare_and_swap_ptr(intptr_t *address, return sync::compare_and_swap(address, oldval, newval); } -extern "C" CDECL void -rust_task_weaken(rust_port_id chan) { - rust_task *task = rust_get_current_task(); - task->kernel->weaken_task(chan); -} - -extern "C" CDECL void -rust_task_unweaken(rust_port_id chan) { - rust_task *task = rust_get_current_task(); - 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(); -} - extern "C" void rust_task_inhibit_kill(rust_task *task) { task->inhibit_kill(); @@ -1023,6 +1008,29 @@ rust_raw_thread_join_delete(raw_thread *thread) { delete thread; } +extern "C" void +rust_register_exit_function(spawn_fn runner, fn_env_pair *f) { + rust_task *task = rust_get_current_task(); + task->kernel->register_exit_function(runner, f); +} + +extern "C" void * +rust_get_global_data_ptr() { + rust_task *task = rust_get_current_task(); + return &task->kernel->global_data; +} + +extern "C" void +rust_inc_weak_task_count() { + rust_task *task = rust_get_current_task(); + task->kernel->inc_weak_task_count(); +} + +extern "C" void +rust_dec_weak_task_count() { + rust_task *task = rust_get_current_task(); + task->kernel->dec_weak_task_count(); +} // // Local Variables: diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 8871d133ea1b2..c365f3cca1ef4 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -30,21 +30,29 @@ rust_kernel::rust_kernel(rust_env *env) : rval(0), max_sched_id(1), killed(false), + already_exiting(false), sched_reaper(this), osmain_driver(NULL), non_weak_tasks(0), - global_loop_chan(0), - global_env_chan(0), - env(env) - + at_exit_runner(NULL), + at_exit_started(false), + env(env), + global_data(0) { - // Create the single threaded scheduler that will run on the platform's // main thread - rust_manual_sched_launcher_factory *launchfac = + rust_manual_sched_launcher_factory *osmain_launchfac = new rust_manual_sched_launcher_factory(); - osmain_scheduler = create_scheduler(launchfac, 1, false); - osmain_driver = launchfac->get_driver(); + osmain_scheduler = create_scheduler(osmain_launchfac, 1, false); + osmain_driver = osmain_launchfac->get_driver(); + + // Create the primary scheduler + rust_thread_sched_launcher_factory *main_launchfac = + new rust_thread_sched_launcher_factory(); + main_scheduler = create_scheduler(main_launchfac, + env->num_sched_threads, + false); + sched_reaper.start(); } @@ -103,15 +111,22 @@ rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, { scoped_lock with(sched_lock); + /*if (sched_table.size() == 2) { + // The main and OS main schedulers may not exit while there are + // other schedulers + KLOG_("Disallowing main scheduler to exit"); + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->disallow_exit(); + } if (sched_table.size() == 1) { - // The OS main scheduler may not exit while there are other - // schedulers KLOG_("Disallowing osmain scheduler to exit"); - rust_scheduler *sched = + rust_scheduler *osmain_sched = get_scheduler_by_id_nolock(osmain_scheduler); - assert(sched != NULL); - sched->disallow_exit(); - } + assert(osmain_sched != NULL); + osmain_sched->disallow_exit(); + }*/ id = max_sched_id++; assert(id != INTPTR_MAX && "Hit the maximum scheduler id"); @@ -175,14 +190,21 @@ rust_kernel::wait_for_schedulers() sched_table.erase(iter); sched->join_task_threads(); sched->deref(); + /*if (sched_table.size() == 2) { + KLOG_("Allowing main scheduler to exit"); + // It's only the main schedulers left. Tell them to exit + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->allow_exit(); + } if (sched_table.size() == 1) { KLOG_("Allowing osmain scheduler to exit"); - // It's only the osmain scheduler left. Tell it to exit - rust_scheduler *sched = + rust_scheduler *osmain_sched = get_scheduler_by_id_nolock(osmain_scheduler); - assert(sched != NULL); - sched->allow_exit(); - } + assert(osmain_sched != NULL); + osmain_sched->allow_exit(); + }*/ } if (!sched_table.empty()) { sched_lock.wait(); @@ -318,60 +340,64 @@ rust_kernel::register_task() { KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); } +void +rust_kernel::allow_scheduler_exit() { + scoped_lock with(sched_lock); + + KLOG_("Allowing main scheduler to exit"); + // It's only the main schedulers left. Tell them to exit + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->allow_exit(); + + KLOG_("Allowing osmain scheduler to exit"); + rust_scheduler *osmain_sched = + get_scheduler_by_id_nolock(osmain_scheduler); + assert(osmain_sched != NULL); + osmain_sched->allow_exit(); +} + void rust_kernel::unregister_task() { KLOG_("Unregistering task"); uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); if (new_non_weak_tasks == 0) { - end_weak_tasks(); + begin_shutdown(); } } void -rust_kernel::weaken_task(rust_port_id chan) { - { - scoped_lock with(weak_task_lock); - KLOG_("Weakening task with channel %" PRIdPTR, chan); - weak_task_chans.push_back(chan); - } +rust_kernel::inc_weak_task_count() { uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); if (new_non_weak_tasks == 0) { - end_weak_tasks(); + begin_shutdown(); } } void -rust_kernel::unweaken_task(rust_port_id chan) { +rust_kernel::dec_weak_task_count() { uintptr_t new_non_weak_tasks = sync::increment(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); - { - scoped_lock with(weak_task_lock); - KLOG_("Unweakening task with channel %" PRIdPTR, chan); - std::vector::iterator iter = - std::find(weak_task_chans.begin(), weak_task_chans.end(), chan); - if (iter != weak_task_chans.end()) { - weak_task_chans.erase(iter); - } - } } void -rust_kernel::end_weak_tasks() { - std::vector chancopies; +rust_kernel::begin_shutdown() { { - scoped_lock with(weak_task_lock); - chancopies = weak_task_chans; - weak_task_chans.clear(); - } - while (!chancopies.empty()) { - rust_port_id chan = chancopies.back(); - chancopies.pop_back(); - KLOG_("Notifying weak task " PRIdPTR, chan); - uintptr_t token = 0; - send_to_port(chan, &token); + scoped_lock with(sched_lock); + // FIXME #4410: This shouldn't be necessary, but because of + // unweaken_task this may end up getting called multiple times. + if (already_exiting) { + return; + } else { + already_exiting = true; + } } + + run_exit_functions(); + allow_scheduler_exit(); } bool @@ -389,6 +415,47 @@ rust_kernel::send_to_port(rust_port_id chan, void *sptr) { } } +void +rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) { + scoped_lock with(at_exit_lock); + + assert(!at_exit_started && "registering at_exit function after exit"); + + if (at_exit_runner) { + assert(runner == at_exit_runner + && "there can be only one at_exit_runner"); + } + + at_exit_runner = runner; + at_exit_fns.push_back(f); +} + +void +rust_kernel::run_exit_functions() { + rust_task *task; + + { + scoped_lock with(at_exit_lock); + + assert(!at_exit_started && "running exit functions twice?"); + + at_exit_started = true; + + if (at_exit_runner == NULL) { + return; + } + + rust_scheduler *sched = get_scheduler_by_id(main_sched_id()); + assert(sched); + task = sched->create_task(NULL, "at_exit"); + + final_exit_fns.count = at_exit_fns.size(); + final_exit_fns.start = at_exit_fns.data(); + } + + task->start(at_exit_runner, NULL, &final_exit_fns); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 48522b57d5c0d..a7c6249e3dbf8 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -49,6 +49,7 @@ #include "memory_region.h" #include "rust_log.h" #include "rust_sched_reaper.h" +#include "rust_type.h" #include "util/hash_map.h" class rust_scheduler; @@ -65,6 +66,13 @@ typedef intptr_t rust_port_id; typedef std::map sched_map; +// This is defined as a struct only because we need a single pointer to pass +// to the Rust function that runs the at_exit functions +struct exit_functions { + size_t count; + fn_env_pair **start; +}; + class rust_kernel { memory_region _region; rust_log _log; @@ -81,7 +89,8 @@ class rust_kernel { lock_and_signal rval_lock; int rval; - // Protects max_sched_id and sched_table, join_list, killed + // Protects max_sched_id and sched_table, join_list, killed, + // already_exiting lock_and_signal sched_lock; // The next scheduler id rust_sched_id max_sched_id; @@ -94,8 +103,13 @@ class rust_kernel { // task group fails). This propagates to all new schedulers and tasks // created after it is set. bool killed; + bool already_exiting; + rust_sched_reaper sched_reaper; + + // The primary scheduler + rust_sched_id main_scheduler; // The single-threaded scheduler that uses the main thread rust_sched_id osmain_scheduler; // Runs the single-threaded scheduler that executes tasks @@ -104,21 +118,22 @@ class rust_kernel { // An atomically updated count of the live, 'non-weak' tasks uintptr_t non_weak_tasks; - // Protects weak_task_chans - lock_and_signal weak_task_lock; - // A list of weak tasks that need to be told when to exit - std::vector weak_task_chans; rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id); - void end_weak_tasks(); + void allow_scheduler_exit(); + void begin_shutdown(); + + lock_and_signal at_exit_lock; + spawn_fn at_exit_runner; + bool at_exit_started; + std::vector at_exit_fns; + exit_functions final_exit_fns; - // Used to communicate with the process-side, global libuv loop - uintptr_t global_loop_chan; - // Used to serialize access to getenv/setenv - uintptr_t global_env_chan; + void run_exit_functions(); public: struct rust_env *env; + uintptr_t global_data; rust_kernel(rust_env *env); @@ -154,17 +169,17 @@ class rust_kernel { void set_exit_status(int code); + rust_sched_id main_sched_id() { return main_scheduler; } rust_sched_id osmain_sched_id() { return osmain_scheduler; } void register_task(); void unregister_task(); - void weaken_task(rust_port_id chan); - void unweaken_task(rust_port_id chan); + void inc_weak_task_count(); + void dec_weak_task_count(); bool send_to_port(rust_port_id chan, void *sptr); - uintptr_t* get_global_loop() { return &global_loop_chan; } - uintptr_t* get_global_env_chan() { return &global_env_chan; } + void register_exit_function(spawn_fn runner, fn_env_pair *f); }; template struct kernel_owned { diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 53d8177bcf82f..2dc70088628f6 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -513,15 +513,6 @@ rust_uv_ip6_port(struct sockaddr_in6* src) { return ntohs(src->sin6_port); } -extern "C" uintptr_t* -rust_uv_get_kernel_global_chan_ptr() { - uintptr_t* result = rust_get_current_task()->kernel->get_global_loop(); - rust_task* task = rust_get_current_task(); - LOG(task, stdlib, "global loop: %lu", (unsigned long int)result); - LOG(task, stdlib,"global loop val: %lu", (unsigned long int)*result); - return result; -} - extern "C" void* rust_uv_current_kernel_malloc(size_t size) { return current_kernel_malloc(size, "rust_uv_current_kernel_malloc"); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index cce4e411e02c7..eb9db6c1d5755 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -61,8 +61,6 @@ rust_task_yield rust_task_is_unwinding rust_get_task rust_get_stack_segment -rust_task_weaken -rust_task_unweaken rust_log_str start_task vec_reserve_shared_actual @@ -158,7 +156,6 @@ rust_uv_get_data_for_req rust_uv_set_data_for_req rust_uv_get_base_from_buf rust_uv_get_len_from_buf -rust_uv_get_kernel_global_chan_ptr rust_uv_current_kernel_malloc rust_uv_current_kernel_free rust_uv_getaddrinfo @@ -174,7 +171,6 @@ rust_dbg_do_nothing rust_dbg_breakpoint rust_osmain_sched_id rust_compare_and_swap_ptr -rust_global_env_chan_ptr rust_port_take rust_port_drop rust_port_task @@ -210,3 +206,7 @@ linenoiseHistorySave linenoiseHistoryLoad rust_raw_thread_start rust_raw_thread_join_delete +rust_register_exit_function +rust_get_global_data_ptr +rust_inc_weak_task_count +rust_dec_weak_task_count \ No newline at end of file diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index a14cc3758b19b..fc5cf1275183b 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -17,7 +17,7 @@ extern mod std; export context; -struct arc_destruct { +struct arc_destruct { _data: int, } diff --git a/src/test/auxiliary/issue_2242_b.rs b/src/test/auxiliary/issue_2242_b.rs deleted file mode 100644 index 73ec1f47230fe..0000000000000 --- a/src/test/auxiliary/issue_2242_b.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[link(name = "b", vers = "0.1")]; -#[crate_type = "lib"]; - -extern mod a; -use a::to_strz; - -impl int: to_strz { - fn to_strz() -> ~str { fmt!("%?", self) } -} diff --git a/src/test/auxiliary/test_comm.rs b/src/test/auxiliary/test_comm.rs index af321b9959f2b..6fd39368baecd 100644 --- a/src/test/auxiliary/test_comm.rs +++ b/src/test/auxiliary/test_comm.rs @@ -24,7 +24,7 @@ use core::libc::size_t; * transmitted. If a port value is copied, both copies refer to the same * port. Ports may be associated with multiple `chan`s. */ -pub enum port { +pub enum port { port_t(@port_ptr) } @@ -35,7 +35,7 @@ pub fn port() -> port { } } -struct port_ptr { +struct port_ptr { po: *rust_port, } diff --git a/src/test/bench/task-perf-word-count-generic.rs b/src/test/bench/task-perf-word-count-generic.rs index a817414314600..b617f6acec6e5 100644 --- a/src/test/bench/task-perf-word-count-generic.rs +++ b/src/test/bench/task-perf-word-count-generic.rs @@ -120,15 +120,15 @@ mod map_reduce { use std::map::HashMap; use std::map; - pub type putter = fn(&K, V); + pub type putter = fn(&K, V); - pub type mapper = fn~(K1, putter); + pub type mapper = fn~(K1, putter); - pub type getter = fn() -> Option; + pub type getter = fn() -> Option; - pub type reducer = fn~(&K, getter); + pub type reducer = fn~(&K, getter); - enum ctrl_proto { + enum ctrl_proto { find_reducer(K, Chan>>), mapper_done } @@ -146,7 +146,7 @@ mod map_reduce { } ) - pub enum reduce_proto { + pub enum reduce_proto { emit_val(V), done, addref, diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs index 839d4137ba923..19cdfe784d2b0 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs @@ -16,9 +16,9 @@ use std::map; fn main() { let buggy_map :HashMap = HashMap::(); - buggy_map.insert(42, ~1); //~ ERROR illegal borrow - + buggy_map.insert(42, &*~1); //~ ERROR illegal borrow + // but it is ok if we use a temporary let tmp = ~2; - buggy_map.insert(43, tmp); + buggy_map.insert(43, &*tmp); } diff --git a/src/test/compile-fail/alt-vec-illegal-tail-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs similarity index 67% rename from src/test/compile-fail/alt-vec-illegal-tail-loan.rs rename to src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index 01f2707721677..358917de85fb9 100644 --- a/src/test/compile-fail/alt-vec-illegal-tail-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -1,9 +1,7 @@ -// xfail-test - fn a() -> &[int] { let vec = [1, 2, 3, 4]; - let tail = match vec { - [_a, ..tail] => tail, //~ ERROR illegal borrow + let tail = match vec { //~ ERROR illegal borrow + [_a, ..tail] => tail, _ => fail ~"foo" }; move tail diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs new file mode 100644 index 0000000000000..27902100373a9 --- /dev/null +++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs @@ -0,0 +1,12 @@ +fn a() { + let mut v = ~[1, 2, 3]; + match v { + [_a, ..tail] => { + v.push(tail[0] + tail[1]); //~ ERROR conflicts with prior loan + } + _ => {} + }; +} + +fn main() {} + diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs new file mode 100644 index 0000000000000..50feff707adfa --- /dev/null +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -0,0 +1,21 @@ +fn a() { + let mut vec = [~1, ~2, ~3]; + match vec { + [~ref _a] => { + vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + } + _ => fail ~"foo" + } +} + +fn b() { + let mut vec = [~1, ~2, ~3]; + match vec { + [.._b] => { + vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + } + } +} + +fn main() {} + diff --git a/src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs similarity index 65% rename from src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs rename to src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index 36d019058ae79..6477fd9fb2cf9 100644 --- a/src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -1,7 +1,7 @@ fn a() -> &int { let vec = [1, 2, 3, 4]; - let tail = match vec { - [_a, ..tail] => &tail[0], //~ ERROR illegal borrow + let tail = match vec { //~ ERROR illegal borrow + [_a, ..tail] => &tail[0], _ => fail ~"foo" }; move tail diff --git a/src/test/compile-fail/coerce-bad-variance.rs b/src/test/compile-fail/coerce-bad-variance.rs new file mode 100644 index 0000000000000..c4cdbcb67e2be --- /dev/null +++ b/src/test/compile-fail/coerce-bad-variance.rs @@ -0,0 +1,17 @@ +fn mutate(x: &mut @const int) { + *x = @3; +} + +fn give_away1(y: @mut @mut int) { + mutate(y); //~ ERROR values differ in mutability +} + +fn give_away2(y: @mut @const int) { + mutate(y); +} + +fn give_away3(y: @mut @int) { + mutate(y); //~ ERROR values differ in mutability +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index 95512a2da6068..6988027235074 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -11,6 +11,7 @@ type Foo = @[u8]; impl Foo : Drop { //~ ERROR the Drop trait may only be implemented +//~^ ERROR cannot provide an extension implementation fn finalize(&self) { io::println("kaboom"); } diff --git a/src/test/compile-fail/issue-2718-a.rs b/src/test/compile-fail/issue-2718-a.rs index 2332d54037fbd..925350d9b8804 100644 --- a/src/test/compile-fail/issue-2718-a.rs +++ b/src/test/compile-fail/issue-2718-a.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub struct send_packet { +pub struct send_packet { p: T } diff --git a/src/test/compile-fail/issue-4500.rs b/src/test/compile-fail/issue-4500.rs index 83938293d7548..356a64498219a 100644 --- a/src/test/compile-fail/issue-4500.rs +++ b/src/test/compile-fail/issue-4500.rs @@ -10,6 +10,5 @@ fn main () { let mut _p: & int = & 4; - _p = ~3; //~ ERROR illegal borrow: borrowed value does not live long enough - //~^ NOTE ...but borrowed value is only valid for the statement + _p = &*~3; //~ ERROR illegal borrow } diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index c7c6aec9f1df8..69f07e3e77492 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -20,11 +20,12 @@ fn repeater(v: @A) -> repeat { } fn main() { - // Here, an error results as the type of y is inferred to - // repeater<</3> where lt is the block. - let y = { - let x: &blk/int = &3; //~ ERROR cannot infer an appropriate lifetime + // Error results because the type of is inferred to be + // repeat<&blk/int> where blk is the lifetime of the block below. + + let y = { //~ ERROR reference is not valid + let x: &blk/int = &3; repeater(@x) }; - assert 3 == *(y.get()); + assert 3 == *(y.get()); //~ ERROR reference is not valid } \ No newline at end of file diff --git a/src/test/compile-fail/lint-default-methods.rs b/src/test/compile-fail/lint-default-methods.rs index 6b71f9e972fb2..1350c3e3ad1cd 100644 --- a/src/test/compile-fail/lint-default-methods.rs +++ b/src/test/compile-fail/lint-default-methods.rs @@ -1,7 +1,7 @@ #[forbid(default_methods)]; trait Foo { //~ ERROR default methods are experimental - fn bar() { io::println("hi"); } + fn bar(&self) { io::println("hi"); } } fn main() {} diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index 89377eb3d152a..7161e85444792 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -11,12 +11,13 @@ extern mod std; use std::map; use std::map::HashMap; -use std::map::Map; +use std::map::StdMap; // Test that trait types printed in error msgs include the type arguments. fn main() { - let x: Map<~str,~str> = map::HashMap::<~str,~str>() as Map::<~str,~str>; - let y: Map = x; - //~^ ERROR mismatched types: expected `@std::map::Map` + let x: StdMap<~str,~str> = map::HashMap::<~str,~str>() as + StdMap::<~str,~str>; + let y: StdMap = x; + //~^ ERROR mismatched types: expected `@std::map::StdMap` } diff --git a/src/test/compile-fail/regions-scoping.rs b/src/test/compile-fail/regions-scoping.rs index 1f59e9a8128cc..f999242973345 100644 --- a/src/test/compile-fail/regions-scoping.rs +++ b/src/test/compile-fail/regions-scoping.rs @@ -25,8 +25,7 @@ fn nested(x: &x/int) { // (1) //~^ ERROR cannot infer an appropriate lifetime return z(y, x, x); - //~^ ERROR mismatched types: expected `&x/int` but found `&y/int` - //~^^ ERROR mismatched types: expected `&y/int` but found `&x/int` + //~^ ERROR cannot infer an appropriate lifetime } ) |foo| { diff --git a/src/test/run-fail/bug-811.rs b/src/test/run-fail/bug-811.rs index 739bf097d4fda..31158df4185f7 100644 --- a/src/test/run-fail/bug-811.rs +++ b/src/test/run-fail/bug-811.rs @@ -14,7 +14,7 @@ fn test00_start(ch: chan_t, message: int) { send(ch, message); } type task_id = int; type port_id = int; -enum chan_t = {task: task_id, port: port_id}; +enum chan_t = {task: task_id, port: port_id}; fn send(ch: chan_t, data: T) { fail; } diff --git a/src/test/run-fail/issue-2444.rs b/src/test/run-fail/issue-2444.rs index b1d8c99faa519..9172364a2f916 100644 --- a/src/test/run-fail/issue-2444.rs +++ b/src/test/run-fail/issue-2444.rs @@ -13,7 +13,7 @@ extern mod std; use std::arc; -enum e { e(arc::ARC) } +enum e { e(arc::ARC) } fn foo() -> e {fail;} diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index 6ea08d200e77d..ee8cf89d528a5 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -128,21 +128,13 @@ impl CLike : cmp::Eq { #[auto_encode] #[auto_decode] +#[deriving_eq] struct Spanned { lo: uint, hi: uint, node: T, } -impl Spanned : cmp::Eq { - pure fn eq(&self, other: &Spanned) -> bool { - self.lo == other.lo && - self.hi == other.hi && - self.node == other.node - } - pure fn ne(&self, other: &Spanned) -> bool { !self.eq(other) } -} - #[auto_encode] #[auto_decode] struct SomeStruct { v: ~[uint] } diff --git a/src/test/run-pass/box-unbox.rs b/src/test/run-pass/box-unbox.rs index 3558501471318..ad32ffc75c9c1 100644 --- a/src/test/run-pass/box-unbox.rs +++ b/src/test/run-pass/box-unbox.rs @@ -10,7 +10,7 @@ -struct Box {c: @T} +struct Box {c: @T} fn unbox(b: Box) -> T { return *b.c; } diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index b802b9708923e..bccb42c493892 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -27,7 +27,7 @@ impl cat_type : cmp::Eq { // for any int value that's less than the meows field // ok: T should be in scope when resolving the trait ref for map -struct cat { +struct cat { // Yes, you can have negative meows priv mut meows : int, @@ -51,7 +51,7 @@ impl cat { } } -impl cat : Map { +impl cat : StdMap { pure fn size() -> uint { self.meows as uint } fn insert(+k: int, +_v: T) -> bool { self.meows += k; diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs new file mode 100644 index 0000000000000..3c9748f29d986 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs @@ -0,0 +1,17 @@ +pure fn negate(x: &int) -> int { + -*x +} + +fn negate_mut(y: &mut int) -> int { + negate(y) +} + +fn negate_imm(y: &int) -> int { + negate(y) +} + +fn negate_const(y: &const int) -> int { + negate(y) +} + +fn main() {} diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs new file mode 100644 index 0000000000000..0d8f40677f8b8 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs @@ -0,0 +1,16 @@ +struct SpeechMaker { + speeches: uint +} + +impl SpeechMaker { + pure fn how_many(&self) -> uint { self.speeches } +} + +fn foo(speaker: &const SpeechMaker) -> uint { + speaker.how_many() + 33 +} + +fn main() { + let mut lincoln = SpeechMaker {speeches: 22}; + assert foo(&const lincoln) == 55; +} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs new file mode 100644 index 0000000000000..54a6b35b8baa7 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs @@ -0,0 +1,19 @@ +pure fn sum(x: &[int]) -> int { + let mut sum = 0; + for x.each |y| { sum += *y; } + return sum; +} + +fn sum_mut(y: &[mut int]) -> int { + sum(y) +} + +fn sum_imm(y: &[int]) -> int { + sum(y) +} + +fn sum_const(y: &[const int]) -> int { + sum(y) +} + +fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs new file mode 100644 index 0000000000000..24fb5cbd88301 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -0,0 +1,18 @@ +fn foo(v: &[const uint]) -> ~[uint] { + v.to_vec() +} + +fn bar(v: &[mut uint]) -> ~[uint] { + v.to_vec() +} + +fn bip(v: &[uint]) -> ~[uint] { + v.to_vec() +} + +fn main() { + let mut the_vec = ~[1, 2, 3, 100]; + assert the_vec == foo(the_vec); + assert the_vec == bar(the_vec); + assert the_vec == bip(the_vec); +} diff --git a/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs b/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs new file mode 100644 index 0000000000000..4579907dfbd49 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs @@ -0,0 +1,22 @@ +struct SpeechMaker { + speeches: uint +} + +fn talk(x: &mut SpeechMaker) { + x.speeches += 1; +} + +fn give_a_few_speeches(speaker: &mut SpeechMaker) { + + // Here speaker is reborrowed for each call, so we don't get errors + // about speaker being moved. + + talk(speaker); + talk(speaker); + talk(speaker); +} + +fn main() { + let mut lincoln = SpeechMaker {speeches: 22}; + give_a_few_speeches(&mut lincoln); +} diff --git a/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs new file mode 100644 index 0000000000000..c915c01416e8e --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs @@ -0,0 +1,24 @@ +struct SpeechMaker { + speeches: uint +} + +impl SpeechMaker { + fn talk(&mut self) { + self.speeches += 1; + } +} + +fn give_a_few_speeches(speaker: &mut SpeechMaker) { + + // Here speaker is reborrowed for each call, so we don't get errors + // about speaker being moved. + + speaker.talk(); + speaker.talk(); + speaker.talk(); +} + +fn main() { + let mut lincoln = SpeechMaker {speeches: 22}; + give_a_few_speeches(&mut lincoln); +} diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs new file mode 100644 index 0000000000000..0cce52e7dc8d3 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs @@ -0,0 +1,15 @@ +trait Reverser { + fn reverse(&self); +} + +fn bar(v: &[mut uint]) { + vec::reverse(v); + vec::reverse(v); + vec::reverse(v); +} + +fn main() { + let mut the_vec = ~[1, 2, 3, 100]; + bar(the_vec); + assert the_vec == ~[100, 3, 2, 1]; +} diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs new file mode 100644 index 0000000000000..9fb748f049fd6 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -0,0 +1,21 @@ +trait Reverser { + fn reverse(&self); +} + +impl &[mut uint] : Reverser { + fn reverse(&self) { + vec::reverse(*self); + } +} + +fn bar(v: &[mut uint]) { + v.reverse(); + v.reverse(); + v.reverse(); +} + +fn main() { + let mut the_vec = ~[1, 2, 3, 100]; + bar(the_vec); + assert the_vec == ~[100, 3, 2, 1]; +} diff --git a/src/test/run-pass/generic-exterior-box.rs b/src/test/run-pass/generic-exterior-box.rs index 738bb73b0be4f..c2abcc7528300 100644 --- a/src/test/run-pass/generic-exterior-box.rs +++ b/src/test/run-pass/generic-exterior-box.rs @@ -10,7 +10,7 @@ -struct Recbox {x: @T} +struct Recbox {x: @T} fn reclift(t: T) -> Recbox { return Recbox {x: @t}; } diff --git a/src/test/run-pass/generic-exterior-unique.rs b/src/test/run-pass/generic-exterior-unique.rs index 2095578aefad8..a4a576abc758c 100644 --- a/src/test/run-pass/generic-exterior-unique.rs +++ b/src/test/run-pass/generic-exterior-unique.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Recbox {x: ~T} +struct Recbox {x: ~T} fn reclift(t: T) -> Recbox { return Recbox {x: ~t}; } diff --git a/src/test/run-pass/issue-2242-d.rs b/src/test/run-pass/issue-2242-d.rs deleted file mode 100644 index 006a33ebb65ed..0000000000000 --- a/src/test/run-pass/issue-2242-d.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-fast (aux-build) -// aux-build:issue_2242_a.rs -// aux-build:issue_2242_b.rs -// aux-build:issue_2242_c.rs - -extern mod a; -extern mod b; -extern mod c; - -use a::to_strz; - -fn main() { - io::println((~"foo").to_strz()); - io::println(1.to_strz()); - io::println(true.to_strz()); -} diff --git a/src/test/run-pass/issue-2288.rs b/src/test/run-pass/issue-2288.rs index 52b3baba58e36..0fa06e2f2129b 100644 --- a/src/test/run-pass/issue-2288.rs +++ b/src/test/run-pass/issue-2288.rs @@ -11,7 +11,7 @@ trait clam { fn chowder(y: A); } -struct foo { +struct foo { x: A, } diff --git a/src/test/run-pass/issue-2311-2.rs b/src/test/run-pass/issue-2311-2.rs index 10befa7422836..21201d0a95705 100644 --- a/src/test/run-pass/issue-2311-2.rs +++ b/src/test/run-pass/issue-2311-2.rs @@ -9,7 +9,7 @@ // except according to those terms. trait clam { } -struct foo { +struct foo { x: A, } diff --git a/src/test/run-pass/issue-2445-b.rs b/src/test/run-pass/issue-2445-b.rs index 35d3d0897098b..f1b7d45e440ec 100644 --- a/src/test/run-pass/issue-2445-b.rs +++ b/src/test/run-pass/issue-2445-b.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct c1 { +struct c1 { x: T, } diff --git a/src/test/run-pass/issue-2445.rs b/src/test/run-pass/issue-2445.rs index 7cf681c9f94ef..fada6a7b02e11 100644 --- a/src/test/run-pass/issue-2445.rs +++ b/src/test/run-pass/issue-2445.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct c1 { +struct c1 { x: T, } diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index f8f2fc461c3ff..68a318eab4e3e 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -34,7 +34,7 @@ pub mod pipes { pure fn ne(&self, other: &state) -> bool { !(*self).eq(other) } } - pub type packet = { + pub type packet = { mut state: state, mut blocked_task: Option, mut payload: Option @@ -157,7 +157,7 @@ pub mod pipes { } } - pub struct send_packet { + pub struct send_packet { mut p: Option<*packet>, } @@ -185,7 +185,7 @@ pub mod pipes { } } - pub struct recv_packet { + pub struct recv_packet { mut p: Option<*packet>, } diff --git a/src/test/run-pass/issue-3026.rs b/src/test/run-pass/issue-3026.rs index 04932676f3d63..8a7ebb8d129e0 100644 --- a/src/test/run-pass/issue-3026.rs +++ b/src/test/run-pass/issue-3026.rs @@ -17,5 +17,5 @@ use std::map; fn main() { let buggy_map :HashMap = HashMap::(); let x = ~1; - buggy_map.insert(42, x); + buggy_map.insert(42, &*x); } diff --git a/src/test/run-pass/issue-3149.rs b/src/test/run-pass/issue-3149.rs index 533106ff93621..c578f1144a785 100644 --- a/src/test/run-pass/issue-3149.rs +++ b/src/test/run-pass/issue-3149.rs @@ -22,7 +22,7 @@ pure fn Matrix4(m11: T, m12: T, m13: T, m14: T, } } -struct Matrix4 { +struct Matrix4 { m11: T, m12: T, m13: T, m14: T, m21: T, m22: T, m23: T, m24: T, m31: T, m32: T, m33: T, m34: T, diff --git a/src/test/run-pass/let-assignability.rs b/src/test/run-pass/let-assignability.rs index 2978585674524..453d556b13c99 100644 --- a/src/test/run-pass/let-assignability.rs +++ b/src/test/run-pass/let-assignability.rs @@ -14,15 +14,7 @@ fn f() { io::println(b); } -fn g() { - let c = ~"world"; - let d: &str; - d = c; - io::println(d); -} - fn main() { f(); - g(); } diff --git a/src/test/run-pass/pipe-detect-term.rs b/src/test/run-pass/pipe-detect-term.rs index c2d4be04191bc..10b13d8757fa2 100644 --- a/src/test/run-pass/pipe-detect-term.rs +++ b/src/test/run-pass/pipe-detect-term.rs @@ -27,7 +27,7 @@ proto! oneshot ( ) fn main() { - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); pipes::spawn_service(oneshot::init, |p| { match try_recv(move p) { diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index e71d0c4931dc7..e138f2562aaef 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -35,7 +35,7 @@ fn main() { use oneshot::client::*; use stream::client::*; - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let c = pipes::spawn_service(stream::init, |p| { error!("waiting for pipes"); diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index 4a6e7b4ce36a8..ae7e4e7fb0ca7 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -27,7 +27,7 @@ fn main() { let c = pipes::spawn_service(oneshot::init, |p| { recv(move p); }); - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); sleep(iotask, 500); signal(move c); diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index d072df4d8e880..c7c1a6bb33195 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -29,7 +29,7 @@ fn align(size: uint, align: uint) -> uint { ((size + align) - 1u) & !(align - 1u) } -enum ptr_visit_adaptor = Inner; +enum ptr_visit_adaptor = Inner; impl ptr_visit_adaptor { @@ -61,154 +61,154 @@ impl ptr_visit_adaptor { impl ptr_visit_adaptor: TyVisitor { - fn visit_bot() -> bool { + fn visit_bot(&self) -> bool { self.align_to::<()>(); if ! self.inner.visit_bot() { return false; } self.bump_past::<()>(); true } - fn visit_nil() -> bool { + fn visit_nil(&self) -> bool { self.align_to::<()>(); if ! self.inner.visit_nil() { return false; } self.bump_past::<()>(); true } - fn visit_bool() -> bool { + fn visit_bool(&self) -> bool { self.align_to::(); if ! self.inner.visit_bool() { return false; } self.bump_past::(); true } - fn visit_int() -> bool { + fn visit_int(&self) -> bool { self.align_to::(); if ! self.inner.visit_int() { return false; } self.bump_past::(); true } - fn visit_i8() -> bool { + fn visit_i8(&self) -> bool { self.align_to::(); if ! self.inner.visit_i8() { return false; } self.bump_past::(); true } - fn visit_i16() -> bool { + fn visit_i16(&self) -> bool { self.align_to::(); if ! self.inner.visit_i16() { return false; } self.bump_past::(); true } - fn visit_i32() -> bool { + fn visit_i32(&self) -> bool { self.align_to::(); if ! self.inner.visit_i32() { return false; } self.bump_past::(); true } - fn visit_i64() -> bool { + fn visit_i64(&self) -> bool { self.align_to::(); if ! self.inner.visit_i64() { return false; } self.bump_past::(); true } - fn visit_uint() -> bool { + fn visit_uint(&self) -> bool { self.align_to::(); if ! self.inner.visit_uint() { return false; } self.bump_past::(); true } - fn visit_u8() -> bool { + fn visit_u8(&self) -> bool { self.align_to::(); if ! self.inner.visit_u8() { return false; } self.bump_past::(); true } - fn visit_u16() -> bool { + fn visit_u16(&self) -> bool { self.align_to::(); if ! self.inner.visit_u16() { return false; } self.bump_past::(); true } - fn visit_u32() -> bool { + fn visit_u32(&self) -> bool { self.align_to::(); if ! self.inner.visit_u32() { return false; } self.bump_past::(); true } - fn visit_u64() -> bool { + fn visit_u64(&self) -> bool { self.align_to::(); if ! self.inner.visit_u64() { return false; } self.bump_past::(); true } - fn visit_float() -> bool { + fn visit_float(&self) -> bool { self.align_to::(); if ! self.inner.visit_float() { return false; } self.bump_past::(); true } - fn visit_f32() -> bool { + fn visit_f32(&self) -> bool { self.align_to::(); if ! self.inner.visit_f32() { return false; } self.bump_past::(); true } - fn visit_f64() -> bool { + fn visit_f64(&self) -> bool { self.align_to::(); if ! self.inner.visit_f64() { return false; } self.bump_past::(); true } - fn visit_char() -> bool { + fn visit_char(&self) -> bool { self.align_to::(); if ! self.inner.visit_char() { return false; } self.bump_past::(); true } - fn visit_str() -> bool { + fn visit_str(&self) -> bool { self.align_to::<~str>(); if ! self.inner.visit_str() { return false; } self.bump_past::<~str>(); true } - fn visit_estr_box() -> bool { + fn visit_estr_box(&self) -> bool { self.align_to::<@str>(); if ! self.inner.visit_estr_box() { return false; } self.bump_past::<@str>(); true } - fn visit_estr_uniq() -> bool { + fn visit_estr_uniq(&self) -> bool { self.align_to::<~str>(); if ! self.inner.visit_estr_uniq() { return false; } self.bump_past::<~str>(); true } - fn visit_estr_slice() -> bool { + fn visit_estr_slice(&self) -> bool { self.align_to::<&static/str>(); if ! self.inner.visit_estr_slice() { return false; } self.bump_past::<&static/str>(); true } - fn visit_estr_fixed(n: uint, + fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool { self.align(align); @@ -217,35 +217,35 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_box(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<@u8>(); if ! self.inner.visit_box(mtbl, inner) { return false; } self.bump_past::<@u8>(); true } - fn visit_uniq(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<~u8>(); if ! self.inner.visit_uniq(mtbl, inner) { return false; } self.bump_past::<~u8>(); true } - fn visit_ptr(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<*u8>(); if ! self.inner.visit_ptr(mtbl, inner) { return false; } self.bump_past::<*u8>(); true } - fn visit_rptr(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<&static/u8>(); if ! self.inner.visit_rptr(mtbl, inner) { return false; } self.bump_past::<&static/u8>(); true } - fn visit_unboxed_vec(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::(); // FIXME (#3732): Inner really has to move its own pointers on this one. // or else possibly we could have some weird interface wherein we @@ -255,35 +255,35 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_vec(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<~[u8]>(); if ! self.inner.visit_vec(mtbl, inner) { return false; } self.bump_past::<~[u8]>(); true } - fn visit_evec_box(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<@[u8]>(); if ! self.inner.visit_evec_box(mtbl, inner) { return false; } self.bump_past::<@[u8]>(); true } - fn visit_evec_uniq(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<~[u8]>(); if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; } self.bump_past::<~[u8]>(); true } - fn visit_evec_slice(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<&static/[u8]>(); if ! self.inner.visit_evec_slice(mtbl, inner) { return false; } self.bump_past::<&static/[u8]>(); true } - fn visit_evec_fixed(n: uint, sz: uint, align: uint, + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *TyDesc) -> bool { self.align(align); if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) { @@ -293,24 +293,25 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_enter_rec(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { self.align(align); if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; } true } - fn visit_rec_field(i: uint, name: &str, + fn visit_rec_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_rec_field(i, name, mtbl, inner) { return false; } true } - fn visit_leave_rec(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; } true } - fn visit_enter_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_class(n_fields, sz, align) { return false; @@ -318,7 +319,7 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_class_field(i: uint, name: &str, + fn visit_class_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_class_field(i, name, mtbl, inner) { return false; @@ -326,30 +327,31 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_leave_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_class(n_fields, sz, align) { return false; } true } - fn visit_enter_tup(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { self.align(align); if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; } true } - fn visit_tup_field(i: uint, inner: *TyDesc) -> bool { + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_tup_field(i, inner) { return false; } true } - fn visit_leave_tup(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; } true } - fn visit_enter_fn(purity: uint, proto: uint, + fn visit_enter_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool { if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) { return false @@ -357,17 +359,17 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_fn_input(i: uint, mode: uint, inner: *TyDesc) -> bool { + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_fn_input(i, mode, inner) { return false; } true } - fn visit_fn_output(retstyle: uint, inner: *TyDesc) -> bool { + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_fn_output(retstyle, inner) { return false; } true } - fn visit_leave_fn(purity: uint, proto: uint, + fn visit_leave_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool { if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) { return false; @@ -375,13 +377,14 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_enter_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; } true } - fn visit_enter_enum_variant(variant: uint, + fn visit_enter_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool { @@ -392,12 +395,12 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_enum_variant_field(i: uint, inner: *TyDesc) -> bool { + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_enum_variant_field(i, inner) { return false; } true } - fn visit_leave_enum_variant(variant: uint, + fn visit_leave_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool { @@ -408,58 +411,59 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_leave_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; } true } - fn visit_trait() -> bool { + fn visit_trait(&self) -> bool { self.align_to::(); if ! self.inner.visit_trait() { return false; } self.bump_past::(); true } - fn visit_var() -> bool { + fn visit_var(&self) -> bool { if ! self.inner.visit_var() { return false; } true } - fn visit_var_integral() -> bool { + fn visit_var_integral(&self) -> bool { if ! self.inner.visit_var_integral() { return false; } true } - fn visit_param(i: uint) -> bool { + fn visit_param(&self, i: uint) -> bool { if ! self.inner.visit_param(i) { return false; } true } - fn visit_self() -> bool { + fn visit_self(&self) -> bool { self.align_to::<&static/u8>(); if ! self.inner.visit_self() { return false; } self.align_to::<&static/u8>(); true } - fn visit_type() -> bool { + fn visit_type(&self) -> bool { if ! self.inner.visit_type() { return false; } true } - fn visit_opaque_box() -> bool { + fn visit_opaque_box(&self) -> bool { self.align_to::<@u8>(); if ! self.inner.visit_opaque_box() { return false; } self.bump_past::<@u8>(); true } - fn visit_constr(inner: *TyDesc) -> bool { + fn visit_constr(&self, inner: *TyDesc) -> bool { if ! self.inner.visit_constr(inner) { return false; } true } - fn visit_closure_ptr(ck: uint) -> bool { + fn visit_closure_ptr(&self, ck: uint) -> bool { self.align_to::(); if ! self.inner.visit_closure_ptr(ck) { return false; } self.bump_past::(); @@ -503,121 +507,125 @@ impl my_visitor: movable_ptr { impl my_visitor: TyVisitor { - fn visit_bot() -> bool { true } - fn visit_nil() -> bool { true } - fn visit_bool() -> bool { + fn visit_bot(&self) -> bool { true } + fn visit_nil(&self) -> bool { true } + fn visit_bool(&self) -> bool { do self.get::() |b| { self.vals += ~[bool::to_str(b)]; }; true } - fn visit_int() -> bool { + fn visit_int(&self) -> bool { do self.get::() |i| { self.vals += ~[int::to_str(i, 10u)]; }; true } - fn visit_i8() -> bool { true } - fn visit_i16() -> bool { true } - fn visit_i32() -> bool { true } - fn visit_i64() -> bool { true } + fn visit_i8(&self) -> bool { true } + fn visit_i16(&self) -> bool { true } + fn visit_i32(&self) -> bool { true } + fn visit_i64(&self) -> bool { true } - fn visit_uint() -> bool { true } - fn visit_u8() -> bool { true } - fn visit_u16() -> bool { true } - fn visit_u32() -> bool { true } - fn visit_u64() -> bool { true } + fn visit_uint(&self) -> bool { true } + fn visit_u8(&self) -> bool { true } + fn visit_u16(&self) -> bool { true } + fn visit_u32(&self) -> bool { true } + fn visit_u64(&self) -> bool { true } - fn visit_float() -> bool { true } - fn visit_f32() -> bool { true } - fn visit_f64() -> bool { true } + fn visit_float(&self) -> bool { true } + fn visit_f32(&self) -> bool { true } + fn visit_f64(&self) -> bool { true } - fn visit_char() -> bool { true } - fn visit_str() -> bool { true } + fn visit_char(&self) -> bool { true } + fn visit_str(&self) -> bool { true } - fn visit_estr_box() -> bool { true } - fn visit_estr_uniq() -> bool { true } - fn visit_estr_slice() -> bool { true } - fn visit_estr_fixed(_n: uint, _sz: uint, + fn visit_estr_box(&self) -> bool { true } + fn visit_estr_uniq(&self) -> bool { true } + fn visit_estr_slice(&self) -> bool { true } + fn visit_estr_fixed(&self, _n: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_box(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_uniq(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_ptr(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_rptr(_mtbl: uint, _inner: *TyDesc) -> bool { true } - - fn visit_vec(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_unboxed_vec(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_box(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_uniq(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_slice(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_fixed(_n: uint, _sz: uint, _align: uint, + fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + + fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint, _mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_enter_rec(_n_fields: uint, + fn visit_enter_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_rec_field(_i: uint, _name: &str, + fn visit_rec_field(&self, _i: uint, _name: &str, _mtbl: uint, inner: *TyDesc) -> bool { error!("rec field!"); self.visit_inner(inner) } - fn visit_leave_rec(_n_fields: uint, + fn visit_leave_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_class(_n_fields: uint, + fn visit_enter_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_class_field(_i: uint, _name: &str, + fn visit_class_field(&self, _i: uint, _name: &str, _mtbl: uint, inner: *TyDesc) -> bool { self.visit_inner(inner) } - fn visit_leave_class(_n_fields: uint, + fn visit_leave_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_tup(_n_fields: uint, + fn visit_enter_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_tup_field(_i: uint, inner: *TyDesc) -> bool { + fn visit_tup_field(&self, _i: uint, inner: *TyDesc) -> bool { error!("tup field!"); self.visit_inner(inner) } - fn visit_leave_tup(_n_fields: uint, + fn visit_leave_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_enum(_n_variants: uint, + fn visit_enter_enum(&self, _n_variants: uint, _sz: uint, _align: uint) -> bool { // FIXME (#3732): this needs to rewind between enum variants, or something. true } - fn visit_enter_enum_variant(_variant: uint, + fn visit_enter_enum_variant(&self, _variant: uint, _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_enum_variant_field(_i: uint, inner: *TyDesc) -> bool { + fn visit_enum_variant_field(&self, _i: uint, inner: *TyDesc) -> bool { self.visit_inner(inner) } - fn visit_leave_enum_variant(_variant: uint, + fn visit_leave_enum_variant(&self, _variant: uint, _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_leave_enum(_n_variants: uint, + fn visit_leave_enum(&self, _n_variants: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_fn(_purity: uint, _proto: uint, + fn visit_enter_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_fn_input(_i: uint, _mode: uint, _inner: *TyDesc) -> bool { true } - fn visit_fn_output(_retstyle: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_fn(_purity: uint, _proto: uint, + fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_leave_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_trait() -> bool { true } - fn visit_var() -> bool { true } - fn visit_var_integral() -> bool { true } - fn visit_param(_i: uint) -> bool { true } - fn visit_self() -> bool { true } - fn visit_type() -> bool { true } - fn visit_opaque_box() -> bool { true } - fn visit_constr(_inner: *TyDesc) -> bool { true } - fn visit_closure_ptr(_ck: uint) -> bool { true } + fn visit_trait(&self) -> bool { true } + fn visit_var(&self) -> bool { true } + fn visit_var_integral(&self) -> bool { true } + fn visit_param(&self, _i: uint) -> bool { true } + fn visit_self(&self) -> bool { true } + fn visit_type(&self) -> bool { true } + fn visit_opaque_box(&self) -> bool { true } + fn visit_constr(&self, _inner: *TyDesc) -> bool { true } + fn visit_closure_ptr(&self, _ck: uint) -> bool { true } } fn get_tydesc_for(&&_t: T) -> *TyDesc { diff --git a/src/test/run-pass/region-dependent-addr-of.rs b/src/test/run-pass/region-dependent-addr-of.rs new file mode 100644 index 0000000000000..6765c1a11ae78 --- /dev/null +++ b/src/test/run-pass/region-dependent-addr-of.rs @@ -0,0 +1,115 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct A { + value: B +} + +struct B { + v1: int, + v2: [int * 3], + v3: ~[int], + v4: C, + v5: ~C, + v6: Option +} + +struct C { + f: int +} + +fn get_v1(a: &v/A) -> &v/int { + // Region inferencer must deduce that &v < L2 < L1 + let foo = &a.value; // L1 + &foo.v1 // L2 +} + +fn get_v2(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v2[i] +} + +fn get_v3(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v3[i] +} + +fn get_v4(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v4.f +} + +fn get_v5(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v5.f +} + +fn get_v6_a(a: &v/A, i: uint) -> &v/int { + match a.value.v6 { + Some(ref v) => &v.f, + None => fail + } +} + +fn get_v6_b(a: &v/A, i: uint) -> &v/int { + match *a { + A { value: B { v6: Some(ref v), _ } } => &v.f, + _ => fail + } +} + +fn get_v6_c(a: &v/A, i: uint) -> &v/int { + match a { + &A { value: B { v6: Some(ref v), _ } } => &v.f, + _ => fail + } +} + +fn get_v5_ref(a: &v/A, i: uint) -> &v/int { + match &a.value { + &B {v5: ~C {f: ref v}, _} => v + } +} + +fn main() { + let a = A {value: B {v1: 22, + v2: [23, 24, 25], + v3: ~[26, 27, 28], + v4: C { f: 29 }, + v5: ~C { f: 30 }, + v6: Some(C { f: 31 })}}; + + let p = get_v1(&a); + assert *p == a.value.v1; + + let p = get_v2(&a, 1); + assert *p == a.value.v2[1]; + + let p = get_v3(&a, 1); + assert *p == a.value.v3[1]; + + let p = get_v4(&a, 1); + assert *p == a.value.v4.f; + + let p = get_v5(&a, 1); + assert *p == a.value.v5.f; + + let p = get_v6_a(&a, 1); + assert *p == a.value.v6.get().f; + + let p = get_v6_b(&a, 1); + assert *p == a.value.v6.get().f; + + let p = get_v6_c(&a, 1); + assert *p == a.value.v6.get().f; + + let p = get_v5_ref(&a, 1); + assert *p == a.value.v5.f; +} diff --git a/src/test/run-pass/region-return-interior-of-option-in-self.rs b/src/test/run-pass/region-return-interior-of-option-in-self.rs deleted file mode 100644 index 8ed85b957ee73..0000000000000 --- a/src/test/run-pass/region-return-interior-of-option-in-self.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test (#3148) - -struct cell { - value: T; -} - -struct cells { - vals: ~[Option>]; -} - -impl &cells { - fn get(idx: uint) -> &self/T { - match self.vals[idx] { - Some(ref v) => &v.value, - None => fail - } - } -} - -fn main() {} diff --git a/src/test/run-pass/resource-generic.rs b/src/test/run-pass/resource-generic.rs index e528cd32974ba..7165d6089e85f 100644 --- a/src/test/run-pass/resource-generic.rs +++ b/src/test/run-pass/resource-generic.rs @@ -13,7 +13,7 @@ struct Arg {val: T, fin: extern fn(T)} -struct finish { +struct finish { arg: Arg } diff --git a/src/test/run-pass/send-type-inference.rs b/src/test/run-pass/send-type-inference.rs index 8476e256cd24c..8cb597a0d792c 100644 --- a/src/test/run-pass/send-type-inference.rs +++ b/src/test/run-pass/send-type-inference.rs @@ -9,7 +9,7 @@ // except according to those terms. // tests that ctrl's type gets inferred properly -type command = {key: K, val: V}; +type command = {key: K, val: V}; fn cache_server(c: oldcomm::Chan>>) { let ctrl = oldcomm::Port(); diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs index 6b005bf0e1218..0d093a1b4b0fd 100644 --- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs @@ -2,7 +2,7 @@ fn main() { let x = &[1, 2, 3, 4, 5]; if !x.is_empty() { let el = match x { - [1, ..ref tail] => &tail[0], + [1, ..ref tail] => &tail[0], _ => ::core::util::unreachable() }; io::println(fmt!("%d", *el));