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.