Skip to content

Commit 9b99d26

Browse files
authored
Merge pull request #7029 from huonw/protocol-self-signature
[AST] Introduce the notion of a protocol requirement signature.
2 parents efdc729 + a964b6a commit 9b99d26

File tree

6 files changed

+145
-6
lines changed

6 files changed

+145
-6
lines changed

include/swift/AST/ArchetypeBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ class RequirementSource {
8383
///
8484
/// These are dropped when building the GenericSignature.
8585
Inherited,
86+
87+
/// The requirement is the Self: Protocol requirement, when computing a
88+
/// protocol's requirement signature.
89+
ProtocolRequirementSignatureSelf,
8690
};
8791

8892
RequirementSource(Kind kind, SourceLoc loc) : StoredKind(kind), Loc(loc) { }

include/swift/AST/Decl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3575,6 +3575,15 @@ class ProtocolDecl : public NominalTypeDecl {
35753575
/// created yet.
35763576
void createGenericParamsIfMissing();
35773577

3578+
/// Retrieve the generic signature representing the requirements introduced by
3579+
/// this protocol.
3580+
///
3581+
/// These are the requirements like any inherited protocols and conformances
3582+
/// for associated types that are mentioned literally in this
3583+
/// decl. Requirements implied via inheritance are not mentioned, nor is the
3584+
/// conformance of Self to this protocol.
3585+
GenericSignature *getRequirementSignature();
3586+
35783587
// Implement isa/cast/dyncast/etc.
35793588
static bool classof(const Decl *D) {
35803589
return D->getKind() == DeclKind::Protocol;

lib/AST/ArchetypeBuilder.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ void RequirementSource::dump(llvm::raw_ostream &out,
6363
case Inherited:
6464
out << "inherited";
6565
break;
66+
67+
case ProtocolRequirementSignatureSelf:
68+
out << "protocol_requirement_signature_self";
69+
break;
6670
}
6771

6872
if (srcMgr && getLoc().isValid()) {
@@ -760,6 +764,7 @@ Type ArchetypeBuilder::PotentialArchetype::getTypeInContext(
760764
case RequirementSource::Explicit:
761765
case RequirementSource::Inferred:
762766
case RequirementSource::Protocol:
767+
case RequirementSource::ProtocolRequirementSignatureSelf:
763768
case RequirementSource::Redundant:
764769
Protos.push_back(conforms.first);
765770
break;
@@ -1009,8 +1014,14 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
10091014
if (!T->addConformance(Proto, /*updateExistingSource=*/true, Source, *this))
10101015
return false;
10111016

1012-
RequirementSource InnerSource(RequirementSource::Redundant, Source.getLoc());
1013-
1017+
// Conformances to inherit protocols are explicit in a protocol requirement
1018+
// signature, but inferred from this conformance otherwise.
1019+
auto InnerKind =
1020+
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
1021+
? RequirementSource::Explicit
1022+
: RequirementSource::Redundant;
1023+
RequirementSource InnerSource(InnerKind, Source.getLoc());
1024+
10141025
bool inserted = Visited.insert(Proto).second;
10151026
assert(inserted);
10161027
(void) inserted;
@@ -1031,10 +1042,15 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
10311042
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
10321043
// Add requirements placed directly on this associated type.
10331044
auto AssocPA = T->getNestedType(AssocType, *this);
1045+
// Requirements introduced by the main protocol are explicit in a protocol
1046+
// requirement signature, but inferred from this conformance otherwise.
1047+
auto Kind = Source.getKind() ==
1048+
RequirementSource::ProtocolRequirementSignatureSelf
1049+
? RequirementSource::Explicit
1050+
: RequirementSource::Protocol;
1051+
10341052
if (AssocPA != T) {
1035-
if (addAbstractTypeParamRequirements(AssocType, AssocPA,
1036-
RequirementSource::Protocol,
1037-
Visited))
1053+
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind, Visited))
10381054
return true;
10391055
}
10401056

@@ -2067,7 +2083,7 @@ void ArchetypeBuilder::dump(llvm::raw_ostream &out) {
20672083

20682084
void ArchetypeBuilder::addGenericSignature(GenericSignature *sig) {
20692085
if (!sig) return;
2070-
2086+
20712087
RequirementSource::Kind sourceKind = RequirementSource::Explicit;
20722088
for (auto param : sig->getGenericParams())
20732089
addGenericParameter(param);
@@ -2097,6 +2113,7 @@ static void collectRequirements(ArchetypeBuilder &builder,
20972113
case RequirementSource::Protocol:
20982114
case RequirementSource::Redundant:
20992115
case RequirementSource::Inherited:
2116+
case RequirementSource::ProtocolRequirementSignatureSelf:
21002117
// The requirement was redundant, drop it.
21012118
return;
21022119
}

lib/AST/Decl.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/AST/Decl.h"
1818
#include "swift/AST/AccessScope.h"
19+
#include "swift/AST/ArchetypeBuilder.h"
1920
#include "swift/AST/AST.h"
2021
#include "swift/AST/ASTContext.h"
2122
#include "swift/AST/ASTWalker.h"
@@ -2999,6 +3000,30 @@ void ProtocolDecl::createGenericParamsIfMissing() {
29993000
setGenericParams(createGenericParams(this));
30003001
}
30013002

3003+
GenericSignature *ProtocolDecl::getRequirementSignature() {
3004+
auto module = getParentModule();
3005+
3006+
auto genericSig = getGenericSignature();
3007+
// The signature should look like <Self where Self : ThisProtocol>, and we
3008+
// reuse the two parts of it because the parameter and the requirement are
3009+
// exactly what we need.
3010+
assert(genericSig->getGenericParams().size() == 1 &&
3011+
genericSig->getRequirements().size() == 1 &&
3012+
"getRequirementSignature with unexpected generic signature");
3013+
3014+
auto selfType = genericSig->getGenericParams()[0];
3015+
auto requirement = genericSig->getRequirements()[0];
3016+
3017+
RequirementSource source(RequirementSource::ProtocolRequirementSignatureSelf,
3018+
getLoc());
3019+
3020+
ArchetypeBuilder builder(getASTContext(), LookUpConformanceInModule(module));
3021+
builder.addGenericParameter(selfType);
3022+
builder.addRequirement(requirement, source);
3023+
3024+
return builder.getGenericSignature();
3025+
}
3026+
30023027
/// Returns the default witness for a requirement, or nullptr if there is
30033028
/// no default.
30043029
Witness ProtocolDecl::getDefaultWitness(ValueDecl *requirement) const {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4371,6 +4371,20 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
43714371
visit(Member);
43724372

43734373
TC.checkDeclAttributes(PD);
4374+
4375+
if (TC.Context.LangOpts.DebugGenericSignatures) {
4376+
auto requirementsSig = PD->getRequirementSignature();
4377+
4378+
llvm::errs() << "Protocol requirement signature:\n";
4379+
PD->dumpRef(llvm::errs());
4380+
llvm::errs() << "\n";
4381+
llvm::errs() << "Requirement signature: ";
4382+
requirementsSig->print(llvm::errs());
4383+
llvm::errs() << "\n";
4384+
llvm::errs() << "Canonical requirement signature: ";
4385+
requirementsSig->getCanonicalSignature()->print(llvm::errs());
4386+
llvm::errs() << "\n";
4387+
}
43744388
}
43754389

43764390
void visitVarDecl(VarDecl *VD) {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %target-typecheck-verify-swift -typecheck %s -verify
2+
// RUN: %target-typecheck-verify-swift -typecheck -debug-generic-signatures %s > %t.dump 2>&1
3+
// RUN: %FileCheck %s < %t.dump
4+
5+
// CHECK-LABEL: .P1@
6+
// CHECK-NEXT: Requirement signature: <Self>
7+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0>
8+
protocol P1 {}
9+
10+
// CHECK-LABEL: .P2@
11+
// CHECK-NEXT: Requirement signature: <Self>
12+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0>
13+
protocol P2 {}
14+
15+
// CHECK-LABEL: .P3@
16+
// CHECK-NEXT: Requirement signature: <Self>
17+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0>
18+
protocol P3 {}
19+
20+
// basic protocol
21+
// CHECK-LABEL: .Q1@
22+
// CHECK-NEXT: Requirement signature: <Self where Self.X : P1>
23+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.X : P1>
24+
protocol Q1 {
25+
associatedtype X: P1
26+
}
27+
28+
// inheritance
29+
// CHECK-LABEL: .Q2@
30+
// CHECK-NEXT: Requirement signature: <Self where Self : Q1>
31+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1>
32+
protocol Q2: Q1 {}
33+
34+
// inheritance without any new requirements
35+
// CHECK-LABEL: .Q3@
36+
// CHECK-NEXT: Requirement signature: <Self where Self : Q1>
37+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1>
38+
protocol Q3: Q1 {
39+
associatedtype X
40+
}
41+
42+
// inheritance adding a new conformance
43+
// CHECK-LABEL: .Q4@
44+
// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X : P2>
45+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X : P2>
46+
protocol Q4: Q1 {
47+
associatedtype X: P2
48+
}
49+
50+
// multiple inheritance
51+
// CHECK-LABEL: .Q5@
52+
// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4>
53+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4>
54+
protocol Q5: Q2, Q3, Q4 {}
55+
56+
// multiple inheritance without any new requirements
57+
// CHECK-LABEL: .Q6@
58+
// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4>
59+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4>
60+
protocol Q6: Q2, Q3, Q4 {
61+
associatedtype X: P1
62+
}
63+
64+
// multiple inheritance with a new conformance
65+
// CHECK-LABEL: .Q7@
66+
// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X : P3>
67+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X : P3>
68+
protocol Q7: Q2, Q3, Q4 {
69+
associatedtype X: P3
70+
}

0 commit comments

Comments
 (0)