Skip to content

-Znext-solver use the trait object's own bounds instead of goal when considering builtin object bounds#152859

Open
ShoyuVanilla wants to merge 2 commits intorust-lang:mainfrom
ShoyuVanilla:issue-152789
Open

-Znext-solver use the trait object's own bounds instead of goal when considering builtin object bounds#152859
ShoyuVanilla wants to merge 2 commits intorust-lang:mainfrom
ShoyuVanilla:issue-152789

Conversation

@ShoyuVanilla
Copy link
Member

@ShoyuVanilla ShoyuVanilla commented Feb 19, 2026

Fixes #152789 and fixes #151329

r? lcnr

@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 Feb 19, 2026
@ShoyuVanilla ShoyuVanilla force-pushed the issue-152789 branch 2 times, most recently from 4a25656 to 0f257f0 Compare February 19, 2026 16:57
@lcnr
Copy link
Contributor

lcnr commented Feb 27, 2026

hmm, thinking about this, given

pub trait Trait<T> {
    type Assoc;
}

pub trait Foo {
    type FooAssoc;
}

pub struct Wrap<U: Foo>(<dyn Trait<i32, Assoc = i64> as Trait<U::FooAssoc>>::Assoc)
where
    dyn Trait<i32, Assoc = i64>: Trait<U::FooAssoc>;

we're checking dyn Trait<i32, Assoc = i64>: Trait<U::FooAssoc> and try to do this via the builtin impl.

This builtin impl should be

impl Trait<i32> for dyn Trait<i32, Assoc = i64>
where
    i32: Sized,
    // we eagerly replace `<Self as Trait<i32>>::Assoc` with `i64` when
    // emitting the impl to avoid non-productive cycles.
    <Self as Trait<i32>>::Assoc: Sized,
{
    type Assoc = i64;
}

The builtin impl only applies here if U::FooAssoc is equal to i32. Generating the builtin impl should not actually care about the trait goal we're proving.

I think the bug is here

We should compute the where-clauses of the builtin impl using only the object type, not the goal we actually have to prove.

This builtin impl won't be applicable for U::FooAssoc because fn probe_and_match_goal_against_assumption will already reject the builtin candidate due to a type mismatch in the trait arguments.

@ShoyuVanilla ShoyuVanilla changed the title -Znext-solver Remove a problematic assertion from probing object bound candidates -Znext-solver se the trait object's own bounds instead of goal when considering builtin object bounds Feb 28, 2026
@ShoyuVanilla
Copy link
Member Author

That looks correct. I was being too narrow in my reasoning about the cause 😅

@rust-log-analyzer

This comment has been minimized.

@@ -83,14 +83,21 @@ where
assumption: I::Clause,
) -> Result<Candidate<I>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
ecx.try_evaluate_added_goals()?;
Copy link
Member Author

Choose a reason for hiding this comment

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

ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
then(ecx)

We equate the goal with the assumption before entering this closure in the above lines.
However, that eq relationship does not actually hold in the problematic cases from the linked issues.

Because this additional goal is introduced through that equality, the ICE still occurs even if we use the trait ref from the trait object (instead of the goal's trait ref) when calling predicates_for_object_candidate.
Those predicates are evaluated here, in projection_may_match:

I think short-circuiting candidates for which the equality cannot hold, before entering the remaining probing, would be harmless and prevent the ICE.

In fact, adding just that early check is enough to fix the ICE in the linked issues.
But I think using trait object's own bounds instead of goal's is correct, so changed the follwing lines as well.

@@ -425,7 +425,7 @@ where
}
}
ty::Dynamic(tt, ..) => {
let principal = tt.principal().map(|p| p.def_id());
let principal = tt.principal_def_id();
Copy link
Member Author

Choose a reason for hiding this comment

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

This change is irrelevant of the issue but seems trivial 😅

@ShoyuVanilla ShoyuVanilla changed the title -Znext-solver se the trait object's own bounds instead of goal when considering builtin object bounds -Znext-solver use the trait object's own bounds instead of goal when considering builtin object bounds Feb 28, 2026
@ShoyuVanilla
Copy link
Member Author

Hmm, the CI failure looks sus. Am I doing somewhat very incorrect thingy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

-Znext-solver: trait object candidate ICE "could not replace AliasTerm" [ICE]: could not replace AliasTerm (unsatisifed bounds)

4 participants