about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLindsey Kuper <lkuper@mozilla.com>2011-03-18 12:32:54 -0700
committerLindsey Kuper <lkuper@mozilla.com>2011-03-18 12:32:54 -0700
commit6dee1ac161a22a4bc1e49c5dac3c7bbba1ff97f0 (patch)
treef423d576e977e7a258f09e50e5a51702525782e2
parent830f2d02f19b45ff4b4a4d7946b69f206b5dcdff (diff)
parent6f65ce5255ac16204490bdd7dcf99acd24876bc6 (diff)
Merge branch 'master' of git://github.com/graydon/rust
-rw-r--r--Makefile.in402
-rwxr-xr-xconfigure133
-rw-r--r--src/Makefile13
-rw-r--r--src/Makefile.in129
-rw-r--r--src/boot/fe/pexp.ml16
-rw-r--r--src/boot/me/type.ml4
-rw-r--r--src/comp/back/x86.rs6
-rw-r--r--src/comp/driver/rustc.rs4
-rw-r--r--src/comp/driver/session.rs9
-rw-r--r--src/comp/front/ast.rs15
-rw-r--r--src/comp/front/eval.rs7
-rw-r--r--src/comp/front/extfmt.rs4
-rw-r--r--src/comp/front/lexer.rs14
-rw-r--r--src/comp/front/parser.rs124
-rw-r--r--src/comp/front/token.rs5
-rw-r--r--src/comp/middle/fold.rs98
-rw-r--r--src/comp/middle/trans.rs236
-rw-r--r--src/comp/middle/ty.rs265
-rw-r--r--src/comp/middle/typeck.rs180
-rw-r--r--src/comp/pretty/pp.rs14
-rw-r--r--src/comp/pretty/pprust.rs59
-rw-r--r--src/comp/util/common.rs9
-rw-r--r--src/configure.sh39
-rw-r--r--src/lib/_str.rs52
-rw-r--r--src/lib/_uint.rs4
-rw-r--r--src/lib/_vec.rs36
-rw-r--r--src/lib/fs.rs12
-rw-r--r--src/lib/io.rs5
-rw-r--r--src/lib/option.rs7
-rw-r--r--src/lib/posix_fs.rs16
-rw-r--r--src/lib/run_program.rs4
-rw-r--r--src/lib/sha1.rs9
-rw-r--r--src/lib/sort.rs56
-rw-r--r--src/lib/std.rc11
-rw-r--r--src/lib/win32_fs.rs9
-rw-r--r--src/llvmext/rustllvm.def473
-rw-r--r--src/rt/rust_builtin.cpp23
-rw-r--r--src/test/bench/99-bottles/99bob-iter.rs2
-rw-r--r--src/test/bench/99-bottles/99bob-simple.rs2
-rw-r--r--src/test/bench/shootout/fasta.rs6
-rw-r--r--src/test/run-pass/append-units.rs15
-rw-r--r--src/test/run-pass/lib-str-buf.rs14
-rw-r--r--src/test/run-pass/maybe-mutable.rs17
43 files changed, 1835 insertions, 723 deletions
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 00000000000..1869476165b
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,402 @@
+######################################################################
+# Residual auto-configuration
+######################################################################
+
+include config.mk
+MKFILES := Makefile config.mk
+
+ifneq ($(MAKE_RESTARTS),)
+CFG_INFO := $(info cfg: make restarts: $(MAKE_RESTARTS))
+endif
+
+CFG_INFO := $(info cfg: building on $(CFG_OSTYPE) $(CFG_CPUTYPE))
+
+CFG_GCC_CFLAGS :=
+CFG_GCC_LINK_FLAGS :=
+CFG_BOOT_FLAGS := $(BOOT_FLAGS)
+CFG_RUSTC_FLAGS := -nowarn
+
+# On Darwin, we need to run dsymutil so the debugging information ends
+# up in the right place.  On other platforms, it automatically gets
+# embedded into the executable, so use a no-op command.
+CFG_DSYMUTIL := true
+
+ifeq ($(CFG_OSTYPE), FreeBSD)
+  LIB := lib$(1).so
+  CFG_GCC_CFLAGS += -fPIC -march=i686 -I/usr/local/include
+  CFG_GCC_LINK_FLAGS += -shared -fPIC -lpthread -lrt
+  ifeq ($(CFG_CPUTYPE), x86_64)
+    CFG_GCC_CFLAGS += -m32
+    CFG_GCC_LINK_FLAGS += -m32
+  endif
+  CFG_UNIXY := 1
+endif
+
+ifeq ($(CFG_OSTYPE), Linux)
+  LIB := lib$(1).so
+  CFG_GCC_CFLAGS += -fPIC -march=i686
+  CFG_GCC_LINK_FLAGS += -shared -fPIC -ldl -lpthread -lrt
+  ifeq ($(CFG_CPUTYPE), x86_64)
+    CFG_GCC_CFLAGS += -m32
+    CFG_GCC_LINK_FLAGS += -m32
+  endif
+  CFG_UNIXY := 1
+endif
+
+ifeq ($(CFG_OSTYPE), Darwin)
+  LIB := lib$(1).dylib
+  CFG_UNIXY := 1
+  CFG_GCC_LINK_FLAGS += -dynamiclib -lpthread
+  # Darwin has a very blurry notion of "64 bit", and claims it's running
+  # "on an i386" when the whole userspace is 64-bit and the compiler
+  # emits 64-bit binaries by default. So we just force -m32 here. Smarter
+  # approaches welcome!
+  CFG_GCC_CFLAGS += -m32
+  CFG_GCC_LINK_FLAGS += -m32
+  CFG_DSYMUTIL := dsymutil
+endif
+
+ifneq ($(findstring MINGW,$(CFG_OSTYPE)),)
+  CFG_WINDOWSY := 1
+endif
+
+ifdef CFG_WINDOWSY
+  CFG_INFO := $(info cfg: windows-y environment)
+
+  CFG_EXE_SUFFIX := .exe
+  CFG_LIB_NAME=$(1).dll
+  CFG_RUN_PROGRAM=$(1)
+
+  CFG_PATH_MUNGE := | sed -e 's/\\\(.\)/\/\1/g'
+  ifdef CFG_FLEXLINK
+    CFG_BOOT_NATIVE := 1
+  endif
+  CFG_GCC_CFLAGS += -march=i686
+  CFG_GCC_LINK_FLAGS += -shared -fPIC
+endif
+
+ifdef CFG_UNIXY
+  CFG_INFO := $(info cfg: unix-y environment)
+
+  CFG_EXE_SUFFIX :=
+  CFG_RUN_PROGRAM = LD_LIBRARY_PATH=$(dir $(1)) $(CFG_VALGRIND) $(1)
+
+  CFG_BOOT_NATIVE := 1
+
+  ifdef MINGW_CROSS
+    CFG_EXE_SUFFIX := .exe
+    CFG_LIB_NAME=$(1).dll
+    CFG_RUN_PROGRAM=$(1)
+
+    CFG_INFO := $(info cfg: mingw-cross)
+    CFG_GCC_CROSS := i586-mingw32msvc-
+    CFG_BOOT_FLAGS += -t win32-x86-pe
+    ifdef CFG_VALGRIND
+      CFG_VALGRIND += wine
+    endif
+    CFG_GCC_CFLAGS := -march=i686
+    CFG_GCC_LINK_FLAGS := -shared
+    ifeq ($(CFG_CPUTYPE), x86_64)
+      CFG_GCC_CFLAGS += -m32
+      CFG_GCC_LINK_FLAGS += -m32
+    endif
+  endif
+  ifdef CFG_VALGRIND
+    CFG_VALGRIND += --leak-check=full \
+                    --error-exitcode=1 \
+                    --quiet --vex-iropt-level=0 \
+                    --suppressions=etc/x86.supp
+  endif
+endif
+
+CFG_RUNTIME :=$(call CFG_LIB_NAME,rustrt)
+CFG_LLVMEXT :=$(call CFG_LIB_NAME,llvmext)
+CFG_STDLIB :=$(call CFG_LIB_NAME,std)
+
+ifdef CFG_GCC
+  CFG_INFO := $(info cfg: using gcc)
+  CFG_GCC_CFLAGS += -Wall -Werror -fno-rtti -fno-exceptions -g
+  CFG_GCC_LINK_FLAGS += -g
+  CFG_COMPILE_C = $(CFG_GCC_CROSS)g++ $(CFG_GCC_CFLAGS) -c -o $(1) $(2)
+  CFG_LINK_C = $(CFG_GCC_CROSS)g++ $(CFG_GCC_LINK_FLAGS) -o $(1)
+  CFG_DEPEND_C = $(CFG_GCC_CROSS)g++ $(CFG_GCC_CFLAGS) -MT "$(1)" -MM $(2)
+else
+  CFG_ERR := $(error please try on a system with gcc)
+endif
+
+ifdef CFG_OCAMLC_OPT
+  $(info cfg: have ocaml native compiler)
+  OPT=.opt
+else
+  $(info cfg: have only ocaml bytecode compiler)
+endif
+
+ifdef BOOT_PROFILE
+  $(info cfg: forcing native bootstrap compiler (BOOT_PROFILE))
+  CFG_BOOT_NATIVE := 1
+  CFG_OCAMLOPT_PROFILE_FLAGS := -p
+endif
+
+ifdef BOOT_DEBUG
+  $(info cfg: forcing bytecode bootstrap compiler (DEBUG))
+  CFG_BOOT_NATIVE :=
+endif
+
+ifdef CFG_BOOT_NATIVE
+  $(info cfg: building native bootstrap compiler)
+else
+  $(info cfg: building bytecode bootstrap compiler)
+endif
+
+ifdef NO_VALGRIND
+  $(info cfg: disabling valgrind (NO_VALGRIND))
+  CFG_VALGRIND :=
+endif
+
+######################################################################
+# Target-and-rule "utility variables"
+######################################################################
+
+ifdef VERBOSE
+  Q :=
+  E =
+else
+  Q := @
+  E = echo $(1)
+endif
+
+R := $(CFG_RUN_PROGRAM)
+S := $(CFG_SRC_DIR)
+X := $(CFG_EXE_SUFFIX)
+
+# Look in doc and src dirs.
+VPATH := $(S)doc $(S)src
+
+# Compilers we build, we now know how to run.
+BOOT := $(Q)OCAMLRUNPARAM="b1" boot/rustboot$(X) $(CFG_BOOT_FLAGS)
+STAGE0 := $(Q)stage0/rustc$(X) $(CFG_RUSTC_FLAGS)
+STAGE1 := $(Q)stage1/rustc$(X) $(CFG_RUSTC_FLAGS)
+STAGE2 := $(Q)stage2/rustc$(X) $(CFG_RUSTC_FLAGS)
+
+# "Source" files we generate in builddir along the way.
+GENERATED := boot/fe/lexer.ml boot/version.ml
+
+# Delete the built-in rules.
+.SUFFIXES:
+%:: %,v
+%:: RCS/%,v
+%:: RCS/%
+%:: s.%
+%:: SCCS/s.%
+
+######################################################################
+# Bootstrap compiler variables
+######################################################################
+
+# We must list them in link order.
+# Nobody calculates the link-order DAG automatically, sadly.
+
+BOOT_MLS :=                                              \
+    $(addsuffix .ml,                                     \
+        boot/version                                     \
+        $(addprefix boot/util/, fmt common bits)         \
+        $(addprefix boot/driver/, session)               \
+        $(addprefix boot/fe/, ast token lexer parser     \
+          extfmt pexp item cexp fuzz)                    \
+        $(addprefix boot/be/, asm il abi)                \
+        $(addprefix boot/me/, walk semant resolve alias  \
+          simplify type dead layer effect typestate      \
+         loop layout transutil trans dwarf)              \
+        $(addprefix boot/be/, x86 ra pe elf macho)       \
+        $(addprefix boot/driver/, lib glue main))        \
+
+BOOT_CMOS := $(BOOT_MLS:.ml=.cmo)
+BOOT_CMXS := $(BOOT_MLS:.ml=.cmx)
+BOOT_OBJS := $(BOOT_MLS:.ml=.o)
+BOOT_CMIS := $(BOOT_MLS:.ml=.cmi)
+
+BS := $(S)/src/boot/
+
+BOOT_ML_DEP_INCS := -I $(BS)/fe   -I $(BS)/me      \
+                    -I $(BS)/be   -I $(BS)/driver  \
+                    -I $(BS)/util -I boot
+
+BOOT_ML_INCS    :=  -I boot/fe   -I boot/me      \
+                    -I boot/be   -I boot/driver  \
+                    -I boot/util -I boot
+
+BOOT_ML_LIBS        := unix.cma  nums.cma  bigarray.cma
+BOOT_ML_NATIVE_LIBS := unix.cmxa nums.cmxa bigarray.cmxa
+BOOT_OCAMLC_FLAGS   := -g $(BOOT_ML_INCS) -w Ael -warn-error Ael
+BOOT_OCAMLOPT_FLAGS := -g $(BOOT_ML_INCS) -w Ael -warn-error Ael
+
+######################################################################
+# Runtime (C++) library variables
+######################################################################
+
+RUNTIME_CS := rt/sync/timer.cpp \
+              rt/sync/sync.cpp \
+              rt/sync/lock_and_signal.cpp \
+              rt/rust.cpp \
+              rt/rust_builtin.cpp \
+              rt/rust_run_program.cpp \
+              rt/rust_crate.cpp \
+              rt/rust_crate_cache.cpp \
+              rt/rust_crate_reader.cpp \
+              rt/rust_comm.cpp \
+              rt/rust_dom.cpp \
+              rt/rust_task.cpp \
+              rt/rust_task_list.cpp \
+              rt/rust_proxy.cpp \
+              rt/rust_chan.cpp \
+              rt/rust_port.cpp \
+              rt/rust_upcall.cpp \
+              rt/rust_log.cpp \
+              rt/rust_message.cpp \
+              rt/rust_timer.cpp \
+              rt/circular_buffer.cpp \
+              rt/isaac/randport.cpp \
+              rt/rust_srv.cpp \
+              rt/rust_kernel.cpp \
+              rt/memory_region.cpp \
+              rt/test/rust_test_harness.cpp \
+              rt/test/rust_test_runtime.cpp \
+              rt/test/rust_test_util.cpp
+
+RUNTIME_HDR := rt/globals.h \
+               rt/rust.h \
+               rt/rust_dwarf.h \
+               rt/rust_internal.h \
+               rt/rust_util.h \
+               rt/rust_chan.h \
+               rt/rust_port.h \
+               rt/rust_dom.h \
+               rt/rust_task.h \
+               rt/rust_task_list.h \
+               rt/rust_proxy.h \
+               rt/rust_log.h \
+               rt/rust_message.h \
+               rt/circular_buffer.h \
+               rt/util/array_list.h \
+               rt/util/indexed_list.h \
+               rt/util/synchronized_indexed_list.h \
+               rt/util/hash_map.h \
+               rt/sync/sync.h \
+               rt/sync/timer.h \
+               rt/sync/lock_free_queue.h \
+               rt/rust_srv.h \
+               rt/rust_kernel.h \
+               rt/memory_region.h \
+               rt/memory.h \
+               rt/test/rust_test_harness.h \
+               rt/test/rust_test_runtime.h \
+               rt/test/rust_test_util.h
+
+RUNTIME_INCS := -I $(S)src/rt/isaac -I $(S)src/rt/uthash
+RUNTIME_OBJS := $(RUNTIME_CS:.cpp=.o)
+
+######################################################################
+# rustc LLVM-extensions (C++) library variables
+######################################################################
+
+LLVMEXT_CS := $(addprefix llvmext/, \
+                MachOObjectFile.cpp Object.cpp RustWrapper.cpp)
+
+LLVMEXT_HDR := llvmext/include/llvm-c/Object.h
+
+LLVMEXT_INCS := -iquote $(CFG_LLVM_INCDIR) -iquote llvmext/include
+LLVMEXT_OBJS := $(LLVMEXT_CS:.cpp=.o)
+LLVMEXT_LIBS := $(CFG_LLVM_LDFLAGS) $(CFG_LLVM_LIBS)
+
+######################################################################
+# Standard library variables
+######################################################################
+
+STDLIB_CRATE := lib/std.rc
+STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/lib/,*.rc *.rs */*.rs))
+
+######################################################################
+# rustc crate variables
+######################################################################
+
+COMPILER_CRATE := comp/rustc.rc
+COMPILER_INPUTS := $(wildcard $(addprefix $(S)/src/comp/, \
+                                rustc.rc *.rs */*.rs))
+
+######################################################################
+# Single-target rules
+######################################################################
+
+all: boot/rustboot$(X) rt/$(CFG_RUNTIME) llvmext/$(CFG_LLVMEXT)
+
+rt/$(CFG_RUNTIME): $(RUNTIME_OBJS) $(MKFILES) $(RUNTIME_HDR)
+	@$(call E, link: $@)
+	$(Q)$(call CFG_LINK_C, $@) $(RUNTIME_OBJS)
+
+llvmext/$(CFG_LLVMEXT): $(LLVMEXT_OBJS) $(MKFILES) $(LLVMEXT_HDR)
+	@$(call E, link: $@)
+	$(Q)$(call CFG_LINK_C, $@ $(LLVMEXT_OBJS) \
+        $(CFG_LLVM_LIBS) $(CFG_LLVM_LDFLAGS))
+
+ifdef CFG_BOOT_NATIVE
+boot/rustboot$(X): $(BOOT_CMXS) $(MKFILES)
+	@$(call E, link: $@)
+	$(Q)ocamlopt$(OPT) -o $@ $(BOOT_OCAMLOPT_FLAGS) $(BOOT_ML_NATIVE_LIBS) \
+        $(BOOT_CMXS)
+else
+boot/rustboot$(X): $(BOOT_CMOS) $(MKFILES)
+	@$(call E, link: $@)
+	$(Q)ocamlc$(OPT) -o $@ $(BOOT_OCAMLC_FLAGS) $(BOOT_ML_LIBS) $(BOOT_CMOS)
+endif
+
+boot/version.ml: $(MKFILES)
+	@$(call E, git: $@)
+	$(Q)git log -1 \
+      --pretty=format:'let version = "prerelease (%h %ci)";;' >$@ || exit 1
+
+
+######################################################################
+# Pattern rules
+######################################################################
+
+rt/%.o: rt/%.cpp $(MKFILES)
+	@$(call E, compile: $@)
+	$(Q)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $<
+
+llvmext/%.o: llvmext/%.cpp $(MKFILES)
+	@$(call E, compile: $@)
+	$(Q)$(call CFG_COMPILE_C, $@, $(CFG_LLVM_CXXFLAGS) \
+		$(SUPPORT_INCS)) $<
+
+%.cmo: %.ml $(MKFILES)
+	@$(call E, compile: $@)
+	$(Q)ocamlc$(OPT) -c -o $@ $(BOOT_OCAMLC_FLAGS) $<
+
+%.cmo: %.cmi $(MKFILES)
+
+%.cmx %.o: %.ml $(MKFILES)
+	@$(call E, compile: $@)
+	$(Q)ocamlopt$(OPT) -c -o $@ $(BOOT_OCAMLOPT_FLAGS) $<
+
+%.ml: %.mll $(MKFILES)
+	@$(call E, lex-gen: $@)
+	$(Q)ocamllex$(OPT) -q -o $@ $<
+
+
+######################################################################
+# Cleanup
+######################################################################
+
+.PHONY: clean
+
+clean:
+	@$(call E, cleaning)
+	$(Q)rm -f $(foreach ext, cmx cmi cmo cma bc o a d $(X)     \
+                             h cpp ml s                        \
+                             out bc dSYM                       \
+                             ,                                 \
+                  $(wildcard     *.$(ext)                      \
+                               */*.$(ext)                      \
+                             */*/*.$(ext)                      \
+                           */*/*/*.$(ext)                      \
+                   ))
diff --git a/configure b/configure
new file mode 100755
index 00000000000..1672375e678
--- /dev/null
+++ b/configure
@@ -0,0 +1,133 @@
+#!/bin/sh
+
+CFG_SRC_DIR=${0%${0##*/}}
+CFG_BUILD_DIR=$PWD
+
+msg() {
+    echo "configure: $1"
+}
+
+err() {
+    echo "configure: error: $1"
+    exit 1
+}
+
+make_dir() {
+    if [ ! -d $1 ]
+    then
+        msg "mkdir -p $1"
+        mkdir -p $1
+    fi
+}
+
+copy() {
+    msg "cp $1 $1"
+    cp $1 $2
+}
+
+make_test_subdirs() {
+    for t in run-pass run-fail compile-fail
+    do
+        make_dir $1/test/$t
+    done
+}
+
+putvar() {
+    local T
+    eval T=\$$1
+    printf "%-20s := %s\n" $1 "$T"
+    printf "%-20s := %s\n" $1 "$T" >>config.mk
+}
+
+probe() {
+    local V=$1
+    local P=$2
+    local T
+    T=$(which $P 2>&1)
+    if [ $? -ne 0 ]
+    then
+        T=""
+    fi
+    eval $V=\$T
+    putvar $V
+}
+
+probe_need() {
+    local V=$1
+    local P=$2
+    probe $1 $2
+    eval VV=\$$V
+    if [ -z "$VV" ]
+    then
+        err "required program '$P' not found"
+    fi
+}
+
+
+msg "recreating config.mk"
+echo '' >config.mk
+
+msg "making directories"
+for i in \
+    doc \
+    boot/fe boot/me boot/be boot/driver boot/util \
+    rt/isaac rt/bigint rt/sync rt/test
+do
+    make_dir $i
+done
+
+make_test_subdirs boot
+
+for i in 0 1 2
+do
+    make_dir stage$i
+    make_test_subdirs stage$i
+done
+
+msg "inspecting environment"
+
+CFG_OSTYPE=$(uname -s)
+CFG_CPUTYPE=$(uname -m)
+
+putvar CFG_SRC_DIR
+putvar CFG_BUILD_DIR
+putvar CFG_OSTYPE
+putvar CFG_CPUTYPE
+
+msg "looking for programs"
+probe_need CFG_GCC          gcc
+probe_need CFG_LLVM_CONFIG  llvm-config
+probe_need CFG_OCAMLC       ocamlc
+probe_need CFG_PERL         perl
+probe_need CFG_SED          sed
+
+probe CFG_VALGRIND         valgrind
+probe CFG_OCAMLOPT         ocamlopt
+probe CFG_OCAMLC_OPT       ocamlc.opt
+probe CFG_OCAMLOPT_OPT     ocamlopt.opt
+probe CFG_FLEXLINK         flexlink
+
+CFG_LLVM_VERSION=$(llvm-config --version)
+case $CFG_LLVM_VERSION in
+    (3.0svn | 3.0)
+    msg "found ok version of LLVM: $CFG_LLVM_VERSION"
+    ;;
+    (*)
+    err "bad LLVM version: $CFG_LLVM_VERSION, need >=3.0svn"
+    ;;
+esac
+CFG_LLVM_INCDIR=$(llvm-config --includedir)
+CFG_LLVM_BINDIR=$(llvm-config --bindir)
+CFG_LLVM_CXXFLAGS=$(llvm-config --cxxflags)
+CFG_LLVM_LDFLAGS=$(llvm-config --ldflags)
+CFG_LLVM_LIBS=$(llvm-config --libs)
+
+putvar CFG_LLVM_INCDIR
+putvar CFG_LLVM_BINDIR
+putvar CFG_LLVM_CXXFLAGS
+putvar CFG_LLVM_LDFLAGS
+putvar CFG_LLVM_LIBS
+
+copy ${CFG_SRC_DIR}Makefile.in ./Makefile
+
+echo "configure: complete"
diff --git a/src/Makefile b/src/Makefile
index 67a8743efee..630babf33c6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,3 +1,13 @@
+# Delete the built-in rules.
+# This speeds builds up substantially on win32, maybe elsewhere.
+
+.SUFFIXES:
+%:: %,v
+%:: RCS/%,v
+%:: RCS/%
+%:: s.%
+%:: SCCS/s.%
+
 ######################################################################
 # Auto-configuration
 ######################################################################
@@ -446,6 +456,7 @@ TEST_XFAILS_BOOT :=  $(TASK_XFAILS) \
                     test/run-pass/iter-ret.rs \
                     test/run-pass/leak-tag-copy.rs \
                     test/run-pass/lib-io.rs \
+                    test/run-pass/maybe-mutable.rs \
                     test/run-pass/mlist-cycle.rs \
                     test/run-pass/obj-as.rs \
                     test/run-pass/seq-compare.rs \
@@ -469,7 +480,6 @@ TEST_XFAILS_RUSTC := $(addprefix test/run-pass/, \
                         acyclic-unwind.rs \
                         alt-pattern-drop.rs \
                         alt-type-simple.rs \
-                        append-units.rs \
                         basic-1.rs \
                         basic-2.rs \
                         basic.rs \
@@ -489,6 +499,7 @@ TEST_XFAILS_RUSTC := $(addprefix test/run-pass/, \
                         lib-sha1.rs \
                         lib-sort.rs \
                         lib-str.rs \
+                        lib-str-buf.rs \
                         lib-task.rs \
                         lib-uint.rs \
                         lib-vec-str-conversions.rs \
diff --git a/src/Makefile.in b/src/Makefile.in
deleted file mode 100644
index fd4bd317067..00000000000
--- a/src/Makefile.in
+++ /dev/null
@@ -1,129 +0,0 @@
-######################################################################
-# Residual auto-configuration
-######################################################################
-
-include config.mk
-MKFILES := Makefile config.mk
-
-ifneq ($(MAKE_RESTARTS),)
-CFG_INFO := $(info cfg: make restarts: $(MAKE_RESTARTS))
-endif
-
-CFG_INFO := $(info cfg: building on $(CFG_OSTYPE) $(CFG_CPUTYPE))
-
-ifdef CFG_OCAMLC_OPT
-  $(info cfg: using ocaml native compiler)
-  OPT=.opt
-else
-  $(info cfg: using ocaml bytecode compiler)
-endif
-
-ifdef PROFILE_BOOT
-  $(info cfg: building bootstrap compiler with profiling (forcing native))
-  CFG_NATIVE_BOOT := 1
-  CFG_OCAMLOPT_PROFILE_FLAGS := -p
-endif
-
-ifdef DEBUG
-  $(info cfg: forcing bytecode bootstrap compiler)
-  CFG_NATIVE_BOOT :=
-endif
-
-ifdef CFG_NATIVE_BOOT
-  $(info cfg: building native bootstrap compiler)
-else
-  $(info cfg: building bytecode bootstrap compiler)
-endif
-
-ifdef NO_VALGRIND
-    CFG_VALGRIND :=
-endif
-
-
-######################################################################
-# Bootstrap compiler variables
-######################################################################
-
-# We must list them in link order.
-# Nobody calculates the link-order DAG automatically, sadly.
-
-BOOT_MLS :=                                              \
-    $(addsuffix .ml,                                     \
-        $(addprefix boot/util/, version fmt common bits) \
-        $(addprefix boot/driver/, session)               \
-        $(addprefix boot/fe/, ast token lexer parser     \
-          extfmt pexp item cexp fuzz)                    \
-        $(addprefix boot/be/, asm il abi)                \
-        $(addprefix boot/me/, walk semant resolve alias  \
-          simplify type dead layer effect typestate      \
-         loop layout transutil trans dwarf)              \
-        $(addprefix boot/be/, x86 ra pe elf macho)       \
-        $(addprefix boot/driver/, lib glue main))        \
-
-BOOT_CMOS := $(BOOT_MLS:.ml=.cmo)
-BOOT_CMXS := $(BOOT_MLS:.ml=.cmx)
-BOOT_OBJS := $(BOOT_MLS:.ml=.o)
-BOOT_CMIS := $(BOOT_MLS:.ml=.cmi)
-
-ML_DEP_INCS := -I $(S)boot/fe     -I $(S)boot/me   -I $(S)boot/be \
-               -I $(S)boot/driver -I $(S)boot/util
-
-ML_INCS        := $(ML_DEP_INCS)
-ML_LIBS        := unix.cma  nums.cma  bigarray.cma
-ML_NATIVE_LIBS := unix.cmxa nums.cmxa bigarray.cmxa
-OCAMLC_FLAGS   := -g $(ML_INCS) -w Ael -warn-error Ael
-
-
-######################################################################
-# Target-and-rule "utility variables"
-######################################################################
-
-ifdef VERBOSE
-  Q :=
-  E =
-else
-  Q := @
-  E = echo $(1)
-endif
-
-S := $(CFG_SRC_DIR)
-X := $(CFG_EXE_SUFFIX)
-
-# Look in src dir.
-VPATH := $(CFG_SRC_DIR)
-
-# Delete the built-in rules.
-.SUFFIXES:
-%:: %,v
-%:: RCS/%,v
-%:: RCS/%
-%:: s.%
-%:: SCCS/s.%
-
-######################################################################
-# Targets and rules
-######################################################################
-
-all: rustboot$(X)
-
-ifdef CFG_NATIVE_BOOT
-rustboot$(X): $(BOOT_CMXS) $(MKFILES)
-	@$(call E, compile: $@)
-	$(Q)ocamlopt$(OPT) -o $@ $(OCAMLOPT_FLAGS) $(ML_NATIVE_LIBS) \
-        $(BOOT_CMXS)
-else
-rustboot$(X): $(BOOT_CMOS) $(MKFILES)
-	@$(call E, compile: $@)
-	$(Q)ocamlc$(OPT) -o $@ $(OCAMLC_FLAGS) $(ML_LIBS) $(BOOT_CMOS)
-endif
-
-
-boot/util/version.ml: $(MKFILES)
-	$(Q)git log -1 \
-      --pretty=format:'let version = "prerelease (%h %ci)";;' >$@ || exit 1
-
-%.cmo: %.ml $(MKFILES)
-	@$(call E, compile: $@)
-	$(Q)ocamlc$(OPT) -c -o $@ $(OCAMLC_FLAGS) $<
-
-%.cmo: %.cmi $(MKFILES)
diff --git a/src/boot/fe/pexp.ml b/src/boot/fe/pexp.ml
index a5f3759a70c..c4dcfe1ddaa 100644
--- a/src/boot/fe/pexp.ml
+++ b/src/boot/fe/pexp.ml
@@ -159,7 +159,14 @@ and parse_effect (ps:pstate) : Ast.effect =
 
 and parse_mutability (ps:pstate) : Ast.mutability =
   match peek ps with
-      MUTABLE -> bump ps; Ast.MUT_mutable
+      MUTABLE ->
+        begin
+          (* HACK: ignore "mutable?" *)
+          bump ps;
+          match peek ps with
+              QUES -> bump ps; Ast.MUT_immutable
+            | _ -> Ast.MUT_mutable
+        end
     | _ -> Ast.MUT_immutable
 
 and parse_ty_fn
@@ -310,7 +317,12 @@ and parse_atomic_ty (ps:pstate) : Ast.ty =
 
     | MUTABLE ->
         bump ps;
-        Ast.TY_mutable (parse_ty ps)
+        begin
+          (* HACK: ignore "mutable?" *)
+          match peek ps with
+              QUES -> bump ps; parse_ty ps
+            | _ -> Ast.TY_mutable (parse_ty ps)
+        end
 
     | LPAREN ->
         begin
diff --git a/src/boot/me/type.ml b/src/boot/me/type.ml
index 87e8e4c1582..72bdd404493 100644
--- a/src/boot/me/type.ml
+++ b/src/boot/me/type.ml
@@ -993,8 +993,7 @@ let check_block (cx:Semant.ctxt) : (fn_ctx -> Ast.block -> unit) =
             let src_ty = check_atom ~deref:true src in
             let dst_ty = check_lval dst in
               match fundamental_ty dst_ty, fundamental_ty src_ty with
-                  Ast.TY_vec elt1, Ast.TY_vec elt2
-                | Ast.TY_vec elt1, elt2 ->
+                  Ast.TY_vec elt1, Ast.TY_vec elt2 ->
                     if elt1 = elt2
                     then ()
                     else
@@ -1002,7 +1001,6 @@ let check_block (cx:Semant.ctxt) : (fn_ctx -> Ast.block -> unit) =
                         "mismatched types in vec-append: %s += %s"
                         (pretty_ty_str dst_ty)
                         (pretty_ty_str src_ty)
-                | Ast.TY_str, (Ast.TY_mach Common.TY_u8)
                 | Ast.TY_str, Ast.TY_str -> ()
                 | _ ->
                     infer_lval src_ty dst;
diff --git a/src/comp/back/x86.rs b/src/comp/back/x86.rs
index 0ed79db453c..345603bb710 100644
--- a/src/comp/back/x86.rs
+++ b/src/comp/back/x86.rs
@@ -212,10 +212,10 @@ fn upcall_glue(int n_args) -> vec[str] {
         + store_esp_to_rust_sp_second_arg()
         + load_esp_from_runtime_sp_second_arg()
 
-        + vec("subl  $" + wstr(n_args + 1) + ", %esp   # esp -= args",
+        + vec("subl  $" + wstr(n_args) + ", %esp   # esp -= args",
               "andl  $~0xf, %esp    # align esp down")
 
-        + _vec.init_fn[str](carg, (n_args + 1) as uint)
+        + _vec.init_fn[str](carg, (n_args) as uint)
 
         +  vec("movl  %edx, %edi     # save task from edx to edi",
                "call  *%ecx          # call *%ecx",
@@ -268,7 +268,7 @@ fn get_module_asm() -> str {
                       rust_yield_glue()))
 
         + _vec.init_fn[str](bind decl_upcall_glue(align, prefix, _),
-                            abi.n_upcall_glues as uint);
+                            (abi.n_upcall_glues + 1) as uint);
 
     ret _str.connect(glues, "\n\n");
 }
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index 312166c499b..f0ce9a95f96 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -203,8 +203,8 @@ impure fn main(vec[str] args) {
                 alt (output_file) {
                     case (none[str]) {
                         let vec[str] parts = _str.split(ifile, '.' as u8);
-                        parts = _vec.pop[str](parts);
-                        parts += ".bc";
+                        _vec.pop[str](parts);
+                        parts += vec(".bc");
                         auto ofile = _str.concat(parts);
                         compile_input(sess, env, ifile, ofile, shared,
                                       library_search_paths);
diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs
index e23dbeed58a..605774fe92f 100644
--- a/src/comp/driver/session.rs
+++ b/src/comp/driver/session.rs
@@ -45,6 +45,15 @@ obj session(cfg targ) {
         fail;
     }
 
+    fn span_unimpl(span sp, str msg) {
+        log #fmt("%s:%u:%u:%u:%u: error: unimplemented %s",
+                 sp.filename,
+                 sp.lo.line, sp.lo.col,
+                 sp.hi.line, sp.hi.col,
+                 msg);
+        fail;
+    }
+
     fn unimpl(str msg) {
         log #fmt("error: unimplemented %s", msg);
         fail;
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index 1970f788b1c..ec93db55c92 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -91,6 +91,7 @@ tag pat_ {
 tag mutability {
     mut;
     imm;
+    maybe_mut;
 }
 
 tag opacity {
@@ -168,7 +169,6 @@ tag unop {
     bitnot;
     not;
     neg;
-    _mutable;
 }
 
 fn unop_to_str(unop op) -> str {
@@ -178,7 +178,6 @@ fn unop_to_str(unop op) -> str {
         case (bitnot) {ret "~";}
         case (not) {ret "!";}
         case (neg) {ret "-";}
-        case (_mutable) {ret "mutable";}
     }
 }
 
@@ -215,7 +214,7 @@ type field = rec(mutability mut, ident ident, @expr expr);
 
 type expr = spanned[expr_];
 tag expr_ {
-    expr_vec(vec[@expr], ann);
+    expr_vec(vec[@expr], mutability, ann);
     expr_tup(vec[elt], ann);
     expr_rec(vec[field], option.t[@expr], ann);
     expr_call(@expr, vec[@expr], ann);
@@ -263,7 +262,8 @@ tag lit_ {
 // NB: If you change this, you'll probably want to change the corresponding
 // type structure in middle/ty.rs as well.
 
-type ty_field = rec(ident ident, @ty ty);
+type mt = rec(@ty ty, mutability mut);
+type ty_field = rec(ident ident, mt mt);
 type ty_arg = rec(mode mode, @ty ty);
 // TODO: effect
 type ty_method = rec(proto proto, ident ident,
@@ -277,16 +277,15 @@ tag ty_ {
     ty_machine(util.common.ty_mach);
     ty_char;
     ty_str;
-    ty_box(@ty);
-    ty_vec(@ty);
+    ty_box(mt);
+    ty_vec(mt);
     ty_port(@ty);
     ty_chan(@ty);
-    ty_tup(vec[@ty]);
+    ty_tup(vec[mt]);
     ty_rec(vec[ty_field]);
     ty_fn(proto, vec[ty_arg], @ty);        // TODO: effect
     ty_obj(vec[ty_method]);
     ty_path(path, option.t[def]);
-    ty_mutable(@ty);
     ty_type;
     ty_constr(@ty, vec[@constr]);
 }
diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs
index ac2498485ce..4cf3765f4d3 100644
--- a/src/comp/front/eval.rs
+++ b/src/comp/front/eval.rs
@@ -13,7 +13,6 @@ import front.parser.new_parser;
 import front.parser.parse_mod_items;
 import util.common;
 import util.common.filename;
-import util.common.append;
 import util.common.span;
 import util.common.new_str_hash;
 
@@ -394,7 +393,7 @@ impure fn eval_crate_directive(parser p,
             auto im = ast.item_mod(id, m0, next_id);
             auto i = @spanned(cdir.span, cdir.span, im);
             ast.index_item(index, i);
-            append[@ast.item](items, i);
+            _vec.push[@ast.item](items, i);
         }
 
         case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) {
@@ -412,11 +411,11 @@ impure fn eval_crate_directive(parser p,
             auto im = ast.item_mod(id, m0, p.next_def_id());
             auto i = @spanned(cdir.span, cdir.span, im);
             ast.index_item(index, i);
-            append[@ast.item](items, i);
+            _vec.push[@ast.item](items, i);
         }
 
         case (ast.cdir_view_item(?vi)) {
-            append[@ast.view_item](view_items, vi);
+            _vec.push[@ast.view_item](view_items, vi);
             ast.index_view_item(index, vi);
         }
 
diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs
index 255614d0f07..0a32a851dac 100644
--- a/src/comp/front/extfmt.rs
+++ b/src/comp/front/extfmt.rs
@@ -113,7 +113,7 @@ fn parse_fmt_string(str s) -> vec[piece] {
     fn flush_buf(str buf, &vec[piece] pieces) -> str {
         if (_str.byte_len(buf) > 0u) {
             auto piece = piece_string(buf);
-            pieces += piece;
+            pieces += vec(piece);
         }
         ret "";
     }
@@ -133,7 +133,7 @@ fn parse_fmt_string(str s) -> vec[piece] {
             } else {
                 buf = flush_buf(buf, pieces);
                 auto res = parse_conversion(s, i, lim);
-                pieces += res._0;
+                pieces += vec(res._0);
                 i = res._1;
             }
         } else {
diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs
index 95fd32c7b49..403558e2934 100644
--- a/src/comp/front/lexer.rs
+++ b/src/comp/front/lexer.rs
@@ -420,7 +420,7 @@ impure fn next_token(reader rdr) -> token.token {
 
     if (is_alpha(c) || c == '_') {
         while (is_alnum(c) || c == '_') {
-            accum_str += (c as u8);
+            _str.push_byte(accum_str, (c as u8));
             rdr.bump();
             c = rdr.curr();
         }
@@ -580,23 +580,23 @@ impure fn next_token(reader rdr) -> token.token {
                         alt (rdr.next()) {
                             case ('n') {
                                 rdr.bump();
-                                accum_str += '\n' as u8;
+                                _str.push_byte(accum_str, '\n' as u8);
                             }
                             case ('r') {
                                 rdr.bump();
-                                accum_str += '\r' as u8;
+                                _str.push_byte(accum_str, '\r' as u8);
                             }
                             case ('t') {
                                 rdr.bump();
-                                accum_str += '\t' as u8;
+                                _str.push_byte(accum_str, '\t' as u8);
                             }
                             case ('\\') {
                                 rdr.bump();
-                                accum_str += '\\' as u8;
+                                _str.push_byte(accum_str, '\\' as u8);
                             }
                             case ('"') {
                                 rdr.bump();
-                                accum_str += '"' as u8;
+                                _str.push_byte(accum_str, '"' as u8);
                             }
                             // FIXME: unicode numeric escapes.
                             case (?c2) {
@@ -607,7 +607,7 @@ impure fn next_token(reader rdr) -> token.token {
                         }
                     }
                     case (_) {
-                        accum_str += rdr.curr() as u8;
+                        _str.push_byte(accum_str, rdr.curr() as u8);
                     }
                 }
                 rdr.bump();
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index a5c79926b63..028b8a3132d 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -9,7 +9,6 @@ import std.map.hashmap;
 import driver.session;
 import util.common;
 import util.common.filename;
-import util.common.append;
 import util.common.span;
 import util.common.new_str_hash;
 
@@ -190,6 +189,11 @@ impure fn parse_ty_fn(ast.proto proto, parser p,
         if (p.peek() == token.BINOP(token.AND)) {
             p.bump();
             mode = ast.alias;
+
+            if (p.peek() == token.MUTABLE) {
+                p.bump();
+                // TODO: handle mutable alias args
+            }
         } else {
             mode = ast.val;
         }
@@ -263,10 +267,16 @@ impure fn parse_ty_obj(parser p, &mutable ast.span hi) -> ast.ty_ {
     ret ast.ty_obj(meths.node);
 }
 
+impure fn parse_mt(parser p) -> ast.mt {
+    auto mut = parse_mutability(p);
+    auto t = parse_ty(p);
+    ret rec(ty=t, mut=mut);
+}
+
 impure fn parse_ty_field(parser p) -> ast.ty_field {
-    auto ty = parse_ty(p);
+    auto mt = parse_mt(p);
     auto id = parse_ident(p);
-    ret rec(ident=id, ty=ty);
+    ret rec(ident=id, mt=mt);
 }
 
 impure fn parse_constr_arg(parser p) -> @ast.constr_arg {
@@ -303,7 +313,7 @@ impure fn parse_constrs(parser p) -> common.spanned[vec[@ast.constr]] {
                 case (token.IDENT(_)) {
                     auto constr = parse_ty_constr(p);
                     hi = constr.span;
-                    append[@ast.constr](constrs, constr);
+                    _vec.push[@ast.constr](constrs, constr);
                     if (p.peek() == token.COMMA) {
                         p.bump();
                         more = false;
@@ -361,25 +371,25 @@ impure fn parse_ty(parser p) -> @ast.ty {
 
         case (token.AT) {
             p.bump();
-            auto t0 = parse_ty(p);
-            hi = t0.span;
-            t = ast.ty_box(t0);
+            auto mt = parse_mt(p);
+            hi = mt.ty.span;
+            t = ast.ty_box(mt);
         }
 
         case (token.VEC) {
             p.bump();
             expect(p, token.LBRACKET);
-            t = ast.ty_vec(parse_ty(p));
+            t = ast.ty_vec(parse_mt(p));
             hi = p.get_span();
             expect(p, token.RBRACKET);
         }
 
         case (token.TUP) {
             p.bump();
-            auto f = parse_ty; // FIXME: trans_const_lval bug
-            auto elems = parse_seq[@ast.ty] (token.LPAREN,
-                                             token.RPAREN,
-                                             some(token.COMMA), f, p);
+            auto f = parse_mt; // FIXME: trans_const_lval bug
+            auto elems = parse_seq[ast.mt] (token.LPAREN,
+                                            token.RPAREN,
+                                            some(token.COMMA), f, p);
             hi = elems.span;
             t = ast.ty_tup(elems.node);
         }
@@ -396,13 +406,6 @@ impure fn parse_ty(parser p) -> @ast.ty {
             t = ast.ty_rec(elems.node);
         }
 
-        case (token.MUTABLE) {
-            p.bump();
-            auto t0 = parse_ty(p);
-            hi = t0.span;
-            t = ast.ty_mutable(t0);
-        }
-
         case (token.FN) {
             auto flo = p.get_span();
             p.bump();
@@ -464,20 +467,22 @@ impure fn parse_arg(parser p) -> ast.arg {
     if (p.peek() == token.BINOP(token.AND)) {
         m = ast.alias;
         p.bump();
+
+        if (p.peek() == token.MUTABLE) {
+            // TODO: handle mutable alias args
+            p.bump();
+        }
     }
     let @ast.ty t = parse_ty(p);
     let ast.ident i = parse_ident(p);
     ret rec(mode=m, ty=t, ident=i, id=p.next_def_id());
 }
 
-impure fn parse_seq[T](token.token bra,
-                      token.token ket,
-                      option.t[token.token] sep,
-                      (impure fn(parser) -> T) f,
-                      parser p) -> util.common.spanned[vec[T]] {
+impure fn parse_seq_to_end[T](token.token ket,
+                              option.t[token.token] sep,
+                              (impure fn(parser) -> T) f,
+                              parser p) -> vec[T] {
     let bool first = true;
-    auto lo = p.get_span();
-    expect(p, bra);
     let vec[T] v = vec();
     while (p.peek() != ket) {
         alt(sep) {
@@ -495,9 +500,20 @@ impure fn parse_seq[T](token.token bra,
         let T t = f(p);
         v += vec(t);
     }
-    auto hi = p.get_span();
     expect(p, ket);
-    ret spanned(lo, hi, v);
+    ret v;
+}
+
+impure fn parse_seq[T](token.token bra,
+                      token.token ket,
+                      option.t[token.token] sep,
+                      (impure fn(parser) -> T) f,
+                      parser p) -> util.common.spanned[vec[T]] {
+    auto lo = p.get_span();
+    expect(p, bra);
+    auto result = parse_seq_to_end[T](ket, sep, f, p);
+    auto hi = p.get_span();
+    ret spanned(lo, hi, result);
 }
 
 impure fn parse_lit(parser p) -> ast.lit {
@@ -573,7 +589,7 @@ impure fn parse_path(parser p, greed g) -> ast.path {
         alt (p.peek()) {
             case (token.IDENT(?i)) {
                 hi = p.get_span();
-                ids += i;
+                ids += vec(i);
                 p.bump();
                 if (p.peek() == token.DOT) {
                     if (g == GREEDY) {
@@ -596,16 +612,20 @@ impure fn parse_path(parser p, greed g) -> ast.path {
     ret spanned(lo, tys.span, rec(idents=ids, types=tys.node));
 }
 
-impure fn parse_mutabliity(parser p) -> ast.mutability {
+impure fn parse_mutability(parser p) -> ast.mutability {
     if (p.peek() == token.MUTABLE) {
         p.bump();
+        if (p.peek() == token.QUES) {
+            p.bump();
+            ret ast.maybe_mut;
+        }
         ret ast.mut;
     }
     ret ast.imm;
 }
 
 impure fn parse_field(parser p) -> ast.field {
-    auto m = parse_mutabliity(p);
+    auto m = parse_mutability(p);
     auto i = parse_ident(p);
     expect(p, token.EQ);
     auto e = parse_expr(p);
@@ -651,7 +671,7 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr {
         case (token.TUP) {
             p.bump();
             impure fn parse_elt(parser p) -> ast.elt {
-                auto m = parse_mutabliity(p);
+                auto m = parse_mutability(p);
                 auto e = parse_expr(p);
                 ret rec(mut=m, expr=e);
             }
@@ -668,12 +688,15 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr {
         case (token.VEC) {
             p.bump();
             auto pf = parse_expr;
-            auto es = parse_seq[@ast.expr](token.LPAREN,
-                                           token.RPAREN,
-                                           some(token.COMMA),
-                                           pf, p);
-            hi = es.span;
-            ex = ast.expr_vec(es.node, ast.ann_none);
+
+            expect(p, token.LPAREN);
+            auto mut = parse_mutability(p);
+
+            auto es = parse_seq_to_end[@ast.expr](token.RPAREN,
+                                                  some(token.COMMA),
+                                                  pf, p);
+            hi = p.get_span();
+            ex = ast.expr_vec(es, mut, ast.ann_none);
         }
 
         case (token.REC) {
@@ -699,7 +722,7 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr {
                     }
                     case (token.COMMA) {
                         p.bump();
-                        fields += parse_field(p);
+                        fields += vec(parse_field(p));
                     }
                     case (?t) {
                         unexpected(p, t);
@@ -877,7 +900,7 @@ impure fn extend_expr_by_ident(parser p, span lo, span hi,
         case (ast.expr_path(?pth, ?def, ?ann)) {
             if (_vec.len[@ast.ty](pth.node.types) == 0u) {
                 auto idents_ = pth.node.idents;
-                idents_ += i;
+                idents_ += vec(i);
                 auto tys = parse_ty_args(p, hi);
                 auto pth_ = spanned(pth.span, tys.span,
                                     rec(idents=idents_,
@@ -1005,13 +1028,6 @@ impure fn parse_prefix_expr(parser p) -> @ast.expr {
             ex = ast.expr_unary(ast.box, e, ast.ann_none);
         }
 
-        case (token.MUTABLE) {
-            p.bump();
-            auto e = parse_prefix_expr(p);
-            hi = e.span;
-            ex = ast.expr_unary(ast._mutable, e, ast.ann_none);
-        }
-
         case (_) {
             ret parse_dot_or_call_expr(p);
         }
@@ -1559,7 +1575,7 @@ fn stmt_ends_with_semi(@ast.stmt stmt) -> bool {
         }
         case (ast.stmt_expr(?e)) {
             alt (e.node) {
-                case (ast.expr_vec(_,_))        { ret true; }
+                case (ast.expr_vec(_,_,_))      { ret true; }
                 case (ast.expr_tup(_,_))        { ret true; }
                 case (ast.expr_rec(_,_,_))      { ret true; }
                 case (ast.expr_call(_,_,_))     { ret true; }
@@ -1723,6 +1739,7 @@ impure fn parse_item_fn_or_iter(parser p, ast.effect eff) -> @ast.item {
 
 
 impure fn parse_obj_field(parser p) -> ast.obj_field {
+    auto mut = parse_mutability(p); // TODO: store this, use it in typeck
     auto ty = parse_ty(p);
     auto ident = parse_ident(p);
     ret rec(ty=ty, ident=ident, id=p.next_def_id(), ann=ast.ann_none);
@@ -1763,8 +1780,8 @@ impure fn parse_item_obj(parser p, ast.layer lyr) -> @ast.item {
                 dtor = some[ast.block](parse_block(p));
             }
             case (_) {
-                append[@ast.method](meths,
-                                    parse_method(p));
+                _vec.push[@ast.method](meths,
+                                       parse_method(p));
             }
         }
     }
@@ -2161,12 +2178,11 @@ impure fn parse_rest_import_name(parser p, ast.ident first,
         -> @ast.view_item {
     auto lo = p.get_span();
     auto hi = lo;
-    let vec[ast.ident] identifiers = vec();
-    identifiers += first;
+    let vec[ast.ident] identifiers = vec(first);
     while (p.peek() != token.SEMI) {
         expect(p, token.DOT);
         auto i = parse_ident(p);
-        identifiers += i;
+        identifiers += vec(i);
     }
     p.bump();
     auto defined_id;
@@ -2402,7 +2418,7 @@ impure fn parse_crate_directives(parser p, token.token term)
 
     while (p.peek() != term) {
         auto cdir = @parse_crate_directive(p);
-        append[@ast.crate_directive](cdirs, cdir);
+        _vec.push[@ast.crate_directive](cdirs, cdir);
     }
 
     ret cdirs;
diff --git a/src/comp/front/token.rs b/src/comp/front/token.rs
index 8c594054e40..62c6406a6b8 100644
--- a/src/comp/front/token.rs
+++ b/src/comp/front/token.rs
@@ -3,6 +3,7 @@ import util.common.ty_mach_to_str;
 import util.common.new_str_hash;
 import std._int;
 import std._uint;
+import std._str;
 
 tag binop {
     PLUS;
@@ -302,8 +303,8 @@ fn to_str(token t) -> str {
         case (LIT_CHAR(?c)) {
             // FIXME: escape and encode.
             auto tmp = "'";
-            tmp += c as u8;
-            tmp += '\'' as u8;
+            _str.push_byte(tmp, c as u8);
+            _str.push_byte(tmp, '\'' as u8);
             ret tmp;
         }
 
diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs
index 73b2cab32a9..703c7ea4400 100644
--- a/src/comp/middle/fold.rs
+++ b/src/comp/middle/fold.rs
@@ -7,7 +7,6 @@ import util.common.new_str_hash;
 import util.common.spanned;
 import util.common.span;
 import util.common.ty_mach;
-import util.common.append;
 
 import front.ast;
 import front.ast.fn_decl;
@@ -29,6 +28,7 @@ import front.ast.arm;
 import front.ast.def;
 import front.ast.def_id;
 import front.ast.ann;
+import front.ast.mt;
 
 import std._uint;
 import std._vec;
@@ -47,10 +47,10 @@ type ast_fold[ENV] =
      (fn(&ENV e, &span sp, ty_mach tm) -> @ty)    fold_ty_machine,
      (fn(&ENV e, &span sp) -> @ty)                fold_ty_char,
      (fn(&ENV e, &span sp) -> @ty)                fold_ty_str,
-     (fn(&ENV e, &span sp, @ty t) -> @ty)         fold_ty_box,
-     (fn(&ENV e, &span sp, @ty t) -> @ty)         fold_ty_vec,
+     (fn(&ENV e, &span sp, &mt tm) -> @ty)        fold_ty_box,
+     (fn(&ENV e, &span sp, &mt tm) -> @ty)        fold_ty_vec,
 
-     (fn(&ENV e, &span sp, vec[@ty] elts) -> @ty) fold_ty_tup,
+     (fn(&ENV e, &span sp, vec[mt] elts) -> @ty)  fold_ty_tup,
 
      (fn(&ENV e, &span sp,
          vec[ast.ty_field] elts) -> @ty)          fold_ty_rec,
@@ -66,13 +66,13 @@ type ast_fold[ENV] =
      (fn(&ENV e, &span sp, ast.path p,
          &option.t[def] d) -> @ty)                fold_ty_path,
 
-     (fn(&ENV e, &span sp, @ty t) -> @ty)         fold_ty_mutable,
      (fn(&ENV e, &span sp, @ty t) -> @ty)         fold_ty_chan,
      (fn(&ENV e, &span sp, @ty t) -> @ty)         fold_ty_port,
 
      // Expr folds.
      (fn(&ENV e, &span sp,
-         vec[@expr] es, ann a) -> @expr)          fold_expr_vec,
+         vec[@expr] es, ast.mutability mut,
+         ann a) -> @expr)                         fold_expr_vec,
 
      (fn(&ENV e, &span sp,
          vec[ast.elt] es, ann a) -> @expr)        fold_expr_tup,
@@ -318,7 +318,7 @@ type ast_fold[ENV] =
 fn fold_path[ENV](&ENV env, ast_fold[ENV] fld, &path p) -> path {
     let vec[@ast.ty] tys_ = vec();
     for (@ast.ty t in p.node.types) {
-        append[@ast.ty](tys_, fold_ty(env, fld, t));
+        _vec.push[@ast.ty](tys_, fold_ty(env, fld, t));
     }
     let ast.path_ p_ = rec(idents=p.node.idents, types=tys_);
     ret fld.fold_path(env, p.span, p_);
@@ -344,20 +344,21 @@ fn fold_ty[ENV](&ENV env, ast_fold[ENV] fld, @ty t) -> @ty {
         case (ast.ty_char) { ret fld.fold_ty_char(env_, t.span); }
         case (ast.ty_str) { ret fld.fold_ty_str(env_, t.span); }
 
-        case (ast.ty_box(?ty)) {
-            auto ty_ = fold_ty(env, fld, ty);
-            ret fld.fold_ty_box(env_, t.span, ty_);
+        case (ast.ty_box(?tm)) {
+            auto ty_ = fold_ty(env, fld, tm.ty);
+            ret fld.fold_ty_box(env_, t.span, rec(ty=ty_, mut=tm.mut));
         }
 
-        case (ast.ty_vec(?ty)) {
-            auto ty_ = fold_ty(env, fld, ty);
-            ret fld.fold_ty_vec(env_, t.span, ty_);
+        case (ast.ty_vec(?tm)) {
+            auto ty_ = fold_ty(env, fld, tm.ty);
+            ret fld.fold_ty_vec(env_, t.span, rec(ty=ty_, mut=tm.mut));
         }
 
         case (ast.ty_tup(?elts)) {
-            let vec[@ty] elts_ = vec();
-            for (@ty elt in elts) {
-                append[@ty](elts_,fold_ty(env, fld, elt));
+            let vec[mt] elts_ = vec();
+            for (mt elt in elts) {
+                auto ty_ = fold_ty(env, fld, elt.ty);
+                _vec.push[mt](elts_, rec(ty=ty_, mut=elt.mut));
             }
             ret fld.fold_ty_tup(env_, t.span, elts_);
         }
@@ -365,8 +366,9 @@ fn fold_ty[ENV](&ENV env, ast_fold[ENV] fld, @ty t) -> @ty {
         case (ast.ty_rec(?flds)) {
             let vec[ast.ty_field] flds_ = vec();
             for (ast.ty_field f in flds) {
-                append[ast.ty_field]
-                    (flds_, rec(ty=fold_ty(env, fld, f.ty) with f));
+                auto ty_ = fold_ty(env, fld, f.mt.ty);
+                _vec.push[ast.ty_field]
+                    (flds_, rec(mt=rec(ty=ty_, mut=f.mt.mut) with f));
             }
             ret fld.fold_ty_rec(env_, t.span, flds_);
         }
@@ -378,7 +380,7 @@ fn fold_ty[ENV](&ENV env, ast_fold[ENV] fld, @ty t) -> @ty {
                                       m.inputs, m.output);
                 alt (tfn.node) {
                     case (ast.ty_fn(?p, ?ins, ?out)) {
-                        append[ast.ty_method]
+                        _vec.push[ast.ty_method]
                             (meths_, rec(proto=p, inputs=ins, output=out
                                          with m));
                     }
@@ -392,11 +394,6 @@ fn fold_ty[ENV](&ENV env, ast_fold[ENV] fld, @ty t) -> @ty {
             ret fld.fold_ty_path(env_, t.span, pth_, ref_opt);
         }
 
-        case (ast.ty_mutable(?ty)) {
-            auto ty_ = fold_ty(env, fld, ty);
-            ret fld.fold_ty_mutable(env_, t.span, ty_);
-        }
-
         case (ast.ty_fn(?proto, ?inputs, ?output)) {
             ret fold_ty_fn(env_, fld, t.span, proto, inputs, output);
         }
@@ -494,7 +491,7 @@ fn fold_pat[ENV](&ENV env, ast_fold[ENV] fld, @ast.pat p) -> @ast.pat {
 fn fold_exprs[ENV](&ENV env, ast_fold[ENV] fld, vec[@expr] es) -> vec[@expr] {
     let vec[@expr] exprs = vec();
     for (@expr e in es) {
-        append[@expr](exprs, fold_expr(env, fld, e));
+        _vec.push[@expr](exprs, fold_expr(env, fld, e));
     }
     ret exprs;
 }
@@ -517,15 +514,15 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
     }
 
     alt (e.node) {
-        case (ast.expr_vec(?es, ?t)) {
+        case (ast.expr_vec(?es, ?mut, ?t)) {
             auto ees = fold_exprs(env_, fld, es);
-            ret fld.fold_expr_vec(env_, e.span, ees, t);
+            ret fld.fold_expr_vec(env_, e.span, ees, mut, t);
         }
 
         case (ast.expr_tup(?es, ?t)) {
             let vec[ast.elt] elts = vec();
             for (ast.elt e in es) {
-                elts += fold_tup_elt[ENV](env, fld, e);
+                elts += vec(fold_tup_elt[ENV](env, fld, e));
             }
             ret fld.fold_expr_tup(env_, e.span, elts, t);
         }
@@ -534,7 +531,7 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
             let vec[ast.field] fields = vec();
             let option.t[@expr] b = none[@expr];
             for (ast.field f in fs) {
-                fields += fold_rec_field(env, fld, f);
+                fields += vec(fold_rec_field(env, fld, f));
             }
             alt (base) {
                 case (none[@ast.expr]) { }
@@ -557,7 +554,7 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
             for (option.t[@ast.expr] t_opt in args_opt) {
                 alt (t_opt) {
                     case (none[@ast.expr]) {
-                        aargs_opt += none[@ast.expr];
+                        aargs_opt += vec(none[@ast.expr]);
                     }
                     case (some[@ast.expr](?e)) {
                         aargs_opt += vec(some(fold_expr(env_, fld, e)));
@@ -779,7 +776,7 @@ fn fold_block[ENV](&ENV env, ast_fold[ENV] fld, &block blk) -> block {
     let vec[@ast.stmt] stmts = vec();
     for (@ast.stmt s in blk.node.stmts) {
         auto new_stmt = fold_stmt[ENV](env_, fld, s);
-        append[@ast.stmt](stmts, new_stmt);
+        _vec.push[@ast.stmt](stmts, new_stmt);
         ast.index_stmt(index, new_stmt);
     }
 
@@ -812,7 +809,7 @@ fn fold_fn_decl[ENV](&ENV env, ast_fold[ENV] fld,
                      &ast.fn_decl decl) -> ast.fn_decl {
     let vec[ast.arg] inputs = vec();
     for (ast.arg a in decl.inputs) {
-        inputs += fold_arg(env, fld, a);
+        inputs += vec(fold_arg(env, fld, a));
     }
     auto output = fold_ty[ENV](env, fld, decl.output);
     ret fld.fold_fn_decl(env, decl.effect, inputs, output);
@@ -846,7 +843,7 @@ fn fold_obj[ENV](&ENV env, ast_fold[ENV] fld, &ast._obj ob) -> ast._obj {
     let vec[ast.obj_field] fields = vec();
     let vec[@ast.method] meths = vec();
     for (ast.obj_field f in ob.fields) {
-        fields += fold_obj_field(env, fld, f);
+        fields += vec(fold_obj_field(env, fld, f));
     }
     let option.t[block] dtor = none[block];
     alt (ob.dtor) {
@@ -867,7 +864,7 @@ fn fold_obj[ENV](&ENV env, ast_fold[ENV] fld, &ast._obj ob) -> ast._obj {
                                                 m.node.ann),
                                span=m.span);
         let ENV _env = fld.update_env_for_item(env, i);
-        append[@ast.method](meths, fold_method(_env, fld, m));
+        _vec.push[@ast.method](meths, fold_method(_env, fld, m));
     }
     ret fld.fold_obj(env, fields, meths, dtor);
 }
@@ -944,8 +941,8 @@ fn fold_item[ENV](&ENV env, ast_fold[ENV] fld, @item i) -> @item {
                     auto new_ty = fold_ty[ENV](env_, fld, va.ty);
                     new_args += vec(rec(ty=new_ty, id=va.id));
                 }
-                new_variants += rec(name=v.name, args=new_args, id=v.id,
-                                    ann=v.ann);
+                new_variants += vec(rec(name=v.name, args=new_args, id=v.id,
+                                        ann=v.ann));
             }
             ret fld.fold_item_tag(env_, i.span, ident, new_variants,
                                   ty_params, id);
@@ -969,13 +966,13 @@ fn fold_mod[ENV](&ENV e, ast_fold[ENV] fld, &ast._mod m) -> ast._mod {
 
     for (@view_item vi in m.view_items) {
         auto new_vi = fold_view_item[ENV](e, fld, vi);
-        append[@view_item](view_items, new_vi);
+        _vec.push[@view_item](view_items, new_vi);
         ast.index_view_item(index, new_vi);
     }
 
     for (@item i in m.items) {
         auto new_item = fold_item[ENV](e, fld, i);
-        append[@item](items, new_item);
+        _vec.push[@item](items, new_item);
         ast.index_item(index, new_item);
     }
 
@@ -1009,12 +1006,12 @@ fn fold_native_mod[ENV](&ENV e, ast_fold[ENV] fld,
 
     for (@view_item vi in m.view_items) {
         auto new_vi = fold_view_item[ENV](e, fld, vi);
-        append[@view_item](view_items, new_vi);
+        _vec.push[@view_item](view_items, new_vi);
     }
 
     for (@native_item i in m.items) {
         auto new_item = fold_native_item[ENV](e, fld, i);
-        append[@native_item](items, new_item);
+        _vec.push[@native_item](items, new_item);
         ast.index_native_item(index, new_item);
     }
 
@@ -1078,16 +1075,16 @@ fn identity_fold_ty_str[ENV](&ENV env, &span sp) -> @ty {
     ret @respan(sp, ast.ty_str);
 }
 
-fn identity_fold_ty_box[ENV](&ENV env, &span sp, @ty t) -> @ty {
-    ret @respan(sp, ast.ty_box(t));
+fn identity_fold_ty_box[ENV](&ENV env, &span sp, &mt tm) -> @ty {
+    ret @respan(sp, ast.ty_box(tm));
 }
 
-fn identity_fold_ty_vec[ENV](&ENV env, &span sp, @ty t) -> @ty {
-    ret @respan(sp, ast.ty_vec(t));
+fn identity_fold_ty_vec[ENV](&ENV env, &span sp, &mt tm) -> @ty {
+    ret @respan(sp, ast.ty_vec(tm));
 }
 
 fn identity_fold_ty_tup[ENV](&ENV env, &span sp,
-                             vec[@ty] elts) -> @ty {
+                             vec[mt] elts) -> @ty {
     ret @respan(sp, ast.ty_tup(elts));
 }
 
@@ -1113,10 +1110,6 @@ fn identity_fold_ty_path[ENV](&ENV env, &span sp, ast.path p,
     ret @respan(sp, ast.ty_path(p, d));
 }
 
-fn identity_fold_ty_mutable[ENV](&ENV env, &span sp, @ty t) -> @ty {
-    ret @respan(sp, ast.ty_mutable(t));
-}
-
 fn identity_fold_ty_chan[ENV](&ENV env, &span sp, @ty t) -> @ty {
     ret @respan(sp, ast.ty_chan(t));
 }
@@ -1128,8 +1121,8 @@ fn identity_fold_ty_port[ENV](&ENV env, &span sp, @ty t) -> @ty {
 // Expr identities.
 
 fn identity_fold_expr_vec[ENV](&ENV env, &span sp, vec[@expr] es,
-                               ann a) -> @expr {
-    ret @respan(sp, ast.expr_vec(es, a));
+                               ast.mutability mut, ann a) -> @expr {
+    ret @respan(sp, ast.expr_vec(es, mut, a));
 }
 
 fn identity_fold_expr_tup[ENV](&ENV env, &span sp,
@@ -1529,11 +1522,10 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
          fold_ty_obj     = bind identity_fold_ty_obj[ENV](_,_,_),
          fold_ty_fn      = bind identity_fold_ty_fn[ENV](_,_,_,_,_),
          fold_ty_path    = bind identity_fold_ty_path[ENV](_,_,_,_),
-         fold_ty_mutable = bind identity_fold_ty_mutable[ENV](_,_,_),
          fold_ty_chan    = bind identity_fold_ty_chan[ENV](_,_,_),
          fold_ty_port    = bind identity_fold_ty_port[ENV](_,_,_),
 
-         fold_expr_vec    = bind identity_fold_expr_vec[ENV](_,_,_,_),
+         fold_expr_vec    = bind identity_fold_expr_vec[ENV](_,_,_,_,_),
          fold_expr_tup    = bind identity_fold_expr_tup[ENV](_,_,_,_),
          fold_expr_rec    = bind identity_fold_expr_rec[ENV](_,_,_,_,_),
          fold_expr_call   = bind identity_fold_expr_call[ENV](_,_,_,_,_),
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index d0569afc2a2..2ef619cb4d2 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -20,7 +20,6 @@ import middle.ty.pat_ty;
 import middle.ty.plain_ty;
 
 import util.common;
-import util.common.append;
 import util.common.istr;
 import util.common.new_def_hash;
 import util.common.new_str_hash;
@@ -476,7 +475,7 @@ fn type_of_explicit_args(@crate_ctxt cx,
     for (ty.arg arg in inputs) {
         if (ty.type_has_dynamic_size(arg.ty)) {
             check (arg.mode == ast.alias);
-            atys += T_typaram_ptr(cx.tn);
+            atys += vec(T_typaram_ptr(cx.tn));
         } else {
             let TypeRef t;
             alt (arg.mode) {
@@ -487,7 +486,7 @@ fn type_of_explicit_args(@crate_ctxt cx,
                     t = type_of_inner(cx, arg.ty, false);
                 }
             }
-            atys += t;
+            atys += vec(t);
         }
     }
     ret atys;
@@ -510,22 +509,22 @@ fn type_of_fn_full(@crate_ctxt cx,
 
     // Arg 0: Output pointer.
     if (ty.type_has_dynamic_size(output)) {
-        atys += T_typaram_ptr(cx.tn);
+        atys += vec(T_typaram_ptr(cx.tn));
     } else {
-        atys += T_ptr(type_of_inner(cx, output, false));
+        atys += vec(T_ptr(type_of_inner(cx, output, false)));
     }
 
     // Arg 1: Task pointer.
-    atys += T_taskptr(cx.tn);
+    atys += vec(T_taskptr(cx.tn));
 
     // Arg 2: Env (closure-bindings / self-obj)
     alt (obj_self) {
         case (some[TypeRef](?t)) {
             check (t as int != 0);
-            atys += t;
+            atys += vec(t);
         }
         case (_) {
-            atys += T_opaque_closure_ptr(cx.tn);
+            atys += vec(T_opaque_closure_ptr(cx.tn));
         }
     }
 
@@ -533,7 +532,7 @@ fn type_of_fn_full(@crate_ctxt cx,
     if (obj_self == none[TypeRef]) {
         auto i = 0u;
         while (i < ty_param_count) {
-            atys += T_ptr(T_tydesc(cx.tn));
+            atys += vec(T_ptr(T_tydesc(cx.tn)));
             i += 1u;
         }
     }
@@ -542,10 +541,11 @@ fn type_of_fn_full(@crate_ctxt cx,
         // If it's an iter, the 'output' type of the iter is actually the
         // *input* type of the function we're given as our iter-block
         // argument.
-        atys += T_fn_pair(cx.tn,
+        atys +=
+            vec(T_fn_pair(cx.tn,
                           type_of_fn_full(cx, ast.proto_fn, none[TypeRef],
                                           vec(rec(mode=ast.val, ty=output)),
-                                          plain_ty(ty.ty_nil), 0u));
+                                          plain_ty(ty.ty_nil), 0u)));
     }
 
     // ... then explicit args.
@@ -568,12 +568,12 @@ fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
                      @ty.t output) -> TypeRef {
     let vec[TypeRef] atys = vec();
     if (abi == ast.native_abi_rust) {
-        atys += T_taskptr(cx.tn);
+        atys += vec(T_taskptr(cx.tn));
         auto t = ty.ty_native_fn(abi, inputs, output);
         auto ty_param_count = ty.count_ty_params(plain_ty(t));
         auto i = 0u;
         while (i < ty_param_count) {
-            atys += T_ptr(T_tydesc(cx.tn));
+            atys += vec(T_ptr(T_tydesc(cx.tn)));
             i += 1u;
         }
     }
@@ -614,23 +614,23 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
                 llty = T_tag(cx.tn, size);
             }
         }
-        case (ty.ty_box(?t)) {
-            llty = T_ptr(T_box(type_of_inner(cx, t, true)));
+        case (ty.ty_box(?mt)) {
+            llty = T_ptr(T_box(type_of_inner(cx, mt.ty, true)));
         }
-        case (ty.ty_vec(?t)) {
-            llty = T_ptr(T_vec(type_of_inner(cx, t, true)));
+        case (ty.ty_vec(?mt)) {
+            llty = T_ptr(T_vec(type_of_inner(cx, mt.ty, true)));
         }
         case (ty.ty_tup(?elts)) {
             let vec[TypeRef] tys = vec();
-            for (@ty.t elt in elts) {
-                tys += type_of_inner(cx, elt, boxed);
+            for (ty.mt elt in elts) {
+                tys += vec(type_of_inner(cx, elt.ty, boxed));
             }
             llty = T_struct(tys);
         }
         case (ty.ty_rec(?fields)) {
             let vec[TypeRef] tys = vec();
             for (ty.field f in fields) {
-                tys += type_of_inner(cx, f.ty, boxed);
+                tys += vec(type_of_inner(cx, f.mt.ty, boxed));
             }
             llty = T_struct(tys);
         }
@@ -650,7 +650,7 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
                     type_of_fn_full(cx, m.proto,
                                     some[TypeRef](self_ty),
                                     m.inputs, m.output, 0u);
-                mtys += T_ptr(mty);
+                mtys += vec(T_ptr(mty));
             }
             let TypeRef vtbl = T_struct(mtys);
             let TypeRef pair = T_struct(vec(T_ptr(vtbl),
@@ -832,8 +832,7 @@ fn decl_upcall_glue(ModuleRef llmod, type_names tn, uint _n) -> ValueRef {
     let int n = _n as int;
     let str s = abi.upcall_glue_name(n);
     let vec[TypeRef] args =
-        vec(T_int(),     // callee
-            T_int()) // taskptr
+        vec(T_int())     // callee
         + _vec.init_elt[TypeRef](T_int(), n as uint);
 
     ret decl_fastcall_fn(llmod, s, T_fn(args, T_int()));
@@ -864,16 +863,16 @@ fn trans_upcall2(builder b, @glue_fns glues, ValueRef lltaskptr,
                  &hashmap[str, ValueRef] upcalls,
                  type_names tn, ModuleRef llmod, str name,
                  vec[ValueRef] args) -> ValueRef {
-    let int n = _vec.len[ValueRef](args) as int;
+    let int n = (_vec.len[ValueRef](args) as int) + 1;
     let ValueRef llupcall = get_upcall(upcalls, tn, llmod, name, n);
     llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());
 
     let ValueRef llglue = glues.upcall_glues.(n);
     let vec[ValueRef] call_args = vec(llupcall);
-    call_args += b.PtrToInt(lltaskptr, T_int());
+    call_args += vec( b.PtrToInt(lltaskptr, T_int()));
 
     for (ValueRef a in args) {
-        call_args += b.ZExtOrBitCast(a, T_int());
+        call_args += vec(b.ZExtOrBitCast(a, T_int()));
     }
 
     ret b.FastCall(llglue, call_args);
@@ -972,8 +971,7 @@ fn static_size_of_tag(@crate_ctxt cx, @ty.t t) -> uint {
     auto max_size = 0u;
     auto variants = tag_variants(cx, tid);
     for (ast.variant variant in variants) {
-        let vec[@ty.t] tys = variant_types(cx, variant);
-        auto tup_ty = ty.plain_ty(ty.ty_tup(tys));
+        auto tup_ty = ty.plain_tup_ty(variant_types(cx, variant));
 
         // Perform any type parameter substitutions.
         tup_ty = ty.substitute_ty_params(ty_params, subtys, tup_ty);
@@ -1022,12 +1020,16 @@ fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
             ret res(szptr.bcx, szptr.bcx.build.Load(szptr.val));
         }
         case (ty.ty_tup(?elts)) {
-            ret align_elements(cx, elts);
+            let vec[@ty.t] tys = vec();
+            for (ty.mt mt in elts) {
+                tys += vec(mt.ty);
+            }
+            ret align_elements(cx, tys);
         }
         case (ty.ty_rec(?flds)) {
             let vec[@ty.t] tys = vec();
             for (ty.field f in flds) {
-                tys += vec(f.ty);
+                tys += vec(f.mt.ty);
             }
             ret align_elements(cx, tys);
         }
@@ -1073,8 +1075,8 @@ fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> result {
         case (ty.ty_tup(?elts)) {
             auto a = C_int(1);
             auto bcx = cx;
-            for (@ty.t e in elts) {
-                auto align = align_of(bcx, e);
+            for (ty.mt e in elts) {
+                auto align = align_of(bcx, e.ty);
                 bcx = align.bcx;
                 a = umax(bcx, a, align.val);
             }
@@ -1084,7 +1086,7 @@ fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> result {
             auto a = C_int(1);
             auto bcx = cx;
             for (ty.field f in flds) {
-                auto align = align_of(bcx, f.ty);
+                auto align = align_of(bcx, f.mt.ty);
                 bcx = align.bcx;
                 a = umax(bcx, a, align.val);
             }
@@ -1112,7 +1114,7 @@ fn GEP_tup_like(@block_ctxt cx, @ty.t t,
     if (! ty.type_has_dynamic_size(t)) {
         let vec[ValueRef] v = vec();
         for (int i in ixs) {
-            v += C_int(i);
+            v += vec(C_int(i));
         }
         ret res(cx, cx.build.GEP(base, v));
     }
@@ -1159,8 +1161,8 @@ fn GEP_tup_like(@block_ctxt cx, @ty.t t,
         let vec[@ty.t] prefix = vec();
         let int i = 0;
         while (i < ix) {
-            append[@ty.t](prefix, ty.get_element_type(t, i as uint));
-            i +=1 ;
+            _vec.push[@ty.t](prefix, ty.get_element_type(t, i as uint));
+            i += 1 ;
         }
 
         auto selected = ty.get_element_type(t, i as uint);
@@ -1184,7 +1186,7 @@ fn GEP_tup_like(@block_ctxt cx, @ty.t t,
     // flattened the incoming structure.
 
     auto s = split_type(t, ixs, 0u);
-    auto prefix_ty = plain_ty(ty.ty_tup(s.prefix));
+    auto prefix_ty = ty.plain_tup_ty(s.prefix);
     auto bcx = cx;
     auto sz = size_of(bcx, prefix_ty);
     bcx = sz.bcx;
@@ -1228,7 +1230,8 @@ fn GEP_tag(@block_ctxt cx,
 
         i += 1;
     }
-    auto tup_ty = ty.plain_ty(ty.ty_tup(true_arg_tys));
+
+    auto tup_ty = ty.plain_tup_ty(true_arg_tys);
 
     // Cast the blob pointer to the appropriate type, if we need to (i.e. if
     // the blob pointer isn't dynamically sized).
@@ -1268,8 +1271,8 @@ fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
 fn trans_malloc_boxed(@block_ctxt cx, @ty.t t) -> result {
     // Synthesize a fake box type structurally so we have something
     // to measure the size of.
-    auto boxed_body = plain_ty(ty.ty_tup(vec(plain_ty(ty.ty_int), t)));
-    auto box_ptr = plain_ty(ty.ty_box(t));
+    auto boxed_body = ty.plain_tup_ty(vec(plain_ty(ty.ty_int), t));
+    auto box_ptr = ty.plain_box_ty(t);
     auto sz = size_of(cx, boxed_body);
     auto llty = type_of(cx.fcx.ccx, box_ptr);
     ret trans_raw_malloc(sz.bcx, llty, sz.val);
@@ -1310,8 +1313,8 @@ fn linearize_ty_params(@block_ctxt cx, @ty.t t)
                         }
                     }
                     if (!seen) {
-                        r.vals += r.cx.fcx.lltydescs.get(pid);
-                        r.defs += pid;
+                        r.vals += vec(r.cx.fcx.lltydescs.get(pid));
+                        r.defs += vec(pid);
                     }
                 }
                 case (_) { }
@@ -1567,7 +1570,7 @@ fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
                                         T_int(), C_int(0));
         }
 
-        case (ty.ty_box(?body_ty)) {
+        case (ty.ty_box(?body_mt)) {
             fn hit_zero(@block_ctxt cx, ValueRef v,
                         @ty.t body_ty) -> result {
                 auto body = cx.build.GEP(v,
@@ -1580,7 +1583,7 @@ fn make_drop_glue(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
                 ret trans_non_gc_free(res.bcx, v);
             }
             ret decr_refcnt_and_if_zero(cx, v,
-                                        bind hit_zero(_, v, body_ty),
+                                        bind hit_zero(_, v, body_mt.ty),
                                         "free box",
                                         T_int(), C_int(0));
         }
@@ -1832,7 +1835,7 @@ fn iter_structural_ty_full(@block_ctxt cx,
         auto box_a_ptr = cx.build.Load(box_a_cell);
         auto box_b_ptr = cx.build.Load(box_b_cell);
         auto tnil = plain_ty(ty.ty_nil);
-        auto tbox = plain_ty(ty.ty_box(tnil));
+        auto tbox = ty.plain_box_ty(tnil);
 
         auto inner_cx = new_sub_block_ctxt(cx, "iter box");
         auto next_cx = new_sub_block_ctxt(cx, "next");
@@ -1847,15 +1850,15 @@ fn iter_structural_ty_full(@block_ctxt cx,
     alt (t.struct) {
         case (ty.ty_tup(?args)) {
             let int i = 0;
-            for (@ty.t arg in args) {
+            for (ty.mt arg in args) {
                 r = GEP_tup_like(r.bcx, t, av, vec(0, i));
                 auto elt_a = r.val;
                 r = GEP_tup_like(r.bcx, t, bv, vec(0, i));
                 auto elt_b = r.val;
                 r = f(r.bcx,
-                      load_scalar_or_boxed(r.bcx, elt_a, arg),
-                      load_scalar_or_boxed(r.bcx, elt_b, arg),
-                      arg);
+                      load_scalar_or_boxed(r.bcx, elt_a, arg.ty),
+                      load_scalar_or_boxed(r.bcx, elt_b, arg.ty),
+                      arg.ty);
                 i += 1;
             }
         }
@@ -1867,9 +1870,9 @@ fn iter_structural_ty_full(@block_ctxt cx,
                 r = GEP_tup_like(r.bcx, t, bv, vec(0, i));
                 auto llfld_b = r.val;
                 r = f(r.bcx,
-                      load_scalar_or_boxed(r.bcx, llfld_a, fld.ty),
-                      load_scalar_or_boxed(r.bcx, llfld_b, fld.ty),
-                      fld.ty);
+                      load_scalar_or_boxed(r.bcx, llfld_a, fld.mt.ty),
+                      load_scalar_or_boxed(r.bcx, llfld_b, fld.mt.ty),
+                      fld.mt.ty);
                 i += 1;
             }
         }
@@ -2107,8 +2110,8 @@ fn iter_sequence(@block_ctxt cx,
     }
 
     alt (t.struct) {
-        case (ty.ty_vec(?et)) {
-            ret iter_sequence_body(cx, v, et, f, false);
+        case (ty.ty_vec(?elt)) {
+            ret iter_sequence_body(cx, v, elt.ty, f, false);
         }
         case (ty.ty_str) {
             auto et = plain_ty(ty.ty_machine(common.ty_u8));
@@ -2365,7 +2368,7 @@ fn trans_unary(@block_ctxt cx, ast.unop op,
             auto box_ty = node_ann_type(sub.bcx.fcx.ccx, a);
             sub = trans_malloc_boxed(sub.bcx, e_ty);
             find_scope_cx(cx).cleanups +=
-                clean(bind drop_ty(_, sub.val, box_ty));
+                vec(clean(bind drop_ty(_, sub.val, box_ty)));
 
             auto box = sub.val;
             auto rc = sub.bcx.build.GEP(box,
@@ -2398,9 +2401,6 @@ fn trans_unary(@block_ctxt cx, ast.unop op,
             }
             ret res(sub.bcx, val);
         }
-        case (ast._mutable) {
-            ret trans_expr(cx, e);
-        }
     }
     fail;
 }
@@ -2646,7 +2646,8 @@ fn trans_vec_add(@block_ctxt cx, @ty.t t,
     r = copy_ty(r.bcx, INIT, tmp, lhs, t);
     auto bcx = trans_vec_append(r.bcx, t, tmp, rhs).bcx;
     tmp = load_scalar_or_boxed(bcx, tmp, t);
-    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, tmp, t));
+    find_scope_cx(cx).cleanups +=
+        vec(clean(bind drop_ty(_, tmp, t)));
     ret res(bcx, tmp);
 }
 
@@ -2698,12 +2699,12 @@ fn autoderef(@block_ctxt cx, ValueRef v, @ty.t t) -> result {
 
     while (true) {
         alt (t1.struct) {
-            case (ty.ty_box(?inner)) {
+            case (ty.ty_box(?mt)) {
                 auto body = cx.build.GEP(v1,
                                          vec(C_int(0),
                                              C_int(abi.box_rc_field_body)));
-                t1 = inner;
-                v1 = load_scalar_or_boxed(cx, body, inner);
+                t1 = mt.ty;
+                v1 = load_scalar_or_boxed(cx, body, t1);
             }
             case (_) {
                 ret res(cx, v1);
@@ -2717,8 +2718,8 @@ fn autoderefed_ty(@ty.t t) -> @ty.t {
 
     while (true) {
         alt (t1.struct) {
-            case (ty.ty_box(?inner)) {
-                t1 = inner;
+            case (ty.ty_box(?mt)) {
+                t1 = mt.ty;
             }
             case (_) {
                 ret t1;
@@ -2800,9 +2801,9 @@ fn join_results(@block_ctxt parent_cx,
 
     for (result r in ins) {
         if (! is_terminated(r.bcx)) {
-            live += r;
-            vals += r.val;
-            bbs += r.bcx.llbb;
+            live += vec(r);
+            vals += vec(r.val);
+            bbs += vec(r.bcx.llbb);
         }
     }
 
@@ -2875,7 +2876,8 @@ fn trans_for(@block_ctxt cx,
         cx.build.Br(scope_cx.llbb);
         auto local_res = alloc_local(scope_cx, local);
         auto bcx = copy_ty(local_res.bcx, INIT, local_res.val, curr, t).bcx;
-        scope_cx.cleanups += clean(bind drop_slot(_, local_res.val, t));
+        scope_cx.cleanups +=
+            vec(clean(bind drop_slot(_, local_res.val, t)));
         bcx = trans_block(bcx, body).bcx;
         bcx.build.Br(next_cx.llbb);
         ret res(next_cx, C_nil());
@@ -3245,7 +3247,8 @@ fn trans_pat_binding(@block_ctxt cx, @ast.pat pat, ValueRef llval)
 
             llvm.LLVMSetValueName(dst, _str.buf(id));
             bcx.fcx.lllocals.insert(def_id, dst);
-            bcx.cleanups += clean(bind drop_slot(_, dst, ty));
+            bcx.cleanups +=
+                vec(clean(bind drop_slot(_, dst, ty)));
 
             ret copy_ty(bcx, INIT, dst, llval, ty);
         }
@@ -3368,7 +3371,7 @@ fn lval_generic_fn(@block_ctxt cx,
         for (@ty.t t in tys) {
             auto td = get_tydesc(bcx, t);
             bcx = td.bcx;
-            append[ValueRef](tydescs, td.val);
+            _vec.push[ValueRef](tydescs, td.val);
         }
         auto gen = rec( item_type = tpt._1,
                         tydescs = tydescs );
@@ -3481,7 +3484,7 @@ fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base,
     r = autoderef(r.bcx, r.val, t);
     t = autoderefed_ty(t);
     alt (t.struct) {
-        case (ty.ty_tup(?fields)) {
+        case (ty.ty_tup(_)) {
             let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field);
             auto v = GEP_tup_like(r.bcx, t, r.val, vec(0, ix as int));
             ret lval_mem(v.bcx, v.val);
@@ -3621,7 +3624,7 @@ fn trans_bind_thunk(@crate_ctxt cx,
     auto fcx = new_fn_ctxt(cx, llthunk);
     auto bcx = new_top_block_ctxt(fcx);
 
-    auto llclosure_ptr_ty = type_of(cx, plain_ty(ty.ty_box(closure_ty)));
+    auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty));
     auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty);
 
     auto lltarget = GEP_tup_like(bcx, closure_ty, llclosure,
@@ -3692,7 +3695,7 @@ fn trans_bind_thunk(@crate_ctxt cx,
                     val = bcx.build.PointerCast(val, llout_arg_ty);
                 }
 
-                llargs += val;
+                llargs += vec(val);
                 b += 1;
             }
 
@@ -3706,7 +3709,7 @@ fn trans_bind_thunk(@crate_ctxt cx,
                                                        llout_arg_ty);
                 }
 
-                llargs += passed_arg;
+                llargs += vec(passed_arg);
                 a += 1u;
             }
         }
@@ -3750,7 +3753,7 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
                 case (none[@ast.expr]) {
                 }
                 case (some[@ast.expr](?e)) {
-                    append[@ast.expr](bound, e);
+                    _vec.push[@ast.expr](bound, e);
                 }
             }
         }
@@ -3786,14 +3789,14 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
                 auto arg = trans_expr(bcx, e);
                 bcx = arg.bcx;
 
-                append[ValueRef](bound_vals, arg.val);
-                append[@ty.t](bound_tys, ty.expr_ty(e));
+                _vec.push[ValueRef](bound_vals, arg.val);
+                _vec.push[@ty.t](bound_tys, ty.expr_ty(e));
 
                 i += 1u;
             }
 
             // Synthesize a closure type.
-            let @ty.t bindings_ty = plain_ty(ty.ty_tup(bound_tys));
+            let @ty.t bindings_ty = ty.plain_tup_ty(bound_tys);
 
             // NB: keep this in sync with T_closure_ptr; we're making
             // a ty.t structure that has the same "shape" as the LLVM type
@@ -3807,9 +3810,9 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
                 vec(tydesc_ty,
                     outgoing_fty,
                     bindings_ty,
-                    plain_ty(ty.ty_tup(captured_tys)));
+                    ty.plain_tup_ty(captured_tys));
 
-            let @ty.t closure_ty = plain_ty(ty.ty_tup(closure_tys));
+            let @ty.t closure_ty = ty.plain_tup_ty(closure_tys);
 
             auto r = trans_malloc_boxed(bcx, closure_ty);
             auto box = r.val;
@@ -3914,7 +3917,7 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
                  pair_box);
 
             find_scope_cx(cx).cleanups +=
-                clean(bind drop_slot(_, pair_v, pair_ty));
+                vec(clean(bind drop_slot(_, pair_v, pair_ty)));
 
             ret res(bcx, pair_v);
         }
@@ -3959,23 +3962,24 @@ fn trans_args(@block_ctxt cx,
         }
     }
     if (ty.type_has_dynamic_size(retty)) {
-        llargs += bcx.build.PointerCast(llretslot,
-                                        T_typaram_ptr(cx.fcx.ccx.tn));
+        llargs += vec(bcx.build.PointerCast(llretslot,
+                                            T_typaram_ptr(cx.fcx.ccx.tn)));
     } else if (ty.count_ty_params(retty) != 0u) {
         // It's possible that the callee has some generic-ness somewhere in
         // its return value -- say a method signature within an obj or a fn
         // type deep in a structure -- which the caller has a concrete view
         // of. If so, cast the caller's view of the restlot to the callee's
         // view, for the sake of making a type-compatible call.
-        llargs += cx.build.PointerCast(llretslot,
-                                       T_ptr(type_of(bcx.fcx.ccx, retty)));
+        llargs +=
+            vec(cx.build.PointerCast(llretslot,
+                                     T_ptr(type_of(bcx.fcx.ccx, retty))));
     } else {
-        llargs += llretslot;
+        llargs += vec(llretslot);
     }
 
 
     // Arg 1: Task pointer.
-    llargs += bcx.fcx.lltaskptr;
+    llargs += vec(bcx.fcx.lltaskptr);
 
     // Arg 2: Env (closure-bindings / self-obj)
     alt (llobj) {
@@ -3983,10 +3987,10 @@ fn trans_args(@block_ctxt cx,
             // Every object is always found in memory,
             // and not-yet-loaded (as part of an lval x.y
             // doted method-call).
-            llargs += bcx.build.Load(ob);
+            llargs += vec(bcx.build.Load(ob));
         }
         case (_) {
-            llargs += llenv;
+            llargs += vec(llenv);
         }
     }
 
@@ -3997,7 +4001,7 @@ fn trans_args(@block_ctxt cx,
     alt (lliterbody) {
         case (none[ValueRef]) {}
         case (some[ValueRef](?lli)) {
-            llargs += lli;
+            llargs += vec(lli);
         }
     }
 
@@ -4054,7 +4058,7 @@ fn trans_args(@block_ctxt cx,
             val = bcx.build.PointerCast(val, lldestty);
         }
 
-        llargs += val;
+        llargs += vec(val);
         i += 1u;
     }
 
@@ -4116,7 +4120,8 @@ fn trans_call(@block_ctxt cx, @ast.expr f,
         // Retval doesn't correspond to anything really tangible in the frame,
         // but it's a ref all the same, so we put a note here to drop it when
         // we're done in this scope.
-        find_scope_cx(cx).cleanups += clean(bind drop_ty(_, retval, ret_ty));
+        find_scope_cx(cx).cleanups +=
+            vec(clean(bind drop_ty(_, retval, ret_ty)));
     }
 
     ret res(bcx, retval);
@@ -4130,7 +4135,8 @@ fn trans_tup(@block_ctxt cx, vec[ast.elt] elts,
     auto tup_val = tup_res.val;
     bcx = tup_res.bcx;
 
-    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, tup_val, t));
+    find_scope_cx(cx).cleanups +=
+        vec(clean(bind drop_ty(_, tup_val, t)));
     let int i = 0;
 
     for (ast.elt e in elts) {
@@ -4150,8 +4156,8 @@ fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
     auto t = node_ann_type(cx.fcx.ccx, ann);
     auto unit_ty = t;
     alt (t.struct) {
-        case (ty.ty_vec(?t)) {
-            unit_ty = t;
+        case (ty.ty_vec(?mt)) {
+            unit_ty = mt.ty;
         }
         case (_) {
             cx.fcx.ccx.sess.bug("non-vec type in trans_vec");
@@ -4171,14 +4177,15 @@ fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
 
     auto llty = type_of(bcx.fcx.ccx, t);
     auto vec_val = vi2p(bcx, sub.val, llty);
-    find_scope_cx(bcx).cleanups += clean(bind drop_ty(_, vec_val, t));
+    find_scope_cx(bcx).cleanups +=
+        vec(clean(bind drop_ty(_, vec_val, t)));
 
     auto body = bcx.build.GEP(vec_val, vec(C_int(0),
                                            C_int(abi.vec_elt_data)));
 
     auto pseudo_tup_ty =
-        plain_ty(ty.ty_tup(_vec.init_elt[@ty.t](unit_ty,
-                                                _vec.len[@ast.expr](args))));
+        ty.plain_tup_ty(_vec.init_elt[@ty.t](unit_ty,
+                                             _vec.len[@ast.expr](args)));
     let int i = 0;
 
     for (@ast.expr e in args) {
@@ -4226,7 +4233,8 @@ fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
     auto rec_val = rec_res.val;
     bcx = rec_res.bcx;
 
-    find_scope_cx(cx).cleanups += clean(bind drop_ty(_, rec_val, t));
+    find_scope_cx(cx).cleanups +=
+        vec(clean(bind drop_ty(_, rec_val, t)));
     let int i = 0;
 
     auto base_val = C_nil();
@@ -4246,7 +4254,7 @@ fn trans_rec(@block_ctxt cx, vec[ast.field] fields,
     }
 
     for (ty.field tf in ty_fields) {
-        auto e_ty = tf.ty;
+        auto e_ty = tf.mt.ty;
         auto dst_res = GEP_tup_like(bcx, t, rec_val, vec(0, i));
         bcx = dst_res.bcx;
 
@@ -4352,7 +4360,7 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
             ret trans_cast(cx, e, ann);
         }
 
-        case (ast.expr_vec(?args, ?ann)) {
+        case (ast.expr_vec(?args, _, ?ann)) {
             ret trans_vec(cx, args, ann);
         }
 
@@ -4499,7 +4507,7 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
                 llarg = bcx.build.Load(llarg);
             }
 
-            llargs += llarg;
+            llargs += vec(llarg);
         }
     }
 
@@ -4557,7 +4565,7 @@ fn init_local(@block_ctxt cx, @ast.local local) -> result {
     auto bcx = cx;
 
     find_scope_cx(cx).cleanups +=
-        clean(bind drop_slot(_, llptr, ty));
+        vec(clean(bind drop_slot(_, llptr, ty)));
 
     alt (local.init) {
         case (some[@ast.expr](?e)) {
@@ -4903,7 +4911,7 @@ fn populate_fn_ctxt_from_llself(@block_ctxt cx, ValueRef llself) -> result {
 
     // Synthesize a tuple type for the fields so that GEP_tup_like() can work
     // its magic.
-    auto fields_tup_ty = ty.plain_ty(ty.ty_tup(field_tys));
+    auto fields_tup_ty = ty.plain_tup_ty(field_tys);
 
     auto n_typarams = _vec.len[ast.ty_param](bcx.fcx.ccx.obj_typarams);
     let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.ccx.tn, n_typarams);
@@ -5026,7 +5034,7 @@ fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
 
         trans_fn(mcx, m.node.meth, m.node.id, some[TypeRef](self_ty),
                  ty_params, m.node.ann);
-        methods += llfn;
+        methods += vec(llfn);
     }
     auto vtbl = C_struct(methods);
     auto gvar = llvm.LLVMAddGlobal(cx.llmod,
@@ -5085,22 +5093,22 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid,
         // Malloc a box for the body and copy args in.
         let vec[@ty.t] obj_fields = vec();
         for (ty.arg a in arg_tys) {
-            append[@ty.t](obj_fields, a.ty);
+            _vec.push[@ty.t](obj_fields, a.ty);
         }
 
         // Synthesize an obj body type.
         auto tydesc_ty = plain_ty(ty.ty_type);
         let vec[@ty.t] tps = vec();
         for (ast.ty_param tp in ty_params) {
-            append[@ty.t](tps, tydesc_ty);
+            _vec.push[@ty.t](tps, tydesc_ty);
         }
 
-        let @ty.t typarams_ty = plain_ty(ty.ty_tup(tps));
-        let @ty.t fields_ty = plain_ty(ty.ty_tup(obj_fields));
-        let @ty.t body_ty = plain_ty(ty.ty_tup(vec(tydesc_ty,
-                                                   typarams_ty,
-                                                   fields_ty)));
-        let @ty.t boxed_body_ty = plain_ty(ty.ty_box(body_ty));
+        let @ty.t typarams_ty = ty.plain_tup_ty(tps);
+        let @ty.t fields_ty = ty.plain_tup_ty(obj_fields);
+        let @ty.t body_ty = ty.plain_tup_ty(vec(tydesc_ty,
+                                                typarams_ty,
+                                                fields_ty));
+        let @ty.t boxed_body_ty = ty.plain_box_ty(body_ty);
 
         // Malloc a box for the body.
         auto box = trans_malloc_boxed(bcx, body_ty);
@@ -6090,7 +6098,7 @@ fn make_glues(ModuleRef llmod, type_names tn) -> @glue_fns {
 
              upcall_glues =
              _vec.init_fn[ValueRef](bind decl_upcall_glue(llmod, tn, _),
-                                    abi.n_upcall_glues as uint),
+                                    abi.n_upcall_glues + 1 as uint),
              no_op_type_glue = decl_no_op_type_glue(llmod, tn),
              memcpy_glue = decl_memcpy_glue(llmod),
              bzero_glue = decl_bzero_glue(llmod),
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 0c540f5c0ba..5fdb4dc2d2c 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -11,22 +11,23 @@ import driver.session;
 import front.ast;
 import front.ast.mutability;
 import util.common;
-import util.common.append;
 import util.common.new_def_hash;
 import util.common.span;
 
 // Data types
 
 type arg = rec(ast.mode mode, @t ty);
-type field = rec(ast.ident ident, @t ty);
+type field = rec(ast.ident ident, mt mt);
 type method = rec(ast.proto proto,
                   ast.ident ident,
                   vec[arg] inputs,
                   @t output);
 
+type mt = rec(@t ty, ast.mutability mut);
+
 // NB: If you change this, you'll probably want to change the corresponding
 // AST structure in front/ast.rs as well.
-type t = rec(sty struct, mutability mut, option.t[str] cname);
+type t = rec(sty struct, option.t[str] cname);
 tag sty {
     ty_nil;
     ty_bool;
@@ -36,11 +37,11 @@ tag sty {
     ty_char;
     ty_str;
     ty_tag(ast.def_id, vec[@t]);
-    ty_box(@t);
-    ty_vec(@t);
+    ty_box(mt);
+    ty_vec(mt);
     ty_port(@t);
     ty_chan(@t);
-    ty_tup(vec[@t]);
+    ty_tup(vec[mt]);
     ty_rec(vec[field]);
     ty_fn(ast.proto, vec[arg], @t);                 // TODO: effect
     ty_native_fn(ast.native_abi, vec[arg], @t);     // TODO: effect
@@ -66,6 +67,8 @@ type unify_handler = obj {
 
 tag type_err {
     terr_mismatch;
+    terr_box_mutability;
+    terr_vec_mutability;
     terr_tuple_size(uint, uint);
     terr_tuple_mutability;
     terr_record_size(uint, uint);
@@ -139,44 +142,51 @@ fn ty_to_str(&@t typ) -> str {
     }
 
     fn field_to_str(&field f) -> str {
-        ret ty_to_str(f.ty) + " " + f.ident;
+        ret mt_to_str(f.mt) + " " + f.ident;
     }
 
-    auto s = "";
-    if (typ.mut == ast.mut) {
-        s += "mutable ";
+    fn mt_to_str(&mt m) -> str {
+        auto mstr;
+        alt (m.mut) {
+            case (ast.mut)       { mstr = "mutable "; }
+            case (ast.imm)       { mstr = "";         }
+            case (ast.maybe_mut) { mstr = "mutable? "; }
+        }
+
+        ret mstr + ty_to_str(m.ty);
     }
 
+    auto s = "";
     alt (typ.struct) {
-        case (ty_native)       { s = "native";                     }
-        case (ty_nil)          { s = "()";                         }
-        case (ty_bool)         { s = "bool";                       }
-        case (ty_int)          { s = "int";                        }
-        case (ty_uint)         { s = "uint";                       }
-        case (ty_machine(?tm)) { s = common.ty_mach_to_str(tm);    }
-        case (ty_char)         { s = "char";                       }
-        case (ty_str)          { s = "str";                        }
-        case (ty_box(?t))      { s = "@" + ty_to_str(t);           }
-        case (ty_vec(?t))      { s = "vec[" + ty_to_str(t) + "]";  }
-        case (ty_port(?t))     { s = "port[" + ty_to_str(t) + "]"; }
-        case (ty_chan(?t))     { s = "chan[" + ty_to_str(t) + "]"; }
-        case (ty_type)         { s = "type";                       }
+        case (ty_native)       { s += "native";                     }
+        case (ty_nil)          { s += "()";                         }
+        case (ty_bool)         { s += "bool";                       }
+        case (ty_int)          { s += "int";                        }
+        case (ty_uint)         { s += "uint";                       }
+        case (ty_machine(?tm)) { s += common.ty_mach_to_str(tm);    }
+        case (ty_char)         { s += "char";                       }
+        case (ty_str)          { s += "str";                        }
+        case (ty_box(?tm))     { s += "@" + mt_to_str(tm);          }
+        case (ty_vec(?tm))     { s += "vec[" + mt_to_str(tm) + "]"; }
+        case (ty_port(?t))     { s += "port[" + ty_to_str(t) + "]"; }
+        case (ty_chan(?t))     { s += "chan[" + ty_to_str(t) + "]"; }
+        case (ty_type)         { s += "type";                       }
 
         case (ty_tup(?elems)) {
-            auto f = ty_to_str;
-            auto strs = _vec.map[@t,str](f, elems);
-            s = "tup(" + _str.connect(strs, ",") + ")";
+            auto f = mt_to_str;
+            auto strs = _vec.map[mt,str](f, elems);
+            s += "tup(" + _str.connect(strs, ",") + ")";
         }
 
         case (ty_rec(?elems)) {
             auto f = field_to_str;
             auto strs = _vec.map[field,str](f, elems);
-            s = "rec(" + _str.connect(strs, ",") + ")";
+            s += "rec(" + _str.connect(strs, ",") + ")";
         }
 
         case (ty_tag(?id, ?tps)) {
             // The user should never see this if the cname is set properly!
-            s = "<tag#" + util.common.istr(id._0) + ":" +
+            s += "<tag#" + util.common.istr(id._0) + ":" +
                 util.common.istr(id._1) + ">";
             if (_vec.len[@t](tps) > 0u) {
                 auto f = ty_to_str;
@@ -186,31 +196,31 @@ fn ty_to_str(&@t typ) -> str {
         }
 
         case (ty_fn(?proto, ?inputs, ?output)) {
-            s = fn_to_str(proto, none[ast.ident], inputs, output);
+            s += fn_to_str(proto, none[ast.ident], inputs, output);
         }
 
         case (ty_native_fn(_, ?inputs, ?output)) {
-            s = fn_to_str(ast.proto_fn, none[ast.ident], inputs, output);
+            s += fn_to_str(ast.proto_fn, none[ast.ident], inputs, output);
         }
 
         case (ty_obj(?meths)) {
             auto f = method_to_str;
             auto m = _vec.map[method,str](f, meths);
-            s = "obj {\n\t" + _str.connect(m, "\n\t") + "\n}";
+            s += "obj {\n\t" + _str.connect(m, "\n\t") + "\n}";
         }
 
         case (ty_var(?v)) {
-            s = "<T" + util.common.istr(v) + ">";
+            s += "<T" + util.common.istr(v) + ">";
         }
 
         case (ty_local(?id)) {
-            s = "<L" + util.common.istr(id._0) + ":" + util.common.istr(id._1)
-                + ">";
+            s += "<L" + util.common.istr(id._0) + ":" +
+                util.common.istr(id._1) + ">";
         }
 
         case (ty_param(?id)) {
-            s = "<P" + util.common.istr(id._0) + ":" + util.common.istr(id._1)
-                + ">";
+            s += "<P" + util.common.istr(id._0) + ":" +
+                util.common.istr(id._1) + ">";
         }
     }
 
@@ -225,7 +235,7 @@ type ty_fold = state obj {
 
 fn fold_ty(ty_fold fld, @t ty) -> @t {
     fn rewrap(@t orig, &sty new) -> @t {
-        ret @rec(struct=new, mut=orig.mut, cname=orig.cname);
+        ret @rec(struct=new, cname=orig.cname);
     }
 
     alt (ty.struct) {
@@ -238,11 +248,11 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
         case (ty_str)           { ret fld.fold_simple_ty(ty); }
         case (ty_type)          { ret fld.fold_simple_ty(ty); }
         case (ty_native)        { ret fld.fold_simple_ty(ty); }
-        case (ty_box(?subty)) {
-            ret rewrap(ty, ty_box(fold_ty(fld, subty)));
+        case (ty_box(?tm)) {
+            ret rewrap(ty, ty_box(rec(ty=fold_ty(fld, tm.ty), mut=tm.mut)));
         }
-        case (ty_vec(?subty)) {
-            ret rewrap(ty, ty_vec(fold_ty(fld, subty)));
+        case (ty_vec(?tm)) {
+            ret rewrap(ty, ty_vec(rec(ty=fold_ty(fld, tm.ty), mut=tm.mut)));
         }
         case (ty_port(?subty)) {
             ret rewrap(ty, ty_port(fold_ty(fld, subty)));
@@ -257,18 +267,20 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
             }
             ret rewrap(ty, ty_tag(tid, new_subtys));
         }
-        case (ty_tup(?subtys)) {
-            let vec[@t] new_subtys = vec();
-            for (@t subty in subtys) {
-                new_subtys += vec(fold_ty(fld, subty));
+        case (ty_tup(?mts)) {
+            let vec[mt] new_mts = vec();
+            for (mt tm in mts) {
+                auto new_subty = fold_ty(fld, tm.ty);
+                new_mts += vec(rec(ty=new_subty, mut=tm.mut));
             }
-            ret rewrap(ty, ty_tup(new_subtys));
+            ret rewrap(ty, ty_tup(new_mts));
         }
         case (ty_rec(?fields)) {
             let vec[field] new_fields = vec();
             for (field fl in fields) {
-                auto new_ty = fold_ty(fld, fl.ty);
-                new_fields += vec(rec(ident=fl.ident, ty=new_ty));
+                auto new_ty = fold_ty(fld, fl.mt.ty);
+                auto new_mt = rec(ty=new_ty, mut=fl.mt.mut);
+                new_fields += vec(rec(ident=fl.ident, mt=new_mt));
             }
             ret rewrap(ty, ty_rec(new_fields));
         }
@@ -352,8 +364,8 @@ fn type_is_sequence(@t ty) -> bool {
 
 fn sequence_element_type(@t ty) -> @t {
     alt (ty.struct) {
-        case (ty_str)     { ret plain_ty(ty_machine(common.ty_u8)); }
-        case (ty_vec(?e)) { ret e; }
+        case (ty_str)      { ret plain_ty(ty_machine(common.ty_u8)); }
+        case (ty_vec(?mt)) { ret mt.ty; }
     }
     fail;
 }
@@ -373,11 +385,11 @@ fn type_is_tup_like(@t ty) -> bool {
 fn get_element_type(@t ty, uint i) -> @t {
     check (type_is_tup_like(ty));
     alt (ty.struct) {
-        case (ty_tup(?tys)) {
-            ret tys.(i);
+        case (ty_tup(?mts)) {
+            ret mts.(i).ty;
         }
         case (ty_rec(?flds)) {
-            ret flds.(i).ty;
+            ret flds.(i).mt.ty;
         }
     }
     fail;
@@ -410,6 +422,7 @@ fn type_is_scalar(@t ty) -> bool {
         case (ty_machine(_)) { ret true; }
         case (ty_char) { ret true; }
         case (ty_type) { ret true; }
+        case (ty_native) { ret true; }
         case (_) { ret false; }
     }
     fail;
@@ -427,17 +440,17 @@ fn type_is_native(@t ty) -> bool {
 
 fn type_has_dynamic_size(@t ty) -> bool {
     alt (ty.struct) {
-        case (ty_tup(?ts)) {
+        case (ty_tup(?mts)) {
             auto i = 0u;
-            while (i < _vec.len[@t](ts)) {
-                if (type_has_dynamic_size(ts.(i))) { ret true; }
+            while (i < _vec.len[mt](mts)) {
+                if (type_has_dynamic_size(mts.(i).ty)) { ret true; }
                 i += 1u;
             }
         }
         case (ty_rec(?fields)) {
             auto i = 0u;
             while (i < _vec.len[field](fields)) {
-                if (type_has_dynamic_size(fields.(i).ty)) { ret true; }
+                if (type_has_dynamic_size(fields.(i).mt.ty)) { ret true; }
                 i += 1u;
             }
         }
@@ -518,7 +531,19 @@ fn type_param(@t ty) -> option.t[ast.def_id] {
 }
 
 fn plain_ty(&sty st) -> @t {
-    ret @rec(struct=st, mut=ast.imm, cname=none[str]);
+    ret @rec(struct=st, cname=none[str]);
+}
+
+fn plain_box_ty(@t subty) -> @t {
+    ret plain_ty(ty_box(rec(ty=subty, mut=ast.imm)));
+}
+
+fn plain_tup_ty(vec[@t] elem_tys) -> @t {
+    let vec[ty.mt] mts = vec();
+    for (@ty.t typ in elem_tys) {
+        mts += vec(rec(ty=typ, mut=ast.imm));
+    }
+    ret plain_ty(ty_tup(mts));
 }
 
 fn hash_ty(&@t ty) -> uint {
@@ -703,7 +728,7 @@ fn pat_ty(@ast.pat pat) -> @t {
 
 fn expr_ty(@ast.expr expr) -> @t {
     alt (expr.node) {
-        case (ast.expr_vec(_, ?ann))          { ret ann_to_type(ann); }
+        case (ast.expr_vec(_, _, ?ann))       { ret ann_to_type(ann); }
         case (ast.expr_tup(_, ?ann))          { ret ann_to_type(ann); }
         case (ast.expr_rec(_, _, ?ann))       { ret ann_to_type(ann); }
         case (ast.expr_bind(_, _, ?ann))      { ret ann_to_type(ann); }
@@ -756,7 +781,7 @@ fn field_num(session.session sess, &span sp, &ast.ident id) -> uint {
                 accum += (c as uint) - ('0' as uint);
             } else {
                 auto s = "";
-                s += c;
+                s += _str.unsafe_from_byte(c);
                 sess.span_err(sp,
                               "bad numeric field on tuple: "
                               + " non-digit character: "
@@ -794,6 +819,14 @@ fn method_idx(session.session sess, &span sp,
     fail;
 }
 
+fn sort_methods(vec[method] meths) -> vec[method] {
+    fn method_lteq(&method a, &method b) -> bool {
+        ret _str.lteq(a.ident, b.ident);
+    }
+
+    ret std.sort.merge_sort[method](bind method_lteq(_,_), meths);
+}
+
 fn is_lval(@ast.expr expr) -> bool {
     alt (expr.node) {
         case (ast.expr_field(_,_,_))    { ret true;  }
@@ -826,6 +859,21 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
         ret ures_err(terr_mismatch, expected, actual);
     }
 
+    // Unifies two mutability flags.
+    fn unify_mut(ast.mutability expected, ast.mutability actual)
+            -> option.t[ast.mutability] {
+        if (expected == actual) {
+            ret some[ast.mutability](expected);
+        }
+        if (expected == ast.maybe_mut) {
+            ret some[ast.mutability](actual);
+        }
+        if (actual == ast.maybe_mut) {
+            ret some[ast.mutability](expected);
+        }
+        ret none[ast.mutability];
+    }
+
     tag fn_common_res {
         fn_common_res_err(unify_result);
         fn_common_res_ok(vec[arg], @t);
@@ -1104,7 +1152,7 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
 
                             alt (result) {
                                 case (ures_ok(?rty)) {
-                                    append[@ty.t](result_tps, rty);
+                                    _vec.push[@ty.t](result_tps, rty);
                                 }
                                 case (_) {
                                     ret result;
@@ -1123,16 +1171,26 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
                 ret ures_err(terr_mismatch, expected, actual);
             }
 
-            case (ty.ty_box(?expected_sub)) {
+            case (ty.ty_box(?expected_mt)) {
                 alt (actual.struct) {
-                    case (ty.ty_box(?actual_sub)) {
+                    case (ty.ty_box(?actual_mt)) {
+                        auto mut;
+                        alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
+                            case (none[ast.mutability]) {
+                                ret ures_err(terr_box_mutability, expected,
+                                             actual);
+                            }
+                            case (some[ast.mutability](?m)) { mut = m; }
+                        }
+
                         auto result = unify_step(bindings,
-                                                 expected_sub,
-                                                 actual_sub,
+                                                 expected_mt.ty,
+                                                 actual_mt.ty,
                                                  handler);
                         alt (result) {
                             case (ures_ok(?result_sub)) {
-                                ret ures_ok(plain_ty(ty.ty_box(result_sub)));
+                                auto mt = rec(ty=result_sub, mut=mut);
+                                ret ures_ok(plain_ty(ty.ty_box(mt)));
                             }
                             case (_) {
                                 ret result;
@@ -1146,16 +1204,26 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
                 }
             }
 
-            case (ty.ty_vec(?expected_sub)) {
+            case (ty.ty_vec(?expected_mt)) {
                 alt (actual.struct) {
-                    case (ty.ty_vec(?actual_sub)) {
+                    case (ty.ty_vec(?actual_mt)) {
+                        auto mut;
+                        alt (unify_mut(expected_mt.mut, actual_mt.mut)) {
+                            case (none[ast.mutability]) {
+                                ret ures_err(terr_vec_mutability, expected,
+                                             actual);
+                            }
+                            case (some[ast.mutability](?m)) { mut = m; }
+                        }
+
                         auto result = unify_step(bindings,
-                                                 expected_sub,
-                                                 actual_sub,
+                                                 expected_mt.ty,
+                                                 actual_mt.ty,
                                                  handler);
                         alt (result) {
                             case (ures_ok(?result_sub)) {
-                                ret ures_ok(plain_ty(ty.ty_vec(result_sub)));
+                                auto mt = rec(ty=result_sub, mut=mut);
+                                ret ures_ok(plain_ty(ty.ty_vec(mt)));
                             }
                             case (_) {
                                 ret result;
@@ -1218,8 +1286,8 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
             case (ty.ty_tup(?expected_elems)) {
                 alt (actual.struct) {
                     case (ty.ty_tup(?actual_elems)) {
-                        auto expected_len = _vec.len[@ty.t](expected_elems);
-                        auto actual_len = _vec.len[@ty.t](actual_elems);
+                        auto expected_len = _vec.len[ty.mt](expected_elems);
+                        auto actual_len = _vec.len[ty.mt](actual_elems);
                         if (expected_len != actual_len) {
                             auto err = terr_tuple_size(expected_len,
                                                        actual_len);
@@ -1228,23 +1296,30 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
 
                         // TODO: implement an iterator that can iterate over
                         // two arrays simultaneously.
-                        let vec[@ty.t] result_elems = vec();
+                        let vec[ty.mt] result_elems = vec();
                         auto i = 0u;
                         while (i < expected_len) {
                             auto expected_elem = expected_elems.(i);
                             auto actual_elem = actual_elems.(i);
-                            if (expected_elem.mut != actual_elem.mut) {
-                                auto err = terr_tuple_mutability;
-                                ret ures_err(err, expected, actual);
+
+                            auto mut;
+                            alt (unify_mut(expected_elem.mut,
+                                           actual_elem.mut)) {
+                                case (none[ast.mutability]) {
+                                    auto err = terr_tuple_mutability;
+                                    ret ures_err(err, expected, actual);
+                                }
+                                case (some[ast.mutability](?m)) { mut = m; }
                             }
 
                             auto result = unify_step(bindings,
-                                                     expected_elem,
-                                                     actual_elem,
+                                                     expected_elem.ty,
+                                                     actual_elem.ty,
                                                      handler);
                             alt (result) {
                                 case (ures_ok(?rty)) {
-                                    append[@ty.t](result_elems,rty);
+                                    auto mt = rec(ty=rty, mut=mut);
+                                    result_elems += vec(mt);
                                 }
                                 case (_) {
                                     ret result;
@@ -1281,14 +1356,19 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
                         while (i < expected_len) {
                             auto expected_field = expected_fields.(i);
                             auto actual_field = actual_fields.(i);
-                            if (expected_field.ty.mut
-                                != actual_field.ty.mut) {
-                                auto err = terr_record_mutability;
-                                ret ures_err(err, expected, actual);
+
+                            auto mut;
+                            alt (unify_mut(expected_field.mt.mut,
+                                           actual_field.mt.mut)) {
+                                case (none[ast.mutability]) {
+                                    ret ures_err(terr_record_mutability,
+                                                 expected, actual);
+                                }
+                                case (some[ast.mutability](?m)) { mut = m; }
                             }
 
                             if (!_str.eq(expected_field.ident,
-                                        actual_field.ident)) {
+                                         actual_field.ident)) {
                                 auto err =
                                     terr_record_fields(expected_field.ident,
                                                        actual_field.ident);
@@ -1296,14 +1376,15 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
                             }
 
                             auto result = unify_step(bindings,
-                                                     expected_field.ty,
-                                                     actual_field.ty,
+                                                     expected_field.mt.ty,
+                                                     actual_field.mt.ty,
                                                      handler);
                             alt (result) {
                                 case (ures_ok(?rty)) {
-                                    append[field]
+                                    auto mt = rec(ty=rty, mut=mut);
+                                    _vec.push[field]
                                         (result_fields,
-                                         rec(ty=rty with expected_field));
+                                         rec(mt=mt with expected_field));
                                 }
                                 case (_) {
                                     ret result;
@@ -1440,6 +1521,12 @@ fn type_err_to_str(&ty.type_err err) -> str {
         case (terr_mismatch) {
             ret "types differ";
         }
+        case (terr_box_mutability) {
+            ret "boxed values differ in mutability";
+        }
+        case (terr_vec_mutability) {
+            ret "vectors differ in mutability";
+        }
         case (terr_tuple_size(?e_sz, ?a_sz)) {
             ret "expected a tuple with " + _uint.to_str(e_sz, 10u) +
                 " elements but found one with " + _uint.to_str(a_sz, 10u) +
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 1818c4fda17..14d4f714b0b 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -4,7 +4,6 @@ import front.ast.mutability;
 import middle.fold;
 import driver.session;
 import util.common;
-import util.common.append;
 import util.common.span;
 
 import middle.ty;
@@ -277,6 +276,10 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty.t {
         ret rec(mode=arg.mode, ty=ast_ty_to_ty(getter, arg.ty));
     }
 
+    fn ast_mt_to_mt(ty_getter getter, &ast.mt mt) -> ty.mt {
+        ret rec(ty=ast_ty_to_ty(getter, mt.ty), mut=mt.mut);
+    }
+
     fn instantiate(ty_getter getter, ast.def_id id,
                    vec[@ast.ty] args) -> @ty.t {
         // TODO: maybe record cname chains so we can do
@@ -306,8 +309,8 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty.t {
         case (ast.ty_machine(?tm)) { sty = ty.ty_machine(tm); }
         case (ast.ty_char)         { sty = ty.ty_char; }
         case (ast.ty_str)          { sty = ty.ty_str; }
-        case (ast.ty_box(?t)) { sty = ty.ty_box(ast_ty_to_ty(getter, t)); }
-        case (ast.ty_vec(?t)) { sty = ty.ty_vec(ast_ty_to_ty(getter, t)); }
+        case (ast.ty_box(?mt)) { sty = ty.ty_box(ast_mt_to_mt(getter, mt)); }
+        case (ast.ty_vec(?mt)) { sty = ty.ty_vec(ast_mt_to_mt(getter, mt)); }
 
         case (ast.ty_port(?t)) {
             sty = ty.ty_port(ast_ty_to_ty(getter, t));
@@ -318,17 +321,17 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty.t {
         }
 
         case (ast.ty_tup(?fields)) {
-            let vec[@ty.t] flds = vec();
-            for (@ast.ty field in fields) {
-                append[@ty.t](flds, ast_ty_to_ty(getter, field));
+            let vec[ty.mt] flds = vec();
+            for (ast.mt field in fields) {
+                _vec.push[ty.mt](flds, ast_mt_to_mt(getter, field));
             }
             sty = ty.ty_tup(flds);
         }
         case (ast.ty_rec(?fields)) {
             let vec[field] flds = vec();
             for (ast.ty_field f in fields) {
-                append[field](flds, rec(ident=f.ident,
-                                        ty=ast_ty_to_ty(getter, f.ty)));
+                _vec.push[field](flds, rec(ident=f.ident,
+                                        mt=ast_mt_to_mt(getter, f.mt)));
             }
             sty = ty.ty_rec(flds);
         }
@@ -358,30 +361,24 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty.t {
             cname = some(path_to_str(path));
         }
 
-        case (ast.ty_mutable(?t)) {
-            mut = ast.mut;
-            auto t0 = ast_ty_to_ty(getter, t);
-            sty = t0.struct;
-            cname = t0.cname;
-        }
-
         case (ast.ty_obj(?meths)) {
             let vec[ty.method] tmeths = vec();
             auto f = bind ast_arg_to_arg(getter, _);
             for (ast.ty_method m in meths) {
                 auto ins = _vec.map[ast.ty_arg, arg](f, m.inputs);
                 auto out = ast_ty_to_ty(getter, m.output);
-                append[ty.method](tmeths,
+                _vec.push[ty.method](tmeths,
                                   rec(proto=m.proto,
                                       ident=m.ident,
                                       inputs=ins,
                                       output=out));
             }
-            sty = ty.ty_obj(tmeths);
+
+            sty = ty.ty_obj(ty.sort_methods(tmeths));
         }
     }
 
-    ret @rec(struct=sty, mut=mut, cname=cname);
+    ret @rec(struct=sty, cname=cname);
 }
 
 fn actual_type(@ty.t t, @ast.item item) -> @ty.t {
@@ -546,14 +543,7 @@ fn collect_item_types(session.session sess, @ast.crate crate)
         auto methods =
             _vec.map[@ast.method,method](f, obj_info.methods);
 
-        fn method_lteq(&method a, &method b) -> bool {
-            ret _str.lteq(a.ident, b.ident);
-        }
-
-        methods = std.sort.merge_sort[method](bind method_lteq(_,_),
-                                              methods);
-
-        auto t_obj = plain_ty(ty.ty_obj(methods));
+        auto t_obj = plain_ty(ty.ty_obj(ty.sort_methods(methods)));
         ret t_obj;
     }
 
@@ -565,7 +555,7 @@ fn collect_item_types(session.session sess, @ast.crate crate)
         for (ast.obj_field f in obj_info.fields) {
             auto g = bind getter(id_to_ty_item, item_to_ty, _);
             auto t_field = ast_ty_to_ty(g, f.ty);
-            append[arg](t_inputs, rec(mode=ast.alias, ty=t_field));
+            _vec.push[arg](t_inputs, rec(mode=ast.alias, ty=t_field));
         }
         auto t_fn = plain_ty(ty.ty_fn(ast.proto_fn, t_inputs, t_obj));
         ret t_fn;
@@ -645,8 +635,7 @@ fn collect_item_types(session.session sess, @ast.crate crate)
                     // Avoid repeating work.
                     ret item_to_ty.get(def_id);
                 }
-                auto x =
-                    @rec(struct=ty.ty_native, mut=ast.imm, cname=none[str]);
+                auto x = @rec(struct=ty.ty_native, cname=none[str]);
                 item_to_ty.insert(def_id, x);
                 ret x;
             }
@@ -870,7 +859,7 @@ fn collect_item_types(session.session sess, @ast.crate crate)
                 with meth.node
             );
             m = @rec(node=m_ with *meth);
-            append[@ast.method](methods, m);
+            _vec.push[@ast.method](methods, m);
         }
         auto g = bind getter(e.id_to_ty_item, e.item_to_ty, _);
         for (ast.obj_field fld in ob.fields) {
@@ -879,7 +868,7 @@ fn collect_item_types(session.session sess, @ast.crate crate)
                 ann=ast.ann_type(fty, none[vec[@ty.t]])
                 with fld
             );
-            append[ast.obj_field](fields, f);
+            _vec.push[ast.obj_field](fields, f);
         }
 
         auto ob_ = rec(methods = methods,
@@ -980,7 +969,7 @@ fn strip_boxes(@ty.t t) -> @ty.t {
     auto t1 = t;
     while (true) {
         alt (t1.struct) {
-            case (ty.ty_box(?inner)) { t1 = inner; }
+            case (ty.ty_box(?inner)) { t1 = inner.ty; }
             case (_) { ret t1; }
         }
     }
@@ -990,7 +979,7 @@ fn strip_boxes(@ty.t t) -> @ty.t {
 fn add_boxes(uint n, @ty.t t) -> @ty.t {
     auto t1 = t;
     while (n != 0u) {
-        t1 = plain_ty(ty.ty_box(t1));
+        t1 = ty.plain_box_ty(t1);
         n -= 1u;
     }
     ret t1;
@@ -1002,7 +991,7 @@ fn count_boxes(@ty.t t) -> uint {
     auto t1 = t;
     while (true) {
         alt (t1.struct) {
-            case (ty.ty_box(?inner)) { n += 1u; t1 = inner; }
+            case (ty.ty_box(?inner)) { n += 1u; t1 = inner.ty; }
             case (_) { ret n; }
         }
     }
@@ -1150,13 +1139,15 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
     auto e_1;
 
     alt (e.node) {
-        case (ast.expr_vec(?es_0, ?ann)) {
+        case (ast.expr_vec(?es_0, ?mut, ?ann)) {
+            // TODO: enforce mutability
+
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
             let vec[@ast.expr] es_1 = vec();
             alt (t.struct) {
-                case (ty.ty_vec(?subty)) {
+                case (ty.ty_vec(?mt)) {
                     for (@ast.expr e_0 in es_0) {
-                        es_1 += vec(demand_expr(fcx, subty, e_0));
+                        es_1 += vec(demand_expr(fcx, mt.ty, e_0));
                     }
                 }
                 case (_) {
@@ -1164,16 +1155,16 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
                     fail;
                 }
             }
-            e_1 = ast.expr_vec(es_1, ast.ann_type(t, none[vec[@ty.t]]));
+            e_1 = ast.expr_vec(es_1, mut, ast.ann_type(t, none[vec[@ty.t]]));
         }
         case (ast.expr_tup(?es_0, ?ann)) {
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
             let vec[ast.elt] elts_1 = vec();
             alt (t.struct) {
-                case (ty.ty_tup(?subtys)) {
+                case (ty.ty_tup(?mts)) {
                     auto i = 0u;
                     for (ast.elt elt_0 in es_0) {
-                        auto e_1 = demand_expr(fcx, subtys.(i), elt_0.expr);
+                        auto e_1 = demand_expr(fcx, mts.(i).ty, elt_0.expr);
                         elts_1 += vec(rec(mut=elt_0.mut, expr=e_1));
                         i += 1u;
                     }
@@ -1192,15 +1183,15 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
             let vec[ast.field] fields_1 = vec();
             alt (t.struct) {
-                case (ty.ty_rec(?field_tys)) {
+                case (ty.ty_rec(?field_mts)) {
                     alt (base_0) {
                         case (none[@ast.expr]) {
                             auto i = 0u;
                             for (ast.field field_0 in fields_0) {
                                 check (_str.eq(field_0.ident,
-                                               field_tys.(i).ident));
+                                               field_mts.(i).ident));
                                 auto e_1 = demand_expr(fcx,
-                                                       field_tys.(i).ty,
+                                                       field_mts.(i).mt.ty,
                                                        field_0.expr);
                                 fields_1 += vec(rec(mut=field_0.mut,
                                                     ident=field_0.ident,
@@ -1217,9 +1208,9 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
 
                             for (ast.field field_0 in fields_0) {
 
-                                for (ty.field ft in field_tys) {
+                                for (ty.field ft in field_mts) {
                                     if (_str.eq(field_0.ident, ft.ident)) {
-                                        auto e_1 = demand_expr(fcx, ft.ty,
+                                        auto e_1 = demand_expr(fcx, ft.mt.ty,
                                                                field_0.expr);
                                         fields_1 +=
                                             vec(rec(mut=field_0.mut,
@@ -1411,7 +1402,8 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
         }
 
         case (_) {
-            fcx.ccx.sess.unimpl("type unification for expression variant");
+            fcx.ccx.sess.span_unimpl(e.span,
+                "type unification for expression variant");
             fail;
         }
     }
@@ -1438,8 +1430,10 @@ fn demand_block(&@fn_ctxt fcx, @ty.t expected, &ast.block bloc) -> ast.block {
 
 // Writeback: the phase that writes inferred types back into the AST.
 
-fn writeback_local(&@fn_ctxt fcx, &span sp, @ast.local local)
+fn writeback_local(&option.t[@fn_ctxt] env, &span sp, @ast.local local)
         -> @ast.decl {
+    auto fcx = option.get[@fn_ctxt](env);
+
     if (!fcx.locals.contains_key(local.id)) {
         fcx.ccx.sess.span_err(sp, "unable to determine type of local: "
                               + local.ident);
@@ -1453,10 +1447,25 @@ fn writeback_local(&@fn_ctxt fcx, &span sp, @ast.local local)
 }
 
 fn writeback(&@fn_ctxt fcx, &ast.block block) -> ast.block {
-    auto fld = fold.new_identity_fold[@fn_ctxt]();
-    auto f = writeback_local;
-    fld = @rec(fold_decl_local = f with *fld);
-    ret fold.fold_block[@fn_ctxt](fcx, fld, block);
+    fn update_env_for_item(&option.t[@fn_ctxt] env, @ast.item i)
+            -> option.t[@fn_ctxt] {
+        ret none[@fn_ctxt];
+    }
+    fn keep_going(&option.t[@fn_ctxt] env) -> bool {
+        ret !option.is_none[@fn_ctxt](env);
+    }
+
+    auto fld = fold.new_identity_fold[option.t[@fn_ctxt]]();
+    auto wbl = writeback_local;
+    auto uefi = update_env_for_item;
+    auto kg = keep_going;
+    fld = @rec(
+        fold_decl_local = wbl,
+        update_env_for_item = uefi,
+        keep_going = kg
+        with *fld
+    );
+    ret fold.fold_block[option.t[@fn_ctxt]](some[@fn_ctxt](fcx), fld, block);
 }
 
 // AST fragment checking
@@ -1572,14 +1581,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
                     // FIXME: this breaks aliases. We need a ty_fn_arg.
                     auto arg_ty = rec(mode=ast.val, ty=expr_ty(a_0));
-                    append[arg](arg_tys_0, arg_ty);
+                    _vec.push[arg](arg_tys_0, arg_ty);
                 }
                 case (none[@ast.expr]) {
                     args_0 += vec(none[@ast.expr]);
 
                     // FIXME: breaks aliases too?
                     auto typ = next_ty_var(fcx.ccx);
-                    append[arg](arg_tys_0, rec(mode=ast.val, ty=typ));
+                    _vec.push[arg](arg_tys_0, rec(mode=ast.val, ty=typ));
                 }
             }
         }
@@ -1623,10 +1632,11 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                 case (some[@ast.expr](?e_0)) {
                     auto arg_ty_1 = arg_tys_1.(i);
                     auto e_1 = demand_expr(fcx, arg_ty_1.ty, e_0);
-                    append[option.t[@ast.expr]](args_1, some[@ast.expr](e_1));
+                    _vec.push[option.t[@ast.expr]](args_1,
+                                                   some[@ast.expr](e_1));
                 }
                 case (none[@ast.expr]) {
-                    append[option.t[@ast.expr]](args_1, none[@ast.expr]);
+                    _vec.push[option.t[@ast.expr]](args_1, none[@ast.expr]);
                 }
             }
 
@@ -1693,11 +1703,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             auto oper_1 = check_expr(fcx, oper);
             auto oper_t = expr_ty(oper_1);
             alt (unop) {
-                case (ast.box) { oper_t = plain_ty(ty.ty_box(oper_t)); }
+                case (ast.box) {
+                    // TODO: mutable
+                    oper_t = ty.plain_box_ty(oper_t);
+                }
                 case (ast.deref) {
                     alt (oper_t.struct) {
-                        case (ty.ty_box(?inner_t)) {
-                            oper_t = inner_t;
+                        case (ty.ty_box(?inner)) {
+                            oper_t = inner.ty;
                         }
                         case (_) {
                             fcx.ccx.sess.span_err
@@ -1707,9 +1720,6 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                         }
                     }
                 }
-                case (ast._mutable) {
-                    oper_t = @rec(mut=ast.mut with *oper_t);
-                }
                 case (_) { oper_t = strip_boxes(oper_t); }
             }
 
@@ -2096,12 +2106,9 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                                         ast.expr_cast(e_1, t, ann));
         }
 
-        case (ast.expr_vec(?args, _)) {
+        case (ast.expr_vec(?args, ?mut, _)) {
             let vec[@ast.expr] args_1 = vec();
 
-            // FIXME: implement mutable vectors with leading 'mutable' flag
-            // marking the elements as mutable.
-
             let @ty.t t;
             if (_vec.len[@ast.expr](args) == 0u) {
                 t = next_ty_var(fcx.ccx);
@@ -2114,28 +2121,27 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                 auto expr_1 = check_expr(fcx, e);
                 auto expr_t = expr_ty(expr_1);
                 demand(fcx, expr.span, t, expr_t);
-                append[@ast.expr](args_1,expr_1);
+                _vec.push[@ast.expr](args_1,expr_1);
             }
-            auto ann = ast.ann_type(plain_ty(ty.ty_vec(t)), none[vec[@ty.t]]);
+
+            auto vec_sty = ty.ty_vec(rec(ty=t, mut=mut));
+            auto ann = ast.ann_type(plain_ty(vec_sty), none[vec[@ty.t]]);
             ret @fold.respan[ast.expr_](expr.span,
-                                        ast.expr_vec(args_1, ann));
+                                        ast.expr_vec(args_1, mut, ann));
         }
 
         case (ast.expr_tup(?elts, _)) {
             let vec[ast.elt] elts_1 = vec();
-            let vec[@ty.t] elts_t = vec();
+            let vec[ty.mt] elts_mt = vec();
 
             for (ast.elt e in elts) {
                 auto expr_1 = check_expr(fcx, e.expr);
                 auto expr_t = expr_ty(expr_1);
-                if (e.mut == ast.mut) {
-                    expr_t = @rec(mut=ast.mut with *expr_t);
-                }
-                append[ast.elt](elts_1, rec(expr=expr_1 with e));
-                append[@ty.t](elts_t, expr_t);
+                _vec.push[ast.elt](elts_1, rec(expr=expr_1 with e));
+                elts_mt += vec(rec(ty=expr_t, mut=e.mut));
             }
 
-            auto ann = ast.ann_type(plain_ty(ty.ty_tup(elts_t)),
+            auto ann = ast.ann_type(plain_ty(ty.ty_tup(elts_mt)),
                                     none[vec[@ty.t]]);
             ret @fold.respan[ast.expr_](expr.span,
                                         ast.expr_tup(elts_1, ann));
@@ -2157,11 +2163,10 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             for (ast.field f in fields) {
                 auto expr_1 = check_expr(fcx, f.expr);
                 auto expr_t = expr_ty(expr_1);
-                if (f.mut == ast.mut) {
-                    expr_t = @rec(mut=ast.mut with *expr_t);
-                }
-                append[ast.field](fields_1, rec(expr=expr_1 with f));
-                append[field](fields_t, rec(ident=f.ident, ty=expr_t));
+                _vec.push[ast.field](fields_1, rec(expr=expr_1 with f));
+
+                auto expr_mt = rec(ty=expr_t, mut=f.mut);
+                _vec.push[field](fields_t, rec(ident=f.ident, mt=expr_mt));
             }
 
             auto ann = ast.ann_none;
@@ -2195,7 +2200,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                         auto found = false;
                         for (ty.field bf in base_fields) {
                             if (_str.eq(f.ident, bf.ident)) {
-                                demand(fcx, expr.span, f.ty, bf.ty);
+                                demand(fcx, expr.span, f.mt.ty, bf.mt.ty);
                                 found = true;
                             }
                         }
@@ -2220,11 +2225,11 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                 case (ty.ty_tup(?args)) {
                     let uint ix = ty.field_num(fcx.ccx.sess,
                                                expr.span, field);
-                    if (ix >= _vec.len[@ty.t](args)) {
+                    if (ix >= _vec.len[ty.mt](args)) {
                         fcx.ccx.sess.span_err(expr.span,
                                               "bad index on tuple");
                     }
-                    auto ann = ast.ann_type(args.(ix), none[vec[@ty.t]]);
+                    auto ann = ast.ann_type(args.(ix).ty, none[vec[@ty.t]]);
                     ret @fold.respan[ast.expr_](expr.span,
                                                 ast.expr_field(base_1,
                                                                field,
@@ -2238,7 +2243,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                         fcx.ccx.sess.span_err(expr.span,
                                               "bad index on record");
                     }
-                    auto ann = ast.ann_type(fields.(ix).ty, none[vec[@ty.t]]);
+                    auto ann = ast.ann_type(fields.(ix).mt.ty,
+                                            none[vec[@ty.t]]);
                     ret @fold.respan[ast.expr_](expr.span,
                                                 ast.expr_field(base_1,
                                                                field,
@@ -2278,14 +2284,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             auto idx_t = expr_ty(idx_1);
 
             alt (base_t.struct) {
-                case (ty.ty_vec(?t)) {
+                case (ty.ty_vec(?mt)) {
                     if (! type_is_integral(idx_t)) {
                         fcx.ccx.sess.span_err
                             (idx.span,
                              "non-integral type of vec index: "
                              + ty_to_str(idx_t));
                     }
-                    auto ann = ast.ann_type(t, none[vec[@ty.t]]);
+                    auto ann = ast.ann_type(mt.ty, none[vec[@ty.t]]);
                     ret @fold.respan[ast.expr_](expr.span,
                                                 ast.expr_index(base_1,
                                                                idx_1,
@@ -2418,7 +2424,7 @@ fn check_stmt(&@fn_ctxt fcx, &@ast.stmt stmt) -> @ast.stmt {
 fn check_block(&@fn_ctxt fcx, &ast.block block) -> ast.block {
     let vec[@ast.stmt] stmts = vec();
     for (@ast.stmt s in block.node.stmts) {
-        append[@ast.stmt](stmts, check_stmt(fcx, s));
+        _vec.push[@ast.stmt](stmts, check_stmt(fcx, s));
     }
 
     auto expr = none[@ast.expr];
diff --git a/src/comp/pretty/pp.rs b/src/comp/pretty/pp.rs
index d3145180282..0c355001e95 100644
--- a/src/comp/pretty/pp.rs
+++ b/src/comp/pretty/pp.rs
@@ -39,12 +39,12 @@ fn mkstate(io.writer out, uint width) -> ps {
 
 impure fn push_context(ps p, contexttype tp, uint indent) {
   before_print(p, false);
-  p.context = _vec.push[context](p.context, rec(tp=tp, indent=base_indent(p)
-                                                + indent));
+  _vec.push[context](p.context, rec(tp=tp, indent=base_indent(p)
+                                    + indent));
 }
 
-impure fn pop_context(ps p) {
-  p.context = _vec.pop[context](p.context);
+fn pop_context(ps p) {
+  _vec.pop[context](p.context);
 }
 
 impure fn add_token(ps p, token tok) {
@@ -110,7 +110,8 @@ impure fn finish_block_scan(ps p, contexttype tp) {
   }
   p.scandepth = 0u;
   push_context(p, tp, indent);
-  for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
+  _vec.shift[token](p.buffered);
+  for (token t in p.buffered) { add_token(p, t); }
 }
 
 impure fn finish_break_scan(ps p) {
@@ -125,7 +126,8 @@ impure fn finish_break_scan(ps p) {
     p.col += width;
   }
   p.scandepth = 0u;
-  for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
+  _vec.shift[token](p.buffered);
+  for (token t in p.buffered) { add_token(p, t); }
 }
 
 impure fn start_scan(ps p, token tok) {
diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs
index a25bc44782f..6f5ea096b05 100644
--- a/src/comp/pretty/pprust.rs
+++ b/src/comp/pretty/pprust.rs
@@ -48,7 +48,7 @@ impure fn bclose(ps s) {
   end(s);
   pp.cwrd(s, "}");
 }
-impure fn commasep[IN](ps s, vec[IN] elts, impure fn (ps, IN) op) {
+impure fn commasep[IN](ps s, vec[IN] elts, impure fn (ps, &IN) op) {
   auto first = true;
   for (IN elt in elts) {
     if (first) {first = false;}
@@ -57,7 +57,16 @@ impure fn commasep[IN](ps s, vec[IN] elts, impure fn (ps, IN) op) {
   }
 }
 
-impure fn print_type(ps s, @ast.ty ty) {
+impure fn print_mt(ps s, &ast.mt mt) {
+    alt (mt.mut) {
+        case (ast.mut)       { wrd1(s, "mutable");  }
+        case (ast.maybe_mut) { wrd1(s, "mutable?"); }
+        case (ast.imm)       { /* nothing */        }
+    }
+    print_type(s, mt.ty);
+}
+
+impure fn print_type(ps s, &@ast.ty ty) {
   hbox(s);
   alt (ty.node) {
     case (ast.ty_nil) {wrd(s, "()");}
@@ -67,22 +76,22 @@ impure fn print_type(ps s, @ast.ty ty) {
     case (ast.ty_machine(?tm)) {wrd(s, util.common.ty_mach_to_str(tm));}
     case (ast.ty_char) {wrd(s, "char");}
     case (ast.ty_str) {wrd(s, "str");}
-    case (ast.ty_box(?t)) {wrd(s, "@"); print_type(s, t);}
-    case (ast.ty_vec(?t)) {wrd(s, "vec["); print_type(s, t); wrd(s, "]");}
+    case (ast.ty_box(?mt)) {wrd(s, "@"); print_mt(s, mt);}
+    case (ast.ty_vec(?mt)) {wrd(s, "vec["); print_mt(s, mt); wrd(s, "]");}
     case (ast.ty_type) {wrd(s, "type");}
     case (ast.ty_tup(?elts)) {
       wrd(s, "tup");
       popen(s);
-      auto f = print_type;
-      commasep[@ast.ty](s, elts, f);
+      auto f = print_mt;
+      commasep[ast.mt](s, elts, f);
       pclose(s);
     }
     case (ast.ty_rec(?fields)) {
       wrd(s, "rec");
       popen(s);
-      impure fn print_field(ps s, ast.ty_field f) {
+      impure fn print_field(ps s, &ast.ty_field f) {
         hbox(s);
-        print_type(s, f.ty);
+        print_mt(s, f.mt);
         space(s);
         wrd(s, f.ident);
         end(s);
@@ -110,10 +119,6 @@ impure fn print_type(ps s, @ast.ty ty) {
     case (ast.ty_path(?path,_)) {
       print_path(s, path);
     }
-    case (ast.ty_mutable(?t)) {
-      wrd1(s, "mutable");
-      print_type(s, t);
-    }
   }
   end(s);
 }
@@ -186,7 +191,7 @@ impure fn print_item(ps s, @ast.item item) {
         wrd(s, v.name);
         if (_vec.len[ast.variant_arg](v.args) > 0u) {
           popen(s);
-          impure fn print_variant_arg(ps s, ast.variant_arg arg) {
+          impure fn print_variant_arg(ps s, &ast.variant_arg arg) {
             print_type(s, arg.ty);
           }
           auto f = print_variant_arg;
@@ -203,7 +208,7 @@ impure fn print_item(ps s, @ast.item item) {
       wrd(s, id);
       print_type_params(s, params);
       popen(s);
-      impure fn print_field(ps s, ast.obj_field field) {
+      impure fn print_field(ps s, &ast.obj_field field) {
         hbox(s);
         print_type(s, field.ty);
         space(s);
@@ -285,18 +290,21 @@ impure fn print_literal(ps s, @ast.lit lit) {
   }
 }
 
-impure fn print_expr(ps s, @ast.expr expr) {
+impure fn print_expr(ps s, &@ast.expr expr) {
   auto pe = print_expr;
   hbox(s);
   alt (expr.node) {
-    case (ast.expr_vec(?exprs,_)) {
+    case (ast.expr_vec(?exprs,?mut,_)) {
+      if (mut == ast.mut) {
+        wrd1(s, "mutable");
+      }
       wrd(s, "vec");
       popen(s);
       commasep[@ast.expr](s, exprs, pe);
       pclose(s);
     }
     case (ast.expr_tup(?exprs,_)) {
-      impure fn printElt(ps s, ast.elt elt) {
+      impure fn printElt(ps s, &ast.elt elt) {
         hbox(s);
         if (elt.mut == ast.mut) {wrd1(s, "mutable");}
         print_expr(s, elt.expr);
@@ -309,7 +317,7 @@ impure fn print_expr(ps s, @ast.expr expr) {
       pclose(s);
     }
     case (ast.expr_rec(?fields,?wth,_)) {
-      impure fn print_field(ps s, ast.field field) {
+      impure fn print_field(ps s, &ast.field field) {
         hbox(s);
         if (field.mut == ast.mut) {wrd1(s, "mutable");}
         wrd(s, field.ident);
@@ -340,7 +348,7 @@ impure fn print_expr(ps s, @ast.expr expr) {
       pclose(s);
     }
     case (ast.expr_bind(?func,?args,_)) {
-      impure fn print_opt(ps s, option.t[@ast.expr] expr) {
+      impure fn print_opt(ps s, &option.t[@ast.expr] expr) {
         alt (expr) {
           case (option.some[@ast.expr](?expr)) {
             print_expr(s, expr);
@@ -364,7 +372,6 @@ impure fn print_expr(ps s, @ast.expr expr) {
     }
     case (ast.expr_unary(?op,?expr,_)) {
       wrd(s, ast.unop_to_str(op));
-      if (op == ast._mutable) {space(s);}
       print_expr(s, expr);
     }
     case (ast.expr_lit(?lit,_)) {
@@ -577,7 +584,7 @@ impure fn print_path(ps s, ast.path path) {
   }
 }
 
-impure fn print_pat(ps s, @ast.pat pat) {
+impure fn print_pat(ps s, &@ast.pat pat) {
   alt (pat.node) {
     case (ast.pat_wild(_)) {wrd(s, "_");}
     case (ast.pat_bind(?id,_,_)) {wrd(s, "?" + id);}
@@ -605,7 +612,7 @@ impure fn print_fn(ps s, ast.fn_decl decl, str name,
   wrd(s, name);
   print_type_params(s, typarams);
   popen(s);
-  impure fn print_arg(ps s, ast.arg x) {
+  impure fn print_arg(ps s, &ast.arg x) {
     hbox(s);
     print_type(s, x.ty);
     space(s);
@@ -627,7 +634,7 @@ impure fn print_fn(ps s, ast.fn_decl decl, str name,
 impure fn print_type_params(ps s, vec[ast.ty_param] params) {
   if (_vec.len[ast.ty_param](params) > 0u) {
     wrd(s, "[");
-    impure fn printParam(ps s, ast.ty_param param) {wrd(s, param.ident);}
+    impure fn printParam(ps s, &ast.ty_param param) {wrd(s, param.ident);}
     auto f = printParam;
     commasep[ast.ty_param](s, params, f);
     wrd(s, "]");
@@ -642,7 +649,7 @@ impure fn print_view_item(ps s, @ast.view_item item) {
       wrd(s, id);
       if (_vec.len[@ast.meta_item](mta) > 0u) {
         popen(s);
-        impure fn print_meta(ps s, @ast.meta_item item) {
+        impure fn print_meta(ps s, &@ast.meta_item item) {
           hbox(s);
           wrd1(s, item.node.name);
           wrd1(s, "=");
@@ -717,7 +724,7 @@ fn escape_str(str st, char to_escape) -> str {
       case ('\\') {out += "\\\\";}
       case (?cur) {
         if (cur == to_escape) {out += "\\";}
-        out += cur as u8;
+        _str.push_byte(out, cur as u8);
       }
     }
     i += 1u;
@@ -738,7 +745,7 @@ impure fn print_ty_fn(ps s, ast.proto proto, option.t[str] id,
     case (_) {}
   }
   popen(s);
-  impure fn print_arg(ps s, ast.ty_arg input) {
+  impure fn print_arg(ps s, &ast.ty_arg input) {
     if (middle.ty.mode_is_alias(input.mode)) {wrd(s, "&");}
     print_type(s, input.ty);
   }
diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs
index 63ec2c692b1..4b4f54818e9 100644
--- a/src/comp/util/common.rs
+++ b/src/comp/util/common.rs
@@ -68,15 +68,6 @@ fn istr(int i) -> str {
     ret _int.to_str(i, 10u);
 }
 
-
-// FIXME: Weird bug. Due to the way we auto-deref + in +=, we can't append a
-// boxed value to a vector-of-boxes using +=.  Best to figure out a way to fix
-// this. Deref-on-demand or something? It's a hazard of the ambiguity between
-// single-element and vector append.
-fn append[T](&mutable vec[T] v, &T t) {
-    v += t;
-}
-
 //
 // Local Variables:
 // mode: rust
diff --git a/src/configure.sh b/src/configure.sh
deleted file mode 100644
index eb7416805aa..00000000000
--- a/src/configure.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-
-CFG_SRC_DIR=${0%${0##*/}}
-CFG_BUILD_DIR=$PWD
-
-CFG_OSTYPE=$(uname -s)
-CFG_CPUTYPE=$(uname -m)
-
-echo "configuring on $CFG_CPUTYPE $CFG_OSTYPE"
-
-echo "setting up build directories"
-for i in boot/{fe,me,be,driver,util} \
-         rt/{isaac,bigint,sync,test} \
-         stage{0,1,2}                \
-         test/{run-pass,compile-{pass,fail}}
-do
-    mkdir -p -v $i
-done
-
-CFG_VALGRIND=$(sh which valgrind)
-CFG_OCAMLC_OPT=$(sh which ocamlc.opt)
-
-echo "copying Makefile"
-cp -v ${CFG_SRC_DIR}Makefile.in ./Makefile
-
-echo "writing config.mk"
-cat >config.mk <<EOF
-
-CFG_OSTYPE        := $CFG_OSTYPE
-CFG_CPUTYPE       := $CFG_CPUTYPE
-CFG_SRC_DIR       := $CFG_SRC_DIR
-CFG_BUILD_DIR     := $CFG_BUILD_DIR
-
-CFG_VALGRIND      := $CFG_VALGRIND
-CFG_OCAMLC_OPT    := $CFG_OCAMLC_OPT
-
-EOF
-
-echo "configured ok"
diff --git a/src/lib/_str.rs b/src/lib/_str.rs
index 526dac8f21f..93d0a9f286a 100644
--- a/src/lib/_str.rs
+++ b/src/lib/_str.rs
@@ -8,6 +8,8 @@ native "rust" mod rustrt {
     fn str_byte_len(str s) -> uint;
     fn str_alloc(uint n_bytes) -> str;
     fn str_from_vec(vec[u8] b) -> str;
+    fn str_from_cstr(sbuf cstr) -> str;
+    fn str_from_buf(sbuf buf, uint len) -> str;
     fn refcount[T](str s) -> uint;
 }
 
@@ -111,6 +113,19 @@ fn unsafe_from_bytes(vec[u8] v) -> str {
     ret rustrt.str_from_vec(v);
 }
 
+fn unsafe_from_byte(u8 u) -> str {
+    ret rustrt.str_from_vec(vec(u));
+}
+
+unsafe fn str_from_cstr(sbuf cstr) -> str {
+    ret rustrt.str_from_cstr(cstr);
+}
+
+unsafe fn str_from_buf(sbuf buf, uint len) -> str {
+    ret rustrt.str_from_buf(buf, len);
+}
+
+
 fn refcount(str s) -> uint {
     auto r = rustrt.refcount[u8](s);
     if (r == dbg.const_refcount) {
@@ -190,7 +205,6 @@ fn starts_with(str haystack, str needle) -> bool {
     ret eq(substr(haystack, 0u, needle_len), needle);
 }
 
-
 fn ends_with(str haystack, str needle) -> bool {
     let uint haystack_len = byte_len(haystack);
     let uint needle_len = byte_len(needle);
@@ -206,34 +220,60 @@ fn ends_with(str haystack, str needle) -> bool {
            needle);
 }
 
-
 fn substr(str s, uint begin, uint len) -> str {
     let str accum = "";
     let uint i = begin;
     while (i < begin+len) {
-        accum += s.(i);
+        accum += unsafe_from_byte(s.(i));
         i += 1u;
     }
     ret accum;
 }
 
+fn shift_byte(&mutable str s) -> u8 {
+    auto len = byte_len(s);
+    check(len > 0u);
+    auto b = s.(0);
+    s = substr(s, 1u, len - 1u);
+    ret b;
+}
+
+fn pop_byte(&mutable str s) -> u8 {
+    auto len = byte_len(s);
+    check(len > 0u);
+    auto b = s.(len - 1u);
+    s = substr(s, 0u, len - 1u);
+    ret b;
+}
+
+fn push_byte(&mutable str s, u8 b) {
+    s += unsafe_from_byte(b);
+}
+
+fn unshift_byte(&mutable str s, u8 b) {
+    auto res = alloc(byte_len(s) + 1u);
+    res += unsafe_from_byte(b);
+    res += s;
+    s = res;
+}
+
 fn split(str s, u8 sep) -> vec[str] {
     let vec[str] v = vec();
     let str accum = "";
     let bool ends_with_sep = false;
     for (u8 c in s) {
         if (c == sep) {
-            v += accum;
+            v += vec(accum);
             accum = "";
             ends_with_sep = true;
         } else {
-            accum += c;
+            accum += unsafe_from_byte(c);
             ends_with_sep = false;
         }
     }
     if (_str.byte_len(accum) != 0u ||
         ends_with_sep) {
-        v += accum;
+        v += vec(accum);
     }
     ret v;
 }
diff --git a/src/lib/_uint.rs b/src/lib/_uint.rs
index ceee9c77478..5e8d4b975e3 100644
--- a/src/lib/_uint.rs
+++ b/src/lib/_uint.rs
@@ -61,7 +61,7 @@ fn to_str(mutable uint n, uint radix) -> str
 
     let str s = "";
     while (n != 0u) {
-        s += digit(n % radix) as u8;
+        s += _str.unsafe_from_byte(digit(n % radix) as u8);
         n /= radix;
     }
 
@@ -69,7 +69,7 @@ fn to_str(mutable uint n, uint radix) -> str
     let uint len = _str.byte_len(s);
     while (len != 0u) {
         len -= 1u;
-        s1 += s.(len);
+        s1 += _str.unsafe_from_byte(s.(len));
     }
     ret s1;
 
diff --git a/src/lib/_vec.rs b/src/lib/_vec.rs
index 680c8884f6d..80cd242d2c8 100644
--- a/src/lib/_vec.rs
+++ b/src/lib/_vec.rs
@@ -103,28 +103,32 @@ fn slice[T](vec[T] v, uint start, uint end) -> vec[T] {
     ret result;
 }
 
-fn shift[T](vec[T] v) -> vec[T] {
-    check(len[T](v) > 0u);
-    ret slice[T](v, 1u, len[T](v));
+fn shift[T](&mutable vec[T] v) -> T {
+    auto ln = len[T](v);
+    check(ln > 0u);
+    auto e = v.(0);
+    v = slice[T](v, 1u, ln);
+    ret e;
 }
 
-fn pop[T](vec[T] v) -> vec[T] {
-    check(len[T](v) > 0u);
-    ret slice[T](v, 0u, len[T](v) - 1u);
+fn pop[T](&mutable vec[T] v) -> T {
+    auto ln = len[T](v);
+    check(ln > 0u);
+    ln -= 1u;
+    auto e = v.(ln);
+    v = slice[T](v, 0u, ln);
+    ret e;
 }
 
-fn push[T](vec[T] v, &T t) -> vec[T] {
-    v += t;
-    ret v;
+fn push[T](&mutable vec[T] v, &T t) {
+    v += vec(t);
 }
 
-fn unshift[T](vec[T] v, &T t) -> vec[T] {
+fn unshift[T](&mutable vec[T] v, &T t) {
     auto res = alloc[T](len[T](v) + 1u);
-    res += t;
-    for (T t_ in v) {
-        res += t_;
-    }
-    ret res;
+    res += vec(t);
+    res += v;
+    v = res;
 }
 
 fn grow[T](&mutable vec[T] v, int n, &T initval) {
@@ -152,7 +156,7 @@ fn map2[T,U,V](&operator2[T,U,V] f, &vec[T] v0, &vec[U] v1) -> vec[V] {
     let vec[V] u = alloc[V](v0_len);
     auto i = 0u;
     while (i < v0_len) {
-        u += f(v0.(i), v1.(i));
+        u += vec(f(v0.(i), v1.(i)));
         i += 1u;
     }
 
diff --git a/src/lib/fs.rs b/src/lib/fs.rs
index 1b9ed4b0a8d..677bbcc4ec8 100644
--- a/src/lib/fs.rs
+++ b/src/lib/fs.rs
@@ -38,8 +38,18 @@ impure fn list_dir(path p) -> vec[str] {
   let vec[str] full_paths = vec();
   for (str filename in os_fs.list_dir(p)) {
     if (!_str.eq(filename, ".")) {if (!_str.eq(filename, "..")) {
-      full_paths = _vec.push[str](full_paths, p + filename);
+      _vec.push[str](full_paths, p + filename);
     }}
   }
   ret full_paths;
 }
+
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/lib/io.rs b/src/lib/io.rs
index 7135c2bc857..a84fbbe995e 100644
--- a/src/lib/io.rs
+++ b/src/lib/io.rs
@@ -52,7 +52,8 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) {
       auto buf = "";
       while (true) {
         auto ch = os.libc.fgetc(f);
-        if (ch == -1) {break;} if (ch == 10) {break;}
+        if (ch == -1) { ret buf; }
+        if (ch == 10) { ret buf; }
         buf += _str.unsafe_from_bytes(vec(ch as u8));
       }
       ret buf;
@@ -61,7 +62,7 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) {
         auto buf = "";
         while (true) {
             auto ch = os.libc.fgetc(f);
-            if (ch < 1) {break;}
+            if (ch < 1) { ret buf; }
             buf += _str.unsafe_from_bytes(vec(ch as u8));
         }
         ret buf;
diff --git a/src/lib/option.rs b/src/lib/option.rs
index 25f82b52a0e..29a6f6eb96b 100644
--- a/src/lib/option.rs
+++ b/src/lib/option.rs
@@ -31,6 +31,13 @@ fn map[T, U](&operator[T, U] f, &t[T] opt) -> t[U] {
     fail;   // FIXME: remove me when exhaustiveness checking works
 }
 
+fn is_none[T](&t[T] opt) -> bool {
+    alt (opt) {
+        case (none[T])      { ret true; }
+        case (some[T](_))   { ret false; }
+    }
+}
+
 // Local Variables:
 // mode: rust;
 // fill-column: 78;
diff --git a/src/lib/posix_fs.rs b/src/lib/posix_fs.rs
index 05366a15dbf..0a37f85d16e 100644
--- a/src/lib/posix_fs.rs
+++ b/src/lib/posix_fs.rs
@@ -9,11 +9,23 @@ impure fn list_dir(str path) -> vec[str] {
   let vec[str] result = vec();
   while (true) {
     auto ent = os.libc.readdir(dir);
-    if (ent as int == 0) {break;}
-    result = _vec.push[str](result, rustrt.rust_dirent_filename(ent));
+    if (ent as int == 0) {
+        os.libc.closedir(dir);
+        ret result;
+    }
+    _vec.push[str](result, rustrt.rust_dirent_filename(ent));
   }
   os.libc.closedir(dir);
   ret result;
 }
 
 const char path_sep = '/';
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/lib/run_program.rs b/src/lib/run_program.rs
index bd9edbc86ac..f3ea95a1d64 100644
--- a/src/lib/run_program.rs
+++ b/src/lib/run_program.rs
@@ -8,9 +8,9 @@ native "rust" mod rustrt {
 fn argvec(str prog, vec[str] args) -> vec[sbuf] {
     auto argptrs = vec(_str.buf(prog));
     for (str arg in args) {
-        argptrs = _vec.push[sbuf](argptrs, _str.buf(arg));
+        _vec.push[sbuf](argptrs, _str.buf(arg));
     }
-    argptrs = _vec.push[sbuf](argptrs, 0 as sbuf);
+    _vec.push[sbuf](argptrs, 0 as sbuf);
     ret argptrs;
 }
 
diff --git a/src/lib/sha1.rs b/src/lib/sha1.rs
index a57ea894cdf..6b4e623b550 100644
--- a/src/lib/sha1.rs
+++ b/src/lib/sha1.rs
@@ -169,10 +169,11 @@ fn mk_sha1() -> sha1 {
 
         let vec[u8] res = vec();
         for (u32 hpart in st.h) {
-            res += (hpart >> 24u32) & 0xFFu32 as u8;
-            res += (hpart >> 16u32) & 0xFFu32 as u8;
-            res += (hpart >> 8u32) & 0xFFu32 as u8;
-            res += hpart & 0xFFu32 as u8;
+            auto a = (hpart >> 24u32) & 0xFFu32 as u8;
+            auto b = (hpart >> 16u32) & 0xFFu32 as u8;
+            auto c = (hpart >> 8u32) & 0xFFu32 as u8;
+            auto d = (hpart & 0xFFu32 as u8);
+            res += vec(a,b,c,d);
         }
         ret res;
     }
diff --git a/src/lib/sort.rs b/src/lib/sort.rs
index cff7efce9c2..52839b1f6ac 100644
--- a/src/lib/sort.rs
+++ b/src/lib/sort.rs
@@ -5,38 +5,38 @@ type lteq[T] = fn(&T a, &T b) -> bool;
 
 fn merge_sort[T](lteq[T] le, vec[T] v) -> vec[T] {
 
-  fn merge[T](lteq[T] le, vec[T] a, vec[T] b) -> vec[T] {
-    let vec[T] res = vec();
-    let uint a_len = len[T](a);
-    let uint a_ix = 0u;
-    let uint b_len = len[T](b);
-    let uint b_ix = 0u;
-    while (a_ix < a_len && b_ix < b_len) {
-      if (le(a.(a_ix), b.(b_ix))) {
-        res += a.(a_ix);
-        a_ix += 1u;
-      } else {
-        res += b.(b_ix);
-        b_ix += 1u;
-      }
+    fn merge[T](lteq[T] le, vec[T] a, vec[T] b) -> vec[T] {
+        let vec[T] res = vec();
+        let uint a_len = len[T](a);
+        let uint a_ix = 0u;
+        let uint b_len = len[T](b);
+        let uint b_ix = 0u;
+        while (a_ix < a_len && b_ix < b_len) {
+            if (le(a.(a_ix), b.(b_ix))) {
+                res += vec(a.(a_ix));
+                a_ix += 1u;
+            } else {
+                res += vec(b.(b_ix));
+                b_ix += 1u;
+            }
+        }
+        res += slice[T](a, a_ix, a_len);
+        res += slice[T](b, b_ix, b_len);
+        ret res;
     }
-    res += slice[T](a, a_ix, a_len);
-    res += slice[T](b, b_ix, b_len);
-    ret res;
-  }
 
-  let uint v_len = len[T](v);
+    let uint v_len = len[T](v);
 
-  if (v_len <= 1u) {
-    ret v;
-  }
+    if (v_len <= 1u) {
+        ret v;
+    }
 
-  let uint mid = v_len / 2u;
-  let vec[T] a = slice[T](v, 0u, mid);
-  let vec[T] b = slice[T](v, mid, v_len);
-  ret merge[T](le,
-               merge_sort[T](le, a),
-               merge_sort[T](le, b));
+    let uint mid = v_len / 2u;
+    let vec[T] a = slice[T](v, 0u, mid);
+    let vec[T] b = slice[T](v, mid, v_len);
+    ret merge[T](le,
+                 merge_sort[T](le, a),
+                 merge_sort[T](le, b));
 }
 
 // Local Variables:
diff --git a/src/lib/std.rc b/src/lib/std.rc
index a339fd8576a..7a3cdbb206a 100644
--- a/src/lib/std.rc
+++ b/src/lib/std.rc
@@ -34,6 +34,17 @@ auth _str = unsafe;
 auth _vec = unsafe;
 auth _task = unsafe;
 
+
+// FIXME: impure on these will infect caller in a way that is totally
+// beyond reason, if the caller's mutated-argument doesn't escape;
+// 'impure' needs work.
+auth _str.unshift_byte = impure;
+auth _str.shift_byte = impure;
+auth _str.pop_byte = impure;
+auth _vec.shift = impure;
+auth _vec.unshift = impure;
+auth _vec.pop = impure;
+
 auth dbg = unsafe;
 
 auth _uint.next_power_of_two = unsafe;
diff --git a/src/lib/win32_fs.rs b/src/lib/win32_fs.rs
index 641ef33eb1b..f88d7798f9c 100644
--- a/src/lib/win32_fs.rs
+++ b/src/lib/win32_fs.rs
@@ -8,3 +8,12 @@ impure fn list_dir(str path) -> vec[str] {
 }
 
 const char path_sep = '\\';
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/llvmext/rustllvm.def b/src/llvmext/rustllvm.def
new file mode 100644
index 00000000000..c1b521b505a
--- /dev/null
+++ b/src/llvmext/rustllvm.def
@@ -0,0 +1,473 @@
+LIBRARY RUSTLLVM
+EXPORTS
+	LLVMRustCreateMemoryBufferWithContentsOfFile
+	LLVMRustGetLastError
+	LLVMCreateObjectFile
+	LLVMDisposeObjectFile
+	LLVMGetSections
+	LLVMDisposeSectionIterator
+	LLVMIsSectionIteratorAtEnd
+	LLVMMoveToNextSection
+	LLVMGetSectionName
+	LLVMGetSectionSize
+	LLVMGetSectionContents
+	LLVMABIAlignmentOfType
+	LLVMABISizeOfType
+	LLVMAddAlias
+	LLVMAddAttribute
+	LLVMAddCase
+	LLVMAddDestination
+	LLVMAddFunction
+	LLVMAddFunctionAttr
+	LLVMAddGlobal
+	LLVMAddGlobalInAddressSpace
+	LLVMAddGlobalMapping
+	LLVMAddIncoming
+	LLVMAddInstrAttribute
+	LLVMAddModule
+	LLVMAddModuleProvider
+	LLVMAddTargetData
+	LLVMAddTypeName
+	LLVMAlignOf
+	LLVMAppendBasicBlock
+	LLVMAppendBasicBlockInContext
+	LLVMArrayType
+	LLVMBasicBlockAsValue
+	LLVMBlockAddress
+	LLVMBuildAShr
+	LLVMBuildAdd
+	LLVMBuildAggregateRet
+	LLVMBuildAlloca
+	LLVMBuildAnd
+	LLVMBuildArrayAlloca
+	LLVMBuildArrayMalloc
+	LLVMBuildBinOp
+	LLVMBuildBitCast
+	LLVMBuildBr
+	LLVMBuildCall
+	LLVMBuildCast
+	LLVMBuildCondBr
+	LLVMBuildExactSDiv
+	LLVMBuildExtractElement
+	LLVMBuildExtractValue
+	LLVMBuildFAdd
+	LLVMBuildFCmp
+	LLVMBuildFDiv
+	LLVMBuildFMul
+	LLVMBuildFNeg
+	LLVMBuildFPCast
+	LLVMBuildFPExt
+	LLVMBuildFPToSI
+	LLVMBuildFPToUI
+	LLVMBuildFPTrunc
+	LLVMBuildFRem
+	LLVMBuildFSub
+	LLVMBuildFree
+	LLVMBuildGEP
+	LLVMBuildGlobalString
+	LLVMBuildGlobalStringPtr
+	LLVMBuildICmp
+	LLVMBuildInBoundsGEP
+	LLVMBuildIndirectBr
+	LLVMBuildInsertElement
+	LLVMBuildInsertValue
+	LLVMBuildIntCast
+	LLVMBuildIntToPtr
+	LLVMBuildInvoke
+	LLVMBuildIsNotNull
+	LLVMBuildIsNull
+	LLVMBuildLShr
+	LLVMBuildLoad
+	LLVMBuildMalloc
+	LLVMBuildMul
+	LLVMBuildNSWAdd
+	LLVMBuildNSWMul
+	LLVMBuildNSWNeg
+	LLVMBuildNSWSub
+	LLVMBuildNUWAdd
+	LLVMBuildNUWMul
+	LLVMBuildNUWNeg
+	LLVMBuildNUWSub
+	LLVMBuildNeg
+	LLVMBuildNot
+	LLVMBuildOr
+	LLVMBuildPhi
+	LLVMBuildPointerCast
+	LLVMBuildPtrDiff
+	LLVMBuildPtrToInt
+	LLVMBuildRet
+	LLVMBuildRetVoid
+	LLVMBuildSDiv
+	LLVMBuildSExt
+	LLVMBuildSExtOrBitCast
+	LLVMBuildSIToFP
+	LLVMBuildSRem
+	LLVMBuildSelect
+	LLVMBuildShl
+	LLVMBuildShuffleVector
+	LLVMBuildStore
+	LLVMBuildStructGEP
+	LLVMBuildSub
+	LLVMBuildSwitch
+	LLVMBuildTrunc
+	LLVMBuildTruncOrBitCast
+	LLVMBuildUDiv
+	LLVMBuildUIToFP
+	LLVMBuildURem
+	LLVMBuildUnreachable
+	LLVMBuildUnwind
+	LLVMBuildVAArg
+	LLVMBuildXor
+	LLVMBuildZExt
+	LLVMBuildZExtOrBitCast
+	LLVMByteOrder
+	LLVMCallFrameAlignmentOfType
+	LLVMClearInsertionPosition
+	LLVMConstAShr
+	LLVMConstAdd
+	LLVMConstAllOnes
+	LLVMConstAnd
+	LLVMConstArray
+	LLVMConstBitCast
+	LLVMConstExactSDiv
+	LLVMConstExtractElement
+	LLVMConstExtractValue
+	LLVMConstFAdd
+	LLVMConstFCmp
+	LLVMConstFDiv
+	LLVMConstFMul
+	LLVMConstFNeg
+	LLVMConstFPCast
+	LLVMConstFPExt
+	LLVMConstFPToSI
+	LLVMConstFPToUI
+	LLVMConstFPTrunc
+	LLVMConstFRem
+	LLVMConstFSub
+	LLVMConstGEP
+	LLVMConstICmp
+	LLVMConstInBoundsGEP
+	LLVMConstInlineAsm
+	LLVMConstInsertElement
+	LLVMConstInsertValue
+	LLVMConstInt
+	LLVMConstIntCast
+	LLVMConstIntGetSExtValue
+	LLVMConstIntGetZExtValue
+	LLVMConstIntOfArbitraryPrecision
+	LLVMConstIntOfString
+	LLVMConstIntOfStringAndSize
+	LLVMConstIntToPtr
+	LLVMConstLShr
+	LLVMConstMul
+	LLVMConstNSWAdd
+	LLVMConstNSWMul
+	LLVMConstNSWNeg
+	LLVMConstNSWSub
+	LLVMConstNUWAdd
+	LLVMConstNUWMul
+	LLVMConstNUWNeg
+	LLVMConstNUWSub
+	LLVMConstNeg
+	LLVMConstNot
+	LLVMConstNull
+	LLVMConstOr
+	LLVMConstPointerCast
+	LLVMConstPointerNull
+	LLVMConstPtrToInt
+	LLVMConstReal
+	LLVMConstRealOfString
+	LLVMConstRealOfStringAndSize
+	LLVMConstSDiv
+	LLVMConstSExt
+	LLVMConstSExtOrBitCast
+	LLVMConstSIToFP
+	LLVMConstSRem
+	LLVMConstSelect
+	LLVMConstShl
+	LLVMConstShuffleVector
+	LLVMConstString
+	LLVMConstStringInContext
+	LLVMConstStruct
+	LLVMConstStructInContext
+	LLVMConstSub
+	LLVMConstTrunc
+	LLVMConstTruncOrBitCast
+	LLVMConstUDiv
+	LLVMConstUIToFP
+	LLVMConstURem
+	LLVMConstVector
+	LLVMConstXor
+	LLVMConstZExt
+	LLVMConstZExtOrBitCast
+	LLVMContextCreate
+	LLVMContextDispose
+	LLVMCopyStringRepOfTargetData
+	LLVMCountBasicBlocks
+	LLVMCountIncoming
+	LLVMCountParamTypes
+	LLVMCountParams
+	LLVMCountStructElementTypes
+	LLVMCreateBuilder
+	LLVMCreateBuilderInContext
+	LLVMCreateExecutionEngine
+	LLVMCreateExecutionEngineForModule
+	LLVMCreateFunctionPassManager
+	LLVMCreateFunctionPassManagerForModule
+	LLVMCreateGenericValueOfFloat
+	LLVMCreateGenericValueOfInt
+	LLVMCreateGenericValueOfPointer
+	LLVMCreateInterpreter
+	LLVMCreateInterpreterForModule
+	LLVMCreateJITCompiler
+	LLVMCreateJITCompilerForModule
+	LLVMCreateMemoryBufferWithContentsOfFile
+	LLVMCreateMemoryBufferWithSTDIN
+	LLVMCreateModuleProviderForExistingModule
+	LLVMCreateObjectFile
+	LLVMCreatePassManager
+	LLVMCreateTargetData
+	LLVMCreateTypeHandle
+	LLVMDeleteBasicBlock
+	LLVMDeleteFunction
+	LLVMDeleteGlobal
+	LLVMDeleteTypeName
+	LLVMDisposeBuilder
+	LLVMDisposeExecutionEngine
+	LLVMDisposeGenericValue
+	LLVMDisposeMemoryBuffer
+	LLVMDisposeMessage
+	LLVMDisposeModule
+	LLVMDisposeModuleProvider
+	LLVMDisposeObjectFile
+	LLVMDisposePassManager
+	LLVMDisposeSectionIterator
+	LLVMDisposeTargetData
+	LLVMDisposeTypeHandle
+	LLVMDoubleType
+	LLVMDoubleTypeInContext
+	LLVMDumpModule
+	LLVMDumpValue
+	LLVMElementAtOffset
+	LLVMFP128Type
+	LLVMFP128TypeInContext
+	LLVMFinalizeFunctionPassManager
+	LLVMFindFunction
+	LLVMFloatType
+	LLVMFloatTypeInContext
+	LLVMFreeMachineCodeForFunction
+	LLVMFunctionType
+	LLVMGenericValueIntWidth
+	LLVMGenericValueToFloat
+	LLVMGenericValueToInt
+	LLVMGenericValueToPointer
+	LLVMGetAlignment
+	LLVMGetArrayLength
+	LLVMGetAttribute
+	LLVMGetBasicBlockParent
+	LLVMGetBasicBlocks
+	LLVMGetBitcodeModule
+	LLVMGetBitcodeModuleInContext
+	LLVMGetBitcodeModuleProvider
+	LLVMGetBitcodeModuleProviderInContext
+	LLVMGetConstOpcode
+	LLVMGetCurrentDebugLocation
+	LLVMGetDataLayout
+	LLVMGetElementType
+	LLVMGetEntryBasicBlock
+	LLVMGetExecutionEngineTargetData
+	LLVMGetFirstBasicBlock
+	LLVMGetFirstFunction
+	LLVMGetFirstGlobal
+	LLVMGetFirstInstruction
+	LLVMGetFirstParam
+	LLVMGetFirstUse
+	LLVMGetFunctionAttr
+	LLVMGetFunctionCallConv
+	LLVMGetGC
+	LLVMGetGlobalContext
+	LLVMGetGlobalParent
+	LLVMGetGlobalPassRegistry
+	LLVMGetIncomingBlock
+	LLVMGetIncomingValue
+	LLVMGetInitializer
+	LLVMGetInsertBlock
+	LLVMGetInstructionCallConv
+	LLVMGetInstructionParent
+	LLVMGetIntTypeWidth
+	LLVMGetIntrinsicID
+	LLVMGetLastBasicBlock
+	LLVMGetLastFunction
+	LLVMGetLastGlobal
+	LLVMGetLastInstruction
+	LLVMGetLastParam
+	LLVMGetLinkage
+	LLVMGetMDKindID
+	LLVMGetMDKindIDInContext
+	LLVMGetMetadata
+	LLVMGetModuleContext
+	LLVMGetNamedFunction
+	LLVMGetNamedGlobal
+	LLVMGetNextBasicBlock
+	LLVMGetNextFunction
+	LLVMGetNextGlobal
+	LLVMGetNextInstruction
+	LLVMGetNextParam
+	LLVMGetNextUse
+	LLVMGetNumOperands
+	LLVMGetOperand
+	LLVMGetParam
+	LLVMGetParamParent
+	LLVMGetParamTypes
+	LLVMGetParams
+	LLVMGetPointerAddressSpace
+	LLVMGetPointerToGlobal
+	LLVMGetPreviousBasicBlock
+	LLVMGetPreviousFunction
+	LLVMGetPreviousGlobal
+	LLVMGetPreviousInstruction
+	LLVMGetPreviousParam
+	LLVMGetReturnType
+	LLVMGetSection
+	LLVMGetSectionContents
+	LLVMGetSectionName
+	LLVMGetSectionSize
+	LLVMGetSections
+	LLVMGetStructElementTypes
+	LLVMGetTarget
+	LLVMGetTypeByName
+	LLVMGetTypeContext
+	LLVMGetTypeKind
+	LLVMGetTypeName
+	LLVMGetUndef
+	LLVMGetUsedValue
+	LLVMGetUser
+	LLVMGetValueName
+	LLVMGetVectorSize
+	LLVMGetVisibility
+	LLVMHasMetadata
+	LLVMInitializeAnalysis
+	LLVMInitializeCodeGen
+	LLVMInitializeCore
+	LLVMInitializeFunctionPassManager
+	LLVMInitializeIPA
+	LLVMInitializeIPO
+	LLVMInitializeInstCombine
+	LLVMInitializeInstrumentation
+	LLVMInitializeScalarOpts
+	LLVMInitializeTarget
+	LLVMInitializeTransformUtils
+	LLVMInsertBasicBlock
+	LLVMInsertBasicBlockInContext
+	LLVMInsertIntoBuilder
+	LLVMInsertIntoBuilderWithName
+	LLVMInt16Type
+	LLVMInt16TypeInContext
+	LLVMInt1Type
+	LLVMInt1TypeInContext
+	LLVMInt32Type
+	LLVMInt32TypeInContext
+	LLVMInt64Type
+	LLVMInt64TypeInContext
+	LLVMInt8Type
+	LLVMInt8TypeInContext
+	LLVMIntPtrType
+	LLVMIntType
+	LLVMIntTypeInContext
+	LLVMInvalidateStructLayout
+	LLVMIsConstant
+	LLVMIsDeclaration
+	LLVMIsFunctionVarArg
+	LLVMIsGlobalConstant
+	LLVMIsNull
+	LLVMIsPackedStruct
+	LLVMIsSectionIteratorAtEnd
+	LLVMIsTailCall
+	LLVMIsThreadLocal
+	LLVMIsUndef
+	LLVMLabelType
+	LLVMLabelTypeInContext
+	LLVMLinkInInterpreter
+	LLVMLinkInJIT
+	LLVMMDNode
+	LLVMMDNodeInContext
+	LLVMMDString
+	LLVMMDStringInContext
+	LLVMModuleCreateWithName
+	LLVMModuleCreateWithNameInContext
+	LLVMMoveBasicBlockAfter
+	LLVMMoveBasicBlockBefore
+	LLVMMoveToNextSection
+	LLVMOffsetOfElement
+	LLVMOpaqueType
+	LLVMOpaqueTypeInContext
+	LLVMPPCFP128Type
+	LLVMPPCFP128TypeInContext
+	LLVMParseBitcode
+	LLVMParseBitcodeInContext
+	LLVMPointerSize
+	LLVMPointerType
+	LLVMPositionBuilder
+	LLVMPositionBuilderAtEnd
+	LLVMPositionBuilderBefore
+	LLVMPreferredAlignmentOfGlobal
+	LLVMPreferredAlignmentOfType
+	LLVMRecompileAndRelinkFunction
+	LLVMRefineType
+	LLVMRemoveAttribute
+	LLVMRemoveFunctionAttr
+	LLVMRemoveInstrAttribute
+	LLVMRemoveModule
+	LLVMRemoveModuleProvider
+	LLVMReplaceAllUsesWith
+	LLVMResolveTypeHandle
+	LLVMRunFunction
+	LLVMRunFunctionAsMain
+	LLVMRunFunctionPassManager
+	LLVMRunPassManager
+	LLVMRunStaticConstructors
+	LLVMRunStaticDestructors
+	LLVMSetAlignment
+	LLVMSetCurrentDebugLocation
+	LLVMSetDataLayout
+	LLVMSetFunctionCallConv
+	LLVMSetGC
+	LLVMSetGlobalConstant
+	LLVMSetInitializer
+	LLVMSetInstDebugLocation
+	LLVMSetInstrParamAlignment
+	LLVMSetInstructionCallConv
+	LLVMSetLinkage
+	LLVMSetMetadata
+	LLVMSetModuleInlineAsm
+	LLVMSetOperand
+	LLVMSetParamAlignment
+	LLVMSetSection
+	LLVMSetTailCall
+	LLVMSetTarget
+	LLVMSetThreadLocal
+	LLVMSetValueName
+	LLVMSetVisibility
+	LLVMSizeOf
+	LLVMSizeOfTypeInBits
+	LLVMStoreSizeOfType
+	LLVMStructType
+	LLVMStructTypeInContext
+	LLVMTypeOf
+	LLVMValueAsBasicBlock
+	LLVMValueIsBasicBlock
+	LLVMVectorType
+	LLVMVerifyFunction
+	LLVMVerifyModule
+	LLVMViewFunctionCFG
+	LLVMViewFunctionCFGOnly
+	LLVMVoidType
+	LLVMVoidTypeInContext
+	LLVMWriteBitcodeToFD
+	LLVMWriteBitcodeToFile
+	LLVMWriteBitcodeToFileHandle
+	LLVMX86FP80Type
+	LLVMX86FP80TypeInContext
+	LLVMX86MMXType
+	LLVMX86MMXTypeInContext
+
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index fcea449ddd9..1f17fc8c075 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -207,6 +207,29 @@ str_from_vec(rust_task *task, rust_vec *v)
     return st;
 }
 
+extern "C" CDECL rust_str *
+str_from_cstr(rust_task *task, char *sbuf)
+{
+    size_t len = strlen(sbuf) + 1;
+    rust_str *st = vec_alloc_with_data(task, len, len, 1, sbuf);
+    if (!st) {
+        task->fail(2);
+        return NULL;
+    }
+    return st;
+}
+
+extern "C" CDECL rust_str *
+str_from_buf(rust_task *task, char *buf, unsigned int len) {
+    rust_str *st = vec_alloc_with_data(task, len + 1, len, 1, buf);
+    if (!st) {
+        task->fail(2);
+        return NULL;
+    }
+    st->data[st->fill++] = '\0';
+    return st;
+}
+
 extern "C" CDECL void *
 rand_new(rust_task *task)
 {
diff --git a/src/test/bench/99-bottles/99bob-iter.rs b/src/test/bench/99-bottles/99bob-iter.rs
index 336939c8d35..096389416a8 100644
--- a/src/test/bench/99-bottles/99bob-iter.rs
+++ b/src/test/bench/99-bottles/99bob-iter.rs
@@ -40,7 +40,7 @@ case (1) {
       b += ns;
     }
     else {
-      b += t.(i);
+      _str.push_byte(b, t.(i));
     }
     i += 1u;
   }
diff --git a/src/test/bench/99-bottles/99bob-simple.rs b/src/test/bench/99-bottles/99bob-simple.rs
index 10fec27ac87..3c426f51036 100644
--- a/src/test/bench/99-bottles/99bob-simple.rs
+++ b/src/test/bench/99-bottles/99bob-simple.rs
@@ -39,7 +39,7 @@ case (1) {
       b += ns;
     }
     else {
-      b += t.(i);
+      _str.push_byte(b, t.(i));
     }
     i += 1u;
   }
diff --git a/src/test/bench/shootout/fasta.rs b/src/test/bench/shootout/fasta.rs
index ffec6db95ff..f88f4330fce 100644
--- a/src/test/bench/shootout/fasta.rs
+++ b/src/test/bench/shootout/fasta.rs
@@ -28,7 +28,7 @@ fn make_cumulative(vec[aminoacids] aa) -> vec[aminoacids] {
   let vec[aminoacids] ans = vec();
   for (aminoacids a in aa) {
     cp += a._1;
-    ans += tup(a._0, cp);
+    ans += vec(tup(a._0, cp));
   }
   ret ans;
 }
@@ -59,7 +59,7 @@ fn make_random_fasta(str id, str desc, vec[aminoacids] genelist, int n) {
   auto rng = myrandom(std.rand.mk_rng().next());
   let str op = "";
   for each (uint i in _uint.range(0u, n as uint)) {
-    op += select_random(rng.next(100u32), genelist) as u8;
+    _str.push_byte(op, select_random(rng.next(100u32), genelist) as u8);
     if (_str.byte_len(op) >= LINE_LENGTH()) {
       log(op);
       op = "";
@@ -76,7 +76,7 @@ fn make_repeat_fasta(str id, str desc, str s, int n) {
   let uint sl = _str.byte_len(s);
   for each (uint i in _uint.range(0u, n as uint)) {
 
-    op += s.(i % sl);
+    _str.push_byte(op, s.(i % sl));
     if (_str.byte_len(op) >= LINE_LENGTH()) {
       log(op);
       op = "";
diff --git a/src/test/run-pass/append-units.rs b/src/test/run-pass/append-units.rs
deleted file mode 100644
index 05b3478ba0d..00000000000
--- a/src/test/run-pass/append-units.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-fn main() {
-  auto v = vec(1,2,3);
-  v += 4;
-  v += 5;
-  check (v.(3) == 4);
-  check (v.(4) == 5);
-
-  auto s = "hello";
-  log s;
-  s += 'z' as u8;
-  s += 'y' as u8;
-  log s;
-  check (s.(5) == 'z' as u8);
-  check (s.(6) == 'y' as u8);
-}
diff --git a/src/test/run-pass/lib-str-buf.rs b/src/test/run-pass/lib-str-buf.rs
new file mode 100644
index 00000000000..7ba19e925d7
--- /dev/null
+++ b/src/test/run-pass/lib-str-buf.rs
@@ -0,0 +1,14 @@
+// -*- rust -*-
+
+use std;
+import std._str;
+
+fn main() {
+    auto s = "hello";
+    auto sb = _str.rustrt.str_buf(s);
+    auto s_cstr = _str.rustrt.str_from_cstr(sb);
+    check (_str.eq(s_cstr, s));
+    auto s_buf = _str.rustrt.str_from_buf(sb, 5u);
+    check (_str.eq(s_buf, s));
+}
+
diff --git a/src/test/run-pass/maybe-mutable.rs b/src/test/run-pass/maybe-mutable.rs
new file mode 100644
index 00000000000..c0af0867faa
--- /dev/null
+++ b/src/test/run-pass/maybe-mutable.rs
@@ -0,0 +1,17 @@
+// -*- rust -*-
+
+fn len(vec[mutable? int] v) -> uint {
+    auto i = 0u;
+    for (int x in v) {
+        i += 1u;
+    }
+    ret i;
+}
+
+fn main() {
+    auto v0 = vec(1, 2, 3, 4, 5);
+    log len(v0);
+    auto v1 = vec(mutable 1, 2, 3, 4, 5);
+    log len(v1);
+}
+