Skip to content

Commit 6c92927

Browse files
committed
Intro a request to compute the requirement signature of a ProtocolDecl
Replaces the explicit call to computeRequirementSignature from validateDecl with a lazy getRequirementSignature. A side effect is that the generic params of a ProtocolDecl are no longer computed from validateDecl and must be computed lazily too.
1 parent 862432f commit 6c92927

File tree

7 files changed

+104
-47
lines changed

7 files changed

+104
-47
lines changed

include/swift/AST/Decl.h

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

40824082
friend class SuperclassDeclRequest;
40834083
friend class SuperclassTypeRequest;
4084+
friend class RequirementSignatureRequest;
40844085
friend class TypeChecker;
40854086

40864087
public:
@@ -4302,22 +4303,19 @@ class ProtocolDecl final : public NominalTypeDecl {
43024303
/// protocol. Requirements implied via any other protocol (e.g., inherited
43034304
/// protocols of the inherited protocols) are not mentioned. The conformance
43044305
/// requirements listed here become entries in the witness table.
4305-
ArrayRef<Requirement> getRequirementSignature() const {
4306-
assert(isRequirementSignatureComputed() &&
4307-
"getting requirement signature before computing it");
4308-
return llvm::makeArrayRef(RequirementSignature,
4309-
Bits.ProtocolDecl.NumRequirementsInSignature);
4310-
}
4306+
ArrayRef<Requirement> getRequirementSignature() const;
43114307

43124308
/// Has the requirement signature been computed yet?
43134309
bool isRequirementSignatureComputed() const {
43144310
return RequirementSignature != nullptr;
43154311
}
43164312

4317-
void computeRequirementSignature();
4318-
43194313
void setRequirementSignature(ArrayRef<Requirement> requirements);
43204314

4315+
private:
4316+
ArrayRef<Requirement> getCachedRequirementSignature() const;
4317+
4318+
public:
43214319
// Implement isa/cast/dyncast/etc.
43224320
static bool classof(const Decl *D) {
43234321
return D->getKind() == DeclKind::Protocol;

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/Decl.cpp

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

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

45844578
void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
4585-
assert(!RequirementSignature && "already computed requirement signature");
4579+
assert(!RequirementSignature && "requirement signature already set");
45864580
if (requirements.empty()) {
45874581
RequirementSignature = reinterpret_cast<Requirement *>(this + 1);
45884582
Bits.ProtocolDecl.NumRequirementsInSignature = 0;
@@ -4592,6 +4586,13 @@ void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
45924586
}
45934587
}
45944588

4589+
ArrayRef<Requirement> ProtocolDecl::getCachedRequirementSignature() const {
4590+
assert(RequirementSignature &&
4591+
"getting requirement signature before computing it");
4592+
return llvm::makeArrayRef(RequirementSignature,
4593+
Bits.ProtocolDecl.NumRequirementsInSignature);
4594+
}
4595+
45954596
void ProtocolDecl::computeKnownProtocolKind() const {
45964597
auto module = getModuleContext();
45974598
if (module != module->getASTContext().getStdlibModule() &&

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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/Sema/TypeCheckDecl.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,35 @@ IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
13841384
return false;
13851385
}
13861386

1387+
llvm::Expected<ArrayRef<Requirement>>
1388+
RequirementSignatureRequest::evaluate(Evaluator &evaluator, ProtocolDecl *proto) const {
1389+
GenericSignatureBuilder builder(proto->getASTContext());
1390+
1391+
// Add all of the generic parameters.
1392+
proto->createGenericParamsIfMissing();
1393+
for (auto gp : *proto->getGenericParams())
1394+
builder.addGenericParameter(gp);
1395+
1396+
// Add the conformance of 'self' to the protocol.
1397+
auto selfType =
1398+
proto->getSelfInterfaceType()->castTo<GenericTypeParamType>();
1399+
auto requirement =
1400+
Requirement(RequirementKind::Conformance, selfType,
1401+
proto->getDeclaredInterfaceType());
1402+
1403+
builder.addRequirement(
1404+
requirement,
1405+
GenericSignatureBuilder::RequirementSource::forRequirementSignature(
1406+
builder, selfType, proto),
1407+
nullptr);
1408+
1409+
auto reqSignature = std::move(builder).computeGenericSignature(
1410+
SourceLoc(),
1411+
/*allowConcreteGenericPArams=*/false,
1412+
/*allowBuilderToMove=*/false);
1413+
return reqSignature->getRequirements();
1414+
}
1415+
13871416
namespace {
13881417
/// How to generate the raw value for each element of an enum that doesn't
13891418
/// have one explicitly specified.
@@ -3014,6 +3043,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30143043

30153044
// Explicitly calculate this bit.
30163045
(void) PD->existentialTypeSupported(&TC);
3046+
3047+
// Explicity compute the requirement signature to detect errors.
3048+
(void) PD->getRequirementSignature();
30173049
}
30183050

30193051
void visitVarDecl(VarDecl *VD) {

0 commit comments

Comments
 (0)