Skip to content

Closure-like blocks capture all generic type and const parameters #65442

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

Open
jonhoo opened this issue Oct 15, 2019 · 10 comments
Open

Closure-like blocks capture all generic type and const parameters #65442

jonhoo opened this issue Oct 15, 2019 · 10 comments
Assignees
Labels
A-async-await Area: Async & Await A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@jonhoo
Copy link
Contributor

jonhoo commented Oct 15, 2019

I'd like to write the following code:

use std::future::Future;
struct Foo<A>(A);
impl<A> Foo<A> {
    fn bar<Q, R: Default>(&mut self, q: Q) -> impl Future<Output = R> {
        let _ = q;
        async move {
            R::default()
        }
    }
    
    fn baz(&mut self, x: &str) -> impl Future<Output = usize> {
        self.bar(x)
    }
}

In particular, I would like to have the impl Trait returned by baz not be tied to the lifetime of its &str argument. Since impl Trait captures the lifetimes of all generic arguments (as per RFC 1951), I can't write the code this way though. So instead, I tried

#![feature(type_alias_impl_trait)]
use std::future::Future;
struct Foo<A>(A);

type BarFut<A, R> = impl Future<Output = R>;
impl<A> Foo<A> {
    fn bar<Q, R: Default>(&mut self, q: Q) -> BarFut<A, R> {
        let _ = q;
        async move {
            R::default()
        }
    }
    
    fn baz(&mut self, x: &str) -> impl Future<Output = usize> {
        self.bar(x)
    }
}

However, with this, I get the error:

error: type parameter `Q` is part of concrete type but not used in parameter list for the `impl Trait` type alias

This seems odd, since Q is (intentionally) not used in the async block. I can work around this by adding an async fn and calling that instead of using async move, but that seems like an odd hack:

async fn make_r_fut<R: Default>() -> R {
    R::default()
}
// ...
    fn bar<Q, R: Default>(&mut self, q: Q) -> BarFut<A, R> {
        let _ = q;
        make_r_fut()
    }
// ...

Is it intentional that the async block "captures" Q here, even though it never contains a Q?

@jonas-schievink jonas-schievink added A-async-await Area: Async & Await A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Oct 15, 2019
@Mark-Simulacrum
Copy link
Member

I suspect the answer is no -- cc @rust-lang/wg-async-await -- this might contribute to "not Send/Sync" errors if we're capturing what we shouldn't be

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Oct 22, 2019

I think my expectation is that the explicit type = impl Trait version should work. I'm not 100% sure why it doesn't, but I can do some investigation.

@nikomatsakis nikomatsakis added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label Oct 22, 2019
@nikomatsakis nikomatsakis self-assigned this Oct 22, 2019
@nikomatsakis
Copy link
Contributor

Assigning to myself to investigate and document the cause of the issue, at least.

@Arnavion
Copy link

Related to / dupe of #42940

@glittershark
Copy link
Contributor

I hate bumping issues but... any movement on this? Just ran into it myself in a very similar context

@nikomatsakis
Copy link
Contributor

No progress I know of

@ranile
Copy link
Contributor

ranile commented Jun 19, 2022

Note that this bug does not require async to trigger. Playground where this triggered using type_alias_impl_trait. I'm not sure if/how this is related #42940 (as mentioned in the comment above). Looking through the discussion there, I couldn't find any mentions of the error returned by the compiler.

@SOF3
Copy link
Contributor

SOF3 commented Sep 10, 2022

Reproduced with a more minimal example: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=319e66180308bede359b022cda8ed0bf

#![feature(type_alias_impl_trait)]

type Ty = impl Fn();

fn run<E>(_: E) -> Ty {
    || ()
}
   Compiling playground v0.0.1 (/playground)
error: type parameter `E` is part of concrete type but not used in parameter list for the `impl Trait` type alias
 --> src/lib.rs:6:5
  |
6 |     || ()
  |     ^^^^^

error: could not compile `playground` due to previous error```

@traviscross
Copy link
Contributor

Here's the minimum async example of this problem:

#![feature(type_alias_impl_trait)]

use std::future::Future;

type Deferred = impl Future<Output = ()> + 'static;

fn future_out<F>(_: F) -> Deferred {
    async move { }
}
error: type parameter `F` is part of concrete type but not used in parameter list for the `impl Trait` type alias
 --> src/lib.rs:8:5
  |
8 |     async move { }
  |     ^^^^^^^^^^^^^^

error: could not compile `playground` (lib) due to previous error

Playground link.

@traviscross

This comment was marked as outdated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants