Move checking of whether fields are Sized or not into wf / trait code.

This commit is contained in:
Niko Matsakis 2014-09-22 20:12:15 -04:00
parent e924357554
commit 3694f42b8c
9 changed files with 100 additions and 125 deletions

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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>;

View File

@ -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>],

View File

@ -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")
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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() {