Merge branch 'incoming' of github.com:mozilla/rust
This commit is contained in:
commit
97422f0f0f
111
doc/tutorial.md
111
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<T: to_str>(elts: ~[T]) -> ~str {
|
||||
let mut result = ~"", first = true;
|
||||
for elts.each |elt| {
|
||||
@ -2476,18 +2480,18 @@ fn comma_sep<T: to_str>(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<T> {
|
||||
trait seq<T> {
|
||||
fn len() -> uint;
|
||||
fn iter(fn(T));
|
||||
}
|
||||
@ -2499,26 +2503,26 @@ impl <T> of seq<T> 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<int>`—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<T: drawable>(shapes: ~[T]) {
|
||||
@ -2549,14 +2553,14 @@ fn draw_all<T: drawable>(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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<T: send> for exclusive<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience code for sharing arcs between tasks
|
||||
|
||||
type get_chan<T: const send> = chan<chan<arc<T>>>;
|
||||
|
||||
// (terminate, get)
|
||||
type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);
|
||||
|
||||
class shared_arc_res {
|
||||
let c: comm::chan<()>;
|
||||
new(c: comm::chan<()>) { self.c = c; }
|
||||
drop { self.c.send(()); }
|
||||
}
|
||||
|
||||
fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
|
||||
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<T: send const>(c: get_chan<T>) -> arc::arc<T> {
|
||||
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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -161,6 +161,7 @@ mod tuple;
|
||||
|
||||
// Ubiquitous-utility-type modules
|
||||
|
||||
mod ops;
|
||||
mod cmp;
|
||||
mod num;
|
||||
mod hash;
|
||||
|
@ -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
|
||||
|
@ -18,12 +18,28 @@ enum dlist_node<T> = @{
|
||||
mut next: dlist_link<T>
|
||||
};
|
||||
|
||||
// Needs to be an @-box so nodes can back-reference it.
|
||||
enum dlist<T> = @{
|
||||
mut size: uint,
|
||||
mut hd: dlist_link<T>,
|
||||
mut tl: dlist_link<T>
|
||||
};
|
||||
class dlist_root<T> {
|
||||
let mut size: uint;
|
||||
let mut hd: dlist_link<T>;
|
||||
let mut tl: dlist_link<T>;
|
||||
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<T> = @dlist_root<T>;
|
||||
|
||||
impl private_methods<T> for dlist_node<T> {
|
||||
pure fn assert_links() {
|
||||
@ -91,7 +107,7 @@ pure fn new_dlist_node<T>(+data: T) -> dlist_node<T> {
|
||||
|
||||
/// Creates a new, empty dlist.
|
||||
pure fn new_dlist<T>() -> dlist<T> {
|
||||
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<T>(lists: dlist<dlist<T>>) -> dlist<T> {
|
||||
result
|
||||
}
|
||||
|
||||
impl private_methods<T> for dlist<T> {
|
||||
impl private_methods<T> for dlist_root<T> {
|
||||
pure fn new_link(-data: T) -> dlist_link<T> {
|
||||
some(dlist_node(@{data: data, mut linked: true,
|
||||
mut prev: none, mut next: none}))
|
||||
@ -288,20 +304,6 @@ impl extensions<T> for dlist<T> {
|
||||
tl.map(|nobe| self.unlink(nobe));
|
||||
tl
|
||||
}
|
||||
/// Remove data from the head of the list. O(1).
|
||||
fn pop() -> option<T> {
|
||||
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<T> {
|
||||
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<dlist_node<T>> { self.hd }
|
||||
/// Get the node at the list's tail. O(1).
|
||||
@ -334,7 +336,7 @@ impl extensions<T> for dlist<T> {
|
||||
* to the other list's head. O(1).
|
||||
*/
|
||||
fn append(them: dlist<T>) {
|
||||
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<T> for dlist<T> {
|
||||
* list's tail to this list's head. O(1).
|
||||
*/
|
||||
fn prepend(them: dlist<T>) {
|
||||
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<T> for dlist<T> {
|
||||
|
||||
/// Reverse the list's elements in place. O(n).
|
||||
fn reverse() {
|
||||
let temp = new_dlist::<T>();
|
||||
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<T> for dlist<T> {
|
||||
}
|
||||
|
||||
impl extensions<T: copy> for dlist<T> {
|
||||
/// Remove data from the head of the list. O(1).
|
||||
fn pop() -> option<T> { self.pop_n().map (|nobe| nobe.data) }
|
||||
/// Remove data from the tail of the list. O(1).
|
||||
fn pop_tail() -> option<T> { self.pop_tail_n().map (|nobe| nobe.data) }
|
||||
/// Get data at the list's head. O(1).
|
||||
pure fn peek() -> option<T> { 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::<int>();
|
||||
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::<int>();
|
||||
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::<int>();
|
||||
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::<int>().head();
|
||||
}
|
||||
#[test] #[should_fail] #[ignore(cfg(windows))]
|
||||
fn test_insert_already_present_before() {
|
||||
fn test_dlist_insert_already_present_before() {
|
||||
let l = new_dlist::<int>();
|
||||
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::<int>();
|
||||
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::<int>();
|
||||
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::<int>();
|
||||
let one = new_dlist_node(1);
|
||||
let two = new_dlist_node(2);
|
||||
|
@ -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; }
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -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; }
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -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]
|
||||
|
@ -112,27 +112,27 @@ fn to_str_bytes<U>(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 {
|
||||
|
@ -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")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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...
|
||||
}
|
||||
|
||||
|
66
src/libcore/ops.rs
Normal file
66
src/libcore/ops.rs
Normal file
@ -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<RHS,Result> {
|
||||
pure fn add(rhs: RHS) -> Result;
|
||||
}
|
||||
|
||||
#[lang="sub"]
|
||||
trait sub<RHS,Result> {
|
||||
pure fn sub(rhs: RHS) -> Result;
|
||||
}
|
||||
|
||||
#[lang="mul"]
|
||||
trait mul<RHS,Result> {
|
||||
pure fn mul(rhs: RHS) -> Result;
|
||||
}
|
||||
|
||||
#[lang="div"]
|
||||
trait div<RHS,Result> {
|
||||
pure fn div(rhs: RHS) -> Result;
|
||||
}
|
||||
|
||||
#[lang="modulo"]
|
||||
trait modulo<RHS,Result> {
|
||||
pure fn modulo(rhs: RHS) -> Result;
|
||||
}
|
||||
|
||||
#[lang="neg"]
|
||||
trait neg<RHS,Result> {
|
||||
pure fn neg(rhs: RHS) -> Result;
|
||||
}
|
||||
|
||||
#[lang="bitops"]
|
||||
trait bitops<RHS,BitCount,Result> {
|
||||
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<Index,Result> {
|
||||
pure fn index(index: Index) -> Result;
|
||||
}
|
||||
|
@ -30,59 +30,6 @@ macro_rules! move {
|
||||
// places. Once there is unary move, it can be removed.
|
||||
fn move<T>(-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<T: send> : recv<T> {
|
||||
vec::push(self.ports, port)
|
||||
}
|
||||
|
||||
fn chan() -> chan<T> {
|
||||
let (ch, po) = stream();
|
||||
self.add(po);
|
||||
ch
|
||||
}
|
||||
|
||||
fn try_recv() -> option<T> {
|
||||
let mut result = none;
|
||||
while result == none && self.ports.len() > 0 {
|
||||
@ -869,3 +822,52 @@ impl chan<T: send> of channel<T> for shared_chan<T> {
|
||||
fn shared_chan<T:send>(+c: chan<T>) -> shared_chan<T> {
|
||||
arc::exclusive(c)
|
||||
}
|
||||
|
||||
trait select2<T: send, U: send> {
|
||||
fn try_select() -> either<option<T>, option<U>>;
|
||||
fn select() -> either<T, U>;
|
||||
}
|
||||
|
||||
impl<T: send, U: send, Left: selectable recv<T>, Right: selectable recv<U>>
|
||||
of select2<T, U> for (Left, Right) {
|
||||
|
||||
fn select() -> either<T, U> {
|
||||
alt self {
|
||||
(lp, rp) {
|
||||
alt select2i(lp, rp) {
|
||||
left(()) { left (lp.recv()) }
|
||||
right(()) { right(rp.recv()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_select() -> either<option<T>, option<U>> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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"; }
|
||||
}
|
||||
|
@ -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] {
|
||||
|
@ -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)) }
|
||||
}
|
||||
|
@ -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,
|
||||
|
209
src/rustc/middle/lang_items.rs
Normal file
209
src/rustc/middle/lang_items.rs
Normal file
@ -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<def_id>;
|
||||
let mut copy_trait: option<def_id>;
|
||||
let mut send_trait: option<def_id>;
|
||||
let mut owned_trait: option<def_id>;
|
||||
|
||||
let mut add_trait: option<def_id>;
|
||||
let mut sub_trait: option<def_id>;
|
||||
let mut mul_trait: option<def_id>;
|
||||
let mut div_trait: option<def_id>;
|
||||
let mut modulo_trait: option<def_id>;
|
||||
let mut neg_trait: option<def_id>;
|
||||
let mut bitops_trait: option<def_id>;
|
||||
let mut index_trait: option<def_id>;
|
||||
|
||||
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<def_id>>;
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<def_id,@hashmap<Atom,()>>;
|
||||
let structs: hashmap<def_id,()>;
|
||||
let structs: hashmap<def_id,bool>;
|
||||
|
||||
// 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,
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
|
||||
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) {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ mod middle {
|
||||
mod region;
|
||||
mod const_eval;
|
||||
mod astencode;
|
||||
mod lang_items;
|
||||
}
|
||||
|
||||
mod front {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -528,6 +528,7 @@ LLVMSetAlignment
|
||||
LLVMSetCleanup
|
||||
LLVMSetCurrentDebugLocation
|
||||
LLVMSetDataLayout
|
||||
LLVMSetDebug
|
||||
LLVMSetFunctionCallConv
|
||||
LLVMSetGC
|
||||
LLVMSetGlobalConstant
|
||||
|
BIN
src/test/compile-fail/not-utf8.bin
Normal file
BIN
src/test/compile-fail/not-utf8.bin
Normal file
Binary file not shown.
5
src/test/compile-fail/not-utf8.rs
Normal file
5
src/test/compile-fail/not-utf8.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// error-pattern: is not UTF-8
|
||||
|
||||
fn foo() {
|
||||
#include("not-utf8.bin")
|
||||
}
|
8
src/test/run-pass/issue-3029.rs
Normal file
8
src/test/run-pass/issue-3029.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// xfail-test
|
||||
fn fail_then_concat() {
|
||||
let x = ~[], y = ~[3];
|
||||
fail;
|
||||
x += y;
|
||||
~"good" + ~"bye";
|
||||
}
|
||||
|
15
src/test/run-pass/issue-868.rs
Normal file
15
src/test/run-pass/issue-868.rs
Normal file
@ -0,0 +1,15 @@
|
||||
fn f<T>(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 _ = (||{});
|
||||
}
|
||||
|
@ -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<int>) {
|
||||
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);
|
||||
}
|
||||
|
@ -1,28 +1,27 @@
|
||||
use std;
|
||||
import task;
|
||||
import comm;
|
||||
import pipes;
|
||||
|
||||
fn start(c: comm::chan<comm::chan<~str>>) {
|
||||
let p = comm::port();
|
||||
comm::send(c, comm::chan(p));
|
||||
fn start(c: pipes::chan<pipes::chan<~str>>) {
|
||||
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();
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
use std;
|
||||
import comm;
|
||||
import pipes;
|
||||
import task;
|
||||
|
||||
fn start(c: comm::chan<comm::chan<int>>) {
|
||||
let p: comm::port<int> = comm::port();
|
||||
comm::send(c, comm::chan(p));
|
||||
fn start(c: pipes::chan<pipes::chan<int>>) {
|
||||
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();
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
use std;
|
||||
import task;
|
||||
import comm;
|
||||
import comm::send;
|
||||
import pipes;
|
||||
import pipes::send;
|
||||
|
||||
fn start(c: comm::chan<int>, start: int, number_of_messages: int) {
|
||||
fn start(c: pipes::chan<int>, 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::<int>();
|
||||
let ch = comm::chan(p);
|
||||
let (ch, p) = pipes::stream();
|
||||
task::try(|| start(ch, 0, 10) );
|
||||
#debug("Joined task");
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
use std;
|
||||
import comm;
|
||||
import task;
|
||||
|
||||
fn main() {
|
||||
let po = comm::port::<int>();
|
||||
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<int>) {
|
||||
fn child(x: int, ch: pipes::chan<int>) {
|
||||
log(debug, x);
|
||||
comm::send(ch, copy x);
|
||||
ch.send(x);
|
||||
}
|
||||
|
@ -1,23 +1,21 @@
|
||||
// xfail-win32
|
||||
use std;
|
||||
import comm;
|
||||
import task;
|
||||
|
||||
fn start(c: comm::chan<int>, i0: int) {
|
||||
fn start(c: pipes::chan<int>, 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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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<int>, 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,43 +1,45 @@
|
||||
use std;
|
||||
import task;
|
||||
import comm;
|
||||
|
||||
fn main() { test00(); }
|
||||
|
||||
fn test00_start(c: comm::chan<int>, start: int, number_of_messages: int) {
|
||||
fn test00_start(c: pipes::chan<int>, 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;
|
||||
}
|
||||
|
@ -1,20 +1,19 @@
|
||||
use std;
|
||||
import task;
|
||||
import comm;
|
||||
|
||||
fn main() { test00(); }
|
||||
|
||||
fn test00_start(c: comm::chan<int>, number_of_messages: int) {
|
||||
fn test00_start(c: pipes::chan<int>, 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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
31
src/test/run-pass/unreachable-code.rs
Normal file
31
src/test/run-pass/unreachable-code.rs
Normal file
@ -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() {}
|
Loading…
x
Reference in New Issue
Block a user