diff --git a/doc/tutorial.md b/doc/tutorial.md index fbb1ca416e4c..ed32100c6fc6 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -34,8 +34,9 @@ high-level features include: * ***Higher-order functions.*** Rust functions may take closures as arguments or return closures as return values. Closures in Rust are very powerful and used pervasively. -* ***Interface polymorphism.*** Rust's type system features a unique - combination of Java-style interfaces and Haskell-style typeclasses. +* ***Trait polymorphism.*** Rust's type system features a unique + combination of Java-style interfaces and Haskell-style typeclasses + called _traits_. * ***Parametric polymorphism (generics).*** Functions and types can be parameterized over type variables with optional type constraints. * ***Type inference.*** Type annotations on local variable @@ -734,9 +735,12 @@ of numeric literal patterns can be expressed with `to`. The underscore (`_`) is a wildcard pattern that matches everything. If the arm with the wildcard pattern was left off in the above -example, running it on a number greater than ten (or negative) would -cause a run-time failure. When no arm matches, `alt` constructs do not -silently fall through—they blow up instead. +example, the typechecker would reject it at compile time. `alt` +constructs must be exhaustive: they must have an arm covering every +possible case. (You may use the `alt check` construct to write a +non-exhaustive match, but it's highly undesirable to do so. You may +reason that the missing cases will never occur, but the typechecker +provides you with no assurance that your reasoning is correct.) A powerful application of pattern matching is *destructuring*, where you use the matching to get at the contents of data types. Remember @@ -2089,9 +2093,9 @@ resource type. Rust has several kinds that can be used as type bounds: mutable fields nor shared boxes. > ***Note:*** Rust type kinds are syntactically very similar to -> [interfaces](#interfaces) when used as type bounds, and can be -> conveniently thought of as built-in interfaces. In the future type -> kinds will actually be interfaces that the compiler has special +> [traits](#traits) when used as type bounds, and can be +> conveniently thought of as built-in traits. In the future type +> kinds will actually be traits that the compiler has special > knowledge about. ## Generic functions and argument-passing @@ -2388,9 +2392,9 @@ This makes it possible to rebind a variable without actually mutating it, which is mostly useful for destructuring (which can rebind, but not assign). -# Interfaces +# Traits -Interfaces are Rust's take on value polymorphism—the thing that +Traits are Rust's take on value polymorphism—the thing that object-oriented languages tend to solve with methods and inheritance. For example, writing a function that can operate on multiple types of collections. @@ -2400,27 +2404,27 @@ collections. ## Declaration -An interface consists of a set of methods. A method is a function that +A trait consists of a set of methods. A method is a function that can be applied to a `self` value and a number of arguments, using the dot notation: `self.foo(arg1, arg2)`. -For example, we could declare the interface `to_str` for things that +For example, we could declare the trait `to_str` for things that can be converted to a string, with a single method of the same name: ~~~~ -iface to_str { +trait to_str { fn to_str() -> ~str; } ~~~~ ## Implementation -To actually implement an interface for a given type, the `impl` form +To actually implement an trait for a given type, the `impl` form is used. This defines implementations of `to_str` for the `int` and `~str` types. ~~~~ -# iface to_str { fn to_str() -> ~str; } +# trait to_str { fn to_str() -> ~str; } impl of to_str for int { fn to_str() -> ~str { int::to_str(self, 10u) } } @@ -2439,13 +2443,13 @@ method that matches the name, and simply calls that. Implementations are not globally visible. Resolving a method to an implementation requires that implementation to be in scope. You can -import and export implementations using the name of the interface they +import and export implementations using the name of the trait they implement (multiple implementations with the same name can be in scope without problems). Or you can give them an explicit name if you prefer, using this syntax: ~~~~ -# iface to_str { fn to_str() -> ~str; } +# trait to_str { fn to_str() -> ~str; } impl nil_to_str of to_str for () { fn to_str() -> ~str { ~"()" } } @@ -2461,7 +2465,7 @@ known at compile time, it is possible to specify 'bounds' for type parameters. ~~~~ -# iface to_str { fn to_str() -> ~str; } +# trait to_str { fn to_str() -> ~str; } fn comma_sep(elts: ~[T]) -> ~str { let mut result = ~"", first = true; for elts.each |elt| { @@ -2476,18 +2480,18 @@ fn comma_sep(elts: ~[T]) -> ~str { The syntax for this is similar to the syntax for specifying that a parameter type has to be copyable (which is, in principle, another kind of bound). By declaring `T` as conforming to the `to_str` -interface, it becomes possible to call methods from that interface on +trait, it becomes possible to call methods from that trait on values of that type inside the function. It will also cause a compile-time error when anyone tries to call `comma_sep` on an array whose element type does not have a `to_str` implementation in scope. -## Polymorphic interfaces +## Polymorphic traits -Interfaces may contain type parameters. This defines an interface for +Traits may contain type parameters. This defines a trait for generalized sequence types: ~~~~ -iface seq { +trait seq { fn len() -> uint; fn iter(fn(T)); } @@ -2499,26 +2503,26 @@ impl of seq for ~[T] { } ~~~~ -Note that the implementation has to explicitly declare the its -parameter `T` before using it to specify its interface type. This is +Note that the implementation has to explicitly declare the type +parameter that it binds, `T`, before using it to specify its trait type. This is needed because it could also, for example, specify an implementation of `seq`—the `of` clause *refers* to a type, rather than defining one. -The type parameters bound by an iface are in scope in each of the +The type parameters bound by a trait are in scope in each of the method declarations. So, re-declaring the type parameter -`T` as an explicit type parameter for `len` -- in either the iface or +`T` as an explicit type parameter for `len` -- in either the trait or the impl -- would be a compile-time error. -## The `self` type in interfaces +## The `self` type in traits -In an interface, `self` is a special type that you can think of as a -type parameter. An implementation of the interface for any given type +In a trait, `self` is a special type that you can think of as a +type parameter. An implementation of the trait for any given type `T` replaces the `self` type parameter with `T`. The following -interface describes types that support an equality operation: +trait describes types that support an equality operation: ~~~~ -iface eq { +trait eq { fn equals(&&other: self) -> bool; } @@ -2530,15 +2534,15 @@ impl of eq for int { Notice that `equals` takes an `int` argument, rather than a `self` argument, in an implementation for type `int`. -## Casting to an interface type +## Casting to an trait type The above allows us to define functions that polymorphically act on -values of *an* unknown type that conforms to a given interface. +values of *an* unknown type that conforms to a given trait. However, consider this function: ~~~~ # type circle = int; type rectangle = int; -# iface drawable { fn draw(); } +# trait drawable { fn draw(); } # impl of drawable for int { fn draw() {} } # fn new_circle() -> int { 1 } fn draw_all(shapes: ~[T]) { @@ -2549,14 +2553,14 @@ fn draw_all(shapes: ~[T]) { ~~~~ You can call that on an array of circles, or an array of squares -(assuming those have suitable `drawable` interfaces defined), but not +(assuming those have suitable `drawable` traits defined), but not on an array containing both circles and squares. -When this is needed, an interface name can be used as a type, causing +When this is needed, a trait name can be used as a type, causing the function to be written simply like this: ~~~~ -# iface drawable { fn draw(); } +# trait drawable { fn draw(); } fn draw_all(shapes: ~[drawable]) { for shapes.each |shape| { shape.draw(); } } @@ -2571,11 +2575,11 @@ is very similar to the 'vtables' used in most object-oriented languages. To construct such a value, you use the `as` operator to cast a value -to an interface type: +to a trait type: ~~~~ # type circle = int; type rectangle = int; -# iface drawable { fn draw(); } +# trait drawable { fn draw(); } # impl of drawable for int { fn draw() {} } # fn new_circle() -> int { 1 } # fn new_rectangle() -> int { 2 } @@ -2594,10 +2598,10 @@ Note that the allocation of a box is somewhat more expensive than simply using a type parameter and passing in the value as-is, and much more expensive than statically resolved method calls. -## Interface-less implementations +## Trait-less implementations If you only intend to use an implementation for static overloading, -and there is no interface available that it conforms to, you are free +and there is no trait available that it conforms to, you are free to leave off the `of` clause. However, this is only possible when you are defining an implementation in the same module as the receiver type, and the receiver type is a named type (i.e., an enum or a @@ -2620,9 +2624,10 @@ OpenSSL libraries installed, it should 'just work'. ~~~~ {.xfail-test} use std; +import libc::c_uint; extern mod crypto { - fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; + fn SHA1(src: *u8, sz: c_uint, out: *u8) -> *u8; } fn as_hex(data: ~[u8]) -> ~str { @@ -2634,7 +2639,7 @@ fn as_hex(data: ~[u8]) -> ~str { fn sha1(data: ~str) -> ~str unsafe { let bytes = str::bytes(data); let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes), - vec::len(bytes), ptr::null()); + vec::len(bytes) as c_uint, ptr::null()); ret as_hex(vec::unsafe::from_buf(hash, 20u)); } @@ -2700,7 +2705,7 @@ return a pointer. ~~~~ {.xfail-test} # extern mod crypto { -fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; +fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8; # } ~~~~ @@ -2791,7 +2796,7 @@ This pointer will become invalid as soon as the vector it points into is cleaned up, so you should be very careful how you use it. In this case, the local variable `bytes` outlives the pointer, so we're good. -Passing a null pointer as third argument to `SHA1` causes it to use a +Passing a null pointer as the third argument to `SHA1` makes it use a static buffer, and thus save us the effort of allocating memory ourselves. `ptr::null` is a generic function that will return an unsafe null pointer of the correct type (Rust generics are awesome @@ -2814,15 +2819,17 @@ microsecond-resolution timer. ~~~~ use std; -type timeval = {mut tv_sec: uint, - mut tv_usec: uint}; +import libc::c_ulonglong; + +type timeval = {mut tv_sec: c_ulonglong, + mut tv_usec: c_ulonglong}; #[nolink] -extern mod libc { +extern mod lib_c { fn gettimeofday(tv: *timeval, tz: *()) -> i32; } fn unix_time_in_microseconds() -> u64 unsafe { - let x = {mut tv_sec: 0u, mut tv_usec: 0u}; - libc::gettimeofday(ptr::addr_of(x), ptr::null()); + let x = {mut tv_sec: 0 as c_ulonglong, mut tv_usec: 0 as c_ulonglong}; + lib_c::gettimeofday(ptr::addr_of(x), ptr::null()); ret (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64); } @@ -2838,8 +2845,8 @@ define a record type with the same contents, and declare The second argument to `gettimeofday` (the time zone) is not used by this program, so it simply declares it to be a pointer to the nil -type. Since null pointer look the same, no matter which type they are -supposed to point at, this is safe. +type. Since all null pointers have the same representation regardless of +their referent type, this is safe. # Tasks diff --git a/mk/tests.mk b/mk/tests.mk index 89646a90a4c7..cf33cff82ea5 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -95,6 +95,9 @@ cleantestlibs: check: cleantestlibs cleantmptestlogs tidy all check-stage2 $(Q)$(S)src/etc/check-summary.py tmp/*.log +check-notidy: cleantestlibs cleantmptestlogs all check-stage2 + $(Q)$(S)src/etc/check-summary.py tmp/*.log + check-full: cleantestlibs cleantmptestlogs tidy \ all check-stage1 check-stage2 check-stage3 $(Q)$(S)src/etc/check-summary.py tmp/*.log diff --git a/src/libcore/arc.rs b/src/libcore/arc.rs index 28f072644105..9c46df9731b9 100644 --- a/src/libcore/arc.rs +++ b/src/libcore/arc.rs @@ -3,10 +3,9 @@ * share immutable data between tasks. */ -import comm::{port, chan, methods}; import sys::methods; -export arc, get, clone, shared_arc, get_arc; +export arc, get, clone; export exclusive, methods; @@ -122,49 +121,6 @@ impl methods for exclusive { } } -// Convenience code for sharing arcs between tasks - -type get_chan = chan>>; - -// (terminate, get) -type shared_arc = (shared_arc_res, get_chan); - -class shared_arc_res { - let c: comm::chan<()>; - new(c: comm::chan<()>) { self.c = c; } - drop { self.c.send(()); } -} - -fn shared_arc(-data: T) -> shared_arc { - let a = arc::arc(data); - let p = port(); - let c = chan(p); - do task::spawn() |move a| { - let mut live = true; - let terminate = port(); - let get = port(); - - c.send((chan(terminate), chan(get))); - - while live { - alt comm::select2(terminate, get) { - either::left(()) { live = false; } - either::right(cc) { - comm::send(cc, arc::clone(&a)); - } - } - } - }; - let (terminate, get) = p.recv(); - (shared_arc_res(terminate), get) -} - -fn get_arc(c: get_chan) -> arc::arc { - let p = port(); - c.send(chan(p)); - p.recv() -} - #[cfg(test)] mod tests { import comm::*; @@ -196,25 +152,6 @@ mod tests { log(info, arc_v); } - #[test] - fn auto_share_arc() { - let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let (_res, arc_c) = shared_arc(v); - - let p = port(); - let c = chan(p); - - do task::spawn() { - let arc_v = get_arc(arc_c); - let v = *get(&arc_v); - assert v[2] == 3; - - c.send(()); - }; - - assert p.recv() == (); - } - #[test] #[ignore] // this can probably infinite loop too. fn exclusive_arc() { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 1bdf3b9909ac..d10b9603af0d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1,10 +1,10 @@ /// Interfaces used for comparison. -iface ord { - fn lt(&&other: self) -> bool; +trait ord { + pure fn lt(&&other: self) -> bool; } -iface eq { - fn eq(&&other: self) -> bool; +trait eq { + pure fn eq(&&other: self) -> bool; } diff --git a/src/libcore/core.rc b/src/libcore/core.rc index d298ff15a9ec..11e305e22e8b 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -161,6 +161,7 @@ mod tuple; // Ubiquitous-utility-type modules +mod ops; mod cmp; mod num; mod hash; diff --git a/src/libcore/core.rs b/src/libcore/core.rs index 4738574fdb47..fdf535241888 100644 --- a/src/libcore/core.rs +++ b/src/libcore/core.rs @@ -30,6 +30,8 @@ import float::num; import f32::num; import f64::num; import num::num; +import ops::{const, copy, send, owned}; +import ops::{add, sub, mul, div, modulo, neg, bitops, index}; export path, option, some, none, unreachable; export extensions; @@ -42,6 +44,9 @@ export immutable_copyable_vector, iter_trait_extensions, vec_concat; export base_iter, copyable_iter, extended_iter; export tuple_ops, extended_tuple_ops; export ptr; +// The following exports are the core operators and kinds +export const, copy, send, owned; +export add, sub, mul, div, modulo, neg, bitops, index; // Export the log levels as global constants. Higher levels mean // more-verbosity. Error is the bottom level, default logging level is diff --git a/src/libcore/dlist.rs b/src/libcore/dlist.rs index 087194f721df..cd36d14816cb 100644 --- a/src/libcore/dlist.rs +++ b/src/libcore/dlist.rs @@ -18,12 +18,28 @@ enum dlist_node = @{ mut next: dlist_link }; -// Needs to be an @-box so nodes can back-reference it. -enum dlist = @{ - mut size: uint, - mut hd: dlist_link, - mut tl: dlist_link -}; +class dlist_root { + let mut size: uint; + let mut hd: dlist_link; + let mut tl: dlist_link; + new() { + self.size = 0; self.hd = none; self.tl = none; + } + drop { + /* FIXME (#????) This doesn't work during task failure - the box + * annihilator might have killed some of our nodes already. This will + * be safe to uncomment when the box annihilator is safer. As is, + * this makes test_dlist_cyclic_link below crash the runtime. + // Empty the list. Not doing this explicitly would leave cyclic links + // around, not to be freed until cycle collection at task exit. + while self.hd.is_some() { + self.unlink(self.hd.get()); + } + */ + } +} + +type dlist = @dlist_root; impl private_methods for dlist_node { pure fn assert_links() { @@ -91,7 +107,7 @@ pure fn new_dlist_node(+data: T) -> dlist_node { /// Creates a new, empty dlist. pure fn new_dlist() -> dlist { - dlist(@{mut size: 0, mut hd: none, mut tl: none}) + @unchecked { dlist_root() } } /// Creates a new dlist with a single element @@ -118,7 +134,7 @@ fn concat(lists: dlist>) -> dlist { result } -impl private_methods for dlist { +impl private_methods for dlist_root { pure fn new_link(-data: T) -> dlist_link { some(dlist_node(@{data: data, mut linked: true, mut prev: none, mut next: none})) @@ -288,20 +304,6 @@ impl extensions for dlist { tl.map(|nobe| self.unlink(nobe)); tl } - /// Remove data from the head of the list. O(1). - fn pop() -> option { - do option::map_consume(self.pop_n()) |nobe| { - let dlist_node(@{ data: x, _ }) <- nobe; - x - } - } - /// Remove data from the tail of the list. O(1). - fn pop_tail() -> option { - do option::map_consume(self.pop_tail_n()) |nobe| { - let dlist_node(@{ data: x, _ }) <- nobe; - x - } - } /// Get the node at the list's head. O(1). pure fn peek_n() -> option> { self.hd } /// Get the node at the list's tail. O(1). @@ -334,7 +336,7 @@ impl extensions for dlist { * to the other list's head. O(1). */ fn append(them: dlist) { - if box::ptr_eq(*self, *them) { + if box::ptr_eq(self, them) { fail ~"Cannot append a dlist to itself!" } if them.len() > 0 { @@ -351,7 +353,7 @@ impl extensions for dlist { * list's tail to this list's head. O(1). */ fn prepend(them: dlist) { - if box::ptr_eq(*self, *them) { + if box::ptr_eq(self, them) { fail ~"Cannot prepend a dlist to itself!" } if them.len() > 0 { @@ -366,15 +368,25 @@ impl extensions for dlist { /// Reverse the list's elements in place. O(n). fn reverse() { - let temp = new_dlist::(); - while !self.is_empty() { - let nobe = self.pop_n().get(); - nobe.linked = true; // meh, kind of disorganised. - temp.add_head(some(nobe)); + do option::while_some(self.hd) |nobe| { + let next_nobe = nobe.next; + self.remove(nobe); + self.make_mine(nobe); + self.add_head(some(nobe)); + next_nobe + } + } + + /** + * Remove everything from the list. This is important because the cyclic + * links won't otherwise be automatically refcounted-collected. O(n). + */ + fn clear() { + // Cute as it would be to simply detach the list and proclaim "O(1)!", + // the GC would still be a hidden O(n). Better to be honest about it. + while !self.is_empty() { + let _ = self.pop_n(); } - self.hd = temp.hd; - self.tl = temp.tl; - self.size = temp.size; } /// Iterate over nodes. @@ -431,6 +443,10 @@ impl extensions for dlist { } impl extensions for dlist { + /// Remove data from the head of the list. O(1). + fn pop() -> option { self.pop_n().map (|nobe| nobe.data) } + /// Remove data from the tail of the list. O(1). + fn pop_tail() -> option { self.pop_tail_n().map (|nobe| nobe.data) } /// Get data at the list's head. O(1). pure fn peek() -> option { self.peek_n().map (|nobe| nobe.data) } /// Get data at the list's tail. O(1). @@ -596,6 +612,13 @@ mod tests { a.assert_consistent(); assert a.is_empty(); } #[test] + fn test_dlist_clear() { + let a = from_vec(~[5,4,3,2,1]); + a.clear(); + assert a.len() == 0; + a.assert_consistent(); + } + #[test] fn test_dlist_is_empty() { let empty = new_dlist::(); let full1 = from_vec(~[1,2,3]); @@ -847,7 +870,7 @@ mod tests { l.assert_consistent(); assert l.is_empty(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_asymmetric_link() { + fn test_dlist_asymmetric_link() { let l = new_dlist::(); let _one = l.push_n(1); let two = l.push_n(2); @@ -855,7 +878,7 @@ mod tests { l.assert_consistent(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_cyclic_list() { + fn test_dlist_cyclic_list() { let l = new_dlist::(); let one = l.push_n(1); let _two = l.push_n(2); @@ -865,32 +888,32 @@ mod tests { l.assert_consistent(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_headless() { + fn test_dlist_headless() { new_dlist::().head(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_already_present_before() { + fn test_dlist_insert_already_present_before() { let l = new_dlist::(); let one = l.push_n(1); let two = l.push_n(2); l.insert_n_before(two, one); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_already_present_after() { + fn test_dlist_insert_already_present_after() { let l = new_dlist::(); let one = l.push_n(1); let two = l.push_n(2); l.insert_n_after(one, two); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_before_orphan() { + fn test_dlist_insert_before_orphan() { let l = new_dlist::(); let one = new_dlist_node(1); let two = new_dlist_node(2); l.insert_n_before(one, two); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_after_orphan() { + fn test_dlist_insert_after_orphan() { let l = new_dlist::(); let one = new_dlist_node(1); let two = new_dlist_node(2); diff --git a/src/libcore/f32.rs b/src/libcore/f32.rs index c72aa6e3aef0..3e7bc0097f74 100644 --- a/src/libcore/f32.rs +++ b/src/libcore/f32.rs @@ -168,15 +168,15 @@ pure fn log2(n: f32) -> f32 { } impl num of num::num for f32 { - fn add(&&other: f32) -> f32 { ret self + other; } - fn sub(&&other: f32) -> f32 { ret self - other; } - fn mul(&&other: f32) -> f32 { ret self * other; } - fn div(&&other: f32) -> f32 { ret self / other; } - fn modulo(&&other: f32) -> f32 { ret self % other; } - fn neg() -> f32 { ret -self; } + pure fn add(&&other: f32) -> f32 { ret self + other; } + pure fn sub(&&other: f32) -> f32 { ret self - other; } + pure fn mul(&&other: f32) -> f32 { ret self * other; } + pure fn div(&&other: f32) -> f32 { ret self / other; } + pure fn modulo(&&other: f32) -> f32 { ret self % other; } + pure fn neg() -> f32 { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> f32 { ret n as f32; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> f32 { ret n as f32; } } // diff --git a/src/libcore/f64.rs b/src/libcore/f64.rs index 40488d9f8f4f..9e84c432bad2 100644 --- a/src/libcore/f64.rs +++ b/src/libcore/f64.rs @@ -195,15 +195,15 @@ pure fn log2(n: f64) -> f64 { } impl num of num::num for f64 { - fn add(&&other: f64) -> f64 { ret self + other; } - fn sub(&&other: f64) -> f64 { ret self - other; } - fn mul(&&other: f64) -> f64 { ret self * other; } - fn div(&&other: f64) -> f64 { ret self / other; } - fn modulo(&&other: f64) -> f64 { ret self % other; } - fn neg() -> f64 { ret -self; } + pure fn add(&&other: f64) -> f64 { ret self + other; } + pure fn sub(&&other: f64) -> f64 { ret self - other; } + pure fn mul(&&other: f64) -> f64 { ret self * other; } + pure fn div(&&other: f64) -> f64 { ret self / other; } + pure fn modulo(&&other: f64) -> f64 { ret self % other; } + pure fn neg() -> f64 { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> f64 { ret n as f64; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> f64 { ret n as f64; } } // diff --git a/src/libcore/float.rs b/src/libcore/float.rs index 0139c60873b8..8b8cc4664dc8 100644 --- a/src/libcore/float.rs +++ b/src/libcore/float.rs @@ -403,32 +403,32 @@ fn pow_with_uint(base: uint, pow: uint) -> float { ret total; } -fn is_positive(x: float) -> bool { f64::is_positive(x as f64) } -fn is_negative(x: float) -> bool { f64::is_negative(x as f64) } -fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) } -fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) } -fn is_zero(x: float) -> bool { f64::is_zero(x as f64) } -fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) } -fn is_finite(x: float) -> bool { f64::is_finite(x as f64) } -fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) } +pure fn is_positive(x: float) -> bool { f64::is_positive(x as f64) } +pure fn is_negative(x: float) -> bool { f64::is_negative(x as f64) } +pure fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) } +pure fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) } +pure fn is_zero(x: float) -> bool { f64::is_zero(x as f64) } +pure fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) } +pure fn is_finite(x: float) -> bool { f64::is_finite(x as f64) } +pure fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) } -fn abs(x: float) -> float { f64::abs(x as f64) as float } -fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float } -fn atan(x: float) -> float { f64::atan(x as f64) as float } -fn sin(x: float) -> float { f64::sin(x as f64) as float } -fn cos(x: float) -> float { f64::cos(x as f64) as float } -fn tan(x: float) -> float { f64::tan(x as f64) as float } +pure fn abs(x: float) -> float { f64::abs(x as f64) as float } +pure fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float } +pure fn atan(x: float) -> float { f64::atan(x as f64) as float } +pure fn sin(x: float) -> float { f64::sin(x as f64) as float } +pure fn cos(x: float) -> float { f64::cos(x as f64) as float } +pure fn tan(x: float) -> float { f64::tan(x as f64) as float } impl num of num::num for float { - fn add(&&other: float) -> float { ret self + other; } - fn sub(&&other: float) -> float { ret self - other; } - fn mul(&&other: float) -> float { ret self * other; } - fn div(&&other: float) -> float { ret self / other; } - fn modulo(&&other: float) -> float { ret self % other; } - fn neg() -> float { ret -self; } + pure fn add(&&other: float) -> float { ret self + other; } + pure fn sub(&&other: float) -> float { ret self - other; } + pure fn mul(&&other: float) -> float { ret self * other; } + pure fn div(&&other: float) -> float { ret self / other; } + pure fn modulo(&&other: float) -> float { ret self % other; } + pure fn neg() -> float { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> float { ret n as float; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> float { ret n as float; } } #[test] diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 02ce125e35cf..2b950e4a7977 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -112,27 +112,27 @@ fn to_str_bytes(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U { fn str(i: T) -> ~str { ret to_str(i, 10u); } impl ord of ord for T { - fn lt(&&other: T) -> bool { + pure fn lt(&&other: T) -> bool { ret self < other; } } impl eq of eq for T { - fn eq(&&other: T) -> bool { + pure fn eq(&&other: T) -> bool { ret self == other; } } impl num of num::num for T { - fn add(&&other: T) -> T { ret self + other; } - fn sub(&&other: T) -> T { ret self - other; } - fn mul(&&other: T) -> T { ret self * other; } - fn div(&&other: T) -> T { ret self / other; } - fn modulo(&&other: T) -> T { ret self % other; } - fn neg() -> T { ret -self; } + pure fn add(&&other: T) -> T { ret self + other; } + pure fn sub(&&other: T) -> T { ret self - other; } + pure fn mul(&&other: T) -> T { ret self * other; } + pure fn div(&&other: T) -> T { ret self / other; } + pure fn modulo(&&other: T) -> T { ret self % other; } + pure fn neg() -> T { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> T { ret n as T; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> T { ret n as T; } } impl times of iter::times for T { diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 25d1b5e66805..3704f2b70da4 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -687,7 +687,11 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) -> fn read_whole_file_str(file: ~str) -> result<~str, ~str> { result::chain(read_whole_file(file), |bytes| { - result::ok(str::from_bytes(bytes)) + if str::is_utf8(bytes) { + result::ok(str::from_bytes(bytes)) + } else { + result::err(file + ~" is not UTF-8") + } }) } diff --git a/src/libcore/num.rs b/src/libcore/num.rs index 130b259c1dfd..038685276559 100644 --- a/src/libcore/num.rs +++ b/src/libcore/num.rs @@ -1,17 +1,17 @@ /// An interface for numbers. -iface num { +trait num { // FIXME: Cross-crate overloading doesn't work yet. (#2615) // FIXME: Interface inheritance. (#2616) - fn add(&&other: self) -> self; - fn sub(&&other: self) -> self; - fn mul(&&other: self) -> self; - fn div(&&other: self) -> self; - fn modulo(&&other: self) -> self; - fn neg() -> self; + pure fn add(&&other: self) -> self; + pure fn sub(&&other: self) -> self; + pure fn mul(&&other: self) -> self; + pure fn div(&&other: self) -> self; + pure fn modulo(&&other: self) -> self; + pure fn neg() -> self; - fn to_int() -> int; - fn from_int(n: int) -> self; // FIXME (#2376) Static functions. + pure fn to_int() -> int; + pure fn from_int(n: int) -> self; // FIXME (#2376) Static functions. // n.b. #2376 is for classes, not ifaces, but it could be generalized... } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs new file mode 100644 index 000000000000..61efe704974a --- /dev/null +++ b/src/libcore/ops.rs @@ -0,0 +1,66 @@ +// Core operators and kinds. + +#[lang="const"] +trait const { + // Empty. +} + +#[lang="copy"] +trait copy { + // Empty. +} + +#[lang="send"] +trait send { + // Empty. +} + +#[lang="owned"] +trait owned { + // Empty. +} + +#[lang="add"] +trait add { + pure fn add(rhs: RHS) -> Result; +} + +#[lang="sub"] +trait sub { + pure fn sub(rhs: RHS) -> Result; +} + +#[lang="mul"] +trait mul { + pure fn mul(rhs: RHS) -> Result; +} + +#[lang="div"] +trait div { + pure fn div(rhs: RHS) -> Result; +} + +#[lang="modulo"] +trait modulo { + pure fn modulo(rhs: RHS) -> Result; +} + +#[lang="neg"] +trait neg { + pure fn neg(rhs: RHS) -> Result; +} + +#[lang="bitops"] +trait bitops { + pure fn and(rhs: RHS) -> Result; + pure fn or(rhs: RHS) -> Result; + pure fn xor(rhs: RHS) -> Result; + pure fn shl(n: BitCount) -> Result; + pure fn shr(n: BitCount) -> Result; +} + +#[lang="index"] +trait index { + pure fn index(index: Index) -> Result; +} + diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 27cd8ef7cafa..4ffa040250f6 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -30,59 +30,6 @@ macro_rules! move { // places. Once there is unary move, it can be removed. fn move(-x: T) -> T { x } -/** - -Some thoughts about fixed buffers. - -The idea is if a protocol is bounded, we will synthesize a record that -has a field for each state. Each of these states contains a packet for -the messages that are legal to be sent in that state. Then, instead of -allocating, the send code just finds a pointer to the right field and -uses that instead. - -Unforunately, this makes things kind of tricky. We need to be able to -find the buffer, which means we need to pass it around. This could -either be associated with the (send|recv)_packet classes, or with the -packet itself. We will also need some form of reference counting so we -can track who has the responsibility of freeing the buffer. - -We want to preserve the ability to do things like optimistic buffer -re-use, and skipping over to a new buffer when necessary. What I mean -is, suppose we had the typical stream protocol. It'd make sense to -amortize allocation costs by allocating a buffer with say 16 -messages. When the sender gets to the end of the buffer, it could -check if the receiver is done with the packet in slot 0. If so, it can -just reuse that one, checking if the receiver is done with the next -one in each case. If it is ever not done, it just allocates a new -buffer and skips over to that. - -Also, since protocols are in libcore, we have to do this in a way that -maintains backwards compatibility. - -buffer header and buffer. Cast as c_void when necessary. - -=== - -Okay, here are some new ideas. - -It'd be nice to keep the bounded/unbounded case as uniform as -possible. It leads to less code duplication, and less things that can -go sublty wrong. For the bounded case, we could either have a struct -with a bunch of unique pointers to pre-allocated packets, or we could -lay them out inline. Inline layout is better, if for no other reason -than that we don't have to allocate each packet -individually. Currently we pass unique packets around as unsafe -pointers, but they are actually unique pointers. We should instead use -real unsafe pointers. This makes freeing data and running destructors -trickier though. Thus, we should allocate all packets in parter of a -higher level buffer structure. Packets can maintain a pointer to their -buffer, and this is the part that gets freed. - -It might be helpful to have some idea of a semi-unique pointer (like -being partially pregnant, also like an ARC). - -*/ - enum state { empty, full, @@ -805,6 +752,12 @@ class port_set : recv { vec::push(self.ports, port) } + fn chan() -> chan { + let (ch, po) = stream(); + self.add(po); + ch + } + fn try_recv() -> option { let mut result = none; while result == none && self.ports.len() > 0 { @@ -869,3 +822,52 @@ impl chan of channel for shared_chan { fn shared_chan(+c: chan) -> shared_chan { arc::exclusive(c) } + +trait select2 { + fn try_select() -> either, option>; + fn select() -> either; +} + +impl, Right: selectable recv> + of select2 for (Left, Right) { + + fn select() -> either { + alt self { + (lp, rp) { + alt select2i(lp, rp) { + left(()) { left (lp.recv()) } + right(()) { right(rp.recv()) } + } + } + } + } + + fn try_select() -> either, option> { + alt self { + (lp, rp) { + alt select2i(lp, rp) { + left(()) { left (lp.try_recv()) } + right(()) { right(rp.try_recv()) } + } + } + } + } +} + +#[cfg(test)] +mod test { + #[test] + fn test_select2() { + let (c1, p1) = pipes::stream(); + let (c2, p2) = pipes::stream(); + + c1.send("abc"); + + alt (p1, p2).select() { + right(_) { fail } + _ { } + } + + c2.send(123); + } +} diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index 75e17cd6a9b0..9561ed4e65f8 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -53,27 +53,27 @@ pure fn compl(i: T) -> T { } impl ord of ord for T { - fn lt(&&other: T) -> bool { + pure fn lt(&&other: T) -> bool { ret self < other; } } impl eq of eq for T { - fn eq(&&other: T) -> bool { + pure fn eq(&&other: T) -> bool { ret self == other; } } impl num of num::num for T { - fn add(&&other: T) -> T { ret self + other; } - fn sub(&&other: T) -> T { ret self - other; } - fn mul(&&other: T) -> T { ret self * other; } - fn div(&&other: T) -> T { ret self / other; } - fn modulo(&&other: T) -> T { ret self % other; } - fn neg() -> T { ret -self; } + pure fn add(&&other: T) -> T { ret self + other; } + pure fn sub(&&other: T) -> T { ret self - other; } + pure fn mul(&&other: T) -> T { ret self * other; } + pure fn div(&&other: T) -> T { ret self / other; } + pure fn modulo(&&other: T) -> T { ret self % other; } + pure fn neg() -> T { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> T { ret n as T; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> T { ret n as T; } } /** diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index a89148ecec9d..f74cbba23ce2 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -2,24 +2,24 @@ const fuzzy_epsilon: float = 1.0e-6; -iface fuzzy_eq { - fn fuzzy_eq(&&other: self) -> bool; +trait fuzzy_eq { + pure fn fuzzy_eq(&&other: self) -> bool; } impl fuzzy_eq of fuzzy_eq for float { - fn fuzzy_eq(&&other: float) -> bool { + pure fn fuzzy_eq(&&other: float) -> bool { ret float::abs(self - other) < fuzzy_epsilon; } } impl fuzzy_eq of fuzzy_eq for f32 { - fn fuzzy_eq(&&other: f32) -> bool { + pure fn fuzzy_eq(&&other: f32) -> bool { ret f32::abs(self - other) < (fuzzy_epsilon as f32); } } impl fuzzy_eq of fuzzy_eq for f64 { - fn fuzzy_eq(&&other: f64) -> bool { + pure fn fuzzy_eq(&&other: f64) -> bool { ret f64::abs(self - other) < (fuzzy_epsilon as f64); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fb27724e369d..4988adf93734 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -87,7 +87,7 @@ enum def { def_upvar(node_id /* local id of closed over var */, @def /* closed over def */, node_id /* expr node that creates the closure */), - def_class(def_id), + def_class(def_id, bool /* has constructor */), def_region(node_id) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 37e8671facd3..0cf593efdc30 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -53,7 +53,7 @@ pure fn def_id_of_def(d: def) -> def_id { def_fn(id, _) | def_mod(id) | def_foreign_mod(id) | def_const(id) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | def_class(id) { id } + def_use(id) | def_class(id, _) { id } def_arg(id, _) | def_local(id, _) | def_self(id) | def_upvar(id, _, _) | def_binding(id) | def_region(id) { local_def(id) diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index c9b35e561bb4..f367fb63985a 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -183,7 +183,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt { {mode: ast::infer(self.next_id()), ty: ty, ident: name, - // FIXME #2886: should this be the same as the infer id? id: self.next_id()} } @@ -280,7 +279,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt { } fn ty_path_ast_builder(path: @ast::path) -> @ast::ty { - // FIXME #2886: make sure the node ids are legal. @{id: self.next_id(), node: ast::ty_path(path, self.next_id()), span: self.empty_span()} diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 52aa88e6cb63..a6734b285a19 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -14,6 +14,7 @@ import io::{reader_util, writer_util}; import getopts::{optopt, optmulti, optflag, optflagopt, opt_present}; import back::{x86, x86_64}; import std::map::hashmap; +import lib::llvm::llvm; enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified, ppm_expanded_identified } @@ -169,6 +170,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, session::sess_os_to_meta_os(sess.targ_cfg.os), sess.opts.static)); + time(time_passes, ~"language item collection", || + middle::lang_items::collect_language_items(crate, sess)); + let { def_map: def_map, exp_map: exp_map, impl_map: impl_map, @@ -440,6 +444,9 @@ fn build_session_options(match: getopts::match, } debugging_opts |= this_bit; } + if debugging_opts & session::debug_llvm != 0 { + llvm::LLVMSetDebug(1); + } let output_type = if parse_only || no_trans { diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs index 64ae30895c41..61ef9f73c3f3 100644 --- a/src/rustc/driver/session.rs +++ b/src/rustc/driver/session.rs @@ -40,6 +40,7 @@ const borrowck_stats: uint = 1024u; const borrowck_note_pure: uint = 2048; const borrowck_note_loan: uint = 4096; const no_landing_pads: uint = 8192; +const debug_llvm: uint = 16384; fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ~[(~"ppregions", ~"prettyprint regions with \ @@ -61,7 +62,8 @@ fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"borrowck-note-loan", ~"note where loans are req'd", borrowck_note_loan), (~"no-landing-pads", ~"omit landing pads for unwinding", - no_landing_pads) + no_landing_pads), + (~"debug-llvm", ~"enable debug output from LLVM", debug_llvm) ] } diff --git a/src/rustc/lib/llvm.rs b/src/rustc/lib/llvm.rs index 376012dcf4e5..7dbefa8e4980 100644 --- a/src/rustc/lib/llvm.rs +++ b/src/rustc/lib/llvm.rs @@ -969,6 +969,9 @@ extern mod llvm { fn LLVMConstNamedStruct(S: TypeRef, ConstantVals: *ValueRef, Count: c_uint) -> ValueRef; + + /** Enables LLVM debug output. */ + fn LLVMSetDebug(Enabled: c_int); } fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) { diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs index 7f97583fe3d2..0ba76c49246a 100644 --- a/src/rustc/metadata/csearch.rs +++ b/src/rustc/metadata/csearch.rs @@ -25,6 +25,7 @@ export get_enum_variants; export get_impls_for_mod; export get_trait_methods; export get_method_names_if_trait; +export get_item_attrs; export each_path; export get_type; export get_impl_traits; @@ -149,6 +150,14 @@ fn get_method_names_if_trait(cstore: cstore::cstore, def: ast::def_id) ret decoder::get_method_names_if_trait(cdata, def.node); } +fn get_item_attrs(cstore: cstore::cstore, + def_id: ast::def_id, + f: fn(~[@ast::meta_item])) { + + let cdata = cstore::get_crate_data(cstore, def_id.crate); + decoder::get_item_attrs(cdata, def_id.node, f) +} + fn get_class_fields(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::field_ty] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 3ff9ded3f1ef..83684413641f 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -39,6 +39,7 @@ export get_crate_vers; export get_impls_for_mod; export get_trait_methods; export get_method_names_if_trait; +export get_item_attrs; export get_crate_module_paths; export def_like; export dl_def; @@ -282,7 +283,8 @@ fn item_to_def_like(item: ebml::doc, did: ast::def_id, cnum: ast::crate_num) let fam_ch = item_family(item); alt fam_ch { 'c' { dl_def(ast::def_const(did)) } - 'C' { dl_def(ast::def_class(did)) } + 'C' { dl_def(ast::def_class(did, true)) } + 'S' { dl_def(ast::def_class(did, false)) } 'u' { dl_def(ast::def_fn(did, ast::unsafe_fn)) } 'f' { dl_def(ast::def_fn(did, ast::impure_fn)) } 'p' { dl_def(ast::def_fn(did, ast::pure_fn)) } @@ -659,6 +661,18 @@ fn get_method_names_if_trait(cdata: cmd, node_id: ast::node_id) ret some(resulting_method_names); } +fn get_item_attrs(cdata: cmd, + node_id: ast::node_id, + f: fn(~[@ast::meta_item])) { + + let item = lookup_item(node_id, cdata.data); + do ebml::tagged_docs(item, tag_attributes) |attributes| { + do ebml::tagged_docs(attributes, tag_attribute) |attribute| { + f(get_meta_items(attribute)); + } + } +} + // Helper function that gets either fields or methods fn get_class_members(cdata: cmd, id: ast::node_id, p: fn(char) -> bool) -> ~[ty::field_ty] { @@ -694,7 +708,7 @@ fn family_has_type_params(fam_ch: char) -> bool { alt check fam_ch { 'c' | 'T' | 'm' | 'n' | 'g' | 'h' | 'j' { false } 'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' | 'C' - | 'a' + | 'a' | 'S' { true } } } @@ -738,6 +752,7 @@ fn item_family_to_str(fam: char) -> ~str { 'i' { ret ~"impl"; } 'I' { ret ~"trait"; } 'C' { ret ~"class"; } + 'S' { ret ~"struct"; } 'g' { ret ~"public field"; } 'j' { ret ~"private field"; } } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index b2847b3acc53..e1ed9fe396aa 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -663,7 +663,16 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, /* Now, make an item for the class itself */ ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'C'); + + alt ctor { + none { + encode_family(ebml_w, 'S'); + } + some(_) { + encode_family(ebml_w, 'C'); + } + } + encode_type_param_bounds(ebml_w, ecx, tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ebml_w, item.ident); @@ -759,6 +768,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_type_param_bounds(ebml_w, ecx, tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ebml_w, item.ident); + encode_attributes(ebml_w, item.attrs); let mut i = 0u; for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| { alt ms[i] { diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 002b4d97e23a..1f5f7c4518d5 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -369,8 +369,8 @@ impl of tr for ast::def { ast::def_upvar(nid1, def, nid2) { ast::def_upvar(xcx.tr_id(nid1), @(*def).tr(xcx), xcx.tr_id(nid2)) } - ast::def_class(did) { - ast::def_class(did.tr(xcx)) + ast::def_class(did, has_constructor) { + ast::def_class(did.tr(xcx), has_constructor) } ast::def_region(nid) { ast::def_region(xcx.tr_id(nid)) } } diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs index f5879145a9d4..4088945e550e 100644 --- a/src/rustc/middle/borrowck/categorization.rs +++ b/src/rustc/middle/borrowck/categorization.rs @@ -196,7 +196,7 @@ impl public_methods for borrowck_ctxt { ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(_, _) | ast::def_ty(_) | ast::def_prim_ty(_) | - ast::def_ty_param(_, _) | ast::def_class(_) | + ast::def_ty_param(_, _) | ast::def_class(_, _) | ast::def_region(_) { @{id:id, span:span, cat:cat_special(sk_static_item), lp:none, diff --git a/src/rustc/middle/lang_items.rs b/src/rustc/middle/lang_items.rs new file mode 100644 index 000000000000..2353da51f981 --- /dev/null +++ b/src/rustc/middle/lang_items.rs @@ -0,0 +1,209 @@ +// Detecting language items. +// +// Language items are items that represent concepts intrinsic to the language +// itself. Examples are: +// +// * Traits that specify "kinds"; e.g. "const", "copy", "send". +// +// * Traits that represent operators; e.g. "add", "sub", "index". +// +// * Functions called by the compiler itself. + +import driver::session::session; +import metadata::csearch::{each_path, get_item_attrs}; +import metadata::cstore::{iter_crate_data}; +import metadata::decoder::{dl_def, dl_field, dl_impl}; +import syntax::ast::{crate, def_id, def_ty, lit_str, meta_item, meta_list}; +import syntax::ast::{meta_name_value, meta_word}; +import syntax::ast_util::{local_def}; +import syntax::visit::{default_simple_visitor, mk_simple_visitor}; +import syntax::visit::{visit_crate, visit_item}; + +import std::map::{hashmap, str_hash}; +import str_eq = str::eq; + +class LanguageItems { + let mut const_trait: option; + let mut copy_trait: option; + let mut send_trait: option; + let mut owned_trait: option; + + let mut add_trait: option; + let mut sub_trait: option; + let mut mul_trait: option; + let mut div_trait: option; + let mut modulo_trait: option; + let mut neg_trait: option; + let mut bitops_trait: option; + let mut index_trait: option; + + new() { + self.const_trait = none; + self.copy_trait = none; + self.send_trait = none; + self.owned_trait = none; + + self.add_trait = none; + self.sub_trait = none; + self.mul_trait = none; + self.div_trait = none; + self.modulo_trait = none; + self.neg_trait = none; + self.bitops_trait = none; + self.index_trait = none; + } +} + +class LanguageItemCollector { + let items: LanguageItems; + + let crate: @crate; + let session: session; + + let item_refs: hashmap<~str,&mut option>; + + new(crate: @crate, session: session) { + self.crate = crate; + self.session = session; + + self.items = LanguageItems(); + + self.item_refs = str_hash(); + } + + // XXX: Needed to work around an issue with constructors. + fn init() { + self.item_refs.insert(~"const", &mut self.items.const_trait); + self.item_refs.insert(~"copy", &mut self.items.copy_trait); + self.item_refs.insert(~"send", &mut self.items.send_trait); + self.item_refs.insert(~"owned", &mut self.items.owned_trait); + + self.item_refs.insert(~"add", &mut self.items.add_trait); + self.item_refs.insert(~"sub", &mut self.items.sub_trait); + self.item_refs.insert(~"mul", &mut self.items.mul_trait); + self.item_refs.insert(~"div", &mut self.items.div_trait); + self.item_refs.insert(~"modulo", &mut self.items.modulo_trait); + self.item_refs.insert(~"neg", &mut self.items.neg_trait); + self.item_refs.insert(~"bitops", &mut self.items.bitops_trait); + self.item_refs.insert(~"index", &mut self.items.index_trait); + } + + fn match_and_collect_meta_item(item_def_id: def_id, + meta_item: meta_item) { + + alt meta_item.node { + meta_name_value(key, literal) => { + alt literal.node { + lit_str(value) => { + self.match_and_collect_item(item_def_id, + *key, + *value); + } + _ => { + // Skip. + } + } + } + meta_word(*) | meta_list(*) { + // Skip. + } + } + } + + fn match_and_collect_item(item_def_id: def_id, key: ~str, value: ~str) { + if !str_eq(key, ~"lang") { + ret; // Didn't match. + } + + alt self.item_refs.find(value) { + none => { + // Didn't match. + } + some(item_ref) => { + // Check for duplicates. + alt copy *item_ref { + some(original_def_id) + if original_def_id != item_def_id => { + + self.session.warn(#fmt("duplicate entry for `%s`", + value)); + } + some(_) | none => { + // OK. + } + } + + // Matched. + *item_ref = some(item_def_id); + } + } + } + + fn collect_local_language_items() { + let this = unsafe { ptr::addr_of(self) }; + visit_crate(*self.crate, (), mk_simple_visitor(@{ + visit_item: |item| { + for item.attrs.each |attribute| { + unsafe { + (*this).match_and_collect_meta_item(local_def(item + .id), + attribute.node + .value); + } + } + } + with *default_simple_visitor() + })); + } + + fn collect_external_language_items() { + let crate_store = self.session.cstore; + do iter_crate_data(crate_store) |crate_number, _crate_metadata| { + for each_path(crate_store, crate_number) |path_entry| { + let def_id; + alt path_entry.def_like { + dl_def(def_ty(did)) => { + def_id = did; + } + dl_def(_) | dl_impl(_) | dl_field { + // Skip this. + again; + } + } + + do get_item_attrs(crate_store, def_id) |meta_items| { + for meta_items.each |meta_item| { + self.match_and_collect_meta_item(def_id, *meta_item); + } + } + } + } + } + + fn check_completeness() { + for self.item_refs.each |key, item_ref| { + alt copy *item_ref { + none => { + self.session.warn(#fmt("no item found for `%s`", key)); + } + some(did) => { + // OK. + } + } + } + } + + fn collect() { + self.init(); + self.collect_local_language_items(); + self.collect_external_language_items(); + self.check_completeness(); + } +} + +fn collect_language_items(crate: @crate, session: session) -> LanguageItems { + let collector = LanguageItemCollector(crate, session); + collector.collect(); + copy collector.items +} + diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs index ca00aeaa0f4a..cc6874bc9679 100644 --- a/src/rustc/middle/region.rs +++ b/src/rustc/middle/region.rs @@ -467,7 +467,7 @@ fn determine_rp_in_ty(ty: @ast::ty, alt ty.node { ast::ty_path(_, id) { alt cx.def_map.get(id) { - ast::def_ty(did) | ast::def_class(did) { + ast::def_ty(did) | ast::def_class(did, _) { if did.crate == ast::local_crate { cx.add_dep(did.node, cx.item_id); } else { diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index bddf83c429e7..e75268cde7f6 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -41,7 +41,7 @@ import syntax::visit::{visit_mod, visit_ty, vt}; import box::ptr_eq; import dvec::{dvec, extensions}; -import option::get; +import option::{get, is_some}; import str::{connect, split_str}; import vec::pop; @@ -604,7 +604,7 @@ class Resolver { let unused_import_lint_level: level; let trait_info: hashmap>; - let structs: hashmap; + let structs: hashmap; // The number of imports that are currently unresolved. let mut unresolved_imports: uint; @@ -926,7 +926,8 @@ class Resolver { (*name_bindings).define_impl(impl_info); // Record the def ID of this struct. - self.structs.insert(local_def(item.id), ()); + self.structs.insert(local_def(item.id), + is_some(optional_ctor)); visit_item(item, new_parent, visitor); } @@ -1378,12 +1379,16 @@ class Resolver { (*child_name_bindings).define_type(def); } - def_class(def_id) { + def_class(def_id, has_constructor) { #debug("(building reduced graph for external \ - crate) building value and type %s", - final_ident); - (*child_name_bindings).define_value(def); + crate) building type %s (value? %d)", + final_ident, + if has_constructor { 1 } else { 0 }); (*child_name_bindings).define_type(def); + + if has_constructor { + (*child_name_bindings).define_value(def); + } } def_self(*) | def_arg(*) | def_local(*) | def_prim_ty(*) | def_ty_param(*) | def_binding(*) | @@ -4201,7 +4206,9 @@ class Resolver { some(definition @ def_ty(class_id)) if self.structs.contains_key(class_id) { - self.record_def(expr.id, def_class(class_id)); + let has_constructor = self.structs.get(class_id); + let class_def = def_class(class_id, has_constructor); + self.record_def(expr.id, class_def); } _ { self.session.span_err(path.span, diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index b6b1873b1dc2..465aeebe3af2 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2587,7 +2587,7 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> ~str { fn def_has_ty_params(def: ast::def) -> bool { alt def { - ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_) + ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_, _) { true } _ { false } } diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs index ebd189a15b71..3baea12ab484 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -270,7 +270,7 @@ fn ast_ty_to_ty( path_to_str(path))); } some(d) { d }}; alt a_def { - ast::def_ty(did) | ast::def_class(did) { + ast::def_ty(did) | ast::def_class(did, _) { ast_path_to_ty(self, rscope, did, path, id).ty } ast::def_prim_ty(nty) { diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 0b78fd1a5054..eaf0e90b26d6 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1649,7 +1649,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, // Resolve the path. let class_id; alt tcx.def_map.find(id) { - some(ast::def_class(type_def_id)) => { + some(ast::def_class(type_def_id, _)) => { class_id = type_def_id; } _ => { @@ -2160,7 +2160,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> } ast::def_fn(id, _) | ast::def_const(id) | - ast::def_variant(_, id) | ast::def_class(id) { + ast::def_variant(_, id) | ast::def_class(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); } ast::def_binding(nid) { diff --git a/src/rustc/middle/typeck/check/regionmanip.rs b/src/rustc/middle/typeck/check/regionmanip.rs index 2231d9b320aa..d1052fd6a2ab 100644 --- a/src/rustc/middle/typeck/check/regionmanip.rs +++ b/src/rustc/middle/typeck/check/regionmanip.rs @@ -200,7 +200,7 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region { ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(_, _) | ast::def_ty(_) | ast::def_prim_ty(_) | - ast::def_ty_param(_, _) | ast::def_class(_) | + ast::def_ty_param(_, _) | ast::def_class(_, _) | ast::def_region(_) { ty::re_static } diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 406c46cc6c6a..b2cce508e57f 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -88,6 +88,7 @@ mod middle { mod region; mod const_eval; mod astencode; + mod lang_items; } mod front { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index a9f759b26aac..4a927744f07a 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/Host.h" +#include "llvm/Support/Debug.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/Object.h" @@ -185,3 +186,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, unwrap(target), unwrap(source), order)); } + +extern "C" void LLVMSetDebug(int Enabled) { + DebugFlag = Enabled; +} diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index f3a3d7f4f23b..64b560999bec 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -528,6 +528,7 @@ LLVMSetAlignment LLVMSetCleanup LLVMSetCurrentDebugLocation LLVMSetDataLayout +LLVMSetDebug LLVMSetFunctionCallConv LLVMSetGC LLVMSetGlobalConstant diff --git a/src/test/compile-fail/not-utf8.bin b/src/test/compile-fail/not-utf8.bin new file mode 100644 index 000000000000..4148e5b88fe6 Binary files /dev/null and b/src/test/compile-fail/not-utf8.bin differ diff --git a/src/test/compile-fail/not-utf8.rs b/src/test/compile-fail/not-utf8.rs new file mode 100644 index 000000000000..2038f1393590 --- /dev/null +++ b/src/test/compile-fail/not-utf8.rs @@ -0,0 +1,5 @@ +// error-pattern: is not UTF-8 + +fn foo() { + #include("not-utf8.bin") +} diff --git a/src/test/run-pass/issue-3029.rs b/src/test/run-pass/issue-3029.rs new file mode 100644 index 000000000000..352ada202e2a --- /dev/null +++ b/src/test/run-pass/issue-3029.rs @@ -0,0 +1,8 @@ +// xfail-test +fn fail_then_concat() { + let x = ~[], y = ~[3]; + fail; + x += y; + ~"good" + ~"bye"; +} + diff --git a/src/test/run-pass/issue-868.rs b/src/test/run-pass/issue-868.rs new file mode 100644 index 000000000000..dcc8c4e08db8 --- /dev/null +++ b/src/test/run-pass/issue-868.rs @@ -0,0 +1,15 @@ +fn f(g: fn() -> T) -> T { g() } + +fn main() { + let _x = f( | | { 10 }); + // used to be: cannot determine a type for this expression + f(| | { }); + // ditto + f( | | { ()}); + // always worked + let _: () = f(| | { }); + // empty block with no type info should compile too + let _ = f(||{}); + let _ = (||{}); +} + diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs index 532daf3651c8..eb866ee7b3e7 100644 --- a/src/test/run-pass/task-comm-0.rs +++ b/src/test/run-pass/task-comm-0.rs @@ -1,31 +1,29 @@ use std; -import comm; -import comm::chan; -import comm::send; +import pipes; +import pipes::chan; +import pipes::port; import task; fn main() { test05(); } fn test05_start(ch : chan) { - log(error, ch); - send(ch, 10); + ch.send(10); #error("sent 10"); - send(ch, 20); + ch.send(20); #error("sent 20"); - send(ch, 30); + ch.send(30); #error("sent 30"); } fn test05() { - let po = comm::port(); - let ch = comm::chan(po); + let (ch, po) = pipes::stream(); task::spawn(|| test05_start(ch) ); - let mut value = comm::recv(po); + let mut value = po.recv(); log(error, value); - value = comm::recv(po); + value = po.recv(); log(error, value); - value = comm::recv(po); + value = po.recv(); log(error, value); assert (value == 30); } diff --git a/src/test/run-pass/task-comm-10.rs b/src/test/run-pass/task-comm-10.rs index 1d0963a29dca..ef94a13c0726 100644 --- a/src/test/run-pass/task-comm-10.rs +++ b/src/test/run-pass/task-comm-10.rs @@ -1,28 +1,27 @@ use std; import task; -import comm; +import pipes; -fn start(c: comm::chan>) { - let p = comm::port(); - comm::send(c, comm::chan(p)); +fn start(c: pipes::chan>) { + let (ch, p) = pipes::stream(); + c.send(ch); let mut a; let mut b; - a = comm::recv(p); + a = p.recv(); assert a == ~"A"; log(error, a); - b = comm::recv(p); + b = p.recv(); assert b == ~"B"; log(error, b); } fn main() { - let p = comm::port(); - let ch = comm::chan(p); + let (ch, p) = pipes::stream(); let child = task::spawn(|| start(ch) ); - let c = comm::recv(p); - comm::send(c, ~"A"); - comm::send(c, ~"B"); + let c = p.recv(); + c.send(~"A"); + c.send(~"B"); task::yield(); } diff --git a/src/test/run-pass/task-comm-11.rs b/src/test/run-pass/task-comm-11.rs index f96f9d148d00..5e1e5c5facd2 100644 --- a/src/test/run-pass/task-comm-11.rs +++ b/src/test/run-pass/task-comm-11.rs @@ -1,15 +1,14 @@ use std; -import comm; +import pipes; import task; -fn start(c: comm::chan>) { - let p: comm::port = comm::port(); - comm::send(c, comm::chan(p)); +fn start(c: pipes::chan>) { + let (ch, p) = pipes::stream(); + c.send(ch); } fn main() { - let p = comm::port(); - let ch = comm::chan(p); + let (ch, p) = pipes::stream(); let child = task::spawn(|| start(ch) ); - let c = comm::recv(p); + let c = p.recv(); } diff --git a/src/test/run-pass/task-comm-13.rs b/src/test/run-pass/task-comm-13.rs index 3ded4aac5ae9..88220437c431 100644 --- a/src/test/run-pass/task-comm-13.rs +++ b/src/test/run-pass/task-comm-13.rs @@ -1,17 +1,16 @@ use std; import task; -import comm; -import comm::send; +import pipes; +import pipes::send; -fn start(c: comm::chan, start: int, number_of_messages: int) { +fn start(c: pipes::chan, start: int, number_of_messages: int) { let mut i: int = 0; - while i < number_of_messages { send(c, start + i); i += 1; } + while i < number_of_messages { c.send(start + i); i += 1; } } fn main() { #debug("Check that we don't deadlock."); - let p = comm::port::(); - let ch = comm::chan(p); + let (ch, p) = pipes::stream(); task::try(|| start(ch, 0, 10) ); #debug("Joined task"); } diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs index ef9c4ae5010d..268b6d06dfde 100644 --- a/src/test/run-pass/task-comm-14.rs +++ b/src/test/run-pass/task-comm-14.rs @@ -1,15 +1,14 @@ -use std; -import comm; import task; fn main() { - let po = comm::port::(); - let ch = comm::chan(po); + let po = pipes::port_set(); // Spawn 10 tasks each sending us back one int. let mut i = 10; while (i > 0) { log(debug, i); + let (ch, p) = pipes::stream(); + po.add(p); task::spawn(|copy i| child(i, ch) ); i = i - 1; } @@ -18,17 +17,16 @@ fn main() { // anything back, so we deadlock here. i = 10; - let mut value = 0; while (i > 0) { log(debug, i); - value = comm::recv(po); + po.recv(); i = i - 1; } #debug("main thread exiting"); } -fn child(x: int, ch: comm::chan) { +fn child(x: int, ch: pipes::chan) { log(debug, x); - comm::send(ch, copy x); + ch.send(x); } diff --git a/src/test/run-pass/task-comm-15.rs b/src/test/run-pass/task-comm-15.rs index d9291fd68986..71a732490ce0 100644 --- a/src/test/run-pass/task-comm-15.rs +++ b/src/test/run-pass/task-comm-15.rs @@ -1,23 +1,21 @@ // xfail-win32 use std; -import comm; import task; -fn start(c: comm::chan, i0: int) { +fn start(c: pipes::chan, i0: int) { let mut i = i0; while i > 0 { - comm::send(c, 0); + c.send(0); i = i - 1; } } fn main() { - let p = comm::port(); // Spawn a task that sends us back messages. The parent task // is likely to terminate before the child completes, so from // the child's point of view the receiver may die. We should // drop messages on the floor in this case, and not crash! - let ch = comm::chan(p); - let child = task::spawn(|| start(ch, 10) ); - let c = comm::recv(p); + let (ch, p) = pipes::stream(); + task::spawn(|| start(ch, 10)); + p.recv(); } diff --git a/src/test/run-pass/task-comm-16.rs b/src/test/run-pass/task-comm-16.rs index bc46de64cd72..2d1c72df713c 100644 --- a/src/test/run-pass/task-comm-16.rs +++ b/src/test/run-pass/task-comm-16.rs @@ -1,44 +1,41 @@ // -*- rust -*- use std; -import comm; -import comm::send; -import comm::port; -import comm::recv; -import comm::chan; +import pipes; +import pipes::send; +import pipes::port; +import pipes::recv; +import pipes::chan; // Tests of ports and channels on various types fn test_rec() { type r = {val0: int, val1: u8, val2: char}; - let po = comm::port(); - let ch = chan(po); + let (ch, po) = pipes::stream(); let r0: r = {val0: 0, val1: 1u8, val2: '2'}; - send(ch, r0); + ch.send(r0); let mut r1: r; - r1 = recv(po); + r1 = po.recv(); assert (r1.val0 == 0); assert (r1.val1 == 1u8); assert (r1.val2 == '2'); } fn test_vec() { - let po = port(); - let ch = chan(po); + let (ch, po) = pipes::stream(); let v0: ~[int] = ~[0, 1, 2]; - send(ch, v0); - let v1 = recv(po); + ch.send(v0); + let v1 = po.recv(); assert (v1[0] == 0); assert (v1[1] == 1); assert (v1[2] == 2); } fn test_str() { - let po = port(); - let ch = chan(po); - let s0 = ~"test"; - send(ch, s0); - let s1 = recv(po); + let (ch, po) = pipes::stream(); + let s0 = "test"; + ch.send(s0); + let s1 = po.recv(); assert (s1[0] == 't' as u8); assert (s1[1] == 'e' as u8); assert (s1[2] == 's' as u8); @@ -47,33 +44,36 @@ fn test_str() { fn test_tag() { enum t { tag1, tag2(int), tag3(int, u8, char), } - let po = port(); - let ch = chan(po); - send(ch, tag1); - send(ch, tag2(10)); - send(ch, tag3(10, 11u8, 'A')); + let (ch, po) = pipes::stream(); + ch.send(tag1); + ch.send(tag2(10)); + ch.send(tag3(10, 11u8, 'A')); let mut t1: t; - t1 = recv(po); + t1 = po.recv(); assert (t1 == tag1); - t1 = recv(po); + t1 = po.recv(); assert (t1 == tag2(10)); - t1 = recv(po); + t1 = po.recv(); assert (t1 == tag3(10, 11u8, 'A')); } fn test_chan() { - let po = port(); - let ch = chan(po); - let po0 = port(); - let ch0 = chan(po0); - send(ch, ch0); - let ch1 = recv(po); + let (ch, po) = pipes::stream(); + let (ch0, po0) = pipes::stream(); + ch.send(ch0); + let ch1 = po.recv(); // Does the transmitted channel still work? - send(ch1, 10); + ch1.send(10); let mut i: int; - i = recv(po0); + i = po0.recv(); assert (i == 10); } -fn main() { test_rec(); test_vec(); test_str(); test_tag(); test_chan(); } +fn main() { + test_rec(); + test_vec(); + test_str(); + test_tag(); + test_chan(); +} diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index c03db4420226..05c057d85fd8 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -1,9 +1,9 @@ use std; import task; -import comm; -import comm::chan; -import comm::send; -import comm::recv; +import pipes; +import pipes::chan; +import pipes::send; +import pipes::recv; fn main() { #debug("===== WITHOUT THREADS ====="); test00(); } @@ -12,7 +12,7 @@ fn test00_start(ch: chan, message: int, count: int) { let mut i: int = 0; while i < count { #debug("Sending Message"); - send(ch, message + 0); + ch.send(message + 0); i = i + 1; } #debug("Ending test00_start"); @@ -24,14 +24,14 @@ fn test00() { #debug("Creating tasks"); - let po = comm::port(); - let ch = chan(po); + let po = pipes::port_set(); let mut i: int = 0; // Create and spawn tasks... let mut results = ~[]; while i < number_of_tasks { + let ch = po.chan(); do task::task().future_result(|-r| { results += ~[r]; }).spawn |copy i| { @@ -45,7 +45,7 @@ fn test00() { for results.each |r| { i = 0; while i < number_of_messages { - let value = recv(po); + let value = po.recv(); sum += value; i = i + 1; } diff --git a/src/test/run-pass/task-comm-4.rs b/src/test/run-pass/task-comm-4.rs index f7de33c63d62..9b99c1cb799b 100644 --- a/src/test/run-pass/task-comm-4.rs +++ b/src/test/run-pass/task-comm-4.rs @@ -1,44 +1,43 @@ use std; -import comm; -import comm::send; +import pipes; +import pipes::send; fn main() { test00(); } fn test00() { let mut r: int = 0; let mut sum: int = 0; - let p = comm::port(); - let c = comm::chan(p); - send(c, 1); - send(c, 2); - send(c, 3); - send(c, 4); - r = comm::recv(p); + let (c, p) = pipes::stream(); + c.send(1); + c.send(2); + c.send(3); + c.send(4); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - send(c, 5); - send(c, 6); - send(c, 7); - send(c, 8); - r = comm::recv(p); + c.send(5); + c.send(6); + c.send(7); + c.send(8); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); assert (sum == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8); diff --git a/src/test/run-pass/task-comm-5.rs b/src/test/run-pass/task-comm-5.rs index a0d4f4595bec..249bdaf1c9a5 100644 --- a/src/test/run-pass/task-comm-5.rs +++ b/src/test/run-pass/task-comm-5.rs @@ -1,17 +1,16 @@ use std; -import comm; +import pipes; fn main() { test00(); } fn test00() { let r: int = 0; let mut sum: int = 0; - let p = comm::port(); - let c = comm::chan(p); + let (c, p) = pipes::stream(); let number_of_messages: int = 1000; let mut i: int = 0; - while i < number_of_messages { comm::send(c, i + 0); i += 1; } + while i < number_of_messages { c.send(i + 0); i += 1; } i = 0; - while i < number_of_messages { sum += comm::recv(p); i += 1; } + while i < number_of_messages { sum += p.recv(); i += 1; } assert (sum == number_of_messages * (number_of_messages - 1) / 2); } diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs index b363b25e864a..8bc93a78913d 100644 --- a/src/test/run-pass/task-comm-6.rs +++ b/src/test/run-pass/task-comm-6.rs @@ -1,37 +1,37 @@ use std; -import comm; -import comm::send; -import comm::chan; -import comm::recv; +import pipes; +import pipes::send; +import pipes::chan; +import pipes::recv; fn main() { test00(); } fn test00() { let mut r: int = 0; let mut sum: int = 0; - let p = comm::port(); - let c0 = chan(p); - let c1 = chan(p); - let c2 = chan(p); - let c3 = chan(p); + let p = pipes::port_set(); + let c0 = p.chan(); + let c1 = p.chan(); + let c2 = p.chan(); + let c3 = p.chan(); let number_of_messages: int = 1000; let mut i: int = 0; while i < number_of_messages { - send(c0, i + 0); - send(c1, i + 0); - send(c2, i + 0); - send(c3, i + 0); + c0.send(i + 0); + c1.send(i + 0); + c2.send(i + 0); + c3.send(i + 0); i += 1; } i = 0; while i < number_of_messages { - r = recv(p); + r = p.recv(); sum += r; - r = recv(p); + r = p.recv(); sum += r; - r = recv(p); + r = p.recv(); sum += r; - r = recv(p); + r = p.recv(); sum += r; i += 1; } diff --git a/src/test/run-pass/task-comm-7.rs b/src/test/run-pass/task-comm-7.rs index b8922400777c..1df3de6ba1eb 100644 --- a/src/test/run-pass/task-comm-7.rs +++ b/src/test/run-pass/task-comm-7.rs @@ -1,43 +1,45 @@ use std; import task; -import comm; fn main() { test00(); } -fn test00_start(c: comm::chan, start: int, number_of_messages: int) { +fn test00_start(c: pipes::chan, start: int, number_of_messages: int) { let mut i: int = 0; - while i < number_of_messages { comm::send(c, start + i); i += 1; } + while i < number_of_messages { c.send(start + i); i += 1; } } fn test00() { let mut r: int = 0; let mut sum: int = 0; - let p = comm::port(); + let p = pipes::port_set(); let number_of_messages: int = 10; - let c = comm::chan(p); + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 0, number_of_messages); } + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 1, number_of_messages); } + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 2, number_of_messages); } + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 3, number_of_messages); } let mut i: int = 0; while i < number_of_messages { - r = comm::recv(p); + r = p.recv(); sum += r; - r = comm::recv(p); + r = p.recv(); sum += r; - r = comm::recv(p); + r = p.recv(); sum += r; - r = comm::recv(p); + r = p.recv(); sum += r; i += 1; } diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs index 964029dee207..939cfd15797f 100644 --- a/src/test/run-pass/task-comm-9.rs +++ b/src/test/run-pass/task-comm-9.rs @@ -1,20 +1,19 @@ use std; import task; -import comm; fn main() { test00(); } -fn test00_start(c: comm::chan, number_of_messages: int) { +fn test00_start(c: pipes::chan, number_of_messages: int) { let mut i: int = 0; - while i < number_of_messages { comm::send(c, i + 0); i += 1; } + while i < number_of_messages { c.send(i + 0); i += 1; } } fn test00() { let r: int = 0; let mut sum: int = 0; - let p = comm::port(); + let p = pipes::port_set(); let number_of_messages: int = 10; - let ch = comm::chan(p); + let ch = p.chan(); let mut result = none; do task::task().future_result(|-r| { result = some(r); }).spawn { @@ -23,7 +22,7 @@ fn test00() { let mut i: int = 0; while i < number_of_messages { - sum += comm::recv(p); + sum += p.recv(); log(debug, r); i += 1; } diff --git a/src/test/run-pass/trivial-message.rs b/src/test/run-pass/trivial-message.rs index 487b440ee420..ab3efd6b22ea 100644 --- a/src/test/run-pass/trivial-message.rs +++ b/src/test/run-pass/trivial-message.rs @@ -1,14 +1,12 @@ -use std; -import comm::*; +import pipes::{port, chan}; /* This is about the simplest program that can successfully send a message. */ fn main() { - let po = port(); - let ch = chan(po); - send(ch, 42); - let r = recv(po); + let (ch, po) = pipes::stream(); + ch.send(42); + let r = po.recv(); log(error, r); } diff --git a/src/test/run-pass/unreachable-code.rs b/src/test/run-pass/unreachable-code.rs new file mode 100644 index 000000000000..0d1a49917512 --- /dev/null +++ b/src/test/run-pass/unreachable-code.rs @@ -0,0 +1,31 @@ +// xfail-pretty + +fn id(x: bool) -> bool { x } + +fn call_id() { + let c <- fail; + id(c); +} + +fn call_id_2() { id(true) && id(ret); } + +fn call_id_3() { id(ret) && id(ret); } + +fn log_fail() { log(error, fail); } + +fn log_ret() { log(error, ret); } + +fn log_break() { loop { log(error, break); } } + +fn log_again() { loop { log(error, again); } } + +fn ret_ret() -> int { ret (ret 2) + 3; } + +fn ret_guard() { + alt 2 { + x if (ret) { x; } + _ {} + } +} + +fn main() {}