diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 2fa0ab9072c..9bff6620aaa 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -109,12 +109,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, b, ref c, ref methods) => { + ast::ItemTrait(ref a, ref 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, (*c).clone(), methods) + ast::ItemTrait((*a).clone(), (*b).clone(), (*c).clone(), methods) } ast::ItemStruct(ref def, ref generics) => { ast::ItemStruct(fold_struct(cx, &**def), generics.clone()) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index f88c0d34ed8..d16f24a0ad1 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -164,19 +164,6 @@ 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| { @@ -393,7 +380,6 @@ 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::empty_builtin_bounds(); // Collect the builtin bounds from the encoded supertraits. // FIXME(#8559): They should be encoded directly. @@ -405,12 +391,6 @@ 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 {types: tp_defs, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 21713672f81..0ec9e31872b 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -881,16 +881,6 @@ 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).as_slice()); - ebml_w.end_tag(); -} - fn encode_stability(ebml_w: &mut Encoder, stab_opt: Option) { stab_opt.map(|stab| { ebml_w.start_tag(tag_items_data_item_stability); @@ -1149,7 +1139,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ast_method) } } - ItemTrait(_, sized, ref super_traits, ref ms) => { + ItemTrait(_, _, 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); @@ -1163,9 +1153,6 @@ 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); encode_stability(ebml_w, stab); for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 30a513407a5..c2f4d2ff6b1 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -3598,6 +3598,7 @@ impl<'a> Resolver<'a> { item.id, ItemRibKind), |this| { + this.resolve_type_parameters(&generics.ty_params); visit::walk_item(this, item, ()); }); } @@ -3623,7 +3624,7 @@ impl<'a> Resolver<'a> { methods.as_slice()); } - ItemTrait(ref generics, _, ref traits, ref methods) => { + ItemTrait(ref generics, ref unbound, ref traits, ref methods) => { // Create a new rib for the self type. let self_type_rib = Rib::new(ItemRibKind); @@ -3645,6 +3646,12 @@ impl<'a> Resolver<'a> { for trt in traits.iter() { this.resolve_trait_reference(item.id, trt, TraitDerivation); } + match unbound { + &Some(ast::TraitTyParamBound(ref tpb)) => { + this.resolve_trait_reference(item.id, tpb, TraitDerivation); + } + _ => {} + } for method in (*methods).iter() { // Create a new rib for the method-specific type @@ -3856,11 +3863,15 @@ impl<'a> Resolver<'a> { } fn resolve_type_parameters(&mut self, - type_parameters: &OwnedSlice) { + type_parameters: &OwnedSlice) { for type_parameter in type_parameters.iter() { for bound in type_parameter.bounds.iter() { self.resolve_type_parameter_bound(type_parameter.id, bound); } + match &type_parameter.unbound { + &Some(ref unbound) => self.resolve_type_parameter_bound(type_parameter.id, unbound), + &None => {} + } match type_parameter.default { Some(ref ty) => self.resolve_type(&**ty), None => {} @@ -3887,9 +3898,9 @@ impl<'a> Resolver<'a> { } fn resolve_trait_reference(&mut self, - id: NodeId, - trait_reference: &TraitRef, - reference_type: TraitReferenceType) { + id: NodeId, + trait_reference: &TraitRef, + reference_type: TraitReferenceType) { match self.resolve_path(id, &trait_reference.path, TypeNS, true) { None => { let path_str = self.path_idents_to_str(&trait_reference.path); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index bf88ec5c438..7b871cbe0fe 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -692,9 +692,9 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { _ => {} } - let (generics, sized, supertraits) = match it.node { - ast::ItemTrait(ref generics, sized, ref supertraits, _) => { - (generics, sized, supertraits) + let (generics, unbound, supertraits) = match it.node { + ast::ItemTrait(ref generics, ref unbound, ref supertraits, _) => { + (generics, unbound, supertraits) } ref s => { tcx.sess.span_bug( @@ -711,7 +711,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { generics); let builtin_bounds = - ensure_supertraits(ccx, it.id, it.span, supertraits, sized); + ensure_supertraits(ccx, it.id, it.span, supertraits, unbound); let substs = mk_item_substs(ccx, &ty_generics); let trait_def = Rc::new(ty::TraitDef { @@ -759,7 +759,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { id: ast::NodeId, sp: codemap::Span, ast_trait_refs: &Vec, - sized: ast::Sized) + unbound: &Option) -> ty::BuiltinBounds { let tcx = ccx.tcx; @@ -798,15 +798,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { } } - 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.as_slice()), - }; - } - + add_unsized_bound(ccx, unbound, &mut bounds, "trait", sp); tcx.supertraits.borrow_mut().insert(local_def(id), Rc::new(ty_trait_refs)); bounds @@ -974,6 +966,43 @@ fn ty_generics_for_fn_or_method(ccx: &CrateCtxt, &generics.ty_params, base_generics) } +// Add the Sized bound, unless the type parameter is marked as `Sized?`. +fn add_unsized_bound(ccx: &CrateCtxt, + unbound: &Option, + bounds: &mut ty::BuiltinBounds, + desc: &str, + span: Span) { + let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem); + match unbound { + &Some(TraitTyParamBound(ref tpb)) => { + // #FIXME(8559) currently requires the unbound to be built-in. + let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb); + match kind_id { + Ok(kind_id) if trait_def_id != kind_id => { + ccx.tcx.sess.span_warn(span, + format!("default bound relaxed \ + for a {}, but this does \ + nothing because the given \ + bound is not a default. \ + Only `Sized?` is supported.", + desc).as_slice()); + ty::try_add_builtin_trait(ccx.tcx, + kind_id, + bounds); + } + _ => {} + } + } + _ if kind_id.is_ok() => { + ty::try_add_builtin_trait(ccx.tcx, + kind_id.unwrap(), + bounds); + } + // No lang item for Sized, so we can't add it as a bound. + _ => {} + } +} + fn ty_generics(ccx: &CrateCtxt, space: subst::ParamSpace, lifetimes: &Vec, @@ -1016,7 +1045,7 @@ fn ty_generics(ccx: &CrateCtxt, let bounds = Rc::new(compute_bounds(ccx, param_ty, ¶m.bounds, - param.sized, + ¶m.unbound, param.ident, param.span)); let default = param.default.map(|path| { @@ -1056,7 +1085,7 @@ fn ty_generics(ccx: &CrateCtxt, ccx: &CrateCtxt, param_ty: ty::ParamTy, ast_bounds: &OwnedSlice, - sized: ast::Sized, + unbound: &Option, ident: ast::Ident, span: Span) -> ty::ParamBounds { @@ -1113,15 +1142,11 @@ 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), - } - } + add_unsized_bound(ccx, + unbound, + &mut param_bounds.builtin_bounds, + "type parameter", + span); check_bounds_compatible(ccx.tcx, ¶m_bounds, ident, span); diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 053a75e7260..35661c14aeb 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -895,9 +895,9 @@ impl<'a> Rebuilder<'a> { ident: ty_param.ident, id: ty_param.id, bounds: bounds, + unbound: ty_param.unbound.clone(), default: ty_param.default, span: ty_param.span, - sized: ty_param.sized, } }) } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index daa9ee3da84..82bb1bd58a6 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -110,7 +110,7 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, // miscellaneous, no highlighting t::DOT | t::DOTDOT | t::DOTDOTDOT | t::COMMA | t::SEMI | t::COLON | t::MOD_SEP | t::LARROW | t::LPAREN | - t::RPAREN | t::LBRACKET | t::LBRACE | t::RBRACE => "", + t::RPAREN | t::LBRACKET | t::LBRACE | t::RBRACE | t::QUESTION => "", t::DOLLAR => { if t::is_ident(&lexer.peek().tok) { is_macro_nonterminal = true; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ce1302c8db8..76dbae48839 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -184,8 +184,8 @@ pub enum TyParamBound { pub struct TyParam { pub ident: Ident, pub id: NodeId, - pub sized: Sized, pub bounds: OwnedSlice, + pub unbound: Option, pub default: Option>, pub span: Span } @@ -1041,12 +1041,6 @@ impl Visibility { } } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] -pub enum Sized { - DynSize, - StaticSize, -} - #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] pub struct StructField_ { pub kind: StructFieldKind, @@ -1115,7 +1109,11 @@ pub enum Item_ { ItemEnum(EnumDef, Generics), ItemStruct(Gc, Generics), /// Represents a Trait Declaration - ItemTrait(Generics, Sized, Vec , Vec ), + ItemTrait(Generics, + Option, // (optional) default bound not required for Self. + // Currently, only Sized makes sense here. + Vec , + Vec), ItemImpl(Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 46bc4ec11ce..4d79ff3257a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -66,8 +66,8 @@ pub trait AstBuilder { fn typaram(&self, span: Span, id: ast::Ident, - sized: ast::Sized, bounds: OwnedSlice, + unbound: Option, default: Option>) -> ast::TyParam; fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; @@ -396,14 +396,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn typaram(&self, span: Span, id: ast::Ident, - sized: ast::Sized, bounds: OwnedSlice, + unbound: Option, default: Option>) -> ast::TyParam { ast::TyParam { ident: id, id: ast::DUMMY_NODE_ID, - sized: sized, bounds: bounds, + unbound: unbound, default: default, span: span } @@ -423,7 +423,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn strip_bounds(&self, generics: &Generics) -> Generics { let new_params = generics.ty_params.map(|ty_param| { - ast::TyParam { bounds: OwnedSlice::empty(), ..*ty_param } + ast::TyParam { bounds: OwnedSlice::empty(), unbound: None, ..*ty_param } }); Generics { ty_params: new_params, diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 0c23d65fde0..6da5f1e2700 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -13,7 +13,6 @@ 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; @@ -39,10 +38,10 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__D", ast::StaticSize, vec!(Path::new_( + bounds: vec!(("__D", None, vec!(Path::new_( vec!("serialize", "Decoder"), None, vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", ast::StaticSize, vec!())) + ("__E", None, vec!())) }, methods: vec!( MethodDef { diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index f57670af199..652d593c004 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -82,7 +82,6 @@ would yield functions like: ``` */ -use ast; use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil}; use codemap::Span; use ext::base::ExtCtxt; @@ -107,10 +106,10 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", ast::StaticSize, vec!(Path::new_( + bounds: vec!(("__S", None, vec!(Path::new_( vec!("serialize", "Encoder"), None, vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", ast::StaticSize, vec!())) + ("__E", None, vec!())) }, methods: vec!( MethodDef { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 157b64fb47c..7ad11b186f5 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -406,8 +406,8 @@ impl<'a> TraitDef<'a> { cx.typaram(self.span, ty_param.ident, - ty_param.sized, OwnedSlice::from_vec(bounds), + ty_param.unbound.clone(), None) })); let trait_generics = Generics { diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index 7501b950770..28f39a4cb8c 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -188,17 +188,18 @@ impl<'a> Ty<'a> { } -fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, sized: ast::Sized, bounds: &[Path], +fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, + bounds: &[Path], unbound: Option, 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), sized, bounds, None) + cx.typaram(span, cx.ident_of(name), bounds, unbound, None) } -fn mk_generics(lifetimes: Vec , ty_params: Vec ) -> Generics { +fn mk_generics(lifetimes: Vec, ty_params: Vec ) -> Generics { Generics { lifetimes: lifetimes, ty_params: OwnedSlice::from_vec(ty_params) @@ -208,7 +209,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, ast::Sized, Vec>)>, + pub bounds: Vec<(&'a str, Option, Vec>)>, } impl<'a> LifetimeBounds<'a> { @@ -228,12 +229,12 @@ impl<'a> LifetimeBounds<'a> { }).collect(); let ty_params = self.bounds.iter().map(|t| { match t { - &(ref name, sized, ref bounds) => { + &(ref name, ref unbound, ref bounds) => { mk_ty_param(cx, span, *name, - sized, bounds.as_slice(), + unbound.clone(), self_ty, self_generics) } diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 77fb013b269..1b3ac47092a 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -8,7 +8,6 @@ // 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; @@ -30,7 +29,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, vec!(box Literal(Path::new_local("__S"))), true), LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", ast::StaticSize, + bounds: vec!(("__S", None, vec!(Path::new(vec!("std", "hash", "Writer"))))), }, Path::new_local("__S")) diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index f6a15ea917e..34b5f120d6a 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -35,7 +35,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec!(("R", - ast::StaticSize, + None, vec!( Path::new(vec!("std", "rand", "Rng")) ))) }, explicit_self: None, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 04e6612daf1..80dd4a83e48 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -491,8 +491,8 @@ 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)), + unbound: tp.unbound.as_ref().map(|x| fold_ty_param_bound(x, fld)), default: tp.default.map(|x| fld.fold_ty(x)), span: tp.span } @@ -666,7 +666,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 sized, ref traits, ref methods) => { + ItemTrait(ref generics, ref unbound, ref traits, ref methods) => { let methods = methods.iter().map(|method| { match *method { Required(ref m) => Required(folder.fold_type_method(m)), @@ -674,7 +674,7 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ } }).collect(); ItemTrait(fold_generics(generics, folder), - *sized, + unbound.clone(), traits.iter().map(|p| fold_trait_ref(p, folder)).collect(), methods) } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 0f188fdf18a..1e72b2de20f 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -849,6 +849,7 @@ impl<'a> StringReader<'a> { '@' => { self.bump(); return token::AT; } '#' => { self.bump(); return token::POUND; } '~' => { self.bump(); return token::TILDE; } + '?' => { self.bump(); return token::QUESTION; } ':' => { self.bump(); if self.curr_is(':') { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6b6387b0127..3119d341281 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -42,7 +42,6 @@ use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, 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; @@ -3564,11 +3563,40 @@ impl<'a> Parser<'a> { return (ret_lifetime, OwnedSlice::from_vec(result)); } - // matches typaram = type? IDENT optbounds ( EQ ty )? + fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { + let segment = ast::PathSegment { + identifier: ident, + lifetimes: Vec::new(), + types: OwnedSlice::empty(), + }; + let path = ast::Path { + span: span, + global: false, + segments: vec![segment], + }; + ast::TraitRef { + path: path, + ref_id: ast::DUMMY_NODE_ID, + } + } + + // matches typaram = (unbound`?`)? IDENT optbounds ( EQ ty )? fn parse_ty_param(&mut self) -> TyParam { - let sized = self.parse_sized(); - let span = self.span; - let ident = self.parse_ident(); + // This is a bit hacky. Currently we are only interested in a single + // unbound, and it may only be `Sized`. To avoid backtracking and other + // complications, we parse an ident, then check for `?`. If we find it, + // we use the ident as the unbound, otherwise, we use it as the name of + // type param. + let mut span = self.span; + let mut ident = self.parse_ident(); + let mut unbound = None; + if self.eat(&token::QUESTION) { + let tref = Parser::trait_ref_from_ident(ident, span); + unbound = Some(TraitTyParamBound(tref)); + span = self.span; + ident = self.parse_ident(); + } + let opt_bounds = { if self.eat(&token::COLON) { let (_, bounds) = self.parse_ty_param_bounds(false); @@ -3589,8 +3617,8 @@ impl<'a> Parser<'a> { TyParam { ident: ident, id: ast::DUMMY_NODE_ID, - sized: sized, bounds: bounds, + unbound: unbound, default: default, span: span, } @@ -4209,21 +4237,19 @@ 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 { + fn parse_for_sized(&mut self) -> Option { if self.eat_keyword(keywords::For) { - if !self.eat_keyword(keywords::Type) { - let last_span = self.last_span; - self.span_err(last_span, - "expected 'type' after for in trait item"); + let span = self.span; + let ident = self.parse_ident(); + if !self.eat(&token::QUESTION) { + self.span_err(span, + "expected 'Sized?' after `for` in trait item"); + return None; } - DynSize + let tref = Parser::trait_ref_from_ident(ident, span); + Some(TraitTyParamBound(tref)) } else { - StaticSize + None } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index dcf37e37ff0..367b18916ac 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -76,6 +76,7 @@ pub enum Token { RBRACE, POUND, DOLLAR, + QUESTION, /* Literals */ LIT_BYTE(u8), @@ -195,6 +196,7 @@ pub fn to_str(t: &Token) -> String { RBRACE => "}".to_string(), POUND => "#".to_string(), DOLLAR => "$".to_string(), + QUESTION => "?".to_string(), /* Literals */ LIT_BYTE(b) => { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index bf210110829..cdaa9bbd8dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -740,14 +740,19 @@ impl<'a> State<'a> { } try!(self.bclose(item.span)); } - ast::ItemTrait(ref generics, ref sized, ref traits, ref methods) => { + ast::ItemTrait(ref generics, ref unbound, ref traits, ref methods) => { try!(self.head(visibility_qualified(item.vis, "trait").as_slice())); try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); - if *sized == ast::DynSize { - try!(space(&mut self.s)); - try!(word(&mut self.s, "for type")); + match unbound { + &Some(TraitTyParamBound(ref tref)) => { + try!(space(&mut self.s)); + try!(self.word_space("for")); + try!(self.print_trait_ref(tref)); + try!(word(&mut self.s, "?")); + } + _ => {} } if traits.len() != 0u { try!(word(&mut self.s, ":")); @@ -2029,8 +2034,12 @@ 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")); + match param.unbound { + Some(TraitTyParamBound(ref tref)) => { + try!(s.print_trait_ref(tref)); + try!(s.word_space("?")); + } + _ => {} } try!(s.print_ident(param.ident)); try!(s.print_bounds(&None, diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index fd09d78a4fa..6fd749b1298 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 f586fbb576b..651eb26cadc 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 9fab3accbb9..ec6aafb43f4 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/unsized3.rs b/src/test/compile-fail/unsized3.rs index c5cc7e8f716..c07dcf93683 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -12,45 +12,45 @@ // Unbounded. -fn f1(x: &X) { +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) { +trait T for Sized? {} +fn f3(x: &X) { f4::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n } fn f4(x: &X) { } // Test with unsized enum. -enum E { +enum E { V(X), } fn f5(x: &Y) {} -fn f6(x: &X) {} -fn f7(x1: &E, x2: &E) { +fn f6(x: &X) {} +fn f7(x1: &E, x2: &E) { f5(x1); //~ERROR instantiating a type parameter with an incompatible type `E`, which does not f6(x2); // ok } // Test with unsized struct. -struct S { +struct S { x: X, } -fn f8(x1: &S, x2: &S) { +fn f8(x1: &S, x2: &S) { f5(x1); //~ERROR instantiating a type parameter with an incompatible type `S`, which does not f6(x2); // ok } // Test some tuples. -fn f9(x1: Box>, x2: Box>) { +fn f9(x1: Box>, x2: Box>) { f5(&(*x1, 34i)); //~ERROR instantiating a type parameter with an incompatible type `(S,int)`, f5(&(32i, *x2)); //~ERROR instantiating a type parameter with an incompatible type `(int,E)`, } @@ -60,20 +60,20 @@ fn f9(x1: Box>, x2: Box>) { // impl - bounded trait T1 { } -struct S3; -impl T1 for S3 { //ERROR instantiating a type parameter with an incompatible type +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 T2 for S3 { //ERROR instantiating a type parameter with an incompatible type `X // impl - struct -trait T3 { +trait T3 { } struct S4; -impl T3 for S4 { //ERROR instantiating a type parameter with an incompatible type `X` +impl T3 for S4 { //ERROR instantiating a type parameter with an incompatible type `X } */ diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs index 968716320fd..e377c9d5f41 100644 --- a/src/test/compile-fail/unsized4.rs +++ b/src/test/compile-fail/unsized4.rs @@ -11,7 +11,7 @@ // Test that bounds are sized-compatible. trait T {} -fn f() { +fn f() { //~^ERROR incompatible bounds on type parameter Y, bound T does not allow unsized type } diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index 614b8e3a5ab..7028f7e798b 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -9,19 +9,19 @@ // except according to those terms. #![feature(struct_variant)] -// Test `type` types not allowed in fields. +// Test `Sized?` types not allowed in fields. -struct S1 { +struct S1 { f1: X, //~ ERROR type `f1` is dynamically sized. dynamically sized types may only appear as the f2: int, } -struct S2 { +struct S2 { f: int, g: X, //~ ERROR type `g` is dynamically sized. dynamically sized types may only appear as the ty h: int, } -enum E { +enum E { 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 } diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 061b003b5e3..def1146526b 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -8,37 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test `type` local variables. +// Test `Sized?` local variables. -trait T for type {} +trait T for Sized? {} -fn f1(x: &X) { +fn f1(x: &X) { let _: X; //~ERROR variable `_` has dynamically sized type `X` let _: (int, (X, int)); //~ERROR variable `_` has dynamically sized type `(int,(X,int))` let y: X; //~ERROR variable `y` has dynamically sized type `X` let y: (int, (X, int)); //~ERROR variable `y` has dynamically sized type `(int,(X,int))` } -fn f2(x: &X) { +fn f2(x: &X) { let _: X; //~ERROR variable `_` has dynamically sized type `X` let _: (int, (X, int)); //~ERROR variable `_` has dynamically sized type `(int,(X,int))` let y: X; //~ERROR variable `y` has dynamically sized type `X` let y: (int, (X, int)); //~ERROR variable `y` has dynamically sized type `(int,(X,int))` } -fn f3(x1: Box, x2: Box, x3: Box) { +fn f3(x1: Box, x2: Box, x3: Box) { let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` let y = *x2; //~ERROR variable `y` has dynamically sized type `X` let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` } -fn f4(x1: Box, x2: Box, x3: Box) { +fn f4(x1: Box, x2: Box, x3: Box) { let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` let y = *x2; //~ERROR variable `y` has dynamically sized type `X` let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` } -fn g1(x: X) {} //~ERROR variable `x` has dynamically sized type `X` -fn g2(x: X) {} //~ERROR variable `x` has dynamically sized type `X` +fn g1(x: X) {} //~ERROR variable `x` has dynamically sized type `X` +fn g2(x: X) {} //~ERROR variable `x` has dynamically sized type `X` pub fn main() { } diff --git a/src/test/run-pass/unsized.rs b/src/test/run-pass/unsized.rs index db0cc83d786..f49e8f46e78 100644 --- a/src/test/run-pass/unsized.rs +++ b/src/test/run-pass/unsized.rs @@ -8,20 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test syntax checks for `type` keyword. +// Test syntax checks for `Sized?` syntax. -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; -enum E {} -impl T1 for S1 {} -fn f() {} +trait T1 for Sized? {} +pub trait T2 for Sized? {} +trait T3 for Sized?: T2 {} +trait T4 {} +trait T5 {} +trait T6 {} +trait T7 {} +trait T8 {} +struct S1; +enum E {} +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 index 53db7f37e8d..9703b55cda7 100644 --- a/src/test/run-pass/unsized2.rs +++ b/src/test/run-pass/unsized2.rs @@ -13,7 +13,7 @@ // Test sized-ness checking in substitution. // Unbounded. -fn f1(x: &X) { +fn f1(x: &X) { f1::(x); } fn f2(x: &X) { @@ -22,8 +22,8 @@ fn f2(x: &X) { } // Bounded. -trait T for type {} -fn f3(x: &X) { +trait T for Sized? {} +fn f3(x: &X) { f3::(x); } fn f4(x: &X) { @@ -32,7 +32,7 @@ fn f4(x: &X) { } // Self type. -trait T2 for type { +trait T2 for Sized? { fn f() -> Box; } struct S; @@ -41,14 +41,14 @@ impl T2 for S { box S } } -fn f5(x: &X) { +fn f5(x: &X) { let _: Box = T2::f(); } fn f6(x: &X) { let _: Box = T2::f(); } -trait T3 for type { +trait T3 for Sized? { fn f() -> Box; } impl T3 for S { @@ -56,7 +56,7 @@ impl T3 for S { box S } } -fn f7(x: &X) { +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 _: Box = T3::f(); @@ -66,7 +66,7 @@ trait T4 { fn m1(x: &T4); fn m2(x: &T5); } -trait T5 { +trait T5 { // not an error (for now) fn m1(x: &T4); fn m2(x: &T5); @@ -76,21 +76,21 @@ trait T6 { fn m1(x: &T4); fn m2(x: &T5); } -trait T7 { +trait T7 { // not an error (for now) fn m1(x: &T4); fn m2(x: &T5); } // The last field in a struct or variant may be unsized -struct S2 { +struct S2 { f: X, } -struct S3 { +struct S3 { f1: int, f2: X, } -enum E { +enum E { V1(X), V2{x: X}, V3(int, X),