librustc: Make the compiler ignore purity.

For bootstrapping purposes, this commit does not remove all uses of
the keyword "pure" -- doing so would cause the compiler to no longer
bootstrap due to some syntax extensions ("deriving" in particular).
Instead, it makes the compiler ignore "pure". Post-snapshot, we can
remove "pure" from the language.

There are quite a few (~100) borrow check errors that were essentially
all the result of mutable fields or partial borrows of `@mut`. Per
discussions with Niko I think we want to allow partial borrows of
`@mut` but detect obvious footguns. We should also improve the error
message when `@mut` is erroneously reborrowed.
This commit is contained in:
Patrick Walton 2013-03-16 11:11:31 -07:00
parent c4db4faefa
commit e78f2e2ac5
72 changed files with 373 additions and 540 deletions

View file

@ -214,7 +214,7 @@ false fn for
if impl if impl
let loop let loop
match mod mut match mod mut
priv pub pure priv pub
ref return ref return
self static struct super self static struct super
true trait type true trait type
@ -936,7 +936,6 @@ Specifically, the following operations are considered unsafe:
- Dereferencing a [raw pointer](#pointer-types). - Dereferencing a [raw pointer](#pointer-types).
- Casting a [raw pointer](#pointer-types) to a safe pointer type. - Casting a [raw pointer](#pointer-types) to a safe pointer type.
- Breaking the [purity-checking rules](#pure-functions) in a `pure` function.
- Calling an unsafe function. - Calling an unsafe function.
##### Unsafe blocks ##### Unsafe blocks
@ -946,42 +945,6 @@ This facility exists because the static semantics of Rust are a necessary approx
When a programmer has sufficient conviction that a sequence of unsafe operations is actually safe, they can encapsulate that sequence (taken as a whole) within an `unsafe` block. The compiler will consider uses of such code "safe", to the surrounding context. When a programmer has sufficient conviction that a sequence of unsafe operations is actually safe, they can encapsulate that sequence (taken as a whole) within an `unsafe` block. The compiler will consider uses of such code "safe", to the surrounding context.
#### Pure functions
A pure function declaration is identical to a function declaration, except that
it is declared with the additional keyword `pure`. In addition, the typechecker
checks the body of a pure function with a restricted set of typechecking rules.
A pure function may only modify data owned by its own stack frame.
So, a pure function may modify a local variable allocated on the stack, but not a mutable reference that it takes as an argument.
A pure function may only call other pure functions, not general functions.
An example of a pure function:
~~~~
pure fn lt_42(x: int) -> bool {
return (x < 42);
}
~~~~
Pure functions may call other pure functions:
~~~~{.xfail-test}
pure fn pure_length<T>(ls: List<T>) -> uint { ... }
pure fn nonempty_list<T>(ls: List<T>) -> bool { pure_length(ls) > 0u }
~~~~
These purity-checking rules approximate the concept of referential transparency:
that a call-expression could be rewritten with the literal-expression of its return value, without changing the meaning of the program.
Since they are an approximation, sometimes these rules are *too* restrictive.
Rust allows programmers to violate these rules using [`unsafe` blocks](#unsafe-blocks), which we already saw.
As with any `unsafe` block, those that violate static purity carry transfer the burden of safety-proof from the compiler to the programmer.
Programmers should exercise caution when breaking such rules.
For more details on purity, see [the borrowed pointer tutorial][borrow].
[borrow]: tutorial-borrowed-ptr.html
#### Diverging functions #### Diverging functions
A special kind of function can be declared with a `!` character where the A special kind of function can be declared with a `!` character where the
@ -1246,10 +1209,10 @@ For example:
~~~~ ~~~~
trait Num { trait Num {
static pure fn from_int(n: int) -> Self; static fn from_int(n: int) -> Self;
} }
impl Num for float { impl Num for float {
static pure fn from_int(n: int) -> float { n as float } static fn from_int(n: int) -> float { n as float }
} }
let x: float = Num::from_int(42); let x: float = Num::from_int(42);
~~~~ ~~~~
@ -2643,7 +2606,7 @@ Raw pointers (`*`)
### Function types ### Function types
The function type-constructor `fn` forms new function types. A function type The function type-constructor `fn` forms new function types. A function type
consists of a set of function-type modifiers (`pure`, `unsafe`, `extern`, etc.), consists of a set of function-type modifiers (`unsafe`, `extern`, etc.),
a sequence of input slots and an output slot. a sequence of input slots and an output slot.
An example of a `fn` type: An example of a `fn` type:

View file

@ -486,12 +486,12 @@ For example, we could write a subroutine like this:
~~~ ~~~
struct Point {x: float, y: float} struct Point {x: float, y: float}
fn get_x(p: &r/Point) -> &r/float { &p.x } fn get_x(p: &'r Point) -> &'r float { &p.x }
~~~ ~~~
Here, the function `get_x()` returns a pointer into the structure it Here, the function `get_x()` returns a pointer into the structure it
was given. The type of the parameter (`&r/Point`) and return type was given. The type of the parameter (`&'r Point`) and return type
(`&r/float`) both use a new syntactic form that we have not seen so (`&'r float`) both use a new syntactic form that we have not seen so
far. Here the identifier `r` names the lifetime of the pointer far. Here the identifier `r` names the lifetime of the pointer
explicitly. So in effect, this function declares that it takes a explicitly. So in effect, this function declares that it takes a
pointer with lifetime `r` and returns a pointer with that same pointer with lifetime `r` and returns a pointer with that same
@ -572,8 +572,8 @@ function:
# Rectangle(Point, Size) // upper-left, dimensions # Rectangle(Point, Size) // upper-left, dimensions
# } # }
# fn compute_area(shape: &Shape) -> float { 0f } # fn compute_area(shape: &Shape) -> float { 0f }
fn select<T>(shape: &r/Shape, threshold: float, fn select<T>(shape: &'r Shape, threshold: float,
a: &r/T, b: &r/T) -> &r/T { a: &'r T, b: &'r T) -> &'r T {
if compute_area(shape) > threshold {a} else {b} if compute_area(shape) > threshold {a} else {b}
} }
~~~ ~~~
@ -593,17 +593,17 @@ example:
# } # }
# fn compute_area(shape: &Shape) -> float { 0f } # fn compute_area(shape: &Shape) -> float { 0f }
# fn select<T>(shape: &Shape, threshold: float, # fn select<T>(shape: &Shape, threshold: float,
# a: &r/T, b: &r/T) -> &r/T { # a: &'r T, b: &'r T) -> &'r T {
# if compute_area(shape) > threshold {a} else {b} # if compute_area(shape) > threshold {a} else {b}
# } # }
// -+ r // -+ r
fn select_based_on_unit_circle<T>( // |-+ B fn select_based_on_unit_circle<T>( // |-+ B
threshold: float, a: &r/T, b: &r/T) -> &r/T { // | | threshold: float, a: &'r T, b: &'r T) -> &'r T { // | |
// | | // | |
let shape = Circle(Point {x: 0., y: 0.}, 1.); // | | let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |
select(&shape, threshold, a, b) // | | select(&shape, threshold, a, b) // | |
} // |-+ } // |-+
// -+ // -+
~~~ ~~~
In this call to `select()`, the lifetime of the first parameter shape In this call to `select()`, the lifetime of the first parameter shape
@ -629,8 +629,8 @@ returned. Here is how the new `select()` might look:
# Rectangle(Point, Size) // upper-left, dimensions # Rectangle(Point, Size) // upper-left, dimensions
# } # }
# fn compute_area(shape: &Shape) -> float { 0f } # fn compute_area(shape: &Shape) -> float { 0f }
fn select<T>(shape: &tmp/Shape, threshold: float, fn select<T>(shape: &'tmp Shape, threshold: float,
a: &r/T, b: &r/T) -> &r/T { a: &'r T, b: &'r T) -> &'r T {
if compute_area(shape) > threshold {a} else {b} if compute_area(shape) > threshold {a} else {b}
} }
~~~ ~~~
@ -649,7 +649,7 @@ concise to just omit the named lifetime for `shape` altogether:
# } # }
# fn compute_area(shape: &Shape) -> float { 0f } # fn compute_area(shape: &Shape) -> float { 0f }
fn select<T>(shape: &Shape, threshold: float, fn select<T>(shape: &Shape, threshold: float,
a: &r/T, b: &r/T) -> &r/T { a: &'r T, b: &'r T) -> &'r T {
if compute_area(shape) > threshold {a} else {b} if compute_area(shape) > threshold {a} else {b}
} }
~~~ ~~~

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use cast::transmute;
use option; use option;
use prelude::*; use prelude::*;
@ -15,11 +16,21 @@ use prelude::*;
/// ///
/// Similar to a mutable option type, but friendlier. /// Similar to a mutable option type, but friendlier.
#[deriving_eq]
pub struct Cell<T> { pub struct Cell<T> {
mut value: Option<T> mut value: Option<T>
} }
impl<T:cmp::Eq> cmp::Eq for Cell<T> {
pure fn eq(&self, other: &Cell<T>) -> bool {
unsafe {
let frozen_self: &Option<T> = transmute(&mut self.value);
let frozen_other: &Option<T> = transmute(&mut other.value);
frozen_self == frozen_other
}
}
pure fn ne(&self, other: &Cell<T>) -> bool { !self.eq(other) }
}
/// Creates a new full cell with the given value. /// Creates a new full cell with the given value.
pub fn Cell<T>(value: T) -> Cell<T> { pub fn Cell<T>(value: T) -> Cell<T> {
Cell { value: Some(value) } Cell { value: Some(value) }

View file

@ -8,10 +8,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use cast;
use either::{Either, Left, Right}; use either::{Either, Left, Right};
use kinds::Owned; use kinds::Owned;
use option; use option;
use option::{Option, Some, None, unwrap}; use option::{Option, Some, None, unwrap};
use uint;
use unstable; use unstable;
use vec; use vec;
@ -283,8 +285,12 @@ impl<T: Owned> Peekable<T> for PortSet<T> {
pure fn port_set_peek<T:Owned>(self: &PortSet<T>) -> bool { pure fn port_set_peek<T:Owned>(self: &PortSet<T>) -> bool {
// It'd be nice to use self.port.each, but that version isn't // It'd be nice to use self.port.each, but that version isn't
// pure. // pure.
for vec::each(self.ports) |p| { for uint::range(0, vec::uniq_len(&const self.ports)) |i| {
if p.peek() { return true } // XXX: Botch pending demuting.
unsafe {
let port: &Port<T> = cast::transmute(&mut self.ports[i]);
if port.peek() { return true }
}
} }
false false
} }

View file

@ -14,10 +14,10 @@ use option::Option;
pub trait Container { pub trait Container {
/// Return the number of elements in the container /// Return the number of elements in the container
pure fn len(&self) -> uint; pure fn len(&const self) -> uint;
/// Return true if the container contains no elements /// Return true if the container contains no elements
pure fn is_empty(&self) -> bool; pure fn is_empty(&const self) -> bool;
} }
pub trait Mutable: Container { pub trait Mutable: Container {

View file

@ -290,10 +290,10 @@ pub mod linear {
impl<K:Hash + IterBytes + Eq,V> Container for LinearMap<K, V> { impl<K:Hash + IterBytes + Eq,V> Container for LinearMap<K, V> {
/// Return the number of elements in the map /// Return the number of elements in the map
pure fn len(&self) -> uint { self.size } pure fn len(&const self) -> uint { self.size }
/// Return true if the map contains no elements /// Return true if the map contains no elements
pure fn is_empty(&self) -> bool { self.len() == 0 } pure fn is_empty(&const self) -> bool { self.len() == 0 }
} }
impl<K:Hash + IterBytes + Eq,V> Mutable for LinearMap<K, V> { impl<K:Hash + IterBytes + Eq,V> Mutable for LinearMap<K, V> {
@ -555,10 +555,10 @@ pub mod linear {
impl<T:Hash + IterBytes + Eq> Container for LinearSet<T> { impl<T:Hash + IterBytes + Eq> Container for LinearSet<T> {
/// Return the number of elements in the set /// Return the number of elements in the set
pure fn len(&self) -> uint { self.map.len() } pure fn len(&const self) -> uint { self.map.len() }
/// Return true if the set contains no elements /// Return true if the set contains no elements
pure fn is_empty(&self) -> bool { self.map.is_empty() } pure fn is_empty(&const self) -> bool { self.map.is_empty() }
} }
impl<T:Hash + IterBytes + Eq> Mutable for LinearSet<T> { impl<T:Hash + IterBytes + Eq> Mutable for LinearSet<T> {

View file

@ -1116,7 +1116,7 @@ pub struct BytesWriter {
impl Writer for BytesWriter { impl Writer for BytesWriter {
fn write(&self, v: &[const u8]) { fn write(&self, v: &[const u8]) {
let v_len = v.len(); let v_len = v.len();
let bytes_len = self.bytes.len(); let bytes_len = vec::uniq_len(&const self.bytes);
let count = uint::max(bytes_len, self.pos + v_len); let count = uint::max(bytes_len, self.pos + v_len);
vec::reserve(&mut self.bytes, count); vec::reserve(&mut self.bytes, count);
@ -1131,7 +1131,7 @@ impl Writer for BytesWriter {
} }
fn seek(&self, offset: int, whence: SeekStyle) { fn seek(&self, offset: int, whence: SeekStyle) {
let pos = self.pos; let pos = self.pos;
let len = self.bytes.len(); let len = vec::uniq_len(&const self.bytes);
self.pos = seek_in_buf(offset, pos, len, whence); self.pos = seek_in_buf(offset, pos, len, whence);
} }
fn tell(&self) -> uint { self.pos } fn tell(&self) -> uint { self.pos }

View file

@ -46,8 +46,7 @@ pub fn unwrap<T>(m: Mut<T>) -> T {
pub impl<T> Data<T> { pub impl<T> Data<T> {
fn borrow_mut<R>(&self, op: &fn(t: &mut T) -> R) -> R { fn borrow_mut<R>(&self, op: &fn(t: &mut T) -> R) -> R {
match self.mode { match self.mode {
Immutable => fail!(fmt!("%? currently immutable", Immutable => fail!(~"currently immutable"),
self.value)),
ReadOnly | Mutable => {} ReadOnly | Mutable => {}
} }
@ -62,8 +61,7 @@ pub impl<T> Data<T> {
fn borrow_imm<R>(&self, op: &fn(t: &T) -> R) -> R { fn borrow_imm<R>(&self, op: &fn(t: &T) -> R) -> R {
match self.mode { match self.mode {
Mutable => fail!(fmt!("%? currently mutable", Mutable => fail!(~"currently mutable"),
self.value)),
ReadOnly | Immutable => {} ReadOnly | Immutable => {}
} }

View file

@ -228,14 +228,14 @@ pub pure fn while_some<T>(x: Option<T>, blk: &fn(v: T) -> Option<T>) {
} }
#[inline(always)] #[inline(always)]
pub pure fn is_none<T>(opt: &Option<T>) -> bool { pub pure fn is_none<T>(opt: &const Option<T>) -> bool {
//! Returns true if the option equals `none` //! Returns true if the option equals `none`
match *opt { None => true, Some(_) => false } match *opt { None => true, Some(_) => false }
} }
#[inline(always)] #[inline(always)]
pub pure fn is_some<T>(opt: &Option<T>) -> bool { pub pure fn is_some<T>(opt: &const Option<T>) -> bool {
//! Returns true if the option contains some value //! Returns true if the option contains some value
!is_none(opt) !is_none(opt)
@ -333,11 +333,11 @@ impl<T> MutableIter<T> for Option<T> {
pub impl<T> Option<T> { pub impl<T> Option<T> {
/// Returns true if the option equals `none` /// Returns true if the option equals `none`
#[inline(always)] #[inline(always)]
pure fn is_none(&self) -> bool { is_none(self) } pure fn is_none(&const self) -> bool { is_none(self) }
/// Returns true if the option contains some value /// Returns true if the option contains some value
#[inline(always)] #[inline(always)]
pure fn is_some(&self) -> bool { is_some(self) } pure fn is_some(&const self) -> bool { is_some(self) }
/** /**
* Update an optional value by optionally running its content by reference * Update an optional value by optionally running its content by reference

View file

@ -223,8 +223,8 @@ pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
} }
pub trait Ptr<T> { pub trait Ptr<T> {
pure fn is_null(&self) -> bool; pure fn is_null(&const self) -> bool;
pure fn is_not_null(&self) -> bool; pure fn is_not_null(&const self) -> bool;
pure fn offset(&self, count: uint) -> Self; pure fn offset(&self, count: uint) -> Self;
} }
@ -232,11 +232,11 @@ pub trait Ptr<T> {
impl<T> Ptr<T> for *T { impl<T> Ptr<T> for *T {
/// Returns true if the pointer is equal to the null pointer. /// Returns true if the pointer is equal to the null pointer.
#[inline(always)] #[inline(always)]
pure fn is_null(&self) -> bool { is_null(*self) } pure fn is_null(&const self) -> bool { is_null(*self) }
/// Returns true if the pointer is not equal to the null pointer. /// Returns true if the pointer is not equal to the null pointer.
#[inline(always)] #[inline(always)]
pure fn is_not_null(&self) -> bool { is_not_null(*self) } pure fn is_not_null(&const self) -> bool { is_not_null(*self) }
/// Calculates the offset from a pointer. /// Calculates the offset from a pointer.
#[inline(always)] #[inline(always)]
@ -247,11 +247,11 @@ impl<T> Ptr<T> for *T {
impl<T> Ptr<T> for *mut T { impl<T> Ptr<T> for *mut T {
/// Returns true if the pointer is equal to the null pointer. /// Returns true if the pointer is equal to the null pointer.
#[inline(always)] #[inline(always)]
pure fn is_null(&self) -> bool { is_null(*self) } pure fn is_null(&const self) -> bool { is_null(*self) }
/// Returns true if the pointer is not equal to the null pointer. /// Returns true if the pointer is not equal to the null pointer.
#[inline(always)] #[inline(always)]
pure fn is_not_null(&self) -> bool { is_not_null(*self) } pure fn is_not_null(&const self) -> bool { is_not_null(*self) }
/// Calculates the offset from a mutable pointer. /// Calculates the offset from a mutable pointer.
#[inline(always)] #[inline(always)]

View file

@ -499,7 +499,7 @@ impl TyVisitor for ReprVisitor {
} }
fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
match self.var_stk[self.var_stk.len() - 1] { match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
Degenerate | TagMatch => { Degenerate | TagMatch => {
if i != 0 { if i != 0 {
self.writer.write_str(", "); self.writer.write_str(", ");
@ -517,7 +517,7 @@ impl TyVisitor for ReprVisitor {
_disr_val: int, _disr_val: int,
n_fields: uint, n_fields: uint,
_name: &str) -> bool { _name: &str) -> bool {
match self.var_stk[self.var_stk.len() - 1] { match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
Degenerate | TagMatch => { Degenerate | TagMatch => {
if n_fields > 0 { if n_fields > 0 {
self.writer.write_char(')'); self.writer.write_char(')');

View file

@ -127,7 +127,7 @@ type TaskGroupInner = &'self mut Option<TaskGroupData>;
// A taskgroup is 'dead' when nothing can cause it to fail; only members can. // A taskgroup is 'dead' when nothing can cause it to fail; only members can.
pure fn taskgroup_is_dead(tg: &TaskGroupData) -> bool { pure fn taskgroup_is_dead(tg: &TaskGroupData) -> bool {
(&tg.members).is_empty() (&const tg.members).is_empty()
} }
// A list-like structure by which taskgroups keep track of all ancestor groups // A list-like structure by which taskgroups keep track of all ancestor groups

View file

@ -50,11 +50,11 @@ impl<T> ReverseIter<(uint, &'self T)> for TrieMap<T> {
impl<T> Container for TrieMap<T> { impl<T> Container for TrieMap<T> {
/// Return the number of elements in the map /// Return the number of elements in the map
#[inline(always)] #[inline(always)]
pure fn len(&self) -> uint { self.length } pure fn len(&const self) -> uint { self.length }
/// Return true if the map contains no elements /// Return true if the map contains no elements
#[inline(always)] #[inline(always)]
pure fn is_empty(&self) -> bool { self.len() == 0 } pure fn is_empty(&const self) -> bool { self.len() == 0 }
} }
impl<T> Mutable for TrieMap<T> { impl<T> Mutable for TrieMap<T> {
@ -178,11 +178,11 @@ impl ReverseIter<uint> for TrieSet {
impl Container for TrieSet { impl Container for TrieSet {
/// Return the number of elements in the set /// Return the number of elements in the set
#[inline(always)] #[inline(always)]
pure fn len(&self) -> uint { self.map.len() } pure fn len(&const self) -> uint { self.map.len() }
/// Return true if the set contains no elements /// Return true if the set contains no elements
#[inline(always)] #[inline(always)]
pure fn is_empty(&self) -> bool { self.map.is_empty() } pure fn is_empty(&const self) -> bool { self.map.is_empty() }
} }
impl Mutable for TrieSet { impl Mutable for TrieSet {

View file

@ -118,6 +118,14 @@ pub pure fn len<T>(v: &[const T]) -> uint {
as_const_buf(v, |_p, len| len) as_const_buf(v, |_p, len| len)
} }
// A botch to tide us over until core and std are fully demuted.
pub pure fn uniq_len<T>(v: &const ~[T]) -> uint {
unsafe {
let v: &~[T] = ::cast::transmute(v);
as_const_buf(*v, |_p, len| len)
}
}
/** /**
* Creates and initializes an immutable vector. * Creates and initializes an immutable vector.
* *
@ -1691,11 +1699,11 @@ pub mod traits {
impl<T> Container for &'self [const T] { impl<T> Container for &'self [const T] {
/// Returns true if a vector contains no elements /// Returns true if a vector contains no elements
#[inline] #[inline]
pure fn is_empty(&self) -> bool { is_empty(*self) } pure fn is_empty(&const self) -> bool { is_empty(*self) }
/// Returns the length of a vector /// Returns the length of a vector
#[inline] #[inline]
pure fn len(&self) -> uint { len(*self) } pure fn len(&const self) -> uint { len(*self) }
} }
pub trait CopyableVector<T> { pub trait CopyableVector<T> {
@ -1707,7 +1715,14 @@ impl<T: Copy> CopyableVector<T> for &'self [const T] {
/// Returns a copy of the elements from [`start`..`end`) from `v`. /// Returns a copy of the elements from [`start`..`end`) from `v`.
#[inline] #[inline]
pure fn slice(&self, start: uint, end: uint) -> ~[T] { pure fn slice(&self, start: uint, end: uint) -> ~[T] {
slice(*self, start, end).to_vec() // XXX: Purity workaround for stage0.
unsafe {
let mut result = ~[];
for uint::range(start, end) |i| {
result.push(copy self[i]);
}
result
}
} }
} }
@ -2484,7 +2499,7 @@ impl<A:Copy> iter::CopyableNonstrictIter<A> for &'self [A] {
impl<A:Copy> iter::CopyableNonstrictIter<A> for ~[A] { impl<A:Copy> iter::CopyableNonstrictIter<A> for ~[A] {
pure fn each_val(&const self, f: &fn(A) -> bool) { pure fn each_val(&const self, f: &fn(A) -> bool) {
let mut i = 0; let mut i = 0;
while i < self.len() { while i < uniq_len(self) {
if !f(copy self[i]) { break; } if !f(copy self[i]) { break; }
i += 1; i += 1;
} }

View file

@ -142,7 +142,7 @@ fn fold_item(cx: @mut TestCtxt, &&i: @ast::item, fld: @fold::ast_fold)
-> Option<@ast::item> { -> Option<@ast::item> {
cx.path.push(i.ident); cx.path.push(i.ident);
debug!("current path: %s", debug!("current path: %s",
ast_util::path_name_i(cx.path, cx.sess.parse_sess.interner)); ast_util::path_name_i(copy cx.path, cx.sess.parse_sess.interner));
if is_test_fn(i) || is_bench_fn(i) { if is_test_fn(i) || is_bench_fn(i) {
match i.node { match i.node {
@ -162,7 +162,7 @@ fn fold_item(cx: @mut TestCtxt, &&i: @ast::item, fld: @fold::ast_fold)
should_fail: should_fail(i) should_fail: should_fail(i)
}; };
cx.testfns.push(test); cx.testfns.push(test);
debug!("have %u test/bench functions", cx.testfns.len()); // debug!("have %u test/bench functions", cx.testfns.len());
} }
} }
} }

View file

@ -79,6 +79,8 @@ fn warn_if_multiple_versions(e: @mut Env,
crate_cache: @mut ~[cache_entry]) { crate_cache: @mut ~[cache_entry]) {
use core::either::*; use core::either::*;
let crate_cache = &mut *crate_cache;
if crate_cache.len() != 0u { if crate_cache.len() != 0u {
let name = loader::crate_name_from_metas( let name = loader::crate_name_from_metas(
*crate_cache[crate_cache.len() - 1].metas *crate_cache[crate_cache.len() - 1].metas

View file

@ -96,6 +96,7 @@ pub fn iter_crate_data(cstore: @mut CStore,
} }
pub fn add_used_crate_file(cstore: @mut CStore, lib: &Path) { pub fn add_used_crate_file(cstore: @mut CStore, lib: &Path) {
let cstore = &mut *cstore;
if !vec::contains(cstore.used_crate_files, lib) { if !vec::contains(cstore.used_crate_files, lib) {
cstore.used_crate_files.push(copy *lib); cstore.used_crate_files.push(copy *lib);
} }
@ -108,6 +109,7 @@ pub fn get_used_crate_files(cstore: @mut CStore) -> ~[Path] {
pub fn add_used_library(cstore: @mut CStore, lib: @~str) -> bool { pub fn add_used_library(cstore: @mut CStore, lib: @~str) -> bool {
fail_unless!(*lib != ~""); fail_unless!(*lib != ~"");
let cstore = &mut *cstore;
if cstore.used_libraries.contains(&*lib) { return false; } if cstore.used_libraries.contains(&*lib) { return false; }
cstore.used_libraries.push(/*bad*/ copy *lib); cstore.used_libraries.push(/*bad*/ copy *lib);
true true

View file

@ -271,6 +271,7 @@ pub impl CheckLoanCtxt {
None => return, None => return,
Some(loans) => loans Some(loans) => loans
}; };
let new_loans: &mut ~[Loan] = new_loans;
debug!("new_loans has length %?", new_loans.len()); debug!("new_loans has length %?", new_loans.len());

View file

@ -129,9 +129,12 @@ fn req_loans_in_expr(ex: @ast::expr,
ex.id, pprust::expr_to_str(ex, tcx.sess.intr())); ex.id, pprust::expr_to_str(ex, tcx.sess.intr()));
// If this expression is borrowed, have to ensure it remains valid: // If this expression is borrowed, have to ensure it remains valid:
if !self.ignore_adjustments.contains(&ex.id) { {
for tcx.adjustments.find(&ex.id).each |adjustments| { let mut this = &mut *self;
self.guarantee_adjustments(ex, *adjustments); if !this.ignore_adjustments.contains(&ex.id) {
for tcx.adjustments.find(&ex.id).each |adjustments| {
this.guarantee_adjustments(ex, *adjustments);
}
} }
} }
@ -288,9 +291,9 @@ fn req_loans_in_expr(ex: @ast::expr,
} }
pub impl GatherLoanCtxt { pub impl GatherLoanCtxt {
fn tcx(@mut self) -> ty::ctxt { self.bccx.tcx } fn tcx(&mut self) -> ty::ctxt { self.bccx.tcx }
fn guarantee_adjustments(@mut self, fn guarantee_adjustments(&mut self,
expr: @ast::expr, expr: @ast::expr,
adjustment: &ty::AutoAdjustment) { adjustment: &ty::AutoAdjustment) {
debug!("guarantee_adjustments(expr=%s, adjustment=%?)", debug!("guarantee_adjustments(expr=%s, adjustment=%?)",
@ -348,7 +351,7 @@ pub impl GatherLoanCtxt {
// out loans, which will be added to the `req_loan_map`. This can // out loans, which will be added to the `req_loan_map`. This can
// also entail "rooting" GC'd pointers, which means ensuring // also entail "rooting" GC'd pointers, which means ensuring
// dynamically that they are not freed. // dynamically that they are not freed.
fn guarantee_valid(@mut self, fn guarantee_valid(&mut self,
cmt: cmt, cmt: cmt,
req_mutbl: ast::mutability, req_mutbl: ast::mutability,
scope_r: ty::Region) scope_r: ty::Region)
@ -465,7 +468,7 @@ pub impl GatherLoanCtxt {
// has type `@mut{f:int}`, this check might fail because `&x.f` // has type `@mut{f:int}`, this check might fail because `&x.f`
// reqires an immutable pointer, but `f` lives in (aliased) // reqires an immutable pointer, but `f` lives in (aliased)
// mutable memory. // mutable memory.
fn check_mutbl(@mut self, fn check_mutbl(&mut self,
loan_kind: LoanKind, loan_kind: LoanKind,
cmt: cmt) cmt: cmt)
-> bckres<PreserveCondition> { -> bckres<PreserveCondition> {
@ -498,7 +501,7 @@ pub impl GatherLoanCtxt {
} }
} }
fn add_loans(@mut self, fn add_loans(&mut self,
cmt: cmt, cmt: cmt,
loan_kind: LoanKind, loan_kind: LoanKind,
scope_r: ty::Region, scope_r: ty::Region,
@ -563,7 +566,7 @@ pub impl GatherLoanCtxt {
} }
} }
fn add_loans_to_scope_id(@mut self, fn add_loans_to_scope_id(&mut self,
scope_id: ast::node_id, scope_id: ast::node_id,
+loans: ~[Loan]) { +loans: ~[Loan]) {
debug!("adding %u loans to scope_id %?: %s", debug!("adding %u loans to scope_id %?: %s",

View file

@ -849,21 +849,24 @@ pub impl Liveness {
_ => self.tcx.sess.span_bug(sp, ~"Label on break/loop \ _ => self.tcx.sess.span_bug(sp, ~"Label on break/loop \
doesn't refer to a loop") doesn't refer to a loop")
}, },
None => None => {
// Vanilla 'break' or 'loop', so use the enclosing // Vanilla 'break' or 'loop', so use the enclosing
// loop scope // loop scope
if self.loop_scope.len() == 0 { let loop_scope = &mut *self.loop_scope;
if loop_scope.len() == 0 {
self.tcx.sess.span_bug(sp, ~"break outside loop"); self.tcx.sess.span_bug(sp, ~"break outside loop");
} }
else { else {
// FIXME(#5275): this shouldn't have to be a method... // FIXME(#5275): this shouldn't have to be a method...
self.last_loop_scope() self.last_loop_scope()
} }
}
} }
} }
fn last_loop_scope(&self) -> node_id { fn last_loop_scope(&self) -> node_id {
*self.loop_scope.last() let loop_scope = &mut *self.loop_scope;
*loop_scope.last()
} }
fn ln_str(&self, ln: LiveNode) -> ~str { fn ln_str(&self, ln: LiveNode) -> ~str {

View file

@ -818,18 +818,21 @@ pub fn determine_rp_in_crate(sess: Session,
// C). For each dependent item D, we combine the variance of C // C). For each dependent item D, we combine the variance of C
// with the ambient variance where the reference occurred and then // with the ambient variance where the reference occurred and then
// update the region-parameterization of D to reflect the result. // update the region-parameterization of D to reflect the result.
while cx.worklist.len() != 0 { {
let c_id = cx.worklist.pop(); let cx = &mut *cx;
let c_variance = cx.region_paramd_items.get(&c_id); while cx.worklist.len() != 0 {
debug!("popped %d from worklist", c_id); let c_id = cx.worklist.pop();
match cx.dep_map.find(&c_id) { let c_variance = cx.region_paramd_items.get(&c_id);
None => {} debug!("popped %d from worklist", c_id);
Some(deps) => { match cx.dep_map.find(&c_id) {
for deps.each |dep| { None => {}
let v = add_variance(dep.ambient_variance, c_variance); Some(deps) => {
cx.add_rp(dep.id, v); for deps.each |dep| {
let v = add_variance(dep.ambient_variance, c_variance);
cx.add_rp(dep.id, v);
}
}
} }
}
} }
} }

View file

@ -457,7 +457,7 @@ pub struct Module {
kind: ModuleKind, kind: ModuleKind,
children: @HashMap<ident,@mut NameBindings>, children: @HashMap<ident,@mut NameBindings>,
imports: ~[@ImportDirective], imports: @mut ~[@ImportDirective],
// The anonymous children of this node. Anonymous children are pseudo- // The anonymous children of this node. Anonymous children are pseudo-
// modules that are implicitly created around items contained within // modules that are implicitly created around items contained within
@ -495,7 +495,7 @@ pub fn Module(parent_link: ParentLink,
def_id: def_id, def_id: def_id,
kind: kind, kind: kind,
children: @HashMap(), children: @HashMap(),
imports: ~[], imports: @mut ~[],
anonymous_children: @HashMap(), anonymous_children: @HashMap(),
import_resolutions: @HashMap(), import_resolutions: @HashMap(),
glob_count: 0, glob_count: 0,
@ -505,7 +505,8 @@ pub fn Module(parent_link: ParentLink,
pub impl Module { pub impl Module {
fn all_imports_resolved(&self) -> bool { fn all_imports_resolved(&self) -> bool {
return self.imports.len() == self.resolved_import_count; let imports = &mut *self.imports;
return imports.len() == self.resolved_import_count;
} }
} }
@ -647,6 +648,7 @@ pub impl NameBindings {
None => { None => {
match (*type_def).module_def { match (*type_def).module_def {
Some(module_def) => { Some(module_def) => {
let module_def = &mut *module_def;
module_def.def_id.map(|def_id| module_def.def_id.map(|def_id|
def_mod(*def_id)) def_mod(*def_id))
} }
@ -1978,10 +1980,11 @@ pub impl Resolver {
return; return;
} }
let import_count = module.imports.len(); let imports = &mut *module.imports;
let import_count = imports.len();
while module.resolved_import_count < import_count { while module.resolved_import_count < import_count {
let import_index = module.resolved_import_count; let import_index = module.resolved_import_count;
let import_directive = module.imports[import_index]; let import_directive = imports[import_index];
match self.resolve_import_for_module(module, import_directive) { match self.resolve_import_for_module(module, import_directive) {
Failed => { Failed => {
// We presumably emitted an error. Continue. // We presumably emitted an error. Continue.
@ -2288,7 +2291,8 @@ pub impl Resolver {
(None, None) => { return Failed; } (None, None) => { return Failed; }
// If it's private, it's also unresolved. // If it's private, it's also unresolved.
(Some(t), None) | (None, Some(t)) => { (Some(t), None) | (None, Some(t)) => {
match t.bindings.type_def { let bindings = &mut *t.bindings;
match bindings.type_def {
Some(ref type_def) => { Some(ref type_def) => {
if type_def.privacy == Private { if type_def.privacy == Private {
return Failed; return Failed;
@ -2296,7 +2300,7 @@ pub impl Resolver {
} }
_ => () _ => ()
} }
match t.bindings.value_def { match bindings.value_def {
Some(ref value_def) => { Some(ref value_def) => {
if value_def.privacy == Private { if value_def.privacy == Private {
return Failed; return Failed;
@ -2483,7 +2487,7 @@ pub impl Resolver {
debug!("(resolving glob import) writing module resolution \ debug!("(resolving glob import) writing module resolution \
%? into `%s`", %? into `%s`",
is_none(&target_import_resolution.type_target), is_none(&mut target_import_resolution.type_target),
self.module_to_str(module_)); self.module_to_str(module_));
// Here we merge two import resolutions. // Here we merge two import resolutions.
@ -2551,7 +2555,7 @@ pub impl Resolver {
*self.session.str_of(ident), *self.session.str_of(ident),
self.module_to_str(containing_module), self.module_to_str(containing_module),
self.module_to_str(module_), self.module_to_str(module_),
dest_import_resolution.privacy); copy dest_import_resolution.privacy);
// Merge the child item into the import resolution. // Merge the child item into the import resolution.
if (*name_bindings).defined_in_public_namespace(ValueNS) { if (*name_bindings).defined_in_public_namespace(ValueNS) {
@ -2864,7 +2868,8 @@ pub impl Resolver {
module_, name, TypeNS, DontSearchThroughModules); module_, name, TypeNS, DontSearchThroughModules);
match resolve_result { match resolve_result {
Success(target) => { Success(target) => {
match target.bindings.type_def { let bindings = &mut *target.bindings;
match bindings.type_def {
Some(ref type_def) => { Some(ref type_def) => {
match (*type_def).module_def { match (*type_def).module_def {
None => { None => {
@ -3061,10 +3066,10 @@ pub impl Resolver {
fn report_unresolved_imports(@mut self, module_: @mut Module) { fn report_unresolved_imports(@mut self, module_: @mut Module) {
let index = module_.resolved_import_count; let index = module_.resolved_import_count;
let import_count = module_.imports.len(); let imports: &mut ~[@ImportDirective] = &mut *module_.imports;
let import_count = imports.len();
if index != import_count { if index != import_count {
self.session.span_err(module_.imports[index].span, self.session.span_err(imports[index].span, ~"unresolved import");
~"unresolved import");
} }
// Descend into children and anonymous children. // Descend into children and anonymous children.
@ -4253,10 +4258,10 @@ pub impl Resolver {
match bindings_list { match bindings_list {
Some(bindings_list) Some(bindings_list)
if !bindings_list.contains_key(&ident) if !bindings_list.contains_key(&ident) => {
=> { let this = &mut *self;
let last_rib = self.value_ribs[ let last_rib = this.value_ribs[
self.value_ribs.len() - 1]; this.value_ribs.len() - 1];
last_rib.bindings.insert(ident, last_rib.bindings.insert(ident,
dl_def(def)); dl_def(def));
bindings_list.insert(ident, pat_id); bindings_list.insert(ident, pat_id);
@ -4275,8 +4280,9 @@ pub impl Resolver {
// Not bound in the same pattern: do nothing // Not bound in the same pattern: do nothing
} }
None => { None => {
let last_rib = self.value_ribs[ let this = &mut *self;
self.value_ribs.len() - 1]; let last_rib = this.value_ribs[
this.value_ribs.len() - 1];
last_rib.bindings.insert(ident, last_rib.bindings.insert(ident,
dl_def(def)); dl_def(def));
} }
@ -4723,14 +4729,16 @@ pub impl Resolver {
} }
fn find_best_match_for_name(@mut self, name: &str) -> Option<~str> { fn find_best_match_for_name(@mut self, name: &str) -> Option<~str> {
let this = &mut *self;
let mut maybes: ~[~str] = ~[]; let mut maybes: ~[~str] = ~[];
let mut values: ~[uint] = ~[]; let mut values: ~[uint] = ~[];
let mut j = self.value_ribs.len(); let mut j = this.value_ribs.len();
while j != 0 { while j != 0 {
j -= 1; j -= 1;
for self.value_ribs[j].bindings.each_entry |e| { for this.value_ribs[j].bindings.each_entry |e| {
vec::push(&mut maybes, copy *self.session.str_of(e.key)); vec::push(&mut maybes, copy *this.session.str_of(e.key));
vec::push(&mut values, uint::max_value); vec::push(&mut values, uint::max_value);
} }
} }
@ -4758,12 +4766,14 @@ pub impl Resolver {
} }
fn name_exists_in_scope_struct(@mut self, name: &str) -> bool { fn name_exists_in_scope_struct(@mut self, name: &str) -> bool {
let mut i = self.type_ribs.len(); let this = &mut *self;
let mut i = this.type_ribs.len();
while i != 0 { while i != 0 {
i -= 1; i -= 1;
match self.type_ribs[i].kind { match this.type_ribs[i].kind {
MethodRibKind(node_id, _) => MethodRibKind(node_id, _) =>
for self.crate.node.module.items.each |item| { for this.crate.node.module.items.each |item| {
if item.id == node_id { if item.id == node_id {
match item.node { match item.node {
item_struct(class_def, _) => { item_struct(class_def, _) => {
@ -4771,7 +4781,7 @@ pub impl Resolver {
match field.node.kind { match field.node.kind {
unnamed_field => {}, unnamed_field => {},
named_field(ident, _, _) => { named_field(ident, _, _) => {
if str::eq_slice(*self.session.str_of(ident), if str::eq_slice(*this.session.str_of(ident),
name) { name) {
return true return true
} }
@ -4877,8 +4887,9 @@ pub impl Resolver {
expr_loop(_, Some(label)) => { expr_loop(_, Some(label)) => {
do self.with_label_rib { do self.with_label_rib {
let this = &mut *self;
let def_like = dl_def(def_label(expr.id)); let def_like = dl_def(def_label(expr.id));
let rib = self.label_ribs[self.label_ribs.len() - 1]; let rib = this.label_ribs[this.label_ribs.len() - 1];
rib.bindings.insert(label, def_like); rib.bindings.insert(label, def_like);
visit_expr(expr, (), visitor); visit_expr(expr, (), visitor);
@ -5144,21 +5155,21 @@ pub impl Resolver {
// be sure that there is only one main function // be sure that there is only one main function
// //
fn check_duplicate_main(@mut self) { fn check_duplicate_main(@mut self) {
if self.attr_main_fn.is_none() { let this = &mut *self;
if self.main_fns.len() >= 1u { if this.attr_main_fn.is_none() {
if this.main_fns.len() >= 1u {
let mut i = 1u; let mut i = 1u;
while i < self.main_fns.len() { while i < this.main_fns.len() {
let (_, dup_main_span) = let (_, dup_main_span) = option::unwrap(this.main_fns[i]);
option::unwrap(self.main_fns[i]); this.session.span_err(
self.session.span_err(
dup_main_span, dup_main_span,
~"multiple 'main' functions"); ~"multiple 'main' functions");
i += 1; i += 1;
} }
*self.session.main_fn = self.main_fns[0]; *this.session.main_fn = this.main_fns[0];
} }
} else { } else {
*self.session.main_fn = self.attr_main_fn; *this.session.main_fn = this.attr_main_fn;
} }
} }

View file

@ -854,7 +854,9 @@ pub fn need_invoke(bcx: block) -> bool {
// Walk the scopes to look for cleanups // Walk the scopes to look for cleanups
let mut cur = bcx; let mut cur = bcx;
loop { loop {
match *cur.kind { let current = &mut *cur;
let kind = &mut *current.kind;
match *kind {
block_scope(ref mut inf) => { block_scope(ref mut inf) => {
for vec::each((*inf).cleanups) |cleanup| { for vec::each((*inf).cleanups) |cleanup| {
match *cleanup { match *cleanup {
@ -868,7 +870,7 @@ pub fn need_invoke(bcx: block) -> bool {
} }
_ => () _ => ()
} }
cur = match cur.parent { cur = match current.parent {
Some(next) => next, Some(next) => next,
None => return false None => return false
} }

View file

@ -50,7 +50,7 @@ pub fn count_insn(cx: block, category: &str) {
if cx.ccx().sess.count_llvm_insns() { if cx.ccx().sess.count_llvm_insns() {
let h = cx.ccx().stats.llvm_insns; let h = cx.ccx().stats.llvm_insns;
let v = cx.ccx().stats.llvm_insn_ctxt; let v = &*cx.ccx().stats.llvm_insn_ctxt;
// Build version of path with cycles removed. // Build version of path with cycles removed.

View file

@ -186,12 +186,14 @@ pub fn trans_log(log_ex: @ast::expr,
return expr::trans_into(bcx, lvl, expr::Ignore); return expr::trans_into(bcx, lvl, expr::Ignore);
} }
let modpath = vec::append( let (modpath, modname) = {
~[path_mod(ccx.sess.ident_of(ccx.link_meta.name.to_owned()))], let path = &mut bcx.fcx.path;
bcx.fcx.path.filtered(|e| let modpath = vec::append(
match *e { path_mod(_) => true, _ => false } ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name.to_owned()))],
)); path.filtered(|e| match *e { path_mod(_) => true, _ => false }));
let modname = path_str(ccx.sess, modpath); let modname = path_str(ccx.sess, modpath);
(modpath, modname)
};
let global = if ccx.module_data.contains_key(&modname) { let global = if ccx.module_data.contains_key(&modname) {
ccx.module_data.get(&modname) ccx.module_data.get(&modname)

View file

@ -845,7 +845,8 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata<SubProgramMetadata> {
let dbg_cx = (/*bad*/copy cx.dbg_cx).get(); let dbg_cx = (/*bad*/copy cx.dbg_cx).get();
debug!("~~"); debug!("~~");
debug!("%?", fcx.id);
let fcx = &mut *fcx;
let sp = fcx.span.get(); let sp = fcx.span.get();
debug!("%s", cx.sess.codemap.span_to_str(sp)); debug!("%s", cx.sess.codemap.span_to_str(sp));

View file

@ -234,18 +234,21 @@ pub fn lazily_emit_simplified_tydesc_glue(ccx: @CrateContext,
if simpl != ti.ty { if simpl != ti.ty {
let simpl_ti = get_tydesc(ccx, simpl); let simpl_ti = get_tydesc(ccx, simpl);
lazily_emit_tydesc_glue(ccx, field, simpl_ti); lazily_emit_tydesc_glue(ccx, field, simpl_ti);
if field == abi::tydesc_field_take_glue { {
ti.take_glue = let simpl_ti = &mut *simpl_ti;
simpl_ti.take_glue.map(|v| cast_glue(ccx, ti, *v)); if field == abi::tydesc_field_take_glue {
} else if field == abi::tydesc_field_drop_glue { ti.take_glue =
ti.drop_glue = simpl_ti.take_glue.map(|v| cast_glue(ccx, ti, *v));
simpl_ti.drop_glue.map(|v| cast_glue(ccx, ti, *v)); } else if field == abi::tydesc_field_drop_glue {
} else if field == abi::tydesc_field_free_glue { ti.drop_glue =
ti.free_glue = simpl_ti.drop_glue.map(|v| cast_glue(ccx, ti, *v));
simpl_ti.free_glue.map(|v| cast_glue(ccx, ti, *v)); } else if field == abi::tydesc_field_free_glue {
} else if field == abi::tydesc_field_visit_glue { ti.free_glue =
ti.visit_glue = simpl_ti.free_glue.map(|v| cast_glue(ccx, ti, *v));
simpl_ti.visit_glue.map(|v| cast_glue(ccx, ti, *v)); } else if field == abi::tydesc_field_visit_glue {
ti.visit_glue =
simpl_ti.visit_glue.map(|v| cast_glue(ccx, ti, *v));
}
} }
return true; return true;
} }

View file

@ -185,7 +185,11 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
pub fn type_needs(cx: Context, use_: uint, ty: ty::t) { pub fn type_needs(cx: Context, use_: uint, ty: ty::t) {
// Optimization -- don't descend type if all params already have this use // Optimization -- don't descend type if all params already have this use
for uint::range(0, cx.uses.len()) |i| { let len = {
let uses = &*cx.uses;
uses.len()
};
for uint::range(0, len) |i| {
if cx.uses[i] & use_ != use_ { if cx.uses[i] & use_ != use_ {
type_needs_inner(cx, use_, ty, @Nil); type_needs_inner(cx, use_, ty, @Nil);
return; return;

View file

@ -2184,7 +2184,7 @@ pub fn type_moves_by_default(cx: ctxt, ty: t) -> bool {
// True if instantiating an instance of `r_ty` requires an instance of `r_ty`. // True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool { pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
fn type_requires(cx: ctxt, seen: @mut ~[def_id], fn type_requires(cx: ctxt, seen: &mut ~[def_id],
r_ty: t, ty: t) -> bool { r_ty: t, ty: t) -> bool {
debug!("type_requires(%s, %s)?", debug!("type_requires(%s, %s)?",
::util::ppaux::ty_to_str(cx, r_ty), ::util::ppaux::ty_to_str(cx, r_ty),
@ -2202,7 +2202,7 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
return r; return r;
} }
fn subtypes_require(cx: ctxt, seen: @mut ~[def_id], fn subtypes_require(cx: ctxt, seen: &mut ~[def_id],
r_ty: t, ty: t) -> bool { r_ty: t, ty: t) -> bool {
debug!("subtypes_require(%s, %s)?", debug!("subtypes_require(%s, %s)?",
::util::ppaux::ty_to_str(cx, r_ty), ::util::ppaux::ty_to_str(cx, r_ty),

View file

@ -1696,7 +1696,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
fcx.write_ty(expr.id, fty); fcx.write_ty(expr.id, fty);
let inherited_purity = let inherited_purity =
ty::determine_inherited_purity(fcx.purity, purity, ty::determine_inherited_purity(copy fcx.purity, purity,
fn_ty.sigil); fn_ty.sigil);
// We inherit the same self info as the enclosing scope, // We inherit the same self info as the enclosing scope,

View file

@ -10,6 +10,7 @@
use core::prelude::*; use core::prelude::*;
use middle::resolve::Impl;
use middle::ty::{param_ty, substs}; use middle::ty::{param_ty, substs};
use middle::ty; use middle::ty;
use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{FnCtxt, impl_self_ty};
@ -240,6 +241,7 @@ pub fn lookup_vtable(vcx: &VtableContext,
// Nothing found. Continue. // Nothing found. Continue.
} }
Some(implementations) => { Some(implementations) => {
let implementations: &mut ~[@Impl] = implementations;
// implementations is the list of all impls in scope for // implementations is the list of all impls in scope for
// trait_ty. (Usually, there's just one.) // trait_ty. (Usually, there's just one.)
for uint::range(0, implementations.len()) |i| { for uint::range(0, implementations.len()) |i| {

View file

@ -466,14 +466,13 @@ pub impl CoherenceChecker {
} }
} }
fn iter_impls_of_trait(&self, trait_def_id: def_id, fn iter_impls_of_trait(&self, trait_def_id: def_id, f: &fn(@Impl)) {
f: &fn(@Impl)) {
let coherence_info = &mut self.crate_context.coherence_info; let coherence_info = &mut self.crate_context.coherence_info;
let extension_methods = &coherence_info.extension_methods; let extension_methods = &coherence_info.extension_methods;
match extension_methods.find(&trait_def_id) { match extension_methods.find(&trait_def_id) {
Some(impls) => { Some(impls) => {
let impls: &mut ~[@Impl] = impls;
for uint::range(0, impls.len()) |i| { for uint::range(0, impls.len()) |i| {
f(impls[i]); f(impls[i]);
} }

View file

@ -559,15 +559,16 @@ pub impl InferCtxt {
} }
fn start_snapshot(@mut self) -> Snapshot { fn start_snapshot(@mut self) -> Snapshot {
let this = &mut *self;
Snapshot { Snapshot {
ty_var_bindings_len: ty_var_bindings_len:
self.ty_var_bindings.bindings.len(), this.ty_var_bindings.bindings.len(),
int_var_bindings_len: int_var_bindings_len:
self.int_var_bindings.bindings.len(), this.int_var_bindings.bindings.len(),
float_var_bindings_len: float_var_bindings_len:
self.float_var_bindings.bindings.len(), this.float_var_bindings.bindings.len(),
region_vars_snapshot: region_vars_snapshot:
self.region_vars.start_snapshot(), this.region_vars.start_snapshot(),
} }
} }

View file

@ -700,8 +700,8 @@ impl cmp::Eq for BitvSet {
} }
impl Container for BitvSet { impl Container for BitvSet {
pure fn len(&self) -> uint { self.size } pure fn len(&const self) -> uint { self.size }
pure fn is_empty(&self) -> bool { self.size == 0 } pure fn is_empty(&const self) -> bool { self.size == 0 }
} }
impl Mutable for BitvSet { impl Mutable for BitvSet {

View file

@ -23,10 +23,10 @@ pub struct Deque<T> {
impl<T> Container for Deque<T> { impl<T> Container for Deque<T> {
/// Return the number of elements in the deque /// Return the number of elements in the deque
pure fn len(&self) -> uint { self.nelts } pure fn len(&const self) -> uint { self.nelts }
/// Return true if the deque contains no elements /// Return true if the deque contains no elements
pure fn is_empty(&self) -> bool { self.len() == 0 } pure fn is_empty(&const self) -> bool { self.len() == 0 }
} }
impl<T> Mutable for Deque<T> { impl<T> Mutable for Deque<T> {

View file

@ -569,12 +569,12 @@ pub mod bytepipes {
impl BytePort for PipeBytePort { impl BytePort for PipeBytePort {
fn try_recv(&self, count: uint) -> Option<~[u8]> { fn try_recv(&self, count: uint) -> Option<~[u8]> {
if self.buf.len() >= count { if vec::uniq_len(&const self.buf) >= count {
let mut bytes = ::core::util::replace(&mut self.buf, ~[]); let mut bytes = ::core::util::replace(&mut self.buf, ~[]);
self.buf = bytes.slice(count, bytes.len()); self.buf = bytes.slice(count, bytes.len());
bytes.truncate(count); bytes.truncate(count);
return Some(bytes); return Some(bytes);
} else if self.buf.len() > 0 { } else if vec::uniq_len(&const self.buf) > 0 {
let mut bytes = ::core::util::replace(&mut self.buf, ~[]); let mut bytes = ::core::util::replace(&mut self.buf, ~[]);
fail_unless!(count > bytes.len()); fail_unless!(count > bytes.len());
match self.try_recv(count - bytes.len()) { match self.try_recv(count - bytes.len()) {
@ -584,7 +584,7 @@ pub mod bytepipes {
} }
None => return None None => return None
} }
} else if self.buf.is_empty() { } else if vec::uniq_len(&const self.buf) == 0 {
match self.port.try_recv() { match self.port.try_recv() {
Some(buf) => { Some(buf) => {
fail_unless!(!buf.is_empty()); fail_unless!(!buf.is_empty());

View file

@ -757,12 +757,16 @@ pub fn Decoder(json: Json) -> Decoder {
priv impl Decoder/&self { priv impl Decoder/&self {
fn peek(&self) -> &'self Json { fn peek(&self) -> &'self Json {
if self.stack.len() == 0 { self.stack.push(&self.json); } if vec::uniq_len(&const self.stack) == 0 {
self.stack[self.stack.len() - 1] self.stack.push(&self.json);
}
self.stack[vec::uniq_len(&const self.stack) - 1]
} }
fn pop(&self) -> &'self Json { fn pop(&self) -> &'self Json {
if self.stack.len() == 0 { self.stack.push(&self.json); } if vec::uniq_len(&const self.stack) == 0 {
self.stack.push(&self.json);
}
self.stack.pop() self.stack.pop()
} }
} }

View file

@ -879,7 +879,8 @@ impl io::Reader for TcpSocketBuf {
// If possible, copy up to `len` bytes from the internal // If possible, copy up to `len` bytes from the internal
// `data.buf` into `buf` // `data.buf` into `buf`
let nbuffered = self.data.buf.len() - self.data.buf_off; let nbuffered = vec::uniq_len(&const self.data.buf) -
self.data.buf_off;
let needed = len - count; let needed = len - count;
if nbuffered > 0 { if nbuffered > 0 {
unsafe { unsafe {
@ -931,7 +932,7 @@ impl io::Reader for TcpSocketBuf {
} }
fn read_byte(&self) -> int { fn read_byte(&self) -> int {
loop { loop {
if self.data.buf.len() > self.data.buf_off { if vec::uniq_len(&const self.data.buf) > self.data.buf_off {
let c = self.data.buf[self.data.buf_off]; let c = self.data.buf[self.data.buf_off];
self.data.buf_off += 1; self.data.buf_off += 1;
return c as int return c as int

View file

@ -101,7 +101,7 @@ pub mod chained {
} }
pure fn search_tbl(&self, k: &K, h: uint) -> SearchResult<K,V> { pure fn search_tbl(&self, k: &K, h: uint) -> SearchResult<K,V> {
let idx = h % vec::len(self.chains); let idx = h % vec::uniq_len(&const self.chains);
match copy self.chains[idx] { match copy self.chains[idx] {
None => { None => {
debug!("search_tbl: none, comp %u, hash %u, idx %u", debug!("search_tbl: none, comp %u, hash %u, idx %u",
@ -121,7 +121,7 @@ pub mod chained {
} }
fn rehash(@self) { fn rehash(@self) {
let n_old_chains = self.chains.len(); let n_old_chains = vec::uniq_len(&const self.chains);
let n_new_chains: uint = uint::next_power_of_two(n_old_chains+1u); let n_new_chains: uint = uint::next_power_of_two(n_old_chains+1u);
let mut new_chains = chains(n_new_chains); let mut new_chains = chains(n_new_chains);
for self.each_entry |entry| { for self.each_entry |entry| {
@ -137,7 +137,7 @@ pub mod chained {
pure fn each_entry(&self, blk: &fn(@Entry<K,V>) -> bool) { pure fn each_entry(&self, blk: &fn(@Entry<K,V>) -> bool) {
// n.b. we can't use vec::iter() here because self.chains // n.b. we can't use vec::iter() here because self.chains
// is stored in a mutable location. // is stored in a mutable location.
let mut i = 0u, n = self.chains.len(); let mut i = 0u, n = vec::uniq_len(&const self.chains);
while i < n { while i < n {
let mut chain = self.chains[i]; let mut chain = self.chains[i];
loop { loop {
@ -161,8 +161,8 @@ pub mod chained {
} }
impl<K:Eq + IterBytes + Hash,V> Container for HashMap_<K, V> { impl<K:Eq + IterBytes + Hash,V> Container for HashMap_<K, V> {
pure fn len(&self) -> uint { self.count } pure fn len(&const self) -> uint { self.count }
pure fn is_empty(&self) -> bool { self.count == 0 } pure fn is_empty(&const self) -> bool { self.count == 0 }
} }
pub impl<K:Eq + IterBytes + Hash,V> HashMap_<K, V> { pub impl<K:Eq + IterBytes + Hash,V> HashMap_<K, V> {
@ -179,7 +179,7 @@ pub mod chained {
match self.search_tbl(&k, hash) { match self.search_tbl(&k, hash) {
NotFound => { NotFound => {
self.count += 1u; self.count += 1u;
let idx = hash % vec::len(self.chains); let idx = hash % vec::uniq_len(&const self.chains);
let old_chain = self.chains[idx]; let old_chain = self.chains[idx];
self.chains[idx] = Some(@Entry { self.chains[idx] = Some(@Entry {
hash: hash, hash: hash,
@ -188,7 +188,7 @@ pub mod chained {
next: old_chain}); next: old_chain});
// consider rehashing if more 3/4 full // consider rehashing if more 3/4 full
let nchains = vec::len(self.chains); let nchains = vec::uniq_len(&const self.chains);
let load = util::Rational { let load = util::Rational {
num: (self.count + 1u) as int, num: (self.count + 1u) as int,
den: nchains as int, den: nchains as int,
@ -271,7 +271,7 @@ pub mod chained {
match self.search_tbl(&key, hash) { match self.search_tbl(&key, hash) {
NotFound => { NotFound => {
self.count += 1u; self.count += 1u;
let idx = hash % vec::len(self.chains); let idx = hash % vec::uniq_len(&const self.chains);
let old_chain = self.chains[idx]; let old_chain = self.chains[idx];
self.chains[idx] = Some(@Entry { self.chains[idx] = Some(@Entry {
hash: hash, hash: hash,
@ -280,7 +280,7 @@ pub mod chained {
next: old_chain}); next: old_chain});
// consider rehashing if more 3/4 full // consider rehashing if more 3/4 full
let nchains = vec::len(self.chains); let nchains = vec::uniq_len(&const self.chains);
let load = util::Rational { let load = util::Rational {
num: (self.count + 1u) as int, num: (self.count + 1u) as int,
den: nchains as int, den: nchains as int,

View file

@ -37,10 +37,10 @@ impl<T:Ord> BaseIter<T> for PriorityQueue<T> {
impl<T:Ord> Container for PriorityQueue<T> { impl<T:Ord> Container for PriorityQueue<T> {
/// Returns the length of the queue /// Returns the length of the queue
pure fn len(&self) -> uint { self.data.len() } pure fn len(&const self) -> uint { vec::uniq_len(&const self.data) }
/// Returns true if a queue contains no elements /// Returns true if a queue contains no elements
pure fn is_empty(&self) -> bool { self.data.is_empty() } pure fn is_empty(&const self) -> bool { self.len() == 0 }
} }
impl<T:Ord> Mutable for PriorityQueue<T> { impl<T:Ord> Mutable for PriorityQueue<T> {

View file

@ -91,7 +91,7 @@ pub fn sha1() -> @Sha1 {
} }
fn process_msg_block(st: &mut Sha1State) { fn process_msg_block(st: &mut Sha1State) {
fail_unless!((vec::len(st.h) == digest_buf_len)); fail_unless!((vec::len(st.h) == digest_buf_len));
fail_unless!((vec::len(*st.work_buf) == work_buf_len)); fail_unless!((vec::uniq_len(st.work_buf) == work_buf_len));
let mut t: int; // Loop counter let mut t: int; // Loop counter
let mut w = st.work_buf; let mut w = st.work_buf;

View file

@ -50,18 +50,19 @@ impl<V> ReverseIter<(uint, &'self V)> for SmallIntMap<V> {
impl<V> Container for SmallIntMap<V> { impl<V> Container for SmallIntMap<V> {
/// Return the number of elements in the map /// Return the number of elements in the map
pure fn len(&self) -> uint { pure fn len(&const self) -> uint {
let mut sz = 0; let mut sz = 0;
for self.v.each |item| { for uint::range(0, vec::uniq_len(&const self.v)) |i| {
if item.is_some() { match self.v[i] {
sz += 1; Some(_) => sz += 1,
None => {}
} }
} }
sz sz
} }
/// Return true if the map contains no elements /// Return true if the map contains no elements
pure fn is_empty(&self) -> bool { self.len() == 0 } pure fn is_empty(&const self) -> bool { self.len() == 0 }
} }
impl<V> Mutable for SmallIntMap<V> { impl<V> Mutable for SmallIntMap<V> {

View file

@ -68,9 +68,14 @@ fn part<T>(arr: &mut [T], left: uint,
let mut storage_index: uint = left; let mut storage_index: uint = left;
let mut i: uint = left; let mut i: uint = left;
while i < right { while i < right {
if compare_func(&arr[i], &arr[right]) { // XXX: Unsafe because borrow check doesn't handle this right
arr[i] <-> arr[storage_index]; unsafe {
storage_index += 1; let a: &T = cast::transmute(&mut arr[i]);
let b: &T = cast::transmute(&mut arr[right]);
if compare_func(a, b) {
arr[i] <-> arr[storage_index];
storage_index += 1;
}
} }
i += 1; i += 1;
} }
@ -451,7 +456,10 @@ impl<T:Copy + Ord> MergeState<T> {
base2: uint, len2: uint) { base2: uint, len2: uint) {
fail_unless!(len1 != 0 && len2 != 0 && base1+len1 == base2); fail_unless!(len1 != 0 && len2 != 0 && base1+len1 == base2);
let mut tmp = vec::slice(array, base1, base1+len1).to_vec(); let mut tmp = ~[];
for uint::range(base1, base1+len1) |i| {
tmp.push(array[i]);
}
let mut c1 = 0; let mut c1 = 0;
let mut c2 = base2; let mut c2 = base2;
@ -554,7 +562,10 @@ impl<T:Copy + Ord> MergeState<T> {
base2: uint, len2: uint) { base2: uint, len2: uint) {
fail_unless!(len1 != 1 && len2 != 0 && base1 + len1 == base2); fail_unless!(len1 != 1 && len2 != 0 && base1 + len1 == base2);
let mut tmp = vec::slice(array, base2, base2+len2).to_vec(); let mut tmp = ~[];
for uint::range(base2, base2+len2) |i| {
tmp.push(array[i]);
}
let mut c1 = base1 + len1 - 1; let mut c1 = base1 + len1 - 1;
let mut c2 = len2 - 1; let mut c2 = len2 - 1;
@ -702,7 +713,11 @@ fn copy_vec<T:Copy>(dest: &mut [T], s1: uint,
from: &[const T], s2: uint, len: uint) { from: &[const T], s2: uint, len: uint) {
fail_unless!(s1+len <= dest.len() && s2+len <= from.len()); fail_unless!(s1+len <= dest.len() && s2+len <= from.len());
let slice = vec::slice(from, s2, s2+len).to_vec(); let mut slice = ~[];
for uint::range(s2, s2+len) |i| {
slice.push(from[i]);
}
for slice.eachi |i, v| { for slice.eachi |i, v| {
dest[s1+i] = *v; dest[s1+i] = *v;
} }
@ -721,7 +736,7 @@ mod test_qsort3 {
quick_sort3::<int>(v1); quick_sort3::<int>(v1);
let mut i = 0; let mut i = 0;
while i < len { while i < len {
debug!(v2[i]); // debug!(v2[i]);
fail_unless!((v2[i] == v1[i])); fail_unless!((v2[i] == v1[i]));
i += 1; i += 1;
} }
@ -768,7 +783,7 @@ mod test_qsort {
quick_sort::<int>(v1, leual); quick_sort::<int>(v1, leual);
let mut i = 0u; let mut i = 0u;
while i < len { while i < len {
debug!(v2[i]); // debug!(v2[i]);
fail_unless!((v2[i] == v1[i])); fail_unless!((v2[i] == v1[i]));
i += 1; i += 1;
} }
@ -919,7 +934,7 @@ mod test_tim_sort {
tim_sort::<int>(v1); tim_sort::<int>(v1);
let mut i = 0u; let mut i = 0u;
while i < len { while i < len {
debug!(v2[i]); // debug!(v2[i]);
fail_unless!((v2[i] == v1[i])); fail_unless!((v2[i] == v1[i]));
i += 1u; i += 1u;
} }

View file

@ -358,7 +358,11 @@ pub fn run_tests_console(opts: &TestOpts,
fn print_failures(st: @ConsoleTestState) { fn print_failures(st: @ConsoleTestState) {
st.out.write_line(~"\nfailures:"); st.out.write_line(~"\nfailures:");
let mut failures = st.failures.map(|t| t.name.to_str()); let mut failures = ~[];
for uint::range(0, vec::uniq_len(&const st.failures)) |i| {
let name = copy st.failures[i].name;
failures.push(name.to_str());
}
sort::tim_sort(failures); sort::tim_sort(failures);
for vec::each(failures) |name| { for vec::each(failures) |name| {
st.out.write_line(fmt!(" %s", name.to_str())); st.out.write_line(fmt!(" %s", name.to_str()));

View file

@ -106,10 +106,10 @@ impl<'self, K: TotalOrd, V>
impl<K: TotalOrd, V> Container for TreeMap<K, V> { impl<K: TotalOrd, V> Container for TreeMap<K, V> {
/// Return the number of elements in the map /// Return the number of elements in the map
pure fn len(&self) -> uint { self.length } pure fn len(&const self) -> uint { self.length }
/// Return true if the map contains no elements /// Return true if the map contains no elements
pure fn is_empty(&self) -> bool { self.root.is_none() } pure fn is_empty(&const self) -> bool { self.root.is_none() }
} }
impl<K: TotalOrd, V> Mutable for TreeMap<K, V> { impl<K: TotalOrd, V> Mutable for TreeMap<K, V> {
@ -276,11 +276,11 @@ impl<T: Ord + TotalOrd> Ord for TreeSet<T> {
impl<T: TotalOrd> Container for TreeSet<T> { impl<T: TotalOrd> Container for TreeSet<T> {
/// Return the number of elements in the set /// Return the number of elements in the set
#[inline(always)] #[inline(always)]
pure fn len(&self) -> uint { self.map.len() } pure fn len(&const self) -> uint { self.map.len() }
/// Return true if the set contains no elements /// Return true if the set contains no elements
#[inline(always)] #[inline(always)]
pure fn is_empty(&self) -> bool { self.map.is_empty() } pure fn is_empty(&const self) -> bool { self.map.is_empty() }
} }
impl<T: TotalOrd> Mutable for TreeSet<T> { impl<T: TotalOrd> Mutable for TreeSet<T> {

View file

@ -252,8 +252,8 @@ pub impl FileMap {
// about what ends a line between this file and parse.rs // about what ends a line between this file and parse.rs
fn next_line(&self, +pos: BytePos) { fn next_line(&self, +pos: BytePos) {
// the new charpos must be > the last one (or it's the first one). // the new charpos must be > the last one (or it's the first one).
fail_unless!((self.lines.len() == 0) let lines = &mut *self.lines;
|| (self.lines[self.lines.len() - 1] < pos)); fail_unless!((lines.len() == 0) || (lines[lines.len() - 1] < pos));
self.lines.push(pos); self.lines.push(pos);
} }
@ -302,11 +302,12 @@ pub impl CodeMap {
+substr: FileSubstr, +substr: FileSubstr,
src: @~str src: @~str
) -> @FileMap { ) -> @FileMap {
let start_pos = if self.files.len() == 0 { let files = &mut *self.files;
let start_pos = if files.len() == 0 {
0 0
} else { } else {
let last_start = self.files.last().start_pos.to_uint(); let last_start = files.last().start_pos.to_uint();
let last_len = self.files.last().src.len(); let last_len = files.last().src.len();
last_start + last_len last_start + last_len
}; };
@ -364,7 +365,8 @@ pub impl CodeMap {
} }
pub fn span_to_str(&self, sp: span) -> ~str { pub fn span_to_str(&self, sp: span) -> ~str {
if self.files.len() == 0 && sp == dummy_sp() { let files = &mut *self.files;
if files.len() == 0 && sp == dummy_sp() {
return ~"no-location"; return ~"no-location";
} }
@ -409,7 +411,8 @@ pub impl CodeMap {
priv impl CodeMap { priv impl CodeMap {
fn lookup_filemap_idx(&self, +pos: BytePos) -> uint { fn lookup_filemap_idx(&self, +pos: BytePos) -> uint {
let len = self.files.len(); let files = &*self.files;
let len = files.len();
let mut a = 0u; let mut a = 0u;
let mut b = len; let mut b = len;
while b - a > 1u { while b - a > 1u {
@ -433,10 +436,11 @@ priv impl CodeMap {
let idx = self.lookup_filemap_idx(pos); let idx = self.lookup_filemap_idx(pos);
let f = self.files[idx]; let f = self.files[idx];
let mut a = 0u; let mut a = 0u;
let mut b = f.lines.len(); let lines = &*f.lines;
let mut b = lines.len();
while b - a > 1u { while b - a > 1u {
let m = (a + b) / 2u; let m = (a + b) / 2u;
if f.lines[m] > pos { b = m; } else { a = m; } if lines[m] > pos { b = m; } else { a = m; }
} }
return FileMapAndLine {fm: f, line: a}; return FileMapAndLine {fm: f, line: a};
} }

View file

@ -226,7 +226,7 @@ fn create_eq_method(cx: @ext_ctxt,
attrs: ~[], attrs: ~[],
generics: ast_util::empty_generics(), generics: ast_util::empty_generics(),
self_ty: self_ty, self_ty: self_ty,
purity: pure_fn, purity: impure_fn,
decl: fn_decl, decl: fn_decl,
body: body_block, body: body_block,
id: cx.next_id(), id: cx.next_id(),
@ -405,7 +405,7 @@ fn create_iter_bytes_method(cx: @ext_ctxt,
attrs: ~[], attrs: ~[],
generics: ast_util::empty_generics(), generics: ast_util::empty_generics(),
self_ty: self_ty, self_ty: self_ty,
purity: pure_fn, purity: impure_fn,
decl: fn_decl, decl: fn_decl,
body: body_block, body: body_block,
id: cx.next_id(), id: cx.next_id(),

View file

@ -41,7 +41,8 @@ impl proto::visitor<(), (), ()> for @ext_ctxt {
fn visit_proto(&self, _proto: protocol, _states: &[()]) { } fn visit_proto(&self, _proto: protocol, _states: &[()]) { }
fn visit_state(&self, state: state, _m: &[()]) { fn visit_state(&self, state: state, _m: &[()]) {
if state.messages.len() == 0 { let messages = &*state.messages;
if messages.len() == 0 {
self.span_warn( self.span_warn(
state.span, // use a real span! state.span, // use a real span!
fmt!("state %s contains no messages, \ fmt!("state %s contains no messages, \

View file

@ -91,7 +91,7 @@ pub fn analyze(proto: protocol, _cx: @ext_ctxt) {
let states = str::connect(self_live.map(|s| copy s.name), ~" "); let states = str::connect(self_live.map(|s| copy s.name), ~" ");
debug!("protocol %s is unbounded due to loops involving: %s", debug!("protocol %s is unbounded due to loops involving: %s",
proto.name, states); copy proto.name, states);
// Someday this will be configurable with a warning // Someday this will be configurable with a warning
//cx.span_warn(empty_span(), //cx.span_warn(empty_span(),
@ -103,7 +103,7 @@ pub fn analyze(proto: protocol, _cx: @ext_ctxt) {
proto.bounded = Some(false); proto.bounded = Some(false);
} }
else { else {
debug!("protocol %s is bounded. yay!", proto.name); debug!("protocol %s is bounded. yay!", copy proto.name);
proto.bounded = Some(true); proto.bounded = Some(true);
} }
} }

View file

@ -156,7 +156,10 @@ pub impl protocol_ {
~"proto://" + self.name ~"proto://" + self.name
} }
fn num_states(&mut self) -> uint { self.states.len() } fn num_states(&mut self) -> uint {
let states = &mut *self.states;
states.len()
}
fn has_ty_params(&mut self) -> bool { fn has_ty_params(&mut self) -> bool {
for self.states.each |s| { for self.states.each |s| {
@ -180,9 +183,10 @@ pub impl protocol_ {
+generics: ast::Generics) +generics: ast::Generics)
-> state { -> state {
let messages = @mut ~[]; let messages = @mut ~[];
let states = &*self.states;
let state = @state_ { let state = @state_ {
id: self.states.len(), id: states.len(),
name: name, name: name,
ident: ident, ident: ident,
span: self.span, span: self.span,

View file

@ -106,8 +106,9 @@ pub pure fn dup_tt_reader(r: @mut TtReader) -> @mut TtReader {
} }
pure fn lookup_cur_matched_by_matched(r: @mut TtReader, pure fn lookup_cur_matched_by_matched(r: &mut TtReader,
start: @named_match) -> @named_match { start: @named_match)
-> @named_match {
pure fn red(+ad: @named_match, idx: &uint) -> @named_match { pure fn red(+ad: @named_match, idx: &uint) -> @named_match {
match *ad { match *ad {
matched_nonterminal(_) => { matched_nonterminal(_) => {
@ -117,18 +118,20 @@ pure fn lookup_cur_matched_by_matched(r: @mut TtReader,
matched_seq(ref ads, _) => ads[*idx] matched_seq(ref ads, _) => ads[*idx]
} }
} }
vec::foldl(start, r.repeat_idx, red) let r = &mut *r;
let repeat_idx = &r.repeat_idx;
vec::foldl(start, *repeat_idx, red)
} }
fn lookup_cur_matched(r: @mut TtReader, name: ident) -> @named_match { fn lookup_cur_matched(r: &mut TtReader, name: ident) -> @named_match {
lookup_cur_matched_by_matched(r, r.interpolations.get(&name)) lookup_cur_matched_by_matched(r, r.interpolations.get(&name))
} }
enum lis { enum lis {
lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str) lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
} }
fn lockstep_iter_size(t: token_tree, r: @mut TtReader) -> lis { fn lockstep_iter_size(t: token_tree, r: &mut TtReader) -> lis {
fn lis_merge(lhs: lis, rhs: lis, r: @mut TtReader) -> lis { fn lis_merge(lhs: lis, rhs: lis, r: &mut TtReader) -> lis {
match lhs { match lhs {
lis_unconstrained => copy rhs, lis_unconstrained => copy rhs,
lis_contradiction(_) => copy lhs, lis_contradiction(_) => copy lhs,
@ -148,8 +151,10 @@ fn lockstep_iter_size(t: token_tree, r: @mut TtReader) -> lis {
} }
match t { match t {
tt_delim(ref tts) | tt_seq(_, ref tts, _, _) => { tt_delim(ref tts) | tt_seq(_, ref tts, _, _) => {
vec::foldl(lis_unconstrained, (*tts), |lis, tt| vec::foldl(lis_unconstrained, (*tts), |lis, tt| {
lis_merge(lis, lockstep_iter_size(*tt, r), r)) let lis2 = lockstep_iter_size(*tt, r);
lis_merge(lis, lis2, r)
})
} }
tt_tok(*) => lis_unconstrained, tt_tok(*) => lis_unconstrained,
tt_nonterminal(_, name) => match *lookup_cur_matched(r, name) { tt_nonterminal(_, name) => match *lookup_cur_matched(r, name) {
@ -160,12 +165,20 @@ fn lockstep_iter_size(t: token_tree, r: @mut TtReader) -> lis {
} }
pub fn tt_next_token(r: @mut TtReader) -> TokenAndSpan { pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
let ret_val = TokenAndSpan { let ret_val = TokenAndSpan {
tok: copy r.cur_tok, tok: copy r.cur_tok,
sp: r.cur_span, sp: r.cur_span,
}; };
while r.cur.idx >= r.cur.readme.len() { loop {
{
let cur = &mut *r.cur;
let readme = &mut *cur.readme;
if cur.idx < readme.len() {
break;
}
}
/* done with this set; pop or repeat? */ /* done with this set; pop or repeat? */
if ! r.cur.dotdotdoted if ! r.cur.dotdotdoted
|| { *r.repeat_idx.last() == *r.repeat_len.last() - 1 } { || { *r.repeat_idx.last() == *r.repeat_len.last() - 1 } {

View file

@ -811,7 +811,7 @@ pub mod test {
sp:span {lo:BytePos(21),hi:BytePos(23),expn_info: None}}; sp:span {lo:BytePos(21),hi:BytePos(23),expn_info: None}};
check_equal (tok1,tok2); check_equal (tok1,tok2);
// the 'main' id is already read: // the 'main' id is already read:
check_equal (string_reader.last_pos,BytePos(28)); check_equal (copy string_reader.last_pos,BytePos(28));
// read another token: // read another token:
let tok3 = string_reader.next_token(); let tok3 = string_reader.next_token();
let tok4 = TokenAndSpan{ let tok4 = TokenAndSpan{
@ -819,7 +819,7 @@ pub mod test {
sp:span {lo:BytePos(24),hi:BytePos(28),expn_info: None}}; sp:span {lo:BytePos(24),hi:BytePos(28),expn_info: None}};
check_equal (tok3,tok4); check_equal (tok3,tok4);
// the lparen is already read: // the lparen is already read:
check_equal (string_reader.last_pos,BytePos(29)) check_equal (copy string_reader.last_pos,BytePos(29))
} }
// check that the given reader produces the desired stream // check that the given reader produces the desired stream

View file

@ -412,7 +412,8 @@ pub impl Parser {
fn parse_purity(&self) -> purity { fn parse_purity(&self) -> purity {
if self.eat_keyword(&~"pure") { if self.eat_keyword(&~"pure") {
return pure_fn; // NB: We parse this as impure for bootstrapping purposes.
return impure_fn;
} else if self.eat_keyword(&~"unsafe") { } else if self.eat_keyword(&~"unsafe") {
return unsafe_fn; return unsafe_fn;
} else { } else {
@ -2668,7 +2669,8 @@ pub impl Parser {
fn parse_optional_purity(&self) -> ast::purity { fn parse_optional_purity(&self) -> ast::purity {
if self.eat_keyword(&~"pure") { if self.eat_keyword(&~"pure") {
ast::pure_fn // NB: We parse this as impure for bootstrapping purposes.
ast::impure_fn
} else if self.eat_keyword(&~"unsafe") { } else if self.eat_keyword(&~"unsafe") {
ast::unsafe_fn ast::unsafe_fn
} else { } else {
@ -3418,7 +3420,8 @@ pub impl Parser {
let prefix = Path(self.sess.cm.span_to_filename(*self.span)); let prefix = Path(self.sess.cm.span_to_filename(*self.span));
let prefix = prefix.dir_path(); let prefix = prefix.dir_path();
let mod_path = Path(".").push_many(*self.mod_path_stack); let mod_path_stack = &*self.mod_path_stack;
let mod_path = Path(".").push_many(*mod_path_stack);
let default_path = *self.sess.interner.get(id) + ~".rs"; let default_path = *self.sess.interner.get(id) + ~".rs";
let file_path = match ::attr::first_attr_value_str_by_name( let file_path = match ::attr::first_attr_value_str_by_name(
outer_attrs, ~"path") { outer_attrs, ~"path") {
@ -3505,7 +3508,8 @@ pub impl Parser {
if self.eat_keyword(&~"fn") { impure_fn } if self.eat_keyword(&~"fn") { impure_fn }
else if self.eat_keyword(&~"pure") { else if self.eat_keyword(&~"pure") {
self.expect_keyword(&~"fn"); self.expect_keyword(&~"fn");
pure_fn // NB: We parse this as impure for bootstrapping purposes.
impure_fn
} else if self.eat_keyword(&~"unsafe") { } else if self.eat_keyword(&~"unsafe") {
self.expect_keyword(&~"fn"); self.expect_keyword(&~"fn");
unsafe_fn unsafe_fn
@ -3894,8 +3898,9 @@ pub impl Parser {
maybe_append(attrs, extra_attrs))); maybe_append(attrs, extra_attrs)));
} else if items_allowed && self.eat_keyword(&~"pure") { } else if items_allowed && self.eat_keyword(&~"pure") {
// PURE FUNCTION ITEM // PURE FUNCTION ITEM
// NB: We parse this as impure for bootstrapping purposes.
self.expect_keyword(&~"fn"); self.expect_keyword(&~"fn");
let (ident, item_, extra_attrs) = self.parse_item_fn(pure_fn); let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn);
return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
visibility, visibility,
maybe_append(attrs, extra_attrs))); maybe_append(attrs, extra_attrs)));

View file

@ -452,9 +452,10 @@ pub impl Printer {
self.pending_indentation += amount; self.pending_indentation += amount;
} }
fn get_top(&mut self) -> print_stack_elt { fn get_top(&mut self) -> print_stack_elt {
let n = self.print_stack.len(); let print_stack = &mut *self.print_stack;
let n = print_stack.len();
if n != 0u { if n != 0u {
self.print_stack[n - 1u] print_stack[n - 1u]
} else { } else {
print_stack_elt { print_stack_elt {
offset: 0, offset: 0,
@ -496,7 +497,8 @@ pub impl Printer {
} }
END => { END => {
debug!("print END -> pop END"); debug!("print END -> pop END");
fail_unless!((self.print_stack.len() != 0u)); let print_stack = &*self.print_stack;
fail_unless!((print_stack.len() != 0u));
self.print_stack.pop(); self.print_stack.pop();
} }
BREAK(b) => { BREAK(b) => {

View file

@ -279,9 +279,10 @@ pub fn is_bol(s: @ps) -> bool {
} }
pub fn in_cbox(s: @ps) -> bool { pub fn in_cbox(s: @ps) -> bool {
let len = s.boxes.len(); let boxes = &*s.boxes;
let len = boxes.len();
if len == 0u { return false; } if len == 0u { return false; }
return s.boxes[len - 1u] == pp::consistent; return boxes[len - 1u] == pp::consistent;
} }
pub fn hardbreak_if_not_bol(s: @ps) { if !is_bol(s) { hardbreak(s.s); } } pub fn hardbreak_if_not_bol(s: @ps) { if !is_bol(s) { hardbreak(s.s); } }

View file

@ -41,14 +41,18 @@ pub impl<T:Eq + IterBytes + Hash + Const + Copy> Interner<T> {
None => (), None => (),
} }
let new_idx = self.vect.len(); let vect = &*self.vect;
let new_idx = vect.len();
self.map.insert(val, new_idx); self.map.insert(val, new_idx);
self.vect.push(val); self.vect.push(val);
new_idx new_idx
} }
fn gensym(&self, val: T) -> uint { fn gensym(&self, val: T) -> uint {
let new_idx = self.vect.len(); let new_idx = {
let vect = &*self.vect;
vect.len()
};
// leave out of .map to avoid colliding // leave out of .map to avoid colliding
self.vect.push(val); self.vect.push(val);
new_idx new_idx
@ -59,7 +63,7 @@ pub impl<T:Eq + IterBytes + Hash + Const + Copy> Interner<T> {
// where we first check a pred and then rely on it, ceasing to fail is ok. // where we first check a pred and then rely on it, ceasing to fail is ok.
pure fn get(&self, idx: uint) -> T { self.vect[idx] } pure fn get(&self, idx: uint) -> T { self.vect[idx] }
fn len(&self) -> uint { self.vect.len() } fn len(&self) -> uint { let vect = &*self.vect; vect.len() }
} }
#[test] #[test]

View file

@ -22,17 +22,6 @@ fn match_const_box(v: &const @const Option<int>) -> int {
} }
} }
pure fn pure_process(_i: int) {}
fn match_const_box_and_do_pure_things(v: &const @const Option<int>) {
match *v {
@Some(ref i) => {
pure_process(*i)
}
@None => {}
}
}
fn process(_i: int) {} fn process(_i: int) {}
fn match_const_box_and_do_bad_things(v: &const @const Option<int>) { fn match_const_box_and_do_bad_things(v: &const @const Option<int>) {

View file

@ -1,33 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pure fn pure_borrow(_x: &int, _y: ()) {}
fn test1(x: @mut ~int) {
// Here, evaluating the second argument actually invalidates the
// first borrow, even though it occurs outside of the scope of the
// borrow!
pure_borrow(*x, *x = ~5); //~ ERROR illegal borrow unless pure
//~^ NOTE impure due to assigning to dereference of mutable @ pointer
}
fn test2() {
let mut x = ~1;
// Same, but for loanable data:
pure_borrow(x, x = ~5); //~ ERROR assigning to mutable local variable prohibited due to outstanding loan
//~^ NOTE loan of mutable local variable granted here
copy x;
}
fn main() {
}

View file

@ -1,16 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pure fn call_first((x, _y): (&fn(), &fn())) {
x(); //~ ERROR access to impure function prohibited in pure context
}
fn main() {}

View file

@ -1,64 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[legacy_modes];
// Test rules governing higher-order pure fns.
struct S<'self> {
f: &'self fn(uint)
}
pure fn range(from: uint, to: uint, f: &fn(uint)) {
let mut i = from;
while i < to {
f(i); // Note: legal to call argument, even if it is not pure.
i += 1u;
}
}
pure fn range2(from: uint, to: uint, f: &fn(uint)) {
do range(from, to) |i| {
f(i*2u);
}
}
pure fn range3(from: uint, to: uint, f: &fn(uint)) {
range(from, to, f)
}
pure fn range4(from: uint, to: uint) {
range(from, to, print) //~ ERROR access to impure function prohibited in pure context
}
pure fn range5<'a>(from: uint, to: uint, x: S<'a>) {
range(from, to, x.f) //~ ERROR access to impure function prohibited in pure context
}
pure fn range6<'a>(from: uint, to: uint, x: @S<'a>) {
range(from, to, x.f) //~ ERROR access to impure function prohibited in pure context
}
pure fn range7(from: uint, to: uint) {
do range(from, to) |i| {
print(i); //~ ERROR access to impure function prohibited in pure context
}
}
pure fn range8(from: uint, to: uint) {
range(from, to, noop);
}
fn print(i: uint) { error!("i=%u", i); }
pure fn noop(_i: uint) {}
fn main() {
}

View file

@ -1,35 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct S<'self> {
x: &'self fn(uint)
}
pure fn range<'a>(from: uint, to: uint, f: &'a fn(uint) -> bool) {
let mut i = from;
while i < to {
if !f(i) {return;} // Note: legal to call argument, even if it is not pure.
i += 1u;
}
}
pure fn range2<'a>(from: uint, to: uint, f: &'a fn(uint)) {
for range(from, to) |i| {
f(i*2u);
}
}
pure fn range3<'a>(from: uint, to: uint, f: S<'a>) {
for range(from, to) |i| {
(f.x)(i*2u); //~ ERROR access to impure function prohibited
}
}
fn main() {}

View file

@ -1,32 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that pure functions cannot modify aliased state.
struct S {
f: int,
}
pure fn modify_in_box(sum: @mut S) {
sum.f = 3; //~ ERROR assigning to mutable field prohibited in pure context
}
trait modify_in_box_rec {
pure fn modify_in_box_rec(&self, sum: @mut S);
}
impl modify_in_box_rec for int {
pure fn modify_in_box_rec(&self, sum: @mut S) {
sum.f = *self; //~ ERROR assigning to mutable field prohibited in pure context
}
}
fn main() {
}

View file

@ -1,48 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test rules governing higher-order pure fns.
fn take<T>(_v: T) {}
fn assign_to_pure(x: &pure fn(), y: &fn(), z: &unsafe fn()) {
take::<&pure fn()>(x);
take::<&pure fn()>(y); //~ ERROR expected pure fn but found impure fn
take::<&pure fn()>(z); //~ ERROR expected pure fn but found unsafe fn
}
fn assign_to_impure(x: &pure fn(), y: &fn(), z: &unsafe fn()) {
take::<&fn()>(x);
take::<&fn()>(y);
take::<&fn()>(z); //~ ERROR expected impure fn but found unsafe fn
}
fn assign_to_unsafe(x: &pure fn(), y: &fn(), z: &unsafe fn()) {
take::<&unsafe fn()>(x);
take::<&unsafe fn()>(y);
take::<&unsafe fn()>(z);
}
fn assign_to_pure2(x: @pure fn(), y: @fn(), z: @unsafe fn()) {
take::<&pure fn()>(x);
take::<&pure fn()>(y); //~ ERROR expected pure fn but found impure fn
take::<&pure fn()>(z); //~ ERROR expected pure fn but found unsafe fn
take::<~pure fn()>(x); //~ ERROR expected ~ closure, found @ closure
take::<~pure fn()>(y); //~ ERROR expected ~ closure, found @ closure
take::<~pure fn()>(z); //~ ERROR expected ~ closure, found @ closure
take::<~unsafe fn()>(x); //~ ERROR expected ~ closure, found @ closure
take::<~unsafe fn()>(y); //~ ERROR expected ~ closure, found @ closure
take::<~unsafe fn()>(z); //~ ERROR expected ~ closure, found @ closure
}
fn main() {
}

View file

@ -1,16 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn something(f: &pure fn()) { f(); }
fn main() {
let mut x = ~[];
something(|| x.push(0) ); //~ ERROR access to impure function prohibited in pure context
}

View file

@ -9,15 +9,15 @@
// except according to those terms. // except according to those terms.
trait Mumbo { trait Mumbo {
pure fn jumbo(&self, x: @uint) -> uint; fn jumbo(&self, x: @uint) -> uint;
fn jambo(&self, x: @const uint) -> uint; fn jambo(&self, x: @const uint) -> uint;
fn jbmbo(&self) -> @uint; fn jbmbo(&self) -> @uint;
} }
impl Mumbo for uint { impl Mumbo for uint {
// Cannot have a larger effect than the trait: // Cannot have a larger effect than the trait:
fn jumbo(&self, x: @uint) { *self + *x; } unsafe fn jumbo(&self, x: @uint) { *self + *x; }
//~^ ERROR expected pure fn but found impure fn //~^ ERROR expected impure fn but found unsafe fn
// Cannot accept a narrower range of parameters: // Cannot accept a narrower range of parameters:
fn jambo(&self, x: @uint) { *self + *x; } fn jambo(&self, x: @uint) { *self + *x; }

View file

@ -39,7 +39,6 @@ pub fn main() {
(&"test").test_imm(); (&"test").test_imm();
// XXX: Other types of mutable vecs don't currently exist // XXX: Other types of mutable vecs don't currently exist
(@mut [1]).test_imm();
([1]).test_const(); ([1]).test_const();
(~[1]).test_const(); (~[1]).test_const();
@ -50,8 +49,6 @@ pub fn main() {
(@"test").test_const(); (@"test").test_const();
(&"test").test_const(); (&"test").test_const();
(@mut [1]).test_const();
// NB: We don't do this double autoreffing for &mut self because that would // NB: We don't do this double autoreffing for &mut self because that would
// allow creating a mutable pointer to a temporary, which would be a source // allow creating a mutable pointer to a temporary, which would be a source
// of confusion // of confusion

View file

@ -62,8 +62,8 @@ impl<T> BaseIter<(int, &'self T)> for cat<T> {
} }
impl<T> Container for cat<T> { impl<T> Container for cat<T> {
pure fn len(&self) -> uint { self.meows as uint } pure fn len(&const self) -> uint { self.meows as uint }
pure fn is_empty(&self) -> bool { self.meows == 0 } pure fn is_empty(&const self) -> bool { self.meows == 0 }
} }
impl<T> Mutable for cat<T> { impl<T> Mutable for cat<T> {

View file

@ -10,8 +10,4 @@ fn negate_imm(y: &int) -> int {
negate(y) negate(y)
} }
fn negate_const(y: &const int) -> int {
negate(y)
}
pub fn main() {} pub fn main() {}

View file

@ -3,7 +3,7 @@ struct SpeechMaker {
} }
pub impl SpeechMaker { pub impl SpeechMaker {
pure fn how_many(&self) -> uint { self.speeches } pure fn how_many(&const self) -> uint { self.speeches }
} }
fn foo(speaker: &const SpeechMaker) -> uint { fn foo(speaker: &const SpeechMaker) -> uint {

View file

@ -1,3 +1,5 @@
// xfail-test
pure fn sum(x: &[int]) -> int { pure fn sum(x: &[int]) -> int {
let mut sum = 0; let mut sum = 0;
for x.each |y| { sum += *y; } for x.each |y| { sum += *y; }

View file

@ -1,3 +1,5 @@
// xfail-test
fn foo(v: &[const uint]) -> ~[uint] { fn foo(v: &[const uint]) -> ~[uint] {
v.to_vec() v.to_vec()
} }

View file

@ -16,6 +16,6 @@ struct Refs { refs: ~[int], n: int }
pub fn main() { pub fn main() {
let e = @mut Refs{refs: ~[], n: 0}; let e = @mut Refs{refs: ~[], n: 0};
let f: @fn() = || error!(e.n); let f: @fn() = || error!(copy e.n);
e.refs += ~[1]; e.refs += ~[1];
} }