about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-08-11 17:12:01 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-08-17 01:39:10 -0700
commit086a5ca7d25307325912cab2a67384867daa04c5 (patch)
tree758037316d3dfcc83fe79017e777dbef44c02072
parentcb9c1e0e702f4a1a5dfc909b15b74e8556013c06 (diff)
downloadrust-086a5ca7d25307325912cab2a67384867daa04c5.tar.gz
rust-086a5ca7d25307325912cab2a67384867daa04c5.zip
librustc: Allow trait bounds on structures and enumerations, and check
them during kind checking.

This implements RFC #11.

Closes #15759.
-rw-r--r--src/liblibc/lib.rs34
-rw-r--r--src/librustc/middle/const_eval.rs12
-rw-r--r--src/librustc/middle/kind.rs198
-rw-r--r--src/librustc/middle/ty.rs80
-rw-r--r--src/librustc/middle/typeck/astconv.rs1
-rw-r--r--src/librustc/middle/typeck/check/mod.rs39
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs50
-rw-r--r--src/librustc/middle/typeck/collect.rs5
-rw-r--r--src/test/auxiliary/trait_bounds_on_structs_and_enums_xc.rs22
-rw-r--r--src/test/compile-fail/deriving-span-Zero-struct.rs6
-rw-r--r--src/test/compile-fail/deriving-span-Zero-tuple-struct.rs4
-rw-r--r--src/test/compile-fail/issue-14915.rs1
-rw-r--r--src/test/compile-fail/map-types.rs2
-rw-r--r--src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs4
-rw-r--r--src/test/compile-fail/object-does-not-impl-trait.rs1
-rw-r--r--src/test/compile-fail/pinned-deep-copy.rs1
-rw-r--r--src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs27
-rw-r--r--src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs25
-rw-r--r--src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs36
-rw-r--r--src/test/compile-fail/trait-bounds-on-structs-and-enums.rs77
-rw-r--r--src/test/compile-fail/unique-pinned-nocopy.rs1
-rw-r--r--src/test/compile-fail/unique-vec-res.rs3
-rw-r--r--src/test/compile-fail/vtable-res-trait-param.rs1
-rw-r--r--src/test/compile-fail/where-clauses-unsatisfied.rs7
-rw-r--r--src/test/run-pass/const-expr-in-fixed-length-vec.rs2
-rw-r--r--src/test/run-pass/trait-bounds-on-structs-and-enums.rs26
26 files changed, 622 insertions, 43 deletions
diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs
index bf0a9f06df8..0051d9a89c2 100644
--- a/src/liblibc/lib.rs
+++ b/src/liblibc/lib.rs
@@ -1456,13 +1456,24 @@ pub mod types {
                     pub Data4: [BYTE, ..8],
                 }
 
+                // NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
+                // workaround).
+                #[cfg(stage0)]
                 pub struct WSAPROTOCOLCHAIN {
                     pub ChainLen: c_int,
                     pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN],
                 }
+                #[cfg(not(stage0))]
+                pub struct WSAPROTOCOLCHAIN {
+                    pub ChainLen: c_int,
+                    pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN as uint],
+                }
 
                 pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;
 
+                // NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
+                // workaround).
+                #[cfg(stage0)]
                 pub struct WSAPROTOCOL_INFO {
                     pub dwServiceFlags1: DWORD,
                     pub dwServiceFlags2: DWORD,
@@ -1485,6 +1496,29 @@ pub mod types {
                     pub dwProviderReserved: DWORD,
                     pub szProtocol: [u8, ..WSAPROTOCOL_LEN+1],
                 }
+                #[cfg(not(stage0))]
+                pub struct WSAPROTOCOL_INFO {
+                    pub dwServiceFlags1: DWORD,
+                    pub dwServiceFlags2: DWORD,
+                    pub dwServiceFlags3: DWORD,
+                    pub dwServiceFlags4: DWORD,
+                    pub dwProviderFlags: DWORD,
+                    pub ProviderId: GUID,
+                    pub dwCatalogEntryId: DWORD,
+                    pub ProtocolChain: WSAPROTOCOLCHAIN,
+                    pub iVersion: c_int,
+                    pub iAddressFamily: c_int,
+                    pub iMaxSockAddr: c_int,
+                    pub iMinSockAddr: c_int,
+                    pub iSocketType: c_int,
+                    pub iProtocol: c_int,
+                    pub iProtocolMaxOffset: c_int,
+                    pub iNetworkByteOrder: c_int,
+                    pub iSecurityScheme: c_int,
+                    pub dwMessageSize: DWORD,
+                    pub dwProviderReserved: DWORD,
+                    pub szProtocol: [u8, ..(WSAPROTOCOL_LEN as uint) + 1u],
+                }
 
                 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
 
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 0b149f5b92e..3c9fb1f7624 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -17,6 +17,7 @@ use middle::def;
 use middle::pat_util::def_to_path;
 use middle::ty;
 use middle::typeck::astconv;
+use middle::typeck::check;
 use util::nodemap::{DefIdMap};
 
 use syntax::ast::*;
@@ -274,6 +275,17 @@ impl<'a> ConstEvalVisitor<'a> {
 }
 
 impl<'a> Visitor<()> for ConstEvalVisitor<'a> {
+    fn visit_ty(&mut self, t: &Ty, _: ()) {
+        match t.node {
+            TyFixedLengthVec(_, expr) => {
+                check::check_const_in_type(self.tcx, &*expr, ty::mk_uint());
+            }
+            _ => {}
+        }
+
+        visit::walk_ty(self, t, ());
+    }
+
     fn visit_expr_post(&mut self, e: &Expr, _: ()) {
         self.classify(e);
     }
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index 17b2c69f453..dbd7d6a5d6a 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -12,20 +12,24 @@
 use middle::freevars::freevar_entry;
 use middle::freevars;
 use middle::subst;
+use middle::ty::ParameterEnvironment;
 use middle::ty;
-use middle::ty_fold;
 use middle::ty_fold::TypeFoldable;
-use middle::typeck;
+use middle::ty_fold;
+use middle::typeck::check::vtable;
 use middle::typeck::{MethodCall, NoAdjustment};
+use middle::typeck;
 use util::ppaux::{Repr, ty_to_string};
 use util::ppaux::UserString;
 
+use std::collections::HashSet;
 use syntax::ast::*;
+use syntax::ast_util;
 use syntax::attr;
 use syntax::codemap::Span;
 use syntax::print::pprust::{expr_to_string, ident_to_string};
-use syntax::{visit};
 use syntax::visit::Visitor;
+use syntax::visit;
 
 // Kind analysis pass.
 //
@@ -47,13 +51,13 @@ use syntax::visit::Visitor;
 // primitives in the stdlib are explicitly annotated to only take sendable
 // types.
 
-#[deriving(Clone)]
 pub struct Context<'a> {
     tcx: &'a ty::ctxt,
+    struct_and_enum_bounds_checked: HashSet<ty::t>,
+    parameter_environments: Vec<ParameterEnvironment>,
 }
 
 impl<'a> Visitor<()> for Context<'a> {
-
     fn visit_expr(&mut self, ex: &Expr, _: ()) {
         check_expr(self, ex);
     }
@@ -74,12 +78,18 @@ impl<'a> Visitor<()> for Context<'a> {
     fn visit_pat(&mut self, p: &Pat, _: ()) {
         check_pat(self, p);
     }
+
+    fn visit_local(&mut self, l: &Local, _: ()) {
+        check_local(self, l);
+    }
 }
 
 pub fn check_crate(tcx: &ty::ctxt,
                    krate: &Crate) {
     let mut ctx = Context {
         tcx: tcx,
+        struct_and_enum_bounds_checked: HashSet::new(),
+        parameter_environments: Vec::new(),
     };
     visit::walk_crate(&mut ctx, krate, ());
     tcx.sess.abort_if_errors();
@@ -165,12 +175,90 @@ fn check_item(cx: &mut Context, item: &Item) {
         match item.node {
             ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
                 check_impl_of_trait(cx, item, trait_ref, &**self_type);
+
+                let parameter_environment =
+                    ParameterEnvironment::for_item(cx.tcx, item.id);
+                cx.parameter_environments.push(parameter_environment);
+
+                // Check bounds on the `self` type.
+                check_bounds_on_structs_or_enums_in_type_if_possible(
+                    cx,
+                    item.span,
+                    ty::node_id_to_type(cx.tcx, item.id));
+
+                // Check bounds on the trait ref.
+                match ty::impl_trait_ref(cx.tcx,
+                                         ast_util::local_def(item.id)) {
+                    None => {}
+                    Some(trait_ref) => {
+                        check_bounds_on_structs_or_enums_in_trait_ref(
+                            cx,
+                            item.span,
+                            &*trait_ref);
+                    }
+                }
+
+                drop(cx.parameter_environments.pop());
+            }
+            ItemEnum(..) => {
+                let parameter_environment =
+                    ParameterEnvironment::for_item(cx.tcx, item.id);
+                cx.parameter_environments.push(parameter_environment);
+
+                let def_id = ast_util::local_def(item.id);
+                for variant in ty::enum_variants(cx.tcx, def_id).iter() {
+                    for arg in variant.args.iter() {
+                        check_bounds_on_structs_or_enums_in_type_if_possible(
+                            cx,
+                            item.span,
+                            *arg)
+                    }
+                }
+
+                drop(cx.parameter_environments.pop());
+            }
+            ItemStruct(..) => {
+                let parameter_environment =
+                    ParameterEnvironment::for_item(cx.tcx, item.id);
+                cx.parameter_environments.push(parameter_environment);
+
+                let def_id = ast_util::local_def(item.id);
+                for field in ty::lookup_struct_fields(cx.tcx, def_id).iter() {
+                    check_bounds_on_structs_or_enums_in_type_if_possible(
+                        cx,
+                        item.span,
+                        ty::node_id_to_type(cx.tcx, field.id.node))
+                }
+
+                drop(cx.parameter_environments.pop());
+
+            }
+            ItemStatic(..) => {
+                let parameter_environment =
+                    ParameterEnvironment::for_item(cx.tcx, item.id);
+                cx.parameter_environments.push(parameter_environment);
+
+                check_bounds_on_structs_or_enums_in_type_if_possible(
+                    cx,
+                    item.span,
+                    ty::node_id_to_type(cx.tcx, item.id));
+
+                drop(cx.parameter_environments.pop());
             }
             _ => {}
         }
     }
 
-    visit::walk_item(cx, item, ());
+    visit::walk_item(cx, item, ())
+}
+
+fn check_local(cx: &mut Context, local: &Local) {
+    check_bounds_on_structs_or_enums_in_type_if_possible(
+        cx,
+        local.span,
+        ty::node_id_to_type(cx.tcx, local.id));
+
+    visit::walk_local(cx, local, ())
 }
 
 // Yields the appropriate function to check the kind of closed over
@@ -254,7 +342,25 @@ fn check_fn(
         });
     });
 
-    visit::walk_fn(cx, fk, decl, body, sp, ());
+    match *fk {
+        visit::FkFnBlock(..) => {
+            let ty = ty::node_id_to_type(cx.tcx, fn_id);
+            check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);
+
+            visit::walk_fn(cx, fk, decl, body, sp, ())
+        }
+        visit::FkItemFn(..) | visit::FkMethod(..) => {
+            let parameter_environment = ParameterEnvironment::for_item(cx.tcx,
+                                                                       fn_id);
+            cx.parameter_environments.push(parameter_environment);
+
+            let ty = ty::node_id_to_type(cx.tcx, fn_id);
+            check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);
+
+            visit::walk_fn(cx, fk, decl, body, sp, ());
+            drop(cx.parameter_environments.pop());
+        }
+    }
 }
 
 pub fn check_expr(cx: &mut Context, e: &Expr) {
@@ -263,6 +369,13 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
     // Handle any kind bounds on type parameters
     check_bounds_on_type_parameters(cx, e);
 
+    // Check bounds on structures or enumerations in the type of the
+    // expression.
+    let expression_type = ty::expr_ty(cx.tcx, e);
+    check_bounds_on_structs_or_enums_in_type_if_possible(cx,
+                                                         e.span,
+                                                         expression_type);
+
     match e.node {
         ExprBox(ref loc, ref interior) => {
             let def = ty::resolve_expr(cx.tcx, &**loc);
@@ -483,6 +596,7 @@ fn check_ty(cx: &mut Context, aty: &Ty) {
         }
         _ => {}
     }
+
     visit::walk_ty(cx, aty, ());
 }
 
@@ -519,6 +633,76 @@ pub fn check_typaram_bounds(cx: &Context,
     });
 }
 
+fn check_bounds_on_structs_or_enums_in_type_if_possible(cx: &mut Context,
+                                                        span: Span,
+                                                        ty: ty::t) {
+    // If we aren't in a function, structure, or enumeration context, we don't
+    // have enough information to ensure that bounds on structures or
+    // enumerations are satisfied. So we don't perform the check.
+    if cx.parameter_environments.len() == 0 {
+        return
+    }
+
+    // If we've already checked for this type, don't do it again. This
+    // massively speeds up kind checking.
+    if cx.struct_and_enum_bounds_checked.contains(&ty) {
+        return
+    }
+    cx.struct_and_enum_bounds_checked.insert(ty);
+
+    ty::walk_ty(ty, |ty| {
+        match ty::get(ty).sty {
+            ty::ty_struct(type_id, ref substs) |
+            ty::ty_enum(type_id, ref substs) => {
+                let polytype = ty::lookup_item_type(cx.tcx, type_id);
+
+                // Check builtin bounds.
+                for (ty, type_param_def) in substs.types
+                                                  .iter()
+                                                  .zip(polytype.generics
+                                                               .types
+                                                               .iter()) {
+                    check_typaram_bounds(cx, span, *ty, type_param_def)
+                }
+
+                // Check trait bounds.
+                let parameter_environment =
+                    cx.parameter_environments.get(cx.parameter_environments
+                                                    .len() - 1);
+                debug!(
+                    "check_bounds_on_structs_or_enums_in_type_if_possible(): \
+                     checking {}",
+                    ty.repr(cx.tcx));
+                vtable::check_param_bounds(cx.tcx,
+                                           span,
+                                           parameter_environment,
+                                           &polytype.generics.types,
+                                           substs,
+                                           |missing| {
+                    cx.tcx
+                      .sess
+                      .span_err(span,
+                                format!("instantiating a type parameter with \
+                                         an incompatible type `{}`, which \
+                                         does not fulfill `{}`",
+                                        ty_to_string(cx.tcx, ty),
+                                        missing.user_string(
+                                            cx.tcx)).as_slice());
+                })
+            }
+            _ => {}
+        }
+    });
+}
+
+fn check_bounds_on_structs_or_enums_in_trait_ref(cx: &mut Context,
+                                                 span: Span,
+                                                 trait_ref: &ty::TraitRef) {
+    for ty in trait_ref.substs.types.iter() {
+        check_bounds_on_structs_or_enums_in_type_if_possible(cx, span, *ty)
+    }
+}
+
 pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
                             bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
 {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 3a2c4857aad..ce3256650fd 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -55,7 +55,7 @@ use syntax::ast::{CrateNum, DefId, FnStyle, 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::{is_local, lit_is_str};
+use syntax::ast_util::{PostExpansionMethod, is_local, lit_is_str};
 use syntax::ast_util;
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
@@ -1083,6 +1083,84 @@ pub struct ParameterEnvironment {
     pub bounds: VecPerParamSpace<ParamBounds>,
 }
 
+impl ParameterEnvironment {
+    pub fn for_item(cx: &ctxt, id: NodeId) -> ParameterEnvironment {
+        match cx.map.find(id) {
+            Some(ast_map::NodeImplItem(ref impl_item)) => {
+                match **impl_item {
+                    ast::MethodImplItem(ref method) => {
+                        let method_def_id = ast_util::local_def(id);
+                        match ty::impl_or_trait_item(cx, method_def_id) {
+                            MethodTraitItem(ref method_ty) => {
+                                let method_generics = &method_ty.generics;
+                                construct_parameter_environment(
+                                    cx,
+                                    method_generics,
+                                    method.pe_body().id)
+                            }
+                        }
+                    }
+                }
+            }
+            Some(ast_map::NodeTraitItem(trait_method)) => {
+                match *trait_method {
+                    ast::RequiredMethod(ref required) => {
+                        cx.sess.span_bug(required.span,
+                                         "ParameterEnvironment::from_item():
+                                          can't create a parameter \
+                                          environment for required trait \
+                                          methods")
+                    }
+                    ast::ProvidedMethod(ref method) => {
+                        let method_def_id = ast_util::local_def(id);
+                        match ty::impl_or_trait_item(cx, method_def_id) {
+                            MethodTraitItem(ref method_ty) => {
+                                let method_generics = &method_ty.generics;
+                                construct_parameter_environment(
+                                    cx,
+                                    method_generics,
+                                    method.pe_body().id)
+                            }
+                        }
+                    }
+                }
+            }
+            Some(ast_map::NodeItem(item)) => {
+                match item.node {
+                    ast::ItemFn(_, _, _, _, ref body) => {
+                        // We assume this is a function.
+                        let fn_def_id = ast_util::local_def(id);
+                        let fn_pty = ty::lookup_item_type(cx, fn_def_id);
+
+                        construct_parameter_environment(cx,
+                                                        &fn_pty.generics,
+                                                        body.id)
+                    }
+                    ast::ItemEnum(..) |
+                    ast::ItemStruct(..) |
+                    ast::ItemImpl(..) |
+                    ast::ItemStatic(..) => {
+                        let def_id = ast_util::local_def(id);
+                        let pty = ty::lookup_item_type(cx, def_id);
+                        construct_parameter_environment(cx, &pty.generics, id)
+                    }
+                    _ => {
+                        cx.sess.span_bug(item.span,
+                                         "ParameterEnvironment::from_item():
+                                          can't create a parameter \
+                                          environment for this kind of item")
+                    }
+                }
+            }
+            _ => {
+                cx.sess.bug(format!("ParameterEnvironment::from_item(): \
+                                     `{}` is not an item",
+                                    cx.map.node_to_string(id)).as_slice())
+            }
+        }
+    }
+}
+
 /// A polytype.
 ///
 /// - `generics`: the set of type parameters and their bounds
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index c317f98a25a..24aee72e00e 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -879,7 +879,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
                 }
             }
             ast::TyFixedLengthVec(ty, e) => {
-                typeck::write_ty_to_tcx(tcx, e.id, ty::mk_uint());
                 match const_eval::eval_const_expr_partial(tcx, &*e) {
                     Ok(ref r) => {
                         match *r {
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 3403a51610c..7896316a472 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -86,7 +86,7 @@ use middle::subst;
 use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace};
 use middle::ty::{FnSig, VariantInfo};
 use middle::ty::{Polytype};
-use middle::ty::{ParamTy, Disr, ExprTyProvider};
+use middle::ty::{Disr, ExprTyProvider, ParamTy, ParameterEnvironment};
 use middle::ty;
 use middle::ty_fold::TypeFolder;
 use middle::typeck::astconv::AstConv;
@@ -281,7 +281,8 @@ impl<'a> Inherited<'a> {
 }
 
 // Used by check_const and check_enum_variants
-fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
+pub fn blank_fn_ctxt<'a>(
+                     ccx: &'a CrateCtxt<'a>,
                      inh: &'a Inherited<'a>,
                      rty: ty::t,
                      region_bnd: ast::NodeId)
@@ -673,11 +674,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
       }
       ast::ItemFn(ref decl, _, _, _, ref body) => {
         let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
-
-        let param_env = ty::construct_parameter_environment(ccx.tcx,
-                                                            &fn_pty.generics,
-                                                            body.id);
-
+        let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
         check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env);
       }
       ast::ItemImpl(_, ref opt_trait_ref, _, ref impl_items) => {
@@ -773,15 +770,7 @@ fn check_method_body(ccx: &CrateCtxt,
     debug!("check_method_body(item_generics={}, method.id={})",
             item_generics.repr(ccx.tcx),
             method.id);
-    let method_def_id = local_def(method.id);
-    let method_ty = match ty::impl_or_trait_item(ccx.tcx, method_def_id) {
-        ty::MethodTraitItem(ref method_ty) => (*method_ty).clone(),
-    };
-    let method_generics = &method_ty.generics;
-
-    let param_env = ty::construct_parameter_environment(ccx.tcx,
-                                                        method_generics,
-                                                        method.pe_body().id);
+    let param_env = ParameterEnvironment::for_item(ccx.tcx, method.id);
 
     let fty = ty::node_id_to_type(ccx.tcx, method.id);
 
@@ -3971,6 +3960,24 @@ fn check_block_with_expected(fcx: &FnCtxt,
     *fcx.ps.borrow_mut() = prev;
 }
 
+/// Checks a constant appearing in a type. At the moment this is just the
+/// length expression in a fixed-length vector, but someday it might be
+/// extended to type-level numeric literals.
+pub fn check_const_in_type(tcx: &ty::ctxt,
+                           expr: &ast::Expr,
+                           expected_type: ty::t) {
+    // Synthesize a crate context. The trait map is not needed here (though I
+    // imagine it will be if we have associated statics --pcwalton), so we
+    // leave it blank.
+    let ccx = CrateCtxt {
+        trait_map: NodeMap::new(),
+        tcx: tcx,
+    };
+    let inh = blank_inherited_fields(&ccx);
+    let fcx = blank_fn_ctxt(&ccx, &inh, expected_type, expr.id);
+    check_const_with_ty(&fcx, expr.span, expr, expected_type);
+}
+
 pub fn check_const(ccx: &CrateCtxt,
                    sp: Span,
                    e: &ast::Expr,
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 850d5c5a8f0..1aa469b15ba 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -66,8 +66,8 @@ use syntax::visit::Visitor;
 // It may be better to do something more clever, like processing fully
 // resolved types first.
 
-/// A vtable context includes an inference context, a crate context, and a
-/// callback function to call in case of type error.
+/// A vtable context includes an inference context, a parameter environment,
+/// and a list of unboxed closure types.
 pub struct VtableContext<'a> {
     pub infcx: &'a infer::InferCtxt<'a>,
     pub param_env: &'a ty::ParameterEnvironment,
@@ -83,8 +83,7 @@ fn lookup_vtables(vcx: &VtableContext,
                   type_param_defs: &VecPerParamSpace<ty::TypeParameterDef>,
                   substs: &subst::Substs,
                   is_early: bool)
-                  -> VecPerParamSpace<vtable_param_res>
-{
+                  -> VecPerParamSpace<vtable_param_res> {
     debug!("lookup_vtables(\
            type_param_defs={}, \
            substs={}",
@@ -154,11 +153,12 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
         match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) {
             Some(vtable) => param_result.push(vtable),
             None => {
-                vcx.tcx().sess.span_fatal(span,
+                vcx.tcx().sess.span_err(span,
                     format!("failed to find an implementation of \
                           trait {} for {}",
                          vcx.infcx.trait_ref_to_string(&*trait_ref),
                          vcx.infcx.ty_to_string(ty)).as_slice());
+                param_result.push(vtable_error)
             }
         }
         true
@@ -583,10 +583,11 @@ fn fixup_ty(vcx: &VtableContext,
     match resolve_type(vcx.infcx, Some(span), ty, resolve_and_force_all_but_regions) {
         Ok(new_type) => Some(new_type),
         Err(e) if !is_early => {
-            tcx.sess.span_fatal(span,
+            tcx.sess.span_err(span,
                 format!("cannot determine a type for this bounded type \
                          parameter: {}",
-                        fixup_err_to_string(e)).as_slice())
+                        fixup_err_to_string(e)).as_slice());
+            Some(ty::mk_err())
         }
         Err(_) => {
             None
@@ -974,3 +975,38 @@ impl<'a, 'b> visit::Visitor<()> for &'a FnCtxt<'b> {
 pub fn resolve_in_block(mut fcx: &FnCtxt, bl: &ast::Block) {
     visit::walk_block(&mut fcx, bl, ());
 }
+
+/// Used in the kind checker after typechecking has finished. Calls
+/// `any_missing` if any bounds were missing.
+pub fn check_param_bounds(tcx: &ty::ctxt,
+                          span: Span,
+                          parameter_environment: &ty::ParameterEnvironment,
+                          type_param_defs:
+                            &VecPerParamSpace<ty::TypeParameterDef>,
+                          substs: &subst::Substs,
+                          any_missing: |&ty::TraitRef|) {
+    let unboxed_closures = RefCell::new(DefIdMap::new());
+    let vcx = VtableContext {
+        infcx: &infer::new_infer_ctxt(tcx),
+        param_env: parameter_environment,
+        unboxed_closures: &unboxed_closures,
+    };
+    let vtable_param_results =
+        lookup_vtables(&vcx, span, type_param_defs, substs, false);
+    for (vtable_param_result, type_param_def) in
+            vtable_param_results.iter().zip(type_param_defs.iter()) {
+        for (vtable_result, trait_ref) in
+                vtable_param_result.iter()
+                                   .zip(type_param_def.bounds
+                                                      .trait_bounds
+                                                      .iter()) {
+            match *vtable_result {
+                vtable_error => any_missing(&**trait_ref),
+                vtable_static(..) |
+                vtable_param(..) |
+                vtable_unboxed_closure(..) => {}
+            }
+        }
+    }
+}
+
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 0c5d58ae930..5c3317972cd 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -462,7 +462,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
         // These don't define types.
         ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {}
         ast::ItemEnum(ref enum_definition, ref generics) => {
-            ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration");
             let pty = ty_of_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, pty.ty);
             get_enum_variant_types(ccx,
@@ -559,9 +558,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
             // static trait methods. This is somewhat unfortunate.
             ensure_trait_methods(ccx, it.id, &*trait_def);
         },
-        ast::ItemStruct(struct_def, ref generics) => {
-            ensure_no_ty_param_bounds(ccx, it.span, generics, "structure");
-
+        ast::ItemStruct(struct_def, _) => {
             // Write the class type.
             let pty = ty_of_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, pty.ty);
diff --git a/src/test/auxiliary/trait_bounds_on_structs_and_enums_xc.rs b/src/test/auxiliary/trait_bounds_on_structs_and_enums_xc.rs
new file mode 100644
index 00000000000..1695e474de9
--- /dev/null
+++ b/src/test/auxiliary/trait_bounds_on_structs_and_enums_xc.rs
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Trait {}
+
+pub struct Foo<T:Trait> {
+    pub x: T,
+}
+
+pub enum Bar<T:Trait> {
+    ABar(int),
+    BBar(T),
+    CBar(uint),
+}
+
diff --git a/src/test/compile-fail/deriving-span-Zero-struct.rs b/src/test/compile-fail/deriving-span-Zero-struct.rs
index ee3a82f7f6d..fec1b3ed492 100644
--- a/src/test/compile-fail/deriving-span-Zero-struct.rs
+++ b/src/test/compile-fail/deriving-span-Zero-struct.rs
@@ -16,9 +16,11 @@ extern crate rand;
 
 struct Error;
 
-#[deriving(Zero)]
+#[deriving(Zero)]   //~ ERROR failed to find an implementation
 struct Struct {
-    x: Error //~ ERROR
+    x: Error //~ ERROR failed to find an implementation
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR type `Error` does not implement any method in scope
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs b/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs
index 21dc0cabdc8..0661e5ee8b2 100644
--- a/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs
+++ b/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs
@@ -16,9 +16,11 @@ extern crate rand;
 
 struct Error;
 
-#[deriving(Zero)]
+#[deriving(Zero)]   //~ ERROR failed to find an implementation
 struct Struct(
     Error //~ ERROR
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR type `Error` does not implement any method in scope
 );
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-14915.rs b/src/test/compile-fail/issue-14915.rs
index e24830907d3..3754d669be6 100644
--- a/src/test/compile-fail/issue-14915.rs
+++ b/src/test/compile-fail/issue-14915.rs
@@ -18,4 +18,5 @@ fn main() {
     //~^ ERROR cannot determine a type for this bounded type parameter: unconstrained type
     println!("{}", y + 1);
     //~^ ERROR binary operation `+` cannot be applied to type `Gc<int>`
+    //~^^ ERROR cannot determine a type for this bounded type parameter: unconstrained type
 }
diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs
index bb5f020e78c..9a974e595d3 100644
--- a/src/test/compile-fail/map-types.rs
+++ b/src/test/compile-fail/map-types.rs
@@ -19,5 +19,5 @@ fn main() {
     let x: Box<Map<int, int>> = x;
     let y: Box<Map<uint, int>> = box x;
     //~^ ERROR failed to find an implementation of trait collections::Map<uint,int>
-    //         for ~collections::Map<int,int>:Send
+    //~^^ ERROR failed to find an implementation of trait core::collections::Collection
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
index 2a9a0358cc6..3ecff26f628 100644
--- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
+++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-test
+//
+// Ignored because of an ICE at the moment.
+
 // Check that non-constant exprs do fail as count in fixed length vec type
 
 fn main() {
diff --git a/src/test/compile-fail/object-does-not-impl-trait.rs b/src/test/compile-fail/object-does-not-impl-trait.rs
index 17083933afa..0cbdb87d56c 100644
--- a/src/test/compile-fail/object-does-not-impl-trait.rs
+++ b/src/test/compile-fail/object-does-not-impl-trait.rs
@@ -15,4 +15,5 @@
 trait Foo {}
 fn take_foo<F:Foo>(f: F) {}
 fn take_object(f: Box<Foo>) { take_foo(f); } //~ ERROR failed to find an implementation of trait
+//~^ ERROR failed to find an implementation
 fn main() {}
diff --git a/src/test/compile-fail/pinned-deep-copy.rs b/src/test/compile-fail/pinned-deep-copy.rs
index 0e3d6cd8168..e62f5fe1a4d 100644
--- a/src/test/compile-fail/pinned-deep-copy.rs
+++ b/src/test/compile-fail/pinned-deep-copy.rs
@@ -44,6 +44,7 @@ fn main() {
         // Can't do this copy
         let x = box box box A {y: r(i)};
         let _z = x.clone(); //~ ERROR failed to find an implementation
+        //~^ ERROR failed to find an implementation
         println!("{:?}", x);
     }
     println!("{:?}", *i);
diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs
new file mode 100644
index 00000000000..226556dc78f
--- /dev/null
+++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs
@@ -0,0 +1,27 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Trait {}
+
+struct Foo<T:Trait> {
+    x: T,
+}
+
+fn main() {
+    let foo = Foo {
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR instantiating a type parameter with an incompatible type
+        x: 3i
+    };
+    let baz: Foo<uint> = fail!();
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR instantiating a type parameter with an incompatible type
+}
+
diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs
new file mode 100644
index 00000000000..142ead75bcf
--- /dev/null
+++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Trait {}
+
+struct Foo<T:Trait> {
+    x: T,
+}
+
+static X: Foo<uint> = Foo {
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+    x: 1,
+};
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs
new file mode 100644
index 00000000000..9be519960b8
--- /dev/null
+++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs
@@ -0,0 +1,36 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:trait_bounds_on_structs_and_enums_xc.rs
+
+extern crate trait_bounds_on_structs_and_enums_xc;
+
+use trait_bounds_on_structs_and_enums_xc::{Bar, Foo, Trait};
+
+fn explode(x: Foo<uint>) {}
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+
+fn kaboom(y: Bar<f32>) {}
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+
+fn main() {
+    let foo = Foo {
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR instantiating a type parameter with an incompatible type
+        x: 3i
+    };
+    let bar: Bar<f64> = return;
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR instantiating a type parameter with an incompatible type
+    let _ = bar;
+}
+
diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs
new file mode 100644
index 00000000000..537656d1479
--- /dev/null
+++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs
@@ -0,0 +1,77 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Trait {}
+
+struct Foo<T:Trait> {
+    x: T,
+}
+
+enum Bar<T:Trait> {
+    ABar(int),
+    BBar(T),
+    CBar(uint),
+}
+
+fn explode(x: Foo<uint>) {}
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+
+fn kaboom(y: Bar<f32>) {}
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+
+impl<T> Foo<T> {
+    fn uhoh() {}
+}
+
+struct Baz {
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+    a: Foo<int>,
+}
+
+enum Boo {
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+    Quux(Bar<uint>),
+}
+
+struct Badness<T> {
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+    b: Foo<T>,
+}
+
+enum MoreBadness<T> {
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+    EvenMoreBadness(Bar<T>),
+}
+
+trait PolyTrait<T> {
+    fn whatever() {}
+}
+
+struct Struct;
+
+impl PolyTrait<Foo<uint>> for Struct {
+//~^ ERROR failed to find an implementation
+//~^^ ERROR instantiating a type parameter with an incompatible type
+    fn whatever() {}
+}
+
+fn main() {
+    let bar: Bar<f64> = return;
+    //~^ ERROR failed to find an implementation
+    //~^^ ERROR instantiating a type parameter with an incompatible type
+    let _ = bar;
+}
+
diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs
index 1b767e0270b..e5b7bf08715 100644
--- a/src/test/compile-fail/unique-pinned-nocopy.rs
+++ b/src/test/compile-fail/unique-pinned-nocopy.rs
@@ -21,5 +21,6 @@ impl Drop for r {
 fn main() {
     let i = box r { b: true };
     let _j = i.clone(); //~ ERROR failed to find an implementation
+    //~^ ERROR failed to find an implementation
     println!("{:?}", i);
 }
diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs
index 456437e2f39..dfb04323005 100644
--- a/src/test/compile-fail/unique-vec-res.rs
+++ b/src/test/compile-fail/unique-vec-res.rs
@@ -37,6 +37,9 @@ fn main() {
     let r2 = vec!(box r { i: i2 });
     f(r1.clone(), r2.clone());
     //~^ ERROR failed to find an implementation of
+    //~^^ ERROR failed to find an implementation of
+    //~^^^ ERROR failed to find an implementation of
+    //~^^^^ ERROR failed to find an implementation of
     println!("{:?}", (r2, i1.get()));
     println!("{:?}", (r1, i2.get()));
 }
diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs
index 5d0991024c4..2baa89d52f2 100644
--- a/src/test/compile-fail/vtable-res-trait-param.rs
+++ b/src/test/compile-fail/vtable-res-trait-param.rs
@@ -25,6 +25,7 @@ impl TraitB for int {
 fn call_it<B:TraitB>(b: B)  -> int {
     let y = 4u;
     b.gimme_an_a(y) //~ ERROR failed to find an implementation of trait TraitA
+    //~^ ERROR failed to find an implementation of trait TraitA
 }
 
 fn main() {
diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs
index 1d21313975f..2324da6b8f4 100644
--- a/src/test/compile-fail/where-clauses-unsatisfied.rs
+++ b/src/test/compile-fail/where-clauses-unsatisfied.rs
@@ -14,7 +14,10 @@ fn equal<T>(_: &T, _: &T) -> bool where T : Eq {
 struct Struct;
 
 fn main() {
-    equal(&Struct, &Struct)
-    //~^ ERROR failed to find an implementation of trait
+    drop(equal(&Struct, &Struct))
+    //~^ ERROR failed to find an implementation of trait core::cmp::Eq
+    //~^^ ERROR failed to find an implementation of trait core::cmp::PartialEq
+    //~^^^ ERROR failed to find an implementation of trait core::cmp::Eq
+    //~^^^^ ERROR failed to find an implementation of trait core::cmp::PartialEq
 }
 
diff --git a/src/test/run-pass/const-expr-in-fixed-length-vec.rs b/src/test/run-pass/const-expr-in-fixed-length-vec.rs
index 48b41d04633..0440a771e98 100644
--- a/src/test/run-pass/const-expr-in-fixed-length-vec.rs
+++ b/src/test/run-pass/const-expr-in-fixed-length-vec.rs
@@ -13,7 +13,7 @@
 
 pub fn main() {
 
-    static FOO: int = 2;
+    static FOO: uint = 2;
     let _v: [int, ..FOO*3];
 
 }
diff --git a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs
new file mode 100644
index 00000000000..ebcaf772db4
--- /dev/null
+++ b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait U {}
+trait T<X: U> {}
+
+trait S2<Y: U> {
+    fn m(x: Box<T<Y>>) {}
+}
+
+struct St<X: U> {
+    f: Box<T<X>>,
+}
+
+impl<X: U> St<X> {
+    fn blah() {}
+}
+
+fn main() {}