diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2014-11-07 06:53:45 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2014-11-07 15:51:30 -0500 |
| commit | 244231720d29db856c5a28c0dda6c2efd7c9219a (patch) | |
| tree | 41648e7c6c16102a7a602be441b4f1cdad8e7411 /src/libsyntax | |
| parent | c18a1327e3ccf02ae9f755ca280d53177eeb298d (diff) | |
| download | rust-244231720d29db856c5a28c0dda6c2efd7c9219a.tar.gz rust-244231720d29db856c5a28c0dda6c2efd7c9219a.zip | |
Update parser with `for` syntax
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 20 | ||||
| -rw-r--r-- | src/libsyntax/ast_map/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 15 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/generic/ty.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 24 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 310 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 31 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 29 |
8 files changed, 261 insertions, 174 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 20f7caac482..145978bb73f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -307,7 +307,7 @@ pub const DUMMY_NODE_ID: NodeId = -1; /// detects Copy, Send and Sync. #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum TyParamBound { - TraitTyParamBound(TraitRef), + TraitTyParamBound(PolyTraitRef), RegionTyParamBound(Lifetime) } @@ -318,7 +318,7 @@ pub struct TyParam { pub ident: Ident, pub id: NodeId, pub bounds: TyParamBounds, - pub unbound: Option<TyParamBound>, + pub unbound: Option<TraitRef>, pub default: Option<P<Ty>>, pub span: Span } @@ -1097,6 +1097,7 @@ pub enum Ty_ { TyBareFn(P<BareFnTy>), TyTup(Vec<P<Ty>> ), TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above + TyPolyTraitRef(P<PolyTraitRef>), // a type like `for<'a> Foo<&'a Bar>` /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType` TyQPath(P<QPath>), /// No-op; kept solely so that we can pretty-print faithfully @@ -1350,7 +1351,6 @@ pub struct Attribute_ { pub is_sugared_doc: bool, } - /// TraitRef's appear in impls. /// resolve maps each TraitRef's ref_id to its defining trait; that's all /// that the ref_id is for. The impl_id maps to the "self type" of this impl. @@ -1360,7 +1360,15 @@ pub struct Attribute_ { pub struct TraitRef { pub path: Path, pub ref_id: NodeId, - pub lifetimes: Vec<LifetimeDef>, +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct PolyTraitRef { + /// The `'a` in `<'a> Foo<&'a T>` + pub bound_lifetimes: Vec<LifetimeDef>, + + /// The `Foo<&'a T>` in `<'a> Foo<&'a T>` + pub trait_ref: TraitRef } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] @@ -1448,8 +1456,8 @@ pub enum Item_ { ItemStruct(P<StructDef>, Generics), /// Represents a Trait Declaration ItemTrait(Generics, - Option<TyParamBound>, // (optional) default bound not required for Self. - // Currently, only Sized makes sense here. + Option<TraitRef>, // (optional) default bound not required for Self. + // Currently, only Sized makes sense here. TyParamBounds, Vec<TraitItem>), ItemImpl(Generics, diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 3adb062864e..d65be4c45e8 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -770,7 +770,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { for b in bounds.iter() { match *b { TraitTyParamBound(ref t) => { - self.insert(t.ref_id, NodeItem(i)); + self.insert(t.trait_ref.ref_id, NodeItem(i)); } _ => {} } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5921d630b89..862cbf3d7ca 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -68,10 +68,11 @@ pub trait AstBuilder { span: Span, id: ast::Ident, bounds: OwnedSlice<ast::TyParamBound>, - unbound: Option<ast::TyParamBound>, + unbound: Option<ast::TraitRef>, default: Option<P<ast::Ty>>) -> ast::TyParam; fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; + fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef; fn typarambound(&self, path: ast::Path) -> ast::TyParamBound; fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime; fn lifetime_def(&self, @@ -417,7 +418,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: Span, id: ast::Ident, bounds: OwnedSlice<ast::TyParamBound>, - unbound: Option<ast::TyParamBound>, + unbound: Option<ast::TraitRef>, default: Option<P<ast::Ty>>) -> ast::TyParam { ast::TyParam { ident: id, @@ -445,12 +446,18 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::TraitRef { path: path, ref_id: ast::DUMMY_NODE_ID, - lifetimes: Vec::new(), + } + } + + fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef { + ast::PolyTraitRef { + bound_lifetimes: Vec::new(), + trait_ref: self.trait_ref(path) } } fn typarambound(&self, path: ast::Path) -> ast::TyParamBound { - ast::TraitTyParamBound(self.trait_ref(path)) + ast::TraitTyParamBound(self.poly_trait_ref(path)) } fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime { diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index a90618a30b6..1ec1e3b1224 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -194,7 +194,7 @@ impl<'a> Ty<'a> { fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, - bounds: &[Path], unbound: Option<ast::TyParamBound>, + bounds: &[Path], unbound: Option<ast::TraitRef>, self_ident: Ident, self_generics: &Generics) -> ast::TyParam { let bounds = bounds.iter().map(|b| { @@ -220,7 +220,7 @@ fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) #[deriving(Clone)] pub struct LifetimeBounds<'a> { pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, - pub bounds: Vec<(&'a str, Option<ast::TyParamBound>, Vec<Path<'a>>)>, + pub bounds: Vec<(&'a str, Option<ast::TraitRef>, Vec<Path<'a>>)>, } impl<'a> LifetimeBounds<'a> { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2074a6bfab9..85d4e157b7b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -227,6 +227,10 @@ pub trait Folder { noop_fold_trait_ref(p, self) } + fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef { + noop_fold_poly_trait_ref(p, self) + } + fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> { noop_fold_struct_def(struct_def, self) } @@ -442,7 +446,10 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> { TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) } - TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)) + TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)), + TyPolyTraitRef(poly_trait_ref) => { + TyPolyTraitRef(poly_trait_ref.map(|p| fld.fold_poly_trait_ref(p))) + }, }, span: fld.new_span(span) }) @@ -711,7 +718,7 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T) -> TyParamBound where T: Folder { match tpb { - TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)), + TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_poly_trait_ref(ty)), RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), } } @@ -722,7 +729,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam { id: fld.new_id(id), ident: ident, bounds: fld.fold_bounds(bounds), - unbound: unbound.map(|x| fld.fold_ty_param_bound(x)), + unbound: unbound.map(|x| fld.fold_trait_ref(x)), default: default.map(|x| fld.fold_ty(x)), span: span } @@ -842,13 +849,18 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef { let id = fld.new_id(p.ref_id); let TraitRef { path, - lifetimes, - .. + ref_id: _, } = p; ast::TraitRef { path: fld.fold_path(path), ref_id: id, - lifetimes: fld.fold_lifetime_defs(lifetimes), + } +} + +pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef { + ast::PolyTraitRef { + bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes), + trait_ref: fld.fold_trait_ref(p.trait_ref) } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9ba11d63da5..6873c015fd5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -42,6 +42,7 @@ use ast::{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::{PolyTraitRef}; use ast::{QPath, RequiredMethod}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -53,7 +54,7 @@ use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TyBot}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; -use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath}; +use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath}; use ast::{TyRptr, TyTup, TyU32, TyUniq, TyVec, UnUniq}; use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; use ast::{UnnamedField, UnsafeBlock}; @@ -968,30 +969,14 @@ impl<'a> Parser<'a> { /// Is the current token one of the keywords that signals a bare function /// type? pub fn token_is_bare_fn_keyword(&mut self) -> bool { - if self.token.is_keyword(keywords::Fn) { - return true - } - - if self.token.is_keyword(keywords::Unsafe) || - self.token.is_keyword(keywords::Once) { - return self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) - } - - false + self.token.is_keyword(keywords::Fn) || + self.token.is_keyword(keywords::Unsafe) || + self.token.is_keyword(keywords::Extern) } /// Is the current token one of the keywords that signals a closure type? pub fn token_is_closure_keyword(&mut self) -> bool { - self.token.is_keyword(keywords::Unsafe) || - self.token.is_keyword(keywords::Once) - } - - /// Is the current token one of the keywords that signals an old-style - /// closure type (with explicit sigil)? - pub fn token_is_old_style_closure_keyword(&mut self) -> bool { - self.token.is_keyword(keywords::Unsafe) || - self.token.is_keyword(keywords::Once) || - self.token.is_keyword(keywords::Fn) + self.token.is_keyword(keywords::Unsafe) } pub fn get_lifetime(&mut self) -> ast::Ident { @@ -1001,8 +986,57 @@ impl<'a> Parser<'a> { } } + pub fn parse_for_in_type(&mut self) -> Ty_ { + /* + Parses whatever can come after a `for` keyword in a type. + The `for` has already been consumed. + + Deprecated: + + - for <'lt> |S| -> T + - for <'lt> proc(S) -> T + + Eventually: + + - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T + - for <'lt> path::foo(a, b) + + */ + + // parse <'lt> + let lifetime_defs = self.parse_late_bound_lifetime_defs(); + + // examine next token to decide to do + if self.eat_keyword(keywords::Proc) { + self.parse_proc_type(lifetime_defs) + } else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() { + self.parse_ty_bare_fn_or_ty_closure(lifetime_defs) + } else if self.token == token::ModSep || + self.token.is_ident() || + self.token.is_path() { + let trait_ref = self.parse_trait_ref(); + TyPolyTraitRef(P(PolyTraitRef { bound_lifetimes: lifetime_defs, + trait_ref: trait_ref })) + } else { + self.parse_ty_closure(lifetime_defs) + } + } + + pub fn parse_ty_path(&mut self, plus_allowed: bool) -> Ty_ { + let mode = if plus_allowed { + LifetimeAndTypesAndBounds + } else { + LifetimeAndTypesWithoutColons + }; + let PathAndBounds { + path, + bounds + } = self.parse_path(mode); + TyPath(path, bounds, ast::DUMMY_NODE_ID) + } + /// parse a TyBareFn type: - pub fn parse_ty_bare_fn(&mut self) -> Ty_ { + pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ { /* [unsafe] [extern "ABI"] fn <'lt> (S) -> T @@ -1023,18 +1057,26 @@ impl<'a> Parser<'a> { }; self.expect_keyword(keywords::Fn); - let (decl, lifetimes) = self.parse_ty_fn_decl(true); + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); + let (inputs, variadic) = self.parse_fn_args(false, true); + let (ret_style, ret_ty) = self.parse_ret_ty(); + let decl = P(FnDecl { + inputs: inputs, + output: ret_ty, + cf: ret_style, + variadic: variadic + }); TyBareFn(P(BareFnTy { abi: abi, fn_style: fn_style, - lifetimes: lifetimes, + lifetimes: lifetime_defs, decl: decl })) } /// Parses a procedure type (`proc`). The initial `proc` keyword must /// already have been parsed. - pub fn parse_proc_type(&mut self) -> Ty_ { + pub fn parse_proc_type(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ { /* proc <'lt> (S) [:Bounds] -> T @@ -1043,19 +1085,12 @@ impl<'a> Parser<'a> { | | | | Return type | | | Bounds | | Argument types - | Lifetimes + | Legacy lifetimes the `proc` keyword */ - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs - } else { - Vec::new() - }; - + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); let (inputs, variadic) = self.parse_fn_args(false, false); let bounds = self.parse_colon_then_ty_param_bounds(); let (ret_style, ret_ty) = self.parse_ret_ty(); @@ -1100,33 +1135,49 @@ impl<'a> Parser<'a> { return None } + pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ { + // Both bare fns and closures can begin with stuff like unsafe + // and extern. So we just scan ahead a few tokens to see if we see + // a `fn`. + // + // Closure: [unsafe] <'lt> |S| [:Bounds] -> T + // Fn: [unsafe] [extern "ABI"] fn <'lt> (S) -> T + + if self.token.is_keyword(keywords::Fn) { + self.parse_ty_bare_fn(lifetime_defs) + } else if self.token.is_keyword(keywords::Extern) { + self.parse_ty_bare_fn(lifetime_defs) + } else if self.token.is_keyword(keywords::Unsafe) { + if self.look_ahead(1, |t| t.is_keyword(keywords::Fn) || + t.is_keyword(keywords::Extern)) { + self.parse_ty_bare_fn(lifetime_defs) + } else { + self.parse_ty_closure(lifetime_defs) + } + } else { + self.parse_ty_closure(lifetime_defs) + } + } + /// Parse a TyClosure type - pub fn parse_ty_closure(&mut self) -> Ty_ { + pub fn parse_ty_closure(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ { /* - [unsafe] [once] <'lt> |S| [:Bounds] -> T - ^~~~~~~^ ^~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ - | | | | | | - | | | | | Return type - | | | | Closure bounds - | | | Argument types - | | Lifetime defs - | Once-ness (a.k.a., affine) + [unsafe] <'lt> |S| [:Bounds] -> T + ^~~~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ + | | | | | + | | | | Return type + | | | Closure bounds + | | Argument types + | Deprecated lifetime defs + | Function Style */ let fn_style = self.parse_unsafety(); - let onceness = if self.eat_keyword(keywords::Once) {Once} else {Many}; - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - - lifetime_defs - } else { - Vec::new() - }; + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); let inputs = if self.eat(&token::OrOr) { Vec::new() @@ -1152,7 +1203,7 @@ impl<'a> Parser<'a> { TyClosure(P(ClosureTy { fn_style: fn_style, - onceness: onceness, + onceness: Many, bounds: bounds, decl: decl, lifetimes: lifetime_defs, @@ -1167,36 +1218,23 @@ impl<'a> Parser<'a> { } } - /// Parse a function type (following the 'fn') - pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool) - -> (P<FnDecl>, Vec<ast::LifetimeDef>) { - /* - - (fn) <'lt> (S) -> T - ^~~~^ ^~^ ^ - | | | - | | Return type - | Argument types - Lifetime_defs - - */ - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs + /// Parses `[ 'for' '<' lifetime_defs '>' ]' + fn parse_legacy_lifetime_defs(&mut self, + lifetime_defs: Vec<ast::LifetimeDef>) + -> Vec<ast::LifetimeDef> + { + if self.eat(&token::Lt) { + if lifetime_defs.is_empty() { + self.warn("deprecated syntax, use `for` keyword now"); + let lifetime_defs = self.parse_lifetime_defs(); + self.expect_gt(); + lifetime_defs + } else { + self.fatal("cannot use new `for` keyword and older syntax together"); + } } else { - Vec::new() - }; - - let (inputs, variadic) = self.parse_fn_args(false, allow_variadic); - let (ret_style, ret_ty) = self.parse_ret_ty(); - let decl = P(FnDecl { - inputs: inputs, - output: ret_ty, - cf: ret_style, - variadic: variadic - }); - (decl, lifetime_defs) + lifetime_defs + } } /// Parses `type Foo;` in a trait declaration only. The `type` keyword has @@ -1433,25 +1471,24 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Bracket)); t } else if self.token == token::BinOp(token::And) || - self.token == token::AndAnd { + self.token == token::AndAnd { // BORROWED POINTER self.expect_and(); self.parse_borrowed_pointee() - } else if self.token.is_keyword(keywords::Extern) || - self.token.is_keyword(keywords::Unsafe) || - self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn() - } else if self.token_is_closure_keyword() || - self.token == token::BinOp(token::Or) || - self.token == token::OrOr || - (self.token == token::Lt && - self.look_ahead(1, |t| { - *t == token::Gt || t.is_lifetime() - })) { + } else if self.token.is_keyword(keywords::For) { + self.parse_for_in_type() + } else if self.token_is_bare_fn_keyword() || + self.token_is_closure_keyword() { + // BARE FUNCTION OR CLOSURE + self.parse_ty_bare_fn_or_ty_closure(Vec::new()) + } else if self.token == token::BinOp(token::Or) || + self.token == token::OrOr || + (self.token == token::Lt && + self.look_ahead(1, |t| { + *t == token::Gt || t.is_lifetime() + })) { // CLOSURE - - self.parse_ty_closure() + self.parse_ty_closure(Vec::new()) } else if self.eat_keyword(keywords::Typeof) { // TYPEOF // In order to not be ambiguous, the type must be surrounded by parens. @@ -1460,7 +1497,7 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren)); TyTypeof(e) } else if self.eat_keyword(keywords::Proc) { - self.parse_proc_type() + self.parse_proc_type(Vec::new()) } else if self.token == token::Lt { // QUALIFIED PATH self.bump(); @@ -1479,16 +1516,7 @@ impl<'a> Parser<'a> { self.token.is_ident() || self.token.is_path() { // NAMED TYPE - let mode = if plus_allowed { - LifetimeAndTypesAndBounds - } else { - LifetimeAndTypesWithoutColons - }; - let PathAndBounds { - path, - bounds - } = self.parse_path(mode); - TyPath(path, bounds, ast::DUMMY_NODE_ID) + self.parse_ty_path(plus_allowed) } else if self.eat(&token::Underscore) { // TYPE TO BE INFERRED TyInfer @@ -3848,29 +3876,17 @@ impl<'a> Parser<'a> { } // matches bounds = ( boundseq )? - // where boundseq = ( bound + boundseq ) | bound - // and bound = 'region | ty + // where boundseq = ( polybound + boundseq ) | polybound + // and polybound = ( 'for' '<' 'region '>' )? bound + // and bound = 'region | trait_ref // NB: The None/Some distinction is important for issue #7264. fn parse_ty_param_bounds(&mut self) -> OwnedSlice<TyParamBound> { let mut result = vec!(); loop { - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs - } else { - Vec::new() - }; match self.token { token::Lifetime(lifetime) => { - if lifetime_defs.len() > 0 { - let span = self.last_span; - self.span_err(span, "lifetime declarations are not \ - allowed here") - } - result.push(RegionTyParamBound(ast::Lifetime { id: ast::DUMMY_NODE_ID, span: self.span, @@ -3879,13 +3895,8 @@ impl<'a> Parser<'a> { self.bump(); } token::ModSep | token::Ident(..) => { - let path = - self.parse_path(LifetimeAndTypesWithoutColons).path; - result.push(TraitTyParamBound(ast::TraitRef { - path: path, - ref_id: ast::DUMMY_NODE_ID, - lifetimes: lifetime_defs, - })) + let poly_trait_ref = self.parse_poly_trait_ref(); + result.push(TraitTyParamBound(poly_trait_ref)) } _ => break, } @@ -3898,7 +3909,7 @@ impl<'a> Parser<'a> { return OwnedSlice::from_vec(result); } - fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { + fn trait_ref_from_ident(ident: Ident, span: Span) -> TraitRef { let segment = ast::PathSegment { identifier: ident, parameters: ast::PathParameters::none() @@ -3911,7 +3922,6 @@ impl<'a> Parser<'a> { ast::TraitRef { path: path, ref_id: ast::DUMMY_NODE_ID, - lifetimes: Vec::new(), } } @@ -3927,7 +3937,7 @@ impl<'a> Parser<'a> { let mut unbound = None; if self.eat(&token::Question) { let tref = Parser::trait_ref_from_ident(ident, span); - unbound = Some(TraitTyParamBound(tref)); + unbound = Some(tref); span = self.span; ident = self.parse_ident(); } @@ -4538,7 +4548,6 @@ impl<'a> Parser<'a> { Some(TraitRef { path: (*path).clone(), ref_id: node_id, - lifetimes: Vec::new(), }) } TyPath(_, Some(_), _) => { @@ -4568,6 +4577,35 @@ impl<'a> Parser<'a> { Some(attrs)) } + /// Parse a::B<String,int> + fn parse_trait_ref(&mut self) -> TraitRef { + ast::TraitRef { + path: self.parse_path(LifetimeAndTypesWithoutColons).path, + ref_id: ast::DUMMY_NODE_ID, + } + } + + fn parse_late_bound_lifetime_defs(&mut self) -> Vec<ast::LifetimeDef> { + if self.eat_keyword(keywords::For) { + self.expect(&token::Lt); + let lifetime_defs = self.parse_lifetime_defs(); + self.expect_gt(); + lifetime_defs + } else { + Vec::new() + } + } + + /// Parse for<'l> a::B<String,int> + fn parse_poly_trait_ref(&mut self) -> PolyTraitRef { + let lifetime_defs = self.parse_late_bound_lifetime_defs(); + + ast::PolyTraitRef { + bound_lifetimes: lifetime_defs, + trait_ref: self.parse_trait_ref() + } + } + /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> ItemInfo { let class_name = self.parse_ident(); @@ -4681,7 +4719,7 @@ impl<'a> Parser<'a> { else { Inherited } } - fn parse_for_sized(&mut self) -> Option<ast::TyParamBound> { + fn parse_for_sized(&mut self) -> Option<ast::TraitRef> { if self.eat_keyword(keywords::For) { let span = self.span; let ident = self.parse_ident(); @@ -4691,7 +4729,7 @@ impl<'a> Parser<'a> { return None; } let tref = Parser::trait_ref_from_ident(ident, span); - Some(TraitTyParamBound(tref)) + Some(tref) } else { None } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 63e2c5499e8..5b57a875c4a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -743,6 +743,9 @@ impl<'a> State<'a> { ast::TyPath(ref path, ref bounds, _) => { try!(self.print_bounded_path(path, bounds)); } + ast::TyPolyTraitRef(ref poly_trait_ref) => { + try!(self.print_poly_trait_ref(&**poly_trait_ref)); + } ast::TyQPath(ref qpath) => { try!(word(&mut self.s, "<")); try!(self.print_type(&*qpath.for_type)); @@ -960,7 +963,7 @@ impl<'a> State<'a> { try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); match unbound { - &Some(TraitTyParamBound(ref tref)) => { + &Some(ref tref) => { try!(space(&mut self.s)); try!(self.word_space("for")); try!(self.print_trait_ref(tref)); @@ -995,19 +998,21 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> { - if t.lifetimes.len() > 0 { - try!(self.print_generics(&ast::Generics { - lifetimes: t.lifetimes.clone(), - ty_params: OwnedSlice::empty(), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, - })); - } self.print_path(&t.path, false) } + fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> { + if !t.bound_lifetimes.is_empty() { + try!(word(&mut self.s, "for<")); + for lifetime_def in t.bound_lifetimes.iter() { + try!(self.print_lifetime_def(lifetime_def)); + } + try!(word(&mut self.s, ">")); + } + + self.print_trait_ref(&t.trait_ref) + } + pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef, generics: &ast::Generics, ident: ast::Ident, span: codemap::Span, @@ -2383,7 +2388,7 @@ impl<'a> State<'a> { try!(match *bound { TraitTyParamBound(ref tref) => { - self.print_trait_ref(tref) + self.print_poly_trait_ref(tref) } RegionTyParamBound(ref lt) => { self.print_lifetime(lt) @@ -2450,7 +2455,7 @@ impl<'a> State<'a> { pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { match param.unbound { - Some(TraitTyParamBound(ref tref)) => { + Some(ref tref) => { try!(self.print_trait_ref(tref)); try!(self.word_space("?")); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9751abacbd3..1b1d1e9cace 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -75,6 +75,10 @@ pub trait Visitor<'v> { } fn visit_ty_method(&mut self, t: &'v TypeMethod) { walk_ty_method(self, t) } fn visit_trait_item(&mut self, t: &'v TraitItem) { walk_trait_item(self, t) } + fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef) { + walk_poly_trait_ref(self, t) + } fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { walk_struct_def(self, s) } @@ -202,9 +206,20 @@ pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, /// Like with walk_method_helper this doesn't correspond to a method /// in Visitor, and so it gets a _helper suffix. -pub fn walk_trait_ref_helper<'v,V>(visitor: &mut V, trait_ref: &'v TraitRef) - where V: Visitor<'v> { - walk_lifetime_decls(visitor, &trait_ref.lifetimes); +pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, + trait_ref: &'v PolyTraitRef) + where V: Visitor<'v> +{ + walk_lifetime_decls(visitor, &trait_ref.bound_lifetimes); + visitor.visit_trait_ref(&trait_ref.trait_ref); +} + +/// Like with walk_method_helper this doesn't correspond to a method +/// in Visitor, and so it gets a _helper suffix. +pub fn walk_trait_ref<'v,V>(visitor: &mut V, + trait_ref: &'v TraitRef) + where V: Visitor<'v> +{ visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } @@ -248,8 +263,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { ref impl_items) => { visitor.visit_generics(type_parameters); match *trait_reference { - Some(ref trait_reference) => walk_trait_ref_helper(visitor, - trait_reference), + Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference), None => () } visitor.visit_ty(&**typ); @@ -383,6 +397,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_ty(&**ty); visitor.visit_expr(&**expression) } + TyPolyTraitRef(ref poly_trait_ref) => { + visitor.visit_poly_trait_ref(&**poly_trait_ref) + } TyTypeof(ref expression) => { visitor.visit_expr(&**expression) } @@ -497,7 +514,7 @@ pub fn walk_ty_param_bounds<'v, V: Visitor<'v>>(visitor: &mut V, for bound in bounds.iter() { match *bound { TraitTyParamBound(ref typ) => { - walk_trait_ref_helper(visitor, typ) + visitor.visit_poly_trait_ref(typ) } RegionTyParamBound(ref lifetime) => { visitor.visit_lifetime_ref(lifetime); |
