Only compute specializes query if (min)specialization is enabled in the crate of the specializing impl by compiler-errors · Pull Request #126139 · rust-lang/rust (original) (raw)

Fixes (after backport) #125197

What

#122791 makes it so that inductive cycles are no longer hard errors. That means that when we are testing, for example, whether these impls overlap:

impl PartialEq for AnyId { fn eq(&self, _: &Self) -> bool { todo!() } }

impl<T: Identifier> PartialEq for AnyId { fn eq(&self, _: &T) -> bool { todo!() } }

...given...

pub trait Identifier: Display + 'static {}

impl Identifier for T where T: PartialEq + Display + 'static {}

Then we try to see if the second impl holds given T = AnyId. That requires AnyId: Identifier, which requires that AnyId: PartialEq, which is satisfied by these two impl candidates... The PartialEq<T> impl is a cycle, and we used to winnow it when we used to treat inductive cycles as errors.

However, now that we don't winnow it, this means that we now try calling candidate_should_be_dropped_in_favor_of, which tries to check whether one of the impls specializes the other: the specializes query. In that query, we currently bail early if the impl is local.

However, in a foreign crate, we try to compute if the two impls specialize each other by doing trait solving. This may itself lead to the same situation where we call specializes, which will lead to a query cycle.

How does this fix the problem

We now record whether specialization is enabled in foreign crates, and extend this early-return behavior to foreign impls too. This means that we can only encounter these cycles if we truly have a specializing impl from a crate with specialization enabled.


r? @oli-obk or @lcnr