Skip to content

Do not compute type_of for impl item if impl where clauses are unsatisfied #140276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2025

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Apr 25, 2025

Consider the following code:

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:

let impl_source = match selcx.select(&trait_obligation) {

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

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Apr 25, 2025
@rust-log-analyzer

This comment has been minimized.

Copy link
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me on the fix. I think there's no good reason not to call try_evaluate_goals here.

I also feel like it sucks that we need to think about these cycles in the first place :< #139788

@lcnr
Copy link
Contributor

lcnr commented Apr 28, 2025

@bors r+ rollup

@bors
Copy link
Collaborator

bors commented Apr 28, 2025

📌 Commit 105d1dc has been approved by lcnr

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 28, 2025
ChrisDenton added a commit to ChrisDenton/rust that referenced this pull request Apr 28, 2025
…y, 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
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 28, 2025
…enton

Rollup of 9 pull requests

Successful merges:

 - rust-lang#139308 (add autodiff inline)
 - rust-lang#140276 (Do not compute type_of for impl item if impl where clauses are unsatisfied)
 - rust-lang#140302 (Move inline asm check to typeck, properly handle aliases)
 - rust-lang#140323 (Implement the internal feature `cfg_target_has_reliable_f16_f128`)
 - rust-lang#140374 (Resolve instance for SymFn in global/naked asm)
 - rust-lang#140391 (Rename sub_ptr to offset_from_unsigned in docs)
 - rust-lang#140394 (Make bootstrap git tests more self-contained)
 - rust-lang#140396 (Workaround for windows-gnu rust-lld test failure)
 - rust-lang#140402 (only return nested goals for `Certainty::Yes`)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 28, 2025
[DO NOT MERGE] bootstrap with `-Znext-solver=globally`

A revival of rust-lang#124812.

Current status:

~~`./x.py b --stage 2` passes 🎉~~

`try` builds succeed 🎉 🎉 🎉

~~[top 100 most downloaded crates on crates.io compile](rust-lang#133502 (comment)

[top 1000 most downloaded crates on crates.io compile](rust-lang#133502 (comment))

[first perf run](rust-lang#133502 (comment)) 👻

### in-flight changes

- rust-lang#124852, unsure whether I actually want to land this PR for now
- rust-lang#139587
- https://github.com/lcnr/rust/tree/opaque-type-method-call
- rust-lang#140302
- rust-lang#140276
- rust-lang#140260
- rust-lang#140405

r? `@ghost`
ChrisDenton added a commit to ChrisDenton/rust that referenced this pull request Apr 28, 2025
…y, 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
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 28, 2025
…enton

Rollup of 10 pull requests

Successful merges:

 - rust-lang#139308 (add autodiff inline)
 - rust-lang#139656 (Stabilize `slice_as_chunks` library feature)
 - rust-lang#140022 (allow deref patterns to move out of boxes)
 - rust-lang#140276 (Do not compute type_of for impl item if impl where clauses are unsatisfied)
 - rust-lang#140302 (Move inline asm check to typeck, properly handle aliases)
 - rust-lang#140323 (Implement the internal feature `cfg_target_has_reliable_f16_f128`)
 - rust-lang#140391 (Rename sub_ptr to offset_from_unsigned in docs)
 - rust-lang#140394 (Make bootstrap git tests more self-contained)
 - rust-lang#140396 (Workaround for windows-gnu rust-lld test failure)
 - rust-lang#140402 (only return nested goals for `Certainty::Yes`)

Failed merges:

 - rust-lang#139765 ([beta] Delay `hash_extract_if` stabilization from 1.87 to 1.88)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 29, 2025
…enton

Rollup of 10 pull requests

Successful merges:

 - rust-lang#139308 (add autodiff inline)
 - rust-lang#139656 (Stabilize `slice_as_chunks` library feature)
 - rust-lang#140022 (allow deref patterns to move out of boxes)
 - rust-lang#140276 (Do not compute type_of for impl item if impl where clauses are unsatisfied)
 - rust-lang#140302 (Move inline asm check to typeck, properly handle aliases)
 - rust-lang#140323 (Implement the internal feature `cfg_target_has_reliable_f16_f128`)
 - rust-lang#140391 (Rename sub_ptr to offset_from_unsigned in docs)
 - rust-lang#140394 (Make bootstrap git tests more self-contained)
 - rust-lang#140396 (Workaround for windows-gnu rust-lld test failure)
 - rust-lang#140402 (only return nested goals for `Certainty::Yes`)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 0bd531a into rust-lang:master Apr 29, 2025
@rustbot rustbot added this to the 1.88.0 milestone Apr 29, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Apr 29, 2025
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
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 29, 2025
[DO NOT MERGE] bootstrap with `-Znext-solver=globally`

A revival of rust-lang#124812.

Current status:

~~`./x.py b --stage 2` passes 🎉~~

`try` builds succeed 🎉 🎉 🎉

~~[top 100 most downloaded crates on crates.io compile](rust-lang#133502 (comment)

[top 1000 most downloaded crates on crates.io compile](rust-lang#133502 (comment))

[first perf run](rust-lang#133502 (comment)) 👻

### in-flight changes

- rust-lang#124852, unsure whether I actually want to land this PR for now
- rust-lang#139587
- https://github.com/lcnr/rust/tree/opaque-type-method-call
- rust-lang#140302
- rust-lang#140276
- rust-lang#140260
- rust-lang#140405

r? `@ghost`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

salvo_core regression: RPITIT type_of cycle
5 participants