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:
parent
3f299ff19d
commit
5376b1c798
10 changed files with 128 additions and 10 deletions
|
@ -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,
|
||||||
|
|
|
@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue