]> git.lizzy.rs Git - rust.git/commitdiff
Accept quantification of lifetimes outside the self type in where clauses.
authorNick Cameron <ncameron@mozilla.com>
Thu, 5 Feb 2015 08:46:01 +0000 (21:46 +1300)
committerNick Cameron <ncameron@mozilla.com>
Sun, 8 Feb 2015 20:29:53 +0000 (09:29 +1300)
Closes #20022

src/librustc/diagnostics.rs
src/librustc/middle/infer/error_reporting.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/ty.rs
src/librustc_typeck/astconv.rs
src/libsyntax/ast.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/deriving/generic/mod.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs

index a808b417b4c6b29768ac9b894bf39cee5871725f..efcc3715d3e3d97f22e3f0586fc039346b39d402 100644 (file)
     E0312, // lifetime of reference outlives lifetime of borrowed content
     E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
     E0314, // closure outlives stack frame
-    E0315 // cannot invoke closure outside of its lifetime
+    E0315, // cannot invoke closure outside of its lifetime
+    E0316 // nested quantification of lifetimes
 }
 
 __build_diagnostic_array! { DIAGNOSTICS }
index 1b513a13588c9360bf2d628cc73c0c0598c79842..99896535442d81363f00d01d88ea58ce0bd132e6 100644 (file)
@@ -1076,7 +1076,8 @@ fn rebuild_ty_param_bounds(&self,
                         trait_ref: ast::TraitRef {
                             path: new_path,
                             ref_id: tr.ref_id,
-                        }
+                        },
+                        span: poly_tr.span,
                     }, modifier)
                 }
             }
index 5e27023e026fbc7152401ecec9649e3281c673e5..6f38dc81064209b997752ae332c8ef5fbcc6c258 100644 (file)
@@ -45,8 +45,8 @@ pub enum DefRegion {
                   /* lifetime decl */ ast::NodeId),
 }
 
-// maps the id of each lifetime reference to the lifetime decl
-// that it corresponds to
+// Maps the id of each lifetime reference to the lifetime decl
+// that it corresponds to.
 pub type NamedRegionMap = NodeMap<DefRegion>;
 
 struct LifetimeContext<'a> {
@@ -54,6 +54,22 @@ struct LifetimeContext<'a> {
     named_region_map: &'a mut NamedRegionMap,
     scope: Scope<'a>,
     def_map: &'a DefMap,
+    // Deep breath. Our representation for poly trait refs contains a single
+    // binder and thus we only allow a single level of quantification. However,
+    // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
+    // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
+    // correct when representing these constraints, we should only introduce one
+    // scope. However, we want to support both locations for the quantifier and
+    // during lifetime resolution we want precise information (so we can't
+    // desugar in an earlier phase).
+
+    // SO, if we encounter a quantifier at the outer scope, we set
+    // trait_ref_hack to true (and introduce a scope), and then if we encounter
+    // a quantifier at the inner scope, we error. If trait_ref_hack is false,
+    // then we introduce the scope at the inner quantifier.
+
+    // I'm sorry.
+    trait_ref_hack: bool,
 }
 
 enum ScopeChain<'a> {
@@ -80,6 +96,7 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio
         named_region_map: &mut named_region_map,
         scope: &ROOT_SCOPE,
         def_map: def_map,
+        trait_ref_hack: false,
     }, krate);
     sess.abort_if_errors();
     named_region_map
@@ -198,9 +215,22 @@ fn visit_generics(&mut self, generics: &ast::Generics) {
             match predicate {
                 &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
                                                                                ref bounds,
+                                                                               ref bound_lifetimes,
                                                                                .. }) => {
-                    self.visit_ty(&**bounded_ty);
-                    visit::walk_ty_param_bounds_helper(self, bounds);
+                    if bound_lifetimes.len() > 0 {
+                        self.trait_ref_hack = true;
+                        let result = self.with(LateScope(bound_lifetimes, self.scope),
+                                               |old_scope, this| {
+                            this.check_lifetime_defs(old_scope, bound_lifetimes);
+                            this.visit_ty(&**bounded_ty);
+                            visit::walk_ty_param_bounds_helper(this, bounds);
+                        });
+                        self.trait_ref_hack = false;
+                        result
+                    } else {
+                        self.visit_ty(&**bounded_ty);
+                        visit::walk_ty_param_bounds_helper(self, bounds);
+                    }
                 }
                 &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
                                                                                 ref bounds,
@@ -222,18 +252,27 @@ fn visit_generics(&mut self, generics: &ast::Generics) {
         }
     }
 
-    fn visit_poly_trait_ref(&mut self, trait_ref:
-                            &ast::PolyTraitRef,
+    fn visit_poly_trait_ref(&mut self,
+                            trait_ref: &ast::PolyTraitRef,
                             _modifier: &ast::TraitBoundModifier) {
         debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
 
-        self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
-            this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
-            for lifetime in &trait_ref.bound_lifetimes {
-                this.visit_lifetime_def(lifetime);
+        if !self.trait_ref_hack || trait_ref.bound_lifetimes.len() > 0 {
+            if self.trait_ref_hack {
+                println!("{:?}", trait_ref.span);
+                span_err!(self.sess, trait_ref.span, E0316,
+                          "nested quantification of lifetimes");
             }
-            this.visit_trait_ref(&trait_ref.trait_ref)
-        })
+            self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
+                this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
+                for lifetime in &trait_ref.bound_lifetimes {
+                    this.visit_lifetime_def(lifetime);
+                }
+                this.visit_trait_ref(&trait_ref.trait_ref)
+            })
+        } else {
+            self.visit_trait_ref(&trait_ref.trait_ref)
+        }
     }
 
     fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
@@ -251,6 +290,7 @@ fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
             named_region_map: *named_region_map,
             scope: &wrap_scope,
             def_map: self.def_map,
+            trait_ref_hack: self.trait_ref_hack,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
index b29a23924bb12d6b460d168e78ab7fd01cc03fca..95f7ff58524402f37655c6dc68c6a64d8b33c1ed 100644 (file)
@@ -1478,7 +1478,7 @@ pub fn to_poly_trait_predicate(&self) -> PolyTraitPredicate<'tcx> {
 /// compiler's representation for things like `for<'a> Fn(&'a int)`
 /// (which would be represented by the type `PolyTraitRef ==
 /// Binder<TraitRef>`). Note that when we skolemize, instantiate,
-/// erase, or otherwise "discharge" these bound reons, we change the
+/// erase, or otherwise "discharge" these bound regions, we change the
 /// type from `Binder<T>` to just `T` (see
 /// e.g. `liberate_late_bound_regions`).
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
index 60771d126b51bc1274778fc9a39d7a632c7f19ef..0dbb53e09b7d97f32c28bb05c563e8d65503e898 100644 (file)
@@ -526,7 +526,7 @@ pub fn instantiate_poly_trait_ref<'tcx>(
 {
     let mut projections = Vec::new();
 
-    // the trait reference introduces a binding level here, so
+    // The trait reference introduces a binding level here, so
     // we need to shift the `rscope`. It'd be nice if we could
     // do away with this rscope stuff and work this knowledge
     // into resolve_lifetimes, as we do with non-omitted
index 71259ff5d9ade3032007ce1f02b5409c0a43cddd..f8793f81b199642e13371c51e2456765afb8f5e7 100644 (file)
@@ -443,6 +443,7 @@ pub enum WherePredicate {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct WhereBoundPredicate {
     pub span: Span,
+    pub bound_lifetimes: Vec<LifetimeDef>,
     pub bounded_ty: P<Ty>,
     pub bounds: OwnedSlice<TyParamBound>,
 }
@@ -1535,6 +1536,8 @@ pub struct PolyTraitRef {
 
     /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
     pub trait_ref: TraitRef,
+
+    pub span: Span,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
index a7d1baf08beacd0cef93fbbf511b4bca2c014c55..6d9a2fdb9f19814092c4173be5ace28cebccb8d0 100644 (file)
@@ -70,7 +70,7 @@ fn typaram(&self,
                default: Option<P<ast::Ty>>) -> ast::TyParam;
 
     fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
-    fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef;
+    fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef;
     fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
     fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
     fn lifetime_def(&self,
@@ -442,15 +442,16 @@ fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
         }
     }
 
-    fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef {
+    fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
         ast::PolyTraitRef {
             bound_lifetimes: Vec::new(),
-            trait_ref: self.trait_ref(path)
+            trait_ref: self.trait_ref(path),
+            span: span,
         }
     }
 
     fn typarambound(&self, path: ast::Path) -> ast::TyParamBound {
-        ast::TraitTyParamBound(self.poly_trait_ref(path), ast::TraitBoundModifier::None)
+        ast::TraitTyParamBound(self.poly_trait_ref(path.span, path), ast::TraitBoundModifier::None)
     }
 
     fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {
index 28573ef757b1295c7efc55eefe6e1e92f5048213..d9242417e047511fc4cd982a4869e01d86f75a48 100644 (file)
@@ -443,6 +443,7 @@ fn create_derived_impl(&self,
                 ast::WherePredicate::BoundPredicate(ref wb) => {
                     ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
                         span: self.span,
+                        bound_lifetimes: wb.bound_lifetimes.clone(),
                         bounded_ty: wb.bounded_ty.clone(),
                         bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
                     })
index b0ddb655882a86a9e6cb2f586db56439df971044..8f1d15f6da885f3d5304cc23ea892b6195d54099 100644 (file)
@@ -806,10 +806,12 @@ pub fn noop_fold_where_predicate<T: Folder>(
                                  fld: &mut T)
                                  -> WherePredicate {
     match pred {
-        ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bounded_ty,
+        ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_lifetimes,
+                                                                     bounded_ty,
                                                                      bounds,
                                                                      span}) => {
             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
                 bounded_ty: fld.fold_ty(bounded_ty),
                 bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
                 span: fld.new_span(span)
@@ -895,7 +897,8 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
 pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
     ast::PolyTraitRef {
         bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
-        trait_ref: fld.fold_trait_ref(p.trait_ref)
+        trait_ref: fld.fold_trait_ref(p.trait_ref),
+        span: fld.new_span(p.span),
     }
 }
 
index 3107f47de7859b83613478b5a193f0ef06221a3e..fd2f0685cab8386d3bf6cf59cd176547f869fdee 100644 (file)
@@ -1036,6 +1036,8 @@ pub fn parse_for_in_type(&mut self) -> Ty_ {
         */
 
         // parse <'lt>
+        let lo = self.span.lo;
+
         let lifetime_defs = self.parse_late_bound_lifetime_defs();
 
         // examine next token to decide to do
@@ -1047,9 +1049,11 @@ pub fn parse_for_in_type(&mut self) -> Ty_ {
                   self.token.is_ident() ||
                   self.token.is_path()
         {
+            let hi = self.span.hi;
             let trait_ref = self.parse_trait_ref();
             let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs,
-                                                     trait_ref: trait_ref };
+                                                     trait_ref: trait_ref,
+                                                     span: mk_sp(lo, hi)};
             let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
                 self.parse_ty_param_bounds(BoundParsingMode::Bare)
             } else {
@@ -4070,7 +4074,8 @@ fn parse_ty_param(&mut self) -> TyParam {
         if let Some(unbound) = unbound {
             let mut bounds_as_vec = bounds.into_vec();
             bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
-                                                                trait_ref: unbound },
+                                                                trait_ref: unbound,
+                                                                span: span },
                                                  TraitBoundModifier::Maybe));
             bounds = OwnedSlice::from_vec(bounds_as_vec);
         };
@@ -4223,6 +4228,16 @@ fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
                 }
 
                 _ => {
+                    let bound_lifetimes = if self.eat_keyword(keywords::For) {
+                        // Higher ranked constraint.
+                        self.expect(&token::Lt);
+                        let lifetime_defs = self.parse_lifetime_defs();
+                        self.expect_gt();
+                        lifetime_defs
+                    } else {
+                        vec![]
+                    };
+
                     let bounded_ty = self.parse_ty();
 
                     if self.eat(&token::Colon) {
@@ -4233,12 +4248,13 @@ fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
                         if bounds.len() == 0 {
                             self.span_err(span,
                                           "each predicate in a `where` clause must have \
-                                   at least one bound in it");
+                                           at least one bound in it");
                         }
 
                         generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
                                 ast::WhereBoundPredicate {
                                     span: span,
+                                    bound_lifetimes: bound_lifetimes,
                                     bounded_ty: bounded_ty,
                                     bounds: bounds,
                         }));
@@ -4674,8 +4690,12 @@ pub fn parse_method(&mut self,
 
     /// Parse trait Foo { ... }
     fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
+
         let ident = self.parse_ident();
         let mut tps = self.parse_generics();
+        // This is not very accurate, but since unbound only exists to catch
+        // obsolete syntax, the span is unlikely to ever be used.
+        let unbound_span = self.span;
         let unbound = self.parse_for_sized();
 
         // Parse supertrait bounds.
@@ -4684,7 +4704,8 @@ fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
         if let Some(unbound) = unbound {
             let mut bounds_as_vec = bounds.into_vec();
             bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
-                                                                trait_ref: unbound },
+                                                                trait_ref: unbound,
+                                                                span:  unbound_span },
                                                  TraitBoundModifier::Maybe));
             bounds = OwnedSlice::from_vec(bounds_as_vec);
         };
@@ -4803,11 +4824,13 @@ fn parse_late_bound_lifetime_defs(&mut self) -> Vec<ast::LifetimeDef> {
 
     /// Parse for<'l> a::B<String,i32>
     fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
+        let lo = self.span.lo;
         let lifetime_defs = self.parse_late_bound_lifetime_defs();
 
         ast::PolyTraitRef {
             bound_lifetimes: lifetime_defs,
-            trait_ref: self.parse_trait_ref()
+            trait_ref: self.parse_trait_ref(),
+            span: mk_sp(lo, self.last_span.hi),
         }
     }