Skip to content

Commit 2c2c9df

Browse files
committed
drop global where-bounds before merging candidates
1 parent 092a284 commit 2c2c9df

File tree

5 files changed

+93
-6
lines changed

5 files changed

+93
-6
lines changed

Diff for: compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1238,10 +1238,11 @@ where
12381238
D: SolverDelegate<Interner = I>,
12391239
I: Interner,
12401240
{
1241+
#[instrument(level = "debug", skip(self, goal), ret)]
12411242
pub(super) fn merge_trait_candidates(
12421243
&mut self,
12431244
goal: Goal<I, TraitPredicate<I>>,
1244-
candidates: Vec<Candidate<I>>,
1245+
mut candidates: Vec<Candidate<I>>,
12451246
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
12461247
if let TypingMode::Coherence = self.typing_mode() {
12471248
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
@@ -1323,13 +1324,16 @@ where
13231324

13241325
// If there are *only* global where bounds, then make sure to return that this
13251326
// is still reported as being proven-via the param-env so that rigid projections
1326-
// operate correctly.
1327+
// operate correctly. Otherwise, drop all global where-bounds before merging the
1328+
// remaining candidates.
13271329
let proven_via =
13281330
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
13291331
TraitGoalProvenVia::ParamEnv
13301332
} else {
1333+
candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_)));
13311334
TraitGoalProvenVia::Misc
13321335
};
1336+
13331337
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
13341338
if let Some(response) = self.try_merge_responses(&all_candidates) {
13351339
Ok((response, Some(proven_via)))

Diff for: tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs

+8
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@ where
3434
MultipleNested: Trait,
3535
{}
3636

37+
// We ignore the trivially true global where-bounds when checking that this
38+
// impl is well-formed, meaning that we depend on `MultipleNested: Trait` when
39+
// recursively proving `MultipleCandidates: Trait`.
40+
//
41+
// These overflow errors will disappear once we treat these cycles as either
42+
// productive or an error.
3743
impl Trait for MultipleNested
44+
//~^ ERROR overflow evaluating the requirement `MultipleNested: Trait`
3845
where
3946
MultipleCandidates: Trait,
47+
//~^ ERROR overflow evaluating the requirement `MultipleCandidates: Trait`
4048
DoesNotImpl: Trait,
4149
{}
4250

Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
1+
error[E0275]: overflow evaluating the requirement `MultipleNested: Trait`
2+
--> $DIR/inductive-cycle-but-err.rs:43:16
3+
|
4+
LL | impl Trait for MultipleNested
5+
| ^^^^^^^^^^^^^^
6+
7+
error[E0275]: overflow evaluating the requirement `MultipleCandidates: Trait`
8+
--> $DIR/inductive-cycle-but-err.rs:46:25
9+
|
10+
LL | MultipleCandidates: Trait,
11+
| ^^^^^
12+
113
error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied
2-
--> $DIR/inductive-cycle-but-err.rs:46:19
14+
--> $DIR/inductive-cycle-but-err.rs:54:19
315
|
416
LL | impls_trait::<MultipleCandidates>();
517
| ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates`
618
|
719
= help: the trait `Trait` is implemented for `MultipleCandidates`
820
note: required by a bound in `impls_trait`
9-
--> $DIR/inductive-cycle-but-err.rs:43:19
21+
--> $DIR/inductive-cycle-but-err.rs:51:19
1022
|
1123
LL | fn impls_trait<T: Trait>() {}
1224
| ^^^^^ required by this bound in `impls_trait`
1325

14-
error: aborting due to 1 previous error
26+
error: aborting due to 3 previous errors
1527

16-
For more information about this error, try `rustc --explain E0277`.
28+
Some errors have detailed explanations: E0275, E0277.
29+
For more information about an error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
5+
6+
// Regression test for trait-system-refactor-initiative#172.
7+
//
8+
// In this test the global where-bound simply constrains the
9+
// object lifetime bound to 'static while the builtin impl
10+
// ends up also emitting a `dyn Any: 'static` type outlives
11+
// constraint. This previously resulted in ambiguity. We now
12+
// always prefer the impl.
13+
14+
pub trait Any: 'static {}
15+
16+
pub trait Downcast<T>: Any
17+
where
18+
T: Any,
19+
{
20+
}
21+
22+
// elided object lifetime: `dyn Any + 'static`
23+
impl dyn Any {
24+
pub fn is<T>(&self)
25+
where
26+
T: Any,
27+
// elaboration adds global where-clause `dyn Any + 'static: Any`
28+
Self: Downcast<T>,
29+
{
30+
}
31+
}
32+
33+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
5+
6+
// Regression test for trait-system-refactor-initiative#172.
7+
//
8+
// The next-generation trait solver previously simply tried
9+
// to merge the global where-bounds with the impl candidates.
10+
// This caused ambiguity in case the where-bound had stricter
11+
// region requirements than the impl.
12+
13+
trait Trait {}
14+
struct Foo<'a, 'b>(&'a (), &'b ());
15+
impl<'a> Trait for Foo<'a, 'static> {}
16+
17+
fn impls_trait<T: Trait>() {}
18+
fn foo()
19+
where
20+
Foo<'static, 'static>: Trait,
21+
{
22+
// impl requires `'1 to be 'static
23+
// global where-bound requires both '0 and '1 to be 'static
24+
//
25+
// we always prefer the impl here.
26+
impls_trait::<Foo<'_, '_>>();
27+
}
28+
29+
fn main() {}

0 commit comments

Comments
 (0)