1
Fork 0

librustc: Parse and resolve higher-rank lifetimes in traits.

They will ICE during typechecking if used, because they depend on trait
reform.

This is part of unboxed closures.
This commit is contained in:
Patrick Walton 2014-09-05 12:21:02 -07:00
parent 3f299ff19d
commit 5376b1c798
10 changed files with 128 additions and 10 deletions

View file

@ -21,6 +21,7 @@ use driver::session::Session;
use middle::subst; use middle::subst;
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::special_idents; use syntax::parse::token::special_idents;
use syntax::parse::token; use syntax::parse::token;
use syntax::print::pprust::{lifetime_to_string}; use syntax::print::pprust::{lifetime_to_string};
@ -98,8 +99,22 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
ast::ItemTy(_, ref generics) | ast::ItemTy(_, ref generics) |
ast::ItemEnum(_, ref generics) | ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) | ast::ItemStruct(_, ref generics) |
ast::ItemImpl(ref generics, _, _, _) | ast::ItemTrait(ref generics, _, _, _) => {
ast::ItemTrait(ref generics, _, _, _) => &generics.lifetimes self.with(|scope, f| {
f(EarlyScope(subst::TypeSpace,
&generics.lifetimes,
scope))
}, |v| v.check_lifetime_defs(&generics.lifetimes));
&generics.lifetimes
}
ast::ItemImpl(ref generics, _, _, _) => {
self.with(|scope, f| {
f(EarlyScope(subst::TypeSpace,
&generics.lifetimes,
scope))
}, |v| v.check_lifetime_defs(&generics.lifetimes));
&generics.lifetimes
}
}; };
self.with(|_, f| f(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE)), |v| { self.with(|_, f| f(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE)), |v| {
@ -155,6 +170,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
} }
self.resolve_lifetime_ref(lifetime_ref); self.resolve_lifetime_ref(lifetime_ref);
} }
fn visit_generics(&mut self, generics: &ast::Generics) {
for ty_param in generics.ty_params.iter() {
self.visit_ty_param_bounds(&ty_param.bounds);
match ty_param.default {
Some(ref ty) => self.visit_ty(&**ty),
None => {}
}
}
for predicate in generics.where_clause.predicates.iter() {
self.visit_ident(predicate.span, predicate.ident);
self.visit_ty_param_bounds(&predicate.bounds);
}
}
} }
impl<'a> LifetimeContext<'a> { impl<'a> LifetimeContext<'a> {
@ -167,6 +196,47 @@ impl<'a> LifetimeContext<'a> {
})) }))
} }
fn visit_ty_param_bounds(&mut self,
bounds: &OwnedSlice<ast::TyParamBound>) {
for bound in bounds.iter() {
match *bound {
ast::TraitTyParamBound(ref trait_ref) => {
self.visit_trait_ref(trait_ref);
}
ast::UnboxedFnTyParamBound(ref fn_decl) => {
self.visit_unboxed_fn_ty_param_bound(&**fn_decl);
}
ast::RegionTyParamBound(ref lifetime) => {
self.visit_lifetime_ref(lifetime);
}
}
}
}
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
self.with(|scope, f| {
f(LateScope(trait_ref.ref_id, &trait_ref.lifetimes, scope))
}, |v| {
v.check_lifetime_defs(&trait_ref.lifetimes);
for lifetime in trait_ref.lifetimes.iter() {
v.visit_lifetime_decl(lifetime);
}
v.visit_path(&trait_ref.path, trait_ref.ref_id);
})
}
fn visit_unboxed_fn_ty_param_bound(&mut self,
bound: &ast::UnboxedFnBound) {
self.with(|scope, f| {
f(LateScope(bound.ref_id, &bound.lifetimes, scope))
}, |v| {
for argument in bound.decl.inputs.iter() {
v.visit_ty(&*argument.ty);
}
v.visit_ty(&*bound.decl.output);
})
}
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`. /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
fn visit_fn_decl(&mut self, fn visit_fn_decl(&mut self,
n: ast::NodeId, n: ast::NodeId,

View file

@ -1110,6 +1110,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
ast::TraitTyParamBound(ast::TraitRef { ast::TraitTyParamBound(ast::TraitRef {
path: new_path, path: new_path,
ref_id: tr.ref_id, ref_id: tr.ref_id,
lifetimes: tr.lifetimes.clone(),
}) })
} }
} }

View file

@ -223,6 +223,7 @@ pub type TyParamBounds = OwnedSlice<TyParamBound>;
pub struct UnboxedFnBound { pub struct UnboxedFnBound {
pub path: Path, pub path: Path,
pub decl: P<FnDecl>, pub decl: P<FnDecl>,
pub lifetimes: Vec<LifetimeDef>,
pub ref_id: NodeId, pub ref_id: NodeId,
} }
@ -1219,6 +1220,7 @@ pub struct Attribute_ {
pub struct TraitRef { pub struct TraitRef {
pub path: Path, pub path: Path,
pub ref_id: NodeId, pub ref_id: NodeId,
pub lifetimes: Vec<LifetimeDef>,
} }
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]

View file

@ -435,7 +435,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef { fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
ast::TraitRef { ast::TraitRef {
path: path, path: path,
ref_id: ast::DUMMY_NODE_ID ref_id: ast::DUMMY_NODE_ID,
lifetimes: Vec::new(),
} }
} }

View file

@ -668,11 +668,13 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
UnboxedFnBound { UnboxedFnBound {
ref path, ref path,
ref decl, ref decl,
ref lifetimes,
ref_id ref_id
} => { } => {
UnboxedFnTyParamBound(P(UnboxedFnBound { UnboxedFnTyParamBound(P(UnboxedFnBound {
path: fld.fold_path(path.clone()), path: fld.fold_path(path.clone()),
decl: fld.fold_fn_decl(decl.clone()), decl: fld.fold_fn_decl(decl.clone()),
lifetimes: fld.fold_lifetime_defs(lifetimes.clone()),
ref_id: fld.new_id(ref_id), ref_id: fld.new_id(ref_id),
})) }))
} }
@ -808,10 +810,17 @@ pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) ->
}) })
} }
pub fn noop_fold_trait_ref<T: Folder>(TraitRef {ref_id, path}: TraitRef, fld: &mut T) -> TraitRef { pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
TraitRef { let id = fld.new_id(p.ref_id);
ref_id: fld.new_id(ref_id), let TraitRef {
path,
lifetimes,
..
} = p;
ast::TraitRef {
path: fld.fold_path(path), path: fld.fold_path(path),
ref_id: id,
lifetimes: fld.fold_lifetime_defs(lifetimes),
} }
} }

View file

@ -34,7 +34,8 @@ use ast::{FnOnceUnboxedClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
use ast::{Ident, NormalFn, Inherited, ImplItem, Item, Item_, ItemStatic}; use ast::{Ident, NormalFn, Inherited, ImplItem, Item, Item_, ItemStatic};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl};
use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, Lit, Lit_}; use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy};
use ast::{LifetimeDef, Lit, Lit_};
use ast::{LitBool, LitChar, LitByte, LitBinary}; use ast::{LitBool, LitChar, LitByte, LitBinary};
use ast::{LitNil, LitStr, LitInt, Local, LocalLet}; use ast::{LitNil, LitStr, LitInt, Local, LocalLet};
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, Matcher, MatchNonterminal}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, Matcher, MatchNonterminal};
@ -3791,8 +3792,21 @@ impl<'a> Parser<'a> {
{ {
let mut result = vec!(); let mut result = vec!();
loop { 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 { match self.token {
token::LIFETIME(lifetime) => { 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 { result.push(RegionTyParamBound(ast::Lifetime {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: self.span, span: self.span,
@ -3818,12 +3832,14 @@ impl<'a> Parser<'a> {
cf: return_style, cf: return_style,
variadic: false, variadic: false,
}), }),
lifetimes: lifetime_defs,
ref_id: ast::DUMMY_NODE_ID, ref_id: ast::DUMMY_NODE_ID,
}))); })));
} else { } else {
result.push(TraitTyParamBound(ast::TraitRef { result.push(TraitTyParamBound(ast::TraitRef {
path: path, path: path,
ref_id: ast::DUMMY_NODE_ID, ref_id: ast::DUMMY_NODE_ID,
lifetimes: lifetime_defs,
})) }))
} }
} }
@ -3852,6 +3868,7 @@ impl<'a> Parser<'a> {
ast::TraitRef { ast::TraitRef {
path: path, path: path,
ref_id: ast::DUMMY_NODE_ID, ref_id: ast::DUMMY_NODE_ID,
lifetimes: Vec::new(),
} }
} }
@ -4482,8 +4499,11 @@ impl<'a> Parser<'a> {
// New-style trait. Reinterpret the type as a trait. // New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node { let opt_trait_ref = match ty.node {
TyPath(ref path, None, node_id) => { TyPath(ref path, None, node_id) => {
Some(TraitRef { path: (*path).clone(), Some(TraitRef {
ref_id: node_id }) path: (*path).clone(),
ref_id: node_id,
lifetimes: Vec::new(),
})
} }
TyPath(_, Some(_), _) => { TyPath(_, Some(_), _) => {
self.span_err(ty.span, self.span_err(ty.span,

View file

@ -900,6 +900,16 @@ impl<'a> State<'a> {
} }
fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> { 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) self.print_path(&t.path, false)
} }

View file

@ -202,7 +202,9 @@ pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V,
/// Like with walk_method_helper this doesn't correspond to a method /// Like with walk_method_helper this doesn't correspond to a method
/// in Visitor, and so it gets a _helper suffix. /// in Visitor, and so it gets a _helper suffix.
pub fn walk_trait_ref_helper<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef) { 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);
visitor.visit_path(&trait_ref.path, trait_ref.ref_id) visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
} }
@ -495,6 +497,7 @@ pub fn walk_ty_param_bounds<'v, V: Visitor<'v>>(visitor: &mut V,
visitor.visit_ty(&*argument.ty) visitor.visit_ty(&*argument.ty)
} }
visitor.visit_ty(&*function_declaration.decl.output); visitor.visit_ty(&*function_declaration.decl.output);
walk_lifetime_decls(visitor, &function_declaration.lifetimes);
} }
RegionTyParamBound(ref lifetime) => { RegionTyParamBound(ref lifetime) => {
visitor.visit_lifetime_ref(lifetime); visitor.visit_lifetime_ref(lifetime);

View file

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
//~^ ERROR lifetime name `'a` declared twice
x: &'a int x: &'a int
} }

View file

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `'static` struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `'static`
//~^ ERROR illegal lifetime parameter name: `'static`
x: &'static int x: &'static int
} }