diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 809660379f326..8a3f76415968e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -81,13 +81,6 @@ struct AstValidator<'a> { is_assoc_ty_bound_banned: bool, lint_buffer: &'a mut LintBuffer, - - /// This is slightly complicated. 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 in where clauses, - /// e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are - /// defined, then error. - trait_ref_hack: bool, } impl<'a> AstValidator<'a> { @@ -1227,17 +1220,33 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // A type binding, eg `for<'c> Foo: Send+Clone+'c` self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); - self.visit_ty(&bound_pred.bounded_ty); - - self.trait_ref_hack = !bound_pred.bound_generic_params.is_empty(); - walk_list!(self, visit_param_bound, &bound_pred.bounds); - walk_list!(self, visit_generic_param, &bound_pred.bound_generic_params); - self.trait_ref_hack = false; - } - _ => { - self.visit_where_predicate(predicate); + // This is slightly complicated. 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 in where clauses, + // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are + // defined, then error. + if !bound_pred.bound_generic_params.is_empty() { + for bound in &bound_pred.bounds { + match bound { + GenericBound::Trait(t, _) => { + if !t.bound_generic_params.is_empty() { + struct_span_err!( + self.err_handler(), + t.span, + E0316, + "nested quantification of lifetimes" + ) + .emit(); + } + } + GenericBound::Outlives(_) => {} + } + } + } } + _ => {} } + self.visit_where_predicate(predicate); } } @@ -1289,19 +1298,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { self.check_late_bound_lifetime_defs(&t.bound_generic_params); - if self.trait_ref_hack && !t.bound_generic_params.is_empty() { - struct_span_err!( - self.err_handler(), - t.span, - E0316, - "nested quantification of lifetimes" - ) - .emit(); - } - let trait_ref_hack = self.trait_ref_hack; - self.trait_ref_hack = false; visit::walk_poly_trait_ref(self, t, m); - self.trait_ref_hack = trait_ref_hack; } fn visit_variant_data(&mut self, s: &'a VariantData) { @@ -1520,7 +1517,6 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, lint_buffer: lints, - trait_ref_hack: false, }; visit::walk_crate(&mut validator, krate); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 3cccbb06bc426..dfb6167c20cac 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1323,14 +1323,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // of "if there isn't a Binder scope above us, add one", but I // imagine there's a better way to go about this. let mut scope = self.scope; - let trait_ref_hack = loop { + let (binders, scope_type) = loop { match scope { Scope::TraitRefBoundary { .. } | Scope::Body { .. } | Scope::Root => { - break false; + break (vec![], BinderScopeType::PolyTraitRef); } - Scope::Binder { .. } => { - break true; + Scope::Binder { hir_id, .. } => { + let binders = self.map.late_bound_vars.entry(*hir_id).or_default().clone(); + break (binders, BinderScopeType::Concatenating); } Scope::Elision { s, .. } @@ -1341,8 +1342,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }; match bound { - hir::GenericBound::LangItemTrait(_, _, hir_id, _) if !trait_ref_hack => { - self.map.late_bound_vars.insert(*hir_id, vec![]); + hir::GenericBound::LangItemTrait(_, _, hir_id, _) => { + self.map.late_bound_vars.insert(*hir_id, binders); let scope = Scope::Binder { hir_id: *hir_id, lifetimes: FxHashMap::default(), @@ -1350,7 +1351,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index: self.next_early_index(), track_lifetime_uses: true, opaque_type_parent: false, - scope_type: BinderScopeType::Other, + scope_type, }; self.with(scope, |_, this| { intravisit::walk_param_bound(this, bound);