18
18
19
19
#include " swift/AST/ASTContext.h"
20
20
#include " swift/AST/Decl.h"
21
+ #include " swift/AST/ExistentialLayout.h"
21
22
#include " swift/AST/ProtocolConformance.h"
22
23
#include " swift/AST/Types.h"
23
24
#include " swift/IRGen/Linking.h"
@@ -1335,14 +1336,15 @@ class ErrorExistentialTypeInfo : public HeapTypeInfo<ErrorExistentialTypeInfo>
1335
1336
1336
1337
} // end anonymous namespace
1337
1338
1338
- static const TypeInfo *createErrorExistentialTypeInfo (IRGenModule &IGM,
1339
- ArrayRef<ProtocolDecl*> protocols) {
1339
+ static const TypeInfo *
1340
+ createErrorExistentialTypeInfo (IRGenModule &IGM,
1341
+ const ExistentialLayout &layout) {
1340
1342
// The Error existential has a special boxed representation. It has
1341
1343
// space only for witnesses to the Error protocol.
1342
- assert (protocols. size () == 1
1343
- && *protocols [0 ]->getKnownProtocolKind () == KnownProtocolKind::Error );
1344
-
1345
- const ProtocolInfo &impl = IGM. getProtocolInfo (protocols[ 0 ]);
1344
+ assert (layout. isErrorExistential ());
1345
+ auto *protocol = layout. getProtocols () [0 ]->getDecl ( );
1346
+ auto &impl = IGM. getProtocolInfo (protocol);
1347
+
1346
1348
auto refcounting = (!IGM.ObjCInterop
1347
1349
? ReferenceCounting::Native
1348
1350
: ReferenceCounting::Error);
@@ -1351,36 +1353,28 @@ static const TypeInfo *createErrorExistentialTypeInfo(IRGenModule &IGM,
1351
1353
IGM.getPointerSize (),
1352
1354
IGM.getHeapObjectSpareBits (),
1353
1355
IGM.getPointerAlignment (),
1354
- ProtocolEntry (protocols[ 0 ] , impl),
1356
+ ProtocolEntry (protocol , impl),
1355
1357
refcounting);
1356
1358
}
1357
1359
1358
- static const TypeInfo *createExistentialTypeInfo (IRGenModule &IGM, CanType T,
1359
- ArrayRef<ProtocolDecl*> protocols) {
1360
+ static const TypeInfo *createExistentialTypeInfo (IRGenModule &IGM, CanType T) {
1361
+ auto layout = T.getExistentialLayout ();
1362
+
1360
1363
SmallVector<llvm::Type*, 5 > fields;
1361
1364
SmallVector<ProtocolEntry, 4 > entries;
1362
1365
1363
1366
// Check for special existentials.
1364
- if (protocols.size () == 1 ) {
1365
- switch (getSpecialProtocolID (protocols[0 ])) {
1366
- case SpecialProtocol::Error:
1367
- // Error has a special runtime representation.
1368
- return createErrorExistentialTypeInfo (IGM, protocols);
1369
- // Other existentials have standard representations.
1370
- case SpecialProtocol::AnyObject:
1371
- case SpecialProtocol::None:
1372
- break ;
1373
- }
1367
+ if (layout.isErrorExistential ()) {
1368
+ // Error has a special runtime representation.
1369
+ return createErrorExistentialTypeInfo (IGM, layout);
1374
1370
}
1375
1371
1372
+ // Note: Protocol composition types are not nominal, but we name them anyway.
1376
1373
llvm::StructType *type;
1377
1374
if (isa<ProtocolType>(T))
1378
1375
type = IGM.createNominalType (T);
1379
- else if (auto compT = dyn_cast<ProtocolCompositionType>(T))
1380
- // Protocol composition types are not nominal, but we name them anyway.
1381
- type = IGM.createNominalType (compT.getPointer ());
1382
1376
else
1383
- llvm_unreachable ( " unknown existential type kind " );
1377
+ type = IGM. createNominalType (cast<ProtocolCompositionType>(T. getPointer ()) );
1384
1378
1385
1379
assert (type->isOpaque () && " creating existential type in concrete struct" );
1386
1380
@@ -1392,25 +1386,25 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
1392
1386
fields.push_back (nullptr );
1393
1387
fields.push_back (nullptr );
1394
1388
1395
- bool requiresClass = false ;
1389
+ // The existential container is class-constrained if any of its protocol
1390
+ // constraints are.
1391
+ bool requiresClass = layout.requiresClass ;
1396
1392
bool allowsTaggedPointers = true ;
1397
1393
1398
- for (auto protocol : protocols) {
1399
- // The existential container is class-constrained if any of its protocol
1400
- // constraints are.
1401
- requiresClass |= protocol->requiresClass ();
1394
+ for (auto protoTy : layout.getProtocols ()) {
1395
+ auto *protoDecl = protoTy->getDecl ();
1402
1396
1403
- if (protocol ->getAttrs ().hasAttribute <UnsafeNoObjCTaggedPointerAttr>())
1397
+ if (protoDecl ->getAttrs ().hasAttribute <UnsafeNoObjCTaggedPointerAttr>())
1404
1398
allowsTaggedPointers = false ;
1405
1399
1406
1400
// ObjC protocols need no layout or witness table info. All dispatch is done
1407
1401
// through objc_msgSend.
1408
- if (!Lowering::TypeConverter::protocolRequiresWitnessTable (protocol ))
1402
+ if (!Lowering::TypeConverter::protocolRequiresWitnessTable (protoDecl ))
1409
1403
continue ;
1410
1404
1411
1405
// Find the protocol layout.
1412
- const ProtocolInfo &impl = IGM.getProtocolInfo (protocol );
1413
- entries.push_back (ProtocolEntry (protocol , impl));
1406
+ const ProtocolInfo &impl = IGM.getProtocolInfo (protoDecl );
1407
+ entries.push_back (ProtocolEntry (protoDecl , impl));
1414
1408
1415
1409
// Each protocol gets a witness table.
1416
1410
fields.push_back (IGM.WitnessTablePtrTy );
@@ -1423,7 +1417,8 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
1423
1417
// native reference counting entry points.
1424
1418
ReferenceCounting refcounting;
1425
1419
1426
- // Replace the type metadata pointer with the class instance.
1420
+ // FIXME: If there is a superclass constraint we might be able to
1421
+ // use native refcounting.
1427
1422
if (!IGM.ObjCInterop ) {
1428
1423
refcounting = ReferenceCounting::Native;
1429
1424
fields[1 ] = IGM.RefCountedPtrTy ;
@@ -1432,6 +1427,7 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
1432
1427
fields[1 ] = IGM.UnknownRefCountedPtrTy ;
1433
1428
}
1434
1429
1430
+ // Replace the type metadata pointer with the class instance.
1435
1431
auto classFields = llvm::makeArrayRef (fields).slice (1 );
1436
1432
type->setBody (classFields);
1437
1433
@@ -1463,33 +1459,31 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T,
1463
1459
fields[1 ] = IGM.TypeMetadataPtrTy ;
1464
1460
type->setBody (fields);
1465
1461
1466
- OpaqueExistentialLayout layout (entries.size ());
1467
- Alignment align = layout .getAlignment (IGM);
1468
- Size size = layout .getSize (IGM);
1462
+ OpaqueExistentialLayout opaque (entries.size ());
1463
+ Alignment align = opaque .getAlignment (IGM);
1464
+ Size size = opaque .getSize (IGM);
1469
1465
return OpaqueExistentialTypeInfo::create (entries, type, size, align);
1470
1466
}
1471
1467
1472
1468
const TypeInfo *TypeConverter::convertProtocolType (ProtocolType *T) {
1473
- // Protocol types are nominal.
1474
- return createExistentialTypeInfo (IGM, CanType (T), T->getDecl ());
1469
+ return createExistentialTypeInfo (IGM, CanType (T));
1475
1470
}
1476
1471
1477
1472
const TypeInfo *
1478
1473
TypeConverter::convertProtocolCompositionType (ProtocolCompositionType *T) {
1479
- // Find the canonical protocols. There might not be any.
1480
- SmallVector<ProtocolDecl*, 4 > protocols;
1481
- T->getExistentialTypeProtocols (protocols);
1482
-
1483
- return createExistentialTypeInfo (IGM, CanType (T), protocols);
1474
+ return createExistentialTypeInfo (IGM, CanType (T));
1484
1475
}
1485
1476
1486
1477
const TypeInfo *
1487
1478
TypeConverter::convertExistentialMetatypeType (ExistentialMetatypeType *T) {
1488
1479
assert (T->hasRepresentation () &&
1489
1480
" metatype should have been assigned a representation by SIL" );
1490
1481
1491
- SmallVector<ProtocolDecl*, 4 > protocols;
1492
- T->getAnyExistentialTypeProtocols (protocols);
1482
+ auto instanceT = CanExistentialMetatypeType (T).getInstanceType ();
1483
+ while (isa<ExistentialMetatypeType>(instanceT))
1484
+ instanceT = cast<ExistentialMetatypeType>(instanceT).getInstanceType ();
1485
+
1486
+ auto layout = instanceT.getExistentialLayout ();
1493
1487
1494
1488
SmallVector<ProtocolEntry, 4 > entries;
1495
1489
SmallVector<llvm::Type*, 4 > fields;
@@ -1502,13 +1496,15 @@ TypeConverter::convertExistentialMetatypeType(ExistentialMetatypeType *T) {
1502
1496
fields.push_back (baseTI.getStorageType ());
1503
1497
spareBits.append (baseTI.getSpareBits ());
1504
1498
1505
- for (auto protocol : protocols) {
1506
- if (!Lowering::TypeConverter::protocolRequiresWitnessTable (protocol))
1499
+ for (auto protoTy : layout.getProtocols ()) {
1500
+ auto *protoDecl = protoTy->getDecl ();
1501
+
1502
+ if (!Lowering::TypeConverter::protocolRequiresWitnessTable (protoDecl))
1507
1503
continue ;
1508
1504
1509
1505
// Find the protocol layout.
1510
- const ProtocolInfo &impl = IGM.getProtocolInfo (protocol );
1511
- entries.push_back (ProtocolEntry (protocol , impl));
1506
+ const ProtocolInfo &impl = IGM.getProtocolInfo (protoDecl );
1507
+ entries.push_back (ProtocolEntry (protoDecl , impl));
1512
1508
1513
1509
// Each protocol gets a witness table.
1514
1510
fields.push_back (IGM.WitnessTablePtrTy );
@@ -1640,15 +1636,17 @@ static void forEachProtocolWitnessTable(IRGenFunction &IGF,
1640
1636
ArrayRef<ProtocolConformanceRef> conformances,
1641
1637
std::function<void (unsigned , llvm::Value*)> body) {
1642
1638
// Collect the conformances that need witness tables.
1643
- SmallVector<ProtocolDecl*, 2 > destProtocols ;
1644
- destType. getExistentialTypeProtocols (destProtocols );
1639
+ auto layout = destType. getExistentialLayout () ;
1640
+ auto destProtocols = layout. getProtocols ( );
1645
1641
1646
1642
SmallVector<ProtocolConformanceRef, 2 > witnessConformances;
1647
1643
assert (destProtocols.size () == conformances.size () &&
1648
1644
" mismatched protocol conformances" );
1649
- for (unsigned i = 0 , size = destProtocols.size (); i < size; ++i)
1650
- if (Lowering::TypeConverter::protocolRequiresWitnessTable (destProtocols[i]))
1645
+ for (unsigned i = 0 , size = destProtocols.size (); i < size; ++i) {
1646
+ auto destProtocol = destProtocols[i]->getDecl ();
1647
+ if (Lowering::TypeConverter::protocolRequiresWitnessTable (destProtocol))
1651
1648
witnessConformances.push_back (conformances[i]);
1649
+ }
1652
1650
1653
1651
assert (protocols.size () == witnessConformances.size () &&
1654
1652
" mismatched protocol conformances" );
@@ -1797,20 +1795,11 @@ void irgen::emitClassExistentialContainer(IRGenFunction &IGF,
1797
1795
// As a special case, an Error existential can be represented as a
1798
1796
// reference to an already existing NSError or CFError instance.
1799
1797
if (outType.getSwiftRValueType ().isExistentialType ()) {
1800
- SmallVector<ProtocolDecl*, 4 > protocols;
1801
- outType.getSwiftRValueType ().getExistentialTypeProtocols (protocols);
1802
- if (protocols.size () == 1 ) {
1803
- switch (getSpecialProtocolID (protocols[0 ])) {
1804
- case SpecialProtocol::Error: {
1805
- // Bitcast the incoming class reference to Error.
1806
- out.add (IGF.Builder .CreateBitCast (instance, IGF.IGM .ErrorPtrTy ));
1807
- return ;
1808
- }
1809
-
1810
- case SpecialProtocol::AnyObject:
1811
- case SpecialProtocol::None:
1812
- break ;
1813
- }
1798
+ auto layout = outType.getSwiftRValueType ().getExistentialLayout ();
1799
+ if (layout.isErrorExistential ()) {
1800
+ // Bitcast the incoming class reference to Error.
1801
+ out.add (IGF.Builder .CreateBitCast (instance, IGF.IGM .ErrorPtrTy ));
1802
+ return ;
1814
1803
}
1815
1804
}
1816
1805
0 commit comments