librustc: Allow trait bounds on structures and enumerations, and check
them during kind checking. This implements RFC #11. Closes #15759.
This commit is contained in:
parent
cb9c1e0e70
commit
086a5ca7d2
26 changed files with 622 additions and 43 deletions
|
@ -1456,13 +1456,24 @@ pub mod types {
|
||||||
pub Data4: [BYTE, ..8],
|
pub Data4: [BYTE, ..8],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
|
||||||
|
// workaround).
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct WSAPROTOCOLCHAIN {
|
pub struct WSAPROTOCOLCHAIN {
|
||||||
pub ChainLen: c_int,
|
pub ChainLen: c_int,
|
||||||
pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN],
|
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;
|
pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;
|
||||||
|
|
||||||
|
// NOTE(pcwalton, stage0): Remove after snapshot (typeck bug
|
||||||
|
// workaround).
|
||||||
|
#[cfg(stage0)]
|
||||||
pub struct WSAPROTOCOL_INFO {
|
pub struct WSAPROTOCOL_INFO {
|
||||||
pub dwServiceFlags1: DWORD,
|
pub dwServiceFlags1: DWORD,
|
||||||
pub dwServiceFlags2: DWORD,
|
pub dwServiceFlags2: DWORD,
|
||||||
|
@ -1485,6 +1496,29 @@ pub mod types {
|
||||||
pub dwProviderReserved: DWORD,
|
pub dwProviderReserved: DWORD,
|
||||||
pub szProtocol: [u8, ..WSAPROTOCOL_LEN+1],
|
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;
|
pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ use middle::def;
|
||||||
use middle::pat_util::def_to_path;
|
use middle::pat_util::def_to_path;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::astconv;
|
use middle::typeck::astconv;
|
||||||
|
use middle::typeck::check;
|
||||||
use util::nodemap::{DefIdMap};
|
use util::nodemap::{DefIdMap};
|
||||||
|
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
|
@ -274,6 +275,17 @@ impl<'a> ConstEvalVisitor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<()> for 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, _: ()) {
|
fn visit_expr_post(&mut self, e: &Expr, _: ()) {
|
||||||
self.classify(e);
|
self.classify(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,24 @@
|
||||||
use middle::freevars::freevar_entry;
|
use middle::freevars::freevar_entry;
|
||||||
use middle::freevars;
|
use middle::freevars;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
|
use middle::ty::ParameterEnvironment;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold;
|
|
||||||
use middle::ty_fold::TypeFoldable;
|
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::{MethodCall, NoAdjustment};
|
||||||
|
use middle::typeck;
|
||||||
use util::ppaux::{Repr, ty_to_string};
|
use util::ppaux::{Repr, ty_to_string};
|
||||||
use util::ppaux::UserString;
|
use util::ppaux::UserString;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
|
use syntax::ast_util;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::print::pprust::{expr_to_string, ident_to_string};
|
use syntax::print::pprust::{expr_to_string, ident_to_string};
|
||||||
use syntax::{visit};
|
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
|
use syntax::visit;
|
||||||
|
|
||||||
// Kind analysis pass.
|
// Kind analysis pass.
|
||||||
//
|
//
|
||||||
|
@ -47,13 +51,13 @@ use syntax::visit::Visitor;
|
||||||
// primitives in the stdlib are explicitly annotated to only take sendable
|
// primitives in the stdlib are explicitly annotated to only take sendable
|
||||||
// types.
|
// types.
|
||||||
|
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
tcx: &'a ty::ctxt,
|
tcx: &'a ty::ctxt,
|
||||||
|
struct_and_enum_bounds_checked: HashSet<ty::t>,
|
||||||
|
parameter_environments: Vec<ParameterEnvironment>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<()> for Context<'a> {
|
impl<'a> Visitor<()> for Context<'a> {
|
||||||
|
|
||||||
fn visit_expr(&mut self, ex: &Expr, _: ()) {
|
fn visit_expr(&mut self, ex: &Expr, _: ()) {
|
||||||
check_expr(self, ex);
|
check_expr(self, ex);
|
||||||
}
|
}
|
||||||
|
@ -74,12 +78,18 @@ impl<'a> Visitor<()> for Context<'a> {
|
||||||
fn visit_pat(&mut self, p: &Pat, _: ()) {
|
fn visit_pat(&mut self, p: &Pat, _: ()) {
|
||||||
check_pat(self, p);
|
check_pat(self, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_local(&mut self, l: &Local, _: ()) {
|
||||||
|
check_local(self, l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate(tcx: &ty::ctxt,
|
pub fn check_crate(tcx: &ty::ctxt,
|
||||||
krate: &Crate) {
|
krate: &Crate) {
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
|
struct_and_enum_bounds_checked: HashSet::new(),
|
||||||
|
parameter_environments: Vec::new(),
|
||||||
};
|
};
|
||||||
visit::walk_crate(&mut ctx, krate, ());
|
visit::walk_crate(&mut ctx, krate, ());
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
|
@ -165,12 +175,90 @@ fn check_item(cx: &mut Context, item: &Item) {
|
||||||
match item.node {
|
match item.node {
|
||||||
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
|
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
|
||||||
check_impl_of_trait(cx, item, trait_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
|
// Yields the appropriate function to check the kind of closed over
|
||||||
|
@ -254,7 +342,25 @@ fn check_fn(
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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, ());
|
visit::walk_fn(cx, fk, decl, body, sp, ());
|
||||||
|
drop(cx.parameter_environments.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_expr(cx: &mut Context, e: &Expr) {
|
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
|
// Handle any kind bounds on type parameters
|
||||||
check_bounds_on_type_parameters(cx, e);
|
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 {
|
match e.node {
|
||||||
ExprBox(ref loc, ref interior) => {
|
ExprBox(ref loc, ref interior) => {
|
||||||
let def = ty::resolve_expr(cx.tcx, &**loc);
|
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, ());
|
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,
|
pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
|
||||||
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
|
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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::{MutImmutable, MutMutable, Name, NamedField, NodeId};
|
||||||
use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField};
|
use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField};
|
||||||
use syntax::ast::{Visibility};
|
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::ast_util;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
|
@ -1083,6 +1083,84 @@ pub struct ParameterEnvironment {
|
||||||
pub bounds: VecPerParamSpace<ParamBounds>,
|
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.
|
/// A polytype.
|
||||||
///
|
///
|
||||||
/// - `generics`: the set of type parameters and their bounds
|
/// - `generics`: the set of type parameters and their bounds
|
||||||
|
|
|
@ -879,7 +879,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::TyFixedLengthVec(ty, e) => {
|
ast::TyFixedLengthVec(ty, e) => {
|
||||||
typeck::write_ty_to_tcx(tcx, e.id, ty::mk_uint());
|
|
||||||
match const_eval::eval_const_expr_partial(tcx, &*e) {
|
match const_eval::eval_const_expr_partial(tcx, &*e) {
|
||||||
Ok(ref r) => {
|
Ok(ref r) => {
|
||||||
match *r {
|
match *r {
|
||||||
|
|
|
@ -86,7 +86,7 @@ use middle::subst;
|
||||||
use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace};
|
use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||||
use middle::ty::{FnSig, VariantInfo};
|
use middle::ty::{FnSig, VariantInfo};
|
||||||
use middle::ty::{Polytype};
|
use middle::ty::{Polytype};
|
||||||
use middle::ty::{ParamTy, Disr, ExprTyProvider};
|
use middle::ty::{Disr, ExprTyProvider, ParamTy, ParameterEnvironment};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::TypeFolder;
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
|
@ -281,7 +281,8 @@ impl<'a> Inherited<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by check_const and check_enum_variants
|
// 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>,
|
inh: &'a Inherited<'a>,
|
||||||
rty: ty::t,
|
rty: ty::t,
|
||||||
region_bnd: ast::NodeId)
|
region_bnd: ast::NodeId)
|
||||||
|
@ -673,11 +674,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
}
|
}
|
||||||
ast::ItemFn(ref decl, _, _, _, ref body) => {
|
ast::ItemFn(ref decl, _, _, _, ref body) => {
|
||||||
let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
|
let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
|
||||||
|
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
|
||||||
let param_env = ty::construct_parameter_environment(ccx.tcx,
|
|
||||||
&fn_pty.generics,
|
|
||||||
body.id);
|
|
||||||
|
|
||||||
check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env);
|
check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env);
|
||||||
}
|
}
|
||||||
ast::ItemImpl(_, ref opt_trait_ref, _, ref impl_items) => {
|
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={})",
|
debug!("check_method_body(item_generics={}, method.id={})",
|
||||||
item_generics.repr(ccx.tcx),
|
item_generics.repr(ccx.tcx),
|
||||||
method.id);
|
method.id);
|
||||||
let method_def_id = local_def(method.id);
|
let param_env = ParameterEnvironment::for_item(ccx.tcx, 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 fty = ty::node_id_to_type(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;
|
*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,
|
pub fn check_const(ccx: &CrateCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
e: &ast::Expr,
|
e: &ast::Expr,
|
||||||
|
|
|
@ -66,8 +66,8 @@ use syntax::visit::Visitor;
|
||||||
// It may be better to do something more clever, like processing fully
|
// It may be better to do something more clever, like processing fully
|
||||||
// resolved types first.
|
// resolved types first.
|
||||||
|
|
||||||
/// A vtable context includes an inference context, a crate context, and a
|
/// A vtable context includes an inference context, a parameter environment,
|
||||||
/// callback function to call in case of type error.
|
/// and a list of unboxed closure types.
|
||||||
pub struct VtableContext<'a> {
|
pub struct VtableContext<'a> {
|
||||||
pub infcx: &'a infer::InferCtxt<'a>,
|
pub infcx: &'a infer::InferCtxt<'a>,
|
||||||
pub param_env: &'a ty::ParameterEnvironment,
|
pub param_env: &'a ty::ParameterEnvironment,
|
||||||
|
@ -83,8 +83,7 @@ fn lookup_vtables(vcx: &VtableContext,
|
||||||
type_param_defs: &VecPerParamSpace<ty::TypeParameterDef>,
|
type_param_defs: &VecPerParamSpace<ty::TypeParameterDef>,
|
||||||
substs: &subst::Substs,
|
substs: &subst::Substs,
|
||||||
is_early: bool)
|
is_early: bool)
|
||||||
-> VecPerParamSpace<vtable_param_res>
|
-> VecPerParamSpace<vtable_param_res> {
|
||||||
{
|
|
||||||
debug!("lookup_vtables(\
|
debug!("lookup_vtables(\
|
||||||
type_param_defs={}, \
|
type_param_defs={}, \
|
||||||
substs={}",
|
substs={}",
|
||||||
|
@ -154,11 +153,12 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
|
||||||
match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) {
|
match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) {
|
||||||
Some(vtable) => param_result.push(vtable),
|
Some(vtable) => param_result.push(vtable),
|
||||||
None => {
|
None => {
|
||||||
vcx.tcx().sess.span_fatal(span,
|
vcx.tcx().sess.span_err(span,
|
||||||
format!("failed to find an implementation of \
|
format!("failed to find an implementation of \
|
||||||
trait {} for {}",
|
trait {} for {}",
|
||||||
vcx.infcx.trait_ref_to_string(&*trait_ref),
|
vcx.infcx.trait_ref_to_string(&*trait_ref),
|
||||||
vcx.infcx.ty_to_string(ty)).as_slice());
|
vcx.infcx.ty_to_string(ty)).as_slice());
|
||||||
|
param_result.push(vtable_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -583,10 +583,11 @@ fn fixup_ty(vcx: &VtableContext,
|
||||||
match resolve_type(vcx.infcx, Some(span), ty, resolve_and_force_all_but_regions) {
|
match resolve_type(vcx.infcx, Some(span), ty, resolve_and_force_all_but_regions) {
|
||||||
Ok(new_type) => Some(new_type),
|
Ok(new_type) => Some(new_type),
|
||||||
Err(e) if !is_early => {
|
Err(e) if !is_early => {
|
||||||
tcx.sess.span_fatal(span,
|
tcx.sess.span_err(span,
|
||||||
format!("cannot determine a type for this bounded type \
|
format!("cannot determine a type for this bounded type \
|
||||||
parameter: {}",
|
parameter: {}",
|
||||||
fixup_err_to_string(e)).as_slice())
|
fixup_err_to_string(e)).as_slice());
|
||||||
|
Some(ty::mk_err())
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
None
|
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) {
|
pub fn resolve_in_block(mut fcx: &FnCtxt, bl: &ast::Block) {
|
||||||
visit::walk_block(&mut fcx, bl, ());
|
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(..) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -462,7 +462,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
// These don't define types.
|
// These don't define types.
|
||||||
ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {}
|
ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {}
|
||||||
ast::ItemEnum(ref enum_definition, ref generics) => {
|
ast::ItemEnum(ref enum_definition, ref generics) => {
|
||||||
ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration");
|
|
||||||
let pty = ty_of_item(ccx, it);
|
let pty = ty_of_item(ccx, it);
|
||||||
write_ty_to_tcx(tcx, it.id, pty.ty);
|
write_ty_to_tcx(tcx, it.id, pty.ty);
|
||||||
get_enum_variant_types(ccx,
|
get_enum_variant_types(ccx,
|
||||||
|
@ -559,9 +558,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
// static trait methods. This is somewhat unfortunate.
|
// static trait methods. This is somewhat unfortunate.
|
||||||
ensure_trait_methods(ccx, it.id, &*trait_def);
|
ensure_trait_methods(ccx, it.id, &*trait_def);
|
||||||
},
|
},
|
||||||
ast::ItemStruct(struct_def, ref generics) => {
|
ast::ItemStruct(struct_def, _) => {
|
||||||
ensure_no_ty_param_bounds(ccx, it.span, generics, "structure");
|
|
||||||
|
|
||||||
// Write the class type.
|
// Write the class type.
|
||||||
let pty = ty_of_item(ccx, it);
|
let pty = ty_of_item(ccx, it);
|
||||||
write_ty_to_tcx(tcx, it.id, pty.ty);
|
write_ty_to_tcx(tcx, it.id, pty.ty);
|
||||||
|
|
22
src/test/auxiliary/trait_bounds_on_structs_and_enums_xc.rs
Normal file
22
src/test/auxiliary/trait_bounds_on_structs_and_enums_xc.rs
Normal file
|
@ -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),
|
||||||
|
}
|
||||||
|
|
|
@ -16,9 +16,11 @@ extern crate rand;
|
||||||
|
|
||||||
struct Error;
|
struct Error;
|
||||||
|
|
||||||
#[deriving(Zero)]
|
#[deriving(Zero)] //~ ERROR failed to find an implementation
|
||||||
struct Struct {
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -16,9 +16,11 @@ extern crate rand;
|
||||||
|
|
||||||
struct Error;
|
struct Error;
|
||||||
|
|
||||||
#[deriving(Zero)]
|
#[deriving(Zero)] //~ ERROR failed to find an implementation
|
||||||
struct Struct(
|
struct Struct(
|
||||||
Error //~ ERROR
|
Error //~ ERROR
|
||||||
|
//~^ ERROR failed to find an implementation
|
||||||
|
//~^^ ERROR type `Error` does not implement any method in scope
|
||||||
);
|
);
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -18,4 +18,5 @@ fn main() {
|
||||||
//~^ ERROR cannot determine a type for this bounded type parameter: unconstrained type
|
//~^ ERROR cannot determine a type for this bounded type parameter: unconstrained type
|
||||||
println!("{}", y + 1);
|
println!("{}", y + 1);
|
||||||
//~^ ERROR binary operation `+` cannot be applied to type `Gc<int>`
|
//~^ ERROR binary operation `+` cannot be applied to type `Gc<int>`
|
||||||
|
//~^^ ERROR cannot determine a type for this bounded type parameter: unconstrained type
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,5 +19,5 @@ fn main() {
|
||||||
let x: Box<Map<int, int>> = x;
|
let x: Box<Map<int, int>> = x;
|
||||||
let y: Box<Map<uint, int>> = box x;
|
let y: Box<Map<uint, int>> = box x;
|
||||||
//~^ ERROR failed to find an implementation of trait collections::Map<uint,int>
|
//~^ 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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
|
// Check that non-constant exprs do fail as count in fixed length vec type
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -15,4 +15,5 @@
|
||||||
trait Foo {}
|
trait Foo {}
|
||||||
fn take_foo<F:Foo>(f: F) {}
|
fn take_foo<F:Foo>(f: F) {}
|
||||||
fn take_object(f: Box<Foo>) { take_foo(f); } //~ ERROR failed to find an implementation of trait
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -44,6 +44,7 @@ fn main() {
|
||||||
// Can't do this copy
|
// Can't do this copy
|
||||||
let x = box box box A {y: r(i)};
|
let x = box box box A {y: r(i)};
|
||||||
let _z = x.clone(); //~ ERROR failed to find an implementation
|
let _z = x.clone(); //~ ERROR failed to find an implementation
|
||||||
|
//~^ ERROR failed to find an implementation
|
||||||
println!("{:?}", x);
|
println!("{:?}", x);
|
||||||
}
|
}
|
||||||
println!("{:?}", *i);
|
println!("{:?}", *i);
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
77
src/test/compile-fail/trait-bounds-on-structs-and-enums.rs
Normal file
77
src/test/compile-fail/trait-bounds-on-structs-and-enums.rs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -21,5 +21,6 @@ impl Drop for r {
|
||||||
fn main() {
|
fn main() {
|
||||||
let i = box r { b: true };
|
let i = box r { b: true };
|
||||||
let _j = i.clone(); //~ ERROR failed to find an implementation
|
let _j = i.clone(); //~ ERROR failed to find an implementation
|
||||||
|
//~^ ERROR failed to find an implementation
|
||||||
println!("{:?}", i);
|
println!("{:?}", i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ fn main() {
|
||||||
let r2 = vec!(box r { i: i2 });
|
let r2 = vec!(box r { i: i2 });
|
||||||
f(r1.clone(), r2.clone());
|
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
|
||||||
|
//~^^^^ ERROR failed to find an implementation of
|
||||||
println!("{:?}", (r2, i1.get()));
|
println!("{:?}", (r2, i1.get()));
|
||||||
println!("{:?}", (r1, i2.get()));
|
println!("{:?}", (r1, i2.get()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ impl TraitB for int {
|
||||||
fn call_it<B:TraitB>(b: B) -> int {
|
fn call_it<B:TraitB>(b: B) -> int {
|
||||||
let y = 4u;
|
let y = 4u;
|
||||||
b.gimme_an_a(y) //~ ERROR failed to find an implementation of trait TraitA
|
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() {
|
fn main() {
|
||||||
|
|
|
@ -14,7 +14,10 @@ fn equal<T>(_: &T, _: &T) -> bool where T : Eq {
|
||||||
struct Struct;
|
struct Struct;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
equal(&Struct, &Struct)
|
drop(equal(&Struct, &Struct))
|
||||||
//~^ ERROR failed to find an implementation of trait
|
//~^ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|
||||||
static FOO: int = 2;
|
static FOO: uint = 2;
|
||||||
let _v: [int, ..FOO*3];
|
let _v: [int, ..FOO*3];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
26
src/test/run-pass/trait-bounds-on-structs-and-enums.rs
Normal file
26
src/test/run-pass/trait-bounds-on-structs-and-enums.rs
Normal file
|
@ -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() {}
|
Loading…
Add table
Add a link
Reference in a new issue