Move checking of whether fields are Sized or not into wf / trait code.
This commit is contained in:
parent
e924357554
commit
3694f42b8c
9 changed files with 100 additions and 125 deletions
|
@ -59,6 +59,7 @@ CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
|||
TOOLS := compiletest rustdoc rustc
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_libc := core
|
||||
DEPS_rlibc := core
|
||||
DEPS_unicode := core
|
||||
DEPS_alloc := core libc native:jemalloc
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
#![allow(missing_doc)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
extern crate core;
|
||||
|
||||
#[cfg(test)] extern crate std;
|
||||
#[cfg(test)] extern crate test;
|
||||
#[cfg(test)] extern crate native;
|
||||
|
|
|
@ -58,8 +58,6 @@ register_diagnostics!(
|
|||
E0039,
|
||||
E0040,
|
||||
E0041,
|
||||
E0042,
|
||||
E0043,
|
||||
E0044,
|
||||
E0045,
|
||||
E0046,
|
||||
|
@ -92,7 +90,6 @@ register_diagnostics!(
|
|||
E0075,
|
||||
E0076,
|
||||
E0077,
|
||||
E0078,
|
||||
E0079,
|
||||
E0080,
|
||||
E0081,
|
||||
|
|
|
@ -80,7 +80,10 @@ pub enum ObligationCauseCode {
|
|||
|
||||
// Captures of variable the given id by a closure (span is the
|
||||
// span of the closure)
|
||||
ClosureCapture(ast::NodeId, Span)
|
||||
ClosureCapture(ast::NodeId, Span),
|
||||
|
||||
// Types of fields (other than the last) in a struct must be sized.
|
||||
FieldSized,
|
||||
}
|
||||
|
||||
pub type Obligations = subst::VecPerParamSpace<Obligation>;
|
||||
|
|
|
@ -381,17 +381,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct CheckItemSizedTypesVisitor<'a, 'tcx: 'a> {
|
||||
ccx: &'a CrateCtxt<'a, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemSizedTypesVisitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &ast::Item) {
|
||||
check_item_sized(self.ccx, i);
|
||||
visit::walk_item(self, i);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_item_types(ccx: &CrateCtxt) {
|
||||
let krate = ccx.tcx.map.krate();
|
||||
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
|
||||
|
@ -405,9 +394,6 @@ pub fn check_item_types(ccx: &CrateCtxt) {
|
|||
visit::walk_crate(&mut visit, krate);
|
||||
|
||||
ccx.tcx.sess.abort_if_errors();
|
||||
|
||||
let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
|
||||
visit::walk_crate(&mut visit, krate);
|
||||
}
|
||||
|
||||
fn check_bare_fn(ccx: &CrateCtxt,
|
||||
|
@ -670,33 +656,6 @@ fn check_for_field_shadowing(tcx: &ty::ctxt,
|
|||
}
|
||||
}
|
||||
|
||||
fn check_fields_sized(tcx: &ty::ctxt,
|
||||
struct_def: &ast::StructDef) {
|
||||
let len = struct_def.fields.len();
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
for f in struct_def.fields.slice_to(len - 1).iter() {
|
||||
let t = ty::node_id_to_type(tcx, f.node.id);
|
||||
if !ty::type_is_sized(tcx, t) {
|
||||
match f.node.kind {
|
||||
ast::NamedField(ident, _) => {
|
||||
span_err!(tcx.sess, f.span, E0042,
|
||||
"type `{}` is dynamically sized. \
|
||||
dynamically sized types may only \
|
||||
appear as the type of the final \
|
||||
field in a struct",
|
||||
token::get_ident(ident));
|
||||
}
|
||||
ast::UnnamedField(_) => {
|
||||
span_err!(tcx.sess, f.span, E0043,
|
||||
"dynamically sized type in field");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
|
@ -711,24 +670,6 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
debug!("check_item(it.id={}, it.ident={})",
|
||||
it.id,
|
||||
ty::item_path_str(ccx.tcx, local_def(it.id)));
|
||||
let _indenter = indenter();
|
||||
|
||||
match it.node {
|
||||
ast::ItemEnum(ref enum_definition, _) => {
|
||||
check_enum_variants_sized(ccx,
|
||||
enum_definition.variants.as_slice());
|
||||
}
|
||||
ast::ItemStruct(..) => {
|
||||
check_fields_sized(ccx.tcx, &*ccx.tcx.map.expect_struct(it.id));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
debug!("check_item(it.id={}, it.ident={})",
|
||||
it.id,
|
||||
|
@ -4946,39 +4887,6 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn check_enum_variants_sized(ccx: &CrateCtxt,
|
||||
vs: &[P<ast::Variant>]) {
|
||||
for v in vs.iter() {
|
||||
match v.node.kind {
|
||||
ast::TupleVariantKind(ref args) if args.len() > 0 => {
|
||||
let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
|
||||
let arg_tys: Vec<ty::t> = ty::ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
|
||||
let len = arg_tys.len();
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
for (i, t) in arg_tys.slice_to(len - 1).iter().enumerate() {
|
||||
// Allow the last field in an enum to be unsized.
|
||||
// We want to do this so that we can support smart pointers.
|
||||
// A struct value with an unsized final field is itself
|
||||
// unsized and we must track this in the type system.
|
||||
if !ty::type_is_sized(ccx.tcx, *t) {
|
||||
span_err!(ccx.tcx.sess, args.get(i).ty.span, E0078,
|
||||
"type `{}` is dynamically sized. dynamically sized types may only \
|
||||
appear as the final type in a variant",
|
||||
ppaux::ty_to_string(ccx.tcx, *t));
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
check_fields_sized(ccx.tcx, &**struct_def)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_enum_variants(ccx: &CrateCtxt,
|
||||
sp: Span,
|
||||
vs: &[P<ast::Variant>],
|
||||
|
|
|
@ -406,5 +406,10 @@ fn note_obligation_cause(fcx: &FnCtxt,
|
|||
name,
|
||||
trait_name);
|
||||
}
|
||||
traits::FieldSized => {
|
||||
span_note!(tcx.sess, obligation.cause.span,
|
||||
"only the last field of a struct or enum variant \
|
||||
may have a dynamically sized type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
item.id,
|
||||
ty::item_path_str(ccx.tcx, local_def(item.id)));
|
||||
|
||||
let ccx = self.ccx;
|
||||
match item.node {
|
||||
ast::ItemImpl(..) => {
|
||||
self.check_impl(item);
|
||||
|
@ -70,26 +69,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
ast::ItemStatic(..) => {
|
||||
self.check_item_type(item);
|
||||
}
|
||||
ast::ItemStruct(..) => {
|
||||
ast::ItemStruct(ref struct_def, _) => {
|
||||
self.check_type_defn(item, |fcx| {
|
||||
ty::struct_fields(ccx.tcx, local_def(item.id),
|
||||
&fcx.inh.param_env.free_substs)
|
||||
.iter()
|
||||
.map(|f| f.mt.ty)
|
||||
.collect()
|
||||
vec![struct_variant(fcx, &**struct_def)]
|
||||
});
|
||||
}
|
||||
ast::ItemEnum(..) => {
|
||||
ast::ItemEnum(ref enum_def, _) => {
|
||||
self.check_type_defn(item, |fcx| {
|
||||
ty::substd_enum_variants(ccx.tcx, local_def(item.id),
|
||||
&fcx.inh.param_env.free_substs)
|
||||
.iter()
|
||||
.flat_map(|variant| {
|
||||
variant.args
|
||||
.iter()
|
||||
.map(|&arg_ty| arg_ty)
|
||||
})
|
||||
.collect()
|
||||
enum_variants(fcx, enum_def)
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
|
@ -116,7 +103,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
|
||||
fn check_type_defn(&mut self,
|
||||
item: &ast::Item,
|
||||
lookup_fields: |&FnCtxt| -> Vec<ty::t>)
|
||||
lookup_fields: |&FnCtxt| -> Vec<AdtVariant>)
|
||||
{
|
||||
/*!
|
||||
* In a type definition, we check that to ensure that the types of the fields are
|
||||
|
@ -124,14 +111,31 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
*/
|
||||
|
||||
self.with_fcx(self.ccx, item, |this, fcx| {
|
||||
let field_tys = lookup_fields(fcx);
|
||||
let variants = lookup_fields(fcx);
|
||||
let mut bounds_checker = BoundsChecker::new(fcx, item.span,
|
||||
item.id, Some(&mut this.cache));
|
||||
for &ty in field_tys.iter() {
|
||||
// Regions are checked below.
|
||||
bounds_checker.check_traits_in_ty(ty);
|
||||
for variant in variants.iter() {
|
||||
for field in variant.fields.iter() {
|
||||
// Regions are checked below.
|
||||
bounds_checker.check_traits_in_ty(field.ty);
|
||||
}
|
||||
|
||||
// For DST, all intermediate types must be sized.
|
||||
if variant.fields.len() > 0 {
|
||||
for field in variant.fields.init().iter() {
|
||||
let cause = traits::ObligationCause::new(field.span, traits::FieldSized);
|
||||
fcx.register_obligation(
|
||||
traits::obligation_for_builtin_bound(fcx.tcx(),
|
||||
cause,
|
||||
field.ty,
|
||||
ty::BoundSized));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field_tys: Vec<ty::t> =
|
||||
variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect();
|
||||
|
||||
regionck::regionck_ensure_component_tys_wf(
|
||||
fcx, item.span, field_tys.as_slice());
|
||||
});
|
||||
|
@ -381,6 +385,62 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ADT
|
||||
|
||||
struct AdtVariant {
|
||||
fields: Vec<AdtField>,
|
||||
}
|
||||
|
||||
struct AdtField {
|
||||
ty: ty::t,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
fn struct_variant(fcx: &FnCtxt, struct_def: &ast::StructDef) -> AdtVariant {
|
||||
let fields =
|
||||
struct_def.fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
|
||||
let field_ty = field_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
AdtField { ty: field_ty, span: field.span }
|
||||
})
|
||||
.collect();
|
||||
AdtVariant { fields: fields }
|
||||
}
|
||||
|
||||
fn enum_variants(fcx: &FnCtxt, enum_def: &ast::EnumDef) -> Vec<AdtVariant> {
|
||||
enum_def.variants.iter()
|
||||
.map(|variant| {
|
||||
match variant.node.kind {
|
||||
ast::TupleVariantKind(ref args) if args.len() > 0 => {
|
||||
let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id);
|
||||
let arg_tys = ty::ty_fn_args(ctor_ty);
|
||||
AdtVariant {
|
||||
fields: args.iter().enumerate().map(|(index, arg)| {
|
||||
let arg_ty = arg_tys[index];
|
||||
let arg_ty = arg_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
AdtField {
|
||||
ty: arg_ty,
|
||||
span: arg.ty.span
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
ast::TupleVariantKind(_) => {
|
||||
AdtVariant {
|
||||
fields: Vec::new()
|
||||
}
|
||||
}
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
struct_variant(fcx, &**struct_def)
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Special drop trait checking
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
// Various examples of structs whose fields are not well-formed.
|
||||
|
||||
#![no_std]
|
||||
#![allow(dead_code)]
|
||||
|
||||
enum Ref1<'a, T> { //~ ERROR the parameter type `T` may not live long enough
|
||||
|
|
|
@ -12,25 +12,25 @@
|
|||
// Test `Sized?` types not allowed in fields (except the last one).
|
||||
|
||||
struct S1<Sized? X> {
|
||||
f1: X, //~ ERROR type `f1` is dynamically sized. dynamically sized types may only appear as the
|
||||
f1: X, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
f2: int,
|
||||
}
|
||||
struct S2<Sized? X> {
|
||||
f: int,
|
||||
g: X, //~ ERROR type `g` is dynamically sized. dynamically sized types may only appear as the ty
|
||||
g: X, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
h: int,
|
||||
}
|
||||
struct S3 {
|
||||
f: str, //~ ERROR type `f` is dynamically sized. dynamically sized types may only appear
|
||||
f: str, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
g: [uint]
|
||||
}
|
||||
struct S4 {
|
||||
f: str, //~ ERROR type `f` is dynamically sized. dynamically sized types may only appear
|
||||
f: str, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
g: uint
|
||||
}
|
||||
enum E<Sized? X> {
|
||||
V1(X, int), //~ERROR type `X` is dynamically sized. dynamically sized types may only appear as t
|
||||
V2{f1: X, f: int}, //~ERROR type `f1` is dynamically sized. dynamically sized types may only app
|
||||
V1(X, int), //~ERROR `core::kinds::Sized` is not implemented
|
||||
V2{f1: X, f: int}, //~ERROR `core::kinds::Sized` is not implemented
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
|
Loading…
Add table
Reference in a new issue