Skip to content

Commit 9ccdd15

Browse files
committed
RequirementMachine: Add upper bound on number of attempts at splitting concrete equivalence classes
1 parent 4069434 commit 9ccdd15

File tree

4 files changed

+41
-4
lines changed

4 files changed

+41
-4
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,10 @@ namespace swift {
525525
/// algorithm.
526526
unsigned RequirementMachineMaxConcreteNesting = 30;
527527

528+
/// Maximum number of attempts to make when splitting concrete equivalence
529+
/// classes.
530+
unsigned RequirementMachineMaxSplitConcreteEquivClassAttempts = 2;
531+
528532
/// Enable the new experimental protocol requirement signature minimization
529533
/// algorithm.
530534
RequirementMachineMode RequirementMachineProtocolSignatures =

include/swift/Option/FrontendOptions.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,12 @@ def requirement_machine_max_concrete_nesting : Joined<["-"], "requirement-machin
355355
Flags<[FrontendOption, HelpHidden, DoesNotAffectIncrementalBuild]>,
356356
HelpText<"Set the maximum concrete type nesting depth before giving up">;
357357

358+
def requirement_machine_max_split_concrete_equiv_class_attempts : Joined<["-"], "requirement-machine-max-split-concrete-equiv-class-attempts=">,
359+
Flags<[FrontendOption, HelpHidden, DoesNotAffectIncrementalBuild]>,
360+
HelpText<"Set the maximum concrete number of attempts at splitting "
361+
"concrete equivalence classes before giving up. There should "
362+
"never be a reason to change this">;
363+
358364
def disable_requirement_machine_concrete_contraction : Flag<["-"], "disable-requirement-machine-concrete-contraction">,
359365
HelpText<"Disable preprocessing pass to eliminate conformance requirements "
360366
"on generic parameters which are made concrete">;

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,19 @@ static bool shouldSplitConcreteEquivalenceClasses(GenericSignature sig) {
275275
static void splitConcreteEquivalenceClasses(
276276
ASTContext &ctx,
277277
GenericSignature sig,
278-
SmallVectorImpl<StructuralRequirement> &requirements) {
278+
SmallVectorImpl<StructuralRequirement> &requirements,
279+
unsigned &attempt) {
280+
unsigned maxAttempts =
281+
ctx.LangOpts.RequirementMachineMaxSplitConcreteEquivClassAttempts;
282+
283+
++attempt;
284+
if (attempt >= maxAttempts) {
285+
llvm::errs() << "Splitting concrete equivalence classes did not "
286+
<< "reach fixed point after " << attempt << " attempts.\n";
287+
llvm::errs() << "Last result: " << sig << "\n";
288+
abort();
289+
}
290+
279291
requirements.clear();
280292

281293
for (auto req : sig.getRequirements()) {
@@ -428,6 +440,7 @@ AbstractGenericSignatureRequestRQM::evaluate(
428440
}
429441
}
430442

443+
unsigned attempt = 0;
431444
for (;;) {
432445
// Heap-allocate the requirement machine to save stack space.
433446
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
@@ -448,7 +461,7 @@ AbstractGenericSignatureRequestRQM::evaluate(
448461

449462
if (!errorFlags) {
450463
if (shouldSplitConcreteEquivalenceClasses(result)) {
451-
splitConcreteEquivalenceClasses(ctx, result, requirements);
464+
splitConcreteEquivalenceClasses(ctx, result, requirements, attempt);
452465
continue;
453466
}
454467

@@ -568,6 +581,7 @@ InferredGenericSignatureRequestRQM::evaluate(
568581
}
569582
}
570583

584+
unsigned attempt = 0;
571585
for (;;) {
572586
// Heap-allocate the requirement machine to save stack space.
573587
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
@@ -599,7 +613,8 @@ InferredGenericSignatureRequestRQM::evaluate(
599613
auto result = GenericSignature::get(genericParams, minimalRequirements);
600614
auto errorFlags = machine->getErrors();
601615

602-
if (ctx.LangOpts.RequirementMachineInferredSignatures ==
616+
if (attempt == 0 &&
617+
ctx.LangOpts.RequirementMachineInferredSignatures ==
603618
RequirementMachineMode::Enabled) {
604619
machine->System.computeRedundantRequirementDiagnostics(errors);
605620
diagnoseRequirementErrors(ctx, errors, allowConcreteGenericParams);
@@ -608,8 +623,9 @@ InferredGenericSignatureRequestRQM::evaluate(
608623
// FIXME: Handle allowConcreteGenericParams
609624

610625
if (!errorFlags) {
626+
// Check if we need to rebuild the signature.
611627
if (shouldSplitConcreteEquivalenceClasses(result)) {
612-
splitConcreteEquivalenceClasses(ctx, result, requirements);
628+
splitConcreteEquivalenceClasses(ctx, result, requirements, attempt);
613629
continue;
614630
}
615631

lib/Frontend/CompilerInvocation.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,17 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
998998
}
999999
}
10001000

1001+
if (const Arg *A = Args.getLastArg(OPT_requirement_machine_max_split_concrete_equiv_class_attempts)) {
1002+
unsigned limit;
1003+
if (StringRef(A->getValue()).getAsInteger(10, limit)) {
1004+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
1005+
A->getAsString(Args), A->getValue());
1006+
HadError = true;
1007+
} else {
1008+
Opts.RequirementMachineMaxSplitConcreteEquivClassAttempts = limit;
1009+
}
1010+
}
1011+
10011012
if (Args.hasArg(OPT_disable_requirement_machine_concrete_contraction))
10021013
Opts.EnableRequirementMachineConcreteContraction = false;
10031014

0 commit comments

Comments
 (0)