Skip to content

Commit 51da51d

Browse files
committed
[AST] Use the requirement signature in the ArchetypeBuilder.
The requirement signature is far more compact than looking at all the members.
1 parent 74091fb commit 51da51d

File tree

5 files changed

+99
-58
lines changed

5 files changed

+99
-58
lines changed

include/swift/AST/ArchetypeBuilder.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ class ArchetypeBuilder {
171171

172172
/// \brief Add a new same-type requirement specifying that the given potential
173173
/// archetypes should map to the equivalent archetype.
174-
bool addSameTypeRequirement(Type T1, Type T2, RequirementSource Source);
174+
bool addSameTypeRequirement(Type T1, Type T2, RequirementSource Source,
175+
PotentialArchetype *basePA = nullptr);
175176

176177
/// Add the requirements placed on the given abstract type parameter
177178
/// to the given potential archetype.
@@ -248,6 +249,10 @@ class ArchetypeBuilder {
248249
/// re-inject requirements from outer contexts.
249250
void addRequirement(const Requirement &req, RequirementSource source);
250251

252+
void addRequirement(const Requirement &req, RequirementSource source,
253+
PotentialArchetype *basePA,
254+
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
255+
251256
bool addLayoutRequirement(PotentialArchetype *PAT,
252257
LayoutConstraint Layout,
253258
RequirementSource Source);
@@ -310,7 +315,12 @@ class ArchetypeBuilder {
310315
/// signature are fully resolved).
311316
///
312317
/// For any type that cannot refer to an archetype, this routine returns null.
313-
PotentialArchetype *resolveArchetype(Type type);
318+
///
319+
/// A non-null \c basePA is used in place of the "true" potential archetype
320+
/// for a GenericTypeParamType, effectively performing a substitution like,
321+
/// e.g., Self = <some PA>.
322+
PotentialArchetype *resolveArchetype(Type type,
323+
PotentialArchetype *basePA = nullptr);
314324

315325
/// \brief Dump all of the requirements, both specified and inferred.
316326
LLVM_ATTRIBUTE_DEPRECATED(

include/swift/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3595,6 +3595,11 @@ class ProtocolDecl : public NominalTypeDecl {
35953595
return RequirementSignature;
35963596
}
35973597

3598+
/// Has the requirement signature been computed yet?
3599+
bool isRequirementSignatureComputed() const {
3600+
return RequirementSignature != nullptr;
3601+
}
3602+
35983603
void computeRequirementSignature();
35993604

36003605
void setRequirementSignature(GenericSignature *sig) {

lib/AST/ArchetypeBuilder.cpp

Lines changed: 77 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -938,8 +938,12 @@ LazyResolver *ArchetypeBuilder::getLazyResolver() const {
938938
return Context.getLazyResolver();
939939
}
940940

941-
auto ArchetypeBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
941+
auto ArchetypeBuilder::resolveArchetype(Type type, PotentialArchetype *basePA)
942+
-> PotentialArchetype * {
942943
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
944+
if (basePA)
945+
return basePA;
946+
943947
unsigned index = GenericParamKey(genericParam).findIndexIn(
944948
Impl->GenericParams);
945949
if (index < Impl->GenericParams.size())
@@ -949,7 +953,7 @@ auto ArchetypeBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
949953
}
950954

951955
if (auto dependentMember = type->getAs<DependentMemberType>()) {
952-
auto base = resolveArchetype(dependentMember->getBase());
956+
auto base = resolveArchetype(dependentMember->getBase(), basePA);
953957
if (!base)
954958
return nullptr;
955959

@@ -1010,52 +1014,66 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
10101014
if (!T->addConformance(Proto, /*updateExistingSource=*/true, Source, *this))
10111015
return false;
10121016

1013-
// Conformances to inherit protocols are explicit in a protocol requirement
1014-
// signature, but inferred from this conformance otherwise.
1015-
auto InnerKind =
1016-
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
1017-
? RequirementSource::Explicit
1018-
: RequirementSource::Redundant;
1019-
RequirementSource InnerSource(InnerKind, Source.getLoc());
1020-
10211017
bool inserted = Visited.insert(Proto).second;
10221018
assert(inserted);
10231019
(void) inserted;
10241020

1025-
// Add all of the inherited protocol requirements, recursively.
1026-
if (auto resolver = getLazyResolver())
1027-
resolver->resolveInheritedProtocols(Proto);
1028-
for (auto InheritedProto : Proto->getInheritedProtocols(getLazyResolver())) {
1029-
if (Visited.count(InheritedProto))
1030-
continue;
1031-
if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited))
1032-
return true;
1033-
}
1021+
// Requirements introduced by the main protocol are explicit in a protocol
1022+
// requirement signature, but inferred from this conformance otherwise.
1023+
auto Kind =
1024+
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
1025+
? RequirementSource::Explicit
1026+
: RequirementSource::Protocol;
10341027

1035-
// Add requirements for each of the associated types.
1036-
// FIXME: This should use the generic signature, not walk the members.
1037-
for (auto Member : Proto->getMembers()) {
1038-
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
1039-
// Add requirements placed directly on this associated type.
1040-
auto AssocPA = T->getNestedType(AssocType, *this);
1041-
// Requirements introduced by the main protocol are explicit in a protocol
1042-
// requirement signature, but inferred from this conformance otherwise.
1043-
auto Kind = Source.getKind() ==
1044-
RequirementSource::ProtocolRequirementSignatureSelf
1045-
? RequirementSource::Explicit
1046-
: RequirementSource::Protocol;
1047-
1048-
if (AssocPA != T) {
1049-
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind, Visited))
1050-
return true;
1051-
}
1028+
// Use the requirement signature to avoid rewalking the entire protocol. This
1029+
// cannot compute the requirement signature directly, because that may be
1030+
// infinitely recursive: this code is also used to construct it.
1031+
if (Proto->isRequirementSignatureComputed()) {
1032+
auto reqSig = Proto->getRequirementSignature();
10521033

1053-
continue;
1034+
for (auto req : reqSig->getRequirements()) {
1035+
RequirementSource InnerSource(Kind, Source.getLoc());
1036+
addRequirement(req, InnerSource, T, Visited);
1037+
}
1038+
} else {
1039+
// Conformances to inherit protocols are explicit in a protocol requirement
1040+
// signature, but inferred from this conformance otherwise.
1041+
auto InnerKind =
1042+
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
1043+
? RequirementSource::Explicit
1044+
: RequirementSource::Redundant;
1045+
RequirementSource InnerSource(InnerKind, Source.getLoc());
1046+
// Add all of the inherited protocol requirements, recursively.
1047+
if (auto resolver = getLazyResolver())
1048+
resolver->resolveInheritedProtocols(Proto);
1049+
1050+
for (auto InheritedProto :
1051+
Proto->getInheritedProtocols(getLazyResolver())) {
1052+
if (Visited.count(InheritedProto))
1053+
continue;
1054+
if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited))
1055+
return true;
10541056
}
10551057

1056-
// FIXME: Requirement declarations.
1058+
// Add requirements for each of the associated types.
1059+
for (auto Member : Proto->getMembers()) {
1060+
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
1061+
// Add requirements placed directly on this associated type.
1062+
auto AssocPA = T->getNestedType(AssocType, *this);
1063+
1064+
if (AssocPA != T) {
1065+
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind,
1066+
Visited))
1067+
return true;
1068+
}
1069+
1070+
continue;
1071+
}
1072+
1073+
// FIXME: Requirement declarations.
1074+
}
10571075
}
1058-
1076+
10591077
Visited.erase(Proto);
10601078
return false;
10611079
}
@@ -1397,13 +1415,14 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete(
13971415

13981416
return false;
13991417
}
1400-
1418+
14011419
bool ArchetypeBuilder::addSameTypeRequirement(Type Reqt1, Type Reqt2,
1402-
RequirementSource Source) {
1420+
RequirementSource Source,
1421+
PotentialArchetype *basePA) {
14031422
// Find the potential archetypes.
1404-
PotentialArchetype *T1 = resolveArchetype(Reqt1);
1405-
PotentialArchetype *T2 = resolveArchetype(Reqt2);
1406-
1423+
PotentialArchetype *T1 = resolveArchetype(Reqt1, basePA);
1424+
PotentialArchetype *T2 = resolveArchetype(Reqt2, basePA);
1425+
14071426
// Require that at least one side of the requirement be a potential archetype.
14081427
if (!T1 && !T2) {
14091428
Diags.diagnose(Source.getLoc(), diag::requires_no_same_type_archetype);
@@ -1609,9 +1628,17 @@ bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) {
16091628

16101629
void ArchetypeBuilder::addRequirement(const Requirement &req,
16111630
RequirementSource source) {
1631+
llvm::SmallPtrSet<ProtocolDecl *, 8> Visited;
1632+
addRequirement(req, source, nullptr, Visited);
1633+
}
1634+
1635+
void ArchetypeBuilder::addRequirement(
1636+
const Requirement &req, RequirementSource source,
1637+
PotentialArchetype *basePA,
1638+
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
16121639
switch (req.getKind()) {
16131640
case RequirementKind::Superclass: {
1614-
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
1641+
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
16151642
if (!pa) return;
16161643

16171644
assert(req.getSecondType()->getClassOrBoundGenericClass());
@@ -1620,30 +1647,31 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
16201647
}
16211648

16221649
case RequirementKind::Layout: {
1623-
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
1650+
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
16241651
if (!pa) return;
16251652

16261653
(void)addLayoutRequirement(pa, req.getLayoutConstraint(), source);
16271654
return;
16281655
}
16291656

16301657
case RequirementKind::Conformance: {
1631-
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
1658+
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
16321659
if (!pa) return;
16331660

16341661
SmallVector<ProtocolDecl *, 4> conformsTo;
16351662
(void)req.getSecondType()->isExistentialType(conformsTo);
16361663

16371664
// Add each of the protocols.
16381665
for (auto proto : conformsTo) {
1639-
(void)addConformanceRequirement(pa, proto, source);
1666+
(void)addConformanceRequirement(pa, proto, source, Visited);
16401667
}
16411668

16421669
return;
16431670
}
16441671

16451672
case RequirementKind::SameType:
1646-
addSameTypeRequirement(req.getFirstType(), req.getSecondType(), source);
1673+
addSameTypeRequirement(req.getFirstType(), req.getSecondType(), source,
1674+
basePA);
16471675
return;
16481676
}
16491677

test/Generics/requirement_inference.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,23 +113,23 @@ struct Model_P3_P4_Eq<T : P3, U : P4> where T.P3Assoc == U.P4Assoc {}
113113
// CHECK-NEXT: Requirements:
114114
// CHECK-NEXT: τ_0_0 : P3 [inferred @ {{.*}}:32]
115115
// CHECK-NEXT: τ_0_1 : P4 [inferred @ {{.*}}:32]
116-
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [redundant @ {{.*}}:18]
117-
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:18]
116+
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}:32]
117+
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:32]
118118
func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
119119

120120
// CHECK-LABEL: .inferSameType2@
121121
// CHECK-NEXT: Requirements:
122122
// CHECK-NEXT: τ_0_0 : P3 [inferred]
123123
// CHECK-NEXT: τ_0_1 : P4 [inferred]
124-
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [redundant @ {{.*}}requirement_inference.swift:{{.*}}:18]
125-
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:18]
124+
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25]
125+
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25]
126126
// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [explicit]
127127
func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
128128

129129
// CHECK-LABEL: .inferSameType3@
130130
// CHECK-NEXT: Requirements:
131131
// CHECK-NEXT: τ_0_0 : PCommonAssoc1 [inferred]
132-
// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [inferred]
132+
// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:76]
133133
// CHECK-NEXT: τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:68]
134134
// CHECK-NEXT: Potential archetypes
135135
func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {}

test/Generics/superclass_constraint.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,13 @@ extension P2 where Self.T : C {
6767
// CHECK: Requirements:
6868
// CHECK-NEXT: τ_0_0 : C [explicit @
6969
// CHECK-NEXT: τ_0_0 : P3 [inherited @
70-
// CHECK-NEXT: τ_0_0[.P3].T == C.T [redundant]
7170
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
7271
func superclassConformance1<T>(t: T) where T : C, T : P3 {}
7372

7473
// CHECK: superclassConformance2
7574
// CHECK: Requirements:
7675
// CHECK-NEXT: τ_0_0 : C [explicit @
7776
// CHECK-NEXT: τ_0_0 : P3 [inherited @
78-
// CHECK-NEXT: τ_0_0[.P3].T == C.T [redundant]
7977
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
8078
func superclassConformance2<T>(t: T) where T : C, T : P3 {}
8179

0 commit comments

Comments
 (0)