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

🚀 existential impl Trait allows lifetimes that would not be allowed by abstract type #46541

Closed
nikomatsakis opened this issue Dec 6, 2017 · 5 comments · Fixed by #49041
Closed
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-traits Working group: Traits, https://internals.rust-lang.org/t/announcing-traits-working-group/6804

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Dec 6, 2017

Consider this curious case:

#![allow(dead_code)]
#![feature(conservative_impl_trait)]
#![feature(in_band_lifetimes)]

use std::cell::Cell;

trait Trait<'a> { }

impl Trait<'b> for Cell<&'a u32> { }

fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
where 'x: 'y
{
    x
}

fn main() { }

Here, the value we are returning is of type Cell<&'x u32>, but the return type ought only to be able to mention 'y. In other words, we are inferring something like

abstract type Foo<'z>: Trait<'z> = Cell<&'x u32>

which is clearly malformed. We allow this because the current code has regionck bound all lifetimes with 'y and considers that sufficient to ensure that nothing is "leaking" that shouldn't -- but, as can be seen here, that's not always true.

I don't think we should accept this -- at least for now. However, I also could not find an obvious way to weaponize it. There may not be one. Consider that this variant, using Box<dyn Trait<'y> + 'y> in place of impl Trait<'y>, type-checks and ought to be sound (afaik). (In part, though, this relies on the fact that we expand impl Trait<'y> to impl Trait<'y> + 'y internally, but it seems like impl Trait<'y> must outlive 'y just by construction, since it could not name any other lifetime.)

One could imagine permitting the example via some sort of subtyping relation on abstract types -- that is, perhaps we might determine a variance for Foo with respect to its type parameters based on the traits that it implements. Not sure if that would be sound, but you could imagine it. Until we have such a justification, though, I think we should not accept the example.

I'll probably fix this en passane while doing some refactoring to support impl Trait in the NLL code.

cc #34511

@nikomatsakis nikomatsakis added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-compiler-nll WG-traits Working group: Traits, https://internals.rust-lang.org/t/announcing-traits-working-group/6804 labels Dec 6, 2017
@nikomatsakis
Copy link
Contributor Author

nikomatsakis commented Jan 18, 2018

removing from WG-compiler-nll since I don't think it's that related

@aturon
Copy link
Member

aturon commented Feb 22, 2018

Ping on this -- is this blocking impl Trait stabilization?

@nikomatsakis
Copy link
Contributor Author

@aturon yep, I think it's a blocker.

@aturon
Copy link
Member

aturon commented Feb 22, 2018

We're shooting for stabilization within this cycle, are we on track?

@nikomatsakis
Copy link
Contributor Author

nikomatsakis commented Feb 22, 2018

I don't know. We should figure that out. I'll try to prep a "stabilization check-in" before lang mtg. (I was already hoping to do this)

@nikomatsakis nikomatsakis changed the title existential impl Trait allows lifetimes that would not be allowed by abstract type 🚀 existential impl Trait allows lifetimes that would not be allowed by abstract type Feb 25, 2018
@XAMPPRocky XAMPPRocky added the C-bug Category: This is a bug. label Feb 26, 2018
bors added a commit that referenced this issue Mar 22, 2018
…etimes, r=cramertj

Detect illegal hidden lifetimes in `impl Trait`

This branch fixes #46541 -- however, it presently doesn't build because it also *breaks* a number of existing usages of impl Trait. I'm opening it as a WIP for now, just because we want to move on impl Trait, but I'll try to fix the problem in a bit.

~~(The problem is due to the fact that we apparently infer stricter lifetimes in closures that we need to; for example, if you capture a variable of type `&'a &'b u32`, we will put *precisely* those lifetimes into the closure, even if the closure would be happy with `&'a &'a u32`. This causes the present chance to affect things that are not invariant.)~~ fixed

r? @cramertj
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-traits Working group: Traits, https://internals.rust-lang.org/t/announcing-traits-working-group/6804
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants