diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 7e0e4abef9d..1c5f0948245 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2590,30 +2590,7 @@ pub fn type_is_machine(ty: t) -> bool { // Is the type's representation size known at compile time? #[allow(dead_code)] // leaving in for DST pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool { - match get(ty).sty { - ty_param(tp) => { - assert_eq!(tp.def_id.krate, ast::LOCAL_CRATE); - - let ty_param_defs = cx.ty_param_defs.borrow(); - let param_def = ty_param_defs.get(&tp.def_id.node); - param_def.bounds.builtin_bounds.contains_elem(BoundSized) - }, - ty_self(def_id) => { - let trait_def = lookup_trait_def(cx, def_id); - trait_def.bounds.contains_elem(BoundSized) - }, - ty_struct(def_id, ref substs) => { - let flds = lookup_struct_fields(cx, def_id); - let mut tps = flds.iter().map(|f| lookup_field_type(cx, def_id, f.id, substs)); - !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 - } + type_contents(cx, ty).is_sized(cx) } // Whether a type is enum like, that is an enum type with only nullary diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b4f22f3fa6e..5e05be1ac91 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -576,15 +576,20 @@ fn check_for_field_shadowing(tcx: &ty::ctxt, } fn check_fields_sized(tcx: &ty::ctxt, - struct_def: @ast::StructDef) { + struct_def: &ast::StructDef) { let len = struct_def.fields.len(); - for i in range(0, len) { - let f = struct_def.fields.get(i); + 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) && i < (len - 1) { + if !ty::type_is_sized(tcx, t) { match f.node.kind { ast::NamedField(ident, _) => { - tcx.sess.span_err(f.span, format!("type of field {} is dynamically sized", + tcx.sess.span_err(f.span, format!("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(_) => { @@ -3519,16 +3524,18 @@ pub fn check_representable(tcx: &ty::ctxt, /// is representable, but not instantiable. pub fn check_instantiable(tcx: &ty::ctxt, sp: Span, - item_id: ast::NodeId) -> bool { + item_id: ast::NodeId) + -> bool { let item_ty = ty::node_id_to_type(tcx, item_id); if !ty::is_instantiable(tcx, item_ty) { tcx.sess.span_err(sp, format!("this type cannot be instantiated \ without an instance of itself; \ consider using `Option<{}>`", ppaux::ty_to_str(tcx, item_ty))); - return false + false + } else { + true } - true } pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { @@ -3567,12 +3574,20 @@ pub fn check_enum_variants_sized(ccx: &CrateCtxt, 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::ty_fn_args(ctor_ty).iter().map(|a| *a).collect(); - for i in range(0, args.len()) { - let t = arg_tys.get(i); + 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. - if !ty::type_is_sized(ccx.tcx, *t) && i < args.len() -1 { + // 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) { ccx.tcx.sess.span_err(args.get(i).ty.span, - format!("type {} is dynamically sized", + format!("type `{}` is dynamically sized. \ + dynamically sized types may only \ + appear as the final type in a variant", ppaux::ty_to_str(ccx.tcx, *t))); } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0e1419dafa0..9c49512d4dc 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1141,14 +1141,12 @@ fn ty_generics(ccx: &CrateCtxt, param_bounds.trait_bounds.as_slice(), |trait_ref| { let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); - for bound in trait_def.bounds.iter() { - if bound == ty::BoundSized { - tcx.sess.span_err(span, - format!("incompatible bounds on type parameter {}, \ - bound {} does not allow unsized type", - token::get_ident(ident), - ppaux::trait_ref_to_str(tcx, trait_ref))); - } + if trait_def.bounds.contains_elem(ty::BoundSized) { + tcx.sess.span_err(span, + format!("incompatible bounds on type parameter {}, \ + bound {} does not allow unsized type", + token::get_ident(ident), + ppaux::trait_ref_to_str(tcx, &*trait_ref))); } true }); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 57438169d6d..f768bf22ce0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -678,7 +678,8 @@ impl<'a> State<'a> { try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); if *sized == ast::DynSize { - try!(self.word_space("for type")); + try!(space(&mut self.s)); + try!(word(&mut self.s, "for type")); } if traits.len() != 0u { try!(word(&mut self.s, ":")); diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index c3b50dcdcaf..9608b7e6b20 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -23,18 +23,18 @@ fn f6(x: &X) { }*/ struct S1 { - f1: X, //~ ERROR type of field f1 is dynamically sized + f1: X, //~ ERROR type `f1` is dynamically sized. dynamically sized types may only appear as the f2: int, } struct S2 { f: int, - g: X, //~ ERROR type of field g is dynamically sized + g: X, //~ ERROR type `g` is dynamically sized. dynamically sized types may only appear as the ty h: int, } enum E { - V1(X, int), //~ERROR type X is dynamically sized - V2{f1: X, f: int}, //~ERROR type of field f1 is dynamically sized + 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 } pub fn main() { diff --git a/src/test/run-pass/unsized2.rs b/src/test/run-pass/unsized2.rs index 7cc2dfd816f..7883adad46a 100644 --- a/src/test/run-pass/unsized2.rs +++ b/src/test/run-pass/unsized2.rs @@ -66,7 +66,8 @@ trait T4 { fn m2(x: &T5); } trait T5 { - fn m1(x: &T4); // not an error (for now) + // not an error (for now) + fn m1(x: &T4); fn m2(x: &T5); } @@ -75,7 +76,8 @@ trait T6 { fn m2(x: &T5); } trait T7 { - fn m1(x: &T4); // not an error (for now) + // not an error (for now) + fn m1(x: &T4); fn m2(x: &T5); }