]> git.lizzy.rs Git - rust.git/commitdiff
librustc: Make the compiler ignore purity.
authorPatrick Walton <pcwalton@mimiga.net>
Sat, 16 Mar 2013 18:11:31 +0000 (11:11 -0700)
committerPatrick Walton <pcwalton@mimiga.net>
Tue, 19 Mar 2013 00:21:16 +0000 (17:21 -0700)
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.

72 files changed:
doc/rust.md
doc/tutorial-borrowed-ptr.md
src/libcore/cell.rs
src/libcore/comm.rs
src/libcore/container.rs
src/libcore/hashmap.rs
src/libcore/io.rs
src/libcore/mutable.rs
src/libcore/option.rs
src/libcore/ptr.rs
src/libcore/repr.rs
src/libcore/task/spawn.rs
src/libcore/trie.rs
src/libcore/vec.rs
src/librustc/front/test.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/cstore.rs
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/borrowck/gather_loans.rs
src/librustc/middle/liveness.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/build.rs
src/librustc/middle/trans/controlflow.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/glue.rs
src/librustc/middle/trans/type_use.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/infer/mod.rs
src/libstd/bitv.rs
src/libstd/deque.rs
src/libstd/flatpipes.rs
src/libstd/json.rs
src/libstd/net_tcp.rs
src/libstd/oldmap.rs
src/libstd/priority_queue.rs
src/libstd/sha1.rs
src/libstd/smallintmap.rs
src/libstd/sort.rs
src/libstd/test.rs
src/libstd/treemap.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/deriving.rs
src/libsyntax/ext/pipes/check.rs
src/libsyntax/ext/pipes/liveness.rs
src/libsyntax/ext/pipes/proto.rs
src/libsyntax/ext/tt/transcribe.rs
src/libsyntax/parse/lexer.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pp.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/interner.rs
src/test/compile-fail/borrowck-pat-enum-in-box.rs
src/test/compile-fail/borrowck-pure-scope-in-call.rs [deleted file]
src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs [deleted file]
src/test/compile-fail/pure-higher-order.rs [deleted file]
src/test/compile-fail/pure-loop-body.rs [deleted file]
src/test/compile-fail/pure-modifies-aliased.rs [deleted file]
src/test/compile-fail/pure-subtyping.rs [deleted file]
src/test/compile-fail/purity-infer-fail.rs [deleted file]
src/test/compile-fail/trait-impl-method-mismatch.rs
src/test/run-pass/auto-ref-slice-plus-ref.rs
src/test/run-pass/class-impl-very-parameterized-trait.rs
src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs
src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs
src/test/run-pass/coerce-reborrow-imm-vec-arg.rs
src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs
src/test/run-pass/lambda-infer-unresolved.rs

index f64877a69ba974983cb6693722710497a0409b25..6be428ef27908a94f420f01664e48e8a17ebfe94 100644 (file)
@@ -214,7 +214,7 @@ false fn for
 if impl
 let loop
 match mod mut
-priv pub pure
+priv pub
 ref return
 self static struct super
 true trait type
@@ -936,7 +936,6 @@ Specifically, the following operations are considered unsafe:
 
   - Dereferencing a [raw pointer](#pointer-types).
   - 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.
 
 ##### 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.
 
 
-#### 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
 
 A special kind of function can be declared with a `!` character where the
@@ -1246,10 +1209,10 @@ For example:
 
 ~~~~
 trait Num {
-    static pure fn from_int(n: int) -> Self;
+    static fn from_int(n: int) -> Self;
 }
 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);
 ~~~~
@@ -2643,7 +2606,7 @@ Raw pointers (`*`)
 ### Function types
 
 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.
 
 An example of a `fn` type:
index e638579253fed8df756a02dbeaf9775c2a752516..8e0ca297f657ceb54e418c783e2398de5eac1277 100644 (file)
@@ -486,12 +486,12 @@ For example, we could write a subroutine like this:
 
 ~~~
 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
-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
+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
 far.  Here the identifier `r` names the lifetime of the pointer
 explicitly. So in effect, this function declares that it takes a
 pointer with lifetime `r` and returns a pointer with that same
@@ -572,8 +572,8 @@ function:
 #     Rectangle(Point, Size)  // upper-left, dimensions
 # }
 # fn compute_area(shape: &Shape) -> float { 0f }
-fn select<T>(shape: &r/Shape, threshold: float,
-             a: &r/T, b: &r/T) -> &r/T {
+fn select<T>(shape: &'r Shape, threshold: float,
+             a: &'r T, b: &'r T) -> &'r T {
     if compute_area(shape) > threshold {a} else {b}
 }
 ~~~
@@ -593,17 +593,17 @@ example:
 # }
 # fn compute_area(shape: &Shape) -> float { 0f }
 # 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}
 # }
-                                                  // -+ r
-fn select_based_on_unit_circle<T>(                //  |-+ B
-    threshold: float, a: &r/T, b: &r/T) -> &r/T { //  | |
-                                                  //  | |
-    let shape = Circle(Point {x: 0., y: 0.}, 1.); //  | |
-    select(&shape, threshold, a, b)               //  | |
-}                                                 //  |-+
-                                                  // -+
+                                                     // -+ r
+fn select_based_on_unit_circle<T>(                   //  |-+ B
+    threshold: float, a: &'r T, b: &'r T) -> &'r T { //  | |
+                                                     //  | |
+    let shape = Circle(Point {x: 0., y: 0.}, 1.);    //  | |
+    select(&shape, threshold, a, b)                  //  | |
+}                                                    //  |-+
+                                                     // -+
 ~~~
 
 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
 # }
 # fn compute_area(shape: &Shape) -> float { 0f }
-fn select<T>(shape: &tmp/Shape, threshold: float,
-             a: &r/T, b: &r/T) -> &r/T {
+fn select<T>(shape: &'tmp Shape, threshold: float,
+             a: &'r T, b: &'r T) -> &'r T {
     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 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}
 }
 ~~~
index da247c648fc8cebaf7517661d895326e4de3ca89..cfd1b8dfef0009c6f6d1b113039775a40fbc4fb7 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cast::transmute;
 use option;
 use prelude::*;
 
 ///
 /// Similar to a mutable option type, but friendlier.
 
-#[deriving_eq]
 pub struct Cell<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.
 pub fn Cell<T>(value: T) -> Cell<T> {
     Cell { value: Some(value) }
index 5b189abf4a373adbd417670b763d7c9cf6e514a8..12dc2d7e34158219c23ec1b4a00d85dbc9b2b530 100644 (file)
@@ -8,10 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cast;
 use either::{Either, Left, Right};
 use kinds::Owned;
 use option;
 use option::{Option, Some, None, unwrap};
+use uint;
 use unstable;
 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 {
     // It'd be nice to use self.port.each, but that version isn't
     // pure.
-    for vec::each(self.ports) |p| {
-        if p.peek() { return true }
+    for uint::range(0, vec::uniq_len(&const self.ports)) |i| {
+        // XXX: Botch pending demuting.
+        unsafe {
+            let port: &Port<T> = cast::transmute(&mut self.ports[i]);
+            if port.peek() { return true }
+        }
     }
     false
 }
index efcf1e26534c218e7621c14dd634e336b593b94b..5044b3a6c5de1a3721efd5b65f289462bf7d8a41 100644 (file)
 
 pub trait 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
-    pure fn is_empty(&self) -> bool;
+    pure fn is_empty(&const self) -> bool;
 }
 
 pub trait Mutable: Container {
index 20d207e9302b52da914521a91638be449f501f99..68a55792077e9600f689b363224d47c7f3705e62 100644 (file)
@@ -290,10 +290,10 @@ impl<K:Hash + IterBytes + Eq,V>
 
     impl<K:Hash + IterBytes + Eq,V> Container for LinearMap<K, V> {
         /// 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
-        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> {
@@ -555,10 +555,10 @@ impl<T:Hash + IterBytes + Eq> Eq for LinearSet<T> {
 
     impl<T:Hash + IterBytes + Eq> Container for LinearSet<T> {
         /// 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
-        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> {
index b580d9c84a85c4d628d270a418becbdb7a7896d8..50e7a42b7b17c2c61bd3d1fa52e9d78ff600ef20 100644 (file)
@@ -1116,7 +1116,7 @@ pub struct BytesWriter {
 impl Writer for BytesWriter {
     fn write(&self, v: &[const u8]) {
         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);
         vec::reserve(&mut self.bytes, count);
@@ -1131,7 +1131,7 @@ fn write(&self, v: &[const u8]) {
     }
     fn seek(&self, offset: int, whence: SeekStyle) {
         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);
     }
     fn tell(&self) -> uint { self.pos }
index 875d378b6453f80084b91f205de87487877a0e27..d0aa6e050f53ced5417bfeb4a38c53bd9713a4bb 100644 (file)
@@ -46,8 +46,7 @@ pub fn unwrap<T>(m: Mut<T>) -> T {
 pub impl<T> Data<T> {
     fn borrow_mut<R>(&self, op: &fn(t: &mut T) -> R) -> R {
         match self.mode {
-            Immutable => fail!(fmt!("%? currently immutable",
-                                   self.value)),
+            Immutable => fail!(~"currently immutable"),
             ReadOnly | Mutable => {}
         }
 
@@ -62,8 +61,7 @@ fn borrow_mut<R>(&self, op: &fn(t: &mut T) -> R) -> R {
 
     fn borrow_imm<R>(&self, op: &fn(t: &T) -> R) -> R {
         match self.mode {
-          Mutable => fail!(fmt!("%? currently mutable",
-                               self.value)),
+          Mutable => fail!(~"currently mutable"),
           ReadOnly | Immutable => {}
         }
 
index 237fc762b3c5340af799c3c85e138d2a33a3ed8a..5e5396ea121149cf88f7b8736aa918dffe0c344d 100644 (file)
@@ -228,14 +228,14 @@ impl<T: Copy + Add<T,T>> Add<Option<T>, Option<T>> for Option<T> {
 }
 
 #[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`
 
     match *opt { None => true, Some(_) => false }
 }
 
 #[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
 
     !is_none(opt)
@@ -333,11 +333,11 @@ fn each_mut(&mut self, f: &fn(&'self mut T) -> bool) {
 pub impl<T> Option<T> {
     /// Returns true if the option equals `none`
     #[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
     #[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
index 481a61f4ab71d54ec1265f6c564cc332cc511533..c1b6b26d86a3584402278553221ecf998664c49b 100644 (file)
@@ -223,8 +223,8 @@ pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
 }
 
 pub trait Ptr<T> {
-    pure fn is_null(&self) -> bool;
-    pure fn is_not_null(&self) -> bool;
+    pure fn is_null(&const self) -> bool;
+    pure fn is_not_null(&const self) -> bool;
     pure fn offset(&self, count: uint) -> Self;
 }
 
@@ -232,11 +232,11 @@ pub trait Ptr<T> {
 impl<T> Ptr<T> for *T {
     /// Returns true if the pointer is equal to the null pointer.
     #[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.
     #[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.
     #[inline(always)]
@@ -247,11 +247,11 @@ impl<T> Ptr<T> for *T {
 impl<T> Ptr<T> for *mut T {
     /// Returns true if the pointer is equal to the null pointer.
     #[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.
     #[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.
     #[inline(always)]
index e6a4a99df4419b2ed97f3edf46673e95acad0489..83df9b7c00fc3b0e3a4aad1a8050c8695ecfcf37 100644 (file)
@@ -499,7 +499,7 @@ fn visit_enter_enum_variant(&self, _variant: uint,
     }
 
     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 => {
                 if i != 0 {
                     self.writer.write_str(", ");
@@ -517,7 +517,7 @@ fn visit_leave_enum_variant(&self, _variant: uint,
                                 _disr_val: int,
                                 n_fields: uint,
                                 _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 => {
                 if n_fields > 0 {
                     self.writer.write_char(')');
index 0fd373b803fb5db012c8552b29a70b0be032b1af..40a6873ad67259bc178ec2731c4c8fc0df4f9f64 100644 (file)
@@ -127,7 +127,7 @@ struct TaskGroupData {
 
 // A taskgroup is 'dead' when nothing can cause it to fail; only members can.
 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
index 26532c1a4ff70668e00563ebf946bf8c59b92855..6b2f2bb6a7dbe2b8f54010bdef9f2f914336de8d 100644 (file)
@@ -50,11 +50,11 @@ impl<T> ReverseIter<(uint, &'self T)> for TrieMap<T> {
 impl<T> Container for TrieMap<T> {
     /// Return the number of elements in the map
     #[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
     #[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> {
@@ -178,11 +178,11 @@ impl ReverseIter<uint> for TrieSet {
 impl Container for TrieSet {
     /// Return the number of elements in the set
     #[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
     #[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 {
index 34d3c022dcac5f6d4205f840af850ef7abed94fd..dc220eaed1bee44bf2a7f3593da735e8c060416b 100644 (file)
@@ -118,6 +118,14 @@ pub fn reserve_at_least<T>(v: &mut ~[T], n: uint) {
     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.
  *
@@ -1691,11 +1699,11 @@ impl<T:Copy> Add<&'self [const T],~[T]> for ~[T] {
 impl<T> Container for &'self [const T] {
     /// Returns true if a vector contains no elements
     #[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
     #[inline]
-    pure fn len(&self) -> uint { len(*self) }
+    pure fn len(&const self) -> uint { len(*self) }
 }
 
 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`.
     #[inline]
     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] {
     pure fn each_val(&const self, f: &fn(A) -> bool) {
         let mut i = 0;
-        while i < self.len() {
+        while i < uniq_len(self) {
             if !f(copy self[i]) { break; }
             i += 1;
         }
index ddbac4085a7d7ed7b78ddc58037c4192f94b4e24..434d992f501979b9667443a176be7dcb8377f308 100644 (file)
@@ -142,7 +142,7 @@ fn fold_item(cx: @mut TestCtxt, &&i: @ast::item, fld: @fold::ast_fold)
           -> Option<@ast::item> {
     cx.path.push(i.ident);
     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) {
         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)
             };
             cx.testfns.push(test);
-            debug!("have %u test/bench functions", cx.testfns.len());
+            // debug!("have %u test/bench functions", cx.testfns.len());
           }
         }
     }
index a9aa5491631aa16c546b33d62598b952809746f0..92de7f3f5e6c7cfc9eea83aa27572b6951ea87e5 100644 (file)
@@ -79,6 +79,8 @@ fn warn_if_multiple_versions(e: @mut Env,
                              crate_cache: @mut ~[cache_entry]) {
     use core::either::*;
 
+    let crate_cache = &mut *crate_cache;
+
     if crate_cache.len() != 0u {
         let name = loader::crate_name_from_metas(
             *crate_cache[crate_cache.len() - 1].metas
index 0909a4437369daa14d085a34acf4b9755658fa81..ee52b48bc328b28ba60e3e4d6b9ca81af3d437ce 100644 (file)
@@ -96,6 +96,7 @@ pub fn iter_crate_data(cstore: @mut CStore,
 }
 
 pub fn add_used_crate_file(cstore: @mut CStore, lib: &Path) {
+    let cstore = &mut *cstore;
     if !vec::contains(cstore.used_crate_files, 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 {
     fail_unless!(*lib != ~"");
 
+    let cstore = &mut *cstore;
     if cstore.used_libraries.contains(&*lib) { return false; }
     cstore.used_libraries.push(/*bad*/ copy *lib);
     true
index 89700427d9674aadb9258883db410e8b7c03d45b..17bdf318e0708407793ba74a98b8a0a512a000e5 100644 (file)
@@ -271,6 +271,7 @@ fn check_for_conflicting_loans(@mut self, scope_id: ast::node_id) {
             None => return,
             Some(loans) => loans
         };
+        let new_loans: &mut ~[Loan] = new_loans;
 
         debug!("new_loans has length %?", new_loans.len());
 
index 2893c460fe26225f93008559b6419a48796e2c2d..e5f056619cc7ef6c09103c53657c69126191f08e 100644 (file)
@@ -129,9 +129,12 @@ fn req_loans_in_expr(ex: @ast::expr,
            ex.id, pprust::expr_to_str(ex, tcx.sess.intr()));
 
     // 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| {
-            self.guarantee_adjustments(ex, *adjustments);
+    {
+        let mut this = &mut *self;
+        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 {
-    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,
                              adjustment: &ty::AutoAdjustment) {
         debug!("guarantee_adjustments(expr=%s, adjustment=%?)",
@@ -348,7 +351,7 @@ fn guarantee_adjustments(@mut self,
     // out loans, which will be added to the `req_loan_map`.  This can
     // also entail "rooting" GC'd pointers, which means ensuring
     // dynamically that they are not freed.
-    fn guarantee_valid(@mut self,
+    fn guarantee_valid(&mut self,
                        cmt: cmt,
                        req_mutbl: ast::mutability,
                        scope_r: ty::Region)
@@ -465,7 +468,7 @@ fn guarantee_valid(@mut self,
     // has type `@mut{f:int}`, this check might fail because `&x.f`
     // reqires an immutable pointer, but `f` lives in (aliased)
     // mutable memory.
-    fn check_mutbl(@mut self,
+    fn check_mutbl(&mut self,
                    loan_kind: LoanKind,
                    cmt: cmt)
                 -> bckres<PreserveCondition> {
@@ -498,7 +501,7 @@ fn check_mutbl(@mut self,
         }
     }
 
-    fn add_loans(@mut self,
+    fn add_loans(&mut self,
                  cmt: cmt,
                  loan_kind: LoanKind,
                  scope_r: ty::Region,
@@ -563,7 +566,7 @@ fn add_loans(@mut self,
         }
     }
 
-    fn add_loans_to_scope_id(@mut self,
+    fn add_loans_to_scope_id(&mut self,
                              scope_id: ast::node_id,
                              +loans: ~[Loan]) {
         debug!("adding %u loans to scope_id %?: %s",
index 2afe9564b207dc432e599e24e2fb423edf792975..a8af6a18c0057e468ee5a8ac2407abd4faf893b3 100644 (file)
@@ -849,21 +849,24 @@ fn find_loop_scope(&self, opt_label: Option<ident>, id: node_id, sp: span)
                     _ => self.tcx.sess.span_bug(sp, ~"Label on break/loop \
                                                     doesn't refer to a loop")
                 },
-            None =>
+            None => {
                 // Vanilla 'break' or 'loop', so use the enclosing
                 // 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");
                 }
                 else {
                     // FIXME(#5275): this shouldn't have to be a method...
                     self.last_loop_scope()
                 }
+            }
         }
     }
 
     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 {
index 05a697194c8b54752ba7bc858ba5618beecc173e..6dcf1ba812863e7bdfa178969f6ed3f022acc004 100644 (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
     // with the ambient variance where the reference occurred and then
     // update the region-parameterization of D to reflect the result.
-    while cx.worklist.len() != 0 {
-        let c_id = cx.worklist.pop();
-        let c_variance = cx.region_paramd_items.get(&c_id);
-        debug!("popped %d from worklist", c_id);
-        match cx.dep_map.find(&c_id) {
-          None => {}
-          Some(deps) => {
-            for deps.each |dep| {
-                let v = add_variance(dep.ambient_variance, c_variance);
-                cx.add_rp(dep.id, v);
+    {
+        let cx = &mut *cx;
+        while cx.worklist.len() != 0 {
+            let c_id = cx.worklist.pop();
+            let c_variance = cx.region_paramd_items.get(&c_id);
+            debug!("popped %d from worklist", c_id);
+            match cx.dep_map.find(&c_id) {
+              None => {}
+              Some(deps) => {
+                for deps.each |dep| {
+                    let v = add_variance(dep.ambient_variance, c_variance);
+                    cx.add_rp(dep.id, v);
+                }
+              }
             }
-          }
         }
     }
 
index 8127f88f25022fa336258983d26b1dd357468eed..6561da0862ae5cefb8bb822b526b39c0fba66d17 100644 (file)
@@ -457,7 +457,7 @@ pub struct Module {
     kind: ModuleKind,
 
     children: @HashMap<ident,@mut NameBindings>,
-    imports: ~[@ImportDirective],
+    imports: @mut ~[@ImportDirective],
 
     // The anonymous children of this node. Anonymous children are pseudo-
     // modules that are implicitly created around items contained within
@@ -495,7 +495,7 @@ pub fn Module(parent_link: ParentLink,
         def_id: def_id,
         kind: kind,
         children: @HashMap(),
-        imports: ~[],
+        imports: @mut ~[],
         anonymous_children: @HashMap(),
         import_resolutions: @HashMap(),
         glob_count: 0,
@@ -505,7 +505,8 @@ pub fn Module(parent_link: ParentLink,
 
 pub impl Module {
     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 @@ fn def_for_namespace(&self, namespace: Namespace) -> Option<def> {
                             None => {
                                 match (*type_def).module_def {
                                     Some(module_def) => {
+                                        let module_def = &mut *module_def;
                                         module_def.def_id.map(|def_id|
                                             def_mod(*def_id))
                                     }
@@ -1978,10 +1980,11 @@ fn resolve_imports_for_module(@mut self, module: @mut Module) {
             return;
         }
 
-        let import_count = module.imports.len();
+        let imports = &mut *module.imports;
+        let import_count = imports.len();
         while module.resolved_import_count < 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) {
                 Failed => {
                     // We presumably emitted an error. Continue.
@@ -2288,7 +2291,8 @@ fn get_binding(import_resolution:
             (None, None) => { return Failed; }
             // If it's private, it's also unresolved.
             (Some(t), None) | (None, Some(t)) => {
-                match t.bindings.type_def {
+                let bindings = &mut *t.bindings;
+                match bindings.type_def {
                     Some(ref type_def) => {
                         if type_def.privacy == Private {
                             return Failed;
@@ -2296,7 +2300,7 @@ fn get_binding(import_resolution:
                     }
                     _ => ()
                 }
-                match t.bindings.value_def {
+                match bindings.value_def {
                     Some(ref value_def) => {
                         if value_def.privacy == Private {
                             return Failed;
@@ -2483,7 +2487,7 @@ fn resolve_glob_import(@mut self,
 
             debug!("(resolving glob import) writing module resolution \
                     %? into `%s`",
-                   is_none(&target_import_resolution.type_target),
+                   is_none(&mut target_import_resolution.type_target),
                    self.module_to_str(module_));
 
             // Here we merge two import resolutions.
@@ -2551,7 +2555,7 @@ fn resolve_glob_import(@mut self,
                    *self.session.str_of(ident),
                    self.module_to_str(containing_module),
                    self.module_to_str(module_),
-                   dest_import_resolution.privacy);
+                   copy dest_import_resolution.privacy);
 
             // Merge the child item into the import resolution.
             if (*name_bindings).defined_in_public_namespace(ValueNS) {
@@ -2864,7 +2868,8 @@ fn resolve_module_in_lexical_scope(@mut self,
             module_, name, TypeNS, DontSearchThroughModules);
         match resolve_result {
             Success(target) => {
-                match target.bindings.type_def {
+                let bindings = &mut *target.bindings;
+                match bindings.type_def {
                     Some(ref type_def) => {
                         match (*type_def).module_def {
                             None => {
@@ -3061,10 +3066,10 @@ fn resolve_name_in_module(@mut self,
 
     fn report_unresolved_imports(@mut self, module_: @mut Module) {
         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 {
-            self.session.span_err(module_.imports[index].span,
-                                  ~"unresolved import");
+            self.session.span_err(imports[index].span, ~"unresolved import");
         }
 
         // Descend into children and anonymous children.
@@ -4253,10 +4258,10 @@ struct in scope",
 
                             match bindings_list {
                                 Some(bindings_list)
-                                if !bindings_list.contains_key(&ident)
-                                    => {
-                                    let last_rib = self.value_ribs[
-                                            self.value_ribs.len() - 1];
+                                if !bindings_list.contains_key(&ident) => {
+                                    let this = &mut *self;
+                                    let last_rib = this.value_ribs[
+                                            this.value_ribs.len() - 1];
                                     last_rib.bindings.insert(ident,
                                                              dl_def(def));
                                     bindings_list.insert(ident, pat_id);
@@ -4275,8 +4280,9 @@ struct in scope",
                                   // Not bound in the same pattern: do nothing
                                 }
                                 None => {
-                                    let last_rib = self.value_ribs[
-                                            self.value_ribs.len() - 1];
+                                    let this = &mut *self;
+                                    let last_rib = this.value_ribs[
+                                            this.value_ribs.len() - 1];
                                     last_rib.bindings.insert(ident,
                                                              dl_def(def));
                                 }
@@ -4723,14 +4729,16 @@ fn resolve_item_by_identifier_in_lexical_scope(@mut self,
     }
 
     fn find_best_match_for_name(@mut self, name: &str) -> Option<~str> {
+        let this = &mut *self;
+
         let mut maybes: ~[~str] = ~[];
         let mut values: ~[uint] = ~[];
 
-        let mut j = self.value_ribs.len();
+        let mut j = this.value_ribs.len();
         while j != 0 {
             j -= 1;
-            for self.value_ribs[j].bindings.each_entry |e| {
-                vec::push(&mut maybes, copy *self.session.str_of(e.key));
+            for this.value_ribs[j].bindings.each_entry |e| {
+                vec::push(&mut maybes, copy *this.session.str_of(e.key));
                 vec::push(&mut values, uint::max_value);
             }
         }
@@ -4758,12 +4766,14 @@ fn find_best_match_for_name(@mut self, name: &str) -> Option<~str> {
     }
 
     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 {
           i -= 1;
-          match self.type_ribs[i].kind {
+          match this.type_ribs[i].kind {
             MethodRibKind(node_id, _) =>
-              for self.crate.node.module.items.each |item| {
+              for this.crate.node.module.items.each |item| {
                 if item.id == node_id {
                   match item.node {
                     item_struct(class_def, _) => {
@@ -4771,7 +4781,7 @@ fn name_exists_in_scope_struct(@mut self, name: &str) -> bool {
                         match field.node.kind {
                           unnamed_field => {},
                           named_field(ident, _, _) => {
-                              if str::eq_slice(*self.session.str_of(ident),
+                              if str::eq_slice(*this.session.str_of(ident),
                                                name) {
                                 return true
                               }
@@ -4877,8 +4887,9 @@ fn resolve_expr(@mut self, expr: @expr, visitor: ResolveVisitor) {
 
             expr_loop(_, Some(label)) => {
                 do self.with_label_rib {
+                    let this = &mut *self;
                     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);
 
                     visit_expr(expr, (), visitor);
@@ -5144,21 +5155,21 @@ fn enforce_default_binding_mode(@mut self,
     // be sure that there is only one main function
     //
     fn check_duplicate_main(@mut self) {
-        if self.attr_main_fn.is_none() {
-            if self.main_fns.len() >= 1u {
+        let this = &mut *self;
+        if this.attr_main_fn.is_none() {
+            if this.main_fns.len() >= 1u {
                 let mut i = 1u;
-                while i < self.main_fns.len() {
-                    let (_, dup_main_span) =
-                            option::unwrap(self.main_fns[i]);
-                    self.session.span_err(
+                while i < this.main_fns.len() {
+                    let (_, dup_main_span) = option::unwrap(this.main_fns[i]);
+                    this.session.span_err(
                         dup_main_span,
                         ~"multiple 'main' functions");
                     i += 1;
                 }
-                *self.session.main_fn = self.main_fns[0];
+                *this.session.main_fn = this.main_fns[0];
             }
         } else {
-            *self.session.main_fn = self.attr_main_fn;
+            *this.session.main_fn = this.attr_main_fn;
         }
     }
 
index a340e6472b8f785ae6eaee2917c2bf3996ebeb2d..4836ce062c9ca16e53bd9061d4a7109b705e0be6 100644 (file)
@@ -854,7 +854,9 @@ pub fn need_invoke(bcx: block) -> bool {
     // Walk the scopes to look for cleanups
     let mut cur = bcx;
     loop {
-        match *cur.kind {
+        let current = &mut *cur;
+        let kind = &mut *current.kind;
+        match *kind {
           block_scope(ref mut inf) => {
             for vec::each((*inf).cleanups) |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,
           None => return false
         }
index 1d31dc4fb8acf1e7ff990d993c1b03763e7dd941..96c124d60de9fca1ac33083348dbc6da1f6fa1e6 100644 (file)
@@ -50,7 +50,7 @@ pub fn count_insn(cx: block, category: &str) {
     if cx.ccx().sess.count_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.
 
index 40394391f1adb337955dbd0428b428863d3290e3..616a5f994992bb16fe384ca7039610312221dd39 100644 (file)
@@ -186,12 +186,14 @@ pub fn trans_log(log_ex: @ast::expr,
        return expr::trans_into(bcx, lvl, expr::Ignore);
     }
 
-    let modpath = vec::append(
-        ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name.to_owned()))],
-        bcx.fcx.path.filtered(|e|
-            match *e { path_mod(_) => true, _ => false }
-        ));
-    let modname = path_str(ccx.sess, modpath);
+    let (modpath, modname) = {
+        let path = &mut bcx.fcx.path;
+        let modpath = vec::append(
+            ~[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);
+        (modpath, modname)
+    };
 
     let global = if ccx.module_data.contains_key(&modname) {
         ccx.module_data.get(&modname)
index 4a1837fd9d0e760024f365a78539c620000c5af8..e4b9d01c50982d4f0b25e6aa2bc0b5426532c062 100644 (file)
@@ -845,7 +845,8 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata<SubProgramMetadata> {
     let dbg_cx = (/*bad*/copy cx.dbg_cx).get();
 
     debug!("~~");
-    debug!("%?", fcx.id);
+
+    let fcx = &mut *fcx;
 
     let sp = fcx.span.get();
     debug!("%s", cx.sess.codemap.span_to_str(sp));
index 8302f46120e6605a0711bff0fbd0be817c3433dd..284a5eac39db84d8589f8ebbb459d7e413b08a67 100644 (file)
@@ -234,18 +234,21 @@ pub fn lazily_emit_simplified_tydesc_glue(ccx: @CrateContext,
     if simpl != ti.ty {
         let simpl_ti = get_tydesc(ccx, simpl);
         lazily_emit_tydesc_glue(ccx, field, simpl_ti);
-        if field == abi::tydesc_field_take_glue {
-            ti.take_glue =
-                simpl_ti.take_glue.map(|v| cast_glue(ccx, ti, *v));
-        } else if field == abi::tydesc_field_drop_glue {
-            ti.drop_glue =
-                simpl_ti.drop_glue.map(|v| cast_glue(ccx, ti, *v));
-        } else if field == abi::tydesc_field_free_glue {
-            ti.free_glue =
-                simpl_ti.free_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));
+        {
+            let simpl_ti = &mut *simpl_ti;
+            if field == abi::tydesc_field_take_glue {
+                ti.take_glue =
+                    simpl_ti.take_glue.map(|v| cast_glue(ccx, ti, *v));
+            } else if field == abi::tydesc_field_drop_glue {
+                ti.drop_glue =
+                    simpl_ti.drop_glue.map(|v| cast_glue(ccx, ti, *v));
+            } else if field == abi::tydesc_field_free_glue {
+                ti.free_glue =
+                    simpl_ti.free_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;
     }
index 692dc392173b3fdd6b0d478289a42a11378e4daa..593919d108b875acea38189d23e84eb52b9fcd60 100644 (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) {
     // 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_ {
             type_needs_inner(cx, use_, ty, @Nil);
             return;
index fcebcaf501ee16d1f262c3e0e0e2160467b118fa..599fa28e242246630e9de8e29cce21eeabdd5aa0 100644 (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`.
 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 {
         debug!("type_requires(%s, %s)?",
                ::util::ppaux::ty_to_str(cx, r_ty),
@@ -2202,7 +2202,7 @@ fn type_requires(cx: ctxt, seen: @mut ~[def_id],
         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 {
         debug!("subtypes_require(%s, %s)?",
                ::util::ppaux::ty_to_str(cx, r_ty),
index f3fff416c5591219f447212f56161ac88a4cb8a9..752d9107d822aa6722eb0fd1ec4d656b21a5b163 100644 (file)
@@ -1696,7 +1696,7 @@ fn check_expr_fn(fcx: @mut FnCtxt,
         fcx.write_ty(expr.id, fty);
 
         let inherited_purity =
-            ty::determine_inherited_purity(fcx.purity, purity,
+            ty::determine_inherited_purity(copy fcx.purity, purity,
                                            fn_ty.sigil);
 
         // We inherit the same self info as the enclosing scope,
index 48a37c9e72ad0c7e75fda613b13f39e1ee26f5c8..6e86bbca0d1c3618edcba2e482f9881617597e66 100644 (file)
@@ -10,6 +10,7 @@
 
 use core::prelude::*;
 
+use middle::resolve::Impl;
 use middle::ty::{param_ty, substs};
 use middle::ty;
 use middle::typeck::check::{FnCtxt, impl_self_ty};
@@ -240,6 +241,7 @@ pub fn lookup_vtable(vcx: &VtableContext,
                     // Nothing found. Continue.
                 }
                 Some(implementations) => {
+                    let implementations: &mut ~[@Impl] = implementations;
                     // implementations is the list of all impls in scope for
                     // trait_ty. (Usually, there's just one.)
                     for uint::range(0, implementations.len()) |i| {
index 3d2ed867de1f2c08d92d0ac6e2dc949a447a41b1..699b8ad74e4cec313f3082b017ff2210dfc586d0 100644 (file)
@@ -466,14 +466,13 @@ fn add_impl_for_trait(&self,
         }
     }
 
-    fn iter_impls_of_trait(&self, trait_def_id: def_id,
-                           f: &fn(@Impl)) {
-
+    fn iter_impls_of_trait(&self, trait_def_id: def_id, f: &fn(@Impl)) {
         let coherence_info = &mut self.crate_context.coherence_info;
         let extension_methods = &coherence_info.extension_methods;
 
         match extension_methods.find(&trait_def_id) {
             Some(impls) => {
+                let impls: &mut ~[@Impl] = impls;
                 for uint::range(0, impls.len()) |i| {
                     f(impls[i]);
                 }
index 03649faff63d6119acef735077ce527734d9bd55..11da6b60328ce4c3eed48bf421d61dd0331a0eb2 100644 (file)
@@ -559,15 +559,16 @@ fn in_snapshot(@mut self) -> bool {
     }
 
     fn start_snapshot(@mut self) -> Snapshot {
+        let this = &mut *self;
         Snapshot {
             ty_var_bindings_len:
-                self.ty_var_bindings.bindings.len(),
+                this.ty_var_bindings.bindings.len(),
             int_var_bindings_len:
-                self.int_var_bindings.bindings.len(),
+                this.int_var_bindings.bindings.len(),
             float_var_bindings_len:
-                self.float_var_bindings.bindings.len(),
+                this.float_var_bindings.bindings.len(),
             region_vars_snapshot:
-                self.region_vars.start_snapshot(),
+                this.region_vars.start_snapshot(),
         }
     }
 
index 9cf2d145eacb46730694853a922e75f94b339413..430a5eab64e0b343ca9244af44c768268e6c6920 100644 (file)
@@ -700,8 +700,8 @@ impl cmp::Eq for BitvSet {
 }
 
 impl Container for BitvSet {
-    pure fn len(&self) -> uint { self.size }
-    pure fn is_empty(&self) -> bool { self.size == 0 }
+    pure fn len(&const self) -> uint { self.size }
+    pure fn is_empty(&const self) -> bool { self.size == 0 }
 }
 
 impl Mutable for BitvSet {
index 90269e28b8a42a7d01caadacfdc3cd8d49e884dc..86304f48e7929a1aee8a7d248789bf2472c507b6 100644 (file)
@@ -23,10 +23,10 @@ pub struct Deque<T> {
 
 impl<T> Container for Deque<T> {
     /// 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
-    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> {
index e2e09f1d6750a273015ff80b6de62b344103a022..c5515c63b29a2048053a344a157d4275e1020721 100644 (file)
@@ -569,12 +569,12 @@ pub struct PipeByteChan {
 
     impl BytePort for PipeBytePort {
         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, ~[]);
                 self.buf = bytes.slice(count, bytes.len());
                 bytes.truncate(count);
                 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, ~[]);
                 fail_unless!(count > bytes.len());
                 match self.try_recv(count - bytes.len()) {
@@ -584,7 +584,7 @@ fn try_recv(&self, count: uint) -> Option<~[u8]> {
                     }
                     None => return None
                 }
-            } else if self.buf.is_empty() {
+            } else if vec::uniq_len(&const self.buf) == 0 {
                 match self.port.try_recv() {
                     Some(buf) => {
                         fail_unless!(!buf.is_empty());
index e52d08c40fe3353b6f5aa11fe5b14906f05a35a8..f2f37604fb5645c79a9d585d7dfae5e57d9b5e3b 100644 (file)
@@ -757,12 +757,16 @@ pub fn Decoder(json: Json) -> Decoder {
 
 priv impl Decoder/&self {
     fn peek(&self) -> &'self Json {
-        if self.stack.len() == 0 { self.stack.push(&self.json); }
-        self.stack[self.stack.len() - 1]
+        if vec::uniq_len(&const self.stack) == 0 {
+            self.stack.push(&self.json);
+        }
+        self.stack[vec::uniq_len(&const self.stack) - 1]
     }
 
     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()
     }
 }
index 54fbae956ce5c01f893e1d726c021363bac71da6..a93e94e0d04309967dca528bde275c3235e94899 100644 (file)
@@ -879,7 +879,8 @@ fn read(&self, buf: &mut [u8], len: uint) -> uint {
 
           // If possible, copy up to `len` bytes from the internal
           // `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;
             if nbuffered > 0 {
                 unsafe {
@@ -931,7 +932,7 @@ fn read(&self, buf: &mut [u8], len: uint) -> uint {
     }
     fn read_byte(&self) -> int {
         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];
             self.data.buf_off += 1;
             return c as int
index a4b00e4dd04284b6abe81f95c02f8896a835193b..0a07a24e8ee5c92d608b1b41f0e0ed9f88eb2e43 100644 (file)
@@ -101,7 +101,7 @@ enum 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] {
               None => {
                 debug!("search_tbl: none, comp %u, hash %u, idx %u",
@@ -121,7 +121,7 @@ enum SearchResult<K, V> {
         }
 
         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 mut new_chains = chains(n_new_chains);
             for self.each_entry |entry| {
@@ -137,7 +137,7 @@ pub impl<K:Eq + IterBytes + Hash,V> HashMap_<K, V> {
         pure fn each_entry(&self, blk: &fn(@Entry<K,V>) -> bool) {
             // n.b. we can't use vec::iter() here because self.chains
             // 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 {
                 let mut chain = self.chains[i];
                 loop {
@@ -161,8 +161,8 @@ fn clear(@self) {
     }
 
     impl<K:Eq + IterBytes + Hash,V> Container for HashMap_<K, V> {
-        pure fn len(&self) -> uint { self.count }
-        pure fn is_empty(&self) -> bool { self.count == 0 }
+        pure fn len(&const self) -> uint { self.count }
+        pure fn is_empty(&const self) -> bool { self.count == 0 }
     }
 
     pub impl<K:Eq + IterBytes + Hash,V> HashMap_<K, V> {
@@ -179,7 +179,7 @@ fn insert(@self, k: K, v: V) -> bool {
             match self.search_tbl(&k, hash) {
               NotFound => {
                 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];
                 self.chains[idx] = Some(@Entry {
                     hash: hash,
@@ -188,7 +188,7 @@ fn insert(@self, k: K, v: V) -> bool {
                     next: old_chain});
 
                 // 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 {
                     num: (self.count + 1u) as int,
                     den: nchains as int,
@@ -271,7 +271,7 @@ fn update_with_key(@self, key: K, newval: V, ff: &fn(K, V, V) -> V)
             match self.search_tbl(&key, hash) {
               NotFound => {
                 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];
                 self.chains[idx] = Some(@Entry {
                     hash: hash,
@@ -280,7 +280,7 @@ fn update_with_key(@self, key: K, newval: V, ff: &fn(K, V, V) -> V)
                     next: old_chain});
 
                 // 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 {
                     num: (self.count + 1u) as int,
                     den: nchains as int,
index b9b5075c4349803c7f54178e88b5b012a3358e02..a5a291c5b18f52d3a85395ff22b42268863370a4 100644 (file)
@@ -37,10 +37,10 @@ impl<T:Ord> BaseIter<T> for PriorityQueue<T> {
 
 impl<T:Ord> Container for PriorityQueue<T> {
     /// 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
-    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> {
index b1ef0233d97e2e4afe7bd3e9c3dde0047c4e6573..f7e31bc7df758c746b1952359293aa817b2a2a27 100644 (file)
@@ -91,7 +91,7 @@ fn add_input(st: &mut Sha1State, msg: &[const u8]) {
     }
     fn process_msg_block(st: &mut Sha1State) {
         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 w = st.work_buf;
 
index c63ef9b72584bd3c5987d28e0939cc8f9c6267a5..dc2688a20e73d0dd4ba7b524fc70bc2457ff497b 100644 (file)
@@ -50,18 +50,19 @@ impl<V> ReverseIter<(uint, &'self V)> for SmallIntMap<V> {
 
 impl<V> Container for SmallIntMap<V> {
     /// Return the number of elements in the map
-    pure fn len(&self) -> uint {
+    pure fn len(&const self) -> uint {
         let mut sz = 0;
-        for self.v.each |item| {
-            if item.is_some() {
-                sz += 1;
+        for uint::range(0, vec::uniq_len(&const self.v)) |i| {
+            match self.v[i] {
+                Some(_) => sz += 1,
+                None => {}
             }
         }
         sz
     }
 
     /// 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> {
index 43c68196eb826840422719f094d033e1ec1c1d48..40be303a147825c1327055512c3eac8c39cfd36b 100644 (file)
@@ -68,9 +68,14 @@ fn part<T>(arr: &mut [T], left: uint,
     let mut storage_index: uint = left;
     let mut i: uint = left;
     while i < right {
-        if compare_func(&arr[i], &arr[right]) {
-            arr[i] <-> arr[storage_index];
-            storage_index += 1;
+        // XXX: Unsafe because borrow check doesn't handle this right
+        unsafe {
+            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;
     }
@@ -451,7 +456,10 @@ fn merge_lo(&mut self, array: &mut [T], base1: uint, len1: uint,
                 base2: uint, len2: uint) {
         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 c2 = base2;
@@ -554,7 +562,10 @@ fn merge_hi(&mut self, array: &mut [T], base1: uint, len1: uint,
                 base2: uint, len2: uint) {
         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 c2 = len2 - 1;
@@ -702,7 +713,11 @@ fn copy_vec<T:Copy>(dest: &mut [T], s1: uint,
                     from: &[const T], s2: uint, len: uint) {
     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| {
         dest[s1+i] = *v;
     }
@@ -721,7 +736,7 @@ pub fn check_sort(v1: &mut [int], v2: &mut [int]) {
         quick_sort3::<int>(v1);
         let mut i = 0;
         while i < len {
-            debug!(v2[i]);
+            // debug!(v2[i]);
             fail_unless!((v2[i] == v1[i]));
             i += 1;
         }
@@ -768,7 +783,7 @@ pub fn check_sort(v1: &mut [int], v2: &mut [int]) {
         quick_sort::<int>(v1, leual);
         let mut i = 0u;
         while i < len {
-            debug!(v2[i]);
+            // debug!(v2[i]);
             fail_unless!((v2[i] == v1[i]));
             i += 1;
         }
@@ -919,7 +934,7 @@ fn check_sort(v1: &mut [int], v2: &mut [int]) {
         tim_sort::<int>(v1);
         let mut i = 0u;
         while i < len {
-            debug!(v2[i]);
+            // debug!(v2[i]);
             fail_unless!((v2[i] == v1[i]));
             i += 1u;
         }
index 63cf4c998df7f212e21f1c5133441da816510457..fcc60c8d978195879857e34371d32656a2551168 100644 (file)
@@ -358,7 +358,11 @@ fn write_pretty(out: @io::Writer,
 
 fn print_failures(st: @ConsoleTestState) {
     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);
     for vec::each(failures) |name| {
         st.out.write_line(fmt!("    %s", name.to_str()));
index 7192da7b88e1f6f383261495bb10539420cebecc..f4d58568ae7d626d10746cfbd8cd594045377598 100644 (file)
@@ -106,10 +106,10 @@ impl<'self, K: TotalOrd, V>
 
 impl<K: TotalOrd, V> Container for TreeMap<K, V> {
     /// 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
-    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> {
@@ -276,11 +276,11 @@ impl<T: Ord + TotalOrd> Ord for TreeSet<T> {
 impl<T: TotalOrd> Container for TreeSet<T> {
     /// Return the number of elements in the set
     #[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
     #[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> {
index 97719a140a6a5f56881196603a8012d20aea0894..538f0de8c842b49ec9bb9a76bf0bde13f1e63fbc 100644 (file)
@@ -252,8 +252,8 @@ pub impl FileMap {
     // about what ends a line between this file and parse.rs
     fn next_line(&self, +pos: BytePos) {
         // the new charpos must be > the last one (or it's the first one).
-        fail_unless!((self.lines.len() == 0)
-                || (self.lines[self.lines.len() - 1] < pos));
+        let lines = &mut *self.lines;
+        fail_unless!((lines.len() == 0) || (lines[lines.len() - 1] < pos));
         self.lines.push(pos);
     }
 
@@ -302,11 +302,12 @@ fn new_filemap_w_substr(
         +substr: FileSubstr,
         src: @~str
     ) -> @FileMap {
-        let start_pos = if self.files.len() == 0 {
+        let files = &mut *self.files;
+        let start_pos = if files.len() == 0 {
             0
         } else {
-            let last_start = self.files.last().start_pos.to_uint();
-            let last_len = self.files.last().src.len();
+            let last_start = files.last().start_pos.to_uint();
+            let last_len = files.last().src.len();
             last_start + last_len
         };
 
@@ -364,7 +365,8 @@ pub fn adjust_span(&self, sp: span) -> span {
     }
 
     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";
         }
 
@@ -409,7 +411,8 @@ pub fn get_filemap(&self, filename: ~str) -> @FileMap {
 priv impl CodeMap {
 
     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 b = len;
         while b - a > 1u {
@@ -433,10 +436,11 @@ fn lookup_line(&self, pos: BytePos) -> FileMapAndLine
         let idx = self.lookup_filemap_idx(pos);
         let f = self.files[idx];
         let mut a = 0u;
-        let mut b = f.lines.len();
+        let lines = &*f.lines;
+        let mut b = lines.len();
         while b - a > 1u {
             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};
     }
index 54b123bff2ff9c631240cf2b1d91e1e8ee9656f0..76ab21f403b3f64a302f274014bed5b331be406f 100644 (file)
@@ -226,7 +226,7 @@ fn create_eq_method(cx: @ext_ctxt,
         attrs: ~[],
         generics: ast_util::empty_generics(),
         self_ty: self_ty,
-        purity: pure_fn,
+        purity: impure_fn,
         decl: fn_decl,
         body: body_block,
         id: cx.next_id(),
@@ -405,7 +405,7 @@ fn create_iter_bytes_method(cx: @ext_ctxt,
         attrs: ~[],
         generics: ast_util::empty_generics(),
         self_ty: self_ty,
-        purity: pure_fn,
+        purity: impure_fn,
         decl: fn_decl,
         body: body_block,
         id: cx.next_id(),
index 30e7e832db197fd129e23dd6363aa844ccd25761..29c9e86ec626a25e4421666913142592e24ae66c 100644 (file)
@@ -41,7 +41,8 @@ impl proto::visitor<(), (), ()> for @ext_ctxt {
     fn visit_proto(&self, _proto: protocol, _states: &[()]) { }
 
     fn visit_state(&self, state: state, _m: &[()]) {
-        if state.messages.len() == 0 {
+        let messages = &*state.messages;
+        if messages.len() == 0 {
             self.span_warn(
                 state.span, // use a real span!
                 fmt!("state %s contains no messages, \
index 15ba7f95538fa478da763b01b6e04bf0175b7524..c6fdf4d9c1b21426eacce1a4334f5dfec318e94c 100644 (file)
@@ -91,7 +91,7 @@ pub fn analyze(proto: protocol, _cx: @ext_ctxt) {
         let states = str::connect(self_live.map(|s| copy s.name), ~" ");
 
         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
         //cx.span_warn(empty_span(),
@@ -103,7 +103,7 @@ pub fn analyze(proto: protocol, _cx: @ext_ctxt) {
         proto.bounded = Some(false);
     }
     else {
-        debug!("protocol %s is bounded. yay!", proto.name);
+        debug!("protocol %s is bounded. yay!", copy proto.name);
         proto.bounded = Some(true);
     }
 }
index c9680ac02c90ee54287ee5ce782c8f8aea452fa6..a47b39a45c86402622307f900a4ddd07cfd2b41d 100644 (file)
@@ -156,7 +156,10 @@ fn filename(&mut self) -> ~str {
         ~"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 {
         for self.states.each |s| {
@@ -180,9 +183,10 @@ fn add_state_poly(@mut self,
                       +generics: ast::Generics)
                    -> state {
         let messages = @mut ~[];
+        let states = &*self.states;
 
         let state = @state_ {
-            id: self.states.len(),
+            id: states.len(),
             name: name,
             ident: ident,
             span: self.span,
index 908fbd44825106ab58bbbe65bb3ce620db70da33..0196ee6d1842699dab8d5af68bf35b8f96798c50 100644 (file)
@@ -106,8 +106,9 @@ pub fn new_tt_reader(sp_diag: @span_handler,
 }
 
 
-pure fn lookup_cur_matched_by_matched(r: @mut TtReader,
-                                      start: @named_match) -> @named_match {
+pure fn lookup_cur_matched_by_matched(r: &mut TtReader,
+                                      start: @named_match)
+                                   -> @named_match {
     pure fn red(+ad: @named_match, idx: &uint) -> @named_match {
         match *ad {
           matched_nonterminal(_) => {
@@ -117,18 +118,20 @@ pub fn new_tt_reader(sp_diag: @span_handler,
           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))
 }
 enum lis {
     lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
 }
 
-fn lockstep_iter_size(t: token_tree, r: @mut TtReader) -> lis {
-    fn lis_merge(lhs: lis, rhs: lis, 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 {
         match lhs {
           lis_unconstrained => copy rhs,
           lis_contradiction(_) => copy lhs,
@@ -148,8 +151,10 @@ fn lis_merge(lhs: lis, rhs: lis, r: @mut TtReader) -> lis {
     }
     match t {
       tt_delim(ref tts) | tt_seq(_, ref tts, _, _) => {
-        vec::foldl(lis_unconstrained, (*tts), |lis, tt|
-            lis_merge(lis, lockstep_iter_size(*tt, r), r))
+        vec::foldl(lis_unconstrained, (*tts), |lis, tt| {
+            let lis2 = lockstep_iter_size(*tt, r);
+            lis_merge(lis, lis2, r)
+        })
       }
       tt_tok(*) => lis_unconstrained,
       tt_nonterminal(_, name) => match *lookup_cur_matched(r, name) {
@@ -160,12 +165,20 @@ fn lis_merge(lhs: lis, rhs: lis, 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 {
         tok: copy r.cur_tok,
         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? */
         if ! r.cur.dotdotdoted
             || { *r.repeat_idx.last() == *r.repeat_len.last() - 1 } {
index 09ffd79c246e3ae54bc99c330ecca9075ae8a61a..90f51fe9b65af47c3983aeacb69153221900b5b7 100644 (file)
@@ -811,7 +811,7 @@ fn setup(teststr: ~str) -> Env {
             sp:span {lo:BytePos(21),hi:BytePos(23),expn_info: None}};
         check_equal (tok1,tok2);
         // 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:
         let tok3 = string_reader.next_token();
         let tok4 = TokenAndSpan{
@@ -819,7 +819,7 @@ fn setup(teststr: ~str) -> Env {
             sp:span {lo:BytePos(24),hi:BytePos(28),expn_info: None}};
         check_equal (tok3,tok4);
         // 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
index 2ea304a0a9bc51ed7abca63a8b129f00fe18bb22..8a883b73a64a3d5c7c6376d5a602620eeff5ed64 100644 (file)
@@ -412,7 +412,8 @@ fn parse_onceness(self: &Parser) -> Onceness {
 
     fn parse_purity(&self) -> purity {
         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") {
             return unsafe_fn;
         } else {
@@ -2668,7 +2669,8 @@ fn mk_ty_path(&self, i: ident) -> @Ty {
 
     fn parse_optional_purity(&self) -> ast::purity {
         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") {
             ast::unsafe_fn
         } else {
@@ -3418,7 +3420,8 @@ fn eval_src_mod(&self, id: ast::ident,
 
         let prefix = Path(self.sess.cm.span_to_filename(*self.span));
         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 file_path = match ::attr::first_attr_value_str_by_name(
             outer_attrs, ~"path") {
@@ -3505,7 +3508,8 @@ fn parse_fn_purity(&self) -> purity {
         if self.eat_keyword(&~"fn") { impure_fn }
         else if self.eat_keyword(&~"pure") {
             self.expect_keyword(&~"fn");
-            pure_fn
+            // NB: We parse this as impure for bootstrapping purposes.
+            impure_fn
         } else if self.eat_keyword(&~"unsafe") {
             self.expect_keyword(&~"fn");
             unsafe_fn
@@ -3894,8 +3898,9 @@ fn parse_item_or_view_item(
                                           maybe_append(attrs, extra_attrs)));
         } else if items_allowed && self.eat_keyword(&~"pure") {
             // PURE FUNCTION ITEM
+            // NB: We parse this as impure for bootstrapping purposes.
             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_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
index 7f46e4522999868e1cb979a7b35bb86b5d2aa1aa..492ecdb3f4de5037a173e6444cc396d73b63684c 100644 (file)
@@ -452,9 +452,10 @@ fn indent(&mut self, amount: int) {
         self.pending_indentation += amount;
     }
     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 {
-            self.print_stack[n - 1u]
+            print_stack[n - 1u]
         } else {
             print_stack_elt {
                 offset: 0,
@@ -496,7 +497,8 @@ fn print(&mut self, x: token, L: int) {
           }
           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();
           }
           BREAK(b) => {
index 5aae5570dbfee8d9f813588e16044b5fa9e1c71e..71f3de174140c4f023ec16a4343b38731f4e392a 100644 (file)
@@ -279,9 +279,10 @@ pub fn is_bol(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; }
-    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); } }
index 7a5708049e9f400bc63a84672baf7ccde58e0f3a..47f49ebadaabfff0ce399f7eb60bb644b2aefcbd 100644 (file)
@@ -41,14 +41,18 @@ fn intern(&self, val: T) -> uint {
             None => (),
         }
 
-        let new_idx = self.vect.len();
+        let vect = &*self.vect;
+        let new_idx = vect.len();
         self.map.insert(val, new_idx);
         self.vect.push(val);
         new_idx
     }
 
     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
         self.vect.push(val);
         new_idx
@@ -59,7 +63,7 @@ fn gensym(&self, val: T) -> uint {
     // 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] }
 
-    fn len(&self) -> uint { self.vect.len() }
+    fn len(&self) -> uint { let vect = &*self.vect; vect.len() }
 }
 
 #[test]
index fe5f474a5f252e0f3b8ce03c82c41b4da9b3edb0..bd1001bf38cb704c0c2d9719ccf29da8071b4ded 100644 (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 match_const_box_and_do_bad_things(v: &const @const Option<int>) {
diff --git a/src/test/compile-fail/borrowck-pure-scope-in-call.rs b/src/test/compile-fail/borrowck-pure-scope-in-call.rs
deleted file mode 100644 (file)
index 7ff1373..0000000
+++ /dev/null
@@ -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() {
-}
diff --git a/src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs b/src/test/compile-fail/nontrivial-fn-arg-pattern-in-pure-fn.rs
deleted file mode 100644 (file)
index c60eec6..0000000
+++ /dev/null
@@ -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() {}
-
diff --git a/src/test/compile-fail/pure-higher-order.rs b/src/test/compile-fail/pure-higher-order.rs
deleted file mode 100644 (file)
index 6d262bc..0000000
+++ /dev/null
@@ -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() {
-}
diff --git a/src/test/compile-fail/pure-loop-body.rs b/src/test/compile-fail/pure-loop-body.rs
deleted file mode 100644 (file)
index 43a5498..0000000
+++ /dev/null
@@ -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() {}
diff --git a/src/test/compile-fail/pure-modifies-aliased.rs b/src/test/compile-fail/pure-modifies-aliased.rs
deleted file mode 100644 (file)
index 4bd56c6..0000000
+++ /dev/null
@@ -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() {
-}
diff --git a/src/test/compile-fail/pure-subtyping.rs b/src/test/compile-fail/pure-subtyping.rs
deleted file mode 100644 (file)
index 2744afb..0000000
+++ /dev/null
@@ -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() {
-}
diff --git a/src/test/compile-fail/purity-infer-fail.rs b/src/test/compile-fail/purity-infer-fail.rs
deleted file mode 100644 (file)
index 3e52965..0000000
+++ /dev/null
@@ -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
-}
index 6931e680e08f23fe991427e7ab103bfd6d5e025c..6676cde3c96a6055726539c948798ed5ea3e80e0 100644 (file)
@@ -9,15 +9,15 @@
 // except according to those terms.
 
 trait Mumbo {
-    pure fn jumbo(&self, x: @uint) -> uint;
+    fn jumbo(&self, x: @uint) -> uint;
     fn jambo(&self, x: @const uint) -> uint;
     fn jbmbo(&self) -> @uint;
 }
 
 impl Mumbo for uint {
     // Cannot have a larger effect than the trait:
-    fn jumbo(&self, x: @uint) { *self + *x; }
-    //~^ ERROR expected pure fn but found impure fn
+    unsafe fn jumbo(&self, x: @uint) { *self + *x; }
+    //~^ ERROR expected impure fn but found unsafe fn
 
     // Cannot accept a narrower range of parameters:
     fn jambo(&self, x: @uint) { *self + *x; }
index ea41a50e382bbd3ba73a28f988013305e9d32528..39fe34bfe528658271be116ba3922394e7b2c278 100644 (file)
@@ -39,7 +39,6 @@ pub fn main() {
     (&"test").test_imm();
 
     // XXX: Other types of mutable vecs don't currently exist
-    (@mut [1]).test_imm();
 
     ([1]).test_const();
     (~[1]).test_const();
@@ -50,8 +49,6 @@ pub fn main() {
     (@"test").test_const();
     (&"test").test_const();
 
-    (@mut [1]).test_const();
-
     // 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
     // of confusion
index 0c285258f7522e78192fc6f5acccf76bb2abacbc..a0a4ea19964f7d7eab5adb17f818074cead14e3d 100644 (file)
@@ -62,8 +62,8 @@ impl<T> BaseIter<(int, &'self T)> for cat<T> {
 }
 
 impl<T> Container for cat<T> {
-    pure fn len(&self) -> uint { self.meows as uint }
-    pure fn is_empty(&self) -> bool { self.meows == 0 }
+    pure fn len(&const self) -> uint { self.meows as uint }
+    pure fn is_empty(&const self) -> bool { self.meows == 0 }
 }
 
 impl<T> Mutable for cat<T> {
index 37770f4d59ba5009863599986d32348ebf22c345..905046756f6ee9126fe7729d38f5f256067fd16b 100644 (file)
@@ -10,8 +10,4 @@ fn negate_imm(y: &int) -> int {
     negate(y)
 }
 
-fn negate_const(y: &const int) -> int {
-    negate(y)
-}
-
 pub fn main() {}
index 8fab061b4de3021c624bea5a9f9a4f82bd0777f3..54d9758aa214546a583c780bd72f772b29284437 100644 (file)
@@ -3,7 +3,7 @@ struct 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 {
index ba7d78ba04f11691098772531302e75dc0cd5cd5..a18b4a2b0c6919148258404712b0a182a2c13706 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-test
+
 pure fn sum(x: &[int]) -> int {
     let mut sum = 0;
     for x.each |y| { sum += *y; }
index 7ab63f43769cf69d91a0864b814835e1585d538b..bf86472d900d78ae6975c2ecdb54fb91603cf855 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-test
+
 fn foo(v: &[const uint]) -> ~[uint] {
     v.to_vec()
 }
index 3f94600ea17d36a13af947e9f01b2b85958ac1c8..2e70e900389719851cee7d4727f910da84a0671b 100644 (file)
@@ -16,6 +16,6 @@ struct Refs { refs: ~[int], n: int }
 
 pub fn main() {
     let e = @mut Refs{refs: ~[], n: 0};
-    let f: @fn() = || error!(e.n);
+    let f: @fn() = || error!(copy e.n);
     e.refs += ~[1];
 }