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
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
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;
|
||||
|
||||
#[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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {}
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
let i = box r { b: true };
|
||||
let _j = i.clone(); //~ ERROR failed to find an implementation
|
||||
//~^ ERROR failed to find an implementation
|
||||
println!("{:?}", i);
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
pub fn main() {
|
||||
|
||||
static FOO: int = 2;
|
||||
static FOO: uint = 2;
|
||||
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…
x
Reference in New Issue
Block a user