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

`impl_trait_in_bindings` and pick-constraint region bounds #61773

Open
nikomatsakis opened this issue Jun 12, 2019 · 2 comments

Comments

Projects
None yet
2 participants
@nikomatsakis
Copy link
Contributor

commented Jun 12, 2019

I'm working on #56238. In the process, I'm extending how impl Trait lifetime inference works -- in particular in scenarios involving multiple, unrelated lifetimes, such as impl Trait<'a, 'b>. The challenge here is that each region 'h in the hidden type must be equal to 'a or 'b, but we can't readily express that relationship in terms of our usual "outlives relationships". The solver is thus extended with a "pick constraint", written pick 'h from ['a, 'b], which expresses that 'h must be equal to 'a or 'b. The current integration into the solver, however, requires that the regions involved are lifetime parameters. This is always true for impl Trait used at function boundaries, but it is not true for let bindings.

The challenge is that if you have a program like:

trait Foo<'_> { }
impl Foo<'_> for &u32 { }

fn bar() {
  let x: impl Foo<'_> = &44; // let's call the region variable for `'_` `'1`
}

then we would wind up with pick '0 from ['1, 'static], where '0 is the region variable in the hidden type (&'0 u32) and '1 is the region variable in the bounds Foo<'1>. This is tricky because both '0 and '1 are being inferred -- so making them equal may have other repercussions.

For the time being, I've chosen to include some assertions that this scenario never comes up. I'm tagging a FIXME in the code with this issue number. I was going to create some tests, but owing to the ICE #60473 (not unrelated to this issue, actually), that proved difficult, so I'll just post comments in here instead.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

commented Jun 12, 2019

Example test. An easy case is when they use named regions from in scope:

trait Foo<'_> { }
impl Foo<'_> for &u32 { }

fn bar<'a>(data: &'a u32) {
  let x: impl Foo<'a> = data;
}
@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

commented Jun 12, 2019

Example test. A harder case is when we have inferred lifetime variables.

trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }


fn bar<'a>(data0: &'a u32, data1: &'b u32) {
  let x: impl Trait<'_, '_> = (data0, data1);
  force_equal(x);
}

fn force_equal<'a>(t: impl Trait<'a, 'a>) { }

I expect this to compile because:

  • the force_equal method forces the two '_ to be equal, so we effectively have impl Trait<'x, 'x>
  • the hidden type is a tuple (&'0 u32, &'1 u32) where 'a: '0 and 'b: '1
  • thus '0 and '1 must either equal 'x or 'static
  • but 'x can be some portion of the fn body -- basically the scope of x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.