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

Tracking issue for `Captures` trait #56046

Open
alexreg opened this Issue Nov 18, 2018 · 3 comments

Comments

Projects
None yet
3 participants
@alexreg
Copy link
Contributor

alexreg commented Nov 18, 2018

This solution was initially suggested by @nikomatsakis in this comment.

Steps:

  • Implement the feature.
  • Adjust documentation.
  • Stabilize feature.

Questions:

  • Is this a permanent solution?
  • Does this need a FCP?
  • Can we get a minimal use case for this feature?

CC @alexcrichton

@alexreg

This comment has been minimized.

Copy link
Contributor Author

alexreg commented Nov 18, 2018

Maybe someone in @rust-lang/libs could kindly add the appropriate tags?

@ExpHP

This comment has been minimized.

Copy link
Contributor

ExpHP commented Nov 20, 2018

Github is making the comments a nuisance to navigate. Is there a cliff-notes version of how this is different from impl Trait + 'a, and the problem it solves?

(I imagine that, since it's a trait bound, it introduces invariance over 'a as opposed to covariance?)

@alexreg

This comment has been minimized.

Copy link
Contributor Author

alexreg commented Nov 20, 2018

@ExpHP I still don't 100% Niko's comment, but I think you're roughly right at least. It's definitely related to invariance somehow. Here is the comment, reproduced.

So #49041 contains a fix for #46541, but that fix has more impact than I anticipated -- e.g., the compiler doesn't bootstrap now -- and it's giving me a measure of pause about the right course here. The problem in #49041 is that we could accidentally allow lifetimes to leak out that we were not supposed to. Here is how this manifests in the compiler. We might have a method like this:

impl TyCtxt<'cx, 'gcx, 'tcx>
where 'gcx: 'tcx, 'tcx: 'cx
{
    fn foos(self) -> impl Iterator<Item = &'tcx Foo> + 'cx {
        /* returns some type `Baz<'cx, 'gcx, 'tcx>` that captures self */
    }
}

The key thing here is that TyCtxt is invariant w/r/t 'tcx and 'gcx, so they must appear in the return type. And yet only 'cx and 'tcx appear in the impl trait bounds, so only those two lifetimes are supposed to be "captured". The old compiler was accepting this because 'gcx: 'cx, but that's not really correct if you think about the desugaring we have in mind. That desugaring would create an abstract type like this:

abstract type Foos<'cx, 'tcx>: Iterator<Item = &'tcx Foo> + 'cx;

and yet the value for this abstract type would be Baz<'cx, 'gcx, 'tcx> -- but 'gcx is not in scope!

The workaround here is that we have to name 'gcx in the bounds. This is kind of annoying to do; we can't use 'cx + 'gcx. We can I suppose make a dummy trait:

trait Captures<'a> { }
impl<T: ?Sized> Captures<'a> for T { }

and then return something like this impl Iterator<Item = &'tcx Foo> + Captures<'gcx> + Captures<'cx>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment