---
title: ITE meeting 2023-12-07
tags: ["impl-trait-everywhere", "triage-meeting", "minutes"]
date: 2023-12-07
discussion: https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/ITE.20triage.20meeting.202023-12-07
url: https://hackmd.io/BCouD7HOQdeVuuqJ18XHrQ
---
# ITE meeting agenda
- Meeting date: 2023-12-07
## Attendance
- People: TC, errs, tmandry
## Meeting roles
- Minutes: TC
## Announcements or custom items
(Meeting attendees, feel free to add items here!)
## impl-trait-utils
tmandry: I'm hoping to hack on a proc macro `impl-trait-utils` that helps with the `Send` bound problem.
https://github.com/rust-lang/impl-trait-utils
## Mini-TAIT status
In the October 2023 T-types meetup, we had a great and very collaborative session on TAIT that resulted in a proposal for a minimal TAIT stabilization named Mini-TAIT. We [presented](https://hackmd.io/CDj92gZdTzilDWORdKhLQA) this to T-lang on 2023-11-08. However, there were only 3 T-lang members present, and the meeting failed to gain consensus as discussion revisited the [#107645 FCP](https://github.com/rust-lang/rust/issues/107645#issuecomment-1571789814) about how we notate what items are allowed to define the hidden type of some opaque.
To disentangle things, as the key aspects of the Mini-TAIT proposal are orthogonal to this notation, we've made T-lang nominations for each aspect of Mini-TAIT:
- [Once modulo regions restriction - #116935](https://github.com/rust-lang/rust/pull/116935#issuecomment-1807243974)
- [May define implies must define restriction - #117861](https://github.com/rust-lang/rust/issues/117861#issue-1989842470)
- [May define may guide inference - #117865](https://github.com/rust-lang/rust/issues/117865#issue-1990005181)
- [Whether nested inner items may define - #117860](https://github.com/rust-lang/rust/issues/117860#issue-1989813479)
There is a dual T-lang/T-types FCP also related to TAIT (but also to RPIT) ongoing here:
- [Exhaustiveness: reveal opaque types properly - #116821](https://github.com/rust-lang/rust/pull/116821)
And we're proposing a new Mini-TAIT restriction here:
- [Must define before use restriction - #117866](https://github.com/rust-lang/rust/issues/117866#issue-1990323059)
The hypothesis is that this restriction could make it more plausible to later lift the "may define implies must define" restriction.
## Prevent opaque types being instantiated twice with different regions within the same function - #116935
CE: aliemjay has an interesting concern here:
https://github.com/rust-lang/rust/pull/116935#issuecomment-1835699182
TC: One of the concerns here is yours, tmandry, and CE, you're probably the best to answer that.
CE: If there are no regressions in a crater run, would we still want to lint first?
tmandry: Thinking about this.
CE: It's really unlikely to have regressions here because you need a recursive call in RPIT with different substitutions. I wouldn't expect to see this in the wild anywhere.
CE: We can't support this in the new solver anyway. So they'll need to fix this regardless.
CE: We could do a beta crater run here also. This would be easy to bisect to this commit.
CE: The error isn't that bad. The error is what the warning would be.
tmandry: If crater is clear, then I'm OK to drop my concern. But if it does cause regressions in big code bases, then we should consider revising it as a warning.
## Add new solver / old solver opaque type tests - #118717
**Link**: https://github.com/rust-lang/rust/pull/118717
CE: A module with just one function in it (no closures either) is identicial to RPIT with the usual caveats (e.g. capture rules, etc.).
CE: When we have an opaque. When you have a value of some type, and you do value dot method. And we assemble the defer ladder. The deref steps. If the opaque has not yet been defined, then we might cut off the deref ladder at that point. Otherwise, it's always ambiguous to call a method on the opaque because of how we do method selection. This is because we require constructing the whole deref ladder even though the first step in the ladder already provides the method you're looking for. This has to do with backward compatibility for inferring the infer type on `*const _`.
```rust
fn main() {
// If an opaque is turbofished here, then it's not an error.
let x = std::ptr::null::<_>();
x.is_null();
//~^ ERROR cannot call a method on a raw pointer with an unknown pointee type
let y: *const () = x;
}
```
CE: In order to preserve that behavior, if we hit an opaque, and that opaque has not yet been defined, then we might just stop. That might cause incompleteness. And would result in a "no method found" error. But only after getting to the bottom of the truncated opaque ladder.
CE: We haven't yet introduced something like this. It currently doesn't work at all with autoderef in the new solver.
CE: But otherwise, we would expect that within the body of an RPIT, or in general within a scope in which the opaque type is defined, that the opaque type can be used equivalently with the concrete type due to lazy normaliation.
CE: Recalling the existing value of an opaque in a body is not defining the opaque again. If we can select an implementation unambiguously, then it's defining. But if there are multiple applicable implementations, then it's going to be ambiguous until we constrain the opaque elsewhere.
Tait: Add<i32> ??????
satisfied by - i32: Add<i32>
satisfied by - &i32: Add<i32>
CE: It would not choose one of them arbitrarily as that would be incompleteness. But it does record that it needs to satisfy one of thone two. If there were only one, then we'd define it immeditaely.
TC: The same applies to field access?
CE: The way it works with fields is similar but different. If the opaque hasn't been defined yet, it'll be ambiguous.
```rust
#![feature(type_alias_impl_trait)]
type Tait = impl Sized;
fn hello(x: &Tait) {
x.field
//~^ ERROR type annotations needed
//~| ERROR no field `field` on type `&Tait` (errs: Seems wrong)
}
```
CE: There's no incompleteness here at all. So even if there's a struct in your crate with that field, the compiler doesn't care and won't use that to guide inference.
THIS IS A BUG:
```rust
// compile-flags: -Ztrait-solver=next
#![feature(type_alias_impl_trait)]
type Tait = impl Sized;
struct Foo {
field: i32,
}
fn hello(mut x: &Tait) {
x = &Foo { field: 0 };
x.field;
}
```
[Godbolt link](https://rust.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DEArgoKkl9ZATwDKjdAGFUtEywZ7HAGTwNMAHLuAEaYxHoADqgKhHYMLm4ekdGxAr7%2BQSyh4VyWmNa2AkIETMQECe6euVaYNnHFpQTpgSFheuaNFUnVJWXNmdkSAJSWqCbEyOwcAKQATABic/MA1GgsEXSYALRUBsAK0wDMAILLWwBaBMRMhFsKrgBuYUcAIv6qBNMax3OHc1z/aYAVgAQlRMEwCONMHMABwEACeEUwAH0xHgmAoUXh1rQUVcbp9ZgBOYEvL4/b6I5HLAAqhOWr2WOIitGWQjwAC9MOgjiCKRTzKYbMt5qhUIyAOz877LOXLGj5XknZmHWZzJwCyXk74UqgMZYIfK0VBwlgmAjLVRHU5zABs9MIc2JUplp3lqkZhxejNmdrFEum0oVeCVNuWGil5MObvlVoAdIraLzddqKRwRrROEDeJ4OFpSKhOAAlMyW%2B7jSa%2Bw48UgETQZkYAaxAh0O8bbna73bt%2Bk4klzDcLnF4ChAGjrDZGcFgMEQKFQ602ZAoEDWG3o4QYeGACAItARpCwDzwkwAaqGAO4AeWRedrNFoBDCY4gwSHwT8pQRnFrn%2BYxAItewTaLU9bcLwaxsII14MAeQ5YMEJjAE4Yi0GOEFHpgLCGMA4j5rw%2BDEGBeBPBhBaYKotQWlMtZ%2BM%2BWYEfoeDBNcgEuFgQ5XDiv4ZnwewKBemA3nevEyIIIhiOwUjifIShqEOui5AYRggKY5jMcEY6QCMqARIUDAYRcBK3PctBPMQrzvAQvCoBZxB4Fg2lQMwbAgDyqQMKQDxiCYUyzBosw8EMIwRIYgSsFMATCcsZkWaO%2BQkfYECOF0VSkD4fgtFkbS5FEMQGWlyQFXE/StDkeQFPUvTlK4lTtIldRFDVZU5RVHRlEVPSNK1gxcCMFYTNJmbZoOTFFhw0WXrFjxhLw4FaCFpAtm2Hbdutba9oxA6kCwIBAhOeYFhNo7jpOBHTnOEBIOuy7kJQt2biA267vuh7HqemBCSJjBiY%2Bz7EK%2B75Mf%2B35iaDgHAaBNhiVBjAELB8FMYhyGobQ6FiVgOFGPhBZESRZFDpR1HPmJ9H5EOtAsWxCIcVMBbcXtEEjLsTD7N9t6/Zh/ASaI4gyTzckqOoTG6LM%2Bi4WpZaac5un6XERmXNcpmzZZ3rIAYCgxMgtn2Y5mDORArnsB5Bneb5/mBcFoXhQEkWcE4mvazN5lzZVSWeClDDOHV3QZd7vW5aQ%2BWeV1wcpAZgftY1BkNJ1vvpTUTUMHHTRZQMQcdbViSJy16flcMoyVsNfYcDmpBHbZDtO6eLvxedi0jEaTBYOEEAjRwO17QdFdDidlhnQtjbLa27YbRtW2cIcY3HSODd8TOUBXUgYwEBEFr3Wui4bmEdtuRw6kEMgywvXuB68KbJCOXoguSfz0iC4owuKZEtv25NMVxW0yyr%2BvNmkJea4EReId3LpXYcH9ppf3CD/C0f95pTmbKPNa48uyly7vtQ6fc55jgnEPS68BrogF/hvVcj1d7v0PsfU%2Bb0L74CIA5dAN9ZB32kg/WQT8FKixAOLMKGR36O0xM7aBIBYFrwtLwQBTBgHM1LmA7BHBBFa1riIsR8D55LWbq3SgHcME93Af3XBGikGrVQd2Uu09e7jTnvgjuswZ5Vw4Agi6IwLIxHsJIIAA%3D%3D)
CE: This should work in the new trait solver.
---
TC: One surprising case is the test:
`reveal-hidden-via-match-at-binding-unwrapped.rs`
```rust
// edition:2021
// revisions: new old
// [new]compile-flags: -Ztrait-solver=next
// [old]compile-flags: -Ztrait-solver=classic
// known-bug: unknown
struct I;
struct IShow;
impl I {
#[allow(dead_code)]
pub fn show(&self) -> IShow {
IShow
}
}
struct OnIShow;
trait OnI {
fn show(&self) -> OnIShow {
OnIShow
}
}
impl OnI for I {}
fn test(n: bool) -> impl OnI {
let true = n else { return I };
// This should be a defining use, but is not currently.
let _: IShow = match test(!n) {
x @ I => x.show(),
};
I
}
fn main() {}
```
CE: This should work in the new solver. That binding should constrain `x`. Right now, method deref steps ignores all opaques in the new solver.
TC: Looking at:
`reveal-hidden-via-match-at-binding-wrapped-onw.rs`
```rust
// edition:2021
// revisions: new old
// [new]compile-flags: -Ztrait-solver=next
// [old]compile-flags: -Ztrait-solver=classic
// [new]check-pass
// [old]known-bug: unknown
struct I;
struct W<T>(T);
struct WIShow;
impl W<I> {
pub fn show(&self) -> WIShow {
WIShow
}
}
struct OnWShow;
trait OnW {
fn show(&self) -> OnWShow {
OnWShow
}
}
impl<T: Sized> OnW for W<T> {}
fn test(n: bool) -> impl Sized {
let true = n else { return 1i32; };
let _: WIShow = match W(test(!n)) {
x => x.show(),
// ~^ ERROR expected `WIShow`, found `OnWShow`
};
todo!()
}
fn main() {}
```
CE: The new trait solver is rather eager, and so in this case, if it's not already constrained, then calling a method that could constrain it does, but if it's not constrained, then we just overlook the method.
CE: We'll want to add comments to the tests so that when we update the behavior of the new solver later, we can update those comments to describe the new intended behavior.
~~CE: Exhaustiveness doesn't constrain an opaque to never, since there could be multiple types.~~
TC: One of the tests is inspired by a hack that people do to work around the lack of `typeof` using TAIT.
`reveal-hidden-via-match-tuple.rs`
The simple version of `make_static!`:
```rust
#![feature(sync_unsafe_cell)]
#![feature(type_alias_impl_trait)]
macro_rules! make_static {
($x:expr) => {{
use core::{cell::SyncUnsafeCell, mem::MaybeUninit};
type T = impl Sized;
static X: SyncUnsafeCell<MaybeUninit<T>> =
SyncUnsafeCell::new(MaybeUninit::uninit());
match unsafe { (*X.get()).write(($x,)) } {
(ref mut x,) => x,
}
}};
}
fn test() {
let x = make_static!(0u32);
let _: &'static mut u32 = x;
}
```
CE: This is just a bug in the sense that this should work even without this indirection of the tuple. It should just work in the new trait solver because we don't care about whether we asign in one direction or the other.
CE: `?0 = impl Sized`, we always assign `?0 := impl Sized`, never `impl Sized := ?0`.
CE: So with the tuple, there's no inference variable that's being made equal to the type of the opaque.
CE: `(?0,) = impl Sized`. Always `impl Sized := (?0,)`, we can later freely constrain `?0` to be whatever our static's actual type is.
TC: What other hard avenues can we explore?
`reveal-hidden-via-wrapped-receiver.rs`
```rust
// edition:2021
// revisions: new old
// [new]compile-flags: -Ztrait-solver=next
// [old]compile-flags: -Ztrait-solver=classic
// [new]check-pass
// [old]known-bug: unknown
struct W<T>(T);
struct WShow;
impl W<()> {
pub fn show(&self) -> WShow {
WShow
}
}
struct OnWShow;
trait OnW {
fn show(&self) -> OnWShow {
OnWShow
}
}
impl<T> OnW for W<T> {}
fn test(n: bool) -> impl Sized {
let true = n else { todo!() };
let _: WShow = W(test(!n)).show();
todo!()
}
fn main() {}
````
TC: That's a good point. I'm going to go back through and make it diverge on those edges.
CE: Method selection and having the opaque defined before or after it are interesting edges. And field access. And maybe trait selection, but maybe that's not interesting.
CE: As you discovered, even today without TAIT, there are going to be differences between the new solver and the old solver are unavailable. So maybe we just shouldn't care that much about some of these edge case inference differences.
## Lint for never-to-any value coercions
TC: We're looking to lint on this case:
```rust
if false { panic!() } else { transmute::<_ /* ?0 */>(()) }
// later in fallback: ?0 := ()
// after ! stabilization: ?0 := !
```
CE: It might be possible as it happens at the end of typechecking. We're looking for fallback.
CE: This is possible I think. Ask waffle or fmease. They can probably do it.
TC: This would make it easier to eventually do this.
CE: We could make this deny-by-default eventually.
## Signature restriction
```rust
// Valid with PR!
// Currently not valid.
fn def<T>() -> Opaque<i32> {
let x: Opaque<T> = ();
todo!()
}
```
CE: In order to make normalization tractable, we need to make it say that it doesn't care what the generic parameters are.
CE: I want Oli to get back to land this.
CE: We're close on the implementation side other than that.
(The meeting ended here.)
## Project board issues
### "AFIT: impl can't add extra lifetime restrictions, unlike non-async" #104689
- **Link:** https://github.com/rust-lang/rust/issues/104689
### "Weird interaction between specialization and RPITITs" #108309
- **Link:** https://github.com/rust-lang/rust/issues/108309
### "RPITIT with Send trait marker breaks borrow checker" #111105
- **Link:** https://github.com/rust-lang/rust/issues/111105
### "`Failed to normalize` `async_fn_in_trait` ICE for indirect recursion of async trait method calls" #112047
- **Link:** https://github.com/rust-lang/rust/issues/112047
### "Exponential compile times for chained RPITIT" #102527
- **Link:** https://github.com/rust-lang/rust/issues/102527
### "Mysterious "higher-ranked lifetime error" with async fn in trait and return-type notation" #110963
- **Link:** https://github.com/rust-lang/rust/issues/110963
### "AFIT: strange errors on circular impls" #112626
- **Link:** https://github.com/rust-lang/rust/issues/112626
### "Nightly (warning): Async traits Self return requires type specification" #113538
- **Link:** https://github.com/rust-lang/rust/issues/113538
### "hrtb + infer types break auto traits with return type notation " #109924
- **Link:** https://github.com/rust-lang/rust/issues/109924
### "`async_fn_in_trait` and `return_type_notation` cause awkward awaits" #112569
- **Link:** https://github.com/rust-lang/rust/issues/112569
## Pending PRs on the impl-trait-initiative repo
None.
## Open PRs
### "stricter hidden type wf-check" rust#115008
- **Link:** https://github.com/rust-lang/rust/pull/115008
- **Labels:** S-waiting-on-review, A-impl-trait, disposition-merge, finished-final-comment-period, T-types, WG-trait-system-refactor
### "rework opaque type region inference" rust#116891
- **Link:** https://github.com/rust-lang/rust/pull/116891
- **Labels:** S-waiting-on-review, needs-fcp, F-type_alias_impl_trait, T-types
### "Prevent opaque types being instantiated twice with different regions within the same function" rust#116935
- **Link:** https://github.com/rust-lang/rust/pull/116935
- **Labels:** T-lang, A-impl-trait, proposed-final-comment-period, S-blocked, disposition-merge, F-type_alias_impl_trait, T-types