rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.24k stars 12.71k forks source link

Option + impl Trait = uncompilable code (?) #37454

Open japaric opened 8 years ago

japaric commented 8 years ago

STR

#![feature(conservative_impl_trait)]

trait Foo {
    fn foo(&self);
}

struct FooStruct {}

impl Foo for FooStruct {
    fn foo(&self) {
        println!("foo");
    }
}

fn mk_foo() -> impl Foo {
    FooStruct {}
}

fn main() {
    let mut maybe_foo = None;

    loop {
        if some_condition() {
            maybe_foo.take().map(|f| f.foo());

            maybe_foo = Some(mk_foo());
        }

        // .. more code ..
    }
}

fn some_condition() -> bool {
    true
}
rustc foo.rs
error: the type of this value must be known in this context
  --> foo.rs:24:38
   |
24 |             maybe_foo.take().map(|f| f.foo());
   |                                      ^^^^^^^

error: aborting due to previous error

This works:

     loop {
         if true {
-            maybe_foo.take().map(|f| f.foo());
-
             maybe_foo = Some(mk_foo());
+
+            maybe_foo.take().map(|f| f.foo());
         }

but changes the behaviour of the code.

My first attempt to fix this was:

 fn main() {
-    let mut maybe_foo = None;
+    let mut maybe_foo: Option<impl Foo> = None;

     loop {

but:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types

My second attempt was:


+fn init_maybe_foo() -> Option<impl Foo> {
+    None::<FooStruct>
+}
+
 fn main() {
-    let mut maybe_foo = None;
+    let mut maybe_foo = init_maybe_foo();

     loop {

but:

$ rustc foo.rs
error[E0308]: mismatched types
  --> foo.rs:30:30
   |
30 |             maybe_foo = Some(mk_foo());
   |                              ^^^^^^^^ expected anonymized type, found a different anonymized type
   |
   = note: expected type `impl Foo` (anonymized type)
   = note:    found type `impl Foo` (anonymized type)

error: aborting due to previous error

What? They have the same type.

Are impl Trait types in let statements planned? Or can type inference be ... improved (?) to handle the last case? Or does anyone know how to work around this? :smile:

cc @eddyb

eddyb commented 8 years ago
fn hint_none<R, F: FnOnce() -> R>(_: F) -> Option<T> {None}
...
let mut maybe_foo = hint_none(mk_foo);
mister-walter commented 6 years ago

Is this blocked on the implemention of rust-lang/rfcs#2071 ?

cramertj commented 6 years ago

This isn't a full solution, but the code in the original issue report can be fixed using UFCS: Foo::foo(&f) works.