Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix nested impl trait lifetimes #48072

Merged
merged 1 commit into from
Feb 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 71 additions & 11 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item = impl Trait2<'a>>
///
/// 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>,
},

Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -1303,32 +1344,49 @@ 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);
this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
});
}

/// 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
Expand All @@ -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));
Expand Down Expand Up @@ -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();
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-pass/impl-trait/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item = impl Iterator<Item = i32> + '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 }

Expand Down