drop global where-bounds before merging candidates
This commit is contained in:
parent
092a284ba0
commit
2c2c9df653
5 changed files with 93 additions and 6 deletions
|
@ -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)))
|
||||
|
|
|
@ -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,
|
||||
{}
|
||||
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
|
@ -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() {}
|
Loading…
Add table
Add a link
Reference in a new issue