Skip to content

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

Closed

Description

@nikomatsakis

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

Activity

  1. added
    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Dec 6, 2017
  2. nikomatsakis commented on Jan 18, 2018

    @nikomatsakis
    ContributorAuthor

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

  3. aturon commented on Feb 22, 2018

    @aturon
    Contributor

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

  4. nikomatsakis commented on Feb 22, 2018

    @nikomatsakis
    ContributorAuthor

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

  5. aturon commented on Feb 22, 2018

    @aturon
    Contributor

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

  6. nikomatsakis commented on Feb 22, 2018

    @nikomatsakis
    ContributorAuthor

    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)

  7. 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[/+] on Feb 25, 2018
  8. added a commit that references this issue on Mar 22, 2018
    e575773
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions