Skip to content

impl_trait_in_bindings: Use function return type for binding? #60367

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

Closed
phil-opp opened this issue Apr 29, 2019 · 4 comments
Closed

impl_trait_in_bindings: Use function return type for binding? #60367

phil-opp opened this issue Apr 29, 2019 · 4 comments
Labels
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.

Comments

@phil-opp
Copy link
Contributor

I tried to lazily initialize a static with an impl trait value returned by a function (playground):

#![feature(impl_trait_in_bindings)]

static mut TEST: Option<impl core::fmt::Debug> = None;

fn main() {
    unsafe { TEST = Some(foo()) }
}

fn foo() -> impl core::fmt::Debug {
    0u32
}

This errors with:

error[E0282]: type annotations needed
 --> src/main.rs:3:25
  |
3 | static mut TEST: Option<impl core::fmt::Debug> = None;
  |                         ^^^^^^^^^^^^^^^^^^^^^ cannot infer type

error[E0308]: mismatched types
 --> src/main.rs:6:26
  |
6 |     unsafe { TEST = Some(foo()) }
  |                          ^^^^^ expected opaque type, found a different opaque type
  |
  = note: expected type `impl std::fmt::Debug` (opaque type)
             found type `impl std::fmt::Debug` (opaque type)

So it can't infer a type that is assigned later. Is this a fundamental limitation or just an incompleteness of the current implementation?

Also, is there a way to name the return type of an function so that I can do e.g. static mut TEST: Option<foo::RETURN_TYPE>?

@Centril
Copy link
Contributor

Centril commented Apr 29, 2019

Customary warning about static mut ==> #53639.

Reduced:

#![feature(impl_trait_in_bindings)]

static mut TEST: Option<impl core::fmt::Debug> = None;

fn main() {
    unsafe {
        TEST = Some(0)
    }
}

So it can't infer a type that is assigned later. Is this a fundamental limitation or just an incompleteness of the current implementation?

I would expect that this is by design but it would be good to write down a fuller explanation in a less ephemeral location for posterity and for the eventual stabilization report.

cc @cramertj @alexreg @oli-obk

Also, is there a way to name the return type of an function so that I can do e.g. static mut TEST: Option<foo::RETURN_TYPE>?

Not to my knowledge. You cannot access foo in the type namespace to use foo::Output and moreover you cannot bound on FnOnce.

@Centril Centril added 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 Apr 29, 2019
@cramertj
Copy link
Member

cramertj commented Apr 29, 2019

Yes, this is intentional-- items such as statics and consts cannot use other bodies to determine the types to which they evaluate. This example would be similar to writing the following:

fn foo() -> impl Debug { None }

fn bar() {
    let mut x = foo();
    x = Some(0);
}

which we obviously can't make work

@phil-opp
Copy link
Contributor Author

Thanks a lot for clarifying!

Just to make sure I understood it right: It can't work because it would require global type inference for statics, function types, etc, but we only do local type inference by design so that e.g. the type of a function does not depend on how it's used. Is that roughly correct?

So it seems that lazily initializing a static with an impl trait type will never be possible. This is a bit unfortunate, since it is an additional thing to consider when designing a library API. But I guess there's no way to fix it without changing the fundamental design decision that statics must independently specify their full types (this rules out both partial global type inference for impl trait and using the foo::Output type).

@phil-opp
Copy link
Contributor Author

I did some more digging and found out that I want to use the existential types feature for this (playground):

#![feature(existential_type)]

existential type Debuggable: core::fmt::Debug;

static mut TEST: Option<Debuggable> = None;

fn main() {
    unsafe { TEST = Some(foo()) }
}

fn foo() -> Debuggable {
    0u32
}

The example currently ICEs, but I think it is the way to solve the problem.

So given that impl trait works as intended, I'm going to close this issue. Thanks again for the explanation!

Customary warning about static mut ==> #53639.

I'm aware of that, thanks! I just used it to get a small example.

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. 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

3 participants