Skip to content

Commit 0f26d02

Browse files
committed
AST: ProtocolConformanceRef can store a pack conformance
1 parent 6549e0e commit 0f26d02

File tree

5 files changed

+113
-33
lines changed

5 files changed

+113
-33
lines changed

include/swift/AST/PackConformance.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,16 @@ class alignas(1 << DeclAlignInBits) PackConformance final
7777
PackConformance *
7878
getAssociatedConformance(Type assocType, ProtocolDecl *protocol) const;
7979

80-
PackConformance *subst(SubstitutionMap subMap,
81-
SubstOptions options=None) const;
82-
83-
PackConformance *subst(TypeSubstitutionFn subs,
84-
LookupConformanceFn conformances,
85-
SubstOptions options=None) const;
80+
/// The ProtocolConformanceRef either stores a pack conformance, or
81+
/// it is invalid in the case of substitution failure.
82+
ProtocolConformanceRef subst(SubstitutionMap subMap,
83+
SubstOptions options=None) const;
84+
85+
/// The ProtocolConformanceRef either stores a pack conformance, or
86+
/// it is invalid in the case of substitution failure.
87+
ProtocolConformanceRef subst(TypeSubstitutionFn subs,
88+
LookupConformanceFn conformances,
89+
SubstOptions options=None) const;
8690

8791
SWIFT_DEBUG_DUMP;
8892
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace swift {
3333

3434
class BuiltinProtocolConformance;
3535
class ConcreteDeclRef;
36+
class PackConformance;
3637
class ProtocolConformance;
3738
enum class EffectKind : uint8_t;
3839

@@ -50,7 +51,9 @@ enum class EffectKind : uint8_t;
5051
/// ProtocolConformanceRef allows the efficient recovery of the protocol
5152
/// even when the conformance is abstract.
5253
class ProtocolConformanceRef {
53-
using UnionType = llvm::PointerUnion<ProtocolDecl*, ProtocolConformance*>;
54+
using UnionType = llvm::PointerUnion<ProtocolDecl *,
55+
ProtocolConformance *,
56+
PackConformance *>;
5457
UnionType Union;
5558

5659
explicit ProtocolConformanceRef(UnionType value) : Union(value) {}
@@ -68,6 +71,12 @@ class ProtocolConformanceRef {
6871
"cannot construct ProtocolConformanceRef with null");
6972
}
7073

74+
/// Create a pack protocol conformance reference.
75+
explicit ProtocolConformanceRef(PackConformance *conf) : Union(conf) {
76+
assert(conf != nullptr &&
77+
"cannot construct ProtocolConformanceRef with null");
78+
}
79+
7180
ProtocolConformanceRef(std::nullptr_t = nullptr)
7281
: Union((ProtocolDecl *)nullptr) {}
7382

@@ -98,6 +107,13 @@ class ProtocolConformanceRef {
98107
return Union.get<ProtocolConformance*>();
99108
}
100109

110+
bool isPack() const {
111+
return !isInvalid() && Union.is<PackConformance*>();
112+
}
113+
PackConformance *getPack() const {
114+
return Union.get<PackConformance*>();
115+
}
116+
101117
bool isAbstract() const {
102118
return !isInvalid() && Union.is<ProtocolDecl*>();
103119
}

lib/AST/ASTDumper.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3260,6 +3260,11 @@ static void dumpProtocolConformanceRec(
32603260
unsigned indent,
32613261
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited);
32623262

3263+
static void dumpPackConformanceRec(
3264+
const PackConformance *conformance, llvm::raw_ostream &out,
3265+
unsigned indent,
3266+
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited);
3267+
32633268
static void dumpProtocolConformanceRefRec(
32643269
const ProtocolConformanceRef conformance, llvm::raw_ostream &out,
32653270
unsigned indent,
@@ -3268,7 +3273,11 @@ static void dumpProtocolConformanceRefRec(
32683273
out.indent(indent) << "(invalid_conformance)";
32693274
} else if (conformance.isConcrete()) {
32703275
dumpProtocolConformanceRec(conformance.getConcrete(), out, indent, visited);
3276+
} else if (conformance.isPack()) {
3277+
dumpPackConformanceRec(conformance.getPack(), out, indent, visited);
32713278
} else {
3279+
assert(conformance.isAbstract());
3280+
32723281
out.indent(indent) << "(abstract_conformance protocol="
32733282
<< conformance.getAbstract()->getName();
32743283
PrintWithColorRAII(out, ParenthesisColor) << ')';
@@ -3509,7 +3518,6 @@ void ProtocolConformanceRef::dump(llvm::raw_ostream &out, unsigned indent,
35093518
void ProtocolConformanceRef::print(llvm::raw_ostream &out) const {
35103519
llvm::SmallPtrSet<const ProtocolConformance *, 8> visited;
35113520
dumpProtocolConformanceRefRec(*this, out, 0, visited);
3512-
35133521
}
35143522

35153523
void ProtocolConformance::dump() const {

lib/AST/PackConformance.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ PackConformance *PackConformance::getAssociatedConformance(
160160
return PackConformance::get(conformingType, protocol, packConformances);
161161
}
162162

163-
PackConformance *PackConformance::subst(SubstitutionMap subMap,
164-
SubstOptions options) const {
163+
ProtocolConformanceRef PackConformance::subst(SubstitutionMap subMap,
164+
SubstOptions options) const {
165165
return subst(QuerySubstitutionMap{subMap},
166166
LookUpConformanceInSubstitutionMap(subMap),
167167
options);
@@ -284,9 +284,9 @@ class PackExpander {
284284
ProtocolDecl *proto) -> ProtocolConformanceRef {
285285
auto substConformance = conformances(origType, substType, proto);
286286

287+
// If the substituted conformance is a pack, project the jth element.
287288
if (isRootedInTypeSequenceParameter(origType)) {
288-
// FIXME: get the corresponding pack conformance
289-
return ProtocolConformanceRef::forInvalid();
289+
return substConformance.getPack()->getPatternConformances()[j];
290290
}
291291

292292
return substConformance;
@@ -376,18 +376,19 @@ class PackConformanceExpander : public PackExpander<PackConformanceExpander> {
376376

377377
}
378378

379-
PackConformance *PackConformance::subst(TypeSubstitutionFn subs,
380-
LookupConformanceFn conformances,
381-
SubstOptions options) const {
379+
ProtocolConformanceRef PackConformance::subst(TypeSubstitutionFn subs,
380+
LookupConformanceFn conformances,
381+
SubstOptions options) const {
382382
PackConformanceExpander expander(subs, conformances, options,
383383
getPatternConformances());
384384
expander.expand(ConformingType);
385385

386386
auto &ctx = Protocol->getASTContext();
387387
auto *substConformingType = PackType::get(ctx, expander.substElements);
388388

389-
return PackConformance::get(substConformingType, Protocol,
390-
expander.substConformances);
389+
auto substConformance = PackConformance::get(substConformingType, Protocol,
390+
expander.substConformances);
391+
return ProtocolConformanceRef(substConformance);
391392
}
392393

393394
void swift::simple_display(llvm::raw_ostream &out, PackConformance *conformance) {

lib/AST/ProtocolConformanceRef.cpp

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "swift/AST/Availability.h"
2121
#include "swift/AST/Decl.h"
2222
#include "swift/AST/Module.h"
23+
#include "swift/AST/PackConformance.h"
24+
#include "swift/AST/ProtocolConformance.h"
2325
#include "swift/AST/TypeCheckRequests.h"
2426
#include "swift/AST/Types.h"
2527

@@ -44,6 +46,8 @@ ProtocolDecl *ProtocolConformanceRef::getRequirement() const {
4446

4547
if (isConcrete()) {
4648
return getConcrete()->getProtocol();
49+
} else if (isPack()) {
50+
return getPack()->getProtocol();
4751
} else {
4852
return getAbstract();
4953
}
@@ -67,11 +71,14 @@ ProtocolConformanceRef::subst(Type origType,
6771
if (isInvalid())
6872
return *this;
6973

70-
// If we have a concrete conformance, we need to substitute the
71-
// conformance to apply to the new type.
7274
if (isConcrete())
7375
return ProtocolConformanceRef(getConcrete()->subst(subs, conformances,
7476
options));
77+
if (isPack())
78+
return getPack()->subst(subs, conformances, options);
79+
80+
// Handle abstract conformances below:
81+
7582
// If the type is an opaque archetype, the conformance will remain abstract,
7683
// unless we're specifically substituting opaque types.
7784
if (auto origArchetype = origType->getAs<ArchetypeType>()) {
@@ -102,17 +109,26 @@ ProtocolConformanceRef::subst(Type origType,
102109
}
103110

104111
ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() const {
105-
if (!isConcrete())
106-
return *this;
112+
if (isConcrete()) {
113+
auto *concrete = getConcrete()->subst(
114+
[](SubstitutableType *type) -> Type {
115+
if (auto *archetypeType = type->getAs<ArchetypeType>())
116+
return archetypeType->getInterfaceType();
117+
return type;
118+
},
119+
MakeAbstractConformanceForGenericType());
120+
return ProtocolConformanceRef(concrete);
121+
} else if (isPack()) {
122+
return getPack()->subst(
123+
[](SubstitutableType *type) -> Type {
124+
if (auto *archetypeType = type->getAs<ArchetypeType>())
125+
return archetypeType->getInterfaceType();
126+
return type;
127+
},
128+
MakeAbstractConformanceForGenericType());
129+
}
107130

108-
auto *concrete = getConcrete()->subst(
109-
[](SubstitutableType *type) -> Type {
110-
if (auto *archetypeType = type->getAs<ArchetypeType>())
111-
return archetypeType->getInterfaceType();
112-
return type;
113-
},
114-
MakeAbstractConformanceForGenericType());
115-
return ProtocolConformanceRef(concrete);
131+
return *this;
116132
}
117133

118134
Type
@@ -171,6 +187,12 @@ ProtocolConformanceRef::getConditionalRequirements() const {
171187

172188
Type ProtocolConformanceRef::getAssociatedType(Type conformingType,
173189
Type assocType) const {
190+
if (isPack()) {
191+
auto *pack = getPack();
192+
assert(conformingType->isEqual(pack->getType()));
193+
return pack->getAssociatedType(assocType);
194+
}
195+
174196
assert(!isConcrete() || getConcrete()->getType()->isEqual(conformingType));
175197

176198
auto type = assocType->getCanonicalType();
@@ -200,6 +222,14 @@ ProtocolConformanceRef
200222
ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
201223
Type assocType,
202224
ProtocolDecl *protocol) const {
225+
// If this is a pack conformance, project the associated conformances.
226+
if (isPack()) {
227+
auto *pack = getPack();
228+
assert(conformingType->isEqual(pack->getType()));
229+
return ProtocolConformanceRef(
230+
pack->getAssociatedConformance(assocType, protocol));
231+
}
232+
203233
// If this is a concrete conformance, look up the associated conformance.
204234
if (isConcrete()) {
205235
auto conformance = getConcrete();
@@ -221,23 +251,33 @@ ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
221251
bool ProtocolConformanceRef::isCanonical() const {
222252
if (isAbstract() || isInvalid())
223253
return true;
254+
if (isPack())
255+
return getPack()->isCanonical();
224256
return getConcrete()->isCanonical();
257+
225258
}
226259

227260
ProtocolConformanceRef
228261
ProtocolConformanceRef::getCanonicalConformanceRef() const {
229262
if (isAbstract() || isInvalid())
230263
return *this;
264+
if (isPack())
265+
return ProtocolConformanceRef(getPack()->getCanonicalConformance());
231266
return ProtocolConformanceRef(getConcrete()->getCanonicalConformance());
232267
}
233268

234269
bool ProtocolConformanceRef::hasUnavailableConformance() const {
235-
if (isInvalid())
270+
if (isInvalid() || isAbstract())
236271
return false;
237272

238-
// Abstract conformances are never unavailable.
239-
if (!isConcrete())
273+
if (isPack()) {
274+
for (auto conformance : getPack()->getPatternConformances()) {
275+
if (conformance.hasUnavailableConformance())
276+
return true;
277+
}
278+
240279
return false;
280+
}
241281

242282
// Check whether this conformance is on an unavailable extension.
243283
auto concrete = getConcrete();
@@ -266,8 +306,17 @@ bool ProtocolConformanceRef::hasMissingConformance(ModuleDecl *module) const {
266306
bool ProtocolConformanceRef::forEachMissingConformance(
267307
ModuleDecl *module,
268308
llvm::function_ref<bool(BuiltinProtocolConformance *missing)> fn) const {
269-
if (!isConcrete())
309+
if (isInvalid() || isAbstract())
310+
return false;
311+
312+
if (isPack()) {
313+
for (auto conformance : getPack()->getPatternConformances()) {
314+
if (conformance.forEachMissingConformance(module, fn))
315+
return true;
316+
}
317+
270318
return false;
319+
}
271320

272321
// Is this a missing conformance?
273322
ProtocolConformance *concreteConf = getConcrete();
@@ -292,6 +341,8 @@ void swift::simple_display(llvm::raw_ostream &out, ProtocolConformanceRef confor
292341
simple_display(out, conformanceRef.getAbstract());
293342
} else if (conformanceRef.isConcrete()) {
294343
simple_display(out, conformanceRef.getConcrete());
344+
} else if (conformanceRef.isPack()) {
345+
simple_display(out, conformanceRef.getPack());
295346
}
296347
}
297348

0 commit comments

Comments
 (0)