Skip to content

Commit b30aa22

Browse files
committed
RequirementMachine: Split off RequirementSignatureRequestRQM from RequirementSignatureRequest
This is a refactoring needed to implement 'verify' mode. The RequirementMachine computes the requirement signature for an entire connected component of protocols at once, whereas the GenericSignatureBuilder only does one protocol at a time. Using the same request for both in 'verify' mode meant that we would only call the GSB for the first protocol in a connected component, and then the RequirementMachine would fill in the rest. To fix this, split it up into two requests. The original RequirementSignatureRequest calls into the GSB, and then kicks off a RequirementSignatureRequestRQM to get the requirement signature computed by the RequirementMachine (possibly cached, if this protocol is part of a connected component with more than one protocol in it).
1 parent ddecb54 commit b30aa22

File tree

5 files changed

+139
-102
lines changed

5 files changed

+139
-102
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4168,6 +4168,7 @@ class ProtocolDecl final : public NominalTypeDecl {
41684168
friend class StructuralRequirementsRequest;
41694169
friend class ProtocolDependenciesRequest;
41704170
friend class RequirementSignatureRequest;
4171+
friend class RequirementSignatureRequestRQM;
41714172
friend class ProtocolRequiresClassRequest;
41724173
friend class ExistentialConformsToSelfRequest;
41734174
friend class InheritedProtocolsRequest;

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,26 @@ class ProtocolDependenciesRequest :
406406
bool isCached() const { return true; }
407407
};
408408

409+
/// Compute the requirements that describe a protocol using the
410+
/// RequirementMachine.
411+
class RequirementSignatureRequestRQM :
412+
public SimpleRequest<RequirementSignatureRequestRQM,
413+
ArrayRef<Requirement>(ProtocolDecl *),
414+
RequestFlags::Cached> {
415+
public:
416+
using SimpleRequest::SimpleRequest;
417+
418+
private:
419+
friend SimpleRequest;
420+
421+
// Evaluation.
422+
ArrayRef<Requirement>
423+
evaluate(Evaluator &evaluator, ProtocolDecl *proto) const;
424+
425+
public:
426+
bool isCached() const { return true; }
427+
};
428+
409429
/// Compute the requirements that describe a protocol.
410430
class RequirementSignatureRequest :
411431
public SimpleRequest<RequirementSignatureRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ SWIFT_REQUEST(TypeChecker, StructuralRequirementsRequest,
225225
SWIFT_REQUEST(TypeChecker, ProtocolDependenciesRequest,
226226
ArrayRef<ProtocolDecl *>(ProtocolDecl *), Cached,
227227
HasNearestLocation)
228+
SWIFT_REQUEST(TypeChecker, RequirementSignatureRequestRQM,
229+
ArrayRef<Requirement>(ProtocolDecl *), Cached,
230+
NoLocationInfo)
228231
SWIFT_REQUEST(TypeChecker, RequirementSignatureRequest,
229232
ArrayRef<Requirement>(ProtocolDecl *), SeparatelyCached,
230233
NoLocationInfo)

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@
5454
using namespace swift;
5555
using llvm::DenseMap;
5656

57-
/// Define this to 1 to enable expensive assertions.
58-
#define SWIFT_GSB_EXPENSIVE_ASSERTIONS 0
57+
#define DEBUG_TYPE "Serialization"
58+
59+
STATISTIC(NumLazyRequirementSignaturesLoaded,
60+
"# of lazily-deserialized requirement signatures loaded");
61+
62+
#undef DEBUG_TYPE
5963

6064
namespace {
6165
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
@@ -8702,3 +8706,71 @@ InferredGenericSignatureRequest::evaluate(
87028706
allowConcreteGenericParams);
87038707
return GenericSignatureWithError(result, hadError);
87048708
}
8709+
8710+
ArrayRef<Requirement>
8711+
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
8712+
ProtocolDecl *proto) const {
8713+
ASTContext &ctx = proto->getASTContext();
8714+
8715+
// First check if we have a deserializable requirement signature.
8716+
if (proto->hasLazyRequirementSignature()) {
8717+
++NumLazyRequirementSignaturesLoaded;
8718+
// FIXME: (transitional) increment the redundant "always-on" counter.
8719+
if (ctx.Stats)
8720+
++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded;
8721+
8722+
auto contextData = static_cast<LazyProtocolData *>(
8723+
ctx.getOrCreateLazyContextData(proto, nullptr));
8724+
8725+
SmallVector<Requirement, 8> requirements;
8726+
contextData->loader->loadRequirementSignature(
8727+
proto, contextData->requirementSignatureData, requirements);
8728+
if (requirements.empty())
8729+
return None;
8730+
return ctx.AllocateCopy(requirements);
8731+
}
8732+
8733+
auto buildViaGSB = [&]() {
8734+
GenericSignatureBuilder builder(proto->getASTContext());
8735+
8736+
// Add all of the generic parameters.
8737+
for (auto gp : *proto->getGenericParams())
8738+
builder.addGenericParameter(gp);
8739+
8740+
// Add the conformance of 'self' to the protocol.
8741+
auto selfType =
8742+
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
8743+
auto requirement =
8744+
Requirement(RequirementKind::Conformance, selfType,
8745+
proto->getDeclaredInterfaceType());
8746+
8747+
builder.addRequirement(
8748+
requirement,
8749+
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
8750+
builder, selfType, proto),
8751+
nullptr);
8752+
8753+
auto reqSignature = std::move(builder).computeGenericSignature(
8754+
/*allowConcreteGenericParams=*/false,
8755+
/*requirementSignatureSelfProto=*/proto);
8756+
return reqSignature.getRequirements();
8757+
};
8758+
8759+
auto buildViaRQM = [&]() {
8760+
return evaluateOrDefault(
8761+
ctx.evaluator,
8762+
RequirementSignatureRequestRQM{const_cast<ProtocolDecl *>(proto)},
8763+
ArrayRef<Requirement>());
8764+
};
8765+
8766+
switch (ctx.LangOpts.RequirementMachineProtocolSignatures) {
8767+
case RequirementMachineMode::Disabled:
8768+
return buildViaGSB();
8769+
8770+
case RequirementMachineMode::Enabled:
8771+
return buildViaRQM();
8772+
8773+
case RequirementMachineMode::Verify:
8774+
abort();
8775+
}
8776+
}

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 41 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//
1919
//===----------------------------------------------------------------------===//
2020

21+
#include "RequirementMachine.h"
2122
#include "swift/AST/ASTContext.h"
2223
#include "swift/AST/Decl.h"
2324
#include "swift/AST/GenericSignature.h"
@@ -27,19 +28,9 @@
2728
#include "swift/Basic/Statistic.h"
2829
#include <vector>
2930

30-
#include "../GenericSignatureBuilder.h" // FIXME: This is temporary
31-
#include "RequirementMachine.h"
32-
3331
using namespace swift;
3432
using namespace rewriting;
3533

36-
#define DEBUG_TYPE "Serialization"
37-
38-
STATISTIC(NumLazyRequirementSignaturesLoaded,
39-
"# of lazily-deserialized requirement signatures loaded");
40-
41-
#undef DEBUG_TYPE
42-
4334
namespace {
4435

4536
/// Represents a set of types related by same-type requirements, and an
@@ -222,104 +213,54 @@ RequirementMachine::computeMinimalRequirements() {
222213
}
223214

224215
ArrayRef<Requirement>
225-
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
226-
ProtocolDecl *proto) const {
216+
RequirementSignatureRequestRQM::evaluate(Evaluator &evaluator,
217+
ProtocolDecl *proto) const {
227218
ASTContext &ctx = proto->getASTContext();
228219

229220
// First check if we have a deserializable requirement signature.
230-
if (proto->hasLazyRequirementSignature()) {
231-
++NumLazyRequirementSignaturesLoaded;
232-
// FIXME: (transitional) increment the redundant "always-on" counter.
233-
if (ctx.Stats)
234-
++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded;
235-
236-
auto contextData = static_cast<LazyProtocolData *>(
237-
ctx.getOrCreateLazyContextData(proto, nullptr));
238-
239-
SmallVector<Requirement, 8> requirements;
240-
contextData->loader->loadRequirementSignature(
241-
proto, contextData->requirementSignatureData, requirements);
242-
if (requirements.empty())
243-
return None;
244-
return ctx.AllocateCopy(requirements);
245-
}
221+
assert(!proto->hasLazyRequirementSignature() &&
222+
"Should be handled in RequirementSignatureRequest");
246223

247-
auto buildViaGSB = [&]() {
248-
GenericSignatureBuilder builder(proto->getASTContext());
249-
250-
// Add all of the generic parameters.
251-
for (auto gp : *proto->getGenericParams())
252-
builder.addGenericParameter(gp);
253-
254-
// Add the conformance of 'self' to the protocol.
255-
auto selfType =
256-
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
257-
auto requirement =
258-
Requirement(RequirementKind::Conformance, selfType,
259-
proto->getDeclaredInterfaceType());
260-
261-
builder.addRequirement(
262-
requirement,
263-
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
264-
builder, selfType, proto),
265-
nullptr);
266-
267-
auto reqSignature = std::move(builder).computeGenericSignature(
268-
/*allowConcreteGenericParams=*/false,
269-
/*requirementSignatureSelfProto=*/proto);
270-
return reqSignature.getRequirements();
271-
};
224+
// We build requirement signatures for all protocols in a strongly connected
225+
// component at the same time.
226+
auto *machine = ctx.getOrCreateRequirementMachine(proto);
227+
auto requirements = machine->computeMinimalRequirements();
272228

273-
auto buildViaRQM = [&]() {
274-
// We build requirement signatures for all protocols in a strongly connected
275-
// component at the same time.
276-
auto *machine = ctx.getOrCreateRequirementMachine(proto);
277-
auto requirements = machine->computeMinimalRequirements();
278-
279-
bool debug = machine->getDebugOptions().contains(DebugFlags::Minimization);
280-
281-
// The requirement signature for the actual protocol that the result
282-
// was kicked off with.
283-
ArrayRef<Requirement> result;
284-
285-
for (const auto &pair : requirements) {
286-
auto *otherProto = pair.first;
287-
const auto &reqs = pair.second;
288-
289-
// setRequirementSignature() doesn't take ownership of the memory, so
290-
// we have to make a copy of the std::vector temporary.
291-
ArrayRef<Requirement> reqsCopy = ctx.AllocateCopy(reqs);
292-
293-
// Don't call setRequirementSignature() on the original proto; the
294-
// request evaluator will do it for us.
295-
if (otherProto == proto)
296-
result = reqsCopy;
297-
else
298-
const_cast<ProtocolDecl *>(otherProto)->setRequirementSignature(reqsCopy);
299-
300-
// Dump the result if requested.
301-
if (debug) {
302-
llvm::dbgs() << "Protocol " << otherProto->getName() << ": ";
303-
304-
auto sig = GenericSignature::get(
305-
otherProto->getGenericSignature().getGenericParams(),
306-
reqsCopy);
307-
llvm::dbgs() << sig << "\n";
308-
}
309-
}
229+
bool debug = machine->getDebugOptions().contains(DebugFlags::Minimization);
310230

311-
// Return the result for the specific protocol this request was kicked off on.
312-
return result;
313-
};
231+
// The requirement signature for the actual protocol that the result
232+
// was kicked off with.
233+
ArrayRef<Requirement> result;
234+
235+
for (const auto &pair : requirements) {
236+
auto *otherProto = pair.first;
237+
const auto &reqs = pair.second;
238+
239+
// setRequirementSignature() doesn't take ownership of the memory, so
240+
// we have to make a copy of the std::vector temporary.
241+
ArrayRef<Requirement> reqsCopy = ctx.AllocateCopy(reqs);
314242

315-
switch (ctx.LangOpts.RequirementMachineProtocolSignatures) {
316-
case RequirementMachineMode::Disabled:
317-
return buildViaGSB();
243+
// Dump the result if requested.
244+
if (debug) {
245+
llvm::dbgs() << "Protocol " << otherProto->getName() << ": ";
318246

319-
case RequirementMachineMode::Enabled:
320-
return buildViaRQM();
247+
auto sig = GenericSignature::get(
248+
otherProto->getGenericSignature().getGenericParams(),
249+
reqsCopy);
250+
llvm::dbgs() << sig << "\n";
251+
}
321252

322-
case RequirementMachineMode::Verify:
323-
abort();
253+
// Don't call setRequirementSignature() on the original proto; the
254+
// request evaluator will do it for us.
255+
if (otherProto == proto)
256+
result = reqsCopy;
257+
else {
258+
ctx.evaluator.cacheOutput(
259+
RequirementSignatureRequestRQM{const_cast<ProtocolDecl *>(otherProto)},
260+
std::move(reqsCopy));
261+
}
324262
}
263+
264+
// Return the result for the specific protocol this request was kicked off on.
265+
return result;
325266
}

0 commit comments

Comments
 (0)