I am trying to use #![feature(type_alias_impl_trait)] and I am getting cycle detected when computing type of discovery::ConnFuture::{opaque#0}`
I do not understand why does Rust need to analyze type of where alias is used (Discovery). Isn't all information needed in the type which generated the opaque type (Connect)?
And broader question is, how do I make low-level (poll) based approach working together with high-level (async) based?
Ok, I've figured out that first, type impl must be bound to some concrete type, and it is looking for this binding everywhere, that's why it is looking in the Discovery type. So, I have to somehow tell it that it is bound to return type of async fn connect(&mut self) -> Self, but how?
On mobile so sorry for no code here, but I think it's more than that.
Create a defining use by having a function that takes a &mut Connect and returns a ConnFuture. You'll find you need a lifetime parameter that infects Discovery.
But the error will remain, and it does seem rooted in assigning self.connecting (replace that with a todo!() and it compiles).
That's as far as I got (and I didn't comment before as I didn't think it'd be useful).
This is actually a bad error message, resulting from TAIT needing a sufficiently well-formed program to be able to resolve the type. The real problem is that you cannot access self.connecting given only Pin<&mut Self>. However, in order to figure that out, I had to rewrite the program so that it could avoid the bad error message. To do that, I introduced a function conn_future() dedicated to the purpose of defining what ConnFuture is — and it also seemed important to put that in the module connection, not discovery.
mod connection {
use std::future::Future;
pub struct Connect {}
impl Connect {
pub async fn connect(self) -> Self { todo!() } // <--- also needs to not be `&mut `self`
}
pub(crate) type ConnFuture = impl Future<Output = Connect>;
pub(crate) fn conn_future() -> ConnFuture {
Connect{}.connect()
}
}
With this change I get:
error[E0594]: cannot assign to data in dereference of `Pin<&mut Discovery>`
--> src/main.rs:36:17
|
36 | self.connecting = Some(conn_future())
| ^^^^^^^^^^^^^^^ cannot assign
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut Discovery>`
Now we see the problem: mutating through Pin requires special considerations. I'm not sure what the best option for this particular case of setting an Option is — the usual go-to- pin_project doesn't solve it, and Pin::get_unchecked_mut can but is unsafe. The program compiles this way:
Hmm, ok. I've got to the same "pin" problem by modifying Connection, but it looks slightly hackish.
I'll work on Pin and will see what happen to type impl