about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-18 09:26:10 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-12-30 09:32:42 -0500
commit4946e1a46317a890b3e8d0157e045adf80b535d3 (patch)
treeca0d88d978a05054d81c7be244e251ed4a3315ec
parent0b64e5796ba3f501042f02d416a7a625802e9e44 (diff)
downloadrust-4946e1a46317a890b3e8d0157e045adf80b535d3.tar.gz
rust-4946e1a46317a890b3e8d0157e045adf80b535d3.zip
Move the TypeContents-based "Sized" queries into trans, where the full
types are always known and hence the ParameterEnvironment is not
necessary. For other `Sized` queries, use the trait infrastructure
just like `Copy`.
-rw-r--r--src/librustc/middle/check_rvalues.rs14
-rw-r--r--src/librustc/middle/traits/mod.rs38
-rw-r--r--src/librustc/middle/ty.rs120
-rw-r--r--src/librustc_trans/trans/adt.rs8
-rw-r--r--src/librustc_trans/trans/base.rs10
-rw-r--r--src/librustc_trans/trans/common.rs56
-rw-r--r--src/librustc_trans/trans/consts.rs2
-rw-r--r--src/librustc_trans/trans/datum.rs4
-rw-r--r--src/librustc_trans/trans/expr.rs16
-rw-r--r--src/librustc_trans/trans/glue.rs26
-rw-r--r--src/librustc_trans/trans/intrinsic.rs4
-rw-r--r--src/librustc_trans/trans/type_of.rs10
-rw-r--r--src/librustc_typeck/check/mod.rs18
13 files changed, 207 insertions, 119 deletions
diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs
index 494d85f7ba5..3b4ea5234f4 100644
--- a/src/librustc/middle/check_rvalues.rs
+++ b/src/librustc/middle/check_rvalues.rs
@@ -28,7 +28,7 @@ pub fn check_crate(tcx: &ty::ctxt,
 }
 
 struct RvalueContext<'a, 'tcx: 'a> {
-    tcx: &'a ty::ctxt<'tcx>
+    tcx: &'a ty::ctxt<'tcx>,
 }
 
 impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
@@ -40,21 +40,27 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
                 fn_id: ast::NodeId) {
         {
             let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
-            let mut euv = euv::ExprUseVisitor::new(self, self.tcx, &param_env);
+            let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: &param_env };
+            let mut euv = euv::ExprUseVisitor::new(&mut delegate, self.tcx, &param_env);
             euv.walk_fn(fd, b);
         }
         visit::walk_fn(self, fk, fd, b, s)
     }
 }
 
-impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContext<'a, 'tcx> {
+struct RvalueContextDelegate<'a, 'tcx: 'a> {
+    tcx: &'a ty::ctxt<'tcx>,
+    param_env: &'a ty::ParameterEnvironment<'tcx>,
+}
+
+impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
     fn consume(&mut self,
                _: ast::NodeId,
                span: Span,
                cmt: mc::cmt<'tcx>,
                _: euv::ConsumeMode) {
         debug!("consume; cmt: {}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
-        if !ty::type_is_sized(self.tcx, cmt.ty) {
+        if !ty::type_is_sized(self.tcx, cmt.ty, self.param_env) {
             span_err!(self.tcx.sess, span, E0161,
                 "cannot move a value of type {0}: the size of {0} cannot be statically determined",
                 ty_to_string(self.tcx, cmt.ty));
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 6597730846d..5676ba6f665 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -22,6 +22,7 @@ use std::rc::Rc;
 use std::slice::Iter;
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
+use util::ppaux::Repr;
 
 pub use self::error_reporting::report_fulfillment_errors;
 pub use self::fulfill::{FulfillmentContext, RegionObligation};
@@ -265,6 +266,43 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
     util::predicates_for_generics(tcx, cause, 0, generic_bounds)
 }
 
+/// Determines whether the type `ty` is known to meet `bound` and
+/// returns true if so. Returns false if `ty` either does not meet
+/// `bound` or is not known to meet bound (note that this is
+/// conservative towards *no impl*, which is the opposite of the
+/// `evaluate` methods).
+pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+                                                 param_env: &ty::ParameterEnvironment<'tcx>,
+                                                 ty: Ty<'tcx>,
+                                                 bound: ty::BuiltinBound)
+                                                 -> bool
+{
+    debug!("type_known_to_meet_builtin_bound(ty={}, bound={})",
+           ty.repr(infcx.tcx),
+           bound);
+
+    let mut fulfill_cx = FulfillmentContext::new();
+
+    // We can use dummy values here because we won't report any errors
+    // that result nor will we pay any mind to region obligations that arise
+    // (there shouldn't really be any anyhow).
+    let cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
+
+    fulfill_cx.register_builtin_bound(infcx.tcx, ty, bound, cause);
+
+    // Note: we only assume something is `Copy` if we can
+    // *definitively* show that it implements `Copy`. Otherwise,
+    // assume it is move; linear is always ok.
+    let result = fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx).is_ok();
+
+    debug!("type_known_to_meet_builtin_bound: ty={} bound={} result={}",
+           ty.repr(infcx.tcx),
+           bound,
+           result);
+
+    result
+}
+
 impl<'tcx,O> Obligation<'tcx,O> {
     pub fn new(cause: ObligationCause<'tcx>,
                trait_ref: O)
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index d09efb006f2..731ad64799e 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -56,7 +56,6 @@ use middle::resolve_lifetime;
 use middle::infer;
 use middle::stability;
 use middle::subst::{mod, Subst, Substs, VecPerParamSpace};
-use middle::traits::ObligationCause;
 use middle::traits;
 use middle::ty;
 use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
@@ -65,7 +64,7 @@ use util::ppaux::{trait_store_to_string, ty_to_string};
 use util::ppaux::{Repr, UserString};
 use util::common::{indenter, memoized, ErrorReported};
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
-use util::nodemap::{FnvHashMap, FnvHashSet};
+use util::nodemap::{FnvHashMap};
 
 use arena::TypedArena;
 use std::borrow::BorrowFrom;
@@ -80,13 +79,13 @@ use collections::enum_set::{EnumSet, CLike};
 use std::collections::{HashMap, HashSet};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use syntax::abi;
-use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, Ident, ItemTrait, LOCAL_CRATE};
+use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
 use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
 use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField};
 use syntax::ast::{Visibility};
 use syntax::ast_util::{mod, is_local, lit_is_str, local_def, PostExpansionMethod};
 use syntax::attr::{mod, AttrMetaMethods};
-use syntax::codemap::{DUMMY_SP, Span};
+use syntax::codemap::Span;
 use syntax::parse::token::{mod, InternedString};
 use syntax::{ast, ast_map};
 
@@ -780,8 +779,15 @@ pub struct ctxt<'tcx> {
     /// Caches the representation hints for struct definitions.
     pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
 
-    /// Caches whether types move by default.
-    pub type_moves_by_default_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
+    /// Caches whether types are known to impl Copy. Note that type
+    /// parameters are never placed into this cache, because their
+    /// results are dependent on the parameter environment.
+    pub type_impls_copy_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
+
+    /// Caches whether types are known to impl Sized. Note that type
+    /// parameters are never placed into this cache, because their
+    /// results are dependent on the parameter environment.
+    pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
 }
 
 // Flags that we track on types. These flags are propagated upwards
@@ -2142,7 +2148,8 @@ pub fn mk_ctxt<'tcx>(s: Session,
         associated_types: RefCell::new(DefIdMap::new()),
         selection_cache: traits::SelectionCache::new(),
         repr_hint_cache: RefCell::new(DefIdMap::new()),
-        type_moves_by_default_cache: RefCell::new(HashMap::new()),
+        type_impls_copy_cache: RefCell::new(HashMap::new()),
+        type_impls_sized_cache: RefCell::new(HashMap::new()),
    }
 }
 
@@ -2791,14 +2798,6 @@ pub fn type_is_unique(ty: Ty) -> bool {
     }
 }
 
-pub fn type_is_fat_ptr<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    match ty.sty {
-        ty_ptr(mt{ty, ..}) | ty_rptr(_, mt{ty, ..})
-        | ty_uniq(ty) if !type_is_sized(cx, ty) => true,
-        _ => false,
-    }
-}
-
 /*
  A scalar type is one that denotes an atomic datum, with no sub-components.
  (A ty_ptr is scalar because it represents a non-managed pointer, so its
@@ -3289,17 +3288,22 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
     }
 }
 
-pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
-                                   ty: Ty<'tcx>,
-                                   param_env: &ParameterEnvironment<'tcx>)
-                                   -> bool
+fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
+                          cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
+                          param_env: &ParameterEnvironment<'tcx>,
+                          ty: Ty<'tcx>,
+                          bound: ty::BuiltinBound)
+                          -> bool
 {
+    assert!(!ty::type_needs_infer(ty));
+
     if !type_has_params(ty) && !type_has_self(ty) {
-        match cx.type_moves_by_default_cache.borrow().get(&ty) {
+        match cache.borrow().get(&ty) {
             None => {}
             Some(&result) => {
-                debug!("determined whether {} moves by default (cached): {}",
+                debug!("type_impls_bound({}, {}) = {} (cached)",
                        ty_to_string(cx, ty),
+                       bound,
                        result);
                 return result
             }
@@ -3307,27 +3311,35 @@ pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
     }
 
     let infcx = infer::new_infer_ctxt(cx);
-    let mut fulfill_cx = traits::FulfillmentContext::new();
+    let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound);
 
-    // we can use dummy values here because we won't report any errors
-    // that result nor will we pay any mind to region obligations that arise
-    // (there shouldn't really be any anyhow)
-    let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
+    debug!("type_impls_bound({}, {}) = {}",
+           ty_to_string(cx, ty),
+           bound,
+           is_impld);
 
-    fulfill_cx.register_builtin_bound(cx, ty, ty::BoundCopy, cause);
+    if !type_has_params(ty) && !type_has_self(ty) {
+        let old_value = cache.borrow_mut().insert(ty, is_impld);
+        assert!(old_value.is_none());
+    }
 
-    // Note: we only assuming something is `Copy` if we can
-    // *definitively* show that it implements `Copy`. Otherwise,
-    // assume it is move; linear is always ok.
-    let is_copy = fulfill_cx.select_all_or_error(&infcx, param_env, cx).is_ok();
-    let is_move = !is_copy;
+    is_impld
+}
 
-    debug!("determined whether {} moves by default: {}",
-           ty_to_string(cx, ty),
-           is_move);
+pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
+                                   ty: Ty<'tcx>,
+                                   param_env: &ParameterEnvironment<'tcx>)
+                                   -> bool
+{
+    !type_impls_bound(cx, &cx.type_impls_copy_cache, param_env, ty, ty::BoundCopy)
+}
 
-    cx.type_moves_by_default_cache.borrow_mut().insert(ty, is_move);
-    is_move
+pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>,
+                           ty: Ty<'tcx>,
+                           param_env: &ParameterEnvironment<'tcx>)
+                           -> bool
+{
+    type_impls_bound(cx, &cx.type_impls_sized_cache, param_env, ty, ty::BoundSized)
 }
 
 pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -3699,40 +3711,6 @@ pub fn type_is_machine(ty: Ty) -> bool {
     }
 }
 
-// Is the type's representation size known at compile time?
-pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    type_contents(cx, ty).is_sized(cx)
-}
-
-pub fn lltype_is_sized<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    match ty.sty {
-        ty_open(_) => true,
-        _ => type_contents(cx, ty).is_sized(cx)
-    }
-}
-
-// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
-// 'Smallest' here means component of the static representation of the type; not
-// the size of an object at runtime.
-pub fn unsized_part_of_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    match ty.sty {
-        ty_str | ty_trait(..) | ty_vec(..) => ty,
-        ty_struct(def_id, substs) => {
-            let unsized_fields: Vec<_> = struct_fields(cx, def_id, substs).iter()
-                .map(|f| f.mt.ty).filter(|ty| !type_is_sized(cx, *ty)).collect();
-            // Exactly one of the fields must be unsized.
-            assert!(unsized_fields.len() == 1);
-
-            unsized_part_of_type(cx, unsized_fields[0])
-        }
-        _ => {
-            assert!(type_is_sized(cx, ty),
-                    "unsized_part_of_type failed even though ty is unsized");
-            panic!("called unsized_part_of_type with sized ty");
-        }
-    }
-}
-
 // Whether a type is enum like, that is an enum type with only nullary
 // constructors
 pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool {
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index 595d252a0b1..717c2af2beb 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -343,7 +343,7 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
                                     mut path: DiscrField) -> Option<DiscrField> {
     match ty.sty {
         // Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait
-        ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) if !ty::type_is_sized(tcx, ty) => {
+        ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) if !type_is_sized(tcx, ty) => {
             path.push(FAT_PTR_ADDR);
             Some(path)
         },
@@ -447,12 +447,12 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                        tys: &[Ty<'tcx>], packed: bool,
                        scapegoat: Ty<'tcx>)
                        -> Struct<'tcx> {
-    let sized = tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty));
+    let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
     let lltys : Vec<Type> = if sized {
         tys.iter()
            .map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
     } else {
-        tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty))
+        tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
            .map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
     };
 
@@ -704,7 +704,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,
                              sizing: bool, dst: bool) -> Vec<Type> {
     if sizing {
-        st.fields.iter().filter(|&ty| !dst || ty::type_is_sized(cx.tcx(), *ty))
+        st.fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
             .map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
     } else {
         st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index f0d738d839d..397baac960d 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -581,7 +581,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
     match t.sty {
         ty::ty_tup(ref tys) if tys.is_empty() => f(nil_type),
         ty::ty_bool | ty::ty_uint(_) | ty::ty_char => f(unsigned_int),
-        ty::ty_ptr(mt) if ty::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
+        ty::ty_ptr(mt) if common::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
         ty::ty_int(_) => f(signed_int),
         ty::ty_float(_) => f(floating_point),
             // Should never get here, because t is scalar.
@@ -719,7 +719,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
         return cx;
     }
 
-    let (data_ptr, info) = if ty::type_is_sized(cx.tcx(), t) {
+    let (data_ptr, info) = if common::type_is_sized(cx.tcx(), t) {
         (av, None)
     } else {
         let data = GEPi(cx, av, &[0, abi::FAT_PTR_ADDR]);
@@ -736,7 +736,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                   let field_ty = field_ty.mt.ty;
                   let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i);
 
-                  let val = if ty::type_is_sized(cx.tcx(), field_ty) {
+                  let val = if common::type_is_sized(cx.tcx(), field_ty) {
                       llfld_a
                   } else {
                       let boxed_ty = ty::mk_open(cx.tcx(), field_ty);
@@ -2522,7 +2522,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
             match ret_ty.sty {
                 // `~` pointer return values never alias because ownership
                 // is transferred
-                ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {}
+                ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {}
                 ty::ty_uniq(_) => {
                     attrs.ret(llvm::NoAliasAttribute);
                 }
@@ -2533,7 +2533,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
             match ret_ty.sty {
                 // These are not really pointers but pairs, (pointer, len)
                 ty::ty_uniq(it) |
-                ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {}
+                ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {}
                 ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
                     let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
                     attrs.ret(llvm::DereferenceableAttribute(llret_sz));
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 7ee4be0ae56..f052a20bc89 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -58,6 +58,58 @@ use util::nodemap::FnvHashSet;
 
 pub use trans::context::CrateContext;
 
+// Is the type's representation size known at compile time?
+pub fn type_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty::type_contents(cx, ty).is_sized(cx)
+}
+
+pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.sty {
+        ty::ty_open(_) => true,
+        _ => type_is_sized(cx, ty),
+    }
+}
+
+pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.sty {
+        ty::ty_ptr(ty::mt{ty, ..}) |
+        ty::ty_rptr(_, ty::mt{ty, ..}) |
+        ty::ty_uniq(ty) => {
+            !type_is_sized(cx, ty)
+        }
+        _ => {
+            false
+        }
+    }
+}
+
+// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
+// 'Smallest' here means component of the static representation of the type; not
+// the size of an object at runtime.
+pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+    match ty.sty {
+        ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty,
+        ty::ty_struct(def_id, substs) => {
+            let unsized_fields: Vec<_> =
+                ty::struct_fields(cx, def_id, substs)
+                .iter()
+                .map(|f| f.mt.ty)
+                .filter(|ty| !type_is_sized(cx, *ty))
+                .collect();
+
+            // Exactly one of the fields must be unsized.
+            assert!(unsized_fields.len() == 1);
+
+            unsized_part_of_type(cx, unsized_fields[0])
+        }
+        _ => {
+            assert!(type_is_sized(cx, ty),
+                    "unsized_part_of_type failed even though ty is unsized");
+            panic!("called unsized_part_of_type with sized ty");
+        }
+    }
+}
+
 // Some things don't need cleanups during unwinding because the
 // task can free them all at once later. Currently only things
 // that only contain scalars and shared boxes can avoid unwind
@@ -128,10 +180,10 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
         ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
         type_is_newtype_immediate(ccx, ty) ||
         ty::type_is_simd(tcx, ty);
-    if simple && !ty::type_is_fat_ptr(tcx, ty) {
+    if simple && !type_is_fat_ptr(tcx, ty) {
         return true;
     }
-    if !ty::type_is_sized(tcx, ty) {
+    if !type_is_sized(tcx, ty) {
         return false;
     }
     match ty.sty {
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index bc386dc96a4..0fd6d286e8b 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -138,7 +138,7 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, v: ValueRef,
         Some(ref mt) => {
             match t.sty {
                 ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => {
-                    if ty::type_is_sized(cx.tcx(), mt.ty) {
+                    if type_is_sized(cx.tcx(), mt.ty) {
                         (const_deref_ptr(cx, v), mt.ty)
                     } else {
                         // Derefing a fat pointer does not change the representation,
diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs
index ca274ab605e..83bf06383a8 100644
--- a/src/librustc_trans/trans/datum.rs
+++ b/src/librustc_trans/trans/datum.rs
@@ -398,7 +398,7 @@ impl<'tcx> Datum<'tcx, Expr> {
                                  -> DatumBlock<'blk, 'tcx, Lvalue> {
         debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx()));
 
-        assert!(ty::lltype_is_sized(bcx.tcx(), self.ty),
+        assert!(lltype_is_sized(bcx.tcx(), self.ty),
                 "Trying to convert unsized value to lval");
         self.match_kind(
             |l| DatumBlock::new(bcx, l),
@@ -456,7 +456,7 @@ impl<'tcx> Datum<'tcx, Lvalue> {
         F: FnOnce(ValueRef) -> ValueRef,
     {
         let val = match self.ty.sty {
-            _ if ty::type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
+            _ if type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
             ty::ty_open(_) => {
                 let base = Load(bcx, expr::get_dataptr(bcx, self.val));
                 gep(base)
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index ae07e094a5c..fc2e6c7b7fd 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -280,7 +280,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                expr.repr(bcx.tcx()),
                datum.to_string(bcx.ccx()));
 
-        if !ty::type_is_sized(bcx.tcx(), datum.ty) {
+        if !type_is_sized(bcx.tcx(), datum.ty) {
             debug!("Taking address of unsized type {}",
                    bcx.ty_to_string(datum.ty));
             ref_fat_ptr(bcx, expr, datum)
@@ -693,7 +693,7 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
             field_tys[ix].mt.ty,
             |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
 
-        if ty::type_is_sized(bcx.tcx(), d.ty) {
+        if type_is_sized(bcx.tcx(), d.ty) {
             DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
         } else {
             let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), "");
@@ -773,7 +773,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                Some(SaveIn(scratch.val)),
                                                true));
             let datum = scratch.to_expr_datum();
-            if ty::type_is_sized(bcx.tcx(), elt_ty) {
+            if type_is_sized(bcx.tcx(), elt_ty) {
                 Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
             } else {
                 Datum::new(datum.val, ty::mk_open(bcx.tcx(), elt_ty), LvalueExpr)
@@ -1522,7 +1522,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 for &(i, t) in base.fields.iter() {
                     let datum = base_datum.get_element(
                             bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
-                    assert!(ty::type_is_sized(bcx.tcx(), datum.ty));
+                    assert!(type_is_sized(bcx.tcx(), datum.ty));
                     let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
                     bcx = datum.store_to(bcx, dest);
                 }
@@ -1650,7 +1650,7 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                -> DatumBlock<'blk, 'tcx, Expr> {
     let _icx = push_ctxt("trans_uniq_expr");
     let fcx = bcx.fcx;
-    assert!(ty::type_is_sized(bcx.tcx(), contents_ty));
+    assert!(type_is_sized(bcx.tcx(), contents_ty));
     let llty = type_of::type_of(bcx.ccx(), contents_ty);
     let size = llsize_of(bcx.ccx(), llty);
     let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
@@ -1985,7 +1985,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
         ty::ty_char        => cast_integral,
         ty::ty_float(..)   => cast_float,
         ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => {
-            if ty::type_is_sized(tcx, mt.ty) {
+            if type_is_sized(tcx, mt.ty) {
                 cast_pointer
             } else {
                 cast_other
@@ -2217,7 +2217,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let r = match datum.ty.sty {
         ty::ty_uniq(content_ty) => {
-            if ty::type_is_sized(bcx.tcx(), content_ty) {
+            if type_is_sized(bcx.tcx(), content_ty) {
                 deref_owned_pointer(bcx, expr, datum, content_ty)
             } else {
                 // A fat pointer and an opened DST value have the same
@@ -2236,7 +2236,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
         ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
-            if ty::type_is_sized(bcx.tcx(), content_ty) {
+            if type_is_sized(bcx.tcx(), content_ty) {
                 let ptr = datum.to_llscalarish(bcx);
 
                 // Always generate an lvalue datum, even if datum.mode is
diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs
index 4217dd4c671..31455920c10 100644
--- a/src/librustc_trans/trans/glue.rs
+++ b/src/librustc_trans/trans/glue.rs
@@ -63,7 +63,7 @@ pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
 
 pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
                                           content_ty: Ty<'tcx>) -> Block<'blk, 'tcx> {
-    assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty));
+    assert!(type_is_sized(bcx.ccx().tcx(), content_ty));
     let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
     let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
 
@@ -81,7 +81,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let tcx = ccx.tcx();
     // Even if there is no dtor for t, there might be one deeper down and we
     // might need to pass in the vtable ptr.
-    if !ty::type_is_sized(tcx, t) {
+    if !type_is_sized(tcx, t) {
         return t
     }
     if !type_needs_drop(tcx, t) {
@@ -89,7 +89,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
     match t.sty {
         ty::ty_uniq(typ) if !type_needs_drop(tcx, typ)
-                         && ty::type_is_sized(tcx, typ) => {
+                         && type_is_sized(tcx, typ) => {
             let llty = sizing_type_of(ccx, typ);
             // `Box<ZeroSizeType>` does not allocate.
             if llsize_of_alloc(ccx, llty) == 0 {
@@ -150,7 +150,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
         _ => { }
     }
 
-    let llty = if ty::type_is_sized(ccx.tcx(), t) {
+    let llty = if type_is_sized(ccx.tcx(), t) {
         type_of(ccx, t).ptr_to()
     } else {
         type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to()
@@ -193,7 +193,7 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                       substs: &subst::Substs<'tcx>)
                                       -> Block<'blk, 'tcx> {
     let repr = adt::represent_type(bcx.ccx(), t);
-    let struct_data = if ty::type_is_sized(bcx.tcx(), t) {
+    let struct_data = if type_is_sized(bcx.tcx(), t) {
         v0
     } else {
         let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
@@ -234,7 +234,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                     bcx.ty_to_string(fty))[])
     };
 
-    let (struct_data, info) = if ty::type_is_sized(bcx.tcx(), t) {
+    let (struct_data, info) = if type_is_sized(bcx.tcx(), t) {
         (v0, None)
     } else {
         let data = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
@@ -251,7 +251,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // Class dtors have no explicit args, so the params should
         // just consist of the environment (self).
         assert_eq!(params.len(), 1);
-        let self_arg = if ty::type_is_fat_ptr(bcx.tcx(), self_ty) {
+        let self_arg = if type_is_fat_ptr(bcx.tcx(), self_ty) {
             // The dtor expects a fat pointer, so make one, even if we have to fake it.
             let boxed_ty = ty::mk_open(bcx.tcx(), t);
             let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self");
@@ -275,7 +275,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         for (i, ty) in st.fields.iter().enumerate().rev() {
             let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
 
-            let val = if ty::type_is_sized(bcx.tcx(), *ty) {
+            let val = if type_is_sized(bcx.tcx(), *ty) {
                 llfld_a
             } else {
                 let boxed_ty = ty::mk_open(bcx.tcx(), *ty);
@@ -303,7 +303,7 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
                                      -> (ValueRef, ValueRef) {
     debug!("calculate size of DST: {}; with lost info: {}",
            bcx.ty_to_string(t), bcx.val_to_string(info));
-    if ty::type_is_sized(bcx.tcx(), t) {
+    if type_is_sized(bcx.tcx(), t) {
         let sizing_type = sizing_type_of(bcx.ccx(), t);
         let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
         let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t));
@@ -383,7 +383,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
                         bcx
                     })
                 }
-                ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), content_ty) => {
+                ty::ty_struct(..) if !type_is_sized(bcx.tcx(), content_ty) => {
                     let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
                     let llbox = Load(bcx, llval);
                     let not_null = IsNotNull(bcx, llbox);
@@ -396,7 +396,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
                     })
                 }
                 _ => {
-                    assert!(ty::type_is_sized(bcx.tcx(), content_ty));
+                    assert!(type_is_sized(bcx.tcx(), content_ty));
                     let llval = v0;
                     let llbox = Load(bcx, llval);
                     let not_null = IsNotNull(bcx, llbox);
@@ -415,7 +415,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
                     // find the drop flag (which is at the end of the struct).
                     // Lets just ignore the flag and pretend everything will be
                     // OK.
-                    if ty::type_is_sized(bcx.tcx(), t) {
+                    if type_is_sized(bcx.tcx(), t) {
                         trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
                     } else {
                         // Give the user a heads up that we are doing something
@@ -468,7 +468,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
         }
         ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
         _ => {
-            assert!(ty::type_is_sized(bcx.tcx(), t));
+            assert!(type_is_sized(bcx.tcx(), t));
             if type_needs_drop(bcx.tcx(), t) &&
                 ty::type_is_structural(t) {
                 iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index f471a92f6c3..6b0baa5d05e 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -120,8 +120,8 @@ pub fn check_intrinsics(ccx: &CrateContext) {
                             "s"
                         })[]);
         }
-        if ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.to) ||
-           ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.from) {
+        if type_is_fat_ptr(ccx.tcx(), transmute_restriction.to) ||
+           type_is_fat_ptr(ccx.tcx(), transmute_restriction.from) {
             ccx.sess()
                .add_lint(::lint::builtin::FAT_PTR_TRANSMUTES,
                          transmute_restriction.id,
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 499195b51b9..aaec82bb177 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -187,7 +187,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
     }
 
     let llsizingty = match t.sty {
-        _ if !ty::lltype_is_sized(cx.tcx(), t) => {
+        _ if !lltype_is_sized(cx.tcx(), t) => {
             cx.sess().bug(format!("trying to take the sizing type of {}, an unsized type",
                                   ppaux::ty_to_string(cx.tcx(), t))[])
         }
@@ -199,7 +199,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
         ty::ty_float(t) => Type::float_from_ty(cx, t),
 
         ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
-            if ty::type_is_sized(cx.tcx(), ty) {
+            if type_is_sized(cx.tcx(), ty) {
                 Type::i8p(cx)
             } else {
                 Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
@@ -267,11 +267,11 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
         // struct which might be unsized, but is monomorphised to a sized type.
         // In this case we'll fake a fat pointer with no unsize info (we use 0).
         // However, its still a fat pointer, so we need some type use.
-        if ty::type_is_sized(cx.tcx(), t) {
+        if type_is_sized(cx.tcx(), t) {
             return Type::i8p(cx);
         }
 
-        match ty::unsized_part_of_type(cx.tcx(), t).sty {
+        match unsized_part_of_type(cx.tcx(), t).sty {
             ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyU),
             ty::ty_trait(_) => Type::vtable_ptr(cx),
             _ => panic!("Unexpected type returned from unsized_part_of_type : {}",
@@ -342,7 +342,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
                   cx.tn().find_type("str_slice").unwrap()
               }
               ty::ty_trait(..) => Type::opaque_trait(cx),
-              _ if !ty::type_is_sized(cx.tcx(), ty) => {
+              _ if !type_is_sized(cx.tcx(), ty) => {
                   let p_ty = type_of(cx, ty).ptr_to();
                   Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, ty)], false)
               }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c8c8211f292..dfa41c2707e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1356,7 +1356,7 @@ fn check_cast(fcx: &FnCtxt,
         return
     }
 
-    if !ty::type_is_sized(fcx.tcx(), t_1) {
+    if !fcx.type_is_known_to_be_sized(t_1) {
         let tstr = fcx.infcx().ty_to_string(t_1);
         fcx.type_error_message(span, |actual| {
             format!("cast to unsized type: `{}` as `{}`", actual, tstr)
@@ -1545,10 +1545,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
 
-    pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a, 'tcx> {
+    pub fn infcx(&self) -> &infer::InferCtxt<'a, 'tcx> {
         &self.inh.infcx
     }
 
+    pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> {
+        &self.inh.param_env
+    }
+
     pub fn sess(&self) -> &Session {
         &self.tcx().sess
     }
@@ -1792,6 +1796,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
     }
 
+    pub fn type_is_known_to_be_sized(&self,
+                                     ty: Ty<'tcx>)
+                                     -> bool
+    {
+        traits::type_known_to_meet_builtin_bound(self.infcx(),
+                                                 self.param_env(),
+                                                 ty,
+                                                 ty::BoundSized)
+    }
+
     pub fn register_builtin_bound(&self,
                                   ty: Ty<'tcx>,
                                   builtin_bound: ty::BuiltinBound,