about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Holk <eric.holk@gmail.com>2012-06-13 16:14:01 -0700
committerEric Holk <eric.holk@gmail.com>2012-06-21 16:11:11 -0700
commit0e5cfd9f339c78384ef3fbcb4d230fa0bb363d54 (patch)
treef71eefbe17ea2b94ab475a0bc63f690a1ea339e4
parentf8fa0a243788e6b1028d254958cd19c6f10034fa (diff)
downloadrust-0e5cfd9f339c78384ef3fbcb4d230fa0bb363d54.tar.gz
rust-0e5cfd9f339c78384ef3fbcb4d230fa0bb363d54.zip
Move vector addition out of trans and into libcore.
-rw-r--r--src/libcore/dvec.rs6
-rw-r--r--src/libcore/ptr.rs9
-rw-r--r--src/libcore/str.rs5
-rw-r--r--src/libcore/vec.rs105
-rw-r--r--src/libstd/deque.rs4
-rw-r--r--src/libstd/rope.rs2
-rw-r--r--src/libsyntax/ast_util.rs17
-rw-r--r--src/libsyntax/parse/common.rs4
-rw-r--r--src/rustc/middle/astencode.rs199
-rw-r--r--src/rustc/middle/trans/base.rs5
-rw-r--r--src/rustc/middle/trans/tvec.rs2
-rw-r--r--src/rustc/middle/tstate/annotate.rs8
-rw-r--r--src/rustc/middle/typeck/check.rs16
-rw-r--r--src/rustc/middle/typeck/check/method.rs13
-rw-r--r--src/test/bench/core-vec-append.rs8
-rw-r--r--src/test/run-fail/zip-different-lengths.rs4
-rw-r--r--src/test/run-pass/import-glob-crate.rs2
-rw-r--r--src/test/run-pass/vec-push.rs6
-rw-r--r--src/test/run-pass/zip-same-length.rs4
19 files changed, 172 insertions, 247 deletions
diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs
index 3ea8de957a0..ef368fe7a8b 100644
--- a/src/libcore/dvec.rs
+++ b/src/libcore/dvec.rs
@@ -137,7 +137,9 @@ impl extensions<A:copy> for dvec<A> {
     #[doc = "Append a single item to the end of the list"]
     fn push(t: A) {
         self.swap { |v|
-            let mut v <- v; v += [t]; v // more efficient than v + [t]
+            let mut v <- v;
+            vec::push(v, t);
+            v
         }
     }
 
@@ -170,7 +172,7 @@ impl extensions<A:copy> for dvec<A> {
             vec::reserve(v, new_len);
             let mut i = from_idx;
             while i < to_idx {
-                v += [ts[i]];
+                vec::push(v, ts[i]);
                 i += 1u;
             }
             v
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 2ce5550d951..2a89abc040f 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -10,6 +10,7 @@ export is_null;
 export is_not_null;
 export memcpy;
 export memmove;
+export memset;
 export buf_len;
 export position;
 export extensions;
@@ -23,6 +24,8 @@ native mod libc_ {
     fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
     #[rust_stack]
     fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
+    #[rust_stack]
+    fn memset(dest: *c_void, c: libc::c_int, len: libc::size_t) -> *c_void;
 }
 
 #[abi = "rust-intrinsic"]
@@ -108,6 +111,12 @@ unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
     libc_::memmove(dst as *c_void, src as *c_void, n as size_t);
 }
 
+#[inline(always)]
+unsafe fn memset<T>(dst: *mut T, c: int, count: uint)  {
+    let n = count * sys::size_of::<T>();
+    libc_::memset(dst as *c_void, c as libc::c_int, n as size_t);
+}
+
 #[doc = "Extension methods for pointers"]
 impl extensions<T> for *T {
     #[doc = "Returns true if the pointer is equal to the null pointer."]
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index f1136fde5e2..078243dfaee 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -1743,8 +1743,9 @@ mod unsafe {
    Does not verify that the vector contains valid UTF-8.
    "]
    unsafe fn from_bytes(v: [const u8]) -> str unsafe {
-       let vcopy = v + [0u8];
-       ret ::unsafe::transmute(vcopy);
+       let mut vcopy : [u8] = ::unsafe::transmute(copy v);
+       vec::push(vcopy, 0u8);
+       ::unsafe::transmute(vcopy)
    }
 
    #[doc = "
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 1eab5b12ea0..a1b2ee23f0f 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -4,6 +4,7 @@ import option::{some, none};
 import ptr::addr_of;
 import libc::size_t;
 
+export append;
 export init_op;
 export is_empty;
 export is_not_empty;
@@ -187,7 +188,9 @@ pure fn from_elem<T: copy>(n_elts: uint, t: T) -> [T] {
     let mut v = [];
     unchecked{reserve(v, n_elts)}
     let mut i: uint = 0u;
-    while i < n_elts { v += [t]; i += 1u; }
+    unsafe { // because push is impure
+        while i < n_elts { push(v, t); i += 1u; }
+    }
     ret v;
 }
 
@@ -372,11 +375,8 @@ fn shift<T: copy>(&v: [T]) -> T {
 }
 
 #[doc = "Prepend an element to a vector"]
-fn unshift<T: copy>(&v: [const T], +t: T) {
-    // n.b.---for most callers, using unshift() ought not to type check, but
-    // it does. It's because the type system is unaware of the mutability of
-    // `v` and so allows the vector to be covariant.
-    v = [const t] + v;
+fn unshift<T: copy>(&v: [T], +t: T) {
+    v = [t] + v;
 }
 
 #[doc = "Remove the last element from a vector and return it"]
@@ -390,12 +390,69 @@ fn pop<T>(&v: [const T]) -> T unsafe {
 }
 
 #[doc = "Append an element to a vector"]
+#[inline(always)]
 fn push<T>(&v: [const T], +initval: T) {
-    v += [initval];
+    let ln = v.len();
+    unsafe {
+        reserve_at_least(v, ln + 1u);
+        unsafe::set_len(v, ln + 1u);
+        let p = ptr::mut_addr_of(v[ln]);
+
+        // FIXME: for performance, try replacing the memmove and <- with a
+        // memset and unsafe::forget.
+        ptr::memset(p, 0, 1u); // needed to stop drop glue from running on
+                               // garbage data.
+        *p = initval;
+    }
 }
 
+#[inline(always)]
+fn push_all<T: copy>(&v: [const T], rhs: [const T]/&) {
+    for uint::range(0u, rhs.len()) {|i|
+        push(v, rhs[i]);
+    }
+}
 
 // Appending
+#[inline(always)]
+pure fn append<T: copy>(lhs: [T]/&, rhs: [const T]/&) -> [T] {
+    let mut v = [];
+    let mut i = 0u;
+    while i < lhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, lhs[i]);
+        }
+        i += 1u;
+    }
+    i = 0u;
+    while i < rhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, rhs[i]);
+        }
+        i += 1u;
+    }
+    ret v;
+}
+
+#[inline(always)]
+pure fn append_mut<T: copy>(lhs: [mut T]/&, rhs: [const T]/&) -> [mut T] {
+    let mut v = [mut];
+    let mut i = 0u;
+    while i < lhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, lhs[i]);
+        }
+        i += 1u;
+    }
+    i = 0u;
+    while i < rhs.len() {
+        unsafe { // This is impure, but it appears pure to the caller.
+            push(v, rhs[i]);
+        }
+        i += 1u;
+    }
+    ret v;
+}
 
 #[doc = "
 Expands a vector in place, initializing the new elements to a given value
@@ -409,7 +466,8 @@ Expands a vector in place, initializing the new elements to a given value
 fn grow<T: copy>(&v: [const T], n: uint, initval: T) {
     reserve_at_least(v, len(v) + n);
     let mut i: uint = 0u;
-    while i < n { v += [initval]; i += 1u; }
+
+    while i < n { push(v, initval); i += 1u; }
 }
 
 #[doc = "
@@ -428,7 +486,7 @@ Function `init_op` is called `n` times with the values [0..`n`)
 fn grow_fn<T>(&v: [const T], n: uint, op: init_op<T>) {
     reserve_at_least(v, len(v) + n);
     let mut i: uint = 0u;
-    while i < n { v += [op(i)]; i += 1u; }
+    while i < n { push(v, op(i)); i += 1u; }
 }
 
 #[doc = "
@@ -453,7 +511,7 @@ Apply a function to each element of a vector and return the results
 pure fn map<T, U>(v: [T]/&, f: fn(T) -> U) -> [U] {
     let mut result = [];
     unchecked{reserve(result, len(v));}
-    for each(v) {|elem| result += [f(elem)]; }
+    for each(v) {|elem| unsafe { push(result, f(elem)); } }
     ret result;
 }
 
@@ -486,7 +544,10 @@ pure fn map2<T: copy, U: copy, V>(v0: [T]/&, v1: [U]/&,
     if v0_len != len(v1) { fail; }
     let mut u: [V] = [];
     let mut i = 0u;
-    while i < v0_len { u += [f(copy v0[i], copy v1[i])]; i += 1u; }
+    while i < v0_len {
+        unsafe { push(u, f(copy v0[i], copy v1[i])) };
+        i += 1u;
+    }
     ret u;
 }
 
@@ -502,7 +563,7 @@ pure fn filter_map<T, U: copy>(v: [T]/&, f: fn(T) -> option<U>)
     for each(v) {|elem|
         alt f(elem) {
           none {/* no-op */ }
-          some(result_elem) { result += [result_elem]; }
+          some(result_elem) { unsafe { push(result, result_elem); } }
         }
     }
     ret result;
@@ -518,7 +579,7 @@ only those elements for which `f` returned true.
 pure fn filter<T: copy>(v: [T]/&, f: fn(T) -> bool) -> [T] {
     let mut result = [];
     for each(v) {|elem|
-        if f(elem) { result += [elem]; }
+        if f(elem) { unsafe { push(result, elem); } }
     }
     ret result;
 }
@@ -530,7 +591,7 @@ Flattens a vector of vectors of T into a single vector of T.
 "]
 pure fn concat<T: copy>(v: [[T]]/&) -> [T] {
     let mut r = [];
-    for each(v) {|inner| r += inner; }
+    for each(v) {|inner| unsafe { push_all(r, inner); } }
     ret r;
 }
 
@@ -541,7 +602,7 @@ pure fn connect<T: copy>(v: [[T]]/&, sep: T) -> [T] {
     let mut r: [T] = [];
     let mut first = true;
     for each(v) {|inner|
-        if first { first = false; } else { r += [sep]; }
+        if first { first = false; } else { unsafe { push(r, sep); } }
         r += inner;
     }
     ret r;
@@ -1025,6 +1086,20 @@ pure fn unpack_mut_slice<T,U>(s: [mut T]/&,
     f(buf, len / sys::size_of::<T>())
 }
 
+impl extensions<T: copy> for [T] {
+    #[inline(always)]
+    pure fn +(rhs: [T]/&) -> [T] {
+        append(self, rhs)
+    }
+}
+
+impl extensions<T: copy> for [mut T] {
+    #[inline(always)]
+    pure fn +(rhs: [mut T]/&) -> [mut T] {
+        append_mut(self, rhs)
+    }
+}
+
 #[doc = "Extension methods for vectors"]
 impl extensions/&<T> for [const T]/& {
     #[doc = "Returns true if a vector contains no elements"]
diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs
index 1e9b2224a63..eafd2776d19 100644
--- a/src/libstd/deque.rs
+++ b/src/libstd/deque.rs
@@ -33,8 +33,8 @@ fn create<T: copy>() -> t<T> {
         let nalloc = uint::next_power_of_two(nelts + 1u);
         while i < nalloc {
             if i < nelts {
-                rv += [mut elts[(lo + i) % nelts]];
-            } else { rv += [mut none]; }
+                vec::push(rv, elts[(lo + i) % nelts]);
+            } else { vec::push(rv, none); }
             i += 1u;
         }
 
diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs
index 945b23cc47a..a8cd3b65ef8 100644
--- a/src/libstd/rope.rs
+++ b/src/libstd/rope.rs
@@ -864,7 +864,7 @@ mod node {
         loop {
             alt (leaf_iterator::next(it)) {
               option::none   { break; }
-              option::some(x) { forest += [mut @leaf(x)]; }
+              option::some(x) { vec::push(forest, @leaf(x)); }
             }
         }
         //2. Rebuild tree from forest
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 09bb2cc5409..e56bb25e55d 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -480,12 +480,17 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
             vfn(id);
         },
 
-        visit_fn: fn@(fk: visit::fn_kind, d: fn_decl,
-                      _b: blk, _sp: span, id: node_id) {
+        visit_fn: fn@(fk: visit::fn_kind, d: ast::fn_decl,
+                      _b: ast::blk, _sp: span, id: ast::node_id) {
             vfn(id);
 
             alt fk {
-              visit::fk_ctor(_, tps, self_id, parent_id) |
+              visit::fk_ctor(nm, tps, self_id, parent_id) {
+                vec::iter(tps) {|tp| vfn(tp.id)}
+                vfn(id);
+                vfn(self_id);
+                vfn(parent_id.node);
+              }
               visit::fk_dtor(tps, self_id, parent_id) {
                 vec::iter(tps) {|tp| vfn(tp.id)}
                 vfn(id);
@@ -500,7 +505,11 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
                 vfn(m.self_id);
                 vec::iter(tps) {|tp| vfn(tp.id)}
               }
-              visit::fk_anon(*) | visit::fk_fn_block(*) {
+              visit::fk_anon(_, capture_clause)
+              | visit::fk_fn_block(capture_clause) {
+                for vec::each(*capture_clause) {|clause|
+                    vfn(clause.id);
+                }
               }
             }
 
diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs
index f8292be51fe..b8362eb8734 100644
--- a/src/libsyntax/parse/common.rs
+++ b/src/libsyntax/parse/common.rs
@@ -159,7 +159,7 @@ impl parser_common for parser {
                        else { self.expect(t); } }
               _ { }
             }
-            v += [f(self)];
+            vec::push(v, f(self));
         }
 
         ret v;
@@ -202,7 +202,7 @@ impl parser_common for parser {
               _ { }
             }
             if sep.trailing_sep_allowed && self.token == ket { break; }
-            v += [f(self)];
+            vec::push(v, f(self));
         }
         ret v;
     }
diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs
index b275ebcb3ae..2fae0850187 100644
--- a/src/rustc/middle/astencode.rs
+++ b/src/rustc/middle/astencode.rs
@@ -66,8 +66,8 @@ type decode_ctxt = @{
 
 type extended_decode_ctxt = @{
     dcx: decode_ctxt,
-    from_id_range: id_range,
-    to_id_range: id_range
+    from_id_range: ast_util::id_range,
+    to_id_range: ast_util::id_range
 };
 
 iface tr {
@@ -86,9 +86,9 @@ fn encode_inlined_item(ecx: @e::encode_ctxt,
            ast_map::path_to_str(path), *ii.ident(),
            ebml_w.writer.tell()];
 
-    let id_range = compute_id_range(ii);
+    let id_range = ast_util::compute_id_range_for_inlined_item(ii);
     ebml_w.wr_tag(c::tag_ast as uint) {||
-        encode_id_range(ebml_w, id_range);
+        ast_util::serialize_id_range(ebml_w, id_range);
         encode_ast(ebml_w, simplify_ast(ii));
         encode_side_tables_for_ii(ecx, maps, ebml_w, ii);
     }
@@ -108,7 +108,8 @@ fn decode_inlined_item(cdata: cstore::crate_metadata,
       none { none }
       some(ast_doc) {
         #debug["> Decoding inlined fn: %s::?", ast_map::path_to_str(path)];
-        let from_id_range = decode_id_range(ast_doc);
+        let ast_dsr = ebml::ebml_deserializer(ast_doc);
+        let from_id_range = ast_util::deserialize_id_range(ast_dsr);
         let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range);
         let xcx = @{dcx: dcx,
                     from_id_range: from_id_range,
@@ -136,178 +137,10 @@ fn decode_inlined_item(cdata: cstore::crate_metadata,
 // ______________________________________________________________________
 // Enumerating the IDs which appear in an AST
 
-type id_range = {min: ast::node_id, max: ast::node_id};
-
-fn empty(range: id_range) -> bool {
-    range.min >= range.max
-}
-
-fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
-    let visitor = visit::mk_simple_visitor(@{
-        visit_mod: fn@(_m: ast::_mod, _sp: span, id: ast::node_id) {
-            vfn(id)
-        },
-
-        visit_view_item: fn@(vi: @ast::view_item) {
-            alt vi.node {
-              ast::view_item_use(_, _, id) { vfn(id) }
-              ast::view_item_import(vps) | ast::view_item_export(vps) {
-                vec::iter(vps) {|vp|
-                    alt vp.node {
-                      ast::view_path_simple(_, _, id) { vfn(id) }
-                      ast::view_path_glob(_, id) { vfn(id) }
-                      ast::view_path_list(_, _, id) { vfn(id) }
-                    }
-                }
-              }
-            }
-        },
-
-        visit_native_item: fn@(ni: @ast::native_item) {
-            vfn(ni.id)
-        },
-
-        visit_item: fn@(i: @ast::item) {
-            vfn(i.id);
-            alt i.node {
-              ast::item_res(_, _, _, d_id, c_id, _) { vfn(d_id); vfn(c_id); }
-              ast::item_enum(vs, _, _) { for vs.each {|v| vfn(v.node.id); } }
-              _ {}
-            }
-        },
-
-        visit_local: fn@(l: @ast::local) {
-            vfn(l.node.id);
-        },
-
-        visit_block: fn@(b: ast::blk) {
-            vfn(b.node.id);
-        },
-
-        visit_stmt: fn@(s: @ast::stmt) {
-            vfn(ast_util::stmt_id(*s));
-        },
-
-        visit_arm: fn@(_a: ast::arm) { },
-
-        visit_pat: fn@(p: @ast::pat) {
-            vfn(p.id)
-        },
-
-        visit_decl: fn@(_d: @ast::decl) {
-        },
-
-        visit_expr: fn@(e: @ast::expr) {
-            vfn(e.id);
-            alt e.node {
-              ast::expr_unary(*) | ast::expr_binary(*) | ast::expr_index(*) {
-                vfn(ast_util::op_expr_callee_id(e));
-              }
-              _ { /* fallthrough */ }
-            }
-        },
-
-        visit_ty: fn@(t: @ast::ty) {
-            alt t.node {
-              ast::ty_path(_, id) {
-                vfn(id)
-              }
-              _ { /* fall through */ }
-            }
-        },
-
-        visit_ty_params: fn@(ps: [ast::ty_param]) {
-            vec::iter(ps) {|p| vfn(p.id) }
-        },
-
-        visit_constr: fn@(_p: @ast::path, _sp: span, id: ast::node_id) {
-            vfn(id);
-        },
-
-        visit_fn: fn@(fk: visit::fn_kind, d: ast::fn_decl,
-                      _b: ast::blk, _sp: span, id: ast::node_id) {
-            vfn(id);
-
-            alt fk {
-              visit::fk_ctor(nm, tps, self_id, parent_id) {
-                vec::iter(tps) {|tp| vfn(tp.id)}
-                vfn(id);
-                vfn(self_id);
-                vfn(parent_id.node);
-              }
-              visit::fk_dtor(tps, self_id, parent_id) {
-                vec::iter(tps) {|tp| vfn(tp.id)}
-                vfn(id);
-                vfn(self_id);
-                vfn(parent_id.node);
-              }
-              visit::fk_item_fn(_, tps) |
-              visit::fk_res(_, tps, _) {
-                vec::iter(tps) {|tp| vfn(tp.id)}
-              }
-              visit::fk_method(_, tps, m) {
-                vfn(m.self_id);
-                vec::iter(tps) {|tp| vfn(tp.id)}
-              }
-              visit::fk_anon(_, capture_clause)
-              | visit::fk_fn_block(capture_clause) {
-                for vec::each(*capture_clause) {|clause|
-                    vfn(clause.id);
-                }
-              }
-            }
-
-            vec::iter(d.inputs) {|arg|
-                vfn(arg.id)
-            }
-        },
-
-        visit_class_item: fn@(c: @ast::class_member) {
-            alt c.node {
-              ast::instance_var(_, _, _, id,_) {
-                vfn(id)
-              }
-              ast::class_method(_) {
-              }
-            }
-        }
-    });
-
-    item.accept((), visitor)
-}
-
-fn compute_id_range(item: ast::inlined_item) -> id_range {
-    let min = @mut int::max_value;
-    let max = @mut int::min_value;
-    visit_ids(item) {|id|
-        *min = int::min(*min, id);
-        *max = int::max(*max, id + 1);
-    }
-    ret {min:*min, max:*max};
-}
-
-fn encode_id_range(ebml_w: ebml::writer, id_range: id_range) {
-    ebml_w.wr_tag(c::tag_id_range as uint) {||
-        ebml_w.emit_tup(2u) {||
-            ebml_w.emit_tup_elt(0u) {|| ebml_w.emit_int(id_range.min) }
-            ebml_w.emit_tup_elt(1u) {|| ebml_w.emit_int(id_range.max) }
-        }
-    }
-}
-
-fn decode_id_range(par_doc: ebml::doc) -> id_range {
-    let range_doc = par_doc[c::tag_id_range];
-    let dsr = ebml::ebml_deserializer(range_doc);
-    dsr.read_tup(2u) {||
-        {min: dsr.read_tup_elt(0u) {|| dsr.read_int() },
-         max: dsr.read_tup_elt(1u) {|| dsr.read_int() }}
-    }
-}
-
 fn reserve_id_range(sess: session,
-                    from_id_range: id_range) -> id_range {
+                    from_id_range: ast_util::id_range) -> ast_util::id_range {
     // Handle the case of an empty range:
-    if empty(from_id_range) { ret from_id_range; }
+    if ast_util::empty(from_id_range) { ret from_id_range; }
     let cnt = from_id_range.max - from_id_range.min;
     let to_id_min = sess.parse_sess.next_id;
     let to_id_max = sess.parse_sess.next_id + cnt;
@@ -318,7 +151,7 @@ fn reserve_id_range(sess: session,
 impl translation_routines for extended_decode_ctxt {
     fn tr_id(id: ast::node_id) -> ast::node_id {
         // from_id_range should be non-empty
-        assert !empty(self.from_id_range);
+        assert !ast_util::empty(self.from_id_range);
         (id - self.from_id_range.min + self.to_id_range.min)
     }
     fn tr_def_id(did: ast::def_id) -> ast::def_id {
@@ -749,12 +582,14 @@ fn encode_side_tables_for_ii(ecx: @e::encode_ctxt,
                              ebml_w: ebml::writer,
                              ii: ast::inlined_item) {
     ebml_w.wr_tag(c::tag_table as uint) {||
-        visit_ids(ii, fn@(id: ast::node_id, copy ebml_w) {
-            // Note: this will cause a copy of ebml_w, which is bad as
-            // it has mut fields.  But I believe it's harmless since
-            // we generate balanced EBML.
-            encode_side_tables_for_id(ecx, maps, ebml_w, id)
-        });
+        ast_util::visit_ids_for_inlined_item(
+            ii,
+            fn@(id: ast::node_id, copy ebml_w) {
+                // Note: this will cause a copy of ebml_w, which is bad as
+                // it has mut fields.  But I believe it's harmless since
+                // we generate balanced EBML.
+                encode_side_tables_for_id(ecx, maps, ebml_w, id)
+            });
     }
 }
 
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 5fa7ddd12ac..d308181d8c7 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1444,7 +1444,7 @@ fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef,
 // doesn't need to be dropped. (Issue #839)
 fn move_val(cx: block, action: copy_action, dst: ValueRef,
             src: lval_result, t: ty::t) -> block {
-    assert !cx.terminated;
+
     let _icx = cx.insn_ctxt("move_val");
     let mut src_val = src.val;
     let tcx = cx.tcx();
@@ -1777,7 +1777,10 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
     // A user-defined operator method
     alt bcx.ccx().maps.method_map.find(ex.id) {
       some(origin) {
+        let bcx = lhs_res.bcx;
         let callee_id = ast_util::op_expr_callee_id(ex);
+        #debug["user-defined method callee_id: %s",
+               ast_map::node_id_to_str(bcx.tcx().items, callee_id)];
         let fty = node_id_type(bcx, callee_id);
 
         let dty = expr_ty(bcx, dst);
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index 1eca2db5e7d..164a089dc88 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -190,7 +190,7 @@ fn trans_evec(bcx: block, args: [@ast::expr],
         let lleltptr = InBoundsGEP(bcx, dataptr, [C_uint(ccx, i)]);
         bcx = base::trans_expr_save_in(bcx, e, lleltptr);
         add_clean_temp_mem(bcx, lleltptr, unit_ty);
-        temp_cleanups += [lleltptr];
+        vec::push(temp_cleanups, lleltptr);
         i += 1u;
     }
 
diff --git a/src/rustc/middle/tstate/annotate.rs b/src/rustc/middle/tstate/annotate.rs
index be38692c49e..d20cbcfe4d4 100644
--- a/src/rustc/middle/tstate/annotate.rs
+++ b/src/rustc/middle/tstate/annotate.rs
@@ -7,16 +7,18 @@ import aux::{num_constraints, get_fn_info, crate_ctxt, add_node};
 import ann::empty_ann;
 import pat_util::pat_binding_ids;
 
-fn collect_ids_expr(e: @expr, rs: @mut [node_id]) { *rs += [e.id]; }
+fn collect_ids_expr(e: @expr, rs: @mut [node_id]) { vec::push(*rs, e.id); }
 
-fn collect_ids_block(b: blk, rs: @mut [node_id]) { *rs += [b.node.id]; }
+fn collect_ids_block(b: blk, rs: @mut [node_id]) {
+    vec::push(*rs, b.node.id);
+}
 
 fn collect_ids_stmt(s: @stmt, rs: @mut [node_id]) {
     alt s.node {
       stmt_decl(_, id) | stmt_expr(_, id) | stmt_semi(_, id) {
         #debug["node_id %s", int::str(id)];
         #debug["%s", stmt_to_str(*s)];
-        *rs += [id];
+        vec::push(*rs, id);
       }
     }
 }
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 93fcfca31ea..16834c37919 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -921,22 +921,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         let lhs_t = fcx.expr_ty(lhs);
         let lhs_t = structurally_resolved_type(fcx, lhs.span, lhs_t);
         ret alt (op, ty::get(lhs_t).struct) {
-          (ast::add, ty::ty_vec(lhs_mt)) {
-            // For adding vectors with type L=[ML TL] and R=[MR TR], the the
-            // result [ML T] where TL <: T and TR <: T.  In other words, the
-            // result type is (generally) the LUB of (TL, TR) and takes the
-            // mutability from the LHS.
-            let t_var = fcx.infcx.next_ty_var();
-            let const_vec_t = ty::mk_vec(tcx, {ty: t_var,
-                                               mutbl: ast::m_const});
-            demand::suptype(fcx, lhs.span, const_vec_t, lhs_t);
-            let rhs_bot = check_expr_with(fcx, rhs, const_vec_t);
-            let result_vec_t = ty::mk_vec(tcx, {ty: t_var,
-                                                mutbl: lhs_mt.mutbl});
-            fcx.write_ty(expr.id, result_vec_t);
-            lhs_bot | rhs_bot
-          }
-
           (_, _) if ty::type_is_integral(lhs_t) &&
           ast_util::is_shift_binop(op) {
             // Shift is a special case: rhs can be any integral type
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index 4af075e8b79..c1793477b2e 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -154,7 +154,6 @@ class lookup {
     }
 
     fn add_candidates_from_param(n: uint, did: ast::def_id) {
-
         let tcx = self.tcx();
         let mut iface_bnd_idx = 0u; // count only iface bounds
         let bounds = tcx.ty_param_bounds.get(did.node);
@@ -202,6 +201,8 @@ class lookup {
 
     fn add_candidates_from_iface(did: ast::def_id, iface_substs: ty::substs) {
 
+        #debug["method_from_iface"];
+
         let ms = *ty::iface_methods(self.tcx(), did);
         for ms.eachi {|i, m|
             if m.ident != self.m_name { cont; }
@@ -235,6 +236,8 @@ class lookup {
 
     fn add_candidates_from_class(did: ast::def_id, class_substs: ty::substs) {
 
+        #debug["method_from_class"];
+
         let ms = *ty::iface_methods(self.tcx(), did);
 
         for ms.each {|m|
@@ -285,6 +288,8 @@ class lookup {
         let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);
         let mut added_any = false;
 
+        #debug["method_from_scope"];
+
         for list::each(impls_vecs) {|impls|
             for vec::each(*impls) {|im|
                 // Check whether this impl has a method with the right name.
@@ -297,9 +302,11 @@ class lookup {
 
                     // if we can assign the caller to the callee, that's a
                     // potential match.  Collect those in the vector.
-                    alt self.fcx.can_mk_assignty(
+                    let can_assign = self.fcx.can_mk_assignty(
                         self.self_expr, self.borrow_scope,
-                        self.self_ty, impl_ty) {
+                        self.self_ty, impl_ty);
+                    #debug["can_assign = %?", can_assign];
+                    alt can_assign {
                       result::err(_) { /* keep looking */ }
                       result::ok(_) {
                         let fty = self.ty_from_did(m.did);
diff --git a/src/test/bench/core-vec-append.rs b/src/test/bench/core-vec-append.rs
index af522ca8bc3..9a29671e184 100644
--- a/src/test/bench/core-vec-append.rs
+++ b/src/test/bench/core-vec-append.rs
@@ -8,6 +8,8 @@ fn collect_raw(num: uint) -> [uint] {
     let mut result = [];
     for uint::range(0u, num) { |i|
         result += [i];
+        //vec::push(result, i);
+        //result = vec::append(result, [i]);
     }
     ret result;
 }
@@ -43,18 +45,18 @@ fn main(args: [str]) {
 
     let raw = mid - start;
     let dvec = end - mid;
-
+    
     let maxf = max as float;
     let rawf = raw as float;
     let dvecf = dvec as float;
-
+    
     io::stdout().write_str(#fmt("Raw     : %? seconds\n", raw));
     io::stdout().write_str(#fmt("        : %f op/sec\n", maxf/rawf));
     io::stdout().write_str(#fmt("\n"));
     io::stdout().write_str(#fmt("Dvec    : %? seconds\n", dvec));
     io::stdout().write_str(#fmt("        : %f op/sec\n", maxf/dvecf));
     io::stdout().write_str(#fmt("\n"));
-
+    
     if dvec < raw {
         io::stdout().write_str(#fmt("Dvec is %f%% faster than raw\n",
                                     (rawf - dvecf) / rawf * 100.0));
diff --git a/src/test/run-fail/zip-different-lengths.rs b/src/test/run-fail/zip-different-lengths.rs
index 4a5ac59efd2..736b61cb935 100644
--- a/src/test/run-fail/zip-different-lengths.rs
+++ b/src/test/run-fail/zip-different-lengths.rs
@@ -10,7 +10,7 @@ fn enum_chars(start: u8, end: u8) -> [char] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i as char]; i += 1u as u8; }
+    while i <= end { vec::push(r, i as char); i += 1u as u8; }
     ret r;
 }
 
@@ -18,7 +18,7 @@ fn enum_uints(start: uint, end: uint) -> [uint] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i]; i += 1u; }
+    while i <= end { vec::push(r, i); i += 1u; }
     ret r;
 }
 
diff --git a/src/test/run-pass/import-glob-crate.rs b/src/test/run-pass/import-glob-crate.rs
index 50e7257a6a0..c1473b1a0d4 100644
--- a/src/test/run-pass/import-glob-crate.rs
+++ b/src/test/run-pass/import-glob-crate.rs
@@ -4,6 +4,6 @@ import vec::*;
 
 fn main() {
     let mut v = from_elem(0u, 0);
-    v += [4, 2];
+    v = vec::append(v, [4, 2]);
     assert (reversed(v) == [2, 4]);
 }
diff --git a/src/test/run-pass/vec-push.rs b/src/test/run-pass/vec-push.rs
index 56661e13a32..15b9239c44b 100644
--- a/src/test/run-pass/vec-push.rs
+++ b/src/test/run-pass/vec-push.rs
@@ -1,5 +1 @@
-
-
-fn push<T: copy>(&v: [const T], t: T) { v += [t]; }
-
-fn main() { let mut v = [1, 2, 3]; push(v, 1); }
+fn main() { let mut v = [1, 2, 3]; vec::push(v, 1); }
diff --git a/src/test/run-pass/zip-same-length.rs b/src/test/run-pass/zip-same-length.rs
index 73a0f66d382..9ffb564ace6 100644
--- a/src/test/run-pass/zip-same-length.rs
+++ b/src/test/run-pass/zip-same-length.rs
@@ -10,7 +10,7 @@ fn enum_chars(start: u8, end: u8) -> [char] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i as char]; i += 1u as u8; }
+    while i <= end { vec::push(r, i as char); i += 1u as u8; }
     ret r;
 }
 
@@ -18,7 +18,7 @@ fn enum_uints(start: uint, end: uint) -> [uint] {
     assert start < end;
     let mut i = start;
     let mut r = [];
-    while i <= end { r += [i]; i += 1u; }
+    while i <= end { vec::push(r, i); i += 1u; }
     ret r;
 }