# This Month in @compiler-errors (rustc contributions) - December
This is the third<sup>(I think?)</sup> installment in the "This Month in Errs" series where I try to talk about all the contributions I've done this month. Between the holiday season and getting a pretty bad cold in the middle of the month, it actually turned out a bit more productive than expected.
There wasn't a major theme to my contributions this month, though I did kick off some work (e.g. unsafe binders, and async fn in dyn trait) that I expect to follow through with in 2025. And while I didn't work on it this month, I also expect to put up some stabilization reports, namely return type notation (RTN, [#109417](https://github.com/rust-lang/rust/issues/109417)) and precise capturing in traits ([#130044](https://github.com/rust-lang/rust/issues/130044)). Stay tuned.
## Async closures
This month was a huge milestone for async closures. Specifically, they're finally stabilized (on nightly), and they're set to land in 1.85[^coincidentally] -- [#132706 <small>"Stabilize async closures (RFC 3668)"</small>](https://github.com/rust-lang/rust/issues/132706). I'm pretty proud with the stabilization report, so give it a read if you'd like.
[^coincidentally]: Coincidentally also when we'll land Rust edition 2024.
I believe I mentioned it in last month's blog post, but during the stabilization process, we decided against stabilizing the `async Fn()` trait bounds syntax. It was moved behind a new feature gate in [#132612 <small>"Gate async fn trait bound modifier on `async_trait_bounds`"</small>](https://github.com/rust-lang/rust/issues/132612).
The stabilization uncovered a few bugs, such as some code which failed to consider that the trait for `AsyncFnOnce` had two associated types ([#134017](https://github.com/rust-lang/rust/issues/134017)), althrough it doesn't affect stable code. [#134933 <small>"Make sure we check the future type is `Sized` in `AsyncFn*`"</small>](https://github.com/rust-lang/rust/issues/134933) fixed a bug where we failed to properly consider erroneous `fn()` types like `fn() -> dyn Future` in the built-in implementations for the `AsyncFn` traits. The feature was also missing stable MIR support, which was added in [#134295 <small>"Encode coroutine-closures in SMIR"</small>](https://github.com/rust-lang/rust/issues/134295).
Future work will include making `AsyncFn` dyn-compatible so they can be boxed (like `Box<dyn AsyncFn()>`), and working on diagnostics to help point users towards using async closures when they get lifetime errors.
## Unsafe binders
I finally sat down and tried to tackle my unsafe binders experiment. If you're unfamiliar with unsafe binders, check out the ["unsafe binder types"](https://hackmd.io/rAyz9MURTlazMdnffl2uSQ) proposal I wrote up, though I apologize if it's a bit technical. The experiment seeks to provide a more ergonomic (and slightly more coherent, type-theoretically) way to deal with *existential* lifetimes.
I had originally opened a large PR to implement *all* of the feature at once. However, this wasn't practical, so I split up the PR. First, [#134140 <small>"Add AST support for unsafe binders"</small>](https://github.com/rust-lang/rust/issues/134140) implemented the parsing and validation of unsafe binders at a synctactical level. Then, [#134625 <small>"Begin to implement type system layer of unsafe binders"</small>](https://github.com/rust-lang/rust/issues/134625) implemented the type-checking layer, but we still issue an error if unsafe binders are actually used and we don't lower them to MIR yet.
I'll be working on the final interactions with MIR in [#130514 <small>"Implement MIR lowering for unsafe binders"</small>](https://github.com/rust-lang/rust/pull/130514). This PR is quite subtle because of the feature's interactions with `Drop` and the distinction Rust makes between places and values. I expect to clean it up and move it out of draft in the next week or so.
Als, I added Rustdoc support to [#134857 <small>"Unsafe binder support in rustdoc"</small>](https://github.com/rust-lang/rust/issues/134857). Small piece of the puzzle, but still incremental progress :^)
## Async Fn in Dyn Traits (AFIDT)
Another feature implementation I started was "async fn in dyn traits" (AFIDT). This experiment seeks to fill the major missing gap in "async fn in trait" functionality, which is that traits with `async fn`s in them are not dyn-compatible.
Niko wrote a lot about it (starting [here](https://smallcultfollowing.com/babysteps//blog/2021/09/30/dyn-async-traits-part-1/)). I barely implemented the vague ideas of the feature in
[#133122 <small>"Add unpolished, experimental support for AFIDT (async fn in dyn trait)"</small>](https://github.com/rust-lang/rust/issues/133122), however, it's clear that it's going to need significant design work to come up with something that is ergonomic, sound, and theoretically self-consistent. I'll be working on that this month hopefully.
## Const traits
I may have mentioned it last month, but [#133325 <small>"Reimplement `~const` trait specialization"</small>](https://github.com/rust-lang/rust/issues/133325) fills a necessary gap in the type system to support `const`ifying the `PartialEq` trait (and others in the standard library) which rely on specialization under the hood. I was then able to open up
[#133995 <small>"Constify `PartialEq`"</small>](https://github.com/rust-lang/rust/issues/133995), which is temporarily blocked on a PR that sorts out our "const stability" story a bit better.
One important validation step in Rust is *const checking*, which validates that the functions called in a `const fn` or `const` item are actually legal to be performed in a const context. The PRs [#134701 <small>"Correctly note item kind in NonConstFunctionCall error message"</small>](https://github.com/rust-lang/rust/issues/134701) and [#134732 <small>"Unify conditional-const error reporting with non-const error reporting"</small>](https://github.com/rust-lang/rust/issues/134732) tweak error reporting to make const errors a bit more readable as we continue to `const`ify the standard library.
[#134951 <small>"Suppress host effect predicates if underlying trait doesn't hold"</small>](https://github.com/rust-lang/rust/issues/134951) tweaks error messages to be less redundant when users write `~const` and `const` trait bounds and the underlying trait is not implemented at all.
[#133926 <small>"Fix const conditions for RPITITs"</small>](https://github.com/rust-lang/rust/issues/133926) fixes support for `~const` bounds in return-position impl traits in trait methods, like:
```rust
#[const_trait] trait Foo {
fn method() -> impl ~const Bar;
}
```
Finally, since we maintain two implementations of const trait checking -- the old trait solver and the [new trait solver](https://github.com/rust-lang/rust/issues/107374) -- there were some discrepancies where the old trait solver wasn't as powerful (i.e., it couldn't prove as many `~const` trait bounds). In [#134638 <small>"Fix effect predicates from item bounds in old solver"</small>](https://github.com/rust-lang/rust/issues/134638) and [#134875 <small>"Implement `const Destruct` in old solver"</small>](https://github.com/rust-lang/rust/issues/134875), those discrepancies are slowly being whittled away.
## New Features
I worked on a couple other types-related features recently. Most significantly, in [#134185 <small>"(Re-)Implement `impl_trait_in_bindings`"</small>](https://github.com/rust-lang/rust/issues/134185), I sketched out a new design for `impl_trait_in_bindings`, which allows code like:
```rust
let x: impl Debug = "hello, world";
```
I'm not totally sure how useful this feature is, but I expect it to be a good way to assert that a local variable implements a trait, and it can also be used to guide inference for things like closures:
```
let c: impl Fn(&i32) = |x| {};
```
The feature also uncovered a funny little bug which I squashed in [#134313 <small>"Don't make a def id for `impl_trait_in_bindings`"</small>](https://github.com/rust-lang/rust/issues/134313).
Unrelatedly, I fixed a rustfmt regression due to the `default_field_values` feature in [#134668 <small>"Make sure we don't lose default struct value when formatting struct"</small>](https://github.com/rust-lang/rust/issues/134668). The regression highlights an interesting interaction with parser extensions and the formatting we do inside of macros.
## New Solver
I worked a bit more on the new trait solver this month. Firstly, I fixed a really funny bug in [#133828 <small>"Make sure to record deps from cached task in new solver on first run"</small>](https://github.com/rust-lang/rust/issues/133828) which has to do with the fact that we were not tracking incremental dependencies correctly on the first invocation of the trait solver for a specific trait goal, like `i32: Debug`. Much thanks to [@lqd](https://github.com/lqd) for minimizing the test to something I could actually analyze.
I fixed a bunch of other random new-trait-solver-related bugs. [#134742](https://github.com/rust-lang/rust/issues/134742) fixes a bug with impl trait inference and async. In [#134744](https://github.com/rust-lang/rust/issues/134744), I suppressed a bug in the `transmute` validation code. The PR [#134746](https://github.com/rust-lang/rust/issues/134746) fixes a bug with autoref coercions and bad associated types. The PR [#134771](https://github.com/rust-lang/rust/issues/134771) fixes a bug when an impl provides an invalid type for a const arg. And finally, [#134940](https://github.com/rust-lang/rust/issues/134940) fixes a bug when normalizing type-outlives `where` clauses like `where Ty::Assoc: 'a` in the borrow-checker.
## Diagnostics
[#134745 <small>"Normalize each signature input/output in `typeck_with_fallback` with its own span"</small>](https://github.com/rust-lang/rust/issues/134745) tweaks the spans that we use to report errors when users write invalid associated types in their function signatures. This results in duplicated error messages getting de-duplicated, since Rust now sees that they're identical.
The PR [#134798 <small>"Make `ty::Error` implement all auto traits"</small>](https://github.com/rust-lang/rust/issues/134798) suppresses unnecessary trait errors when users write structs with fields that have typo'd field types. Hopefully this will help users more clearly see the *actionable* error message when the make a typo.
The [#134945 <small>"Some small nits to the borrowck suggestions for mutating a map through index"</small>](https://github.com/rust-lang/rust/issues/134945) makes a few tweaks to the preexisting error logic we have when users try to mutate a `HashMap` or `BTreeMap` through the `IndexMut` operator, like `k[v] = i`.
Finally, [#134639 <small>"Make sure we note ambiguity causes on positive/negative impl conflicts"</small>](https://github.com/rust-lang/rust/issues/134639) fixes an inconsistency with `#[feature(negative_impls)]` where if we have an overlap between a negative impl and a positive (normal) impl, we wouldn't explain *why*.
## Miscellaneous correctness
[#133992 <small>"Actually walk into lifetimes and attrs in `EarlyContextAndPass`"</small>](https://github.com/rust-lang/rust/issues/133992) was a fix to the way that the `Visitor` pattern is implemented for our ASTs. Specifically, we were not fully visiting lifetimes and attributes (`#[attr]`) correctly. Fixing this bug uncovered some previously untriggered instances (false-negatives) of the `HiddenUnicodeCodepoints` lint, which detect bad unicode codepoints (like the RTL control characters).
Related to that last lint, [#134956 <small>"Account for C string literals and format_args in `HiddenUnicodeCodepoints` lint"</small>](https://github.com/rust-lang/rust/issues/134956) also fixed a bug where we weren't detecting bad unicode codepoints on `c""` strings and also in the format string inside of `println!("...")` and related macros.
The PR [#134735 <small>"Consider arm to diverge if guard diverges"</small>](https://github.com/rust-lang/rust/issues/134735) is a small ergonomic improvement to our *divergence analysis* which is responsible for detecting dead code that follows expressions with divering control flow (like `return`, `break`, and `panic!()`). It specifically fixed a case where we didn't consider diverging match guards (like `match x { 1 if panic!() => {} }`).
Finally, [#133889 <small>"Consider fields to be inhabited if they are unstable"</small>](https://github.com/rust-lang/rust/issues/133889) fixes a bug introduced by the `min_exhaustive_patterns` feature stabilization, where although [`Pin`](https://doc.rust-lang.org/1.83.0/src/core/pin.rs.html#1101)'s "inner" pinned field is public, it's unstable, and therefore we probably should consider it the same as private when considering struct inhabitedness.
## Edition 2024
This month was major polishing time for the new edition. [@ehuss](https://github.com/ehuss) did some amazing work triaging and identifying a ton of bugs having to do with the edition migration lints, and I spent some time working on improving them as a result. I'm incredibly excited for Edition 2024 to land.
The PR [#134142 <small>"Rudimentary heuristic to insert parentheses when needed for RPIT overcaptures lint"</small>](https://github.com/rust-lang/rust/issues/134142) improves the suggestion to change `impl Trait` to `impl Trait + use<'a, 'b>` to consider when parentheses may need to be added for parsing to succeed.
Never type fallback will change in 2024, and I previously discussed improving the error to give better suggestion about where to add `()` unit type ascription to preserve the old behavior. In [#134144 <small>"Properly consider APITs for never type fallback ascription fix"</small>](https://github.com/rust-lang/rust/issues/134144), this fixes a bug where we didn't consider the fact that APIT (argument-position impl trait) cannot be turbofished.
Another major change coming in the edition is changes to the way we handle temporary expressions, which the `tail_expr_drop_order` lint aims to detect. To do so, it changes the way we emit drop statements in MIR to also emit a set of "drop hint" statements at the points where drops would happen in edition 2024, which we can use to do analysis about any major drop changes between editions 2021 and 2024.
However, the code overlooked some codepaths, and we accidentally were affecting the way drops *behaved* in normal code. This was fixed by [#134486 <small>"Make sure we handle `backwards_incompatible_lint` drops appropriately in drop elaboration"</small>](https://github.com/rust-lang/rust/issues/134486) and
[#134575 <small>"Handle `DropKind::ForLint` in coroutines correctly"</small>](https://github.com/rust-lang/rust/issues/134575). I'm always appreciative of our users reporting the strangest and coolest bugs to fix, so special thanks to [@Clipi-12](https://github.com/Clipi-12) for minimizing and reporting the issue in [#134482](https://github.com/rust-lang/rust/issues/134482).
The PR [#134493 <small>"Always run `tail_expr_drop_order` lint in promoted MIR query"</small>](https://github.com/rust-lang/rust/issues/134493) fixes a bug where `cargo check` would not fire the `tail_expr_drop_order` lint, but `cargo build` would, due to the place in the compiler pipeline that the lint was originally configured to trigger. Moving the analysis further up the pipeline fixed that.
The PR [#134478 <small>"Properly record metavar spans for other expansions other than TT"</small>](https://github.com/rust-lang/rust/issues/134478) aims to fix some subtleties around error suggestions and macro metavariables (like `$expr`). This has the side-effect of improving the edition migration lints, but also other suggestions and errors that involve macros as well :cat:
In the final days before Edition 2024 lands on beta, I put up [#134929 <small>"Stabilize `style_edition = "2024"` in-tree"</small>](https://github.com/rust-lang/rust/issues/134929) to make sure that users can specify `style_edition = "..."` in their `rustfmt.toml` file. This is important in case they'd like to decouple upgrading to Edition 2024 and reformatting all their code against the new style edition 2024 we are releasing at the same time, since while I wholeheartedly believe that the new style edition is an improvement over the status quo, it may result in a lot of formatting changes in some projects, and they should have the freedom to stage those changes separately if desired.
## Miscellaneous ICE fixes
[#134635 <small>"Don't ICE on illegal `dyn*` casts"</small>](https://github.com/rust-lang/rust/issues/134635) fixes a bug where we used to panic if we tried to do a nontrivial `dyn*` to `dyn*` coercion, such as turning `dyn* Trait + Send` to `dyn* Trait`. These are not supported coercions for now, but we weren't expecting them to fail either.
[#134103 <small>"Don't ICE when encountering never in range pattern"</small>](https://github.com/rust-lang/rust/issues/134103) fixes a bug where we were previously panicking if we encountered a bad range pattern involving a variable whose type is `!`.
## Miscellaneous cleanups
[#133768 <small>"Remove `generic_associated_types_extended` feature gate"</small>](https://github.com/rust-lang/rust/issues/133768) removed code that was originally added to the compiler to experiment with dyn-compatible generic associated types, like `dyn for<'a> Foo<Assoc<'a> = &'a ()>`. However, this feature ended up not making much progress, and maintaining the code was a bit of a hassle. Removing this code also allowed us to remove more `dyn Trait` special casing in [#133872 <small>"No need to create placeholders for GAT args in `confirm_object_candidate`"</small>](https://github.com/rust-lang/rust/issues/133872).
[#134141 <small>"Remove more traces of anonymous ADTs"</small>](https://github.com/rust-lang/rust/issues/134141) removes some leftover code having to do with the "`unnamed_fields`" feature that was removed from nightly Rust [recently](https://github.com/rust-lang/rust/pull/131045).
[#134259 <small>"Clean up `infer_return_ty_for_fn_sig`"</small>](https://github.com/rust-lang/rust/issues/134259) is a minor ergonomic tweak in the control flow for some type lowering code, which previously conceptually prioritied the "recovery" over the "good" path when handling functions signatures with `_` in them, like `fn foo() -> _ { ... }`. It moves all the recovery logic into a new function so it's out of the way.
The PR [#134741 <small>"Actually print all the relevant parts of a coroutine in verbose mode"</small>](https://github.com/rust-lang/rust/issues/134741) improves the `-Zverbose-internals` unstable flag to actually print all of the "components" of a coroutine (i.e. its return/yield/resume) types. This is very useful when debugging async and impl trait related bugs.
I tweaked a lot of code in a somewhat disorganized way. [#134827 <small>"Some random region tweaks"</small>](https://github.com/rust-lang/rust/issues/134827) removes a redundant accessor in the lifetime constraint handling code, and adds an assertion that may catch bugs later in the migration to the new solver. [#134491 <small>"Some destructor/drop related tweaks"</small>](https://github.com/rust-lang/rust/issues/134491) cleans up some ID handling around `Drop`/destructor code. And finally, [#134984 <small>"`ObligationCause` construction tweaks in typeck"</small>](https://github.com/rust-lang/rust/issues/134984) consolidates some tracking around trait obligations in the type checker.