diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 34 | ||||
| -rw-r--r-- | src/libsyntax/ast_map/blocks.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/ast_map/mod.rs | 108 | ||||
| -rw-r--r-- | src/libsyntax/ast_util.rs | 57 | ||||
| -rw-r--r-- | src/libsyntax/config.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 26 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 135 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 244 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 42 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 27 |
11 files changed, 530 insertions, 155 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5546f868ba0..eac158e664c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -555,6 +555,18 @@ pub enum Expr_ { ExprParen(P<Expr>) } +/// A "qualified path": +/// +/// <Vec<T> as SomeTrait>::SomeAssociatedItem +/// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~ +/// for_type trait_name item_name +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct QPath { + pub for_type: P<Ty>, + pub trait_name: Path, + pub item_name: Ident, +} + #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum CaptureClause { CaptureByValue, @@ -766,11 +778,31 @@ pub struct TypeMethod { pub enum TraitItem { RequiredMethod(TypeMethod), ProvidedMethod(P<Method>), + TypeTraitItem(P<AssociatedType>), } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum ImplItem { MethodImplItem(P<Method>), + TypeImplItem(P<Typedef>), +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct AssociatedType { + pub id: NodeId, + pub span: Span, + pub ident: Ident, + pub attrs: Vec<Attribute>, +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct Typedef { + pub id: NodeId, + pub span: Span, + pub ident: Ident, + pub vis: Visibility, + pub attrs: Vec<Attribute>, + pub typ: P<Ty>, } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)] @@ -917,6 +949,8 @@ pub enum Ty_ { TyUnboxedFn(P<UnboxedFnTy>), TyTup(Vec<P<Ty>> ), TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above + /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType` + TyQPath(P<QPath>), /// No-op; kept solely so that we can pretty-print faithfully TyParen(P<Ty>), TyTypeof(P<Expr>), diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 1400e494917..8280f34615f 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -207,6 +207,9 @@ impl<'a> FnLikeNode<'a> { ast_map::NodeImplItem(ii) => { match *ii { ast::MethodImplItem(ref m) => method(&**m), + ast::TypeImplItem(_) => { + fail!("impl method FnLikeNode that is not fn-like") + } } } ast_map::NodeExpr(e) => match e.node { diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index ed0b8700bf3..a5458461a8b 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -11,11 +11,11 @@ use abi; use ast::*; use ast_util; -use ast_util::PostExpansionMethod; use codemap::{DUMMY_SP, Span, Spanned}; use fold::Folder; use parse::token; use print::pprust; +use ptr::P; use visit::{mod, Visitor}; use arena::TypedArena; @@ -391,16 +391,20 @@ impl<'ast> Map<'ast> { } } } + TypeImplItem(ref t) => PathName(t.ident.name), } }, NodeTraitItem(tm) => match *tm { RequiredMethod(ref m) => PathName(m.ident.name), - ProvidedMethod(ref m) => match m.node { - MethDecl(ident, _, _, _, _, _, _, _) => { - PathName(ident.name) + ProvidedMethod(ref m) => { + match m.node { + MethDecl(ident, _, _, _, _, _, _, _) => { + PathName(ident.name) + } + MethMac(_) => fail!("no path elem for {:?}", node), } - MethMac(_) => fail!("no path elem for {:?}", node), } + TypeTraitItem(ref m) => PathName(m.ident.name), }, NodeVariant(v) => PathName(v.node.name.name), _ => fail!("no path elem for {:?}", node) @@ -459,11 +463,13 @@ impl<'ast> Map<'ast> { NodeForeignItem(fi) => Some(fi.attrs.as_slice()), NodeTraitItem(ref tm) => match **tm { RequiredMethod(ref type_m) => Some(type_m.attrs.as_slice()), - ProvidedMethod(ref m) => Some(m.attrs.as_slice()) + ProvidedMethod(ref m) => Some(m.attrs.as_slice()), + TypeTraitItem(ref typ) => Some(typ.attrs.as_slice()), }, NodeImplItem(ref ii) => { match **ii { MethodImplItem(ref m) => Some(m.attrs.as_slice()), + TypeImplItem(ref t) => Some(t.attrs.as_slice()), } } NodeVariant(ref v) => Some(v.node.attrs.as_slice()), @@ -503,11 +509,13 @@ impl<'ast> Map<'ast> { match *trait_method { RequiredMethod(ref type_method) => type_method.span, ProvidedMethod(ref method) => method.span, + TypeTraitItem(ref typedef) => typedef.span, } } Some(NodeImplItem(ref impl_item)) => { match **impl_item { MethodImplItem(ref method) => method.span, + TypeImplItem(ref typedef) => typedef.span, } } Some(NodeVariant(variant)) => variant.span, @@ -633,6 +641,7 @@ impl Named for TraitItem { match *self { RequiredMethod(ref tm) => tm.ident.name, ProvidedMethod(ref m) => m.name(), + TypeTraitItem(ref at) => at.ident.name, } } } @@ -640,6 +649,7 @@ impl Named for ImplItem { fn name(&self) -> Name { match *self { MethodImplItem(ref m) => m.name(), + TypeImplItem(ref td) => td.ident.name, } } } @@ -712,10 +722,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { match i.node { ItemImpl(_, _, _, ref impl_items) => { for impl_item in impl_items.iter() { - let id = match *impl_item { - MethodImplItem(ref m) => m.id - }; - self.insert(id, NodeImplItem(impl_item)); + match *impl_item { + MethodImplItem(ref m) => { + self.insert(m.id, NodeImplItem(impl_item)); + } + TypeImplItem(ref t) => { + self.insert(t.id, NodeImplItem(impl_item)); + } + } } } ItemEnum(ref enum_definition, _) => { @@ -737,13 +751,28 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { None => {} } } - ItemTrait(_, _, _, ref methods) => { - for tm in methods.iter() { - let id = match *tm { - RequiredMethod(ref m) => m.id, - ProvidedMethod(ref m) => m.id - }; - self.insert(id, NodeTraitItem(tm)); + ItemTrait(_, _, ref bounds, ref trait_items) => { + for b in bounds.iter() { + match *b { + TraitTyParamBound(ref t) => { + self.insert(t.ref_id, NodeItem(i)); + } + _ => {} + } + } + + for tm in trait_items.iter() { + match *tm { + RequiredMethod(ref m) => { + self.insert(m.id, NodeTraitItem(tm)); + } + ProvidedMethod(ref m) => { + self.insert(m.id, NodeTraitItem(tm)); + } + TypeTraitItem(ref typ) => { + self.insert(typ.id, NodeTraitItem(tm)); + } + } } } _ => {} @@ -892,6 +921,11 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, IITraitItem(fld.fold_ops.new_def_id(d), RequiredMethod(fld.fold_type_method(ty_m))) } + TypeTraitItem(at) => { + IITraitItem( + fld.fold_ops.new_def_id(d), + TypeTraitItem(P(fld.fold_associated_type((*at).clone())))) + } }, IIImplItem(d, m) => match m { MethodImplItem(m) => { @@ -899,6 +933,10 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, MethodImplItem(fld.fold_method(m) .expect_one("expected one method"))) } + TypeImplItem(t) => { + IIImplItem(fld.fold_ops.new_def_id(d), + TypeImplItem(P(fld.fold_typedef((*t).clone())))) + } }, IIForeign(i) => IIForeign(fld.fold_foreign_item(i)) }; @@ -924,14 +962,16 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, IITraitItem(_, ref trait_item) => { let trait_item_id = match *trait_item { ProvidedMethod(ref m) => m.id, - RequiredMethod(ref m) => m.id + RequiredMethod(ref m) => m.id, + TypeTraitItem(ref ty) => ty.id, }; collector.insert(trait_item_id, NodeTraitItem(trait_item)); } IIImplItem(_, ref impl_item) => { let impl_item_id = match *impl_item { - MethodImplItem(ref m) => m.id + MethodImplItem(ref m) => m.id, + TypeImplItem(ref ti) => ti.id, }; collector.insert(impl_item_id, NodeImplItem(impl_item)); @@ -1007,16 +1047,30 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String { pprust::mac_to_string(mac), id) } } + TypeImplItem(ref t) => { + format!("typedef {} in {} (id={})", + token::get_ident(t.ident), + map.path_to_string(id), + id) + } } } - Some(NodeTraitItem(ref ti)) => { - let ident = match **ti { - ProvidedMethod(ref m) => m.pe_ident(), - RequiredMethod(ref m) => m.ident - }; - format!("method {} in {} (id={})", - token::get_ident(ident), - map.path_to_string(id), id) + Some(NodeTraitItem(ref tm)) => { + match **tm { + RequiredMethod(_) | ProvidedMethod(_) => { + let m = ast_util::trait_item_to_ty_method(&**tm); + format!("method {} in {} (id={})", + token::get_ident(m.ident), + map.path_to_string(id), + id) + } + TypeTraitItem(ref t) => { + format!("type item {} in {} (id={})", + token::get_ident(t.ident), + map.path_to_string(id), + id) + } + } } Some(NodeVariant(ref variant)) => { format!("variant {} in {} (id={})", diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index becfe715f29..6d61c851476 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -213,6 +213,62 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident { token::gensym_ident(pretty.as_slice()) } +pub fn trait_method_to_ty_method(method: &Method) -> TypeMethod { + match method.node { + MethDecl(ident, + ref generics, + abi, + ref explicit_self, + fn_style, + ref decl, + _, + vis) => { + TypeMethod { + ident: ident, + attrs: method.attrs.clone(), + fn_style: fn_style, + decl: (*decl).clone(), + generics: generics.clone(), + explicit_self: (*explicit_self).clone(), + id: method.id, + span: method.span, + vis: vis, + abi: abi, + } + }, + MethMac(_) => fail!("expected non-macro method declaration") + } +} + +/// extract a TypeMethod from a TraitItem. if the TraitItem is +/// a default, pull out the useful fields to make a TypeMethod +// +// NB: to be used only after expansion is complete, and macros are gone. +pub fn trait_item_to_ty_method(method: &TraitItem) -> TypeMethod { + match *method { + RequiredMethod(ref m) => (*m).clone(), + ProvidedMethod(ref m) => trait_method_to_ty_method(&**m), + TypeTraitItem(_) => { + fail!("trait_method_to_ty_method(): expected method but found \ + typedef") + } + } +} + +pub fn split_trait_methods(trait_methods: &[TraitItem]) + -> (Vec<TypeMethod>, Vec<P<Method>> ) { + let mut reqd = Vec::new(); + let mut provd = Vec::new(); + for trt_method in trait_methods.iter() { + match *trt_method { + RequiredMethod(ref tm) => reqd.push((*tm).clone()), + ProvidedMethod(ref m) => provd.push((*m).clone()), + TypeTraitItem(_) => {} + } + }; + (reqd, provd) +} + pub fn struct_field_visibility(field: ast::StructField) -> Visibility { match field.node.kind { ast::NamedField(_, v) | ast::UnnamedField(v) => v @@ -471,6 +527,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { match *tm { ast::RequiredMethod(ref m) => self.operation.visit_id(m.id), ast::ProvidedMethod(ref m) => self.operation.visit_id(m.id), + ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.id), } visit::walk_trait_item(self, tm); } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index cb96cd911b5..3b250de8701 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -235,13 +235,15 @@ fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool { fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool { match *meth { ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()), - ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()) + ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()), + ast::TypeTraitItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()), } } fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool { match *impl_item { ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()), + ast::TypeImplItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()), } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 6c7bbb2384c..7a7dbc54c9e 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -90,7 +90,10 @@ impl<'a> MacResult for ParserAnyMacro<'a> { let mut parser = self.parser.borrow_mut(); match parser.token { EOF => break, - _ => ret.push(parser.parse_method(None)) + _ => { + let attrs = parser.parse_outer_attributes(); + ret.push(parser.parse_method(attrs, ast::Inherited)) + } } } self.ensure_complete_parse(false); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e22e55193fc..5203ed0a073 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -68,6 +68,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("import_shadowing", Active), ("advanced_slice_patterns", Active), ("tuple_indexing", Active), + ("associated_types", Active), // if you change this list without updating src/doc/rust.md, cmr will be sad @@ -235,7 +236,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { } } - ast::ItemImpl(..) => { + ast::ItemImpl(_, _, _, ref items) => { if attr::contains_name(i.attrs.as_slice(), "unsafe_destructor") { self.gate_feature("unsafe_destructor", @@ -244,6 +245,18 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { many unsafe patterns and may be \ removed in the future"); } + + for item in items.iter() { + match *item { + ast::MethodImplItem(_) => {} + ast::TypeImplItem(ref typedef) => { + self.gate_feature("associated_types", + typedef.span, + "associated types are \ + experimental") + } + } + } } _ => {} @@ -252,6 +265,17 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { visit::walk_item(self, i); } + fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { + match *trait_item { + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} + ast::TypeTraitItem(ref ti) => { + self.gate_feature("associated_types", + ti.span, + "associated types are experimental") + } + } + } + fn visit_mac(&mut self, macro: &ast::Mac) { let ast::MacInvocTT(ref path, _, _) = macro.node; let id = path.segments.last().unwrap().identifier; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4806c5fa7c0..3beba5bcda4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -287,6 +287,15 @@ pub trait Folder { noop_fold_where_predicate(where_predicate, self) } + fn fold_typedef(&mut self, typedef: Typedef) -> Typedef { + noop_fold_typedef(typedef, self) + } + + fn fold_associated_type(&mut self, associated_type: AssociatedType) + -> AssociatedType { + noop_fold_associated_type(associated_type, self) + } + fn new_id(&mut self, i: NodeId) -> NodeId { i } @@ -414,6 +423,13 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> { fld.fold_opt_bounds(bounds), id) } + TyQPath(ref qpath) => { + TyQPath(P(QPath { + for_type: fld.fold_ty(qpath.for_type.clone()), + trait_name: fld.fold_path(qpath.trait_name.clone()), + item_name: fld.fold_ident(qpath.item_name.clone()), + })) + } TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) } @@ -735,6 +751,44 @@ pub fn noop_fold_where_predicate<T: Folder>( } } +pub fn noop_fold_typedef<T>(t: Typedef, folder: &mut T) + -> Typedef + where T: Folder { + let new_id = folder.new_id(t.id); + let new_span = folder.new_span(t.span); + let new_attrs = t.attrs.iter().map(|attr| { + folder.fold_attribute((*attr).clone()) + }).collect(); + let new_ident = folder.fold_ident(t.ident); + let new_type = folder.fold_ty(t.typ); + ast::Typedef { + ident: new_ident, + typ: new_type, + id: new_id, + span: new_span, + vis: t.vis, + attrs: new_attrs, + } +} + +pub fn noop_fold_associated_type<T>(at: AssociatedType, folder: &mut T) + -> AssociatedType + where T: Folder { + let new_id = folder.new_id(at.id); + let new_span = folder.new_span(at.span); + let new_ident = folder.fold_ident(at.ident); + let new_attrs = at.attrs + .iter() + .map(|attr| folder.fold_attribute((*attr).clone())) + .collect(); + ast::AssociatedType { + ident: new_ident, + attrs: new_attrs, + id: new_id, + span: new_span, + } +} + pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> { struct_def.map(|StructDef {fields, ctor_id, super_struct, is_virtual}| StructDef { fields: fields.move_map(|f| fld.fold_struct_field(f)), @@ -857,31 +911,59 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ { ItemStruct(struct_def, folder.fold_generics(generics)) } ItemImpl(generics, ifce, ty, impl_items) => { + let mut new_impl_items = Vec::new(); + for impl_item in impl_items.iter() { + match *impl_item { + MethodImplItem(ref x) => { + for method in folder.fold_method((*x).clone()) + .move_iter() { + new_impl_items.push(MethodImplItem(method)) + } + } + TypeImplItem(ref t) => { + new_impl_items.push(TypeImplItem( + P(folder.fold_typedef((**t).clone())))); + } + } + } + let ifce = match ifce { + None => None, + Some(ref trait_ref) => { + Some(folder.fold_trait_ref((*trait_ref).clone())) + } + }; ItemImpl(folder.fold_generics(generics), - ifce.map(|p| folder.fold_trait_ref(p)), + ifce, folder.fold_ty(ty), - impl_items.into_iter().flat_map(|impl_item| match impl_item { - MethodImplItem(x) => { - folder.fold_method(x).into_iter().map(|x| MethodImplItem(x)) - } - }).collect()) + new_impl_items) } ItemTrait(generics, unbound, bounds, methods) => { let bounds = folder.fold_bounds(bounds); - let methods = methods.into_iter().flat_map(|method| match method { - RequiredMethod(m) => { - SmallVector::one(RequiredMethod(folder.fold_type_method(m))).into_iter() - } - ProvidedMethod(method) => { - // the awkward collect/iter idiom here is because - // even though an iter and a map satisfy the same trait bound, - // they're not actually the same type, so the method arms - // don't unify. - let methods: SmallVector<ast::TraitItem> = - folder.fold_method(method).into_iter() - .map(|m| ProvidedMethod(m)).collect(); - methods.into_iter() - } + let methods = methods.into_iter().flat_map(|method| { + let r = match method { + RequiredMethod(m) => { + SmallVector::one(RequiredMethod( + folder.fold_type_method(m))) + .move_iter() + } + ProvidedMethod(method) => { + // the awkward collect/iter idiom here is because + // even though an iter and a map satisfy the same + // trait bound, they're not actually the same type, so + // the method arms don't unify. + let methods: SmallVector<ast::TraitItem> = + folder.fold_method(method).move_iter() + .map(|m| ProvidedMethod(m)).collect(); + methods.move_iter() + } + TypeTraitItem(at) => { + SmallVector::one(TypeTraitItem(P( + folder.fold_associated_type( + (*at).clone())))) + .move_iter() + } + }; + r }).collect(); ItemTrait(folder.fold_generics(generics), unbound, @@ -893,7 +975,18 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ { } pub fn noop_fold_type_method<T: Folder>(m: TypeMethod, fld: &mut T) -> TypeMethod { - let TypeMethod {id, ident, attrs, fn_style, abi, decl, generics, explicit_self, vis, span} = m; + let TypeMethod { + id, + ident, + attrs, + fn_style, + abi, + decl, + generics, + explicit_self, + vis, + span + } = m; TypeMethod { id: fld.new_id(id), ident: fld.fold_ident(ident), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ea392c87723..ff4fd41fbd7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -11,11 +11,11 @@ #![macro_escape] use abi; -use ast::{BareFnTy, ClosureTy}; +use ast::{AssociatedType, BareFnTy, ClosureTy}; use ast::{RegionTyParamBound, TraitTyParamBound}; use ast::{ProvidedMethod, Public, FnStyle}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; -use ast::{BiBitAnd, BiBitOr, BiBitXor, Block}; +use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, Block}; use ast::{BlockCheckMode, UnBox}; use ast::{CaptureByRef, CaptureByValue, CaptureClause}; use ast::{Crate, CrateConfig, Decl, DeclItem}; @@ -42,7 +42,7 @@ use ast::{MatchSeq, MatchTok, Method, MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; -use ast::{BiRem, RequiredMethod}; +use ast::{QPath, RequiredMethod}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub}; @@ -52,10 +52,10 @@ use ast::{TokenTree, TraitItem, TraitRef, TTDelim, TTSeq, TTTok}; use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; -use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr}; -use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq}; -use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound}; -use ast::{UnnamedField, UnsafeBlock}; +use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath}; +use ast::{TyRptr, TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq}; +use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; +use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock}; use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause, WherePredicate}; @@ -1235,86 +1235,125 @@ impl<'a> Parser<'a> { (decl, lifetime_defs) } - /// Parse the methods in a trait declaration - pub fn parse_trait_methods(&mut self) -> Vec<TraitItem> { + /// Parses `type Foo;` in a trait declaration only. The `type` keyword has + /// already been parsed. + fn parse_associated_type(&mut self, attrs: Vec<Attribute>) + -> AssociatedType { + let lo = self.span.lo; + let ident = self.parse_ident(); + let hi = self.span.hi; + self.expect(&token::SEMI); + AssociatedType { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + ident: ident, + attrs: attrs, + } + } + + /// Parses `type Foo = TYPE;` in an implementation declaration only. The + /// `type` keyword has already been parsed. + fn parse_typedef(&mut self, attrs: Vec<Attribute>, vis: Visibility) + -> Typedef { + let lo = self.span.lo; + let ident = self.parse_ident(); + self.expect(&token::EQ); + let typ = self.parse_ty(true); + let hi = self.span.hi; + self.expect(&token::SEMI); + Typedef { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + ident: ident, + vis: vis, + attrs: attrs, + typ: typ, + } + } + + /// Parse the items in a trait declaration + pub fn parse_trait_items(&mut self) -> Vec<TraitItem> { self.parse_unspanned_seq( &token::LBRACE, &token::RBRACE, seq_sep_none(), |p| { let attrs = p.parse_outer_attributes(); - let lo = p.span.lo; - - // NB: at the moment, trait methods are public by default; this - // could change. - let vis = p.parse_visibility(); - let abi = if p.eat_keyword(keywords::Extern) { - p.parse_opt_abi().unwrap_or(abi::C) - } else if attr::contains_name(attrs.as_slice(), - "rust_call_abi_hack") { - // FIXME(stage0, pcwalton): Remove this awful hack after a - // snapshot, and change to `extern "rust-call" fn`. - abi::RustCall + + if p.eat_keyword(keywords::Type) { + TypeTraitItem(P(p.parse_associated_type(attrs))) } else { - abi::Rust - }; - let style = p.parse_fn_style(); - let ident = p.parse_ident(); + let lo = p.span.lo; - let mut generics = p.parse_generics(); + let vis = p.parse_visibility(); + let abi = if p.eat_keyword(keywords::Extern) { + p.parse_opt_abi().unwrap_or(abi::C) + } else if attr::contains_name(attrs.as_slice(), + "rust_call_abi_hack") { + // FIXME(stage0, pcwalton): Remove this awful hack after a + // snapshot, and change to `extern "rust-call" fn`. + abi::RustCall + } else { + abi::Rust + }; - let (explicit_self, d) = p.parse_fn_decl_with_self(|p| { - // This is somewhat dubious; We don't want to allow argument - // names to be left off if there is a definition... - p.parse_arg_general(false) - }); + let style = p.parse_fn_style(); + let ident = p.parse_ident(); + let mut generics = p.parse_generics(); - p.parse_where_clause(&mut generics); + let (explicit_self, d) = p.parse_fn_decl_with_self(|p| { + // This is somewhat dubious; We don't want to allow + // argument names to be left off if there is a + // definition... + p.parse_arg_general(false) + }); - let hi = p.last_span.hi; - match p.token { - token::SEMI => { - p.bump(); - debug!("parse_trait_methods(): parsing required method"); - RequiredMethod(TypeMethod { - ident: ident, - attrs: attrs, - fn_style: style, - decl: d, - generics: generics, - abi: abi, - explicit_self: explicit_self, - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - vis: vis, - }) - } - token::LBRACE => { - debug!("parse_trait_methods(): parsing provided method"); - let (inner_attrs, body) = - p.parse_inner_attrs_and_block(); - let mut attrs = attrs; - attrs.extend(inner_attrs.into_iter()); - ProvidedMethod(P(ast::Method { - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - node: ast::MethDecl(ident, - generics, - abi, - explicit_self, - style, - d, - body, - vis) - })) - } + p.parse_where_clause(&mut generics); + + let hi = p.last_span.hi; + match p.token { + token::SEMI => { + p.bump(); + debug!("parse_trait_methods(): parsing required method"); + RequiredMethod(TypeMethod { + ident: ident, + attrs: attrs, + fn_style: style, + decl: d, + generics: generics, + abi: abi, + explicit_self: explicit_self, + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + vis: vis, + }) + } + token::LBRACE => { + debug!("parse_trait_methods(): parsing provided method"); + let (inner_attrs, body) = + p.parse_inner_attrs_and_block(); + let attrs = attrs.append(inner_attrs.as_slice()); + ProvidedMethod(P(ast::Method { + attrs: attrs, + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, hi), + node: ast::MethDecl(ident, + generics, + abi, + explicit_self, + style, + d, + body, + vis) + })) + } - _ => { - let token_str = p.this_token_to_string(); - p.fatal((format!("expected `;` or `{{`, found `{}`", - token_str)).as_slice()) - } + _ => { + let token_str = p.this_token_to_string(); + p.fatal((format!("expected `;` or `{{`, found `{}`", + token_str)).as_slice()) + } + } } }) } @@ -1455,12 +1494,11 @@ impl<'a> Parser<'a> { } else if self.token_is_closure_keyword() || self.token == token::BINOP(token::OR) || self.token == token::OROR || - self.token == token::LT { + (self.token == token::LT && + self.look_ahead(1, |t| { + *t == token::GT || Parser::token_is_lifetime(t) + })) { // CLOSURE - // - // FIXME(pcwalton): Eventually `token::LT` will not unambiguously - // introduce a closure, once procs can have lifetime bounds. We - // will need to refactor the grammar a little bit at that point. self.parse_ty_closure() } else if self.eat_keyword(keywords::Typeof) { @@ -1472,6 +1510,20 @@ impl<'a> Parser<'a> { TyTypeof(e) } else if self.eat_keyword(keywords::Proc) { self.parse_proc_type() + } else if self.token == token::LT { + // QUALIFIED PATH + self.bump(); + let for_type = self.parse_ty(true); + self.expect_keyword(keywords::As); + let trait_name = self.parse_path(LifetimeAndTypesWithoutColons); + self.expect(&token::GT); + self.expect(&token::MOD_SEP); + let item_name = self.parse_ident(); + TyQPath(P(QPath { + for_type: for_type, + trait_name: trait_name.path, + item_name: item_name, + })) } else if self.token == token::MOD_SEP || is_ident_or_path(&self.token) { // NAMED TYPE @@ -2071,7 +2123,7 @@ impl<'a> Parser<'a> { } } hi = self.last_span.hi; - }, + } _ => { if self.eat_keyword(keywords::Ref) { return self.parse_lambda_expr(CaptureByRef); @@ -4215,14 +4267,9 @@ impl<'a> Parser<'a> { /// Parse a method in a trait impl, starting with `attrs` attributes. pub fn parse_method(&mut self, - already_parsed_attrs: Option<Vec<Attribute>>) + attrs: Vec<Attribute>, + visa: Visibility) -> P<Method> { - let next_attrs = self.parse_outer_attributes(); - let attrs = match already_parsed_attrs { - Some(mut a) => { a.push_all_move(next_attrs); a } - None => next_attrs - }; - let lo = self.span.lo; // code copied from parse_macro_use_or_failure... abstraction! @@ -4251,7 +4298,6 @@ impl<'a> Parser<'a> { self.span.hi) }; (ast::MethMac(m), self.span.hi, attrs) } else { - let visa = self.parse_visibility(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) } else if attr::contains_name(attrs.as_slice(), @@ -4302,18 +4348,28 @@ impl<'a> Parser<'a> { self.parse_where_clause(&mut tps); - let meths = self.parse_trait_methods(); + let meths = self.parse_trait_items(); (ident, ItemTrait(tps, sized, bounds, meths), None) } fn parse_impl_items(&mut self) -> (Vec<ImplItem>, Vec<Attribute>) { let mut impl_items = Vec::new(); self.expect(&token::LBRACE); - let (inner_attrs, next) = self.parse_inner_attrs_and_next(); - let mut method_attrs = Some(next); + let (inner_attrs, mut method_attrs) = + self.parse_inner_attrs_and_next(); while !self.eat(&token::RBRACE) { - impl_items.push(MethodImplItem(self.parse_method(method_attrs))); - method_attrs = None; + method_attrs.push_all_move(self.parse_outer_attributes()); + let vis = self.parse_visibility(); + if self.eat_keyword(keywords::Type) { + impl_items.push(TypeImplItem(P(self.parse_typedef( + method_attrs, + vis)))) + } else { + impl_items.push(MethodImplItem(self.parse_method( + method_attrs, + vis))); + } + method_attrs = self.parse_outer_attributes(); } (impl_items, inner_attrs) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d0df95d711e..0ae5303641b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -9,10 +9,11 @@ // except according to those terms. use abi; -use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind}; -use ast::{FnUnboxedClosureKind, MethodImplItem}; -use ast::{RegionTyParamBound, TraitTyParamBound, UnboxedClosureKind}; -use ast::{UnboxedFnTyParamBound, RequiredMethod, ProvidedMethod}; +use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; +use ast::{FnOnceUnboxedClosureKind}; +use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound}; +use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem}; +use ast::{UnboxedClosureKind, UnboxedFnTyParamBound}; use ast; use ast_util; use owned_slice::OwnedSlice; @@ -660,6 +661,16 @@ impl<'a> State<'a> { ast::TyPath(ref path, ref bounds, _) => { try!(self.print_bounded_path(path, bounds)); } + ast::TyQPath(ref qpath) => { + try!(word(&mut self.s, "<")); + try!(self.print_type(&*qpath.for_type)); + try!(space(&mut self.s)); + try!(self.word_space("as")); + try!(self.print_path(&qpath.trait_name, false)); + try!(word(&mut self.s, ">")); + try!(word(&mut self.s, "::")); + try!(self.print_ident(qpath.item_name)); + } ast::TyFixedLengthVec(ref ty, ref v) => { try!(word(&mut self.s, "[")); try!(self.print_type(&**ty)); @@ -708,6 +719,22 @@ impl<'a> State<'a> { } } + fn print_associated_type(&mut self, typedef: &ast::AssociatedType) + -> IoResult<()> { + try!(self.word_space("type")); + try!(self.print_ident(typedef.ident)); + word(&mut self.s, ";") + } + + fn print_typedef(&mut self, typedef: &ast::Typedef) -> IoResult<()> { + try!(self.word_space("type")); + try!(self.print_ident(typedef.ident)); + try!(space(&mut self.s)); + try!(self.word_space("=")); + try!(self.print_type(&*typedef.typ)); + word(&mut self.s, ";") + } + /// Pretty-print an item pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { try!(self.hardbreak_if_not_bol()); @@ -825,6 +852,9 @@ impl<'a> State<'a> { ast::MethodImplItem(ref meth) => { try!(self.print_method(&**meth)); } + ast::TypeImplItem(ref typ) => { + try!(self.print_typedef(&**typ)); + } } } try!(self.bclose(item.span)); @@ -1071,13 +1101,15 @@ impl<'a> State<'a> { m: &ast::TraitItem) -> IoResult<()> { match *m { RequiredMethod(ref ty_m) => self.print_ty_method(ty_m), - ProvidedMethod(ref m) => self.print_method(&**m) + ProvidedMethod(ref m) => self.print_method(&**m), + TypeTraitItem(ref t) => self.print_associated_type(&**t), } } pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> IoResult<()> { match *ii { MethodImplItem(ref m) => self.print_method(&**m), + TypeImplItem(ref td) => self.print_typedef(&**td), } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 30a38e28729..d425c60f4c9 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -116,12 +116,19 @@ pub trait Visitor<'v> { fn visit_attribute(&mut self, _attr: &'v Attribute) {} } -pub fn walk_inlined_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v InlinedItem) { +pub fn walk_inlined_item<'v,V>(visitor: &mut V, item: &'v InlinedItem) + where V: Visitor<'v> { match *item { IIItem(ref i) => visitor.visit_item(&**i), IIForeign(ref i) => visitor.visit_foreign_item(&**i), IITraitItem(_, ref ti) => visitor.visit_trait_item(ti), - IIImplItem(_, MethodImplItem(ref m)) => walk_method_helper(visitor, &**m) + IIImplItem(_, MethodImplItem(ref m)) => { + walk_method_helper(visitor, &**m) + } + IIImplItem(_, TypeImplItem(ref typedef)) => { + visitor.visit_ident(typedef.span, typedef.ident); + visitor.visit_ty(&*typedef.typ); + } } } @@ -248,6 +255,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { MethodImplItem(ref method) => { walk_method_helper(visitor, &**method) } + TypeImplItem(ref typedef) => { + visitor.visit_ident(typedef.span, typedef.ident); + visitor.visit_ty(&*typedef.typ); + } } } } @@ -366,6 +377,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { None => { } } } + TyQPath(ref qpath) => { + visitor.visit_ty(&*qpath.for_type); + visitor.visit_path(&qpath.trait_name, typ.id); + visitor.visit_ident(typ.span, qpath.item_name); + } TyFixedLengthVec(ref ty, ref expression) => { visitor.visit_ty(&**ty); visitor.visit_expr(&**expression) @@ -573,10 +589,11 @@ pub fn walk_ty_method<'v, V: Visitor<'v>>(visitor: &mut V, method_type: &'v Type pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v TraitItem) { match *trait_method { - RequiredMethod(ref method_type) => { - visitor.visit_ty_method(method_type) - } + RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type), ProvidedMethod(ref method) => walk_method_helper(visitor, &**method), + TypeTraitItem(ref associated_type) => { + visitor.visit_ident(associated_type.span, associated_type.ident) + } } } |
