Skip to content

Commit

Permalink
Rollup merge of rust-lang#48072 - cramertj:impl-trait-lifetime-res, r…
Browse files Browse the repository at this point in the history
…=nikomatsakis

Fix nested impl trait lifetimes

Fixes rust-lang#46464
cc rust-lang#34511

r? @nikomatsakis
  • Loading branch information
Manishearth committed Feb 23, 2018
2 parents abf4d70 + dd481d5 commit 4941cb4
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 11 deletions.
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

0 comments on commit 4941cb4

Please sign in to comment.