about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-12-22 09:30:03 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-12-22 09:30:03 -0800
commit47d27af228e574e281184a10f9a98f47ecce32ac (patch)
treed5dce2b742d73bb01ea0a9c528d9f996aacf1216
parent8005f0c564311fe2a3c0a72a5f3d4482ad0947e2 (diff)
parent07d7f828cd858bed67855e5a5ba24369625a981e (diff)
Merge branch 'master' of github.com:graydon/rust
-rw-r--r--AUTHORS.txt1
-rw-r--r--src/comp/metadata/encoder.rs2
-rw-r--r--src/comp/middle/check_const.rs1
-rw-r--r--src/comp/middle/debuginfo.rs7
-rw-r--r--src/comp/middle/trans.rs41
-rw-r--r--src/comp/middle/ty.rs227
-rw-r--r--src/comp/middle/typeck.rs39
-rw-r--r--src/comp/syntax/ast_util.rs17
-rw-r--r--src/comp/syntax/parse/parser.rs2
-rw-r--r--src/libcore/float.rs54
-rw-r--r--src/libstd/json.rs12
-rw-r--r--src/test/compile-fail/non-triv-cast-be.rs17
-rw-r--r--src/test/run-pass/triv-cast-be.rs28
-rw-r--r--src/test/run-pass/triv-cast-const.rs13
-rw-r--r--src/test/stdtest/json.rs7
-rw-r--r--src/test/stdtest/list.rs30
16 files changed, 176 insertions, 322 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt
index c6f4240a32c..c07ef5b37a0 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -27,6 +27,7 @@ Jesse Ruderman <jruderman@gmail.com>
 Josh Matthews <josh@joshmatthews.net>
 Joshua Wise <joshua@joshuawise.com>
 Kelly Wilson <wilsonk@cpsc.ucalgary.ca>
+Lennart Kudling
 Lindsey Kuper <lkuper@mozilla.com>
 Marijn Haverbeke <marijnh@gmail.com>
 Matt Brubeck <mbrubeck@limpet.net>
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index 1e844d39bca..169a1354f98 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -653,7 +653,7 @@ fn encode_hash(ebml_w: ebml::writer, hash: str) {
 
 fn encode_metadata(cx: @crate_ctxt, crate: @crate) -> str {
 
-    let abbrevs = map::mk_hashmap(ty::hash_ty, ty::eq_ty);
+    let abbrevs = ty::new_ty_hash();
     let ecx = @{ccx: cx, type_abbrevs: abbrevs};
 
     let string_w = io::string_writer();
diff --git a/src/comp/middle/check_const.rs b/src/comp/middle/check_const.rs
index 81d41b06e49..1a34fe631e9 100644
--- a/src/comp/middle/check_const.rs
+++ b/src/comp/middle/check_const.rs
@@ -43,7 +43,6 @@ fn check_expr(sess: session, e: @expr, &&is_const: bool, v: visit::vt<bool>) {
                           "disallowed operator in constant expression");
             ret;
           }
-          expr_cast(_, _) { }
           expr_lit(@{node: lit_str(_), _}) {
             sess.span_err(e.span,
                           "string constants are not supported");
diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs
index 96868cd0bf0..19b1578b29a 100644
--- a/src/comp/middle/debuginfo.rs
+++ b/src/comp/middle/debuginfo.rs
@@ -267,8 +267,7 @@ fn create_basic_type(cx: @crate_ctxt, t: ty::t, ty: @ast::ty)
     let cache = get_cache(cx);
     let tg = BasicTypeDescriptorTag;
     alt cached_metadata::<@metadata<tydesc_md>>(
-        cache, tg,
-        {|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) {
+        cache, tg, {|md| t == md.data.hash}) {
       option::some(md) { ret md; }
       option::none. {}
     }
@@ -311,7 +310,7 @@ fn create_basic_type(cx: @crate_ctxt, t: ty::t, ty: @ast::ty)
                   lli32(0), //XXX flags?
                   lli32(encoding)];
     let llnode = llmdnode(lldata);
-    let mdval = @{node: llnode, data: {hash: ty::hash_ty(t)}};
+    let mdval = @{node: llnode, data: {hash: t}};
     update_cache(cache, tg, tydesc_metadata(mdval));
     add_named_metadata(cx, "llvm.dbg.ty", llnode);
     ret mdval;
@@ -333,7 +332,7 @@ fn create_pointer_type(cx: @crate_ctxt, t: ty::t, span: codemap::span,
     //let cu_node = create_compile_unit(cx, fname);
     let llnode = create_derived_type(tg, file_node.node, "", 0, size * 8,
                                      align * 8, 0, pointee.node);
-    let mdval = @{node: llnode, data: {hash: ty::hash_ty(t)}};
+    let mdval = @{node: llnode, data: {hash: t}};
     //update_cache(cache, tg, tydesc_metadata(mdval));
     add_named_metadata(cx, "llvm.dbg.ty", llnode);
     ret mdval;
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index c163ac9871b..786ab1886c8 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3581,12 +3581,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
         }
         else { ret lval_to_dps(bcx, a, dest); }
       }
-      ast::expr_cast(val, _) {
-        alt tcx.cast_map.find(e.id) {
-          some(ty::triv_cast.) { ret trans_expr(bcx, val, dest); }
-          _ { ret trans_cast(bcx, val, e.id, dest); }
-        }
-      }
+      ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
       ast::expr_anon_obj(anon_obj) {
         ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest);
       }
@@ -3615,7 +3610,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
         // that is_call_expr(ex) -- but we don't support that
         // yet
         // FIXME
-        check (ast_util::is_tail_call_expr(ex));
+        check (ast_util::is_call_expr(ex));
         ret trans_be(bcx, ex);
       }
       ast::expr_fail(expr) {
@@ -3952,8 +3947,7 @@ fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
 fn build_return(bcx: @block_ctxt) { Br(bcx, bcx_fcx(bcx).llreturn); }
 
 // fn trans_be(cx: &@block_ctxt, e: &@ast::expr) -> result {
-fn trans_be(cx: @block_ctxt, e: @ast::expr) :
-ast_util::is_tail_call_expr(e) ->
+fn trans_be(cx: @block_ctxt, e: @ast::expr) : ast_util::is_call_expr(e) ->
    @block_ctxt {
     // FIXME: Turn this into a real tail call once
     // calling convention issues are settled
@@ -4354,7 +4348,7 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: span, llfndecl: ValueRef,
           lllocals: new_int_hash::<local_val>(),
           llupvars: new_int_hash::<ValueRef>(),
           mutable lltydescs: [],
-          derived_tydescs: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
+          derived_tydescs: ty::new_ty_hash(),
           id: id,
           ret_style: rstyle,
           sp: sp,
@@ -4728,16 +4722,6 @@ fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
 // that does so later on?
 fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
     alt e.node {
-      ast::expr_cast(e1, _) {
-        alt ccx_tcx(cx).cast_map.find(e.id) {
-          some(ty::triv_cast.) { trans_const_expr(cx, e1) }
-          _ {
-              cx.sess.span_err(e.span,
-                               "non-trivial cast in constant expression");
-              fail;
-            }
-        }
-      }
       ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); }
       ast::expr_binary(b, e1, e2) {
         let te1 = trans_const_expr(cx, e1);
@@ -5658,13 +5642,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
     tn.associate("taskptr", taskptr_type);
     let tydesc_type = T_tydesc(targ_cfg);
     tn.associate("tydesc", tydesc_type);
-    let hasher = ty::hash_ty;
-    let eqer = ty::eq_ty;
-    let tag_sizes = map::mk_hashmap::<ty::t, uint>(hasher, eqer);
-    let tydescs = map::mk_hashmap::<ty::t, @tydesc_info>(hasher, eqer);
-    let lltypes = map::mk_hashmap::<ty::t, TypeRef>(hasher, eqer);
-    let sha1s = map::mk_hashmap::<ty::t, str>(hasher, eqer);
-    let short_names = map::mk_hashmap::<ty::t, str>(hasher, eqer);
     let crate_map = decl_crate_map(sess, link_meta.name, llmod);
     let dbg_cx = if sess.get_opts().debuginfo {
         option::some(@{llmetadata: map::new_int_hash(),
@@ -5685,18 +5662,18 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           item_symbols: new_int_hash::<str>(),
           mutable main_fn: none::<ValueRef>,
           link_meta: link_meta,
-          tag_sizes: tag_sizes,
+          tag_sizes: ty::new_ty_hash(),
           discrims: ast_util::new_def_id_hash::<ValueRef>(),
           discrim_symbols: new_int_hash::<str>(),
           consts: new_int_hash::<ValueRef>(),
           obj_methods: new_int_hash::<()>(),
-          tydescs: tydescs,
+          tydescs: ty::new_ty_hash(),
           module_data: new_str_hash::<ValueRef>(),
-          lltypes: lltypes,
+          lltypes: ty::new_ty_hash(),
           names: namegen(0),
           sha: sha,
-          type_sha1s: sha1s,
-          type_short_names: short_names,
+          type_sha1s: ty::new_ty_hash(),
+          type_short_names: ty::new_ty_hash(),
           tcx: tcx,
           mut_map: mut_map,
           copy_map: copy_map,
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index ca63fdb6dd8..25c8d948a40 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -31,13 +31,11 @@ export ast_constr_to_constr;
 export bind_params_in_type;
 export block_ty;
 export constr;
-export cast_type;
 export constr_general;
 export constr_table;
 export count_ty_params;
 export ctxt;
 export def_has_ty_params;
-export eq_ty;
 export expr_has_ty_params;
 export expr_ty;
 export expr_ty_params_and_ty;
@@ -48,7 +46,6 @@ export field_idx;
 export get_field;
 export fm_general;
 export get_element_type;
-export hash_ty;
 export idx_nil;
 export is_binopable;
 export is_pred_ty;
@@ -104,10 +101,9 @@ export stmt_node_id;
 export sty;
 export substitute_type_params;
 export t;
+export new_ty_hash;
 export tag_variants;
 export tag_variant_with_id;
-export triv_cast;
-export triv_eq_ty;
 export ty_param_substs_opt_and_ty;
 export ty_param_kinds_and_ty;
 export ty_native_fn;
@@ -133,7 +129,6 @@ export ty_param;
 export ty_ptr;
 export ty_rec;
 export ty_tag;
-export ty_to_machine_ty;
 export ty_tup;
 export ty_type;
 export ty_send_type;
@@ -141,6 +136,7 @@ export ty_uint;
 export ty_uniq;
 export ty_var;
 export ty_named;
+export same_type, same_method;
 export ty_var_id;
 export ty_param_substs_opt_and_ty_to_monotype;
 export ty_fn_args;
@@ -211,20 +207,10 @@ type mt = {ty: t, mut: ast::mutability};
 // the types of AST nodes.
 type creader_cache = hashmap<{cnum: int, pos: uint, len: uint}, ty::t>;
 
-type tag_var_cache =
-    @smallintmap::smallintmap<@mutable [variant_info]>;
-
-tag cast_type {
-    /* cast may be ignored after substituting primitive with machine types
-       since expr already has the right type */
-    triv_cast;
-}
-
 type ctxt =
     @{ts: @type_store,
       sess: session::session,
       def_map: resolve::def_map,
-      cast_map: hashmap<ast::node_id, cast_type>,
       node_types: node_type_table,
       items: ast_map::map,
       freevars: freevars::freevar_map,
@@ -234,7 +220,7 @@ type ctxt =
       needs_drop_cache: hashmap<t, bool>,
       kind_cache: hashmap<t, ast::kind>,
       ast_ty_to_ty_cache: hashmap<@ast::ty, option::t<t>>,
-      tag_var_cache: tag_var_cache};
+      tag_var_cache: hashmap<ast::def_id, @[variant_info]>};
 
 type ty_ctxt = ctxt;
 
@@ -409,29 +395,31 @@ fn mk_rcache() -> creader_cache {
     ret map::mk_hashmap(hash_cache_entry, eq_cache_entries);
 }
 
+fn new_ty_hash<copy V>() -> map::hashmap<t, V> { map::new_uint_hash() }
 
 fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
            freevars: freevars::freevar_map) -> ctxt {
     let ntt: node_type_table =
         @smallintmap::mk::<ty::ty_param_substs_opt_and_ty>();
-    let tcache = new_def_hash::<ty::ty_param_kinds_and_ty>();
+    fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
+        ret a.hash == b.hash && a.struct == b.struct;
+    }
     let ts = @interner::mk::<@raw_t>(hash_raw_ty, eq_raw_ty);
     let cx =
         @{ts: ts,
           sess: s,
           def_map: dm,
-          cast_map: ast_util::new_node_hash(),
           node_types: ntt,
           items: amap,
           freevars: freevars,
-          tcache: tcache,
+          tcache: new_def_hash(),
           rcache: mk_rcache(),
-          short_names_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
-          needs_drop_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
-          kind_cache: map::mk_hashmap(ty::hash_ty, ty::eq_ty),
+          short_names_cache: new_ty_hash(),
+          needs_drop_cache: new_ty_hash(),
+          kind_cache: new_ty_hash(),
           ast_ty_to_ty_cache:
               map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty),
-          tag_var_cache: @smallintmap::mk()};
+          tag_var_cache: new_def_hash()};
     populate_type_store(cx);
     ret cx;
 }
@@ -1245,8 +1233,7 @@ fn type_autoderef(cx: ctxt, t: ty::t) -> ty::t {
     ret t1;
 }
 
-// Type hashing. This function is private to this module (and slow); external
-// users should use `hash_ty()` instead.
+// Type hashing.
 fn hash_type_structure(st: sty) -> uint {
     fn hash_uint(id: uint, n: uint) -> uint {
         let h = id;
@@ -1261,7 +1248,7 @@ fn hash_type_structure(st: sty) -> uint {
     }
     fn hash_subty(id: uint, subty: t) -> uint {
         let h = id;
-        h += (h << 5u) + hash_ty(subty);
+        h += (h << 5u) + subty;
         ret h;
     }
     fn hash_subtys(id: uint, subtys: [t]) -> uint {
@@ -1296,8 +1283,8 @@ fn hash_type_structure(st: sty) -> uint {
 
     fn hash_fn(id: uint, args: [arg], rty: t) -> uint {
         let h = id;
-        for a: arg in args { h += (h << 5u) + hash_ty(a.ty); }
-        h += (h << 5u) + hash_ty(rty);
+        for a: arg in args { h += (h << 5u) + a.ty; }
+        h += (h << 5u) + rty;
         ret h;
     }
     alt st {
@@ -1320,14 +1307,14 @@ fn hash_type_structure(st: sty) -> uint {
       ty_str. { ret 17u; }
       ty_tag(did, tys) {
         let h = hash_def(18u, did);
-        for typ: t in tys { h += (h << 5u) + hash_ty(typ); }
+        for typ: t in tys { h += (h << 5u) + typ; }
         ret h;
       }
       ty_box(mt) { ret hash_subty(19u, mt.ty); }
       ty_vec(mt) { ret hash_subty(21u, mt.ty); }
       ty_rec(fields) {
         let h = 26u;
-        for f: field in fields { h += (h << 5u) + hash_ty(f.mt.ty); }
+        for f: field in fields { h += (h << 5u) + f.mt.ty; }
         ret h;
       }
       ty_tup(ts) { ret hash_subtys(25u, ts); }
@@ -1366,13 +1353,6 @@ fn hash_type_structure(st: sty) -> uint {
 
 fn hash_raw_ty(&&rt: @raw_t) -> uint { ret rt.hash; }
 
-fn hash_ty(&&typ: t) -> uint { ret typ; }
-
-
-// Type equality. This function is private to this module (and slow); external
-// users should use `eq_ty()` instead.
-fn eq_int(&&x: uint, &&y: uint) -> bool { ret x == y; }
-
 fn arg_eq<T>(eq: fn(T, T) -> bool, a: @sp_constr_arg<T>, b: @sp_constr_arg<T>)
    -> bool {
     alt a.node {
@@ -1401,6 +1381,7 @@ fn args_eq<T>(eq: fn(T, T) -> bool, a: [@sp_constr_arg<T>],
 }
 
 fn constr_eq(c: @constr, d: @constr) -> bool {
+    fn eq_int(&&x: uint, &&y: uint) -> bool { ret x == y; }
     ret path_to_str(c.node.path) == path_to_str(d.node.path) &&
             // FIXME: hack
             args_eq(eq_int, c.node.args, d.node.args);
@@ -1413,52 +1394,6 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool {
     ret true;
 }
 
-// This function is private to this module.
-fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
-    ret a.hash == b.hash && a.struct == b.struct;
-}
-
-
-// This is the equality function the public should use. It works as long as
-// the types are interned.
-fn eq_ty(&&a: t, &&b: t) -> bool { a == b }
-
-
-// Convert type to machine type
-// (i.e. replace uint, int, float with target architecture machine types)
-//
-// FIXME somewhat expensive but this should only be called rarely
-fn ty_to_machine_ty(cx: ctxt, ty: t) -> t {
-    fn sub_fn(cx: ctxt, uint_ty: t, int_ty: t, float_ty: t, in: t) -> t {
-        alt struct(cx, in) {
-          ty_uint(ast::ty_u.) { ret uint_ty; }
-          ty_int(ast::ty_i.) { ret int_ty; }
-          ty_float(ast::ty_f.) { ret float_ty; }
-          _ { ret in; }
-        }
-    }
-
-    let cfg      = cx.sess.get_targ_cfg();
-    let uint_ty  = mk_mach_uint(cx, cfg.uint_type);
-    let int_ty   = mk_mach_int(cx, cfg.int_type);
-    let float_ty = mk_mach_float(cx, cfg.float_type);
-    let fold_m   = fm_general(bind sub_fn(cx, uint_ty, int_ty, float_ty, _));
-
-    ret fold_ty(cx, fold_m, ty);
-}
-
-// Two types are trivially equal if they are either
-// equal or if they are equal after substituting all occurences of
-//  machine independent primitive types by their machine type equivalents
-// for the current target architecture
-fn triv_eq_ty(cx: ctxt, &&a: t, &&b: t) -> bool {
-    let a = alt interner::get(*cx.ts, a).struct
-        { ty_named(t, _) { t } _ { a } };
-    let b = alt interner::get(*cx.ts, b).struct
-        { ty_named(t, _) { t } _ { b } };
-    a == b || ty_to_machine_ty(cx, a) == ty_to_machine_ty(cx, b)
-}
-
 // Type lookups
 fn node_id_to_ty_param_substs_opt_and_ty(cx: ctxt, id: ast::node_id) ->
    ty_param_substs_opt_and_ty {
@@ -1745,7 +1680,7 @@ mod unify {
     type var_bindings =
         {sets: ufind::ufind, types: smallintmap::smallintmap<t>};
 
-    type ctxt = {vb: @var_bindings, tcx: ty_ctxt};
+    type ctxt = {vb: option::t<@var_bindings>, tcx: ty_ctxt};
 
     fn mk_var_bindings() -> @var_bindings {
         ret @{sets: ufind::make(), types: smallintmap::mk::<t>()};
@@ -1754,31 +1689,32 @@ mod unify {
     // Unifies two sets.
     fn union(cx: @ctxt, set_a: uint, set_b: uint,
              variance: variance) -> union_result {
-        ufind::grow(cx.vb.sets, float::max(set_a, set_b) + 1u);
-        let root_a = ufind::find(cx.vb.sets, set_a);
-        let root_b = ufind::find(cx.vb.sets, set_b);
+        let vb = option::get(cx.vb);
+        ufind::grow(vb.sets, float::max(set_a, set_b) + 1u);
+        let root_a = ufind::find(vb.sets, set_a);
+        let root_b = ufind::find(vb.sets, set_b);
 
         let replace_type =
-            bind fn (cx: @ctxt, t: t, set_a: uint, set_b: uint) {
-                     ufind::union(cx.vb.sets, set_a, set_b);
-                     let root_c: uint = ufind::find(cx.vb.sets, set_a);
-                     smallintmap::insert::<t>(cx.vb.types, root_c, t);
+            bind fn (vb: @var_bindings, t: t, set_a: uint, set_b: uint) {
+                     ufind::union(vb.sets, set_a, set_b);
+                     let root_c: uint = ufind::find(vb.sets, set_a);
+                     smallintmap::insert::<t>(vb.types, root_c, t);
                  }(_, _, set_a, set_b);
 
 
-        alt smallintmap::find(cx.vb.types, root_a) {
+        alt smallintmap::find(vb.types, root_a) {
           none. {
-            alt smallintmap::find(cx.vb.types, root_b) {
-              none. { ufind::union(cx.vb.sets, set_a, set_b); ret unres_ok; }
-              some(t_b) { replace_type(cx, t_b); ret unres_ok; }
+            alt smallintmap::find(vb.types, root_b) {
+              none. { ufind::union(vb.sets, set_a, set_b); ret unres_ok; }
+              some(t_b) { replace_type(vb, t_b); ret unres_ok; }
             }
           }
           some(t_a) {
-            alt smallintmap::find(cx.vb.types, root_b) {
-              none. { replace_type(cx, t_a); ret unres_ok; }
+            alt smallintmap::find(vb.types, root_b) {
+              none. { replace_type(vb, t_a); ret unres_ok; }
               some(t_b) {
                 alt unify_step(cx, t_a, t_b, variance) {
-                  ures_ok(t_c) { replace_type(cx, t_c); ret unres_ok; }
+                  ures_ok(t_c) { replace_type(vb, t_c); ret unres_ok; }
                   ures_err(terr) { ret unres_err(terr); }
                 }
               }
@@ -1803,10 +1739,11 @@ mod unify {
     fn record_var_binding(
         cx: @ctxt, key: int, typ: t, variance: variance) -> result {
 
-        ufind::grow(cx.vb.sets, (key as uint) + 1u);
-        let root = ufind::find(cx.vb.sets, key as uint);
+        let vb = option::get(cx.vb);
+        ufind::grow(vb.sets, (key as uint) + 1u);
+        let root = ufind::find(vb.sets, key as uint);
         let result_type = typ;
-        alt smallintmap::find::<t>(cx.vb.types, root) {
+        alt smallintmap::find(vb.types, root) {
           some(old_type) {
             alt unify_step(cx, old_type, typ, variance) {
               ures_ok(unified_type) { result_type = unified_type; }
@@ -1815,7 +1752,7 @@ mod unify {
           }
           none. {/* fall through */ }
         }
-        smallintmap::insert::<t>(cx.vb.types, root, result_type);
+        smallintmap::insert::<t>(vb.types, root, result_type);
         ret ures_ok(typ);
     }
 
@@ -2136,12 +2073,15 @@ mod unify {
 
     fn unify_step(cx: @ctxt, expected: t, actual: t,
                   variance: variance) -> result {
-        // TODO: rewrite this using tuple pattern matching when available, to
+        // FIXME: rewrite this using tuple pattern matching when available, to
         // avoid all this rightward drift and spikiness.
+        // NOTE: we have tuple matching now, but that involves copying the
+        // matched elements into a tuple first, which is expensive, since sty
+        // holds vectors, which are currently unique
 
         // Fast path.
+        if expected == actual { ret ures_ok(expected); }
 
-        if eq_ty(expected, actual) { ret ures_ok(expected); }
         // Stage 1: Handle the cases in which one side or another is a type
         // variable.
 
@@ -2149,6 +2089,7 @@ mod unify {
           // If the RHS is a variable type, then just do the
           // appropriate binding.
           ty::ty_var(actual_id) {
+            assert option::is_some(cx.vb);
             let actual_n = actual_id as uint;
             alt struct(cx.tcx, expected) {
               ty::ty_var(expected_id) {
@@ -2173,8 +2114,8 @@ mod unify {
         }
         alt struct(cx.tcx, expected) {
           ty::ty_var(expected_id) {
+            assert option::is_some(cx.vb);
             // Add a binding. (`actual` can't actually be a var here.)
-
             alt record_var_binding_for_expected(
                 cx, expected_id, actual,
                 variance) {
@@ -2490,8 +2431,8 @@ mod unify {
           }
         }
     }
-    fn unify(expected: t, actual: t, vb: @var_bindings, tcx: ty_ctxt) ->
-       result {
+    fn unify(expected: t, actual: t, vb: option::t<@var_bindings>,
+             tcx: ty_ctxt) -> result {
         let cx = @{vb: vb, tcx: tcx};
         ret unify_step(cx, expected, actual, covariant);
     }
@@ -2564,6 +2505,19 @@ mod unify {
     }
 }
 
+fn same_type(cx: ctxt, a: t, b: t) -> bool {
+    alt unify::unify(a, b, none, cx) {
+      unify::ures_ok(_) { true }
+      _ { false }
+    }
+}
+fn same_method(cx: ctxt, a: method, b: method) -> bool {
+    a.proto == b.proto && a.ident == b.ident &&
+    vec::all2(a.inputs, b.inputs,
+              {|a, b| a.mode == b.mode && same_type(cx, a.ty, b.ty) }) &&
+    same_type(cx, a.output, b.output) && a.cf == b.cf
+}
+
 fn type_err_to_str(err: ty::type_err) -> str {
     alt err {
       terr_mismatch. { ret "types differ"; }
@@ -2669,45 +2623,34 @@ fn def_has_ty_params(def: ast::def) -> bool {
 // Tag information
 type variant_info = @{args: [ty::t], ctor_ty: ty::t, id: ast::def_id};
 
-fn tag_variants(cx: ctxt, id: ast::def_id) -> @mutable [variant_info] {
-    if ast::local_crate != id.crate {
-        ret @mutable csearch::get_tag_variants(cx, id);
-    }
-    assert (id.node >= 0);
-    alt smallintmap::find(*cx.tag_var_cache, id.node as uint) {
-      option::some(variants) { ret variants; }
+fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
+    alt cx.tag_var_cache.find(id) {
+      some(variants) { ret variants; }
       _ { /* fallthrough */ }
     }
-    let item =
-        alt cx.items.find(id.node) {
-          some(i) { i }
-          none. { cx.sess.bug("expected to find cached node_item") }
-        };
-    alt item {
-      ast_map::node_item(item) {
-        alt item.node {
-          ast::item_tag(variants, _) {
-            let result: @mutable [variant_info] = @mutable [];
-            for variant: ast::variant in variants {
-                let ctor_ty = node_id_to_monotype(cx, variant.node.id);
-                let arg_tys: [t] = [];
-                if vec::len(variant.node.args) > 0u {
-                    for a: arg in ty_fn_args(cx, ctor_ty) {
-                        arg_tys += [a.ty];
-                    }
-                }
-                let did = variant.node.id;
-                *result +=
-                    [@{args: arg_tys,
-                       ctor_ty: ctor_ty,
-                       id: ast_util::local_def(did)}];
+    let result = if ast::local_crate != id.crate {
+        @csearch::get_tag_variants(cx, id)
+    } else {
+        alt cx.items.get(id.node) {
+          ast_map::node_item(item) {
+            alt item.node {
+              ast::item_tag(variants, _) {
+                @vec::map(variants, {|variant|
+                    let ctor_ty = node_id_to_monotype(cx, variant.node.id);
+                    let arg_tys = if vec::len(variant.node.args) > 0u {
+                        vec::map(ty_fn_args(cx, ctor_ty), {|a| a.ty})
+                    } else { [] };
+                    @{args: arg_tys,
+                      ctor_ty: ctor_ty,
+                      id: ast_util::local_def(variant.node.id)}
+                })
+              }
             }
-            smallintmap::insert(*cx.tag_var_cache, id.node as uint, result);
-            ret result;
           }
         }
-      }
-    }
+    };
+    cx.tag_var_cache.insert(id, result);
+    result
 }
 
 
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 1de1457b76a..400411fa68a 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -791,7 +791,8 @@ mod collect {
 mod unify {
     fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) ->
        ty::unify::result {
-        ret ty::unify::unify(expected, actual, fcx.var_bindings, fcx.ccx.tcx);
+        ret ty::unify::unify(expected, actual, some(fcx.var_bindings),
+                             fcx.ccx.tcx);
     }
 }
 
@@ -1106,7 +1107,7 @@ fn gather_locals(ccx: @crate_ctxt,
             alt ty_opt {
               none. {/* nothing to do */ }
               some(typ) {
-                ty::unify::unify(ty::mk_var(tcx, var_id), typ, vb, tcx);
+                ty::unify::unify(ty::mk_var(tcx, var_id), typ, some(vb), tcx);
               }
             }
         };
@@ -1198,8 +1199,8 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
         check_expr_with(fcx, end, expected);
         let b_ty = resolve_type_vars_if_possible(fcx, expr_ty(fcx.ccx.tcx,
                                                               begin));
-        if b_ty != resolve_type_vars_if_possible(fcx, expr_ty(fcx.ccx.tcx,
-                                                              end)) {
+        if !ty::same_type(fcx.ccx.tcx, b_ty, resolve_type_vars_if_possible(
+            fcx, expr_ty(fcx.ccx.tcx, end))) {
             fcx.ccx.tcx.sess.span_err(pat.span, "mismatched types in range");
         } else if !ty::type_is_numeric(fcx.ccx.tcx, b_ty) {
             fcx.ccx.tcx.sess.span_err(pat.span,
@@ -1850,21 +1851,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       }
       ast::expr_be(e) {
         // FIXME: prove instead of assert
-        assert (ast_util::is_tail_call_expr(e));
+        assert (ast_util::is_call_expr(e));
         check_expr_with(fcx, e, fcx.ret_ty);
-
-        alt e.node {
-          ast::expr_cast(_, _) {
-            alt tcx.cast_map.find(e.id) {
-              option::some(ty::triv_cast.) { }
-              _ { tcx.sess.span_err(expr.span,
-                    "non-trivial cast of tail-call return value");
-                }
-            }
-          }
-          _ { /* regular tail call */ }
-        }
-
         bot = true;
         write::nil_ty(tcx, id);
       }
@@ -2066,19 +2054,19 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       ast::expr_cast(e, t) {
         bot = check_expr(fcx, e);
         let t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
-        let t_e = expr_ty(tcx, e);
+        let t_e = ty::expr_ty(tcx, e);
 
         if ty::type_is_nil(tcx, t_e) {
             tcx.sess.span_err(expr.span,
                               "cast from nil: " +
-                                  ty_to_str(tcx, expr_ty(tcx, e)) + " as " +
+                                  ty_to_str(tcx, t_e) + " as " +
                                   ty_to_str(tcx, t_1));
         }
 
         if ty::type_is_nil(tcx, t_1) {
             tcx.sess.span_err(expr.span,
                               "cast to nil: " +
-                                  ty_to_str(tcx, expr_ty(tcx, e)) + " as " +
+                                  ty_to_str(tcx, t_e) + " as " +
                                   ty_to_str(tcx, t_1));
         }
 
@@ -2087,14 +2075,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
              && type_is_scalar(fcx, expr.span, t_1)) {
             tcx.sess.span_err(expr.span,
                               "non-scalar cast: " +
-                                  ty_to_str(tcx, expr_ty(tcx, e)) + " as " +
+                                  ty_to_str(tcx, t_e) + " as " +
                                   ty_to_str(tcx, t_1));
         }
-
-        // mark as triv_cast for later dropping in trans
-        if ty::triv_eq_ty(tcx, t_1, t_e)
-            { tcx.cast_map.insert(expr.id, ty::triv_cast); }
-
         write::ty_only_fixup(fcx, id, t_1);
       }
       ast::expr_vec(args, mut) {
@@ -2342,7 +2325,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
                         // We'd better be overriding with one of the same
                         // type.  Check to make sure.
                         let new_type = ty_of_method(ccx.tcx, m_check, om);
-                        if new_type != m {
+                        if !ty::same_method(ccx.tcx, new_type, m) {
                             ccx.tcx.sess.span_fatal
                                 (om.span, "attempted to override method "
                                  + m.ident + " with one of a different type");
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index ea3ca0bd504..f32b4f7aa93 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -1,5 +1,3 @@
-import core::{str, option, int};
-import std::map;
 import codemap::span;
 import ast::*;
 
@@ -7,13 +5,6 @@ fn respan<copy T>(sp: span, t: T) -> spanned<T> {
     ret {node: t, span: sp};
 }
 
-fn new_node_hash<copy V>() -> map::hashmap<node_id, V> {
-    fn node_id_hash(&&i: node_id) -> uint { ret int::hash(i as int); }
-    fn node_id_eq(&&a: node_id, &&b: node_id) -> bool
-        { ret int::eq(a as int, b as int); }
-    ret map::mk_hashmap(node_id_hash, node_id_eq);
-}
-
 /* assuming that we're not in macro expansion */
 fn mk_sp(lo: uint, hi: uint) -> span {
     ret {lo: lo, hi: hi, expanded_from: codemap::os_none};
@@ -198,14 +189,6 @@ pure fn is_call_expr(e: @expr) -> bool {
     alt e.node { expr_call(_, _, _) { true } _ { false } }
 }
 
-pure fn is_tail_call_expr(e: @expr) -> bool {
-    alt e.node {
-      expr_call(_, _, _) { true }
-      expr_cast(inner_e, _) { is_call_expr(inner_e) }
-      _ { false }
-    }
-}
-
 fn is_constraint_arg(e: @expr) -> bool {
     alt e.node {
       expr_lit(_) { ret true; }
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 81e476e22c3..84c60144501 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -961,7 +961,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
         let e = parse_expr(p);
 
         // FIXME: Is this the right place for this check?
-        if /*check*/ ast_util::is_tail_call_expr(e) {
+        if /*check*/ast_util::is_call_expr(e) {
             hi = e.span.hi;
             ex = ast::expr_be(e);
         } else { p.fatal("Non-call expression in tail call"); }
diff --git a/src/libcore/float.rs b/src/libcore/float.rs
index ab27b938b53..fdc5dda996d 100644
--- a/src/libcore/float.rs
+++ b/src/libcore/float.rs
@@ -482,7 +482,7 @@ Function: acos
 Returns the arccosine of an angle (measured in rad)
 */
 pure fn acos(x: float) -> float
-    { be m_float::acos(x as m_float) as float }
+    { ret m_float::acos(x as m_float) as float }
 
 /*
 Function: asin
@@ -490,7 +490,7 @@ Function: asin
 Returns the arcsine of an angle (measured in rad)
 */
 pure fn asin(x: float) -> float
-    { be m_float::asin(x as m_float) as float }
+    { ret m_float::asin(x as m_float) as float }
 
 /*
 Function: atan
@@ -498,7 +498,7 @@ Function: atan
 Returns the arctangents of an angle (measured in rad)
 */
 pure fn atan(x: float) -> float
-    { be m_float::atan(x as m_float) as float }
+    { ret m_float::atan(x as m_float) as float }
 
 
 /*
@@ -507,7 +507,7 @@ Function: atan2
 Returns the arctangent of an angle (measured in rad)
 */
 pure fn atan2(y: float, x: float) -> float
-    { be m_float::atan2(y as m_float, x as m_float) as float }
+    { ret m_float::atan2(y as m_float, x as m_float) as float }
 
 /*
 Function: ceil
@@ -515,7 +515,7 @@ Function: ceil
 Returns the smallest integral value less than or equal to `n`
 */
 pure fn ceil(n: float) -> float
-    { be m_float::ceil(n as m_float) as float }
+    { ret m_float::ceil(n as m_float) as float }
 
 /*
 Function: cos
@@ -523,7 +523,7 @@ Function: cos
 Returns the cosine of an angle `x` (measured in rad)
 */
 pure fn cos(x: float) -> float
-    { be m_float::cos(x as m_float) as float }
+    { ret m_float::cos(x as m_float) as float }
 
 /*
 Function: cosh
@@ -532,7 +532,7 @@ Returns the hyperbolic cosine of `x`
 
 */
 pure fn cosh(x: float) -> float
-    { be m_float::cosh(x as m_float) as float }
+    { ret m_float::cosh(x as m_float) as float }
 
 
 /*
@@ -541,7 +541,7 @@ Function: exp
 Returns `consts::e` to the power of `n*
 */
 pure fn exp(n: float) -> float
-    { be m_float::exp(n as m_float) as float }
+    { ret m_float::exp(n as m_float) as float }
 
 /*
 Function: abs
@@ -549,7 +549,7 @@ Function: abs
 Returns the absolute value of  `n`
 */
 pure fn abs(n: float) -> float
-    { be m_float::abs(n as m_float) as float }
+    { ret m_float::abs(n as m_float) as float }
 
 /*
 Function: floor
@@ -557,7 +557,7 @@ Function: floor
 Returns the largest integral value less than or equal to `n`
 */
 pure fn floor(n: float) -> float
-    { be m_float::floor(n as m_float) as float }
+    { ret m_float::floor(n as m_float) as float }
 
 /*
 Function: fmod
@@ -565,7 +565,7 @@ Function: fmod
 Returns the floating-point remainder of `x/y`
 */
 pure fn fmod(x: float, y: float) -> float
-    { be m_float::fmod(x as m_float, y as m_float) as float }
+    { ret m_float::fmod(x as m_float, y as m_float) as float }
 
 /*
 Function: ln
@@ -573,7 +573,7 @@ Function: ln
 Returns the natural logaritm of `n`
 */
 pure fn ln(n: float) -> float
-    { be m_float::ln(n as m_float) as float }
+    { ret m_float::ln(n as m_float) as float }
 
 /*
 Function: ldexp
@@ -581,7 +581,7 @@ Function: ldexp
 Returns `x` multiplied by 2 to the power of `n`
 */
 pure fn ldexp(n: float, i: int) -> float
-    { be m_float::ldexp(n as m_float, i as c_int) as float }
+    { ret m_float::ldexp(n as m_float, i as c_int) as float }
 
 /*
 Function: ln1p
@@ -590,7 +590,7 @@ Returns the natural logarithm of `1+n` accurately,
 even for very small values of `n`
 */
 pure fn ln1p(n: float) -> float
-    { be m_float::ln1p(n as m_float) as float }
+    { ret m_float::ln1p(n as m_float) as float }
 
 /*
 Function: log10
@@ -598,7 +598,7 @@ Function: log10
 Returns the logarithm to base 10 of `n`
 */
 pure fn log10(n: float) -> float
-    { be m_float::log10(n as m_float) as float }
+    { ret m_float::log10(n as m_float) as float }
 
 /*
 Function: log2
@@ -606,7 +606,7 @@ Function: log2
 Returns the logarithm to base 2 of `n`
 */
 pure fn log2(n: float) -> float
-    { be m_float::log2(n as m_float) as float }
+    { ret m_float::log2(n as m_float) as float }
 
 /*
 Function: modf
@@ -622,7 +622,7 @@ The fractional part of `n`
 */
 #[no(warn_trivial_casts)] // FIXME Implement
 pure fn modf(n: float, &iptr: float) -> float { unsafe {
-    be m_float::modf(n as m_float, ptr::addr_of(iptr) as *m_float) as float
+    ret m_float::modf(n as m_float, ptr::addr_of(iptr) as *m_float) as float
 } }
 
 /*
@@ -640,13 +640,13 @@ Returns:
 The fractional part of `n`
 */
 pure fn frexp(n: float, &exp: c_int) -> float
-    { be m_float::frexp(n as m_float, exp) as float }
+    { ret m_float::frexp(n as m_float, exp) as float }
 
 /*
 Function: pow
 */
 pure fn pow(v: float, e: float) -> float
-    { be m_float::pow(v as m_float, e as m_float) as float }
+    { ret m_float::pow(v as m_float, e as m_float) as float }
 
 
 /*
@@ -656,7 +656,7 @@ Returns the integral value nearest to `x` (according to the
 prevailing rounding mode) in floating-point format
 */
 pure fn rint(x: float) -> float
-    { be m_float::rint(x as m_float) as float }
+    { ret m_float::rint(x as m_float) as float }
 
 /*
 Function: round
@@ -666,7 +666,7 @@ Return the integral value nearest to `x` rounding half-way
 cases away from zero, regardless of the current rounding direction.
 */
 pure fn round(x: float) -> float
-    { be m_float::round(x as m_float) as float }
+    { ret m_float::round(x as m_float) as float }
 
 /*
 Function: sin
@@ -674,7 +674,7 @@ Function: sin
 Returns the sine of an angle `x` (measured in rad)
 */
 pure fn sin(x: float) -> float
-    { be m_float::sin(x as m_float) as float }
+    { ret m_float::sin(x as m_float) as float }
 
 /*
 Function: sinh
@@ -682,7 +682,7 @@ Function: sinh
 Returns the hyperbolic sine of an angle `x` (measured in rad)
 */
 pure fn sinh(x: float) -> float
-    { be m_float::sinh(x as m_float) as float }
+    { ret m_float::sinh(x as m_float) as float }
 
 /*
 Function: sqrt
@@ -690,7 +690,7 @@ Function: sqrt
 Returns the square root of `x`
 */
 pure fn sqrt(x: float) -> float
-    { be m_float::sqrt(x as m_float) as float }
+    { ret m_float::sqrt(x as m_float) as float }
 
 /*
 Function: tan
@@ -699,7 +699,7 @@ Returns the tangent of an angle `x` (measured in rad)
 
 */
 pure fn tan(x: float) -> float
-    { be m_float::tan(x as m_float) as float }
+    { ret m_float::tan(x as m_float) as float }
 
 /*
 Function: tanh
@@ -708,7 +708,7 @@ Returns the hyperbolic tangent of an angle `x` (measured in rad)
 
 */
 pure fn tanh(x: float) -> float
-    { be m_float::tanh(x as m_float) as float }
+    { ret m_float::tanh(x as m_float) as float }
 
 /*
 Function: trunc
@@ -717,7 +717,7 @@ Returns the integral value nearest to but no larger in magnitude than `x`
 
 */
 pure fn trunc(x: float) -> float
-    { be m_float::trunc(x as m_float) as float }
+    { ret m_float::trunc(x as m_float) as float }
 
 //
 // Local Variables:
diff --git a/src/libstd/json.rs b/src/libstd/json.rs
index e0b559ec747..64ce2794bb4 100644
--- a/src/libstd/json.rs
+++ b/src/libstd/json.rs
@@ -34,6 +34,8 @@ tag json {
     list(@[json]);
     /* Variant: dict */
     dict(map::hashmap<str,json>);
+    /* Variant: null */
+    null;
 }
 
 /*
@@ -63,6 +65,7 @@ fn to_str(j: json) -> str {
             });
             str::concat(["{ ", str::connect(parts, ", "), " }"])
         }
+        null { "null" }
     }
 }
 
@@ -233,6 +236,14 @@ fn from_str_bool(s: str) -> (option::t<json>, str) {
     }
 }
 
+fn from_str_null(s: str) -> (option::t<json>, str) {
+    if (str::starts_with(s, "null")) {
+        (some(null), str::slice(s, 4u, str::byte_len(s)))
+    } else {
+        (none, s)
+    }
+}
+
 fn from_str_helper(s: str) -> (option::t<json>, str) {
     let s = str::trim_left(s);
     if str::is_empty(s) { ret (none, s); }
@@ -243,6 +254,7 @@ fn from_str_helper(s: str) -> (option::t<json>, str) {
         '{' { from_str_dict(s) }
         '0' to '9' | '-' | '+' | '.' { from_str_float(s) }
         't' | 'f' { from_str_bool(s) }
+        'n' { from_str_null(s) }
         _ { ret (none, s); }
     }
 }
diff --git a/src/test/compile-fail/non-triv-cast-be.rs b/src/test/compile-fail/non-triv-cast-be.rs
deleted file mode 100644
index 458013a912c..00000000000
--- a/src/test/compile-fail/non-triv-cast-be.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// error-pattern: non-trivial cast of tail-call return value
-import core::mtypes::*;
-
-fn foo_float() -> m_float { ret 0.0 as m_float; }
-fn bar_float() -> bool { be foo_float() as bool; }
-
-fn foo_int() -> m_int { ret 0 as m_int; }
-fn bar_int() -> bool { be foo_int() as bool; }
-
-fn foo_uint() -> m_uint { ret 0u as m_uint; }
-fn bar_uint() -> bool { be foo_uint() as bool; }
-
-fn main() {
-    assert bar_float() == 0.0;
-    assert bar_int() == 0.0;
-    assert bar_uint() == 0.0;
-}
\ No newline at end of file
diff --git a/src/test/run-pass/triv-cast-be.rs b/src/test/run-pass/triv-cast-be.rs
deleted file mode 100644
index 0fbb1ad2830..00000000000
--- a/src/test/run-pass/triv-cast-be.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-import core::ctypes::*;
-
-import core::mtypes::m_float;
-import core::mtypes::m_int;
-import core::mtypes::m_uint;
-
-fn foo_float() -> m_float { ret 0.0 as m_float; }
-fn bar_float() -> float { be foo_float() as float; }
-
-fn foo_int() -> m_int { ret 0 as m_int; }
-fn bar_int() -> int { be foo_int() as int; }
-
-fn foo_uint() -> m_uint { ret 0u as m_uint; }
-fn bar_uint() -> uint { be foo_uint() as uint; }
-
-fn foo_long() -> long { ret 0 as long; }
-fn bar_long() -> int { be foo_long() as int; }
-
-fn foo_ulong() -> ulong { ret 0u as ulong; }
-fn bar_ulong() -> uint { be foo_uint() as uint; }
-
-fn main() {
-    assert bar_float() == 0.0;
-    assert bar_int() == 0;
-    assert bar_uint() == 0u;
-    assert bar_long() == 0;
-    assert bar_ulong() == 0u;
-}
\ No newline at end of file
diff --git a/src/test/run-pass/triv-cast-const.rs b/src/test/run-pass/triv-cast-const.rs
deleted file mode 100644
index 0880fc82c48..00000000000
--- a/src/test/run-pass/triv-cast-const.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-import core::mtypes::m_int;
-
-// This will be more interesting once there is support
-// for consts that refer to other consts, i.e. math_f64::consts::pi as m_float
-#[cfg(target_arch="x86")]
-const foo: m_int = 0i32 as m_int;
-
-#[cfg(target_arch="x86_64")]
-const foo: m_int = 0i64 as m_int;
-
-fn main() {
-    assert foo == 0 as m_int;
-}
\ No newline at end of file
diff --git a/src/test/stdtest/json.rs b/src/test/stdtest/json.rs
index db65b223ff7..41031b2e16a 100644
--- a/src/test/stdtest/json.rs
+++ b/src/test/stdtest/json.rs
@@ -6,6 +6,11 @@ import std::json::*;
 import option::{none, some};
 
 #[test]
+fn test_from_str_null() {
+    assert(from_str("null") == some(null));
+}
+
+#[test]
 fn test_from_str_num() {
     assert(from_str("3") == some(num(3f)));
     assert(from_str("3.1") == some(num(3.1f)));
@@ -31,6 +36,7 @@ fn test_from_str_bool() {
 fn test_from_str_list() {
     assert(from_str("[]") == some(list(@[])));
     assert(from_str("[true]") == some(list(@[boolean(true)])));
+    assert(from_str("[null]") == some(list(@[null])));
     assert(from_str("[3, 1]") == some(list(@[num(3f), num(1f)])));
     assert(from_str("[2, [4, 1]]") ==
         some(list(@[num(2f), list(@[num(4f), num(1f)])])));
@@ -44,6 +50,7 @@ fn test_from_str_list() {
 fn test_from_str_dict() {
     assert(from_str("{}") != none);
     assert(from_str("{\"a\": 3}") != none);
+    assert(from_str("{\"a\": null}") != none);
     assert(from_str("{\"a\": }") == none);
     assert(from_str("{\"a\" }") == none);
     assert(from_str("{\"a\"") == none);
diff --git a/src/test/stdtest/list.rs b/src/test/stdtest/list.rs
index da1643e9274..227e8ad299d 100644
--- a/src/test/stdtest/list.rs
+++ b/src/test/stdtest/list.rs
@@ -16,6 +16,12 @@ fn test_from_vec() {
 }
 
 #[test]
+fn test_from_vec_empty() {
+    let empty : list::list<int> = from_vec([]);
+    assert (empty == list::nil::<int>);
+}
+
+#[test]
 fn test_from_vec_mut() {
     let l = from_vec([mutable 0, 1, 2]);
     assert (head(l) == 0);
@@ -25,10 +31,11 @@ fn test_from_vec_mut() {
 
 #[test]
 fn test_foldl() {
-    let l = from_vec([0, 1, 2, 3, 4]);
     fn add(&&a: uint, &&b: int) -> uint { ret a + (b as uint); }
-    let rs = list::foldl(l, 0u, add);
-    assert (rs == 10u);
+    let l = from_vec([0, 1, 2, 3, 4]);
+    let empty = list::nil::<int>;
+    assert (list::foldl(l, 0u, add) == 10u);
+    assert (list::foldl(empty, 0u, add) == 0u);
 }
 
 #[test]
@@ -37,26 +44,25 @@ fn test_foldl2() {
         a - b
     }
     let l = from_vec([1, 2, 3, 4]);
-    let sum = list::foldl(l, 0, sub);
-    assert sum == -10;
+    assert (list::foldl(l, 0, sub) == -10);
 }
 
 #[test]
 fn test_find_success() {
-    let l = from_vec([0, 1, 2]);
     fn match(&&i: int) -> option::t<int> {
         ret if i == 2 { option::some(i) } else { option::none::<int> };
     }
-    let rs = list::find(l, match);
-    assert (rs == option::some(2));
+    let l = from_vec([0, 1, 2]);
+    assert (list::find(l, match) == option::some(2));
 }
 
 #[test]
 fn test_find_fail() {
-    let l = from_vec([0, 1, 2]);
     fn match(&&_i: int) -> option::t<int> { ret option::none::<int>; }
-    let rs = list::find(l, match);
-    assert (rs == option::none::<int>);
+    let l = from_vec([0, 1, 2]);
+    let empty = list::nil::<int>;
+    assert (list::find(l, match) == option::none::<int>);
+    assert (list::find(empty, match) == option::none::<int>);
 }
 
 #[test]
@@ -72,6 +78,8 @@ fn test_has() {
 #[test]
 fn test_len() {
     let l = from_vec([0, 1, 2]);
+    let empty = list::nil::<int>;
     assert (list::len(l) == 3u);
+    assert (list::len(empty) == 0u);
 }