Skip to content

Commit 374db66

Browse files
authored
Merge pull request #8685 from slavapestov/subclass-existentials-silgen
Preliminary SILGen support for subclass existentials (SE-0156)
2 parents e457d67 + 67ec712 commit 374db66

21 files changed

+438
-147
lines changed

docs/ABI.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,7 @@ Types
10441044
type ::= associated-type
10451045
type ::= nominal-type
10461046
type ::= protocol-list 'p' // existential type
1047+
type ::= protocol-list superclass 'XE' // existential type with superclass
10471048
type ::= type-list 't' // tuple
10481049
type ::= type generic-signature 'u' // generic type
10491050
type ::= 'x' // generic param, depth=0, idx=0

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3093,7 +3093,11 @@ ERROR(function_type_no_parens,none,
30933093
NOTE(not_objc_empty_protocol_composition,none,
30943094
"'Any' is not considered '@objc'; use 'AnyObject' instead", ())
30953095
NOTE(not_objc_protocol,none,
3096-
"protocol %0 is not '@objc'", (Type))
3096+
"protocol-constrained type containing protocol %0 cannot be represented "
3097+
"in Objective-C", (Type))
3098+
NOTE(not_objc_class_constraint,none,
3099+
"protocol-constrained type containing class %0 cannot be represented "
3100+
"in Objective-C", (Type))
30973101
NOTE(not_objc_error_protocol_composition,none,
30983102
"protocol-constrained type containing 'Error' cannot be represented "
30993103
"in Objective-C", ())

include/swift/AST/ExistentialLayout.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,13 @@ struct ExistentialLayout {
5858
return requiresClass && !containsNonObjCProtocol;
5959
}
6060

61+
// Does this existential contain the Error protocol?
6162
bool isExistentialWithError(ASTContext &ctx) const;
6263

64+
// Does this existential consist of an Error protocol only with no other
65+
// constraints?
66+
bool isErrorExistential() const;
67+
6368
ArrayRef<ProtocolType *> getProtocols() const {
6469
if (singleProtocol)
6570
return ArrayRef<ProtocolType *>{&singleProtocol, 1};

include/swift/AST/Types.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4552,21 +4552,6 @@ inline CanType CanType::getNominalParent() const {
45524552
}
45534553
}
45544554

4555-
inline bool TypeBase::mayHaveSuperclass() {
4556-
if (getClassOrBoundGenericClass())
4557-
return true;
4558-
4559-
// FIXME: requiresClass() is not the same as having an explicit superclass;
4560-
// is this wrong?
4561-
if (auto archetype = getAs<ArchetypeType>())
4562-
return (bool)archetype->requiresClass();
4563-
4564-
if (isExistentialType())
4565-
return (bool)getSuperclass(nullptr);
4566-
4567-
return is<DynamicSelfType>();
4568-
}
4569-
45704555
inline TupleTypeElt::TupleTypeElt(Type ty, Identifier name, bool isVariadic,
45714556
bool isAutoClosure, bool isEscaping)
45724557
: Name(name), ElementType(ty),

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ CONTEXT_NODE(Protocol)
123123
NODE(ProtocolConformance)
124124
NODE(ProtocolDescriptor)
125125
NODE(ProtocolList)
126+
NODE(ProtocolListWithClass)
126127
NODE(ProtocolWitness)
127128
NODE(ProtocolWitnessTable)
128129
NODE(ProtocolWitnessTableAccessor)

lib/AST/ASTMangler.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/ASTMangler.h"
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/ASTVisitor.h"
20+
#include "swift/AST/ExistentialLayout.h"
2021
#include "swift/AST/GenericEnvironment.h"
2122
#include "swift/AST/Initializer.h"
2223
#include "swift/AST/Module.h"
@@ -631,16 +632,32 @@ void ASTMangler::appendType(Type type) {
631632
appendTypeList(type);
632633
return appendOperator("t");
633634

634-
case TypeKind::Protocol:
635+
case TypeKind::Protocol: {
636+
bool First = true;
637+
appendProtocolName(cast<ProtocolType>(tybase)->getDecl());
638+
appendListSeparator(First);
639+
return appendOperator("p");
640+
}
641+
635642
case TypeKind::ProtocolComposition: {
636643
// We mangle ProtocolType and ProtocolCompositionType using the
637644
// same production:
638645
bool First = true;
639-
appendProtocolList(type, First);
646+
auto layout = type->getExistentialLayout();
647+
for (Type protoTy : layout.getProtocols()) {
648+
appendProtocolName(protoTy->castTo<ProtocolType>()->getDecl());
649+
appendListSeparator(First);
650+
}
640651
if (First)
641652
appendOperator("y");
653+
654+
if (layout.superclass) {
655+
appendType(layout.superclass);
656+
return appendOperator("XE");
657+
}
642658
return appendOperator("p");
643659
}
660+
644661
case TypeKind::UnboundGeneric:
645662
case TypeKind::Class:
646663
case TypeKind::Enum:

lib/AST/Type.cpp

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ ExistentialLayout::ExistentialLayout(ProtocolCompositionType *type) {
273273
isa<ClassDecl>(members[0]->getAnyNominal())) {
274274
superclass = members[0];
275275
members = members.slice(1);
276+
requiresClass = true;
277+
requiresClassImplied = true;
276278
}
277279

278280
for (auto member : members) {
@@ -600,6 +602,13 @@ bool TypeBase::isAnyObject() {
600602
return canTy.getExistentialLayout().isAnyObject();
601603
}
602604

605+
bool ExistentialLayout::isErrorExistential() const {
606+
auto protocols = getProtocols();
607+
return (!requiresClass &&
608+
protocols.size() == 1 &&
609+
protocols[0]->getDecl()->isSpecificProtocol(KnownProtocolKind::Error));
610+
}
611+
603612
bool ExistentialLayout::isExistentialWithError(ASTContext &ctx) const {
604613
auto errorProto = ctx.getProtocol(KnownProtocolKind::Error);
605614
if (!errorProto) return false;
@@ -1562,6 +1571,16 @@ LayoutConstraint TypeBase::getLayoutConstraint() {
15621571
return LayoutConstraint();
15631572
}
15641573

1574+
bool TypeBase::mayHaveSuperclass() {
1575+
if (getClassOrBoundGenericClass())
1576+
return true;
1577+
1578+
if (auto archetype = getAs<ArchetypeType>())
1579+
return (bool)archetype->requiresClass();
1580+
1581+
return is<DynamicSelfType>();
1582+
}
1583+
15651584
Type TypeBase::getSuperclass(LazyResolver *resolver) {
15661585
auto *nominalDecl = getAnyNominal();
15671586
auto *classDecl = dyn_cast_or_null<ClassDecl>(nominalDecl);
@@ -1987,10 +2006,18 @@ getObjCObjectRepresentable(Type type, const DeclContext *dc) {
19872006
return ForeignRepresentableKind::Object;
19882007
}
19892008

1990-
// Objective-C existential types.
1991-
if (type->isObjCExistentialType())
1992-
return ForeignRepresentableKind::Object;
1993-
2009+
// Objective-C existential types are trivially representable if
2010+
// they don't have a superclass constraint, or if the superclass
2011+
// constraint is an @objc class.
2012+
if (type->isExistentialType()) {
2013+
auto layout = type->getExistentialLayout();
2014+
if (layout.isObjC() &&
2015+
(!layout.superclass ||
2016+
getObjCObjectRepresentable(layout.superclass, dc) ==
2017+
ForeignRepresentableKind::Object))
2018+
return ForeignRepresentableKind::Object;
2019+
}
2020+
19942021
// Any can be bridged to id.
19952022
if (type->isAny()) {
19962023
return ForeignRepresentableKind::Bridged;

lib/Demangling/Demangler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,12 @@ NodePointer Demangler::demangleSpecialType() {
15831583
case 'p':
15841584
return createType(createWithChild(Node::Kind::ExistentialMetatype,
15851585
popNode(Node::Kind::Type)));
1586+
case 'E': {
1587+
NodePointer Superclass = popNode(Node::Kind::Type);
1588+
NodePointer Protocols = demangleProtocolListType();
1589+
return createType(createWithChildren(Node::Kind::ProtocolListWithClass,
1590+
Protocols, Superclass));
1591+
}
15861592
case 'X':
15871593
case 'x': {
15881594
// SIL box types.

lib/Demangling/NodePrinter.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ class NodePrinter {
265265
case Node::Kind::ProtocolList:
266266
return pointer->getChild(0)->getNumChildren() <= 1;
267267

268+
case Node::Kind::ProtocolListWithClass:
268269
case Node::Kind::Allocator:
269270
case Node::Kind::ArgumentTuple:
270271
case Node::Kind::AssociatedTypeMetadataAccessor:
@@ -576,7 +577,8 @@ class NodePrinter {
576577

577578
static bool isExistentialType(NodePointer node) {
578579
return (node->getKind() == Node::Kind::ExistentialMetatype ||
579-
node->getKind() == Node::Kind::ProtocolList);
580+
node->getKind() == Node::Kind::ProtocolList ||
581+
node->getKind() == Node::Kind::ProtocolListWithClass);
580582
}
581583

582584
/// Print the relevant parameters and return the new index.
@@ -1386,6 +1388,16 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
13861388
printChildren(type_list, " & ");
13871389
return;
13881390
}
1391+
case Node::Kind::ProtocolListWithClass: {
1392+
if (pointer->getNumChildren() < 2)
1393+
return;
1394+
NodePointer protocols = pointer->getChild(0);
1395+
NodePointer superclass = pointer->getChild(1);
1396+
print(superclass);
1397+
Printer << " & ";
1398+
printChildren(protocols, " & ");
1399+
return;
1400+
}
13891401
case Node::Kind::AssociatedType:
13901402
// Don't print for now.
13911403
return;

lib/Demangling/Remangler.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ class Remangler {
249249
mangleChildNodes(Proto);
250250
}
251251

252+
void mangleProtocolList(Node *protocols, Node *superclass);
253+
252254
bool trySubstitution(Node *node, SubstitutionEntry &entry,
253255
bool treatAsIdentifier = false);
254256
void addSubstitution(const SubstitutionEntry &entry);
@@ -1401,17 +1403,31 @@ void Remangler::mangleProtocolDescriptor(Node *node) {
14011403
Buffer << "Mp";
14021404
}
14031405

1404-
void Remangler::mangleProtocolList(Node *node) {
1405-
node = getSingleChild(node, Node::Kind::TypeList);
1406+
void Remangler::mangleProtocolList(Node *node, Node *superclass) {
14061407
bool FirstElem = true;
14071408
for (NodePointer Child : *node) {
14081409
manglePureProtocol(Child);
14091410
mangleListSeparator(FirstElem);
14101411
}
14111412
mangleEndOfList(FirstElem);
1413+
if (superclass) {
1414+
mangleType(superclass);
1415+
Buffer << "XE";
1416+
return;
1417+
}
14121418
Buffer << 'p';
14131419
}
14141420

1421+
void Remangler::mangleProtocolList(Node *node) {
1422+
auto *protocols = getSingleChild(node, Node::Kind::TypeList);
1423+
mangleProtocolList(protocols, nullptr);
1424+
}
1425+
1426+
void Remangler::mangleProtocolListWithClass(Node *node) {
1427+
mangleProtocolList(node->getChild(0),
1428+
node->getChild(1));
1429+
}
1430+
14151431
void Remangler::mangleProtocolWitness(Node *node) {
14161432
mangleChildNodes(node);
14171433
Buffer << "TW";

lib/SIL/SILType.cpp

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/SIL/SILType.h"
14+
#include "swift/AST/ExistentialLayout.h"
1415
#include "swift/AST/GenericEnvironment.h"
1516
#include "swift/AST/Type.h"
1617
#include "swift/SIL/SILModule.h"
@@ -473,16 +474,9 @@ static bool isBridgedErrorClass(SILModule &M,
473474
return false;
474475
}
475476

476-
static bool isErrorExistential(ArrayRef<ProtocolDecl*> protocols) {
477-
return protocols.size() == 1
478-
&& protocols[0]->isSpecificProtocol(KnownProtocolKind::Error);
479-
}
480-
481477
ExistentialRepresentation
482478
SILType::getPreferredExistentialRepresentation(SILModule &M,
483479
Type containedType) const {
484-
SmallVector<ProtocolDecl *, 4> protocols;
485-
486480
// Existential metatypes always use metatype representation.
487481
if (is<ExistentialMetatypeType>())
488482
return ExistentialRepresentation::Metatype;
@@ -491,11 +485,9 @@ SILType::getPreferredExistentialRepresentation(SILModule &M,
491485
if (!isExistentialType())
492486
return ExistentialRepresentation::None;
493487

494-
// Get the list of existential constraints.
495-
getSwiftRValueType()->getExistentialTypeProtocols(protocols);
488+
auto layout = getSwiftRValueType().getExistentialLayout();
496489

497-
// The (uncomposed) Error existential uses a special boxed representation.
498-
if (isErrorExistential(protocols)) {
490+
if (layout.isErrorExistential()) {
499491
// NSError or CFError references can be adopted directly as Error
500492
// existentials.
501493
if (isBridgedErrorClass(M, containedType)) {
@@ -507,10 +499,8 @@ SILType::getPreferredExistentialRepresentation(SILModule &M,
507499

508500
// A class-constrained protocol composition can adopt the conforming
509501
// class reference directly.
510-
for (auto proto : protocols) {
511-
if (proto->requiresClass())
512-
return ExistentialRepresentation::Class;
513-
}
502+
if (layout.requiresClass)
503+
return ExistentialRepresentation::Class;
514504

515505
// Otherwise, we need to use a fixed-sized buffer.
516506
return ExistentialRepresentation::Opaque;
@@ -529,23 +519,22 @@ SILType::canUseExistentialRepresentation(SILModule &M,
529519
// Look at the protocols to see what representation is appropriate.
530520
if (!getSwiftRValueType().isExistentialType())
531521
return false;
532-
SmallVector<ProtocolDecl *, 4> protocols;
533-
getSwiftRValueType().getExistentialTypeProtocols(protocols);
522+
523+
auto layout = getSwiftRValueType().getExistentialLayout();
534524

535525
// The (uncomposed) Error existential uses a special boxed
536526
// representation. It can also adopt class references of bridged error types
537527
// directly.
538-
if (isErrorExistential(protocols))
528+
if (layout.isErrorExistential())
539529
return repr == ExistentialRepresentation::Boxed
540530
|| (repr == ExistentialRepresentation::Class
541531
&& isBridgedErrorClass(M, containedType));
542532

543533
// A class-constrained composition uses ClassReference representation;
544-
// otherwise, we use a fixed-sized buffer
545-
for (auto *proto : protocols) {
546-
if (proto->requiresClass())
547-
return repr == ExistentialRepresentation::Class;
548-
}
534+
// otherwise, we use a fixed-sized buffer.
535+
if (layout.requiresClass)
536+
return repr == ExistentialRepresentation::Class;
537+
549538
return repr == ExistentialRepresentation::Opaque;
550539
}
551540
case ExistentialRepresentation::Metatype:

0 commit comments

Comments
 (0)