---
title: WG-async triage meeting 2024-01-08
tags: ["WG-async", "triage-meeting", "minutes"]
date: 2024-01-08
url: https://hackmd.io/LxYe4fqeQE2jhLDw8GAVUw
---
# WG-async meeting agenda
- Meeting date: 2024-01-08
## Attendance
- People: TC, Yosh, CE
## Meeting roles
- Minutes: TC
## Scheduled meetings
- 2024-01-11: "Open discussion: 2024-01-11" [#328](https://github.com/rust-lang/wg-async/issues/328)
- 2024-01-18: "Roadmap planning: 2024-01-18" [#329](https://github.com/rust-lang/wg-async/issues/329)
- 2024-01-25: "Discuss `async Drop`" [#330](https://github.com/rust-lang/wg-async/issues/330)
Update these [here](https://github.com/orgs/rust-lang/projects/40/views/1).
## Proposed meetings
None.
Update these [here](https://github.com/orgs/rust-lang/projects/40/views/1).
## Announcements or custom items
(Meeting attendees, feel free to add items here!)
## Nominated RFCs, PRs, and issues
### "Tracking Issue for `task::Waker::noop`" rust#98286
**Link:** https://github.com/rust-lang/rust/issues/98286
We talked about this back in December but left it nominated:
> We discussed this in the WG-async triage call today. While everyone did see use cases for this, some also had concerns about this potentially being misused. E.g. someone might use this when the person should instead call `.await`. No-one seemed to think that was a blocker by itself ("Rust has lots of hard things"). Some were also unsure whether this was worth it and whether the cost of duplicating this code might actually induce a useful friction.
>
> We were curious to hear more about the use cases. If people here could help to fill in the details of the various use cases for this, that would help with discussion, and it may help enable a WG-async consensus to form.
It looks like people have since filled in some use cases.
### "Add `AsyncFn` family of traits" rust#119305
**Link:** https://github.com/rust-lang/rust/pull/119305
CE: I think we can introduce `LendingFn` and `LendingFnMut`. Then an async closure will implement `FnOnce` and one of `LendingFn`, or `LendingFnMut`.
`FnOnce::Output` is a distinct future type from `LendingFnMut::BorrowOutput<'_>`.
### "Tracking Issue for `Ready::into_inner()`" rust#101196
**Link:** https://github.com/rust-lang/rust/issues/101196
We're waiting to see use cases here.
### "Rename `AsyncIterator` back to `Stream`, introduce an AFIT-based `AsyncIterator` trait" rust#119550
**Link:** https://github.com/rust-lang/rust/pull/119550
We'll talk about this at the open meeting on Thursday.
### "Add LocalWaker support" libs-team#191
**Link:** https://github.com/rust-lang/libs-team/issues/191
We left feedback here in December and should look into what's been said since then.
## Discussion on RTN
Could RTN be used everywhere in type position if we automatically did what a user would do to work around the lack of RTN with GATs, by converting all generics in the method signature to generics on the GAT?
E.g., from...
```rust
impl T {
fn foo(x: &()) {}
}
```
...to...
```rust
impl T {
type Foo<'a> = ();
fn foo(x: &()) -> Self::Foo<'_> {}
}
```
While that could in principle work, the problem is syntax. The method does not in fact have any generics that can be turbofished, so it would be strange to write:
```rust
T::foo<'a>
```
Instead, we conceive of writing:
```rust
T::foo(&'a ())
```
However, the method signature can have arbitrary projections and other generics, early and late-bound lifetimes, etc....
```rust
trait Id {
type Type;
}
impl<T> Id for T {
type Type = T;
}
struct T;
impl T {
fn foo<'b, 'c: 'c, T>(x: <&() as Id>::Type) {}
}
```
...so deciding whether some "call" to RTN, e.g....
```rust
T::foo(&'static ())
```
...is fully constrained requires full type checking.
This is probably possible to do in principle, but where in the compile and when to do this during compilation is an open question and may be tricky.
Further, the ergonomics of having to fully specify all generic parameters may not be great.
As conceived, RTN makes lifetimes higher-ranked automatically:
```rust
T::foo()
// Becomes:
// for<'a> T::foo(&'a ())
```
If RTN could be used everywhere in type position, here's how it could act similar to TAIT:
```rust
fn foo(x: &i32) -> impl Sized { x }
struct Foo<'a> {
x: foo(&'a ()),
}
```
## const Trait
We don't support this:
```rust
trait Foo {
const fn foo();
}
```
We do want to support this:
```rust
#[const_trait] trait Foo<const> {
fn foo();
}
const fn bar<T: ~const PartialEq>(t1: T, t2: T) {
t1 == t2
}
```
Given refinement, it's conceivable someone could want to write:
```rust
where T: Foo<bar(): ~const> // Given refinement.
```
E.g., with:
```rust
trait Foo {
fn bar() {}
}
impl Foo for () {
const fn bar() {}
}
```
However, Rust uses trait definitions as a source of truth, and so to the degree that `const` here acts as an early-bound parameter on the method, it's difficult to conceive of how `rustc` could support this.
This is a good example of where, from a syntax perspective, it's clear what this should mean and why users might want it, but where implementation considerations are paramount.
## ATPIT
We said that we're looking through projections on the `Self` type only (which amounts to something like a syntactic check). What about where a projection on a non-`Self` type leads back to an `impl Trait` opaque type in an AT on the `Self` type? E.g.:
```rust
struct Struct<T: Foo + ?Sized> {
field: <T as Foo>::Bar,
}
trait Foo {
type Bar;
fn r#struct() -> Struct<Self>;
}
impl Foo for () {
type Bar = impl Sized;
fn r#struct() -> Struct<Self> {
Struct { field: () }
}
}
```
Following what we discussed in the ITE meeting, we probably want to disallow this for the stabilization. We might want to save the space for a more semantic check. The concern is, of course, that restrictions that we add now to save space may never be lifted. I.e., that a decision deferred today will be deferred forever. But this may be a place where we really do want to see how people will use it and what frictions they may run up against.
One of the arguments against this working is that it introduces a kind of non-locality. One has to look at the definiton of the struct, which may be non-local, to determine whether the signature rule has been met.
Of course, we do allow other non-local reasons similar to this. E.g., implied bounds have a similar non-locality:
```rust
struct Foo<'a, T> { // T: 'a
f: &'a T,
}
fn foo<'a, T>(x: Foo<'a, T>) {
// Implied T: 'a
}
```
The function `foo` can rely on the fact that `T: 'a` even though it did not specify that in its own bounds, but you would have to look at the definition of the struct `Foo` (which could be non-local) to deteremine that.
Separately, and interestingly, this does not work currently:
```rust
trait Foo {
type Bar;
fn foo() -> Self::Bar;
}
impl Foo for () {
type Bar = impl Sized;
fn foo() -> i32 {
0
}
}
```
But this is probably just something that we can fix.
(The meeting ended here.)
## Untriaged issues
### "ICE with "failed to resolve instance for <... as IntoFuture>::into_future: Ok(None)" (regression between 1.73 and 1.74)" rust#119095
**Link:** https://github.com/rust-lang/rust/issues/119095
### "Add `AsyncFn` family of traits" rust#119305
**Link:** https://github.com/rust-lang/rust/pull/119305
### "Add LocalWaker support" libs-team#191
**Link:** https://github.com/rust-lang/libs-team/issues/191
## WG RFCs, PRs, and issues nominated for T-lang/T-types
### "`.await` does not perform autoref or autoderef" rust#111546
**Link:** https://github.com/rust-lang/rust/issues/111546
## Pending PRs on the WG-async repo
None.
## `S-waiting-on-team`
### "Rename `AsyncIterator` back to `Stream`, introduce an AFIT-based `AsyncIterator` trait" rust#119550
**Link:** https://github.com/rust-lang/rust/pull/119550
## Proposed FCPs
**Check your boxes!**
### "Tracking Issue for `Ready::into_inner()`" rust#101196
**Link:** https://github.com/rust-lang/rust/issues/101196
## Active FCPs
None.
## P-critical issues
None.
## WG-async work project board
https://github.com/orgs/rust-lang/projects/29/views1/d