Find cycles in rewrite constraints without performing the full exponential expansion of the RHS (#5673)

Make Subst perform "recursion" on the RHS instructions as they are
replaced, effectively doing a depth-first traversal through the rewrite
constraints doing replacements. This allows us to fully compute
individual associated constants in the minimal amount of work, and cache
the results so they can be reused cheaply in cases where the rewrite
constraints generate an exponential number of references to associated
constants.

Fixes https://github.com/carbon-language/carbon-lang/issues/5672
This commit is contained in:
Dana Jansens
2025-07-29 16:31:28 +00:00
committed by GitHub
parent 0bba03ce71
commit b36a987e73
8 changed files with 609 additions and 169 deletions
+8 -14
View File
@@ -640,8 +640,10 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
// GetConstantValueIgnoringPeriodSelf() which will update the phase
// accordingly.
info.rewrite_constraints = orig.rewrite_constraints;
ResolveFacetTypeRewriteConstraints(eval_context.context(), loc_id,
info.rewrite_constraints);
if (!ResolveFacetTypeRewriteConstraints(eval_context.context(), loc_id,
info.rewrite_constraints)) {
*phase = Phase::UnknownDueToError;
}
for (auto& rewrite : info.rewrite_constraints) {
// `where` requirements using `.Self` should not be considered symbolic.
@@ -1582,18 +1584,10 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context,
auto combined_info = SemIR::FacetTypeInfo::Combine(
context.facet_types().Get(lhs_facet_type_id),
context.facet_types().Get(rhs_facet_type_id));
// TODO: The instructions in the rewrite constraints have already been
// canonicalized before coming here, and it leads to incorrect diagnostics
// in resolve when assigning the same thing to an associated constant
// in both facet types being combined.
ResolveFacetTypeRewriteConstraints(eval_context.context(), loc_id,
combined_info.rewrite_constraints);
for (auto& rewrite : combined_info.rewrite_constraints) {
if (rewrite.lhs_id == SemIR::ErrorInst::InstId ||
rewrite.rhs_id == SemIR::ErrorInst::InstId) {
phase = Phase::UnknownDueToError;
break;
}
if (!ResolveFacetTypeRewriteConstraints(
eval_context.context(), loc_id,
combined_info.rewrite_constraints)) {
phase = Phase::UnknownDueToError;
}
combined_info.Canonicalize();
return MakeFacetTypeResult(eval_context.context(), combined_info, phase);