Check for unsized types in enums.
And allow the last field of a struct or variant to be unsized.
This commit is contained in:
parent
f78add10cd
commit
0540a59382
|
@ -2608,6 +2608,10 @@ pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool {
|
|||
!tps.any(|ty| !type_is_sized(cx, ty))
|
||||
}
|
||||
ty_tup(ref ts) => !ts.iter().any(|t| !type_is_sized(cx, *t)),
|
||||
ty_enum(did, ref substs) => {
|
||||
let variants = substd_enum_variants(cx, did, substs);
|
||||
!variants.iter().any(|v| v.args.iter().any(|t| !type_is_sized(cx, *t)))
|
||||
}
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,9 +317,23 @@ impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
struct CheckItemSizedTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
|
||||
|
||||
impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
|
||||
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, krate: &ast::Crate) {
|
||||
let mut visit = CheckItemTypesVisitor { ccx: ccx };
|
||||
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,
|
||||
|
@ -562,19 +576,19 @@ fn check_for_field_shadowing(tcx: &ty::ctxt,
|
|||
}
|
||||
|
||||
fn check_fields_sized(tcx: &ty::ctxt,
|
||||
id: ast::NodeId) {
|
||||
let struct_def = tcx.map.expect_struct(id);
|
||||
// FIXME(#13121) allow the last field to be DST
|
||||
for f in struct_def.fields.iter() {
|
||||
struct_def: @ast::StructDef) {
|
||||
let len = struct_def.fields.len();
|
||||
for i in range(0, len) {
|
||||
let f = struct_def.fields.get(i);
|
||||
let t = ty::node_id_to_type(tcx, f.node.id);
|
||||
if !ty::type_is_sized(tcx, t) {
|
||||
if !ty::type_is_sized(tcx, t) && i < (len - 1) {
|
||||
match f.node.kind {
|
||||
ast::NamedField(ident, _) => {
|
||||
tcx.sess.span_err(f.span, format!("Dynamically sized type in field {}",
|
||||
tcx.sess.span_err(f.span, format!("type of field {} is dynamically sized",
|
||||
token::get_ident(ident)));
|
||||
}
|
||||
ast::UnnamedField(_) => {
|
||||
tcx.sess.span_err(f.span, "Dynamically sized type in field");
|
||||
tcx.sess.span_err(f.span, "dynamically sized type in field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -584,14 +598,8 @@ fn check_fields_sized(tcx: &ty::ctxt,
|
|||
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
// Check that the struct is representable
|
||||
check_representable(tcx, span, id, "struct");
|
||||
|
||||
// Check that the struct is instantiable
|
||||
if check_instantiable(tcx, span, id) {
|
||||
// This might cause stack overflow if id is not instantiable.
|
||||
check_fields_sized(tcx, id);
|
||||
}
|
||||
check_instantiable(tcx, span, id);
|
||||
|
||||
// Check there are no overlapping fields in super-structs
|
||||
check_for_field_shadowing(tcx, local_def(id));
|
||||
|
@ -601,6 +609,24 @@ 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,
|
||||
|
@ -3459,7 +3485,7 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
|
|||
pub fn check_representable(tcx: &ty::ctxt,
|
||||
sp: Span,
|
||||
item_id: ast::NodeId,
|
||||
designation: &str) {
|
||||
designation: &str) -> bool {
|
||||
let rty = ty::node_id_to_type(tcx, item_id);
|
||||
|
||||
// Check that it is possible to represent this type. This call identifies
|
||||
|
@ -3473,9 +3499,11 @@ pub fn check_representable(tcx: &ty::ctxt,
|
|||
sp, format!("illegal recursive {} type; \
|
||||
wrap the inner value in a box to make it representable",
|
||||
designation));
|
||||
return false
|
||||
}
|
||||
ty::Representable | ty::ContainsRecursive => (),
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/// Checks whether a type can be created without an instance of itself.
|
||||
|
@ -3532,6 +3560,29 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_enum_variants_sized(ccx: &CrateCtxt,
|
||||
vs: &[ast::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();
|
||||
for i in range(0, args.len()) {
|
||||
let t = arg_tys.get(i);
|
||||
// Allow the last field in an enum to be unsized.
|
||||
if !ty::type_is_sized(ccx.tcx, *t) && i < args.len() -1 {
|
||||
ccx.tcx.sess.span_err(args.get(i).ty.span,
|
||||
format!("type {} is dynamically sized",
|
||||
ppaux::ty_to_str(ccx.tcx, *t)));
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::StructVariantKind(struct_def) => check_fields_sized(ccx.tcx, struct_def),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_enum_variants(ccx: &CrateCtxt,
|
||||
sp: Span,
|
||||
vs: &[ast::P<ast::Variant>],
|
||||
|
@ -3652,7 +3703,6 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
|
|||
// cache so that ty::enum_variants won't repeat this work
|
||||
ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants));
|
||||
|
||||
// Check that it is possible to represent this enum.
|
||||
check_representable(ccx.tcx, sp, id, "enum");
|
||||
|
||||
// Check that it is possible to instantiate this enum:
|
||||
|
|
|
@ -283,6 +283,13 @@ impl Map {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_variant(&self, id: NodeId) -> P<Variant> {
|
||||
match self.find(id) {
|
||||
Some(NodeVariant(variant)) => variant,
|
||||
_ => fail!(format!("expected variant, found {}", self.node_to_str(id))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem {
|
||||
match self.find(id) {
|
||||
Some(NodeForeignItem(item)) => item,
|
||||
|
|
|
@ -25,6 +25,35 @@ fn f3<type X: T>(x: &X) {
|
|||
fn f4<X: T>(x: &X) {
|
||||
}
|
||||
|
||||
// Test with unsized enum.
|
||||
enum E<type X> {
|
||||
V(X),
|
||||
}
|
||||
|
||||
fn f5<Y>(x: &Y) {}
|
||||
fn f6<type X>(x: &X) {}
|
||||
fn f7<type X>(x1: &E<X>, x2: &E<X>) {
|
||||
f5(x1); //~ERROR instantiating a type parameter with an incompatible type `E<X>`, which does not
|
||||
f6(x2); // ok
|
||||
}
|
||||
|
||||
|
||||
// Test with unsized struct.
|
||||
struct S<type X> {
|
||||
x: X,
|
||||
}
|
||||
|
||||
fn f8<type X>(x1: &S<X>, x2: &S<X>) {
|
||||
f5(x1); //~ERROR instantiating a type parameter with an incompatible type `S<X>`, which does not
|
||||
f6(x2); // ok
|
||||
}
|
||||
|
||||
// Test some tuples.
|
||||
fn f9<type X>(x1: ~S<X>, x2: ~E<X>) {
|
||||
f5(&(*x1, 34)); //~ERROR instantiating a type parameter with an incompatible type `(S<X>,int)`,
|
||||
f5(&(32, *x2)); //~ERROR instantiating a type parameter with an incompatible type `(int,E<X>)`,
|
||||
}
|
||||
|
||||
// I would like these to fail eventually.
|
||||
/*
|
||||
// impl - bounded
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// 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.
|
||||
#![feature(struct_variant)]
|
||||
|
||||
// Test `type` types not allowed in fields or local variables.
|
||||
|
||||
/*trait T for type {}
|
||||
|
||||
fn f5<type X>(x: &X) {
|
||||
let _: X; // ERROR local variable with dynamically sized type X
|
||||
let _: (int, (X, int)); // ERROR local variable with dynamically sized type (int,(X,int))
|
||||
}
|
||||
fn f6<type X: T>(x: &X) {
|
||||
let _: X; // ERROR local variable with dynamically sized type X
|
||||
let _: (int, (X, int)); // ERROR local variable with dynamically sized type (int,(X,int))
|
||||
}*/
|
||||
|
||||
struct S1<type X> {
|
||||
f1: X, //~ ERROR type of field f1 is dynamically sized
|
||||
f2: int,
|
||||
}
|
||||
struct S2<type X> {
|
||||
f: int,
|
||||
g: X, //~ ERROR type of field g is dynamically sized
|
||||
h: int,
|
||||
}
|
||||
|
||||
enum E<type X> {
|
||||
V1(X, int), //~ERROR type X is dynamically sized
|
||||
V2{f1: X, f: int}, //~ERROR type of field f1 is dynamically sized
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
|
@ -19,6 +19,7 @@ trait T6<Y, type X> {}
|
|||
trait T7<type X, type Y> {}
|
||||
trait T8<type X: T2> {}
|
||||
struct S1<type X>;
|
||||
enum E<type X> {}
|
||||
impl <type X> T1 for S1<X> {}
|
||||
fn f<type X>() {}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// <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.
|
||||
#![feature(struct_variant)]
|
||||
|
||||
// Test sized-ness checking in substitution.
|
||||
|
||||
|
@ -78,5 +79,20 @@ trait T7<type X: T> {
|
|||
fn m2(x: &T5<X>);
|
||||
}
|
||||
|
||||
// The last field in a struct or variant may be unsized
|
||||
struct S2<type X> {
|
||||
f: X,
|
||||
}
|
||||
struct S3<type X> {
|
||||
f1: int,
|
||||
f2: X,
|
||||
}
|
||||
enum E<type X> {
|
||||
V1(X),
|
||||
V2{x: X},
|
||||
V3(int, X),
|
||||
V4{u: int, x: X},
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue