Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RequirementMachine: Redo concrete contraction after splitting concrete equivalence classes #61199

Merged
merged 2 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/AST/RequirementMachine/Debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ enum class DebugFlags : unsigned {

/// Print conflicting rules.
ConflictingRules = (1<<18),

/// Print debug output from concrete equivalence class splitting during
/// minimization.
SplitConcreteEquivalenceClass = (1<<19),
};

using DebugOptions = OptionSet<DebugFlags>;
Expand Down
101 changes: 63 additions & 38 deletions lib/AST/RequirementMachine/RequirementMachineRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ static void splitConcreteEquivalenceClasses(
TypeArrayView<GenericTypeParamType> genericParams,
SmallVectorImpl<StructuralRequirement> &splitRequirements,
unsigned &attempt) {
bool debug = machine->getDebugOptions().contains(
DebugFlags::SplitConcreteEquivalenceClass);

unsigned maxAttempts =
ctx.LangOpts.RequirementMachineMaxSplitConcreteEquivClassAttempts;

Expand All @@ -172,6 +175,10 @@ static void splitConcreteEquivalenceClasses(

splitRequirements.clear();

if (debug) {
llvm::dbgs() << "\n# Splitting concrete equivalence classes:\n";
}

for (auto req : requirements) {
if (shouldSplitConcreteEquivalenceClass(req, proto, machine)) {
auto concreteType = machine->getConcreteType(
Expand All @@ -183,10 +190,24 @@ static void splitConcreteEquivalenceClasses(
req.getSecondType(), concreteType);
splitRequirements.push_back({firstReq, SourceLoc(), /*inferred=*/false});
splitRequirements.push_back({secondReq, SourceLoc(), /*inferred=*/false});

if (debug) {
llvm::dbgs() << "- First split: ";
firstReq.dump(llvm::dbgs());
llvm::dbgs() << "\n- Second split: ";
secondReq.dump(llvm::dbgs());
llvm::dbgs() << "\n";
}
continue;
}

splitRequirements.push_back({req, SourceLoc(), /*inferred=*/false});

if (debug) {
llvm::dbgs() << "- Not split: ";
req.dump(llvm::dbgs());
llvm::dbgs() << "\n";
}
}
}

Expand Down Expand Up @@ -299,20 +320,6 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator,
requirements.push_back(req);
for (auto req : proto->getTypeAliasRequirements())
requirements.push_back({req, SourceLoc(), /*inferred=*/false});

// Preprocess requirements to eliminate conformances on type parameters
// which are made concrete.
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
SmallVector<StructuralRequirement, 4> contractedRequirements;

bool debug = rewriteCtx.getDebugOptions()
.contains(DebugFlags::ConcreteContraction);

if (performConcreteContraction(requirements, contractedRequirements,
errors, debug)) {
std::swap(contractedRequirements, requirements);
}
}
}

if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
Expand All @@ -335,6 +342,24 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator,

unsigned attempt = 0;
for (;;) {
for (const auto *proto : component) {
auto &requirements = protos[proto];

// Preprocess requirements to eliminate conformances on type parameters
// which are made concrete.
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
SmallVector<StructuralRequirement, 4> contractedRequirements;

bool debug = rewriteCtx.getDebugOptions()
.contains(DebugFlags::ConcreteContraction);

if (performConcreteContraction(requirements, contractedRequirements,
errors, debug)) {
std::swap(contractedRequirements, requirements);
}
}
}

// Heap-allocate the requirement machine to save stack space.
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
rewriteCtx));
Expand Down Expand Up @@ -639,20 +664,20 @@ AbstractGenericSignatureRequest::evaluate(
llvm::dbgs() << "\n";
}

// Preprocess requirements to eliminate conformances on generic parameters
// which are made concrete.
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
SmallVector<StructuralRequirement, 4> contractedRequirements;
bool debug = rewriteCtx.getDebugOptions()
.contains(DebugFlags::ConcreteContraction);
if (performConcreteContraction(requirements, contractedRequirements,
errors, debug)) {
std::swap(contractedRequirements, requirements);
}
}

unsigned attempt = 0;
for (;;) {
// Preprocess requirements to eliminate conformances on generic parameters
// which are made concrete.
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
SmallVector<StructuralRequirement, 4> contractedRequirements;
bool debug = rewriteCtx.getDebugOptions()
.contains(DebugFlags::ConcreteContraction);
if (performConcreteContraction(requirements, contractedRequirements,
errors, debug)) {
std::swap(contractedRequirements, requirements);
}
}

// Heap-allocate the requirement machine to save stack space.
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
rewriteCtx));
Expand Down Expand Up @@ -834,20 +859,20 @@ InferredGenericSignatureRequest::evaluate(
llvm::dbgs() << "\n";
}

// Preprocess requirements to eliminate conformances on generic parameters
// which are made concrete.
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
SmallVector<StructuralRequirement, 4> contractedRequirements;
bool debug = rewriteCtx.getDebugOptions()
.contains(DebugFlags::ConcreteContraction);
if (performConcreteContraction(requirements, contractedRequirements,
errors, debug)) {
std::swap(contractedRequirements, requirements);
}
}

unsigned attempt = 0;
for (;;) {
// Preprocess requirements to eliminate conformances on generic parameters
// which are made concrete.
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
SmallVector<StructuralRequirement, 4> contractedRequirements;
bool debug = rewriteCtx.getDebugOptions()
.contains(DebugFlags::ConcreteContraction);
if (performConcreteContraction(requirements, contractedRequirements,
errors, debug)) {
std::swap(contractedRequirements, requirements);
}
}

// Heap-allocate the requirement machine to save stack space.
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
rewriteCtx));
Expand Down
1 change: 1 addition & 0 deletions lib/AST/RequirementMachine/RewriteContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ static DebugOptions parseDebugFlags(StringRef debugFlags) {
.Case("propagate-requirement-ids", DebugFlags::PropagateRequirementIDs)
.Case("timers", DebugFlags::Timers)
.Case("conflicting-rules", DebugFlags::ConflictingRules)
.Case("split-concrete-equiv-class", DebugFlags::SplitConcreteEquivalenceClass)
.Default(None);
if (!flag) {
llvm::errs() << "Unknown debug flag in -debug-requirement-machine "
Expand Down
15 changes: 15 additions & 0 deletions test/Generics/issue-61192.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %target-swift-frontend -typecheck -verify %s -debug-generic-signatures -warn-redundant-requirements 2>&1 | %FileCheck %s

struct C {}

protocol P {
associatedtype A
}

struct G<A>: P {}

struct Body<T: P> where T.A == C {
// CHECK-LABEL: .init(_:)@
// CHECK-NEXT: <T, U where T == G<C>, U : P, U.[P]A == C>
init<U: P>(_: U) where T == G<T.A>, U.A == T.A {}
}