Skip to content

Impossible to return unboxed closure from some functions. #66426

Closed
@wdanilo

Description

@wdanilo

Hi! I'm trying to write a lens library for Rust (see this for reference about lenses: https://github.com/ekmett/lens/wiki). I'm trying to write it in an zero-overhead style, so all lens-usages could be optimized away during compilation stage, thus, I'm trying to create unboxed closures and glue them together. However, a very strange error occurs here. Consider the following code:

#![feature(type_alias_impl_trait)]
#![feature(trait_alias)]

use std::marker::PhantomData;

trait OptGetter<'t,A,B> = Fn(&'t A) -> Option<&'t B>
    where A:'t, B:'t, Self:Copy;

struct Lens<'t,Get,A,B>
    where Get: OptGetter<'t,A,B> {
    get: Get,
    phantom: PhantomData<(&'t(),A,B)>
}

type CombinedOptGetter<'t,Get1,Get2,A,B,C> = impl OptGetter<'t,A,C>;
fn combine_opt_getter <'t,Get1,Get2,A,B,C>
(f1: Get1, f2: Get2) -> CombinedOptGetter<'t,Get1,Get2,A,B,C>
    where Get1:OptGetter<'t,A,B>,
          Get2:OptGetter<'t,B,C> {
    move |a| f1(a).and_then(f2)
}

impl<'t,Get,A,B> Lens<'t,Get,A,B>
    where Get: OptGetter<'t,A,B> {
    pub fn new(get: Get) -> Self {
        let phantom = PhantomData;
        Self { get, phantom }
    }

    pub fn combine<Get2, C>(self, that: Lens<'t,Get2,B,C>)
    -> Lens<'t,CombinedOptGetter<'t,Get,Get2,A,B,C>,A,C>
        where Get2: OptGetter<'t,B,C> {
        Lens::new(combine_opt_getter(self.get, that.get))
    }
}

trait OptionLens {
    type Out;
    fn _Some(self) -> Self::Out;
}

type SomeGetter<'t,A> = impl OptGetter<'t,Option<A>,A>;
fn some_getter<'t,A:'t>() -> Lens<'t,SomeGetter<'t,A>,Option<A>,A> {
    Lens::new(move|t: &'t Option<A>| t.as_ref())
}

fn _Some<'t, Get, A, B> (this: Lens<'t,Get,A,Option<B>>) -> i32
where Get: OptGetter<'t,A,Option<B>> {
    let wrapped: Lens<'t,SomeGetter<'t,B>,Option<B>,B> = some_getter();
    let wrapper: Lens<'t,CombinedOptGetter<'t,Get,SomeGetter<'t,B>,A,Option<B>,B>,A,B> = this.combine(wrapped);
    7
}

It compiles fine. However, if you try to return wrapper from the _Some function, the code will not compile and the errrors we get are not very explanatory either. With this code instead:

fn _Some<'t, Get, A, B> (this: Lens<'t,Get,A,Option<B>>) -> Lens<'t,CombinedOptGetter<'t,Get,SomeGetter<'t,B>,A,Option<B>,B>,A,B>
where Get: OptGetter<'t,A,Option<B>> {
    let wrapped: Lens<'t,SomeGetter<'t,B>,Option<B>,B> = some_getter();
    let wrapper: Lens<'t,CombinedOptGetter<'t,Get,SomeGetter<'t,B>,A,Option<B>,B>,A,B> = this.combine(wrapped);
    wrapper
}

We get:

error[E0283]: type annotations needed: cannot resolve `_: OptGetter<'t, std::option::Option<B>, B>`
  --> lib/optics/src/lib.rs:42:1
   |
42 | type SomeGetter<'t,A> = impl OptGetter<'t,Option<A>,A>;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: the return type of a function must have a statically known size

error: concrete type differs from previous defining opaque type use
  --> lib/optics/src/lib.rs:47:1
   |
47 | / fn _Some<'t, Get, A, B> (this: Lens<'t,Get,A,Option<B>>) -> Lens<'t,CombinedOptGetter<'t,Get,SomeGetter<'t,B>,A,Option<B>,B>,A,B>
48 | | where Get: OptGetter<'t,A,Option<B>> {
49 | |     let wrapped: Lens<'t,SomeGetter<'t,B>,Option<B>,B> = some_getter();
50 | |     let wrapper: Lens<'t,CombinedOptGetter<'t,Get,SomeGetter<'t,B>,A,Option<B>,B>,A,B> = this.combine(wrapped);
51 | |     wrapper
52 | | }
   | |_^ expected `[closure@lib/optics/src/lib.rs:44:15: 44:48]`, got `[type error]`
   |
note: previous use here
  --> lib/optics/src/lib.rs:43:1
   |
43 | / fn some_getter<'t,A:'t>() -> Lens<'t,SomeGetter<'t,A>,Option<A>,A> {
44 | |     Lens::new(move|t: &'t Option<A>| t.as_ref())
45 | | }
   | |_^

Metadata

Metadata

Assignees

No one assigned

    Labels

    F-trait_alias`#![feature(trait_alias)]`F-type_alias_impl_trait`#[feature(type_alias_impl_trait)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    Status

    Wontfix

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions