Skip to content

Commit 67ec712

Browse files
committed
SIL: Type lowering for subclass existentials
1 parent b756f76 commit 67ec712

File tree

4 files changed

+184
-49
lines changed

4 files changed

+184
-49
lines changed

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:

lib/SIL/SILVerifier.cpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "swift/AST/ASTContext.h"
1515
#include "swift/AST/AnyFunctionRef.h"
1616
#include "swift/AST/Decl.h"
17+
#include "swift/AST/ExistentialLayout.h"
1718
#include "swift/AST/GenericEnvironment.h"
1819
#include "swift/AST/Module.h"
1920
#include "swift/AST/ProtocolConformance.h"
@@ -2473,7 +2474,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
24732474
"alloc_existential_box must be used with a boxed existential "
24742475
"type");
24752476

2476-
checkExistentialProtocolConformances(exType, AEBI->getConformances());
2477+
checkExistentialProtocolConformances(exType,
2478+
AEBI->getFormalConcreteType(),
2479+
AEBI->getConformances());
24772480
verifyOpenedArchetype(AEBI, AEBI->getFormalConcreteType());
24782481
}
24792482

@@ -2504,7 +2507,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
25042507
"init_existential_addr payload must be a lowering of the formal "
25052508
"concrete type");
25062509

2507-
checkExistentialProtocolConformances(exType, AEI->getConformances());
2510+
checkExistentialProtocolConformances(exType,
2511+
AEI->getFormalConcreteType(),
2512+
AEI->getConformances());
25082513
verifyOpenedArchetype(AEI, AEI->getFormalConcreteType());
25092514
}
25102515

@@ -2529,7 +2534,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
25292534
"init_existential_opaque operand must be a lowering of the formal "
25302535
"concrete type");
25312536

2532-
checkExistentialProtocolConformances(exType, IEI->getConformances());
2537+
checkExistentialProtocolConformances(exType,
2538+
IEI->getFormalConcreteType(),
2539+
IEI->getConformances());
25332540
verifyOpenedArchetype(IEI, IEI->getFormalConcreteType());
25342541
}
25352542

@@ -2559,7 +2566,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
25592566
"init_existential_ref operand must be a lowering of the formal "
25602567
"concrete type");
25612568

2562-
checkExistentialProtocolConformances(exType, IEI->getConformances());
2569+
checkExistentialProtocolConformances(exType,
2570+
IEI->getFormalConcreteType(),
2571+
IEI->getConformances());
25632572
verifyOpenedArchetype(IEI, IEI->getFormalConcreteType());
25642573
}
25652574

@@ -2614,23 +2623,41 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
26142623
"init_existential_metatype result must match representation of "
26152624
"operand");
26162625

2617-
while(auto metatypeType = resultType.is<ExistentialMetatypeType>())
2626+
while(auto metatypeType = resultType.is<ExistentialMetatypeType>()) {
26182627
resultType = resultType.getMetatypeInstanceType(F.getModule());
2628+
operandType = operandType.getMetatypeInstanceType(F.getModule());
2629+
}
26192630

2620-
checkExistentialProtocolConformances(resultType, I->getConformances());
2631+
checkExistentialProtocolConformances(resultType,
2632+
operandType.getSwiftRValueType(),
2633+
I->getConformances());
26212634
verifyOpenedArchetype(I, MetaTy.getInstanceType());
26222635
}
26232636

26242637
void checkExistentialProtocolConformances(SILType resultType,
2638+
CanType concreteType,
26252639
ArrayRef<ProtocolConformanceRef> conformances) {
2626-
SmallVector<ProtocolDecl*, 4> protocols;
2627-
resultType.getSwiftRValueType().getExistentialTypeProtocols(protocols);
2640+
auto layout = resultType.getSwiftRValueType().getExistentialLayout();
2641+
auto protocols = layout.getProtocols();
26282642

26292643
require(conformances.size() == protocols.size(),
26302644
"init_existential instruction must have the "
26312645
"right number of conformances");
2646+
2647+
if (layout.requiresClass) {
2648+
require(concreteType->mayHaveSuperclass() ||
2649+
(concreteType.isExistentialType() &&
2650+
concreteType.getExistentialLayout().requiresClass),
2651+
"init_existential of class existential with non-class type");
2652+
}
2653+
2654+
if (layout.superclass) {
2655+
require(layout.superclass->isExactSuperclassOf(concreteType, nullptr),
2656+
"init_existential of subclass existential with wrong type");
2657+
}
2658+
26322659
for (auto i : indices(conformances)) {
2633-
require(conformances[i].getRequirement() == protocols[i],
2660+
require(conformances[i].getRequirement() == protocols[i]->getDecl(),
26342661
"init_existential instruction must have conformances in "
26352662
"proper order");
26362663

lib/SILGen/SILGenPoly.cpp

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
#include "swift/AST/GenericSignatureBuilder.h"
8484
#include "swift/AST/Decl.h"
8585
#include "swift/AST/DiagnosticsCommon.h"
86+
#include "swift/AST/ExistentialLayout.h"
8687
#include "swift/AST/GenericEnvironment.h"
8788
#include "swift/AST/ProtocolConformance.h"
8889
#include "swift/AST/Types.h"
@@ -160,16 +161,15 @@ namespace {
160161
;
161162

162163
static ArrayRef<ProtocolConformanceRef>
163-
collectExistentialConformances(ModuleDecl *M, Type fromType, Type toType) {
164-
assert(!fromType->isAnyExistentialType());
164+
collectExistentialConformances(ModuleDecl *M, CanType fromType, CanType toType) {
165+
assert(!fromType.isAnyExistentialType());
165166

166-
SmallVector<ProtocolDecl *, 4> protocols;
167-
toType->getExistentialTypeProtocols(protocols);
167+
auto protocols = toType.getExistentialLayout().getProtocols();
168168

169169
SmallVector<ProtocolConformanceRef, 4> conformances;
170170
for (auto proto : protocols) {
171171
auto conformance =
172-
M->lookupConformance(fromType, proto, nullptr).getPointer();
172+
M->lookupConformance(fromType, proto->getDecl(), nullptr);
173173
conformances.push_back(*conformance);
174174
}
175175

@@ -206,16 +206,16 @@ static ManagedValue emitTransformExistential(SILGenFunction &SGF,
206206
}
207207

208208
// Build conformance table
209-
Type fromInstanceType = inputType;
210-
Type toInstanceType = outputType;
209+
CanType fromInstanceType = inputType;
210+
CanType toInstanceType = outputType;
211211

212212
// Look through metatypes
213-
while (fromInstanceType->is<AnyMetatypeType>() &&
214-
toInstanceType->is<ExistentialMetatypeType>()) {
215-
fromInstanceType = fromInstanceType->castTo<AnyMetatypeType>()
216-
->getInstanceType();
217-
toInstanceType = toInstanceType->castTo<ExistentialMetatypeType>()
218-
->getInstanceType();
213+
while (isa<MetatypeType>(fromInstanceType) &&
214+
isa<ExistentialMetatypeType>(toInstanceType)) {
215+
fromInstanceType = cast<MetatypeType>(fromInstanceType)
216+
.getInstanceType();
217+
toInstanceType = cast<ExistentialMetatypeType>(toInstanceType)
218+
.getInstanceType();
219219
}
220220

221221
ArrayRef<ProtocolConformanceRef> conformances =
@@ -450,10 +450,11 @@ ManagedValue Transform::transform(ManagedValue v,
450450

451451
// - metatypes
452452
if (auto outputMetaType = dyn_cast<MetatypeType>(outputSubstType)) {
453-
auto inputMetaType = cast<MetatypeType>(inputSubstType);
454-
return transformMetatype(v,
455-
inputOrigType, inputMetaType,
456-
outputOrigType, outputMetaType);
453+
if (auto inputMetaType = dyn_cast<MetatypeType>(inputSubstType)) {
454+
return transformMetatype(v,
455+
inputOrigType, inputMetaType,
456+
outputOrigType, outputMetaType);
457+
}
457458
}
458459

459460
// Subtype conversions:
@@ -534,6 +535,33 @@ ManagedValue Transform::transform(ManagedValue v,
534535
ctxt);
535536
}
536537

538+
// - upcasting class-constrained existentials or metatypes thereof
539+
if (inputSubstType->isAnyExistentialType()) {
540+
auto instanceType = inputSubstType;
541+
while (auto metatypeType = dyn_cast<ExistentialMetatypeType>(instanceType))
542+
instanceType = metatypeType.getInstanceType();
543+
544+
auto layout = instanceType.getExistentialLayout();
545+
if (layout.superclass) {
546+
CanType openedType = ArchetypeType::getAnyOpened(inputSubstType);
547+
SILType loweredOpenedType = SGF.getLoweredType(openedType);
548+
549+
// Unwrap zero or more metatype levels
550+
auto openedArchetype = getOpenedArchetype(openedType);
551+
552+
auto state = SGF.emitOpenExistential(Loc, v, openedArchetype,
553+
loweredOpenedType,
554+
AccessKind::Read);
555+
auto payload = SGF.manageOpaqueValue(state, Loc, SGFContext());
556+
return transform(payload,
557+
AbstractionPattern::getOpaque(),
558+
openedType,
559+
outputOrigType,
560+
outputSubstType,
561+
ctxt);
562+
}
563+
}
564+
537565
// - T : Hashable to AnyHashable
538566
if (isa<StructType>(outputSubstType) &&
539567
outputSubstType->getAnyNominal() ==
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -parse-as-library -enable-experimental-subclass-existentials %s | %FileCheck %s
2+
3+
protocol Q {}
4+
5+
class Base<T> : Q {
6+
func classSelfReturn() -> Self {}
7+
static func classSelfReturn() -> Self {}
8+
}
9+
10+
protocol P {
11+
func protocolSelfReturn() -> Self
12+
static func protocolSelfReturn() -> Self
13+
}
14+
15+
class Derived : Base<Int>, P {
16+
func protocolSelfReturn() -> Self {}
17+
static func protocolSelfReturn() -> Self {}
18+
}
19+
20+
protocol R {}
21+
22+
// CHECK-LABEL: sil hidden @_T021subclass_existentials11conversionsyAA1P_AA4BaseCySiGXE8baseAndP_AA7DerivedC7derivedAA1R_AIXE0hF1RAaC_AFXEXp0eF5PTypeAIm0H4TypeAaK_AIXEXp0hF5RTypetF : $@convention(thin) (@owned Base<Int> & P, @owned Derived, @owned Derived & R, @thick (Base<Int> & P).Type, @thick Derived.Type, @thick (Derived & R).Type) -> () {
23+
24+
func conversions(
25+
baseAndP: Base<Int> & P,
26+
derived: Derived,
27+
derivedAndR: Derived & R,
28+
29+
baseAndPType: (Base<Int> & P).Type,
30+
derivedType: Derived.Type,
31+
derivedAndRType: (Derived & R).Type) {
32+
33+
// Values
34+
let _: Base<Int> = baseAndP
35+
let _: P = baseAndP
36+
let _: Q = baseAndP
37+
38+
let _: Base<Int> & P = derivedAndR
39+
40+
// Metatypes
41+
let _: Base<Int>.Type = baseAndPType
42+
let _: P.Type = baseAndPType
43+
let _: Q.Type = baseAndPType
44+
45+
let _: (Base<Int> & P).Type = derivedAndRType
46+
}
47+
48+
func methodCalls(
49+
baseAndP: Base<Int> & P,
50+
baseAndPType: (Base<Int> & P).Type) {
51+
52+
let _: Base<Int> & P = baseAndP.classSelfReturn()
53+
let _: Base<Int> & P = baseAndP.protocolSelfReturn()
54+
55+
let _: Base<Int> & P = baseAndPType.classSelfReturn()
56+
let _: Base<Int> & P = baseAndPType.protocolSelfReturn()
57+
58+
// Partial applications
59+
let _: () -> (Base<Int> & P) = baseAndP.classSelfReturn
60+
let _: () -> (Base<Int> & P) = baseAndP.protocolSelfReturn
61+
62+
let _: () -> (Base<Int> & P) = baseAndPType.classSelfReturn
63+
let _: () -> (Base<Int> & P) = baseAndPType.protocolSelfReturn
64+
}
65+
66+
func functionConversions(
67+
returnsBaseAndP: @escaping () -> (Base<Int> & P),
68+
returnsBaseAndPType: @escaping () -> (Base<Int> & P).Type,
69+
returnsDerived: @escaping () -> Derived,
70+
returnsDerivedType: @escaping () -> Derived.Type,
71+
returnsDerivedAndR: @escaping () -> Derived & R,
72+
returnsDerivedAndRType: @escaping () -> (Derived & R).Type) {
73+
74+
let _: () -> Base<Int> = returnsBaseAndP
75+
let _: () -> Base<Int>.Type = returnsBaseAndPType
76+
77+
let _: () -> P = returnsBaseAndP
78+
let _: () -> P.Type = returnsBaseAndPType
79+
80+
let _: () -> (Base<Int> & P) = returnsDerived
81+
let _: () -> (Base<Int> & P).Type = returnsDerivedType
82+
83+
let _: () -> Base<Int> = returnsDerivedAndR
84+
let _: () -> Base<Int>.Type = returnsDerivedAndRType
85+
86+
let _: () -> (Base<Int> & P) = returnsDerivedAndR
87+
let _: () -> (Base<Int> & P).Type = returnsDerivedAndRType
88+
89+
let _: () -> P = returnsDerivedAndR
90+
let _: () -> P.Type = returnsDerivedAndRType
91+
}

0 commit comments

Comments
 (0)