Skip to content

Commit 55069b6

Browse files
Don't assemble non-env/bound candidates if projection is rigid
1 parent 092a284 commit 55069b6

File tree

6 files changed

+91
-42
lines changed

6 files changed

+91
-42
lines changed

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

+39-20
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,10 @@ where
289289
D: SolverDelegate<Interner = I>,
290290
I: Interner,
291291
{
292-
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
292+
fn assemble_and_evaluate_candidates_with_normalized_goal<G: GoalKind<D>>(
293293
&mut self,
294294
goal: Goal<I, G>,
295+
assemble: impl FnOnce(&mut Self, Goal<I, G>) -> Vec<Candidate<I>>,
295296
) -> Vec<Candidate<I>> {
296297
let Ok(normalized_self_ty) =
297298
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
@@ -310,25 +311,40 @@ where
310311
// normalizing the self type as well, since type variables are not uniquified.
311312
let goal = self.resolve_vars_if_possible(goal);
312313

313-
let mut candidates = vec![];
314-
315314
if let TypingMode::Coherence = self.typing_mode() {
316315
if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
317316
return vec![candidate];
318317
}
319318
}
320319

321-
self.assemble_impl_candidates(goal, &mut candidates);
322-
323-
self.assemble_builtin_impl_candidates(goal, &mut candidates);
324-
325-
self.assemble_alias_bound_candidates(goal, &mut candidates);
326-
327-
self.assemble_object_bound_candidates(goal, &mut candidates);
320+
assemble(self, goal)
321+
}
328322

329-
self.assemble_param_env_candidates(goal, &mut candidates);
323+
pub(super) fn assemble_and_evaluate_candidates_from_env_and_bounds<G: GoalKind<D>>(
324+
&mut self,
325+
goal: Goal<I, G>,
326+
) -> Vec<Candidate<I>> {
327+
self.assemble_and_evaluate_candidates_with_normalized_goal(goal, |ecx, goal| {
328+
let mut candidates = vec![];
329+
ecx.assemble_alias_bound_candidates(goal, &mut candidates);
330+
ecx.assemble_param_env_candidates(goal, &mut candidates);
331+
candidates
332+
})
333+
}
330334

331-
candidates
335+
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
336+
&mut self,
337+
goal: Goal<I, G>,
338+
) -> Vec<Candidate<I>> {
339+
self.assemble_and_evaluate_candidates_with_normalized_goal(goal, |ecx, goal| {
340+
let mut candidates = vec![];
341+
ecx.assemble_impl_candidates(goal, &mut candidates);
342+
ecx.assemble_builtin_impl_candidates(goal, &mut candidates);
343+
ecx.assemble_alias_bound_candidates(goal, &mut candidates);
344+
ecx.assemble_object_bound_candidates(goal, &mut candidates);
345+
ecx.assemble_param_env_candidates(goal, &mut candidates);
346+
candidates
347+
})
332348
}
333349

334350
pub(super) fn forced_ambiguity(
@@ -778,10 +794,10 @@ where
778794
///
779795
/// See trait-system-refactor-initiative#124 for more details.
780796
#[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
781-
pub(super) fn merge_candidates(
797+
pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
782798
&mut self,
783799
proven_via: Option<TraitGoalProvenVia>,
784-
candidates: Vec<Candidate<I>>,
800+
goal: Goal<I, G>,
785801
inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
786802
) -> QueryResult<I> {
787803
let Some(proven_via) = proven_via else {
@@ -800,15 +816,16 @@ where
800816
// constness checking. Doing so is *at least theoretically* breaking,
801817
// see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
802818
TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
803-
let mut candidates_from_env_and_bounds: Vec<_> = candidates
804-
.iter()
805-
.filter(|c| {
806-
matches!(
819+
let mut candidates_from_env_and_bounds: Vec<_> = self
820+
.assemble_and_evaluate_candidates_from_env_and_bounds(goal)
821+
.into_iter()
822+
.map(|c| {
823+
debug_assert!(matches!(
807824
c.source,
808825
CandidateSource::AliasBound | CandidateSource::ParamEnv(_)
809-
)
826+
));
827+
c.result
810828
})
811-
.map(|c| c.result)
812829
.collect();
813830

814831
// If the trait goal has been proven by using the environment, we want to treat
@@ -826,6 +843,8 @@ where
826843
}
827844
}
828845
TraitGoalProvenVia::Misc => {
846+
let candidates = self.assemble_and_evaluate_candidates(goal);
847+
829848
// Prefer "orphaned" param-env normalization predicates, which are used
830849
// (for example, and ideally only) when proving item bounds for an impl.
831850
let candidates_from_env: Vec<_> = candidates

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,11 @@ where
399399
&mut self,
400400
goal: Goal<I, ty::HostEffectPredicate<I>>,
401401
) -> QueryResult<I> {
402-
let candidates = self.assemble_and_evaluate_candidates(goal);
403402
let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
404403
let trait_goal: Goal<I, ty::TraitPredicate<I>> =
405404
goal.with(ecx.cx(), goal.predicate.trait_ref);
406405
ecx.compute_trait_goal(trait_goal)
407406
})?;
408-
self.merge_candidates(proven_via, candidates, |_ecx| Err(NoSolution))
407+
self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
409408
}
410409
}

compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,13 @@ where
3232
let cx = self.cx();
3333
match goal.predicate.alias.kind(cx) {
3434
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
35-
let candidates = self.assemble_and_evaluate_candidates(goal);
3635
let trait_ref = goal.predicate.alias.trait_ref(cx);
3736
let (_, proven_via) =
3837
self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
3938
let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
4039
ecx.compute_trait_goal(trait_goal)
4140
})?;
42-
self.merge_candidates(proven_via, candidates, |ecx| {
41+
self.assemble_and_merge_candidates(proven_via, goal, |ecx| {
4342
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
4443
this.structurally_instantiate_normalizes_to_term(
4544
goal,

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ impl<'tcx> BestObligation<'tcx> {
269269
goal: &inspect::InspectGoal<'_, 'tcx>,
270270
self_ty: Ty<'tcx>,
271271
) -> ControlFlow<PredicateObligation<'tcx>> {
272-
assert!(!self.consider_ambiguities);
272+
//assert!(!self.consider_ambiguities);
273273
let tcx = goal.infcx().tcx;
274274
if let ty::Alias(..) = self_ty.kind() {
275275
let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);

tests/ui/impl-unused-tps.stderr

+17-17
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,6 @@ LL | impl<T> Foo<T> for [isize; 0] {
77
LL | impl<T, U> Foo<T> for U {
88
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
99

10-
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
11-
--> $DIR/impl-unused-tps.rs:32:9
12-
|
13-
LL | impl<T, U> Bar for T {
14-
| ^ unconstrained type parameter
15-
16-
error[E0119]: conflicting implementations of trait `Bar`
17-
--> $DIR/impl-unused-tps.rs:40:1
18-
|
19-
LL | impl<T, U> Bar for T {
20-
| -------------------- first implementation here
21-
...
22-
LL | / impl<T, U> Bar for T
23-
LL | | where
24-
LL | | T: Bar<Out = U>,
25-
| |____________________^ conflicting implementation
26-
2710
error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
2811
--> $DIR/impl-unused-tps.rs:49:1
2912
|
@@ -52,6 +35,12 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self
5235
LL | impl<T, U> Foo<T> for [isize; 1] {
5336
| ^ unconstrained type parameter
5437

38+
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
39+
--> $DIR/impl-unused-tps.rs:32:9
40+
|
41+
LL | impl<T, U> Bar for T {
42+
| ^ unconstrained type parameter
43+
5544
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
5645
--> $DIR/impl-unused-tps.rs:40:9
5746
|
@@ -70,6 +59,17 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self
7059
LL | impl<T, U, V> Foo<T> for T
7160
| ^ unconstrained type parameter
7261

62+
error[E0119]: conflicting implementations of trait `Bar`
63+
--> $DIR/impl-unused-tps.rs:40:1
64+
|
65+
LL | impl<T, U> Bar for T {
66+
| -------------------- first implementation here
67+
...
68+
LL | / impl<T, U> Bar for T
69+
LL | | where
70+
LL | | T: Bar<Out = U>,
71+
| |____________________^ conflicting implementation
72+
7373
error: aborting due to 9 previous errors
7474

7575
Some errors have detailed explanations: E0119, E0207.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ compile-flags: -Znext-solver
2+
//@ check-pass
3+
//@ edition: 2024
4+
5+
// Ensure we don't end up in a query cycle due to trying to assemble an impl candidate
6+
// for an RPITIT normalizes-to goal, even though that impl candidate would *necessarily*
7+
// be made rigid by a where clause. This query cycle is thus avoidable by not assembling
8+
// that impl candidate which we *know* we are going to throw away anyways.
9+
10+
use std::future::Future;
11+
12+
pub trait ReactiveFunction: Send {
13+
type Output;
14+
15+
fn invoke(self) -> Self::Output;
16+
}
17+
18+
trait AttributeValue {
19+
fn resolve(self) -> impl Future<Output = ()> + Send;
20+
}
21+
22+
impl<F, V> AttributeValue for F
23+
where
24+
F: ReactiveFunction<Output = V>,
25+
V: AttributeValue,
26+
{
27+
async fn resolve(self) {
28+
self.invoke().resolve().await
29+
}
30+
}
31+
32+
fn main() {}

0 commit comments

Comments
 (0)