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

non-defining existential type use in defining scope with empty lifetime name #53457

Open
Nemo157 opened this Issue Aug 17, 2018 · 5 comments

Comments

Projects
None yet
5 participants
@Nemo157
Copy link
Contributor

Nemo157 commented Aug 17, 2018

Really not sure where the error here is coming from, as far as I can tell there should only be a single relevant lifetime, 'a. The same function written as a free function generic over a Write returning impl Future<...> + 'a works fine (included in the playground). I'll try and come up with a reduced example in the next couple of days (playground)

error: non-defining existential type use in defining scope
  --> src/lib.rs:19:5
   |
19 | /     {
20 | |         poll_fn(move |cx| self.reborrow().poll_close(cx))
21 | |     }
   | |_____^ lifetime `` is part of concrete type but not used in parameter list of existential type
#![feature(arbitrary_self_types, existential_type, pin, futures_api)]

use std::future::Future;
use std::marker::Unpin;
use std::mem::PinMut;
use std::task::{self, Poll};

pub trait Write {
    type Error;

    fn poll_close(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Result<(), Self::Error>>;
}

existential type Close<'a, W: Write>: Future<Output = Result<(), W::Error>> + 'a;

trait WriteExt: Write {
    fn close<'a>(self: PinMut<'a, Self>) -> Close<'a, Self>
    where
        Self: Sized,
    {
        poll_fn(move |cx| self.reborrow().poll_close(cx))
    }
}

// ------------
// from futures-util-preview 0.3

pub struct PollFn<F> {
    f: F,
}

impl<F> Unpin for PollFn<F> {}

pub fn poll_fn<T, F>(f: F) -> PollFn<F>
where
    F: FnMut(&mut task::Context) -> Poll<T>,
{
    PollFn { f }
}

impl<T, F> Future for PollFn<F>
where
    F: FnMut(&mut task::Context) -> Poll<T>,
{
    type Output = T;

    fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<T> {
        (&mut self.f)(cx)
    }
}

(CC @oli-obk in case you have any hints on where to look)

@Nemo157

This comment has been minimized.

Copy link
Contributor Author

Nemo157 commented Aug 20, 2018

Minimized example (playground)

#![feature(existential_type)]

trait Future {
    fn poll(&self, cx: &mut ());
}

trait Write {
    fn poll_close(&self, cx: &mut ());
}

existential type Close<'a, W: Write>: Future + 'a;

fn broken<'a, W: Write>(w: &'a W) -> Close<'a, W> {
    PollFn(move |cx| w.poll_close(cx))
}

fn working<'a, W: Write>(w: &'a W) -> impl Future + 'a {
    PollFn(move |cx| w.poll_close(cx))
}

pub struct PollFn<F: Fn(&mut ())>(F);

impl<F> Future for PollFn<F> where F: Fn(&mut ()) {
    fn poll(&self, cx: &mut ()) {
        (&self.0)(cx)
    }
}
error: non-defining existential type use in defining scope
  --> src/lib.rs:13:51
   |
13 |   fn broken<'a, W: Write>(w: &'a W) -> Close<'a, W> {
   |  ___________________________________________________^
14 | |     PollFn(move |cx| w.poll_close(cx))
15 | | }
   | |_^ lifetime `` is part of concrete type but not used in parameter list of existential type

Removing the cx parameter everywhere makes this work, at a guess it seems like existential types are incorrectly attributing the lifetime of the &mut () that should be hidden in the closure to the concrete type.

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Aug 21, 2018

This might be because existential types skip (

) the lifetime hacks (
for lifetime in &path.segments[0].args.as_ref().unwrap().args {
) that impl Trait does

@talchas

This comment has been minimized.

Copy link

talchas commented Oct 10, 2018

Even more minified:

existential type X: Clone;

fn bar<F: Fn(&i32) + Clone>(f: F) -> F {
    f
}

fn foo() -> X {
    bar(|x| ())
}

or using more stdlib stuff:

existential type X: Iterator<Item = i32>;

fn temp() -> X {
    vec![1].into_iter().filter(|x| *x > 1)
}
@ExpHP

This comment has been minimized.

Copy link
Contributor

ExpHP commented Oct 22, 2018

Also seen in const/static items of type impl Fn(&T): #55272

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jan 17, 2019

I've hit this as well, have reduced it further:

#![feature(existential_type)]

existential type Foo<R>: Fn(&R) -> ();

fn bar<R>() -> Foo<R> {
    |r| ()
}

Playground

Changing from Fn(&R) -> () to Fn(R) -> () works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment