Skip to content

Commit d55e2e4

Browse files
authored
Rollup merge of #137314 - lcnr:cycles-with-unknown-kind, r=compiler-errors
change definitely unproductive cycles to error builds on top of #136824 by adding a third variant to `PathKind` for paths which may change to be coinductive in the future but must not be so right now. Most notably, impl where-clauses of not yet coinductive traits. With this, we can change cycles which are definitely unproductive to a proper error. This fixes rust-lang/trait-system-refactor-initiative#114. This does not affect stable as we keep these cycles as ambiguous during coherence. r? ````````@compiler-errors```````` ````````@nikomatsakis````````
2 parents 0998d40 + 18809a2 commit d55e2e4

21 files changed

+285
-205
lines changed

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

+43-8
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,39 @@ where
271271
/// and will need to clearly document it in the rustc-dev-guide before
272272
/// stabilization.
273273
pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
274-
match (self.current_goal_kind, source) {
275-
(_, GoalSource::NormalizeGoal(step_kind)) => step_kind,
276-
(CurrentGoalKind::CoinductiveTrait, GoalSource::ImplWhereBound) => {
277-
PathKind::Coinductive
274+
match source {
275+
// We treat these goals as unknown for now. It is likely that most miscellaneous
276+
// nested goals will be converted to an inductive variant in the future.
277+
//
278+
// Having unknown cycles is always the safer option, as changing that to either
279+
// succeed or hard error is backwards compatible. If we incorrectly treat a cycle
280+
// as inductive even though it should not be, it may be unsound during coherence and
281+
// fixing it may cause inference breakage or introduce ambiguity.
282+
GoalSource::Misc => PathKind::Unknown,
283+
GoalSource::NormalizeGoal(path_kind) => path_kind,
284+
GoalSource::ImplWhereBound => {
285+
// We currently only consider a cycle coinductive if it steps
286+
// into a where-clause of a coinductive trait.
287+
//
288+
// We probably want to make all traits coinductive in the future,
289+
// so we treat cycles involving their where-clauses as ambiguous.
290+
if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind {
291+
PathKind::Coinductive
292+
} else {
293+
PathKind::Unknown
294+
}
278295
}
279-
_ => PathKind::Inductive,
296+
// Relating types is always unproductive. If we were to map proof trees to
297+
// corecursive functions as explained in #136824, relating types never
298+
// introduces a constructor which could cause the recursion to be guarded.
299+
GoalSource::TypeRelating => PathKind::Inductive,
300+
// Instantiating a higher ranked goal can never cause the recursion to be
301+
// guarded and is therefore unproductive.
302+
GoalSource::InstantiateHigherRanked => PathKind::Inductive,
303+
// These goal sources are likely unproductive and can be changed to
304+
// `PathKind::Inductive`. Keeping them as unknown until we're confident
305+
// about this and have an example where it is necessary.
306+
GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
280307
}
281308
}
282309

@@ -606,7 +633,7 @@ where
606633

607634
let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw(
608635
GoalEvaluationKind::Nested,
609-
GoalSource::Misc,
636+
GoalSource::TypeRelating,
610637
unconstrained_goal,
611638
)?;
612639
// Add the nested goals from normalization to our own nested goals.
@@ -683,7 +710,7 @@ where
683710
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
684711
goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(
685712
self,
686-
GoalSource::Misc,
713+
GoalSource::TypeRelating,
687714
goal.param_env,
688715
));
689716
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
@@ -939,7 +966,15 @@ where
939966
rhs: T,
940967
) -> Result<(), NoSolution> {
941968
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
942-
self.add_goals(GoalSource::Misc, goals);
969+
if cfg!(debug_assertions) {
970+
for g in goals.iter() {
971+
match g.predicate.kind().skip_binder() {
972+
ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {}
973+
p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
974+
}
975+
}
976+
}
977+
self.add_goals(GoalSource::TypeRelating, goals);
943978
Ok(())
944979
}
945980

compiler/rustc_next_trait_solver/src/solve/inspect/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
421421
self.add_goal(
422422
delegate,
423423
max_input_universe,
424-
GoalSource::Misc,
424+
GoalSource::TypeRelating,
425425
goal.with(delegate.cx(), goal.predicate),
426426
);
427427
}

compiler/rustc_next_trait_solver/src/solve/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,9 @@ where
313313
ty::AliasRelationDirection::Equate,
314314
),
315315
);
316-
self.add_goal(GoalSource::Misc, alias_relate_goal);
316+
// We normalize the self type to be able to relate it with
317+
// types from candidates.
318+
self.add_goal(GoalSource::TypeRelating, alias_relate_goal);
317319
self.try_evaluate_added_goals()?;
318320
Ok(self.resolve_vars_if_possible(normalized_term))
319321
} else {

compiler/rustc_next_trait_solver/src/solve/project_goals.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ where
2424
ty::AliasRelationDirection::Equate,
2525
),
2626
);
27-
self.add_goal(GoalSource::Misc, goal);
27+
// A projection goal holds if the alias is equal to the expected term.
28+
self.add_goal(GoalSource::TypeRelating, goal);
2829
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
2930
}
3031
}

compiler/rustc_next_trait_solver/src/solve/search_graph.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::convert::Infallible;
22
use std::marker::PhantomData;
33

4-
use rustc_type_ir::Interner;
54
use rustc_type_ir::search_graph::{self, PathKind};
6-
use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult};
5+
use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult};
6+
use rustc_type_ir::{Interner, TypingMode};
77

88
use super::inspect::ProofTreeBuilder;
99
use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints};
@@ -47,7 +47,24 @@ where
4747
) -> QueryResult<I> {
4848
match kind {
4949
PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
50-
PathKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)),
50+
PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)),
51+
// Even though we know these cycles to be unproductive, we still return
52+
// overflow during coherence. This is both as we are not 100% confident in
53+
// the implementation yet and any incorrect errors would be unsound there.
54+
// The affected cases are also fairly artificial and not necessarily desirable
55+
// so keeping this as ambiguity is fine for now.
56+
//
57+
// See `tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs` for an
58+
// example where this would matter. We likely should change these cycles to `NoSolution`
59+
// even in coherence once this is a bit more settled.
60+
PathKind::Inductive => match input.typing_mode {
61+
TypingMode::Coherence => {
62+
response_no_constraints(cx, input, Certainty::overflow(false))
63+
}
64+
TypingMode::Analysis { .. }
65+
| TypingMode::PostBorrowckAnalysis { .. }
66+
| TypingMode::PostAnalysis => Err(NoSolution),
67+
},
5168
}
5269
}
5370

@@ -57,12 +74,7 @@ where
5774
input: CanonicalInput<I>,
5875
result: QueryResult<I>,
5976
) -> bool {
60-
match kind {
61-
PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes) == result,
62-
PathKind::Inductive => {
63-
response_no_constraints(cx, input, Certainty::overflow(false)) == result
64-
}
65-
}
77+
Self::initial_provisional_result(cx, kind, input) == result
6678
}
6779

6880
fn on_stack_overflow(

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
440440
match (child_mode, nested_goal.source()) {
441441
(
442442
ChildMode::Trait(_) | ChildMode::Host(_),
443-
GoalSource::Misc | GoalSource::NormalizeGoal(_),
443+
GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
444444
) => {
445445
continue;
446446
}

0 commit comments

Comments
 (0)