Merge branch 'incoming' of github.com:mozilla/rust

This commit is contained in:
Paul Stansifer 2012-07-26 16:16:28 -07:00
commit 97422f0f0f
57 changed files with 829 additions and 467 deletions

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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;
}

View File

@ -161,6 +161,7 @@ mod tuple;
// Ubiquitous-utility-type modules
mod ops;
mod cmp;
mod num;
mod hash;

View File

@ -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

View File

@ -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);

View File

@ -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; }
}
//

View File

@ -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; }
}
//

View File

@ -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]

View File

@ -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 {

View File

@ -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")
}
})
}

View File

@ -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
View 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;
}

View File

@ -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);
}
}

View File

@ -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; }
}
/**

View File

@ -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);
}
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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()}

View File

@ -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 {

View File

@ -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)
]
}

View File

@ -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) {

View File

@ -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);

View File

@ -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"; }
}

View File

@ -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] {

View File

@ -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)) }
}

View File

@ -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,

View 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
}

View File

@ -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 {

View File

@ -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,

View File

@ -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 }
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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
}

View File

@ -88,6 +88,7 @@ mod middle {
mod region;
mod const_eval;
mod astencode;
mod lang_items;
}
mod front {

View File

@ -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;
}

View File

@ -528,6 +528,7 @@ LLVMSetAlignment
LLVMSetCleanup
LLVMSetCurrentDebugLocation
LLVMSetDataLayout
LLVMSetDebug
LLVMSetFunctionCallConv
LLVMSetGC
LLVMSetGlobalConstant

Binary file not shown.

View File

@ -0,0 +1,5 @@
// error-pattern: is not UTF-8
fn foo() {
#include("not-utf8.bin")
}

View File

@ -0,0 +1,8 @@
// xfail-test
fn fail_then_concat() {
let x = ~[], y = ~[3];
fail;
x += y;
~"good" + ~"bye";
}

View 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 _ = (||{});
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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");
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View 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() {}