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: Use function return type for binding? #60367

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

Comments

Projects
None yet
3 participants
@phil-opp
Copy link
Contributor

commented Apr 29, 2019

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

This comment has been minimized.

Copy link
Member

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.

@cramertj

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Contributor Author

commented Apr 30, 2019

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

This comment has been minimized.

Copy link
Contributor Author

commented Apr 30, 2019

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.

@phil-opp phil-opp closed this Apr 30, 2019

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.