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
|
TOOLS := compiletest rustdoc rustc
|
||||||
|
|
||||||
DEPS_core :=
|
DEPS_core :=
|
||||||
|
DEPS_libc := core
|
||||||
DEPS_rlibc := core
|
DEPS_rlibc := core
|
||||||
DEPS_unicode := core
|
DEPS_unicode := core
|
||||||
DEPS_alloc := core libc native:jemalloc
|
DEPS_alloc := core libc native:jemalloc
|
||||||
|
|
|
@ -79,6 +79,8 @@
|
||||||
#![allow(missing_doc)]
|
#![allow(missing_doc)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
#[cfg(test)] extern crate std;
|
#[cfg(test)] extern crate std;
|
||||||
#[cfg(test)] extern crate test;
|
#[cfg(test)] extern crate test;
|
||||||
#[cfg(test)] extern crate native;
|
#[cfg(test)] extern crate native;
|
||||||
|
|
|
@ -58,8 +58,6 @@ register_diagnostics!(
|
||||||
E0039,
|
E0039,
|
||||||
E0040,
|
E0040,
|
||||||
E0041,
|
E0041,
|
||||||
E0042,
|
|
||||||
E0043,
|
|
||||||
E0044,
|
E0044,
|
||||||
E0045,
|
E0045,
|
||||||
E0046,
|
E0046,
|
||||||
|
@ -92,7 +90,6 @@ register_diagnostics!(
|
||||||
E0075,
|
E0075,
|
||||||
E0076,
|
E0076,
|
||||||
E0077,
|
E0077,
|
||||||
E0078,
|
|
||||||
E0079,
|
E0079,
|
||||||
E0080,
|
E0080,
|
||||||
E0081,
|
E0081,
|
||||||
|
|
|
@ -80,7 +80,10 @@ pub enum ObligationCauseCode {
|
||||||
|
|
||||||
// Captures of variable the given id by a closure (span is the
|
// Captures of variable the given id by a closure (span is the
|
||||||
// span of the closure)
|
// 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>;
|
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) {
|
pub fn check_item_types(ccx: &CrateCtxt) {
|
||||||
let krate = ccx.tcx.map.krate();
|
let krate = ccx.tcx.map.krate();
|
||||||
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
|
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
|
||||||
|
@ -405,9 +394,6 @@ pub fn check_item_types(ccx: &CrateCtxt) {
|
||||||
visit::walk_crate(&mut visit, krate);
|
visit::walk_crate(&mut visit, krate);
|
||||||
|
|
||||||
ccx.tcx.sess.abort_if_errors();
|
ccx.tcx.sess.abort_if_errors();
|
||||||
|
|
||||||
let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
|
|
||||||
visit::walk_crate(&mut visit, krate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_bare_fn(ccx: &CrateCtxt,
|
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) {
|
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
||||||
let tcx = ccx.tcx;
|
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) {
|
pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
debug!("check_item(it.id={}, it.ident={})",
|
debug!("check_item(it.id={}, it.ident={})",
|
||||||
it.id,
|
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,
|
pub fn check_enum_variants(ccx: &CrateCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
vs: &[P<ast::Variant>],
|
vs: &[P<ast::Variant>],
|
||||||
|
|
|
@ -406,5 +406,10 @@ fn note_obligation_cause(fcx: &FnCtxt,
|
||||||
name,
|
name,
|
||||||
trait_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,
|
item.id,
|
||||||
ty::item_path_str(ccx.tcx, local_def(item.id)));
|
ty::item_path_str(ccx.tcx, local_def(item.id)));
|
||||||
|
|
||||||
let ccx = self.ccx;
|
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemImpl(..) => {
|
ast::ItemImpl(..) => {
|
||||||
self.check_impl(item);
|
self.check_impl(item);
|
||||||
|
@ -70,26 +69,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||||
ast::ItemStatic(..) => {
|
ast::ItemStatic(..) => {
|
||||||
self.check_item_type(item);
|
self.check_item_type(item);
|
||||||
}
|
}
|
||||||
ast::ItemStruct(..) => {
|
ast::ItemStruct(ref struct_def, _) => {
|
||||||
self.check_type_defn(item, |fcx| {
|
self.check_type_defn(item, |fcx| {
|
||||||
ty::struct_fields(ccx.tcx, local_def(item.id),
|
vec![struct_variant(fcx, &**struct_def)]
|
||||||
&fcx.inh.param_env.free_substs)
|
|
||||||
.iter()
|
|
||||||
.map(|f| f.mt.ty)
|
|
||||||
.collect()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ast::ItemEnum(..) => {
|
ast::ItemEnum(ref enum_def, _) => {
|
||||||
self.check_type_defn(item, |fcx| {
|
self.check_type_defn(item, |fcx| {
|
||||||
ty::substd_enum_variants(ccx.tcx, local_def(item.id),
|
enum_variants(fcx, enum_def)
|
||||||
&fcx.inh.param_env.free_substs)
|
|
||||||
.iter()
|
|
||||||
.flat_map(|variant| {
|
|
||||||
variant.args
|
|
||||||
.iter()
|
|
||||||
.map(|&arg_ty| arg_ty)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -116,7 +103,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||||
|
|
||||||
fn check_type_defn(&mut self,
|
fn check_type_defn(&mut self,
|
||||||
item: &ast::Item,
|
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
|
* 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| {
|
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,
|
let mut bounds_checker = BoundsChecker::new(fcx, item.span,
|
||||||
item.id, Some(&mut this.cache));
|
item.id, Some(&mut this.cache));
|
||||||
for &ty in field_tys.iter() {
|
for variant in variants.iter() {
|
||||||
// Regions are checked below.
|
for field in variant.fields.iter() {
|
||||||
bounds_checker.check_traits_in_ty(ty);
|
// 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(
|
regionck::regionck_ensure_component_tys_wf(
|
||||||
fcx, item.span, field_tys.as_slice());
|
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
|
// Special drop trait checking
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
// Various examples of structs whose fields are not well-formed.
|
// Various examples of structs whose fields are not well-formed.
|
||||||
|
|
||||||
#![no_std]
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
enum Ref1<'a, T> { //~ ERROR the parameter type `T` may not live long enough
|
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).
|
// Test `Sized?` types not allowed in fields (except the last one).
|
||||||
|
|
||||||
struct S1<Sized? X> {
|
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,
|
f2: int,
|
||||||
}
|
}
|
||||||
struct S2<Sized? X> {
|
struct S2<Sized? X> {
|
||||||
f: int,
|
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,
|
h: int,
|
||||||
}
|
}
|
||||||
struct S3 {
|
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]
|
g: [uint]
|
||||||
}
|
}
|
||||||
struct S4 {
|
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
|
g: uint
|
||||||
}
|
}
|
||||||
enum E<Sized? X> {
|
enum E<Sized? X> {
|
||||||
V1(X, int), //~ERROR type `X` is dynamically sized. dynamically sized types may only appear as t
|
V1(X, int), //~ERROR `core::kinds::Sized` is not implemented
|
||||||
V2{f1: X, f: int}, //~ERROR type `f1` is dynamically sized. dynamically sized types may only app
|
V2{f1: X, f: int}, //~ERROR `core::kinds::Sized` is not implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue