drop global where-bounds before merging candidates

This commit is contained in:
lcnr 2025-04-14 12:43:16 +02:00
parent 092a284ba0
commit 2c2c9df653
5 changed files with 93 additions and 6 deletions

View file

@ -1238,10 +1238,11 @@ where
D: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "debug", skip(self, goal), ret)]
pub(super) fn merge_trait_candidates(
&mut self,
goal: Goal<I, TraitPredicate<I>>,
candidates: Vec<Candidate<I>>,
mut candidates: Vec<Candidate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
if let TypingMode::Coherence = self.typing_mode() {
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
@ -1323,13 +1324,16 @@ where
// If there are *only* global where bounds, then make sure to return that this
// is still reported as being proven-via the param-env so that rigid projections
// operate correctly.
// operate correctly. Otherwise, drop all global where-bounds before merging the
// remaining candidates.
let proven_via =
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
TraitGoalProvenVia::ParamEnv
} else {
candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_)));
TraitGoalProvenVia::Misc
};
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
if let Some(response) = self.try_merge_responses(&all_candidates) {
Ok((response, Some(proven_via)))

View file

@ -34,9 +34,17 @@ where
MultipleNested: Trait,
{}
// We ignore the trivially true global where-bounds when checking that this
// impl is well-formed, meaning that we depend on `MultipleNested: Trait` when
// recursively proving `MultipleCandidates: Trait`.
//
// These overflow errors will disappear once we treat these cycles as either
// productive or an error.
impl Trait for MultipleNested
//~^ ERROR overflow evaluating the requirement `MultipleNested: Trait`
where
MultipleCandidates: Trait,
//~^ ERROR overflow evaluating the requirement `MultipleCandidates: Trait`
DoesNotImpl: Trait,
{}

View file

@ -1,16 +1,29 @@
error[E0275]: overflow evaluating the requirement `MultipleNested: Trait`
--> $DIR/inductive-cycle-but-err.rs:43:16
|
LL | impl Trait for MultipleNested
| ^^^^^^^^^^^^^^
error[E0275]: overflow evaluating the requirement `MultipleCandidates: Trait`
--> $DIR/inductive-cycle-but-err.rs:46:25
|
LL | MultipleCandidates: Trait,
| ^^^^^
error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied
--> $DIR/inductive-cycle-but-err.rs:46:19
--> $DIR/inductive-cycle-but-err.rs:54:19
|
LL | impls_trait::<MultipleCandidates>();
| ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates`
|
= help: the trait `Trait` is implemented for `MultipleCandidates`
note: required by a bound in `impls_trait`
--> $DIR/inductive-cycle-but-err.rs:43:19
--> $DIR/inductive-cycle-but-err.rs:51:19
|
LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait`
error: aborting due to 1 previous error
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0275, E0277.
For more information about an error, try `rustc --explain E0275`.

View file

@ -0,0 +1,33 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-pass
// Regression test for trait-system-refactor-initiative#172.
//
// In this test the global where-bound simply constrains the
// object lifetime bound to 'static while the builtin impl
// ends up also emitting a `dyn Any: 'static` type outlives
// constraint. This previously resulted in ambiguity. We now
// always prefer the impl.
pub trait Any: 'static {}
pub trait Downcast<T>: Any
where
T: Any,
{
}
// elided object lifetime: `dyn Any + 'static`
impl dyn Any {
pub fn is<T>(&self)
where
T: Any,
// elaboration adds global where-clause `dyn Any + 'static: Any`
Self: Downcast<T>,
{
}
}
fn main() {}

View file

@ -0,0 +1,29 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-pass
// Regression test for trait-system-refactor-initiative#172.
//
// The next-generation trait solver previously simply tried
// to merge the global where-bounds with the impl candidates.
// This caused ambiguity in case the where-bound had stricter
// region requirements than the impl.
trait Trait {}
struct Foo<'a, 'b>(&'a (), &'b ());
impl<'a> Trait for Foo<'a, 'static> {}
fn impls_trait<T: Trait>() {}
fn foo()
where
Foo<'static, 'static>: Trait,
{
// impl requires `'1 to be 'static
// global where-bound requires both '0 and '1 to be 'static
//
// we always prefer the impl here.
impls_trait::<Foo<'_, '_>>();
}
fn main() {}