Skip to content

Commit a728176

Browse files
authored
Unrolled build for rust-lang#140276
Rollup merge of rust-lang#140276 - compiler-errors:typeof-less-eagerly, r=lcnr Do not compute type_of for impl item if impl where clauses are unsatisfied Consider the following code: ```rust trait Foo { fn call(self) -> impl Send; } trait Nested {} impl<T> Foo for T where T: Nested, { fn call(self) -> impl Sized { NotSatisfied.call() } } struct NotSatisfied; impl Foo for NotSatisfied { fn call(self) -> impl Sized { todo!() } } ``` In `impl Foo for NotSatisfied`, we need to prove that the RPITIT is well formed. This requires proving the item bound `<NotSatisfied as Foo>::RPITIT: Send`. Normalizing `<NotSatisfied as Foo>::RPITIT: Send` assembles two impl candidates, via the `NotSatisfied` impl and the blanket `T` impl. We end up computing the `type_of` for the blanket impl even if `NotSatisfied: Nested` where clause does not hold. This type_of query ends up needing to prove that its own `impl Sized` RPIT satisfies `Send`, which ends up needing to compute the hidden type of the RPIT, which is equal to the return type of `NotSatisfied.call()`. That ends up in a query cycle, since we subsequently try normalizing that return type via the blanket impl again! In the old solver, we don't end up computing the `type_of` an impl candidate if its where clauses don't hold, since this select call would fail before confirming the projection candidate: https://github.com/rust-lang/rust/blob/d7ea436a02d5de4033fcf7fd4eb8ed965d0f574c/compiler/rustc_trait_selection/src/traits/project.rs#L882 This PR makes the new solver more consistent with the old solver by adding a call to `try_evaluate_added_goals` after regstering the impl predicates, which causes us to bail before computing the `type_of` for impls if the impl definitely doesn't apply. r? lcnr Fixes rust-lang/trait-system-refactor-initiative#185
2 parents 25cdf1f + 105d1dc commit a728176

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ where
194194
.map(|pred| goal.with(cx, pred));
195195
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
196196

197+
// Bail if the nested goals don't hold here. This is to avoid unnecessarily
198+
// computing the `type_of` query for associated types that never apply, as
199+
// this may result in query cycles in the case of RPITITs.
200+
// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/185>.
201+
ecx.try_evaluate_added_goals()?;
202+
197203
// Add GAT where clauses from the trait's definition.
198204
// FIXME: We don't need these, since these are the type's own WF obligations.
199205
ecx.add_goals(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
//@ edition: 2024
6+
7+
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/185>.
8+
// Avoid unnecessarily computing the RPITIT type of the first impl when checking the WF of the
9+
// second impl, since the first impl relies on the hidden type of the second impl.
10+
11+
use std::future::Future;
12+
13+
trait Handler {}
14+
15+
struct W<T>(T);
16+
17+
trait SendTarget {
18+
fn call(self) -> impl Future<Output = ()> + Send;
19+
}
20+
21+
impl<T> SendTarget for W<T>
22+
where
23+
T: Handler + Send,
24+
{
25+
async fn call(self) {
26+
todo!()
27+
}
28+
}
29+
30+
impl<T> SendTarget for T
31+
where
32+
T: Handler + Send,
33+
{
34+
async fn call(self) {
35+
W(self).call().await
36+
}
37+
}
38+
39+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
//@ edition: 2024
6+
7+
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/185>.
8+
// Avoid unnecessarily computing the RPITIT type of the first impl when checking the WF of the
9+
// second impl, since the first impl relies on the hidden type of the second impl.
10+
11+
trait Foo {
12+
fn call(self) -> impl Send;
13+
}
14+
15+
trait Nested {}
16+
impl<T> Foo for T
17+
where
18+
T: Nested,
19+
{
20+
fn call(self) -> impl Sized {
21+
NotSatisfied.call()
22+
}
23+
}
24+
25+
struct NotSatisfied;
26+
impl Foo for NotSatisfied {
27+
fn call(self) -> impl Sized {
28+
todo!()
29+
}
30+
}
31+
32+
fn main() {}

0 commit comments

Comments
 (0)