about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-09-05 12:21:02 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-09-22 21:14:58 -0700
commit5376b1c79870c80d0081540c72ae060d3ed5d1f5 (patch)
treed8191fe6c6eaa83ff613f9024996ee5a5f8355d8
parent3f299ff19ddb3ee4752e6db120689189ab4c4231 (diff)
downloadrust-5376b1c79870c80d0081540c72ae060d3ed5d1f5.tar.gz
rust-5376b1c79870c80d0081540c72ae060d3ed5d1f5.zip
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.
-rw-r--r--src/librustc/middle/resolve_lifetime.rs74
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs1
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ext/build.rs3
-rw-r--r--src/libsyntax/fold.rs15
-rw-r--r--src/libsyntax/parse/parser.rs26
-rw-r--r--src/libsyntax/print/pprust.rs10
-rw-r--r--src/libsyntax/visit.rs5
-rw-r--r--src/test/compile-fail/regions-name-duplicated.rs1
-rw-r--r--src/test/compile-fail/regions-name-static.rs1
10 files changed, 128 insertions, 10 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 22acdca5f9b..42ae8771224 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -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};
@@ -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| {
@@ -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> {
@@ -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,
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index 6ea80a59230..d35885cbf17 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -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(),
                     })
                 }
             }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5c84745c20c..74c69762be1 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -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,
 }
 
@@ -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)]
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 16ecd83180e..0586868eb45 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -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(),
         }
     }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 7ebb11c148b..91a339a73f7 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -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),
                     }))
                 }
@@ -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),
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 1ff6c3f9418..cbc710821f9 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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};
@@ -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,
@@ -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,
                         }))
                     }
                 }
@@ -3852,6 +3868,7 @@ impl<'a> Parser<'a> {
         ast::TraitRef {
             path: path,
             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.
             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,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 473179a037a..1fbd4af8627 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -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)
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 32084856817..3b2ed30b76d 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -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)
 }
 
@@ -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);
diff --git a/src/test/compile-fail/regions-name-duplicated.rs b/src/test/compile-fail/regions-name-duplicated.rs
index 518fe0b00b6..58eaa4c57fe 100644
--- a/src/test/compile-fail/regions-name-duplicated.rs
+++ b/src/test/compile-fail/regions-name-duplicated.rs
@@ -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
 }
 
diff --git a/src/test/compile-fail/regions-name-static.rs b/src/test/compile-fail/regions-name-static.rs
index 9f50ad36660..bc8ca87d7e2 100644
--- a/src/test/compile-fail/regions-name-static.rs
+++ b/src/test/compile-fail/regions-name-static.rs
@@ -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
 }