Rollup merge of #139762 - compiler-errors:non-env, r=lcnr

Don't assemble non-env/bound candidates if projection is rigid

Putting this up for an initial review, it's still missing comments, clean-up, and possibly a tweak to deal with ambiguities in the `BestObligation` folder.

This PR fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/173. Specifically, we're creating an unnecessary query cycle in normalization by assembling an *impl candidate* even if we know later on during `merge_candidates` that we'll be filtering out that impl candidate.

This PR adjusts the `merge_candidates` to assemble *only* env/bound candidates if we have `TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound`.

I'll leave some thoughts/comments in the code.

r? lcnr
This commit is contained in:
Chris Denton 2025-04-19 15:09:34 +00:00 committed by GitHub
commit 688478fe45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 107 additions and 56 deletions

View file

@ -7,23 +7,6 @@ LL | impl<T> Foo<T> for [isize; 0] {
LL | impl<T, U> Foo<T> for U {
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> $DIR/impl-unused-tps.rs:32:9
|
LL | impl<T, U> Bar for T {
| ^ unconstrained type parameter
error[E0119]: conflicting implementations of trait `Bar`
--> $DIR/impl-unused-tps.rs:40:1
|
LL | impl<T, U> Bar for T {
| -------------------- first implementation here
...
LL | / impl<T, U> Bar for T
LL | | where
LL | | T: Bar<Out = U>,
| |____________________^ conflicting implementation
error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
--> $DIR/impl-unused-tps.rs:49:1
|
@ -52,6 +35,12 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self
LL | impl<T, U> Foo<T> for [isize; 1] {
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> $DIR/impl-unused-tps.rs:32:9
|
LL | impl<T, U> Bar for T {
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> $DIR/impl-unused-tps.rs:40:9
|
@ -70,6 +59,17 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self
LL | impl<T, U, V> Foo<T> for T
| ^ unconstrained type parameter
error[E0119]: conflicting implementations of trait `Bar`
--> $DIR/impl-unused-tps.rs:40:1
|
LL | impl<T, U> Bar for T {
| -------------------- first implementation here
...
LL | / impl<T, U> Bar for T
LL | | where
LL | | T: Bar<Out = U>,
| |____________________^ conflicting implementation
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0119, E0207.

View file

@ -0,0 +1,32 @@
//@ compile-flags: -Znext-solver
//@ check-pass
//@ edition: 2024
// Ensure we don't end up in a query cycle due to trying to assemble an impl candidate
// for an RPITIT normalizes-to goal, even though that impl candidate would *necessarily*
// be made rigid by a where clause. This query cycle is thus avoidable by not assembling
// that impl candidate which we *know* we are going to throw away anyways.
use std::future::Future;
pub trait ReactiveFunction: Send {
type Output;
fn invoke(self) -> Self::Output;
}
trait AttributeValue {
fn resolve(self) -> impl Future<Output = ()> + Send;
}
impl<F, V> AttributeValue for F
where
F: ReactiveFunction<Output = V>,
V: AttributeValue,
{
async fn resolve(self) {
self.invoke().resolve().await
}
}
fn main() {}