Skip to content

Commit

Permalink
auto merge of rust-lang#17028 : pcwalton/rust/higher-rank-trait-lifet…
Browse files Browse the repository at this point in the history
…imes, r=pnkfelix

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

This is part of unboxed closures.

r? @nikomatsakis
  • Loading branch information
bors committed Sep 23, 2014
2 parents 2f9669c + 5376b1c commit d80cd3d
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 10 deletions.
74 changes: 72 additions & 2 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use driver::session::Session;
use middle::subst;
use syntax::ast;
use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::special_idents;
use syntax::parse::token;
use syntax::print::pprust::{lifetime_to_string};
Expand Down Expand Up @@ -98,8 +99,22 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
ast::ItemTy(_, ref generics) |
ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) |
ast::ItemImpl(ref generics, _, _, _) |
ast::ItemTrait(ref generics, _, _, _) => &generics.lifetimes
ast::ItemTrait(ref generics, _, _, _) => {
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| {
Expand Down Expand Up @@ -155,6 +170,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
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> {
Expand All @@ -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`.
fn visit_fn_decl(&mut self,
n: ast::NodeId,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
ast::TraitTyParamBound(ast::TraitRef {
path: new_path,
ref_id: tr.ref_id,
lifetimes: tr.lifetimes.clone(),
})
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ pub type TyParamBounds = OwnedSlice<TyParamBound>;
pub struct UnboxedFnBound {
pub path: Path,
pub decl: P<FnDecl>,
pub lifetimes: Vec<LifetimeDef>,
pub ref_id: NodeId,
}

Expand Down Expand Up @@ -1219,6 +1220,7 @@ 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)]
Expand Down
3 changes: 2 additions & 1 deletion src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
ast::TraitRef {
path: path,
ref_id: ast::DUMMY_NODE_ID
ref_id: ast::DUMMY_NODE_ID,
lifetimes: Vec::new(),
}
}

Expand Down
15 changes: 12 additions & 3 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,11 +668,13 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
UnboxedFnBound {
ref path,
ref decl,
ref lifetimes,
ref_id
} => {
UnboxedFnTyParamBound(P(UnboxedFnBound {
path: fld.fold_path(path.clone()),
decl: fld.fold_fn_decl(decl.clone()),
lifetimes: fld.fold_lifetime_defs(lifetimes.clone()),
ref_id: fld.new_id(ref_id),
}))
}
Expand Down Expand Up @@ -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 {
TraitRef {
ref_id: fld.new_id(ref_id),
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,
..
} = p;
ast::TraitRef {
path: fld.fold_path(path),
ref_id: id,
lifetimes: fld.fold_lifetime_defs(lifetimes),
}
}

Expand Down
26 changes: 23 additions & 3 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ use ast::{FnOnceUnboxedClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
use ast::{Ident, NormalFn, Inherited, ImplItem, Item, Item_, ItemStatic};
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::{LitNil, LitStr, LitInt, Local, LocalLet};
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, Matcher, MatchNonterminal};
Expand Down Expand Up @@ -3791,8 +3792,21 @@ impl<'a> Parser<'a> {
{
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,
Expand All @@ -3818,12 +3832,14 @@ impl<'a> Parser<'a> {
cf: return_style,
variadic: false,
}),
lifetimes: lifetime_defs,
ref_id: ast::DUMMY_NODE_ID,
})));
} else {
result.push(TraitTyParamBound(ast::TraitRef {
path: path,
ref_id: ast::DUMMY_NODE_ID,
lifetimes: lifetime_defs,
}))
}
}
Expand Down Expand Up @@ -3852,6 +3868,7 @@ impl<'a> Parser<'a> {
ast::TraitRef {
path: path,
ref_id: ast::DUMMY_NODE_ID,
lifetimes: Vec::new(),
}
}

Expand Down Expand Up @@ -4482,8 +4499,11 @@ impl<'a> Parser<'a> {
// New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node {
TyPath(ref path, None, node_id) => {
Some(TraitRef { path: (*path).clone(),
ref_id: node_id })
Some(TraitRef {
path: (*path).clone(),
ref_id: node_id,
lifetimes: Vec::new(),
})
}
TyPath(_, Some(_), _) => {
self.span_err(ty.span,
Expand Down
10 changes: 10 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,16 @@ 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)
}

Expand Down
5 changes: 4 additions & 1 deletion src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
/// 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)
}

Expand Down Expand Up @@ -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(&*function_declaration.decl.output);
walk_lifetime_decls(visitor, &function_declaration.lifetimes);
}
RegionTyParamBound(ref lifetime) => {
visitor.visit_lifetime_ref(lifetime);
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/regions-name-duplicated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
//~^ ERROR lifetime name `'a` declared twice
x: &'a int
}

Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/regions-name-static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `'static`
//~^ ERROR illegal lifetime parameter name: `'static`
x: &'static int
}

Expand Down

0 comments on commit d80cd3d

Please sign in to comment.