From 105d1dcefd9baa520e63830f557d9c472f50d4fd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 25 Apr 2025 00:55:28 +0000 Subject: [PATCH] Do not compute type_of for impl item if impl where clauses are unsatisfied --- .../src/solve/normalizes_to/mod.rs | 6 +++ .../in-trait/cycle-if-impl-doesnt-apply.rs | 39 +++++++++++++++++++ .../in-trait/cycle-if-impl-doesnt-apply.rs | 32 +++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 tests/ui/async-await/in-trait/cycle-if-impl-doesnt-apply.rs create mode 100644 tests/ui/impl-trait/in-trait/cycle-if-impl-doesnt-apply.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 119d197de134f..fa8cfbba7fcd0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -194,6 +194,12 @@ where .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); + // Bail if the nested goals don't hold here. This is to avoid unnecessarily + // computing the `type_of` query for associated types that never apply, as + // this may result in query cycles in the case of RPITITs. + // See . + ecx.try_evaluate_added_goals()?; + // Add GAT where clauses from the trait's definition. // FIXME: We don't need these, since these are the type's own WF obligations. ecx.add_goals( diff --git a/tests/ui/async-await/in-trait/cycle-if-impl-doesnt-apply.rs b/tests/ui/async-await/in-trait/cycle-if-impl-doesnt-apply.rs new file mode 100644 index 0000000000000..54992c986558c --- /dev/null +++ b/tests/ui/async-await/in-trait/cycle-if-impl-doesnt-apply.rs @@ -0,0 +1,39 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition: 2024 + +// Regression test for . +// Avoid unnecessarily computing the RPITIT type of the first impl when checking the WF of the +// second impl, since the first impl relies on the hidden type of the second impl. + +use std::future::Future; + +trait Handler {} + +struct W(T); + +trait SendTarget { + fn call(self) -> impl Future + Send; +} + +impl SendTarget for W +where + T: Handler + Send, +{ + async fn call(self) { + todo!() + } +} + +impl SendTarget for T +where + T: Handler + Send, +{ + async fn call(self) { + W(self).call().await + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/cycle-if-impl-doesnt-apply.rs b/tests/ui/impl-trait/in-trait/cycle-if-impl-doesnt-apply.rs new file mode 100644 index 0000000000000..72e08ed350426 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/cycle-if-impl-doesnt-apply.rs @@ -0,0 +1,32 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition: 2024 + +// Regression test for . +// Avoid unnecessarily computing the RPITIT type of the first impl when checking the WF of the +// second impl, since the first impl relies on the hidden type of the second impl. + +trait Foo { + fn call(self) -> impl Send; +} + +trait Nested {} +impl 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!() + } +} + +fn main() {}