From fcab98038c3b466d9ecd00b0f27e9c748e7acbde Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 5 Aug 2014 22:59:24 -0400 Subject: [PATCH] Temporary bootstrapping hack: introduce syntax for r egion bounds like `'b:'a`, meaning `'b outlives 'a`. Syntax currently does nothing but is needed for full fix to #5763. To use this syntax, the issue_5763_bootstrap feature guard is required. --- src/librustc/lint/context.rs | 2 +- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 44 +++++---- src/librustc/middle/typeck/collect.rs | 11 ++- .../middle/typeck/infer/error_reporting.rs | 13 ++- src/librustc/middle/typeck/variance.rs | 3 +- src/librustc_back/svh.rs | 4 +- src/librustdoc/clean/mod.rs | 6 ++ src/libsyntax/ast.rs | 12 ++- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/ext/build.rs | 16 ++++ src/libsyntax/ext/deriving/generic/mod.rs | 8 +- src/libsyntax/ext/deriving/generic/ty.rs | 15 ++- src/libsyntax/fold.rs | 29 +++++- src/libsyntax/parse/parser.rs | 91 +++++++++++++------ src/libsyntax/print/pprust.rs | 20 +++- src/libsyntax/visit.rs | 4 +- .../regions-bound-lists-feature-gate-2.rs | 18 ++++ .../regions-bound-lists-feature-gate-2.rs | 20 ++++ 19 files changed, 240 insertions(+), 80 deletions(-) create mode 100644 src/test/compile-fail/regions-bound-lists-feature-gate-2.rs create mode 100644 src/test/run-pass/regions-bound-lists-feature-gate-2.rs diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e3829892f7bff..59a6b08638e91 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -576,7 +576,7 @@ impl<'a> Visitor<()> for Context<'a> { run_lints!(self, check_lifetime_ref, lt); } - fn visit_lifetime_decl(&mut self, lt: &ast::Lifetime, _: ()) { + fn visit_lifetime_decl(&mut self, lt: &ast::LifetimeDef, _: ()) { run_lints!(self, check_lifetime_decl, lt); } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 9224647bc798b..1bf77b42bec04 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -150,7 +150,7 @@ pub trait LintPass { fn check_variant(&mut self, _: &Context, _: &ast::Variant, _: &ast::Generics) { } fn check_opt_lifetime_ref(&mut self, _: &Context, _: Span, _: &Option) { } fn check_lifetime_ref(&mut self, _: &Context, _: &ast::Lifetime) { } - fn check_lifetime_decl(&mut self, _: &Context, _: &ast::Lifetime) { } + fn check_lifetime_decl(&mut self, _: &Context, _: &ast::LifetimeDef) { } fn check_explicit_self(&mut self, _: &Context, _: &ast::ExplicitSelf) { } fn check_mac(&mut self, _: &Context, _: &ast::Mac) { } fn check_path(&mut self, _: &Context, _: &ast::Path, _: ast::NodeId) { } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 1c85413a8d8eb..5001e7a88bd93 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -59,10 +59,10 @@ struct LifetimeContext<'a> { enum ScopeChain<'a> { /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. - EarlyScope(subst::ParamSpace, &'a Vec, Scope<'a>), + EarlyScope(subst::ParamSpace, &'a Vec, Scope<'a>), /// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound /// lifetimes introduced by the declaration binder_id. - LateScope(ast::NodeId, &'a Vec, Scope<'a>), + LateScope(ast::NodeId, &'a Vec, Scope<'a>), /// lifetimes introduced by items within a code block are scoped /// to that block. BlockScope(ast::NodeId, Scope<'a>), @@ -136,7 +136,7 @@ impl<'a, 'b> Visitor> for LifetimeContext<'b> { fn push_fn_scope(this: &mut LifetimeContext, ty: &ast::Ty, scope: Scope, - lifetimes: &Vec) { + lifetimes: &Vec) { let scope1 = LateScope(ty.id, lifetimes, scope); this.check_lifetime_names(lifetimes); debug!("pushing fn scope id={} due to type", ty.id); @@ -216,7 +216,7 @@ impl<'a> LifetimeContext<'a> { walk(self, &scope1) } else { let (early, late) = generics.lifetimes.clone().partition( - |l| referenced_idents.iter().any(|&i| i == l.name)); + |l| referenced_idents.iter().any(|&i| i == l.lifetime.name)); let scope1 = EarlyScope(subst::FnSpace, &early, scope); let scope2 = LateScope(n, &late, &scope1); @@ -334,29 +334,39 @@ impl<'a> LifetimeContext<'a> { token::get_name(lifetime_ref.name)).as_slice()); } - fn check_lifetime_names(&self, lifetimes: &Vec) { + fn check_lifetime_names(&self, lifetimes: &Vec) { for i in range(0, lifetimes.len()) { let lifetime_i = lifetimes.get(i); let special_idents = [special_idents::static_lifetime]; for lifetime in lifetimes.iter() { - if special_idents.iter().any(|&i| i.name == lifetime.name) { + if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) { self.sess.span_err( - lifetime.span, + lifetime.lifetime.span, format!("illegal lifetime parameter name: `{}`", - token::get_name(lifetime.name)).as_slice()); + token::get_name(lifetime.lifetime.name)) + .as_slice()); } } for j in range(i + 1, lifetimes.len()) { let lifetime_j = lifetimes.get(j); - if lifetime_i.name == lifetime_j.name { + if lifetime_i.lifetime.name == lifetime_j.lifetime.name { self.sess.span_err( - lifetime_j.span, + lifetime_j.lifetime.span, format!("lifetime name `{}` declared twice in \ the same scope", - token::get_name(lifetime_j.name)).as_slice()); + token::get_name(lifetime_j.lifetime.name)) + .as_slice()); + } + } + + for bound in lifetime_i.bounds.iter() { + if !self.sess.features.issue_5723_bootstrap.get() { + self.sess.span_err( + bound.span, + "region bounds require `issue_5723_bootstrap`"); } } } @@ -379,12 +389,12 @@ impl<'a> LifetimeContext<'a> { } } -fn search_lifetimes(lifetimes: &Vec, +fn search_lifetimes(lifetimes: &Vec, lifetime_ref: &ast::Lifetime) -> Option<(uint, ast::NodeId)> { for (i, lifetime_decl) in lifetimes.iter().enumerate() { - if lifetime_decl.name == lifetime_ref.name { - return Some((i, lifetime_decl.id)); + if lifetime_decl.lifetime.name == lifetime_ref.name { + return Some((i, lifetime_decl.lifetime.id)); } } return None; @@ -392,15 +402,15 @@ fn search_lifetimes(lifetimes: &Vec, /////////////////////////////////////////////////////////////////////////// -pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec { +pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec { let referenced_idents = free_lifetimes(&generics.ty_params); if referenced_idents.is_empty() { return Vec::new(); } generics.lifetimes.iter() - .filter(|l| referenced_idents.iter().any(|&i| i == l.name)) - .map(|l| *l) + .filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name)) + .map(|l| (*l).clone()) .collect() } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 9a48045b369bd..fb0a9e32df916 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -804,9 +804,10 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { generics.lifetimes .iter() .enumerate() - .map(|(i, def)| ty::ReEarlyBound(def.id, + .map(|(i, def)| ty::ReEarlyBound(def.lifetime.id, subst::TypeSpace, - i, def.name)) + i, + def.lifetime.name)) .collect(); let types = @@ -1073,7 +1074,7 @@ fn add_unsized_bound(ccx: &CrateCtxt, fn ty_generics(ccx: &CrateCtxt, space: subst::ParamSpace, - lifetimes: &Vec, + lifetimes: &Vec, types: &OwnedSlice, base_generics: ty::Generics) -> ty::Generics @@ -1081,10 +1082,10 @@ fn ty_generics(ccx: &CrateCtxt, let mut result = base_generics; for (i, l) in lifetimes.iter().enumerate() { - let def = ty::RegionParameterDef { name: l.name, + let def = ty::RegionParameterDef { name: l.lifetime.name, space: space, index: i, - def_id: local_def(l.id) }; + def_id: local_def(l.lifetime.id) }; debug!("ty_generics: def for region param: {}", def); result.regions.push(space, def); } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 8be1700b635b4..e191fb343b53a 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -976,10 +976,13 @@ impl<'a> Rebuilder<'a> { -> ast::Generics { let mut lifetimes = Vec::new(); for lt in add.iter() { - lifetimes.push(*lt); + lifetimes.push(ast::LifetimeDef { lifetime: *lt, + bounds: Vec::new() }); } for lt in generics.lifetimes.iter() { - if keep.contains(<.name) || !remove.contains(<.name) { + if keep.contains(<.lifetime.name) || + !remove.contains(<.lifetime.name) + { lifetimes.push((*lt).clone()); } } @@ -1439,7 +1442,7 @@ impl Resolvable for Rc { fn lifetimes_in_scope(tcx: &ty::ctxt, scope_id: ast::NodeId) - -> Vec { + -> Vec { let mut taken = Vec::new(); let parent = tcx.map.get_parent(scope_id); let method_id_opt = match tcx.map.find(parent) { @@ -1486,10 +1489,10 @@ struct LifeGiver { } impl LifeGiver { - fn with_taken(taken: &[ast::Lifetime]) -> LifeGiver { + fn with_taken(taken: &[ast::LifetimeDef]) -> LifeGiver { let mut taken_ = HashSet::new(); for lt in taken.iter() { - let lt_name = token::get_name(lt.name).get().to_string(); + let lt_name = token::get_name(lt.lifetime.name).get().to_string(); taken_.insert(lt_name); } LifeGiver { diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 4a8bc97183ace..be9ae0cc719f2 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -358,7 +358,8 @@ impl<'a> Visitor<()> for TermsContext<'a> { ast::ItemStruct(_, ref generics) | ast::ItemTrait(ref generics, _, _, _) => { for (i, p) in generics.lifetimes.iter().enumerate() { - self.add_inferred(item.id, RegionParam, TypeSpace, i, p.id); + let id = p.lifetime.id; + self.add_inferred(item.id, RegionParam, TypeSpace, i, id); } for (i, p) in generics.ty_params.iter().enumerate() { self.add_inferred(item.id, TypeParam, TypeSpace, i, p.id); diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 94dea6cb540e3..d45ebb3858e9f 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -410,8 +410,8 @@ mod svh_visitor { SawLifetimeRef(content(l.name)).hash(self.st); } - fn visit_lifetime_decl(&mut self, l: &Lifetime, _: E) { - SawLifetimeDecl(content(l.name)).hash(self.st); + fn visit_lifetime_decl(&mut self, l: &LifetimeDef, _: E) { + SawLifetimeDecl(content(l.lifetime.name)).hash(self.st); } // We do recursively walk the bodies of functions/methods diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e9d5fb70281e7..8dc57d3e574ad 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -614,6 +614,12 @@ impl Clean for ast::Lifetime { } } +impl Clean for ast::LifetimeDef { + fn clean(&self) -> Lifetime { + Lifetime(token::get_name(self.lifetime.name).get().to_string()) + } +} + impl Clean for ty::RegionParameterDef { fn clean(&self) -> Lifetime { Lifetime(token::get_name(self.name).get().to_string()) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2d39a47a85e67..fc000d2357e30 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -160,6 +160,12 @@ pub struct Lifetime { pub name: Name } +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct LifetimeDef { + pub lifetime: Lifetime, + pub bounds: Vec +} + /// A "Path" is essentially Rust's notion of a name; for instance: /// std::cmp::PartialEq . It's represented as a sequence of identifiers, /// along with a bunch of supporting information. @@ -231,7 +237,7 @@ pub struct TyParam { /// of a function, enum, trait, etc. #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Generics { - pub lifetimes: Vec, + pub lifetimes: Vec, pub ty_params: OwnedSlice, } @@ -861,7 +867,7 @@ impl fmt::Show for Onceness { /// Represents the type of a closure #[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct ClosureTy { - pub lifetimes: Vec, + pub lifetimes: Vec, pub fn_style: FnStyle, pub onceness: Onceness, pub decl: P, @@ -876,7 +882,7 @@ pub struct ClosureTy { pub struct BareFnTy { pub fn_style: FnStyle, pub abi: Abi, - pub lifetimes: Vec, + pub lifetimes: Vec, pub decl: P } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index e58187fe30d13..cf2b5bc406373 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -369,7 +369,7 @@ impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { self.operation.visit_id(type_parameter.id) } for lifetime in generics.lifetimes.iter() { - self.operation.visit_id(lifetime.id) + self.operation.visit_id(lifetime.lifetime.id) } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index d500600e25d0c..0e687c02c1daf 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -73,6 +73,11 @@ pub trait AstBuilder { fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; fn typarambound(&self, path: ast::Path) -> ast::TyParamBound; fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime; + fn lifetime_def(&self, + span: Span, + name: ast::Name, + bounds: Vec) + -> ast::LifetimeDef; // statements fn stmt_expr(&self, expr: Gc) -> Gc; @@ -456,6 +461,17 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, name: name } } + fn lifetime_def(&self, + span: Span, + name: ast::Name, + bounds: Vec) + -> ast::LifetimeDef { + ast::LifetimeDef { + lifetime: self.lifetime(span, name), + bounds: bounds + } + } + fn stmt_expr(&self, expr: Gc) -> Gc { box(GC) respan(expr.span, ast::StmtSemi(expr, ast::DUMMY_NODE_ID)) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 9225e4414c40e..5842ca4a0d54d 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -395,7 +395,7 @@ impl<'a> TraitDef<'a> { let mut ty_params = ty_params.into_vec(); // Copy the lifetimes - lifetimes.extend(generics.lifetimes.iter().map(|l| *l)); + lifetimes.extend(generics.lifetimes.iter().map(|l| (*l).clone())); // Create the type parameters. ty_params.extend(generics.ty_params.iter().map(|ty_param| { @@ -429,7 +429,11 @@ impl<'a> TraitDef<'a> { cx.ty_ident(self.span, ty_param.ident) }); - let self_lifetimes = generics.lifetimes.clone(); + let self_lifetimes: Vec = + generics.lifetimes + .iter() + .map(|ld| ld.lifetime) + .collect(); // Create the type of `self`. let self_type = cx.ty_path( diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index 5d8b56606986b..2130b6f4e9dbc 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -174,7 +174,9 @@ impl<'a> Ty<'a> { let self_params = self_generics.ty_params.map(|ty_param| { cx.ty_ident(span, ty_param.ident) }); - let lifetimes = self_generics.lifetimes.clone(); + let lifetimes = self_generics.lifetimes.iter() + .map(|d| d.lifetime) + .collect(); cx.path_all(span, false, vec!(self_ty), lifetimes, self_params.into_vec()) @@ -200,7 +202,7 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, 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) @@ -210,7 +212,7 @@ fn mk_generics(lifetimes: Vec, ty_params: Vec ) -> /// Lifetimes and bounds on type parameters #[deriving(Clone)] pub struct LifetimeBounds<'a> { - pub lifetimes: Vec<&'a str>, + pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, pub bounds: Vec<(&'a str, Option, Vec>)>, } @@ -226,8 +228,11 @@ impl<'a> LifetimeBounds<'a> { self_ty: Ident, self_generics: &Generics) -> Generics { - let lifetimes = self.lifetimes.iter().map(|lt| { - cx.lifetime(span, cx.ident_of(*lt).name) + let lifetimes = self.lifetimes.iter().map(|&(ref lt, ref bounds)| { + let bounds = + bounds.iter().map( + |b| cx.lifetime(span, cx.ident_of(*b).name)).collect(); + cx.lifetime_def(span, cx.ident_of(*lt).name, bounds) }).collect(); let ty_params = self.bounds.iter().map(|t| { match t { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2f82702ece497..80325c64349e8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -163,6 +163,10 @@ pub trait Folder { noop_fold_lifetime(l, self) } + fn fold_lifetime_def(&mut self, l: &LifetimeDef) -> LifetimeDef { + noop_fold_lifetime_def(l, self) + } + fn fold_attribute(&mut self, at: Attribute) -> Attribute { noop_fold_attribute(at, self) } @@ -187,6 +191,10 @@ pub trait Folder { noop_fold_lifetimes(lts, self) } + fn fold_lifetime_defs(&mut self, lts: &[LifetimeDef]) -> Vec { + noop_fold_lifetime_defs(lts, self) + } + fn fold_ty_param(&mut self, tp: &TyParam) -> TyParam { noop_fold_ty_param(tp, self) } @@ -337,7 +345,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { onceness: f.onceness, bounds: fld.fold_opt_bounds(&f.bounds), decl: fld.fold_fn_decl(&*f.decl), - lifetimes: f.lifetimes.iter().map(|l| fld.fold_lifetime(l)).collect(), + lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()), }, fld.fold_opt_lifetime(region)) } TyProc(ref f) => { @@ -346,12 +354,12 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { onceness: f.onceness, bounds: fld.fold_opt_bounds(&f.bounds), decl: fld.fold_fn_decl(&*f.decl), - lifetimes: f.lifetimes.iter().map(|l| fld.fold_lifetime(l)).collect(), + lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()), }) } TyBareFn(ref f) => { TyBareFn(box(GC) BareFnTy { - lifetimes: f.lifetimes.iter().map(|l| fld.fold_lifetime(l)).collect(), + lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()), fn_style: f.fn_style, abi: f.abi, decl: fld.fold_fn_decl(&*f.decl) @@ -665,10 +673,23 @@ pub fn noop_fold_lifetime(l: &Lifetime, fld: &mut T) -> Lifetime { } } +pub fn noop_fold_lifetime_def(l: &LifetimeDef, fld: &mut T) + -> LifetimeDef +{ + LifetimeDef { + lifetime: fld.fold_lifetime(&l.lifetime), + bounds: fld.fold_lifetimes(l.bounds.as_slice()), + } +} + pub fn noop_fold_lifetimes(lts: &[Lifetime], fld: &mut T) -> Vec { lts.iter().map(|l| fld.fold_lifetime(l)).collect() } +pub fn noop_fold_lifetime_defs(lts: &[LifetimeDef], fld: &mut T) -> Vec { + lts.iter().map(|l| fld.fold_lifetime_def(l)).collect() +} + pub fn noop_fold_opt_lifetime(o_lt: &Option, fld: &mut T) -> Option { o_lt.as_ref().map(|lt| fld.fold_lifetime(lt)) @@ -676,7 +697,7 @@ pub fn noop_fold_opt_lifetime(o_lt: &Option, fld: &mut T) pub fn noop_fold_generics(generics: &Generics, fld: &mut T) -> Generics { Generics {ty_params: fld.fold_ty_params(generics.ty_params.as_slice()), - lifetimes: fld.fold_lifetimes(generics.lifetimes.as_slice())} + lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice())} } pub fn noop_fold_struct_def(struct_def: Gc, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c9fba355c4d58..7ea000d3aac41 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1053,10 +1053,10 @@ impl<'a> Parser<'a> { */ - let lifetimes = if self.eat(&token::LT) { - let lifetimes = self.parse_lifetimes(); + let lifetime_defs = if self.eat(&token::LT) { + let lifetime_defs = self.parse_lifetime_defs(); self.expect_gt(); - lifetimes + lifetime_defs } else { Vec::new() }; @@ -1082,7 +1082,7 @@ impl<'a> Parser<'a> { onceness: Once, bounds: bounds, decl: decl, - lifetimes: lifetimes, + lifetimes: lifetime_defs, }) } @@ -1096,7 +1096,7 @@ impl<'a> Parser<'a> { | | | | | Return type | | | | Closure bounds | | | Argument types - | | Lifetimes + | | Lifetime defs | Once-ness (a.k.a., affine) Function Style @@ -1105,11 +1105,11 @@ impl<'a> Parser<'a> { let fn_style = self.parse_unsafety(); let onceness = if self.eat_keyword(keywords::Once) {Once} else {Many}; - let lifetimes = if self.eat(&token::LT) { - let lifetimes = self.parse_lifetimes(); + let lifetime_defs = if self.eat(&token::LT) { + let lifetime_defs = self.parse_lifetime_defs(); self.expect_gt(); - lifetimes + lifetime_defs } else { Vec::new() }; @@ -1164,7 +1164,7 @@ impl<'a> Parser<'a> { onceness: onceness, bounds: bounds, decl: decl, - lifetimes: lifetimes, + lifetimes: lifetime_defs, }, region) } } @@ -1179,7 +1179,7 @@ impl<'a> Parser<'a> { /// Parse a function type (following the 'fn') pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool) - -> (P, Vec) { + -> (P, Vec) { /* (fn) <'lt> (S) -> T @@ -1187,13 +1187,13 @@ impl<'a> Parser<'a> { | | | | | Return type | Argument types - Lifetimes + Lifetime_defs */ - let lifetimes = if self.eat(&token::LT) { - let lifetimes = self.parse_lifetimes(); + let lifetime_defs = if self.eat(&token::LT) { + let lifetime_defs = self.parse_lifetime_defs(); self.expect_gt(); - lifetimes + lifetime_defs } else { Vec::new() }; @@ -1206,7 +1206,7 @@ impl<'a> Parser<'a> { cf: ret_style, variadic: variadic }); - (decl, lifetimes) + (decl, lifetime_defs) } /// Parse the methods in a trait declaration @@ -1770,31 +1770,34 @@ impl<'a> Parser<'a> { } } - // matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) - // actually, it matches the empty one too, but putting that in there - // messes up the grammar.... - pub fn parse_lifetimes(&mut self) -> Vec { + pub fn parse_lifetime_defs(&mut self) -> Vec { /*! - * - * Parses zero or more comma separated lifetimes. - * Expects each lifetime to be followed by either - * a comma or `>`. Used when parsing type parameter - * lists, where we expect something like `<'a, 'b, T>`. + * Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` + * where `lifetime_def = lifetime [':' lifetimes]` */ let mut res = Vec::new(); loop { match self.token { token::LIFETIME(_) => { - res.push(self.parse_lifetime()); + let lifetime = self.parse_lifetime(); + let bounds = + if self.eat(&token::COLON) { + self.parse_lifetimes(token::BINOP(token::PLUS)) + } else { + Vec::new() + }; + res.push(ast::LifetimeDef { lifetime: lifetime, + bounds: bounds }); } + _ => { return res; } } match self.token { - token::COMMA => { self.bump();} + token::COMMA => { self.bump(); } token::GT => { return res; } token::BINOP(token::SHR) => { return res; } _ => { @@ -1807,6 +1810,36 @@ impl<'a> Parser<'a> { } } + // matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) + // actually, it matches the empty one too, but putting that in there + // messes up the grammar.... + pub fn parse_lifetimes(&mut self, sep: token::Token) -> Vec { + /*! + * Parses zero or more comma separated lifetimes. + * Expects each lifetime to be followed by either + * a comma or `>`. Used when parsing type parameter + * lists, where we expect something like `<'a, 'b, T>`. + */ + + let mut res = Vec::new(); + loop { + match self.token { + token::LIFETIME(_) => { + res.push(self.parse_lifetime()); + } + _ => { + return res; + } + } + + if self.token != sep { + return res; + } + + self.bump(); + } + } + pub fn token_is_mutability(tok: &token::Token) -> bool { token::is_keyword(keywords::Mut, tok) || token::is_keyword(keywords::Const, tok) @@ -3664,7 +3697,7 @@ impl<'a> Parser<'a> { /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> ast::Generics { if self.eat(&token::LT) { - let lifetimes = self.parse_lifetimes(); + let lifetime_defs = self.parse_lifetime_defs(); let mut seen_default = false; let ty_params = self.parse_seq_to_gt(Some(token::COMMA), |p| { p.forbid_lifetime(); @@ -3678,14 +3711,14 @@ impl<'a> Parser<'a> { } ty_param }); - ast::Generics { lifetimes: lifetimes, ty_params: ty_params } + ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params } } else { ast_util::empty_generics() } } fn parse_generic_values_after_lt(&mut self) -> (Vec, Vec> ) { - let lifetimes = self.parse_lifetimes(); + let lifetimes = self.parse_lifetimes(token::COMMA); let result = self.parse_seq_to_gt( Some(token::COMMA), |p| { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ab0269f807a8d..d60e4cb3b542b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2082,10 +2082,26 @@ impl<'a> State<'a> { } pub fn print_lifetime(&mut self, - lifetime: &ast::Lifetime) -> IoResult<()> { + lifetime: &ast::Lifetime) + -> IoResult<()> + { self.print_name(lifetime.name) } + pub fn print_lifetime_def(&mut self, + lifetime: &ast::LifetimeDef) + -> IoResult<()> + { + try!(self.print_lifetime(&lifetime.lifetime)); + let mut sep = ":"; + for v in lifetime.bounds.iter() { + try!(word(&mut self.s, sep)); + try!(self.print_lifetime(v)); + sep = "+"; + } + Ok(()) + } + pub fn print_generics(&mut self, generics: &ast::Generics) -> IoResult<()> { let total = generics.lifetimes.len() + generics.ty_params.len(); @@ -2102,7 +2118,7 @@ impl<'a> State<'a> { |s, &idx| { if idx < generics.lifetimes.len() { let lifetime = generics.lifetimes.get(idx); - s.print_lifetime(lifetime) + s.print_lifetime_def(lifetime) } else { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 733c4bfc2b00b..647e81db1f1c0 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -122,7 +122,7 @@ pub trait Visitor { fn visit_lifetime_ref(&mut self, _lifetime: &Lifetime, _e: E) { /*! Visits a reference to a lifetime */ } - fn visit_lifetime_decl(&mut self, _lifetime: &Lifetime, _e: E) { + fn visit_lifetime_decl(&mut self, _lifetime: &LifetimeDef, _e: E) { /*! Visits a declaration of a lifetime */ } fn visit_explicit_self(&mut self, es: &ExplicitSelf, e: E) { @@ -424,7 +424,7 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { } fn walk_lifetime_decls>(visitor: &mut V, - lifetimes: &Vec, + lifetimes: &Vec, env: E) { for l in lifetimes.iter() { visitor.visit_lifetime_decl(l, env.clone()); diff --git a/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs b/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs new file mode 100644 index 0000000000000..0f79716f370e8 --- /dev/null +++ b/src/test/compile-fail/regions-bound-lists-feature-gate-2.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty + +trait Foo { } + +fn foo<'a, 'b:'a>() { //~ ERROR region bounds require `issue_5723_bootstrap` +} + +pub fn main() { } diff --git a/src/test/run-pass/regions-bound-lists-feature-gate-2.rs b/src/test/run-pass/regions-bound-lists-feature-gate-2.rs new file mode 100644 index 0000000000000..0a95a89d57c32 --- /dev/null +++ b/src/test/run-pass/regions-bound-lists-feature-gate-2.rs @@ -0,0 +1,20 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty + +#![feature(issue_5723_bootstrap)] + +trait Foo { } + +fn foo<'a, 'b, 'c:'a+'b, 'd>() { +} + +pub fn main() { }