Skip to content

Commit 9c4c304

Browse files
authored
Merge pull request #24591 from xymus/req-sig-request
GSB: Lazy requirement signature
2 parents c2ecf6d + cfae7bb commit 9c4c304

17 files changed

+129
-112
lines changed

include/swift/AST/Decl.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4084,6 +4084,7 @@ class ProtocolDecl final : public NominalTypeDecl {
40844084

40854085
friend class SuperclassDeclRequest;
40864086
friend class SuperclassTypeRequest;
4087+
friend class RequirementSignatureRequest;
40874088
friend class TypeChecker;
40884089

40894090
public:
@@ -4305,22 +4306,22 @@ class ProtocolDecl final : public NominalTypeDecl {
43054306
/// protocol. Requirements implied via any other protocol (e.g., inherited
43064307
/// protocols of the inherited protocols) are not mentioned. The conformance
43074308
/// requirements listed here become entries in the witness table.
4308-
ArrayRef<Requirement> getRequirementSignature() const {
4309-
assert(isRequirementSignatureComputed() &&
4310-
"getting requirement signature before computing it");
4311-
return llvm::makeArrayRef(RequirementSignature,
4312-
Bits.ProtocolDecl.NumRequirementsInSignature);
4313-
}
4309+
ArrayRef<Requirement> getRequirementSignature() const;
4310+
4311+
/// Is the requirement signature currently being computed?
4312+
bool isComputingRequirementSignature() const;
43144313

43154314
/// Has the requirement signature been computed yet?
43164315
bool isRequirementSignatureComputed() const {
43174316
return RequirementSignature != nullptr;
43184317
}
43194318

4320-
void computeRequirementSignature();
4321-
43224319
void setRequirementSignature(ArrayRef<Requirement> requirements);
43234320

4321+
private:
4322+
ArrayRef<Requirement> getCachedRequirementSignature() const;
4323+
4324+
public:
43244325
// Implement isa/cast/dyncast/etc.
43254326
static bool classof(const Decl *D) {
43264327
return D->getKind() == DeclKind::Protocol;

include/swift/AST/Evaluator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ class Evaluator {
309309
/// caching.
310310
void clearCache() { cache.clear(); }
311311

312+
/// Is the given request, or an equivalent, currently being evaluated?
313+
template <typename Request>
314+
bool hasActiveRequest(const Request &request) const {
315+
return activeRequests.count(AnyRequest(request));
316+
}
317+
312318
private:
313319
template <typename Request>
314320
const AnyRequest &getCanonicalRequest(const Request &request) {

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ class GenericSignatureBuilder::RequirementSource final
10561056
WrittenRequirementLoc writtenReqLoc)
10571057
: kind(kind), storageKind(StorageKind::StoredType),
10581058
hasTrailingWrittenRequirementLoc(!writtenReqLoc.isNull()),
1059-
usesRequirementSignature(protocol->isRequirementSignatureComputed()),
1059+
usesRequirementSignature(!protocol->isComputingRequirementSignature()),
10601060
parent(parent) {
10611061
assert((static_cast<bool>(parent) != isRootKind(kind)) &&
10621062
"Root RequirementSource should not have parent (or vice versa)");

include/swift/AST/TypeCheckRequests.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,32 @@ class IsDynamicRequest :
243243
void cacheResult(bool value) const;
244244
};
245245

246+
/// Compute the requirements that describe a protocol.
247+
class RequirementSignatureRequest :
248+
public SimpleRequest<RequirementSignatureRequest,
249+
CacheKind::SeparatelyCached,
250+
ArrayRef<Requirement>,
251+
ProtocolDecl *> {
252+
public:
253+
using SimpleRequest::SimpleRequest;
254+
255+
private:
256+
friend SimpleRequest;
257+
258+
// Evaluation.
259+
llvm::Expected<ArrayRef<Requirement>> evaluate(Evaluator &evaluator, ProtocolDecl *proto) const;
260+
261+
public:
262+
// Cycle handling
263+
void diagnoseCycle(DiagnosticEngine &diags) const;
264+
void noteCycleStep(DiagnosticEngine &diags) const;
265+
266+
// Separate caching.
267+
bool isCached() const { return true; }
268+
Optional<ArrayRef<Requirement>> getCachedResult() const;
269+
void cacheResult(ArrayRef<Requirement> value) const;
270+
};
271+
246272
/// Describes the owner of a where clause, from which we can extract
247273
/// requirements.
248274
struct WhereClauseOwner {

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ SWIFT_TYPEID(IsObjCRequest)
2222
SWIFT_TYPEID(IsFinalRequest)
2323
SWIFT_TYPEID(IsDynamicRequest)
2424
SWIFT_TYPEID(RequirementRequest)
25+
SWIFT_TYPEID(RequirementSignatureRequest)
2526
SWIFT_TYPEID(USRGenerationRequest)
2627
SWIFT_TYPEID(StructuralTypeRequest)
2728
SWIFT_TYPEID(DefaultTypeRequest)

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,6 @@ bestRequirementPrintLocation(ProtocolDecl *proto, const Requirement &req) {
12691269

12701270
void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto,
12711271
Decl *attachingTo) {
1272-
assert(proto->isRequirementSignatureComputed());
12731272
printGenericSignature(
12741273
GenericSignature::get({proto->getProtocolSelfType()} ,
12751274
proto->getRequirementSignature()),
@@ -1282,7 +1281,6 @@ void PrintAST::printInheritedFromRequirementSignature(ProtocolDecl *proto,
12821281

12831282
void PrintAST::printWhereClauseFromRequirementSignature(ProtocolDecl *proto,
12841283
Decl *attachingTo) {
1285-
assert(proto->isRequirementSignatureComputed());
12861284
unsigned flags = PrintRequirements;
12871285
if (isa<AssociatedTypeDecl>(attachingTo))
12881286
flags |= SwapSelfAndDependentMemberType;
@@ -2316,11 +2314,7 @@ void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
23162314
});
23172315

23182316
auto proto = decl->getProtocol();
2319-
if (proto->isRequirementSignatureComputed()) {
2320-
printInheritedFromRequirementSignature(proto, decl);
2321-
} else {
2322-
printInherited(decl);
2323-
}
2317+
printInheritedFromRequirementSignature(proto, decl);
23242318

23252319
if (decl->hasDefaultDefinitionType()) {
23262320
Printer << " = ";
@@ -2329,13 +2323,7 @@ void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
23292323

23302324
// As with protocol's trailing where clauses, use the requirement signature
23312325
// when available.
2332-
if (proto->isRequirementSignatureComputed()) {
2333-
printWhereClauseFromRequirementSignature(proto, decl);
2334-
} else {
2335-
if (auto trailingWhere = decl->getTrailingWhereClause()) {
2336-
printTrailingWhereClause(trailingWhere);
2337-
}
2338-
}
2326+
printWhereClauseFromRequirementSignature(proto, decl);
23392327
}
23402328

23412329
void PrintAST::visitEnumDecl(EnumDecl *decl) {
@@ -2442,23 +2430,13 @@ void PrintAST::visitProtocolDecl(ProtocolDecl *decl) {
24422430
Printer.printName(decl->getName());
24432431
});
24442432

2445-
if (decl->isRequirementSignatureComputed()) {
2446-
printInheritedFromRequirementSignature(decl, decl);
2447-
} else {
2448-
printInherited(decl);
2449-
}
2433+
printInheritedFromRequirementSignature(decl, decl);
24502434

24512435
// The trailing where clause is a syntactic thing, which isn't serialized
24522436
// (etc.) and thus isn't available for printing things out of
24532437
// already-compiled SIL modules. The requirement signature is available in
24542438
// such cases, so let's go with that when we can.
2455-
if (decl->isRequirementSignatureComputed()) {
2456-
printWhereClauseFromRequirementSignature(decl, decl);
2457-
} else {
2458-
if (auto trailingWhere = decl->getTrailingWhereClause()) {
2459-
printTrailingWhereClause(trailingWhere);
2460-
}
2461-
}
2439+
printWhereClauseFromRequirementSignature(decl, decl);
24622440
}
24632441
if (Options.TypeDefinitions) {
24642442
printMembersOfDecl(decl, false, true,

lib/AST/Decl.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4569,20 +4569,19 @@ void ProtocolDecl::createGenericParamsIfMissing() {
45694569
setGenericParams(result);
45704570
}
45714571

4572-
void ProtocolDecl::computeRequirementSignature() {
4573-
assert(!RequirementSignature && "already computed requirement signature");
4572+
ArrayRef<Requirement> ProtocolDecl::getRequirementSignature() const {
4573+
return evaluateOrDefault(getASTContext().evaluator,
4574+
RequirementSignatureRequest { const_cast<ProtocolDecl *>(this) },
4575+
None);
4576+
}
45744577

4575-
// Compute and record the signature.
4576-
auto requirementSig =
4577-
GenericSignatureBuilder::computeRequirementSignature(this);
4578-
RequirementSignature = requirementSig->getRequirements().data();
4579-
assert(RequirementSignature != nullptr);
4580-
Bits.ProtocolDecl.NumRequirementsInSignature =
4581-
requirementSig->getRequirements().size();
4578+
bool ProtocolDecl::isComputingRequirementSignature() const {
4579+
return getASTContext().evaluator.hasActiveRequest(
4580+
RequirementSignatureRequest{const_cast<ProtocolDecl*>(this)});
45824581
}
45834582

45844583
void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
4585-
assert(!RequirementSignature && "already computed requirement signature");
4584+
assert(!RequirementSignature && "requirement signature already set");
45864585
if (requirements.empty()) {
45874586
RequirementSignature = reinterpret_cast<Requirement *>(this + 1);
45884587
Bits.ProtocolDecl.NumRequirementsInSignature = 0;
@@ -4592,6 +4591,13 @@ void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
45924591
}
45934592
}
45944593

4594+
ArrayRef<Requirement> ProtocolDecl::getCachedRequirementSignature() const {
4595+
assert(RequirementSignature &&
4596+
"getting requirement signature before computing it");
4597+
return llvm::makeArrayRef(RequirementSignature,
4598+
Bits.ProtocolDecl.NumRequirementsInSignature);
4599+
}
4600+
45954601
void ProtocolDecl::computeKnownProtocolKind() const {
45964602
auto module = getModuleContext();
45974603
if (module != module->getASTContext().getStdlibModule() &&

lib/AST/DeclContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ GenericTypeParamType *DeclContext::getProtocolSelfType() const {
9090

9191
GenericParamList *genericParams;
9292
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
93+
const_cast<ProtocolDecl*>(proto)->createGenericParamsIfMissing();
9394
genericParams = proto->getGenericParams();
9495
} else {
9596
genericParams = cast<ExtensionDecl>(this)->getGenericParams();

lib/AST/GenericSignature.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -771,11 +771,6 @@ static bool hasNonCanonicalSelfProtocolRequirement(
771771
// If we don't already have a requirement signature for this protocol,
772772
// build one now.
773773
auto inProto = source->getProtocolDecl();
774-
if (!inProto->isRequirementSignatureComputed()) {
775-
inProto->computeRequirementSignature();
776-
assert(inProto->isRequirementSignatureComputed() &&
777-
"couldn't compute requirement signature?");
778-
}
779774

780775
// Check whether the given requirement is in the requirement signature.
781776
if (!source->usesRequirementSignature &&
@@ -856,13 +851,9 @@ void GenericSignature::buildConformanceAccessPath(
856851

857852
// The generic signature builder we're using for this protocol
858853
// wasn't built from its own requirement signature, so we can't
859-
// trust it. Make sure we have a requirement signature, then build
860-
// a new generic signature builder.
854+
// trust it, build a new generic signature builder.
861855
// FIXME: It would be better if we could replace the canonical generic
862856
// signature builder with the rebuilt one.
863-
if (!requirementSignatureProto->isRequirementSignatureComputed())
864-
requirementSignatureProto->computeRequirementSignature();
865-
assert(requirementSignatureProto->isRequirementSignatureComputed());
866857

867858
replacementBuilder.emplace(getASTContext());
868859
replacementBuilder->addGenericSignature(

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4107,7 +4107,7 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
41074107
// Use the requirement signature to avoid rewalking the entire protocol. This
41084108
// cannot compute the requirement signature directly, because that may be
41094109
// infinitely recursive: this code is also used to construct it.
4110-
if (proto->isRequirementSignatureComputed()) {
4110+
if (!proto->isComputingRequirementSignature()) {
41114111
auto innerSource =
41124112
FloatingRequirementSource::viaProtocolRequirement(source, proto,
41134113
/*inferred=*/false);
@@ -7447,34 +7447,6 @@ GenericSignature *GenericSignatureBuilder::computeGenericSignature(
74477447
return sig;
74487448
}
74497449

7450-
GenericSignature *GenericSignatureBuilder::computeRequirementSignature(
7451-
ProtocolDecl *proto) {
7452-
GenericSignatureBuilder builder(proto->getASTContext());
7453-
7454-
// Add all of the generic parameters.
7455-
proto->createGenericParamsIfMissing();
7456-
for (auto gp : *proto->getGenericParams())
7457-
builder.addGenericParameter(gp);
7458-
7459-
// Add the conformance of 'self' to the protocol.
7460-
auto selfType =
7461-
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
7462-
auto requirement =
7463-
Requirement(RequirementKind::Conformance, selfType,
7464-
proto->getDeclaredInterfaceType());
7465-
7466-
builder.addRequirement(
7467-
requirement,
7468-
RequirementSource::forRequirementSignature(builder, selfType,
7469-
proto),
7470-
nullptr);
7471-
7472-
return std::move(builder).computeGenericSignature(
7473-
SourceLoc(),
7474-
/*allowConcreteGenericPArams=*/false,
7475-
/*allowBuilderToMove=*/false);
7476-
}
7477-
74787450
#pragma mark Generic signature verification
74797451

74807452
void GenericSignatureBuilder::verifyGenericSignature(ASTContext &context,

lib/AST/TypeCheckRequests.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,33 @@ void IsDynamicRequest::cacheResult(bool value) const {
284284
decl->setIsDynamic(value);
285285
}
286286

287+
//----------------------------------------------------------------------------//
288+
// RequirementSignatureRequest computation.
289+
//----------------------------------------------------------------------------//
290+
291+
void RequirementSignatureRequest::diagnoseCycle(DiagnosticEngine &diags) const {
292+
auto decl = std::get<0>(getStorage());
293+
diags.diagnose(decl, diag::circular_reference);
294+
}
295+
296+
void RequirementSignatureRequest::noteCycleStep(DiagnosticEngine &diags) const {
297+
auto decl = std::get<0>(getStorage());
298+
diags.diagnose(decl, diag::circular_reference_through);
299+
}
300+
301+
Optional<ArrayRef<Requirement>> RequirementSignatureRequest::getCachedResult() const {
302+
auto proto = std::get<0>(getStorage());
303+
if (proto->isRequirementSignatureComputed())
304+
return proto->getCachedRequirementSignature();
305+
306+
return None;
307+
}
308+
309+
void RequirementSignatureRequest::cacheResult(ArrayRef<Requirement> value) const {
310+
auto proto = std::get<0>(getStorage());
311+
proto->setRequirementSignature(value);
312+
}
313+
287314
//----------------------------------------------------------------------------//
288315
// Requirement computation.
289316
//----------------------------------------------------------------------------//

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4521,10 +4521,6 @@ namespace {
45214521
inheritedTypes);
45224522
result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes));
45234523

4524-
// Compute the requirement signature.
4525-
if (!result->isRequirementSignatureComputed())
4526-
result->computeRequirementSignature();
4527-
45284524
result->setMemberLoader(&Impl, 0);
45294525

45304526
// Add the protocol decl to ExternalDefinitions so that IRGen can emit
@@ -7878,9 +7874,6 @@ void ClangImporter::Implementation::finishNormalConformance(
78787874
PrettyStackTraceConformance trace(SwiftContext, "completing import of",
78797875
conformance);
78807876

7881-
if (!proto->isRequirementSignatureComputed())
7882-
proto->computeRequirementSignature();
7883-
78847877
finishTypeWitnesses(conformance);
78857878
finishInheritedConformances(conformance);
78867879
finishSignatureConformances(conformance);

0 commit comments

Comments
 (0)