Skip to content

Commit 512ebc5

Browse files
authored
Merge pull request #41743 from CodaFi/existential-dread
2 parents cf05e61 + 0aead28 commit 512ebc5

32 files changed

+592
-86
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ Types
635635
type ::= protocol-list 'p' // existential type
636636
type ::= protocol-list superclass 'Xc' // existential type with superclass
637637
type ::= protocol-list 'Xl' // existential type with AnyObject
638+
type ::= protocol-list 'y' (type* '_')* type* retroactive-conformance* 'Xp' // parameterized protocol type
638639
type ::= type-list 't' // tuple
639640
type ::= type generic-signature 'u' // generic type
640641
type ::= 'x' // generic param, depth=0, idx=0

include/swift/AST/ASTDemangler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ class ASTBuilder {
112112
bool isClassBound,
113113
bool forRequirement = true);
114114

115+
Type createParameterizedProtocolType(Type base, ArrayRef<Type> args);
116+
115117
Type createExistentialMetatypeType(Type instance,
116118
Optional<Demangle::ImplMetatypeRepresentation> repr=None);
117119

include/swift/AST/Expr.h

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,10 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
297297
IsNonAccessing : 1
298298
);
299299

300-
SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32,
300+
SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32+20,
301301
: NumPadBits,
302-
NumConformances : 32
302+
NumConformances : 32,
303+
NumArgumentConversions : 20
303304
);
304305

305306
SWIFT_INLINE_BITFIELD_FULL(UnresolvedSpecializeExpr, Expr, 32,
@@ -3244,20 +3245,35 @@ class CollectionUpcastConversionExpr : public ImplicitConversionExpr {
32443245
/// "Appropriate kind" means e.g. a concrete/existential metatype if the
32453246
/// result is an existential metatype.
32463247
class ErasureExpr final : public ImplicitConversionExpr,
3247-
private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef> {
3248+
private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef,
3249+
CollectionUpcastConversionExpr::ConversionPair> {
32483250
friend TrailingObjects;
3251+
using ConversionPair = CollectionUpcastConversionExpr::ConversionPair;
32493252

32503253
ErasureExpr(Expr *subExpr, Type type,
3251-
ArrayRef<ProtocolConformanceRef> conformances)
3254+
ArrayRef<ProtocolConformanceRef> conformances,
3255+
ArrayRef<ConversionPair> argConversions)
32523256
: ImplicitConversionExpr(ExprKind::Erasure, subExpr, type) {
32533257
Bits.ErasureExpr.NumConformances = conformances.size();
32543258
std::uninitialized_copy(conformances.begin(), conformances.end(),
32553259
getTrailingObjects<ProtocolConformanceRef>());
3260+
3261+
Bits.ErasureExpr.NumArgumentConversions = argConversions.size();
3262+
std::uninitialized_copy(argConversions.begin(), argConversions.end(),
3263+
getTrailingObjects<ConversionPair>());
32563264
}
32573265

32583266
public:
32593267
static ErasureExpr *create(ASTContext &ctx, Expr *subExpr, Type type,
3260-
ArrayRef<ProtocolConformanceRef> conformances);
3268+
ArrayRef<ProtocolConformanceRef> conformances,
3269+
ArrayRef<ConversionPair> argConversions);
3270+
3271+
size_t numTrailingObjects(OverloadToken<ProtocolConformanceRef>) const {
3272+
return Bits.ErasureExpr.NumConformances;
3273+
}
3274+
size_t numTrailingObjects(OverloadToken<ConversionPair>) const {
3275+
return Bits.ErasureExpr.NumArgumentConversions;
3276+
}
32613277

32623278
/// Retrieve the mapping specifying how the type of the subexpression
32633279
/// maps to the resulting existential type. If the resulting existential
@@ -3274,6 +3290,30 @@ class ErasureExpr final : public ImplicitConversionExpr,
32743290
Bits.ErasureExpr.NumConformances };
32753291
}
32763292

3293+
/// Retrieve the conversion expressions mapping requirements from any
3294+
/// parameterized existentials involved in this erasure.
3295+
///
3296+
/// If the destination type is not a parameterized protocol type,
3297+
/// this array will be empty
3298+
ArrayRef<ConversionPair> getArgumentConversions() const {
3299+
return {getTrailingObjects<ConversionPair>(),
3300+
Bits.ErasureExpr.NumArgumentConversions };
3301+
}
3302+
3303+
/// Retrieve the conversion expressions mapping requirements from any
3304+
/// parameterized existentials involved in this erasure.
3305+
///
3306+
/// If the destination type is not a parameterized protocol type,
3307+
/// this array will be empty
3308+
MutableArrayRef<ConversionPair> getArgumentConversions() {
3309+
return {getTrailingObjects<ConversionPair>(),
3310+
Bits.ErasureExpr.NumArgumentConversions };
3311+
}
3312+
3313+
void setArgumentConversion(unsigned i, const ConversionPair &p) {
3314+
getArgumentConversions()[i] = p;
3315+
}
3316+
32773317
static bool classof(const Expr *E) {
32783318
return E->getKind() == ExprKind::Erasure;
32793319
}

include/swift/AST/Types.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6417,9 +6417,10 @@ inline bool TypeBase::isAnyExistentialType() {
64176417
}
64186418

64196419
inline bool CanType::isExistentialTypeImpl(CanType type) {
6420-
return (isa<ProtocolType>(type) ||
6421-
isa<ProtocolCompositionType>(type) ||
6422-
isa<ExistentialType>(type));
6420+
return isa<ProtocolType>(type) ||
6421+
isa<ProtocolCompositionType>(type) ||
6422+
isa<ExistentialType>(type) ||
6423+
isa<ParameterizedProtocolType>(type);
64236424
}
64246425

64256426
inline bool CanType::isAnyExistentialTypeImpl(CanType type) {
@@ -6515,6 +6516,8 @@ inline NominalTypeDecl *CanType::getNominalOrBoundGenericNominal() const {
65156516
return Ty->getDecl();
65166517
if (auto Ty = dyn_cast<ExistentialType>(*this))
65176518
return Ty->getConstraintType()->getNominalOrBoundGenericNominal();
6519+
if (auto Ty = dyn_cast<ParameterizedProtocolType>(*this))
6520+
return Ty->getBaseType()->getNominalOrBoundGenericNominal();
65186521
return nullptr;
65196522
}
65206523

@@ -6525,7 +6528,8 @@ inline NominalTypeDecl *TypeBase::getAnyNominal() {
65256528
inline Type TypeBase::getNominalParent() {
65266529
if (auto existential = getAs<ExistentialType>())
65276530
return existential->getConstraintType()->getNominalParent();
6528-
6531+
if (auto ppt = getAs<ParameterizedProtocolType>())
6532+
return ppt->getBaseType()->getNominalParent();
65296533
return castTo<AnyGenericType>()->getParent();
65306534
}
65316535

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ NODE(EscapingObjCBlock)
170170
CONTEXT_NODE(OtherNominalType)
171171
CONTEXT_NODE(OwningAddressor)
172172
CONTEXT_NODE(OwningMutableAddressor)
173+
NODE(ParameterizedProtocol)
173174
NODE(PartialApplyForwarder)
174175
NODE(PartialApplyObjCForwarder)
175176
NODE(PostfixOperator)

include/swift/Demangling/TypeDecoder.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,34 @@ class TypeDecoder {
710710
forRequirement);
711711
}
712712

713+
case NodeKind::ParameterizedProtocol: {
714+
if (Node->getNumChildren() < 2)
715+
return MAKE_NODE_TYPE_ERROR(Node,
716+
"fewer children (%zu) than required (2)",
717+
Node->getNumChildren());
718+
719+
auto protocolType = decodeMangledType(Node->getChild(0), depth + 1);
720+
if (protocolType.isError())
721+
return protocolType;
722+
723+
llvm::SmallVector<BuiltType, 8> args;
724+
725+
const auto &genericArgs = Node->getChild(1);
726+
if (genericArgs->getKind() != NodeKind::TypeList)
727+
return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList");
728+
729+
for (auto genericArg : *genericArgs) {
730+
auto paramType = decodeMangledType(genericArg, depth + 1,
731+
/*forRequirement=*/false);
732+
if (paramType.isError())
733+
return paramType;
734+
args.push_back(paramType.getType());
735+
}
736+
737+
return Builder.createParameterizedProtocolType(protocolType.getType(),
738+
args);
739+
}
740+
713741
case NodeKind::Protocol:
714742
case NodeKind::ProtocolSymbolicReference: {
715743
if (auto Proto = decodeMangledProtocolType(Node, depth + 1)) {

include/swift/Reflection/TypeRef.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,42 @@ class ProtocolCompositionTypeRef final : public TypeRef {
563563
}
564564
};
565565

566+
class ParameterizedProtocolTypeRef final : public TypeRef {
567+
const ProtocolCompositionTypeRef *Base;
568+
std::vector<const TypeRef *> Args;
569+
570+
static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol,
571+
std::vector<const TypeRef *> Args) {
572+
TypeRefID ID;
573+
ID.addPointer(Protocol);
574+
for (auto Arg : Args) {
575+
ID.addPointer(Arg);
576+
}
577+
return ID;
578+
}
579+
580+
public:
581+
ParameterizedProtocolTypeRef(const ProtocolCompositionTypeRef *Protocol,
582+
std::vector<const TypeRef *> Args)
583+
: TypeRef(TypeRefKind::ParameterizedProtocol), Base(Protocol),
584+
Args(Args) {}
585+
586+
template <typename Allocator>
587+
static const ParameterizedProtocolTypeRef *
588+
create(Allocator &A, const ProtocolCompositionTypeRef *Protocol,
589+
std::vector<const TypeRef *> Args) {
590+
FIND_OR_CREATE_TYPEREF(A, ParameterizedProtocolTypeRef, Protocol, Args);
591+
}
592+
593+
const ProtocolCompositionTypeRef *getBase() const { return Base; }
594+
595+
const std::vector<const TypeRef *> &getArgs() const { return Args; }
596+
597+
static bool classof(const TypeRef *TR) {
598+
return TR->getKind() == TypeRefKind::ParameterizedProtocol;
599+
}
600+
};
601+
566602
class MetatypeTypeRef final : public TypeRef {
567603
const TypeRef *InstanceType;
568604
bool WasAbstract;

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,15 @@ class TypeRefBuilder {
614614
isClassBound);
615615
}
616616

617+
const ParameterizedProtocolTypeRef *
618+
createParameterizedProtocolType(const TypeRef *base,
619+
llvm::ArrayRef<const TypeRef *> args) {
620+
auto *baseProto = llvm::dyn_cast<ProtocolCompositionTypeRef>(base);
621+
if (!baseProto)
622+
return nullptr;
623+
return ParameterizedProtocolTypeRef::create(*this, baseProto, args);
624+
}
625+
617626
const ExistentialMetatypeTypeRef *createExistentialMetatypeType(
618627
const TypeRef *instance,
619628
llvm::Optional<Demangle::ImplMetatypeRepresentation> repr = None) {

include/swift/Reflection/TypeRefs.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ TYPEREF(BoundGeneric, TypeRef)
2222
TYPEREF(Tuple, TypeRef)
2323
TYPEREF(Function, TypeRef)
2424
TYPEREF(ProtocolComposition, TypeRef)
25+
TYPEREF(ParameterizedProtocol, TypeRef)
2526
TYPEREF(Metatype, TypeRef)
2627
TYPEREF(ExistentialMetatype, TypeRef)
2728
TYPEREF(GenericTypeParameter, TypeRef)

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4444,7 +4444,8 @@ CanTypeWrapper<OpenedArchetypeType>
44444444
OpenedArchetypeType::get(CanType existential, GenericSignature parentSig,
44454445
Optional<UUID> knownID) {
44464446
assert(existential->isExistentialType());
4447-
auto interfaceType = OpenedArchetypeType::getSelfInterfaceTypeFromContext(parentSig, existential->getASTContext());
4447+
auto interfaceType = OpenedArchetypeType::getSelfInterfaceTypeFromContext(
4448+
parentSig, existential->getASTContext());
44484449
return get(existential, interfaceType, parentSig, knownID);
44494450
}
44504451

@@ -4510,7 +4511,8 @@ CanType OpenedArchetypeType::getAny(CanType existential, Type interfaceType,
45104511

45114512
CanType OpenedArchetypeType::getAny(CanType existential,
45124513
GenericSignature parentSig) {
4513-
auto interfaceTy = OpenedArchetypeType::getSelfInterfaceTypeFromContext(parentSig, existential->getASTContext());
4514+
auto interfaceTy = OpenedArchetypeType::getSelfInterfaceTypeFromContext(
4515+
parentSig, existential->getASTContext());
45144516
return getAny(existential, interfaceTy, parentSig);
45154517
}
45164518

lib/AST/ASTDemangler.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,14 @@ Type ASTBuilder::createExistentialMetatypeType(Type instance,
621621
getMetatypeRepresentation(*repr));
622622
}
623623

624+
Type ASTBuilder::createParameterizedProtocolType(Type base,
625+
ArrayRef<Type> args) {
626+
if (!base->getAs<ProtocolType>())
627+
return Type();
628+
return ParameterizedProtocolType::get(base->getASTContext(),
629+
base->castTo<ProtocolType>(), args);
630+
}
631+
624632
Type ASTBuilder::createMetatypeType(Type instance,
625633
Optional<Demangle::ImplMetatypeRepresentation> repr) {
626634
if (!repr)

lib/AST/ASTMangler.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,8 +1269,11 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
12691269
}
12701270

12711271
case TypeKind::ParameterizedProtocol: {
1272-
llvm::errs() << "Not implemented\n";
1273-
abort();
1272+
auto layout = type->getExistentialLayout();
1273+
appendExistentialLayout(layout, sig, forDecl);
1274+
bool isFirstArgList = true;
1275+
appendBoundGenericArgs(type, sig, isFirstArgList, forDecl);
1276+
return appendOperator("XP");
12741277
}
12751278

12761279
case TypeKind::Existential: {
@@ -1574,6 +1577,9 @@ void ASTMangler::appendBoundGenericArgs(Type type, GenericSignature sig,
15741577
if (Type parent = nominalType->getParent())
15751578
appendBoundGenericArgs(parent->getDesugaredType(), sig, isFirstArgList,
15761579
forDecl);
1580+
} else if (auto *ppt = dyn_cast<ParameterizedProtocolType>(typePtr)) {
1581+
assert(!ppt->getBaseType()->getParent());
1582+
genericArgs = ppt->getArgs();
15771583
} else {
15781584
auto boundType = cast<BoundGenericType>(typePtr);
15791585
genericArgs = boundType->getGenericArgs();

lib/AST/ASTVerifier.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,25 @@ class Verifier : public ASTWalker {
14691469
verifyCheckedBase(E);
14701470
}
14711471

1472+
bool shouldVerify(ErasureExpr *expr) {
1473+
if (!shouldVerify(cast<Expr>(expr)))
1474+
return false;
1475+
1476+
for (auto &elt : expr->getArgumentConversions()) {
1477+
assert(!OpaqueValues.count(elt.OrigValue));
1478+
OpaqueValues[elt.OrigValue] = 0;
1479+
}
1480+
1481+
return true;
1482+
}
1483+
1484+
void cleanup(ErasureExpr *expr) {
1485+
for (auto &elt : expr->getArgumentConversions()) {
1486+
assert(OpaqueValues.count(elt.OrigValue));
1487+
OpaqueValues.erase(elt.OrigValue);
1488+
}
1489+
}
1490+
14721491
void verifyChecked(ErasureExpr *E) {
14731492
PrettyStackTraceExpr debugStack(Ctx, "verifying ErasureExpr", E);
14741493

lib/AST/ASTWalker.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,29 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
695695
}
696696
return nullptr;
697697
}
698-
698+
699+
Expr *visitErasureExpr(ErasureExpr *E) {
700+
if (Expr *E2 = doIt(E->getSubExpr())) {
701+
E->setSubExpr(E2);
702+
} else {
703+
return nullptr;
704+
}
705+
706+
for (unsigned i = 0; i < E->getArgumentConversions().size(); ++i) {
707+
const auto &conv = E->getArgumentConversions()[i];
708+
auto kConv = conv.Conversion;
709+
if (!kConv) {
710+
return nullptr;
711+
} else if (Expr *E2 = doIt(kConv)) {
712+
E->setArgumentConversion(i, {conv.OrigValue, E2});
713+
} else {
714+
return nullptr;
715+
}
716+
}
717+
718+
return E;
719+
}
720+
699721
Expr *visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E) {
700722
if (Expr *E2 = doIt(E->getSubExpr())) {
701723
E->setSubExpr(E2);

lib/AST/Expr.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,14 +1178,16 @@ SequenceExpr *SequenceExpr::create(ASTContext &ctx, ArrayRef<Expr*> elements) {
11781178
assert(elements.size() & 1 && "even number of elements in sequence");
11791179
size_t bytes = totalSizeToAlloc<Expr *>(elements.size());
11801180
void *Buffer = ctx.Allocate(bytes, alignof(SequenceExpr));
1181-
return ::new(Buffer) SequenceExpr(elements);
1181+
return ::new (Buffer) SequenceExpr(elements);
11821182
}
11831183

11841184
ErasureExpr *ErasureExpr::create(ASTContext &ctx, Expr *subExpr, Type type,
1185-
ArrayRef<ProtocolConformanceRef> conformances){
1186-
auto size = totalSizeToAlloc<ProtocolConformanceRef>(conformances.size());
1185+
ArrayRef<ProtocolConformanceRef> conformances,
1186+
ArrayRef<ConversionPair> argConversions) {
1187+
auto size = totalSizeToAlloc<ProtocolConformanceRef, ConversionPair>(conformances.size(),
1188+
argConversions.size());
11871189
auto mem = ctx.Allocate(size, alignof(ErasureExpr));
1188-
return ::new(mem) ErasureExpr(subExpr, type, conformances);
1190+
return ::new (mem) ErasureExpr(subExpr, type, conformances, argConversions);
11891191
}
11901192

11911193
UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
@@ -1194,8 +1196,8 @@ UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
11941196
SourceLoc RAngleLoc) {
11951197
auto size = totalSizeToAlloc<TypeRepr *>(UnresolvedParams.size());
11961198
auto mem = ctx.Allocate(size, alignof(UnresolvedSpecializeExpr));
1197-
return ::new(mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
1198-
UnresolvedParams, RAngleLoc);
1199+
return ::new (mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
1200+
UnresolvedParams, RAngleLoc);
11991201
}
12001202

12011203
CaptureListEntry::CaptureListEntry(PatternBindingDecl *PBD) : PBD(PBD) {

lib/AST/Type.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ NominalTypeDecl *CanType::getAnyNominal() const {
106106
GenericTypeDecl *CanType::getAnyGeneric() const {
107107
if (auto existential = dyn_cast<ExistentialType>(*this))
108108
return existential->getConstraintType()->getAnyGeneric();
109+
if (auto ppt = dyn_cast<ParameterizedProtocolType>(*this))
110+
return ppt->getBaseType()->getDecl();
109111
if (auto Ty = dyn_cast<AnyGenericType>(*this))
110112
return Ty->getDecl();
111113
return nullptr;

0 commit comments

Comments
 (0)