about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-04-09 17:32:49 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-04-11 11:08:40 -0700
commit7a3b29024548e1dcb13590002d5cf4dd94ddd4d4 (patch)
treea0cc34e4635bb317347ca1b5424e494ec68e9909 /src/rustc
parent0c94cd5d431816c68825a08bcb24754d09b8dc31 (diff)
downloadrust-7a3b29024548e1dcb13590002d5cf4dd94ddd4d4.tar.gz
rust-7a3b29024548e1dcb13590002d5cf4dd94ddd4d4.zip
Add vstore/evec/estr to compiler.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/metadata/tyencode.rs2
-rw-r--r--src/rustc/middle/mutbl.rs2
-rw-r--r--src/rustc/middle/region.rs1
-rw-r--r--src/rustc/middle/trans/base.rs73
-rw-r--r--src/rustc/middle/trans/shape.rs58
-rw-r--r--src/rustc/middle/trans/tvec.rs43
-rw-r--r--src/rustc/middle/trans/type_of.rs23
-rw-r--r--src/rustc/middle/trans/type_use.rs4
-rw-r--r--src/rustc/middle/tstate/pre_post_conditions.rs9
-rw-r--r--src/rustc/middle/tstate/states.rs6
-rw-r--r--src/rustc/middle/ty.rs165
-rw-r--r--src/rustc/middle/typeck.rs101
12 files changed, 427 insertions, 60 deletions
diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs
index fb0a84b603f..0739764b08b 100644
--- a/src/rustc/metadata/tyencode.rs
+++ b/src/rustc/metadata/tyencode.rs
@@ -176,6 +176,7 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
           ty_f64 { w.write_str("MF"); }
         }
       }
+      ty::ty_estr(_) { cx.tcx.sess.unimpl("tyencode::enc_sty on estr"); }
       ty::ty_str { w.write_char('S'); }
       ty::ty_enum(def, tys) {
         w.write_str("t[");
@@ -204,6 +205,7 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
         enc_region(w, r);
         enc_mt(w, cx, mt);
       }
+      ty::ty_evec(_, _) { cx.tcx.sess.unimpl("tyencode::enc_sty on evec"); }
       ty::ty_vec(mt) { w.write_char('I'); enc_mt(w, cx, mt); }
       ty::ty_rec(fields) {
         w.write_str("R[");
diff --git a/src/rustc/middle/mutbl.rs b/src/rustc/middle/mutbl.rs
index d6488334311..fa2e8ddb0d7 100644
--- a/src/rustc/middle/mutbl.rs
+++ b/src/rustc/middle/mutbl.rs
@@ -92,12 +92,14 @@ fn expr_root_(tcx: ty::ctxt, ctor_self: option<node_id>,
           expr_index(base, _) {
             let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base));
             alt ty::get(auto_unbox.t).struct {
+              ty::ty_evec(mt, _) |
               ty::ty_vec(mt) {
                 ds +=
                     [@{mutbl: mt.mutbl == m_mutbl,
                        kind: index,
                        outer_t: auto_unbox.t}];
               }
+              ty::ty_estr(_) |
               ty::ty_str {
                 ds += [@{mutbl: false, kind: index, outer_t: auto_unbox.t}];
               }
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index c66f09f8836..39f08983b4b 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -414,6 +414,7 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
     cx.region_map.ast_type_to_inferred_region.insert(ty.id, inferred_region);
 
     alt ty.node {
+      ast::ty_vstore(_, ast::vstore_slice(r)) |
       ast::ty_rptr(r, _) {
         resolve_region_binding(cx, ty.span, r);
       }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index fcb983a7291..dbf3ca841ba 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -573,7 +573,8 @@ fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
     let _icx = bcx.insn_ctxt("make_take_glue");
     // NB: v is a *pointer* to type t here, not a direct value.
     let bcx = alt ty::get(t).struct {
-      ty::ty_box(_) | ty::ty_opaque_box {
+      ty::ty_box(_) | ty::ty_opaque_box |
+      ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) {
         incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
       }
       ty::ty_uniq(_) {
@@ -581,7 +582,8 @@ fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
         Store(bcx, val, v);
         bcx
       }
-      ty::ty_vec(_) | ty::ty_str {
+      ty::ty_vec(_) | ty::ty_str |
+      ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) {
         let {bcx, val} = tvec::duplicate(bcx, Load(bcx, v), t);
         Store(bcx, val, v);
         bcx
@@ -629,6 +631,12 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
         let bcx = drop_ty(bcx, body, body_mt.ty);
         trans_free(bcx, v)
       }
+
+      ty::ty_estr(ty::vstore_box) {
+        let v = PointerCast(bcx, v, type_of(ccx, t));
+        trans_free(bcx, v)
+      }
+
       ty::ty_opaque_box {
         let v = PointerCast(bcx, v, type_of(ccx, t));
         let td = Load(bcx, GEPi(bcx, v, [0, abi::box_field_tydesc]));
@@ -641,9 +649,13 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
         let v = PointerCast(bcx, v, type_of(ccx, t));
         uniq::make_free_glue(bcx, v, t)
       }
+      ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
       ty::ty_vec(_) | ty::ty_str {
         tvec::make_free_glue(bcx, PointerCast(bcx, v, type_of(ccx, t)), t)
       }
+      ty::ty_evec(_, _) {
+          bcx.sess().unimpl("trans::base::make_free_glue on other evec");
+      }
       ty::ty_fn(_) {
         closure::make_fn_glue(bcx, v, t, free_ty)
       }
@@ -660,7 +672,8 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
     let _icx = bcx.insn_ctxt("make_drop_glue");
     let ccx = bcx.ccx();
     let bcx = alt ty::get(t).struct {
-      ty::ty_box(_) | ty::ty_opaque_box {
+      ty::ty_box(_) | ty::ty_opaque_box |
+      ty::ty_estr(ty::vstore_box) {
         decr_refcnt_maybe_free(bcx, Load(bcx, v0), t)
       }
       ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str {
@@ -900,6 +913,10 @@ fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
             cx = f(cx, llfld_a, fld.mt.ty);
         }
       }
+      ty::ty_estr(ty::vstore_fixed(n)) |
+      ty::ty_evec(_, ty::vstore_fixed(n)) {
+        cx = tvec::iter_vec_raw(cx, av, t, C_uint(cx.ccx(), n), f);
+      }
       ty::ty_tup(args) {
         for vec::eachi(args) {|i, arg|
             let llfld_a = GEPi(cx, av, [0, i as int]);
@@ -1111,8 +1128,14 @@ fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
 fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
     let _icx = bcx.insn_ctxt("drop_ty_immediate");
     alt ty::get(t).struct {
-      ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str { free_ty(bcx, v, t) }
-      ty::ty_box(_) | ty::ty_opaque_box {
+      ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str |
+      ty::ty_evec(_, ty::vstore_uniq) |
+      ty::ty_estr(ty::vstore_uniq) {
+        free_ty(bcx, v, t)
+      }
+      ty::ty_box(_) | ty::ty_opaque_box |
+      ty::ty_evec(_, ty::vstore_box) |
+      ty::ty_estr(ty::vstore_box) {
         decr_refcnt_maybe_free(bcx, v, t)
       }
       _ { bcx.tcx().sess.bug("drop_ty_immediate: non-box ty"); }
@@ -1122,14 +1145,20 @@ fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
 fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> result {
     let _icx = bcx.insn_ctxt("take_ty_immediate");
     alt ty::get(t).struct {
-      ty::ty_box(_) | ty::ty_opaque_box {
+      ty::ty_box(_) | ty::ty_opaque_box |
+      ty::ty_evec(_, ty::vstore_box) |
+      ty::ty_estr(ty::vstore_box) {
         incr_refcnt_of_boxed(bcx, v);
         rslt(bcx, v)
       }
       ty::ty_uniq(_) {
         uniq::duplicate(bcx, v, t)
       }
-      ty::ty_str | ty::ty_vec(_) { tvec::duplicate(bcx, v, t) }
+      ty::ty_str | ty::ty_vec(_) |
+      ty::ty_evec(_, ty::vstore_uniq) |
+      ty::ty_estr(ty::vstore_uniq) {
+        tvec::duplicate(bcx, v, t)
+      }
       _ { rslt(bcx, v) }
     }
 }
@@ -1299,9 +1328,9 @@ fn trans_lit(cx: block, lit: ast::lit, dest: dest) -> block {
     let _icx = cx.insn_ctxt("trans_lit");
     if dest == ignore { ret cx; }
     alt lit.node {
-      ast::lit_str(s) { ret tvec::trans_str(cx, s, dest); }
+      ast::lit_str(s) { tvec::trans_str(cx, s, dest) }
       _ {
-        ret store_in_dest(cx, trans_crate_lit(cx.ccx(), lit), dest);
+        store_in_dest(cx, trans_crate_lit(cx.ccx(), lit), dest)
       }
     }
 }
@@ -2255,8 +2284,29 @@ fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
     maybe_name_value(cx.ccx(), unit_sz, "unit_sz");
     let scaled_ix = Mul(bcx, ix_val, unit_sz);
     maybe_name_value(cx.ccx(), scaled_ix, "scaled_ix");
-    let lim = tvec::get_fill(bcx, v);
-    let body = tvec::get_dataptr(bcx, v, type_of(ccx, unit_ty));
+
+    let (lim,  body) = alt ty::get(base_ty).struct {
+      ty::ty_estr(ty::vstore_fixed(n)) |
+      ty::ty_evec(_, ty::vstore_fixed(n)) {
+        // FIXME: support static bounds-check elimination
+        // and/or error checking here.
+        let lim = C_uint(bcx.ccx(), n);
+        let body = GEPi(bcx, v, [0, 0]);
+        (lim, body)
+      }
+      ty::ty_estr(_) | ty::ty_evec(_, _) {
+        bcx.sess().unimpl(#fmt("unsupported evec/estr type trans_index"));
+      }
+      _ {
+        let lim = tvec::get_fill(bcx, v);
+        let body = tvec::get_dataptr(bcx, v, type_of(ccx, unit_ty));
+        (lim, body)
+      }
+    };
+
+    #debug("trans_index: lim %s", val_str(bcx.ccx().tn, lim));
+    #debug("trans_index: body %s", val_str(bcx.ccx().tn, body));
+
     let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, lim);
     let bcx = with_cond(bcx, bounds_check) {|bcx|
         // fail: bad bounds check.
@@ -3017,6 +3067,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
         ret trans_rec(bcx, args, base, e.id, dest);
       }
       ast::expr_tup(args) { ret trans_tup(bcx, args, dest); }
+      ast::expr_vstore(e, v) { ret tvec::trans_vstore(bcx, e, v, dest); }
       ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); }
       ast::expr_vec(args, _) { ret tvec::trans_vec(bcx, args, e.id, dest); }
       ast::expr_binary(op, lhs, rhs) {
diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs
index 5460b4c8f28..f79a77ce1d6 100644
--- a/src/rustc/middle/trans/shape.rs
+++ b/src/rustc/middle/trans/shape.rs
@@ -58,6 +58,8 @@ const shape_bare_fn: u8 = 27u8;
 const shape_tydesc: u8 = 28u8;
 const shape_send_tydesc: u8 = 29u8;
 const shape_rptr: u8 = 31u8;
+const shape_fixedvec: u8 = 32u8;
+const shape_slice: u8 = 33u8;
 
 fn hash_res_info(ri: res_info) -> uint {
     let mut h = 5381u;
@@ -305,6 +307,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
       ty::ty_int(ast::ty_i64) { [shape_i64] }
       ty::ty_float(ast::ty_f32) { [shape_f32] }
       ty::ty_float(ast::ty_f64) { [shape_f64] }
+      ty::ty_estr(ty::vstore_uniq) |
       ty::ty_str {
         let mut s = [shape_vec];
         add_bool(s, true); // type is POD
@@ -340,18 +343,67 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
           }
         }
       }
+      ty::ty_estr(ty::vstore_box) |
+      ty::ty_evec(_, ty::vstore_box) |
       ty::ty_box(_) | ty::ty_opaque_box { [shape_box] }
       ty::ty_uniq(mt) {
         let mut s = [shape_uniq];
         add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
         s
       }
+      ty::ty_evec(mt, ty::vstore_uniq) |
       ty::ty_vec(mt) {
         let mut s = [shape_vec];
         add_bool(s, ty::type_is_pod(ccx.tcx, mt.ty));
         add_substr(s, shape_of(ccx, mt.ty, ty_param_map));
         s
       }
+
+      // FIXME: grotesque hacks for encoding fixed-size evecs and estrs.
+
+      ty::ty_estr(ty::vstore_fixed(n)) {
+        let mut s = [shape_struct], sub = [];
+        let mut i = 0u;
+        let u8_t = ty::mk_mach_uint(ccx.tcx, ast::ty_u8);
+        while i < n {
+            sub += shape_of(ccx, u8_t, ty_param_map);
+        }
+        add_substr(s, sub);
+        s
+      }
+
+      ty::ty_evec(mt, ty::vstore_fixed(n)) {
+        let mut s = [shape_struct], sub = [];
+        let mut i = 0u;
+        while i < n {
+            sub += shape_of(ccx, mt.ty, ty_param_map);
+        }
+        add_substr(s, sub);
+        s
+      }
+
+
+      // FIXME: slightly-less-grotesque hack for encoding slic,e evecs and
+      // estrs.
+
+      ty::ty_estr(ty::vstore_slice(r)) {
+        let mut s = [shape_struct], sub = [];
+        let u8_mt = {ty: ty::mk_mach_uint(ccx.tcx, ast::ty_u8),
+                     mutbl: ast::m_imm };
+        sub += shape_of(ccx, ty::mk_rptr(ccx.tcx, r, u8_mt), ty_param_map);
+        sub += shape_of(ccx, ty::mk_uint(ccx.tcx), ty_param_map);
+        add_substr(s, sub);
+        s
+      }
+
+      ty::ty_evec(mt, ty::vstore_slice(r)) {
+        let mut s = [shape_struct], sub = [];
+        sub += shape_of(ccx, ty::mk_rptr(ccx.tcx, r, mt), ty_param_map);
+        sub += shape_of(ccx, ty::mk_uint(ccx.tcx), ty_param_map);
+        add_substr(s, sub);
+        s
+      }
+
       ty::ty_rec(fields) {
         let mut s = [shape_struct], sub = [];
         for vec::each(fields) {|f|
@@ -632,12 +684,18 @@ fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
     fn simplifier(tcx: ty::ctxt, typ: ty::t) -> ty::t {
         alt ty::get(typ).struct {
           ty::ty_box(_) | ty::ty_opaque_box | ty::ty_uniq(_) | ty::ty_vec(_) |
+          ty::ty_evec(_, ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_box) |
+          ty::ty_estr(ty::vstore_uniq) | ty::ty_estr(ty::vstore_box) |
           ty::ty_ptr(_) | ty::ty_rptr(_,_) { nilptr(tcx) }
           ty::ty_fn(_) { ty::mk_tup(tcx, [nilptr(tcx), nilptr(tcx)]) }
           ty::ty_res(_, sub, tps) {
             let sub1 = ty::substitute_type_params(tcx, tps, sub);
             ty::mk_tup(tcx, [ty::mk_int(tcx), simplify_type(tcx, sub1)])
           }
+          ty::ty_evec(_, ty::vstore_slice(_)) |
+          ty::ty_estr(ty::vstore_slice(_)) {
+            ty::mk_tup(tcx, [nilptr(tcx), ty::mk_int(tcx)])
+          }
           _ { typ }
         }
     }
diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs
index f3d06591942..bce423e37e4 100644
--- a/src/rustc/middle/trans/tvec.rs
+++ b/src/rustc/middle/trans/tvec.rs
@@ -6,6 +6,7 @@ import base::{call_memmove, shared_malloc,
                INIT, copy_val, load_if_immediate, get_tydesc,
                sub_block, do_spill_noroot,
                dest, bcx_icx};
+import syntax::codemap::span;
 import shape::llsize_of;
 import build::*;
 import common::*;
@@ -129,6 +130,48 @@ fn trans_vec(bcx: block, args: [@ast::expr], id: ast::node_id,
     ret base::store_in_dest(bcx, vptr, dest);
 }
 
+fn trans_vstore(bcx: block, e: @ast::expr,
+                v: ast::vstore, dest: dest) -> block {
+    alt e.node {
+      ast::expr_lit(@{node: ast::lit_str(s), span: _}) {
+        ret trans_estr(bcx, s, v, e.span, dest);
+      }
+      ast::expr_vec(es, mutbl) {
+        bcx.ccx().sess.span_unimpl(e.span, "unhandled tvec::trans_vstore");
+      }
+      _ {
+        bcx.sess().span_bug(e.span, "vstore on non-sequence type");
+      }
+    }
+}
+
+fn trans_estr(bcx: block, s: str, vstore: ast::vstore,
+              sp: span, dest: dest) -> block {
+    let _icx = bcx.insn_ctxt("tvec::trans_estr");
+    alt vstore {
+      ast::vstore_fixed(_)
+      {
+        let c = str::as_bytes(s) {|bytes|
+            // NB: The byte vector we have here includes the trailing \0,
+            // but we are doing a fixed-size str, meaning we _exclude_
+            // the trailing \0. And we don't let LLVM null-terminate
+            // either.
+            unsafe {
+                lib::llvm::llvm::LLVMConstString(
+                    unsafe::reinterpret_cast(vec::unsafe::to_ptr(bytes)),
+                    (bytes.len() - 1u) as libc::c_uint, lib::llvm::True)
+            }
+        };
+
+        #debug("trans_estr: src %s",val_str(bcx.ccx().tn, c));
+        ret base::store_in_dest(bcx, c, dest);
+      }
+      _ {
+        bcx.ccx().sess.span_unimpl(sp, "unhandled tvec::trans_estr");
+      }
+    }
+}
+
 fn trans_str(bcx: block, s: str, dest: dest) -> block {
     let _icx = bcx.insn_ctxt("tvec::trans_str");
     let ccx = bcx.ccx();
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index 7f471e76bb7..6e24b4c72a1 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -48,14 +48,37 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
       ty::ty_int(t) { T_int_ty(cx, t) }
       ty::ty_uint(t) { T_uint_ty(cx, t) }
       ty::ty_float(t) { T_float_ty(cx, t) }
+      ty::ty_estr(ty::vstore_uniq) |
       ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
       ty::ty_enum(did, _) { type_of_enum(cx, did, t) }
+      ty::ty_estr(ty::vstore_box) { T_ptr(T_box(cx, T_i8())) }
+      ty::ty_evec(mt, ty::vstore_box) |
       ty::ty_box(mt) { T_ptr(T_box(cx, type_of(cx, mt.ty))) }
       ty::ty_opaque_box { T_ptr(T_box(cx, T_i8())) }
       ty::ty_uniq(mt) { T_ptr(type_of(cx, mt.ty)) }
+      ty::ty_evec(mt, ty::vstore_uniq) |
       ty::ty_vec(mt) { T_ptr(T_vec(cx, type_of(cx, mt.ty))) }
       ty::ty_ptr(mt) { T_ptr(type_of(cx, mt.ty)) }
       ty::ty_rptr(_, mt) { T_ptr(type_of(cx, mt.ty)) }
+
+      ty::ty_evec(mt, ty::vstore_slice(_)) {
+        T_struct([T_ptr(type_of(cx, mt.ty)),
+                  T_uint_ty(cx, ast::ty_u)])
+      }
+
+      ty::ty_estr(ty::vstore_slice(_)) {
+        T_struct([T_ptr(T_i8()),
+                  T_uint_ty(cx, ast::ty_u)])
+      }
+
+      ty::ty_estr(ty::vstore_fixed(n)) {
+        T_array(T_i8(), n)
+      }
+
+      ty::ty_evec(mt, ty::vstore_fixed(n)) {
+        T_array(type_of(cx, mt.ty), n)
+      }
+
       ty::ty_rec(fields) {
         let mut tys: [TypeRef] = [];
         for vec::each(fields) {|f|
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index cbed8a0dbc5..4b993f8224c 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -136,7 +136,9 @@ fn node_type_needs(cx: ctx, use: uint, id: node_id) {
 
 fn mark_for_expr(cx: ctx, e: @expr) {
     alt e.node {
-      expr_vec(_, _) | expr_rec(_, _) | expr_tup(_) |
+      expr_vstore(_, _) |
+      expr_vec(_, _) |
+      expr_rec(_, _) | expr_tup(_) |
       expr_unary(box(_), _) | expr_unary(uniq(_), _) |
       expr_cast(_, _) | expr_binary(add, _, _) |
       expr_copy(_) | expr_move(_, _) {
diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs
index ec7c8354d8c..fc74db67b37 100644
--- a/src/rustc/middle/tstate/pre_post_conditions.rs
+++ b/src/rustc/middle/tstate/pre_post_conditions.rs
@@ -321,7 +321,14 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
           _ { }
         }
       }
-      expr_vec(args, _) { find_pre_post_exprs(fcx, args, e.id); }
+      expr_vstore(ee, _) {
+        find_pre_post_expr(fcx, ee);
+        let p = expr_pp(fcx.ccx, ee);
+        set_pre_and_post(fcx.ccx, e.id, p.precondition, p.postcondition);
+      }
+      expr_vec(args, _) {
+        find_pre_post_exprs(fcx, args, e.id);
+      }
       expr_path(p) {
         let rslt = expr_pp(fcx.ccx, e);
         clear_pp(rslt);
diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs
index 8ec37b9c0cb..7d3016a6636 100644
--- a/src/rustc/middle/tstate/states.rs
+++ b/src/rustc/middle/tstate/states.rs
@@ -358,6 +358,12 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
       expr_new(p, _, v) {
         ret find_pre_post_state_two(fcx, pres, p, v, e.id, oper_pure);
       }
+      expr_vstore(ee, _) {
+        let mut changed = find_pre_post_state_expr(fcx, pres, ee);
+        set_prestate_ann(fcx.ccx, e.id, expr_prestate(fcx.ccx, ee));
+        set_poststate_ann(fcx.ccx, e.id, expr_poststate(fcx.ccx, ee));
+        ret changed;
+      }
       expr_vec(elts, _) {
         ret find_pre_post_state_exprs(fcx, pres, e.id,
                                       vec::from_elem(vec::len(elts),
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index f4d134459be..4994fe24ed3 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -80,6 +80,9 @@ export ty_fn_proto, ty_fn_ret, ty_fn_ret_style;
 export ty_int, mk_int, mk_mach_int, mk_char;
 export ty_str, mk_str, type_is_str;
 export ty_vec, mk_vec, type_is_vec;
+export ty_estr, mk_estr;
+export ty_evec, mk_evec;
+export vstore, vstore_fixed, vstore_uniq, vstore_box, vstore_slice;
 export ty_nil, mk_nil, type_is_nil;
 export ty_iface, mk_iface;
 export ty_res, mk_res;
@@ -164,6 +167,13 @@ type constr_table = hashmap<ast::node_id, [constr]>;
 
 type mt = {ty: t, mutbl: ast::mutability};
 
+enum vstore {
+    vstore_fixed(uint),
+    vstore_uniq,
+    vstore_box,
+    vstore_slice(region)
+}
+
 type field_ty = {
   ident: ident,
   id: def_id,
@@ -293,10 +303,12 @@ enum sty {
     ty_uint(ast::uint_ty),
     ty_float(ast::float_ty),
     ty_str,
+    ty_estr(vstore),
     ty_enum(def_id, [t]),
     ty_box(mt),
     ty_uniq(mt),
     ty_vec(mt),
+    ty_evec(mt, vstore),
     ty_ptr(mt),
     ty_rptr(region, mt),
     ty_rec([field]),
@@ -458,8 +470,15 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
         has_rptrs |= t.has_rptrs;
     }
     alt st {
+      ty_estr(vstore_slice(_)) {
+        has_rptrs = true;
+      }
+      ty_evec(mt, vstore_slice(_)) {
+        has_rptrs = true;
+        derive_flags(has_params, has_vars, has_rptrs, mt.ty);
+      }
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
-      ty_str | ty_type | ty_opaque_closure_ptr(_) |
+      ty_str | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
       ty_opaque_box {}
       ty_param(_, _) { has_params = true; }
       ty_var(_) | ty_self(_) { has_vars = true; }
@@ -468,7 +487,7 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
             derive_flags(has_params, has_vars, has_rptrs, tt);
         }
       }
-      ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_ptr(m) {
+      ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_evec(m, _) | ty_ptr(m) {
         derive_flags(has_params, has_vars, has_rptrs, m.ty);
       }
       ty_rptr(r, m) {
@@ -536,6 +555,10 @@ fn mk_char(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_char)) }
 
 fn mk_str(cx: ctxt) -> t { mk_t(cx, ty_str) }
 
+fn mk_estr(cx: ctxt, t: vstore) -> t {
+    mk_t(cx, ty_estr(t))
+}
+
 fn mk_enum(cx: ctxt, did: ast::def_id, tys: [t]) -> t {
     mk_t(cx, ty_enum(did, tys))
 }
@@ -567,6 +590,10 @@ fn mk_nil_ptr(cx: ctxt) -> t {
 
 fn mk_vec(cx: ctxt, tm: mt) -> t { mk_t(cx, ty_vec(tm)) }
 
+fn mk_evec(cx: ctxt, tm: mt, t: vstore) -> t {
+    mk_t(cx, ty_evec(tm, t))
+}
+
 fn mk_rec(cx: ctxt, fs: [field]) -> t { mk_t(cx, ty_rec(fs)) }
 
 fn mk_constr(cx: ctxt, t: t, cs: [@type_constr]) -> t {
@@ -630,9 +657,10 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
     if !f(ty) { ret; }
     alt get(ty).struct {
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
-      ty_str | ty_type | ty_opaque_box |
+      ty_str | ty_estr(_) | ty_type | ty_opaque_box |
       ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {}
-      ty_box(tm) | ty_vec(tm) | ty_ptr(tm) | ty_rptr(_, tm) {
+      ty_box(tm) | ty_vec(tm) | ty_evec(tm, _) |
+      ty_ptr(tm) | ty_rptr(_, tm) {
         maybe_walk_ty(tm.ty, f);
       }
       ty_enum(_, subtys) | ty_iface(_, subtys) | ty_class(_, subtys)
@@ -674,6 +702,9 @@ fn fold_sty(sty: sty, fldop: fn(t) -> t) -> sty {
       ty_vec(tm) {
         ty_vec({ty: fldop(tm.ty), mutbl: tm.mutbl})
       }
+      ty_evec(tm, vst) {
+        ty_evec({ty: fldop(tm.ty), mutbl: tm.mutbl}, vst)
+      }
       ty_enum(tid, subtys) {
         ty_enum(tid, vec::map(subtys) {|t| fldop(t) })
       }
@@ -718,7 +749,7 @@ fn fold_sty(sty: sty, fldop: fn(t) -> t) -> sty {
         ty_class(did, new_tps)
       }
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
-      ty_str | ty_type | ty_opaque_closure_ptr(_) |
+      ty_str | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
       ty_opaque_box | ty_var(_) | ty_param(_, _) {
         sty
       }
@@ -751,6 +782,15 @@ fn fold_region(cx: ctxt, t0: t, fldop: fn(region, bool) -> region) -> t {
             let m_t1 = do_fold(cx, t1, true, fldop);
             ty::mk_rptr(cx, m_r, {ty: m_t1, mutbl: m})
           }
+          ty_estr(vstore_slice(r)) {
+            let m_r = fldop(r, under_r);
+            ty::mk_estr(cx, vstore_slice(m_r))
+          }
+          ty_evec({ty: t1, mutbl: m}, vstore_slice(r)) {
+            let m_r = fldop(r, under_r);
+            let m_t1 = do_fold(cx, t1, true, fldop);
+            ty::mk_evec(cx, {ty: m_t1, mutbl: m}, vstore_slice(m_r))
+          }
           ty_fn(_) {
             // do not recurse into functions, which introduce fresh bindings
             t0
@@ -786,7 +826,8 @@ fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool }
 fn type_is_structural(ty: t) -> bool {
     alt get(ty).struct {
       ty_rec(_) | ty_class(_,_) | ty_tup(_) | ty_enum(_, _) | ty_fn(_) |
-      ty_iface(_, _) | ty_res(_, _, _) { true }
+      ty_iface(_, _) | ty_res(_, _, _) | ty_evec(_, vstore_fixed(_))
+      | ty_estr(vstore_fixed(_)) { true }
       _ { false }
     }
 }
@@ -797,18 +838,22 @@ fn type_is_copyable(cx: ctxt, ty: t) -> bool {
 
 fn type_is_sequence(ty: t) -> bool {
     alt get(ty).struct {
-      ty_str { ret true; }
-      ty_vec(_) { ret true; }
-      _ { ret false; }
+      ty_str | ty_estr(_) | ty_vec(_) | ty_evec(_, _) { true }
+      _ { false }
     }
 }
 
-fn type_is_str(ty: t) -> bool { get(ty).struct == ty_str }
+fn type_is_str(ty: t) -> bool {
+    alt get(ty).struct {
+      ty_str | ty_estr(_) { true }
+      _ { false }
+    }
+}
 
 fn sequence_element_type(cx: ctxt, ty: t) -> t {
     alt get(ty).struct {
-      ty_str { ret mk_mach_uint(cx, ast::ty_u8); }
-      ty_vec(mt) { ret mt.ty; }
+      ty_str | ty_estr(_) { ret mk_mach_uint(cx, ast::ty_u8); }
+      ty_vec(mt) | ty_evec(mt, _) { ret mt.ty; }
       _ { cx.sess.bug("sequence_element_type called on non-sequence value"); }
     }
 }
@@ -858,8 +903,8 @@ pure fn type_is_unsafe_ptr(ty: t) -> bool {
 
 pure fn type_is_vec(ty: t) -> bool {
     ret alt get(ty).struct {
-          ty_vec(_) { true }
-          ty_str { true }
+          ty_vec(_) | ty_evec(_, _) { true }
+          ty_str | ty_estr(_) { true }
           _ { false }
         };
 }
@@ -867,8 +912,8 @@ pure fn type_is_vec(ty: t) -> bool {
 pure fn type_is_unique(ty: t) -> bool {
     alt get(ty).struct {
       ty_uniq(_) { ret true; }
-      ty_vec(_) { true }
-      ty_str { true }
+      ty_vec(_) | ty_evec(_, vstore_uniq) { true }
+      ty_str | ty_estr(vstore_uniq) { true }
       _ { ret false; }
     }
 }
@@ -897,7 +942,10 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
     let result = alt get(ty).struct {
       // scalar types
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
-      ty_type | ty_ptr(_) | ty_rptr(_, _) { false }
+      ty_type | ty_ptr(_) | ty_rptr(_, _) |
+      ty_estr(vstore_fixed(_)) | ty_estr(vstore_slice(_)) |
+      ty_evec(_, vstore_slice(_)) { false }
+      ty_evec(mt, vstore_fixed(_)) { type_needs_drop(cx, mt.ty) }
       ty_rec(flds) {
         for flds.each {|f| if type_needs_drop(cx, f.mt.ty) { accum = true; } }
         accum
@@ -983,7 +1031,12 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
             }
             !needs_unwind_cleanup
           }
-          ty_uniq(_) | ty_str | ty_vec(_) | ty_res(_, _, _) {
+          ty_uniq(_) | ty_str | ty_vec(_) | ty_res(_, _, _) |
+          ty_estr(vstore_uniq) |
+          ty_estr(vstore_box) |
+          ty_evec(_, vstore_uniq) |
+          ty_evec(_, vstore_box)
+          {
             // Once we're inside a box, the annihilator will find
             // it and destroy it.
             if !encountered_box {
@@ -1046,6 +1099,17 @@ fn lower_kind(a: kind, b: kind) -> kind {
     if kind_lteq(a, b) { a } else { b }
 }
 
+#[test]
+fn test_kinds() {
+    // The kind "lattice" is nocopy <= copy <= send
+    assert kind_lteq(kind_sendable, kind_sendable);
+    assert kind_lteq(kind_copyable, kind_sendable);
+    assert kind_lteq(kind_copyable, kind_copyable);
+    assert kind_lteq(kind_noncopyable, kind_sendable);
+    assert kind_lteq(kind_noncopyable, kind_copyable);
+    assert kind_lteq(kind_noncopyable, kind_noncopyable);
+}
+
 fn type_kind(cx: ctxt, ty: t) -> kind {
     alt cx.kind_cache.find(ty) {
       some(result) { ret result; }
@@ -1061,15 +1125,33 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
       ty_ptr(_) | ty_str { kind_sendable }
       ty_type { kind_copyable }
       ty_fn(f) { proto_kind(f.proto) }
+
+      // Closures have kind determined by capture mode
       ty_opaque_closure_ptr(ck_block) { kind_noncopyable }
       ty_opaque_closure_ptr(ck_box) { kind_copyable }
       ty_opaque_closure_ptr(ck_uniq) { kind_sendable }
-      // Those with refcounts-to-inner raise pinned to shared,
-      // lower unique to shared. Therefore just set result to shared.
+
+      // Those with refcounts raise noncopyable to copyable,
+      // lower sendable to copyable. Therefore just set result to copyable.
       ty_box(_) | ty_iface(_, _) | ty_opaque_box { kind_copyable }
       ty_rptr(_, _) { kind_copyable }
-      // Boxes and unique pointers raise pinned to shared.
+
+      // Unique boxes and vecs have the kind of their contained type.
       ty_vec(tm) | ty_uniq(tm) { type_kind(cx, tm.ty) }
+
+      // Slice and refcounted evecs are copyable; uniques and interiors
+      // depend on the their contained type.
+      ty_evec(_, vstore_box) |
+      ty_evec(_, vstore_slice(_)) { kind_copyable }
+      ty_evec(tm, vstore_uniq) |
+      ty_evec(tm, vstore_fixed(_)) { type_kind(cx, tm.ty)  }
+
+      // All estrs are copyable; uniques and interiors are sendable.
+      ty_estr(vstore_box) |
+      ty_estr(vstore_slice(_)) { kind_copyable }
+      ty_estr(vstore_uniq) |
+      ty_estr(vstore_fixed(_)) { kind_sendable  }
+
       // Records lower to the lowest of their members.
       ty_rec(flds) {
         let mut lowest = kind_sendable;
@@ -1152,6 +1234,7 @@ fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
           ty_uint(_) |
           ty_float(_) |
           ty_str |
+          ty_estr(_) |
           ty_fn(_) |
           ty_var(_) |
           ty_param(_, _) |
@@ -1159,6 +1242,7 @@ fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
           ty_type |
           ty_opaque_box |
           ty_opaque_closure_ptr(_) |
+          ty_evec(_, _) |
           ty_vec(_) {
             false
           }
@@ -1277,6 +1361,9 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
         let sty = substitute_type_params(cx, tps, sub);
         ret type_structurally_contains(cx, sty, test);
       }
+      ty_evec(mt, vstore_fixed(_)) {
+        ret type_structurally_contains(cx, mt.ty, test);
+      }
       _ { ret false; }
     }
 }
@@ -1288,6 +1375,11 @@ fn type_allows_implicit_copy(cx: ctxt, ty: t) -> bool {
     ret !type_structurally_contains(cx, ty, {|sty|
         alt sty {
           ty_param(_, _) { true }
+
+          ty_evec(_, _) | ty_estr(_) {
+            cx.sess.unimpl("estr/evec in type_allows_implicit_copy");
+          }
+
           ty_vec(mt) {
             mt.mutbl != ast::m_imm
           }
@@ -1302,9 +1394,11 @@ fn type_allows_implicit_copy(cx: ctxt, ty: t) -> bool {
 fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool {
     ret type_structurally_contains(cx, ty, {|sty|
         alt sty {
-          ty_uniq(_) { true }
-          ty_vec(_) { true }
-          ty_str { true }
+          ty_uniq(_) |
+          ty_vec(_) |
+          ty_evec(_, vstore_uniq) |
+          ty_str |
+          ty_estr(vstore_uniq) { true }
           _ { false }
         }
     });
@@ -1365,6 +1459,10 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
       ty_tup(elts) {
         for elts.each {|elt| if !type_is_pod(cx, elt) { result = false; } }
       }
+      ty_estr(vstore_fixed(_)) { result = true; }
+      ty_evec(mt, vstore_fixed(_)) {
+        result = type_is_pod(cx, mt.ty);
+      }
       ty_res(_, inner, tps) {
         result = type_is_pod(cx, substitute_type_params(cx, tps, inner));
       }
@@ -1503,6 +1601,7 @@ fn hash_type_structure(st: sty) -> uint {
       ty_float(t) {
         alt t { ast::ty_f { 13u } ast::ty_f32 { 14u } ast::ty_f64 { 15u } }
       }
+      ty_estr(_) { 16u }
       ty_str { 17u }
       ty_enum(did, tys) {
         let mut h = hash_def(18u, did);
@@ -1510,6 +1609,7 @@ fn hash_type_structure(st: sty) -> uint {
         h
       }
       ty_box(mt) { hash_subty(19u, mt.ty) }
+      ty_evec(mt, _) { hash_subty(20u, mt.ty) }
       ty_vec(mt) { hash_subty(21u, mt.ty) }
       ty_rec(fields) {
         let mut h = 26u;
@@ -1849,15 +1949,15 @@ fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) {
 fn ty_sort_str(cx: ctxt, t: t) -> str {
     alt get(t).struct {
       ty_nil | ty_bot | ty_bool | ty_int(_) |
-      ty_uint(_) | ty_float(_) | ty_str | ty_type | ty_opaque_box |
-      ty_opaque_closure_ptr(_) {
+      ty_uint(_) | ty_float(_) | ty_estr(_) | ty_str |
+      ty_type | ty_opaque_box | ty_opaque_closure_ptr(_) {
         ty_to_str(cx, t)
       }
 
       ty_enum(_, _) { "enum" }
       ty_box(_) { "@-ptr" }
       ty_uniq(_) { "~-ptr" }
-      ty_vec(_) { "vector" }
+      ty_evec(_, _) | ty_vec(_) { "vector" }
       ty_ptr(_) { "*-ptr" }
       ty_rptr(_, _) { "&-ptr" }
       ty_rec(_) { "record" }
@@ -2312,14 +2412,11 @@ fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool {
     fn tycat(ty: t) -> int {
         alt get(ty).struct {
           ty_bool { tycat_bool }
-          ty_int(_) { tycat_int }
-          ty_uint(_) { tycat_int }
+          ty_int(_) | ty_uint(_) { tycat_int }
           ty_float(_) { tycat_float }
-          ty_str { tycat_str }
-          ty_vec(_) { tycat_vec }
-          ty_rec(_) { tycat_struct }
-          ty_tup(_) { tycat_struct }
-          ty_enum(_, _) { tycat_struct }
+          ty_estr(_) | ty_str { tycat_str }
+          ty_evec(_, _) | ty_vec(_) { tycat_vec }
+          ty_rec(_) | ty_tup(_) | ty_enum(_, _) { tycat_struct }
           ty_bot { tycat_bot }
           _ { tycat_other }
         }
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index f89a34e668f..46e8a2ad096 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -276,6 +276,53 @@ fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool {
 
 enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), }
 
+fn ast_region_to_region(tcx: ty::ctxt,
+                        region: ast::region) -> ty::region {
+    alt region.node {
+      ast::re_inferred {
+        // this must be replaced later by a fixup_regions() pass
+        ty::re_default
+      }
+      ast::re_self | ast::re_named(_) {
+        tcx.region_map.ast_type_to_region.get(region.id)
+      }
+      ast::re_static {
+        ty::re_static
+      }
+    }
+}
+
+fn ast_vstore_to_vstore(tcx: ty::ctxt, span: span, n: option<uint>,
+                        v: ast::vstore) -> ty::vstore {
+    alt v {
+      ast::vstore_fixed(none) {
+        alt n {
+          some(n) { ty::vstore_fixed(n) }
+          none {
+            tcx.sess.bug("implied fixed length in ast_vstore_to_vstore with \
+                          no default length")
+          }
+        }
+      }
+      ast::vstore_fixed(some(u)) {
+        alt n {
+          some(n) if n != u {
+            tcx.sess.span_err(span,
+                              #fmt("fixed-size sequence mismatch: %u vs. %u",
+                                   u, n));
+          }
+          _ { }
+        }
+        ty::vstore_fixed(u)
+      }
+      ast::vstore_uniq { ty::vstore_uniq }
+      ast::vstore_box { ty::vstore_box }
+      ast::vstore_slice(region) {
+        ty::vstore_slice(ast_region_to_region(tcx, region))
+      }
+    }
+}
+
 // Parses the programmer's textual representation of a type into our
 // internal notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
@@ -361,19 +408,8 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
             ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_rptr(region, mt) {
-            let r = alt region.node {
-              ast::re_inferred {
-                // this must be replaced later by a fixup_regions() pass
-                ty::re_default
-              }
-              ast::re_self | ast::re_named(_) {
-                tcx.region_map.ast_type_to_region.get(region.id)
-              }
-              ast::re_static {
-                ty::re_static
-              }
-            };
-            ty::mk_rptr(tcx, r, ast_mt_to_mt(tcx, mode, mt))
+            let region = ast_region_to_region(tcx, region);
+            ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_tup(fields) {
             let flds = vec::map(fields, bind do_ast_ty_to_ty(tcx, mode, _));
@@ -436,6 +472,18 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
               }
             }
           }
+          ast::ty_vstore(t, vst) {
+            let vst = ast_vstore_to_vstore(tcx, ast_ty.span, none, vst);
+            alt ty::get(do_ast_ty_to_ty(tcx, mode, t)).struct {
+              ty::ty_vec(mt) { ty::mk_evec(tcx, mt, vst) }
+              ty::ty_str { ty::mk_estr(tcx, vst) }
+              _ {
+                tcx.sess.span_fatal(ast_ty.span,
+                                    "found sequence storage modifier \
+                                     on non-sequence type");
+              }
+            }
+          }
           ast::ty_constr(t, cs) {
             let mut out_cs = [];
             for cs.each {|constr|
@@ -2799,6 +2847,31 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     let id = expr.id;
     let mut bot = false;
     alt expr.node {
+
+      ast::expr_vstore(ev, vst) {
+        alt ev.node {
+          ast::expr_lit(@{node: ast::lit_str(s), span:_}) {
+            let tt = ast_vstore_to_vstore(tcx, expr.span,
+                                          some(str::len(s)), vst);
+            let typ = ty::mk_estr(tcx, tt);
+            fcx.write_ty(ev.id, typ);
+            fcx.write_ty(id, typ);
+          }
+          ast::expr_vec(args, mutbl) {
+            let tt = ast_vstore_to_vstore(tcx, expr.span,
+                                          some(vec::len(args)), vst);
+            let t: ty::t = next_ty_var(fcx);
+            for args.each {|e| bot |= check_expr_with(fcx, e, t); }
+            let typ = ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, tt);
+            fcx.write_ty(ev.id, typ);
+            fcx.write_ty(id, typ);
+          }
+          _ {
+            tcx.sess.span_err(expr.span, "vstore modifier on non-sequence");
+          }
+        }
+      }
+
       ast::expr_lit(lit) {
         let typ = check_lit(fcx.ccx, lit);
         fcx.write_ty(id, typ);
@@ -3319,10 +3392,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         bot |= check_expr(fcx, idx);
         let idx_t = fcx.expr_ty(idx);
         alt structure_of(fcx, expr.span, base_t) {
+          ty::ty_evec(mt, _) |
           ty::ty_vec(mt) {
             require_integral(fcx, idx.span, idx_t);
             fcx.write_ty(id, mt.ty);
           }
+          ty::ty_estr(_) |
           ty::ty_str {
             require_integral(fcx, idx.span, idx_t);
             let typ = ty::mk_mach_uint(tcx, ast::ty_u8);