Skip to content

The old solver doesn't record required depth on cache #159228

Description

@adwinwhite
#![recursion_limit = "8"]

// The field order matters 😂
struct Foo<T> {
    t: T,
    opt_t: Option<T>,
}

fn require_sync<T: Sync>() {}

fn main() {
    require_sync::<Foo<Foo<Foo<Foo<Foo<Foo<()>>>>>>>();
}

The above code compiles with the old solver, while it requires recursion_limit = "12" for the next solver.
To prove Foo^N: Sync, we have to prove constituent nested goals Foo^N-1: Sync and Option<Foo^N-1>: Sync.
If we require depth d to prove the former, the next solver requires the depth d + 1 for the later, because we goes down one depth from Option<Foo^N-1>: Sync to its constituent goal Foo^N-1: Sync, and we hit the cache with required depth d for this nested goal.
So, the total required depth for the root goal is proportional to N with slope 2.
But for the old solver, we check the recursion limit when we actually consider the obligation and don't record/lookup the required depth for its deeply nested goals.
Therefore, the total required depth for the root goal is proportional to N with slope 1 and the next-solver requires twice more recursion limits as N grows.

This affects wgpu = "25.0.2".

This is investigated and explained by @ShoyuVanilla. zulip discussion

It's planned to add a FCW for this. #159224

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.WG-trait-system-refactorThe Rustc Trait System Refactor Initiative (-Znext-solver)

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions