Commit 8378487 from #114611 changed the location of an obligation
deduplication step in `opt_normalize_projection_type`. This meant that
deduplication stopped happening on one path where it was still
necessary, causing a couple of drastic performance regressions.
This commit moves the deduplication back to the old location. The good
news is that #114611 had four commits and 8378487 was of minimal
importance, so the perf benefits from that PR remain.
Fixes#116780, #116797.
Normalize opaques with late-bound vars again
We have a hack in the compiler where if an opaque has escaping late-bound vars, we skip revealing it even though we *could* reveal it from a technical perspective. First of all, this is weird, since we really should be revealing all opaques in `Reveal::All` mode. Second of all, it causes subtle bugs (linked below).
I attempted to fix this in #100980, which was unfortunately reverted due to perf regressions on codebases that used really deeply nested futures in some interesting ways. The worst of which was #103423, which caused the project to hang on build. Another one was #104842, which was just a slow-down, but not a hang. I took some time afterwards to investigate how to rework `normalize_erasing_regions` to take advantage of better caching, but that effort kinda fizzled out (#104133).
However, recently, I was made aware of more bugs whose root cause is not revealing opaques during codegen. That made me want to fix this again -- in the process, interestingly, I took the the minimized example from https://github.com/rust-lang/rust/issues/103423#issuecomment-1292947043, and it doesn't seem to hang any more...
Thinking about this harder, there have been some changes to the way we lower and typecheck async futures that may have reduced the pathologically large number of outlives obligations (see description of #103423) that we were encountering when normalizing opaques with bound vars the last time around:
* #104321 (lower `async { .. }` directly as a generator that implements `Future`, removing the `from_generator` shim)
* #104833 (removing an `identity_future` fn that was wrapping desugared future generators)
... so given that I can see:
* No significant regression on rust perf bot (https://github.com/rust-lang/rust/pull/107620#issuecomment-1600070317)
* No timeouts in crater run I did (https://github.com/rust-lang/rust/pull/107620#issuecomment-1605428952, rechecked failing crates in https://github.com/rust-lang/rust/pull/107620#issuecomment-1605973434)
... and given that this PR:
* Fixes#104601
* Fixes#107557
* Fixes#109464
* Allows us to remove a `DefiningAnchor::Bubble` from codegen (75a8f68183)
I'm inclined to give this another shot at landing this. Best case, it just works -- worst case, we get more examples to study how we need to improve the compiler to make this work.
r? types
Add a fully fledged `Clause` type, rename old `Clause` to `ClauseKind`
Does two basic things before I put up a more delicate set of PRs (along the lines of #112714, but hopefully much cleaner) that migrate existing usages of `ty::Predicate` to `ty::Clause` (`predicates_of`/`item_bounds`/`ParamEnv::caller_bounds`).
1. Rename `Clause` to `ClauseKind`, so it's parallel with `PredicateKind`.
2. Add a new `Clause` type which is parallel to `Predicate`.
* This type exposes `Clause::kind(self) -> Binder<'tcx, ClauseKind<'tcx>>` which is parallel to `Predicate::kind` 😸
The new `Clause` type essentially acts as a newtype wrapper around `Predicate` that asserts that it is specifically a `PredicateKind::Clause`. Turns out from experimentation[^1] that this is not negative performance-wise, which is wonderful, since this a much simpler design than something that requires encoding the discriminant into the alignment bits of a predicate kind, or something else like that...
r? ``@lcnr`` or ``@oli-obk``
[^1]: https://github.com/rust-lang/rust/pull/112714#issuecomment-1595653910
Add `implement_via_object` to `rustc_deny_explicit_impl` to control object candidate assembly
Some built-in traits are special, since they are used to prove facts about the program that are important for later phases of compilation such as codegen and CTFE. For example, the `Unsize` trait is used to assert to the compiler that we are able to unsize a type into another type. It doesn't have any methods because it doesn't actually *instruct* the compiler how to do this unsizing, but this is later used (alongside an exhaustive match of combinations of unsizeable types) during codegen to generate unsize coercion code.
Due to this, these built-in traits are incompatible with the type erasure provided by object types. For example, the existence of `dyn Unsize<T>` does not mean that the compiler is able to unsize `Box<dyn Unsize<T>>` into `Box<T>`, since `Unsize` is a *witness* to the fact that a type can be unsized, and it doesn't actually encode that unsizing operation in its vtable as mentioned above.
The old trait solver gets around this fact by having complex control flow that never considers object bounds for certain built-in traits:
2f896da247/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs (L61-L132)
However, candidate assembly in the new solver is much more lovely, and I'd hate to add this list of opt-out cases into the new solver. Instead of maintaining this complex and hard-coded control flow, instead we can make this a property of the trait via a built-in attribute. We already have such a build attribute that's applied to every single trait that we care about: `rustc_deny_explicit_impl`. This PR adds `implement_via_object` as a meta-item to that attribute that allows us to opt a trait out of object-bound candidate assembly as well.
r? `@lcnr`