From dd481d5f462d8c7bd5e81438ccc1ef3013343408 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 17 Jan 2018 17:22:40 -0800 Subject: [PATCH] fix nested impl trait lifetimes --- src/librustc/middle/resolve_lifetime.rs | 82 ++++++++++++++++++++--- src/test/run-pass/impl-trait/lifetimes.rs | 8 +++ 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 59460141166b1..5201df2119dac 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -270,6 +270,19 @@ enum Scope<'a> { /// we should use for an early-bound region? next_early_index: u32, + /// Whether or not this binder would serve as the parent + /// binder for abstract types introduced within. For example: + /// + /// fn foo<'a>() -> impl for<'b> Trait> + /// + /// Here, the abstract types we create for the `impl Trait` + /// and `impl Trait2` references will both have the `foo` item + /// as their parent. When we get to `impl Trait2`, we find + /// that it is nested within the `for<>` binder -- this flag + /// allows us to skip that when looking for the parent binder + /// of the resulting abstract type. + abstract_type_parent: bool, + s: ScopeRef<'a>, }, @@ -498,6 +511,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { lifetimes, next_early_index, + abstract_type_parent: true, s: ROOT_SCOPE, }; self.with(scope, |old_scope, this| { @@ -541,6 +555,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .collect(), s: self.scope, next_early_index, + abstract_type_parent: false, }; self.with(scope, |old_scope, this| { // a bare fn has no bounds, so everything @@ -614,7 +629,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ref generics, ref bounds, } = *exist_ty; - let mut index = self.next_early_index(); + + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut index = self.next_early_index_for_abstract_type(); debug!("visit_ty: index = {}", index); let mut elision = None; @@ -638,7 +656,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope }; self.with(scope, |_old_scope, this| { - let scope = Scope::Binder { lifetimes, next_early_index, s: this.scope }; + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: this.scope, + abstract_type_parent: false, + }; this.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { @@ -647,7 +670,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }); }); } else { - let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope }; + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + abstract_type_parent: false, + }; self.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { @@ -681,7 +709,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .collect(); let next_early_index = index + generics.ty_params().count() as u32; - let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope }; + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + abstract_type_parent: true, + }; self.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { @@ -721,7 +754,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .collect(); let next_early_index = index + generics.ty_params().count() as u32; - let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope }; + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + abstract_type_parent: true, + }; self.with(scope, |_old_scope, this| { this.visit_generics(generics); this.visit_ty(ty); @@ -792,6 +830,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .collect(), s: self.scope, next_early_index, + abstract_type_parent: false, }; let result = self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &bound_generic_params); @@ -853,6 +892,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .collect(), s: self.scope, next_early_index, + abstract_type_parent: false, }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); @@ -1046,6 +1086,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { ref lifetimes, s, next_early_index: _, + abstract_type_parent: _, } => { // FIXME (#24278): non-hygienic comparison if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) { @@ -1303,6 +1344,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetimes, next_early_index, s: self.scope, + abstract_type_parent: true, }; self.with(scope, move |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); @@ -1310,25 +1352,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }); } - /// Returns the next index one would use for an early-bound-region - /// if extending the current scope. - fn next_early_index(&self) -> u32 { + fn next_early_index_helper(&self, only_abstract_type_parent: bool) -> u32 { let mut scope = self.scope; loop { match *scope { Scope::Root => return 0, Scope::Binder { - next_early_index, .. - } => return next_early_index, + next_early_index, + abstract_type_parent, + .. + } if (!only_abstract_type_parent || abstract_type_parent) + => return next_early_index, - Scope::Body { s, .. } + Scope::Binder { s, .. } + | Scope::Body { s, .. } | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => scope = s, } } } + /// Returns the next index one would use for an early-bound-region + /// if extending the current scope. + fn next_early_index(&self) -> u32 { + self.next_early_index_helper(true) + } + + /// Returns the next index one would use for an `impl Trait` that + /// is being converted into an `abstract type`. This will be the + /// next early index from the enclosing item, for the most + /// part. See the `abstract_type_parent` field for more info. + fn next_early_index_for_abstract_type(&self) -> u32 { + self.next_early_index_helper(false) + } + fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); // Walk up the scope chain, tracking the number of fn scopes @@ -1353,6 +1411,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ref lifetimes, s, next_early_index: _, + abstract_type_parent: _, } => { if let Some(&def) = lifetimes.get(&lifetime_ref.name) { break Some(def.shifted(late_depth)); @@ -2102,6 +2161,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ref lifetimes, s, next_early_index: _, + abstract_type_parent: _, } => { if let Some(&def) = lifetimes.get(&lifetime.name) { let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap(); diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 1f2d76f289472..213a46ded8e76 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -50,6 +50,14 @@ fn closure_hr_elided_return() -> impl Fn(&u32) -> &u32 { |x| x } fn closure_pass_through_elided_return(x: impl Fn(&u32) -> &u32) -> impl Fn(&u32) -> &u32 { x } fn closure_pass_through_reference_elided(x: &impl Fn(&u32) -> &u32) -> &impl Fn(&u32) -> &u32 { x } +fn nested_lifetime<'a>(input: &'a str) + -> impl Iterator + 'a> + 'a +{ + input.lines().map(|line| { + line.split_whitespace().map(|cell| cell.parse().unwrap()) + }) +} + fn pass_through_elision(x: &u32) -> impl Into<&u32> { x } fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) -> &u32> { x }