From f78add10cde772b9d743a84a604dc584b63a06fc Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 3 Apr 2014 13:38:45 +1300 Subject: [PATCH] Support unsized types with the `type` keyword --- src/librustc/front/config.rs | 4 +- src/librustc/metadata/common.rs | 1 + src/librustc/metadata/decoder.rs | 21 +++++ src/librustc/metadata/encoder.rs | 15 +++- src/librustc/middle/privacy.rs | 8 +- src/librustc/middle/resolve.rs | 7 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/middle/ty.rs | 26 ++++-- src/librustc/middle/typeck/check/mod.rs | 57 +++++++++---- src/librustc/middle/typeck/collect.rs | 76 ++++++++++++++--- .../middle/typeck/infer/error_reporting.rs | 2 + src/librustc/middle/typeck/variance.rs | 2 +- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ast.rs | 9 +- src/libsyntax/ast_map.rs | 20 ++++- src/libsyntax/ext/build.rs | 3 + src/libsyntax/ext/deriving/decodable.rs | 5 +- src/libsyntax/ext/deriving/encodable.rs | 5 +- src/libsyntax/ext/deriving/generic.rs | 6 +- src/libsyntax/ext/deriving/hash.rs | 3 +- src/libsyntax/ext/deriving/rand.rs | 3 +- src/libsyntax/ext/deriving/ty.rs | 9 +- src/libsyntax/fold.rs | 4 +- src/libsyntax/parse/parser.rs | 27 +++++- src/libsyntax/print/pprust.rs | 8 +- src/libsyntax/visit.rs | 2 +- .../compile-fail/bad-mid-path-type-params.rs | 3 + .../borrowck-move-subcomponent.rs | 3 + src/test/compile-fail/lint-dead-code-1.rs | 4 + src/test/compile-fail/privacy1.rs | 3 + src/test/compile-fail/unsized-bare-typaram.rs | 2 +- src/test/compile-fail/unsized-enum.rs | 2 +- src/test/compile-fail/unsized-struct.rs | 2 +- src/test/compile-fail/unsized.rs | 16 ++++ src/test/compile-fail/unsized2.rs | 17 ++++ src/test/compile-fail/unsized3.rs | 51 ++++++++++++ src/test/compile-fail/unsized4.rs | 19 +++++ src/test/run-pass/unsized.rs | 26 ++++++ src/test/run-pass/unsized2.rs | 82 +++++++++++++++++++ 39 files changed, 484 insertions(+), 73 deletions(-) create mode 100644 src/test/compile-fail/unsized.rs create mode 100644 src/test/compile-fail/unsized2.rs create mode 100644 src/test/compile-fail/unsized3.rs create mode 100644 src/test/compile-fail/unsized4.rs create mode 100644 src/test/run-pass/unsized.rs create mode 100644 src/test/run-pass/unsized2.rs diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index e630d7e15e039..b8f20b5e43968 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -103,12 +103,12 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ { .map(|x| *x).collect(); ast::ItemImpl((*a).clone(), (*b).clone(), c, methods) } - ast::ItemTrait(ref a, ref b, ref methods) => { + ast::ItemTrait(ref a, b, ref c, ref methods) => { let methods = methods.iter() .filter(|m| trait_method_in_cfg(cx, *m) ) .map(|x| (*x).clone()) .collect(); - ast::ItemTrait((*a).clone(), (*b).clone(), methods) + ast::ItemTrait((*a).clone(), b, (*c).clone(), methods) } ast::ItemStruct(def, ref generics) => { ast::ItemStruct(fold_struct(cx, def), generics.clone()) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 4a0b3ea0cf6a0..0ea6598a99f00 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -170,6 +170,7 @@ pub static tag_lang_items_item_node_id: uint = 0x73; pub static tag_item_unnamed_field: uint = 0x74; pub static tag_items_data_item_visibility: uint = 0x76; +pub static tag_items_data_item_sized: uint = 0x77; pub static tag_item_method_tps: uint = 0x79; pub static tag_item_method_fty: uint = 0x7a; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 37d9d3417c9f5..b76b6d0c38065 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -164,6 +164,19 @@ fn item_visibility(item: ebml::Doc) -> ast::Visibility { } } +fn item_sized(item: ebml::Doc) -> ast::Sized { + match reader::maybe_get_doc(item, tag_items_data_item_sized) { + None => ast::StaticSize, + Some(sized_doc) => { + match reader::doc_as_u8(sized_doc) as char { + 'd' => ast::DynSize, + 's' => ast::StaticSize, + _ => fail!("unknown sized-ness character") + } + } + } +} + fn item_method_sort(item: ebml::Doc) -> char { let mut ret = 'r'; reader::tagged_docs(item, tag_item_trait_method_sort, |doc| { @@ -371,6 +384,7 @@ pub fn get_trait_def(cdata: Cmd, let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, tag_items_data_item_ty_param_bounds); let rp_defs = item_region_param_defs(item_doc, cdata); + let sized = item_sized(item_doc); let mut bounds = ty::EmptyBuiltinBounds(); // Collect the builtin bounds from the encoded supertraits. // FIXME(#8559): They should be encoded directly. @@ -382,6 +396,13 @@ pub fn get_trait_def(cdata: Cmd, }); true }); + // Turn sized into a bound, FIXME(#8559). + if sized == ast::StaticSize { + tcx.lang_items.to_builtin_kind(tcx.lang_items.sized_trait().unwrap()).map(|bound| { + bounds.add(bound); + }); + } + ty::TraitDef { generics: ty::Generics {type_param_defs: tp_defs, region_param_defs: rp_defs}, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 848fd8d362e12..d5ee1b15ae252 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -832,6 +832,16 @@ fn encode_extension_implementations(ecx: &EncodeContext, } } +fn encode_sized(ebml_w: &mut Encoder, sized: Sized) { + ebml_w.start_tag(tag_items_data_item_sized); + let ch = match sized { + DynSize => 'd', + StaticSize => 's', + }; + ebml_w.wr_str(str::from_char(ch)); + ebml_w.end_tag(); +} + fn encode_info_for_item(ecx: &EncodeContext, ebml_w: &mut Encoder, item: &Item, @@ -1070,7 +1080,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ast_method) } } - ItemTrait(_, ref super_traits, ref ms) => { + ItemTrait(_, sized, ref super_traits, ref ms) => { add_to_index(item, ebml_w, index); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); @@ -1084,6 +1094,9 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_trait_ref(ebml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); encode_name(ebml_w, item.ident.name); encode_attributes(ebml_w, item.attrs.as_slice()); + // When we fix the rest of the supertrait nastiness (FIXME(#8559)), we + // should no longer need this ugly little hack either. + encode_sized(ebml_w, sized); encode_visibility(ebml_w, vis); for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() { ebml_w.start_tag(tag_item_trait_method); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 427a7f406b015..eeccd1ca33449 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -79,7 +79,7 @@ impl Visitor<()> for ParentVisitor { // method to the root. In this case, if the trait is private, then // parent all the methods to the trait to indicate that they're // private. - ast::ItemTrait(_, _, ref methods) if item.vis != ast::Public => { + ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => { for m in methods.iter() { match *m { ast::Provided(ref m) => self.parents.insert(m.id, item.id), @@ -274,7 +274,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> { // Default methods on traits are all public so long as the trait // is public - ast::ItemTrait(_, _, ref methods) if public_first => { + ast::ItemTrait(_, _, _, ref methods) if public_first => { for method in methods.iter() { match *method { ast::Provided(ref m) => { @@ -1082,7 +1082,7 @@ impl<'a> SanePrivacyVisitor<'a> { } } - ast::ItemTrait(_, _, ref methods) => { + ast::ItemTrait(_, _, _, ref methods) => { for m in methods.iter() { match *m { ast::Provided(ref m) => { @@ -1142,7 +1142,7 @@ impl<'a> SanePrivacyVisitor<'a> { ast::ItemStruct(ref def, _) => check_struct(def), - ast::ItemTrait(_, _, ref methods) => { + ast::ItemTrait(_, _, _, ref methods) => { for m in methods.iter() { match *m { ast::Required(..) => {} diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index d645b628affc5..a2e6d6d1cab9c 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1325,7 +1325,7 @@ impl<'a> Resolver<'a> { ItemImpl(_, Some(_), _, _) => parent, - ItemTrait(_, _, ref methods) => { + ItemTrait(_, _, _, ref methods) => { let name_bindings = self.add_child(ident, parent.clone(), ForbidDuplicateTypes, sp); @@ -3578,7 +3578,7 @@ impl<'a> Resolver<'a> { methods.as_slice()); } - ItemTrait(ref generics, ref traits, ref methods) => { + ItemTrait(ref generics, _, ref traits, ref methods) => { // Create a new rib for the self type. let self_type_rib = Rib::new(NormalRibKind); // plain insert (no renaming) @@ -3786,9 +3786,8 @@ impl<'a> Resolver<'a> { } Some(declaration) => { for argument in declaration.inputs.iter() { - let binding_mode = ArgumentIrrefutableMode; this.resolve_pattern(argument.pat, - binding_mode, + ArgumentIrrefutableMode, None); this.resolve_type(argument.ty); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 130c93ac51e91..88989f7ce0824 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -84,7 +84,7 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | ast::ItemImpl(ref generics, _, _, _) | - ast::ItemTrait(ref generics, _, _) => { + ast::ItemTrait(ref generics, _, _, _) => { self.check_lifetime_names(&generics.lifetimes); EarlyScope(0, &generics.lifetimes, &root) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9a3bdcc1e15e3..49968de28daf5 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2591,16 +2591,24 @@ pub fn type_is_machine(ty: t) -> bool { #[allow(dead_code)] // leaving in for DST pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool { match get(ty).sty { - // FIXME(#6308) add trait, vec, str, etc here. - ty_param(p) => { + 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(&p.def_id.node); - if param_def.bounds.builtin_bounds.contains_elem(BoundSized) { - return true; - } - return false; + let param_def = ty_param_defs.get(&tp.def_id.node); + param_def.bounds.builtin_bounds.contains_elem(BoundSized) }, - _ => return true, + 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)), + _ => true } } @@ -3495,7 +3503,7 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec> { match cx.map.find(id.node) { Some(ast_map::NodeItem(item)) => { match item.node { - ItemTrait(_, _, ref ms) => { + ItemTrait(_, _, _, ref ms) => { let (_, p) = ast_util::split_trait_methods(ms.as_slice()); p.iter().map(|m| method(cx, ast_util::local_def(m.id))).collect() } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index dc5b4f6d520a4..cd880f8081729 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -369,21 +369,21 @@ impl<'a> GatherLocalsVisitor<'a> { } impl<'a> Visitor<()> for GatherLocalsVisitor<'a> { - // Add explicitly-declared locals. + // Add explicitly-declared locals. fn visit_local(&mut self, local: &ast::Local, _: ()) { - let o_ty = match local.ty.node { - ast::TyInfer => None, - _ => Some(self.fcx.to_ty(local.ty)) - }; - self.assign(local.id, o_ty); - debug!("Local variable {} is assigned type {}", - self.fcx.pat_to_str(local.pat), - self.fcx.infcx().ty_to_str( - self.fcx.inh.locals.borrow().get_copy(&local.id))); - visit::walk_local(self, local, ()); - + let o_ty = match local.ty.node { + ast::TyInfer => None, + _ => Some(self.fcx.to_ty(local.ty)) + }; + self.assign(local.id, o_ty); + debug!("Local variable {} is assigned type {}", + self.fcx.pat_to_str(local.pat), + self.fcx.infcx().ty_to_str( + self.fcx.inh.locals.borrow().get_copy(&local.id))); + visit::walk_local(self, local, ()); } - // Add pattern bindings. + + // Add pattern bindings. fn visit_pat(&mut self, p: &ast::Pat, _: ()) { match p.node { ast::PatIdent(_, ref path, _) @@ -561,6 +561,26 @@ 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() { + 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, _) => { + tcx.sess.span_err(f.span, format!("Dynamically sized type in field {}", + token::get_ident(ident))); + } + ast::UnnamedField(_) => { + tcx.sess.span_err(f.span, "Dynamically sized type in field"); + } + } + } + } +} + pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { let tcx = ccx.tcx; @@ -568,7 +588,10 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { check_representable(tcx, span, id, "struct"); // Check that the struct is instantiable - check_instantiable(tcx, span, id); + if check_instantiable(tcx, span, id) { + // This might cause stack overflow if id is not instantiable. + check_fields_sized(tcx, id); + } // Check there are no overlapping fields in super-structs check_for_field_shadowing(tcx, local_def(id)); @@ -630,7 +653,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { } } - ast::ItemTrait(_, _, ref trait_methods) => { + ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); for trait_method in (*trait_methods).iter() { match *trait_method { @@ -3468,14 +3491,16 @@ 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) { + 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 } + true } pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0102001aa3cd9..0e1419dafa09c 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -32,6 +32,7 @@ are represented as `ty_param()` instances. use metadata::csearch; +use middle::lang_items::SizedTraitLangItem; use middle::resolve_lifetime; use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs}; use middle::ty::{ty_param_bounds_and_ty}; @@ -189,7 +190,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { match tcx.map.get(trait_id) { ast_map::NodeItem(item) => { match item.node { - ast::ItemTrait(ref generics, _, ref ms) => { + ast::ItemTrait(ref generics, _, _, ref ms) => { let trait_ty_generics = ty_generics_for_type(ccx, generics); // For each method, construct a suitable ty::Method and @@ -402,7 +403,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { pub fn ensure_supertraits(ccx: &CrateCtxt, id: ast::NodeId, sp: codemap::Span, - ast_trait_refs: &[ast::TraitRef]) + ast_trait_refs: &[ast::TraitRef], + sized: ast::Sized) -> ty::BuiltinBounds { let tcx = ccx.tcx; @@ -433,6 +435,12 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, } } } + if sized == ast::StaticSize { + match tcx.lang_items.require(SizedTraitLangItem) { + Ok(def_id) => { ty::try_add_builtin_trait(tcx, def_id, &mut bounds); }, + Err(s) => tcx.sess.err(s), + }; + } tcx.supertraits.borrow_mut().insert(local_def(id), Rc::new(ty_trait_refs)); bounds @@ -562,8 +570,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, if ty_param.bounds.len() > 0 { ccx.tcx.sess.span_err( span, - format!("trait bounds are not allowed in {} definitions", - thing)); + format!("trait bounds are not allowed in {} definitions", thing)); } } } @@ -634,7 +641,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { } } }, - ast::ItemTrait(ref generics, _, ref trait_methods) => { + ast::ItemTrait(ref generics, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); // Run convert_methods on the provided methods. @@ -863,14 +870,15 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { } match it.node { - ast::ItemTrait(ref generics, ref supertraits, _) => { + ast::ItemTrait(ref generics, sized, ref supertraits, _) => { let self_ty = ty::mk_self(tcx, def_id); let ty_generics = ty_generics_for_type(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty)); let bounds = ensure_supertraits(ccx, it.id, it.span, - supertraits.as_slice()); + supertraits.as_slice(), + sized); let trait_def = Rc::new(ty::TraitDef { generics: ty_generics, bounds: bounds, @@ -1032,7 +1040,12 @@ fn ty_generics(ccx: &CrateCtxt, existing_def_opt.unwrap_or_else(|| { let param_ty = ty::param_ty {idx: base_index + offset, def_id: local_def(param.id)}; - let bounds = Rc::new(compute_bounds(ccx, param_ty, ¶m.bounds)); + let bounds = Rc::new(compute_bounds(ccx, + param_ty, + ¶m.bounds, + param.sized, + param.ident, + param.span)); let default = param.default.map(|path| { let ty = ast_ty_to_ty(ccx, &ExplicitRscope, path); let cur_idx = param_ty.idx; @@ -1067,7 +1080,10 @@ fn ty_generics(ccx: &CrateCtxt, fn compute_bounds( ccx: &CrateCtxt, param_ty: ty::param_ty, - ast_bounds: &OwnedSlice) -> ty::ParamBounds + ast_bounds: &OwnedSlice, + sized: ast::Sized, + ident: ast::Ident, + span: Span) -> ty::ParamBounds { /*! * Translate the AST's notion of ty param bounds (which are an @@ -1086,9 +1102,8 @@ fn ty_generics(ccx: &CrateCtxt, let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); let trait_ref = instantiate_trait_ref(ccx, b, ty); if !ty::try_add_builtin_trait( - ccx.tcx, trait_ref.def_id, - &mut param_bounds.builtin_bounds) - { + ccx.tcx, trait_ref.def_id, + &mut param_bounds.builtin_bounds) { // Must be a user-defined trait param_bounds.trait_bounds.push(trait_ref); } @@ -1100,8 +1115,45 @@ fn ty_generics(ccx: &CrateCtxt, } } + if sized == ast::StaticSize { + match ccx.tcx.lang_items.require(SizedTraitLangItem) { + Ok(def_id) => { ty::try_add_builtin_trait(ccx.tcx, + def_id, + &mut param_bounds.builtin_bounds); }, + // Fixme(13367) after `type` makes it into the snapshot, we can check this properly + Err(_s) => {}, //ccx.tcx.sess.err(s), + } + } + + check_bounds_compatible(ccx.tcx, ¶m_bounds, ident, span); + param_bounds } + + fn check_bounds_compatible(tcx: &ty::ctxt, + param_bounds: &ty::ParamBounds, + ident: ast::Ident, + span: Span) { + // Currently the only bound which is incompatible with other bounds is + // Sized/Unsized. + if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) { + ty::each_bound_trait_and_supertraits(tcx, + 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))); + } + } + true + }); + } + } } pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index a5d41b15d5d31..bb9c6a87babda 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -878,6 +878,8 @@ impl<'a> Rebuilder<'a> { id: ty_param.id, bounds: bounds, default: ty_param.default, + span: ty_param.span, + sized: ty_param.sized, } }) } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 9e7c221d3c55f..5485cddb4763a 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -347,7 +347,7 @@ impl<'a> Visitor<()> for TermsContext<'a> { match item.node { ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(ref generics, _, _) => { + ast::ItemTrait(ref generics, _, _, _) => { for (i, p) in generics.lifetimes.iter().enumerate() { self.add_inferred(item.id, RegionParam, i, p.id); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 7de898a50a9e3..3fc65dd9647cd 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -261,7 +261,7 @@ impl<'a> RustdocVisitor<'a> { }; om.statics.push(s); }, - ast::ItemTrait(ref gen, ref tr, ref met) => { + ast::ItemTrait(ref gen, _, ref tr, ref met) => { let t = Trait { name: item.ident, methods: met.iter().map(|x| (*x).clone()).collect(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5d0b24fdb3ec3..97ddff787899f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -180,6 +180,7 @@ pub enum TyParamBound { pub struct TyParam { pub ident: Ident, pub id: NodeId, + pub sized: Sized, pub bounds: OwnedSlice, pub default: Option>, pub span: Span @@ -1051,6 +1052,12 @@ impl Visibility { } } +#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)] +pub enum Sized { + DynSize, + StaticSize, +} + #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)] pub struct StructField_ { pub kind: StructFieldKind, @@ -1109,7 +1116,7 @@ pub enum Item_ { ItemTy(P, Generics), ItemEnum(EnumDef, Generics), ItemStruct(@StructDef, Generics), - ItemTrait(Generics, Vec , Vec ), + ItemTrait(Generics, Sized, Vec , Vec ), ItemImpl(Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 45954800e7e9a..d0e3ff4ae546a 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -265,6 +265,24 @@ impl Map { } } + pub fn expect_struct(&self, id: NodeId) -> @StructDef { + match self.find(id) { + Some(NodeItem(i)) => { + match i.node { + ItemStruct(struct_def, _) => struct_def, + _ => fail!("struct ID bound to non-struct") + } + } + Some(NodeVariant(ref variant)) => { + match (*variant).node.kind { + StructVariantKind(struct_def) => struct_def, + _ => fail!("struct ID bound to enum variant that isn't struct-like"), + } + } + _ => fail!(format!("expected struct, found {}", self.node_to_str(id))), + } + } + pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem { match self.find(id) { Some(NodeForeignItem(item)) => item, @@ -453,7 +471,7 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> { None => {} } } - ItemTrait(_, ref traits, ref methods) => { + ItemTrait(_, _, ref traits, ref methods) => { for t in traits.iter() { self.insert(t.ref_id, EntryItem(self.parent, i)); } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index c1289ef98588a..e1174ea6cc434 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -68,6 +68,7 @@ pub trait AstBuilder { fn typaram(&self, span: Span, id: ast::Ident, + sized: ast::Sized, bounds: OwnedSlice, default: Option>) -> ast::TyParam; @@ -371,11 +372,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn typaram(&self, span: Span, id: ast::Ident, + sized: ast::Sized, bounds: OwnedSlice, default: Option>) -> ast::TyParam { ast::TyParam { ident: id, id: ast::DUMMY_NODE_ID, + sized: sized, bounds: bounds, default: default, span: span diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 579de82c8db37..35a1eb0bb8381 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -13,6 +13,7 @@ The compiler code necessary for `#[deriving(Decodable)]`. See encodable.rs for more. */ +use ast; use ast::{MetaItem, Item, Expr, MutMutable, Ident}; use codemap::Span; use ext::base::ExtCtxt; @@ -35,10 +36,10 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( + bounds: vec!(("__D", ast::StaticSize, vec!(Path::new_( vec!("serialize", "Decoder"), None, vec!(~Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) + ("__E", ast::StaticSize, vec!())) }, methods: vec!( MethodDef { diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 1c3edce96fb1d..806560f6826ad 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -82,6 +82,7 @@ would yield functions like: ``` */ +use ast; use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil}; use codemap::Span; use ext::base::ExtCtxt; @@ -103,10 +104,10 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( + bounds: vec!(("__S", ast::StaticSize, vec!(Path::new_( vec!("serialize", "Encoder"), None, vec!(~Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) + ("__E", ast::StaticSize, vec!())) }, methods: vec!( MethodDef { diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index c040361a8ebb2..914451fb4024e 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -380,7 +380,11 @@ impl<'a> TraitDef<'a> { // require the current trait bounds.push(cx.typarambound(trait_path.clone())); - cx.typaram(self.span, ty_param.ident, OwnedSlice::from_vec(bounds), None) + cx.typaram(self.span, + ty_param.ident, + ty_param.sized, + OwnedSlice::from_vec(bounds), + None) })); let trait_generics = Generics { lifetimes: lifetimes, diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 23331dc03cb4f..d22027d203fac 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use ast; use ast::{MetaItem, Item, Expr, MutMutable}; use codemap::Span; use ext::base::ExtCtxt; @@ -25,7 +26,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, vec!(~Literal(Path::new_local("__S"))), true), LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new(vec!("std", "io", "Writer"))))), + bounds: vec!(("__S", ast::StaticSize, vec!(Path::new(vec!("std", "io", "Writer"))))), }, Path::new_local("__S")) } else { diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 6b824e52bb3d7..e81aa55d10d32 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -32,7 +32,8 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec!(("R", - vec!( Path::new(vec!("rand", "Rng")) ))) + ast::StaticSize, + vec!( Path::new(vec!("rand", "Rng")) ))) }, explicit_self: None, args: vec!( diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index a6bbad62b8e79..6e3327b40392e 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -186,14 +186,14 @@ impl<'a> Ty<'a> { } -fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, bounds: &[Path], +fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, sized: ast::Sized, bounds: &[Path], self_ident: Ident, self_generics: &Generics) -> ast::TyParam { let bounds = bounds.iter().map(|b| { let path = b.to_path(cx, span, self_ident, self_generics); cx.typarambound(path) }).collect(); - cx.typaram(span, cx.ident_of(name), bounds, None) + cx.typaram(span, cx.ident_of(name), sized, bounds, None) } fn mk_generics(lifetimes: Vec , ty_params: Vec ) -> Generics { @@ -206,7 +206,7 @@ fn mk_generics(lifetimes: Vec , ty_params: Vec ) - /// Lifetimes and bounds on type parameters pub struct LifetimeBounds<'a> { pub lifetimes: Vec<&'a str>, - pub bounds: Vec<(&'a str, Vec>)>, + pub bounds: Vec<(&'a str, ast::Sized, Vec>)>, } impl<'a> LifetimeBounds<'a> { @@ -226,10 +226,11 @@ impl<'a> LifetimeBounds<'a> { }).collect(); let ty_params = self.bounds.iter().map(|t| { match t { - &(ref name, ref bounds) => { + &(ref name, sized, ref bounds) => { mk_ty_param(cx, span, *name, + sized, bounds.as_slice(), self_ty, self_generics) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 72be633d456ad..04b289b9fca46 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -447,6 +447,7 @@ pub fn fold_ty_param(tp: &TyParam, fld: &mut T) -> TyParam { TyParam { ident: tp.ident, id: id, + sized: tp.sized, bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)), default: tp.default.map(|x| fld.fold_ty(x)), span: tp.span @@ -620,7 +621,7 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ methods.iter().map(|x| folder.fold_method(*x)).collect() ) } - ItemTrait(ref generics, ref traits, ref methods) => { + ItemTrait(ref generics, ref sized, ref traits, ref methods) => { let methods = methods.iter().map(|method| { match *method { Required(ref m) => Required(folder.fold_type_method(m)), @@ -628,6 +629,7 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ } }).collect(); ItemTrait(fold_generics(generics, folder), + *sized, traits.iter().map(|p| fold_trait_ref(p, folder)).collect(), methods) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 85480bebc90ef..8808312bed759 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -42,6 +42,7 @@ use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatUniq, PatWild, PatWildMulti}; use ast::{BiRem, Required}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; +use ast::{Sized, DynSize, StaticSize}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub}; use ast::StrStyle; @@ -3390,10 +3391,11 @@ impl<'a> Parser<'a> { return (ret_lifetime, Some(OwnedSlice::from_vec(result))); } - // matches typaram = IDENT optbounds ( EQ ty )? + // matches typaram = type? IDENT optbounds ( EQ ty )? fn parse_ty_param(&mut self) -> TyParam { - let ident = self.parse_ident(); + let sized = self.parse_sized(); let span = self.span; + let ident = self.parse_ident(); let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false); // For typarams we don't care about the difference b/w "" and "". let bounds = opt_bounds.unwrap_or_default(); @@ -3407,6 +3409,7 @@ impl<'a> Parser<'a> { TyParam { ident: ident, id: ast::DUMMY_NODE_ID, + sized: sized, bounds: bounds, default: default, span: span, @@ -3797,6 +3800,7 @@ impl<'a> Parser<'a> { fn parse_item_trait(&mut self) -> ItemInfo { let ident = self.parse_ident(); let tps = self.parse_generics(); + let sized = self.parse_for_sized(); // Parse traits, if necessary. let traits; @@ -3808,7 +3812,7 @@ impl<'a> Parser<'a> { } let meths = self.parse_trait_methods(); - (ident, ItemTrait(tps, traits, meths), None) + (ident, ItemTrait(tps, sized, traits, meths), None) } // Parses two variants (with the region/type params always optional): @@ -3999,6 +4003,23 @@ impl<'a> Parser<'a> { else { Inherited } } + fn parse_sized(&mut self) -> Sized { + if self.eat_keyword(keywords::Type) { DynSize } + else { StaticSize } + } + + fn parse_for_sized(&mut self) -> Sized { + if self.eat_keyword(keywords::For) { + if !self.eat_keyword(keywords::Type) { + self.span_err(self.last_span, + "expected 'type' after for in trait item"); + } + DynSize + } else { + StaticSize + } + } + // given a termination token and a vector of already-parsed // attributes (of length 0 or 1), parse all of the items in a module fn parse_mod_items(&mut self, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f4e337e2048f3..57438169d6da3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -673,10 +673,13 @@ impl<'a> State<'a> { } try!(self.bclose(item.span)); } - ast::ItemTrait(ref generics, ref traits, ref methods) => { + ast::ItemTrait(ref generics, ref sized, ref traits, ref methods) => { try!(self.head(visibility_qualified(item.vis, "trait"))); try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); + if *sized == ast::DynSize { + try!(self.word_space("for type")); + } if traits.len() != 0u { try!(word(&mut self.s, ":")); for (i, trait_) in traits.iter().enumerate() { @@ -1910,6 +1913,9 @@ impl<'a> State<'a> { } else { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); + if param.sized == ast::DynSize { + try!(s.word_space("type")); + } try!(s.print_ident(param.ident)); try!(s.print_bounds(&None, ¶m.bounds, false)); match param.default { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 1f75c2e062ff0..e830daf8edeb6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -257,7 +257,7 @@ pub fn walk_item>(visitor: &mut V, item: &Item, env: E) item.id, env) } - ItemTrait(ref generics, ref trait_paths, ref methods) => { + ItemTrait(ref generics, _, ref trait_paths, ref methods) => { visitor.visit_generics(generics, env.clone()); for trait_path in trait_paths.iter() { visitor.visit_path(&trait_path.path, diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs index 1b72e46842862..58ed6624cbf3b 100644 --- a/src/test/compile-fail/bad-mid-path-type-params.rs +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -12,6 +12,9 @@ #![no_std] +#[lang="sized"] +pub trait Sized {} + struct S { contents: T, } diff --git a/src/test/compile-fail/borrowck-move-subcomponent.rs b/src/test/compile-fail/borrowck-move-subcomponent.rs index f6ca6ac42b2fe..6940c85e0e63d 100644 --- a/src/test/compile-fail/borrowck-move-subcomponent.rs +++ b/src/test/compile-fail/borrowck-move-subcomponent.rs @@ -13,6 +13,9 @@ #![no_std] +#[lang="sized"] +pub trait Sized {} + struct S { x : ~int } diff --git a/src/test/compile-fail/lint-dead-code-1.rs b/src/test/compile-fail/lint-dead-code-1.rs index 04326403376f8..bbcc59f0d6cbd 100644 --- a/src/test/compile-fail/lint-dead-code-1.rs +++ b/src/test/compile-fail/lint-dead-code-1.rs @@ -17,6 +17,10 @@ #![crate_type="lib"] pub use foo2::Bar2; + +#[lang="sized"] +pub trait Sized {} + mod foo { pub struct Bar; //~ ERROR: code is never used } diff --git a/src/test/compile-fail/privacy1.rs b/src/test/compile-fail/privacy1.rs index 45d13bd7996a8..83141020b29e4 100644 --- a/src/test/compile-fail/privacy1.rs +++ b/src/test/compile-fail/privacy1.rs @@ -11,6 +11,9 @@ #![feature(globs)] #![no_std] // makes debugging this test *a lot* easier (during resolve) +#[lang="sized"] +pub trait Sized {} + mod bar { // shouln't bring in too much pub use self::glob::*; diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index ff9d379c30f5e..fd09d78a4fa62 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -10,5 +10,5 @@ // error-pattern: instantiating a type parameter with an incompatible type fn bar() { } -fn foo() { bar::() } +fn foo() { bar::() } fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index df7d82f0b2590..f586fbb576b32 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -10,5 +10,5 @@ // error-pattern: instantiating a type parameter with an incompatible type fn bar() { } -fn foo() { bar::>() } +fn foo() { bar::>() } fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index da3e9e1243058..9fab3accbb9de 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -13,5 +13,5 @@ struct Foo { data: T } fn bar() { } -fn foo() { bar::>() } +fn foo() { bar::>() } fn main() { } diff --git a/src/test/compile-fail/unsized.rs b/src/test/compile-fail/unsized.rs new file mode 100644 index 0000000000000..d5c2bbb21cad6 --- /dev/null +++ b/src/test/compile-fail/unsized.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test syntax checks for `type` keyword. + +struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name but found `for` + +pub fn main() { +} diff --git a/src/test/compile-fail/unsized2.rs b/src/test/compile-fail/unsized2.rs new file mode 100644 index 0000000000000..0c9d05e298832 --- /dev/null +++ b/src/test/compile-fail/unsized2.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test syntax checks for `type` keyword. + +fn f() {} + +pub fn main() { + f(); //~ ERROR found `type` in ident position +} diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs new file mode 100644 index 0000000000000..d842a28928927 --- /dev/null +++ b/src/test/compile-fail/unsized3.rs @@ -0,0 +1,51 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test sized-ness checking in substitution. + +// Unbounded. +fn f1(x: &X) { + f2::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n +} +fn f2(x: &X) { +} + +// Bounded. +trait T for type {} +fn f3(x: &X) { + f4::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n +} +fn f4(x: &X) { +} + +// I would like these to fail eventually. +/* +// impl - bounded +trait T1 { +} +struct S3; +impl T1 for S3 { //ERROR instantiating a type parameter with an incompatible type +} + +// impl - unbounded +trait T2 { +} +impl T2 for S3 { //ERROR instantiating a type parameter with an incompatible type `X` + +// impl - struct +trait T3 { +} +struct S4; +impl T3 for S4 { //ERROR instantiating a type parameter with an incompatible type `X` +} +*/ + +pub fn main() { +} diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs new file mode 100644 index 0000000000000..968716320fd5e --- /dev/null +++ b/src/test/compile-fail/unsized4.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that bounds are sized-compatible. + +trait T {} +fn f() { +//~^ERROR incompatible bounds on type parameter Y, bound T does not allow unsized type +} + +pub fn main() { +} diff --git a/src/test/run-pass/unsized.rs b/src/test/run-pass/unsized.rs new file mode 100644 index 0000000000000..e7dadd4b5eb4f --- /dev/null +++ b/src/test/run-pass/unsized.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test syntax checks for `type` keyword. + +trait T1 for type {} +pub trait T2 for type {} +trait T3 for type: T2 {} +trait T4 {} +trait T5 {} +trait T6 {} +trait T7 {} +trait T8 {} +struct S1; +impl T1 for S1 {} +fn f() {} + +pub fn main() { +} diff --git a/src/test/run-pass/unsized2.rs b/src/test/run-pass/unsized2.rs new file mode 100644 index 0000000000000..c8e8f98145fe8 --- /dev/null +++ b/src/test/run-pass/unsized2.rs @@ -0,0 +1,82 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test sized-ness checking in substitution. + +// Unbounded. +fn f1(x: &X) { + f1::(x); +} +fn f2(x: &X) { + f1::(x); + f2::(x); +} + +// Bounded. +trait T for type {} +fn f3(x: &X) { + f3::(x); +} +fn f4(x: &X) { + f3::(x); + f4::(x); +} + +// Self type. +trait T2 for type { + fn f() -> ~Self; +} +struct S; +impl T2 for S { + fn f() -> ~S { + ~S + } +} +fn f5(x: &X) { + let _: ~X = T2::f(); +} +fn f6(x: &X) { + let _: ~X = T2::f(); +} + +trait T3 for type { + fn f() -> ~Self; +} +impl T3 for S { + fn f() -> ~S { + ~S + } +} +fn f7(x: &X) { + // This is valid, but the unsized bound on X is irrelevant because any type + // which implements T3 must have statically known size. + let _: ~X = T3::f(); +} + +trait T4 { + fn m1(x: &T4); + fn m2(x: &T5); +} +trait T5 { + fn m1(x: &T4); // not an error (for now) + fn m2(x: &T5); +} + +trait T6 { + fn m1(x: &T4); + fn m2(x: &T5); +} +trait T7 { + fn m1(x: &T4); // not an error (for now) + fn m2(x: &T5); +} + +pub fn main() { +}