@@ -1320,10 +1320,14 @@ Type TypeBase::getMetatypeInstanceType() {
1320
1320
return this ;
1321
1321
}
1322
1322
1323
+ using ParameterizedProtocolMap =
1324
+ llvm::DenseMap<ProtocolDecl *, ParameterizedProtocolType *>;
1325
+
1323
1326
// / Collect the protocols in the existential type T into the given
1324
1327
// / vector.
1325
1328
static void addProtocols (Type T,
1326
1329
SmallVectorImpl<ProtocolDecl *> &Protocols,
1330
+ ParameterizedProtocolMap &Parameterized,
1327
1331
Type &Superclass,
1328
1332
bool &HasExplicitAnyObject) {
1329
1333
if (auto Proto = T->getAs <ProtocolType>()) {
@@ -1335,7 +1339,14 @@ static void addProtocols(Type T,
1335
1339
if (PC->hasExplicitAnyObject ())
1336
1340
HasExplicitAnyObject = true ;
1337
1341
for (auto P : PC->getMembers ())
1338
- addProtocols (P, Protocols, Superclass, HasExplicitAnyObject);
1342
+ addProtocols (P, Protocols, Parameterized, Superclass,
1343
+ HasExplicitAnyObject);
1344
+ return ;
1345
+ }
1346
+
1347
+ if (auto PP = T->getAs <ParameterizedProtocolType>()) {
1348
+ Parameterized.insert ({PP->getProtocol (), PP});
1349
+ Protocols.push_back (PP->getProtocol ());
1339
1350
return ;
1340
1351
}
1341
1352
@@ -1377,8 +1388,8 @@ bool ProtocolType::visitAllProtocols(
1377
1388
return false ;
1378
1389
}
1379
1390
1380
- void ProtocolType:: canonicalizeProtocols (
1381
- SmallVectorImpl<ProtocolDecl *> &protocols ) {
1391
+ static void canonicalizeProtocols (SmallVectorImpl<ProtocolDecl *> &protocols,
1392
+ ParameterizedProtocolMap *parameterized ) {
1382
1393
llvm::SmallDenseMap<ProtocolDecl *, unsigned > known;
1383
1394
bool zappedAny = false ;
1384
1395
@@ -1410,6 +1421,10 @@ void ProtocolType::canonicalizeProtocols(
1410
1421
1411
1422
auto found = known.find (inherited);
1412
1423
if (found != known.end ()) {
1424
+ // Don't zap protocols associated with parameterized types.
1425
+ if (parameterized && parameterized->count (inherited))
1426
+ return TypeWalker::Action::Continue;
1427
+
1413
1428
protocols[found->second ] = nullptr ;
1414
1429
zappedAny = true ;
1415
1430
}
@@ -1428,6 +1443,11 @@ void ProtocolType::canonicalizeProtocols(
1428
1443
llvm::array_pod_sort (protocols.begin (), protocols.end (), TypeDecl::compare);
1429
1444
}
1430
1445
1446
+ void ProtocolType::canonicalizeProtocols (
1447
+ SmallVectorImpl<ProtocolDecl *> &protocols) {
1448
+ return ::canonicalizeProtocols (protocols, nullptr );
1449
+ }
1450
+
1431
1451
static void
1432
1452
getCanonicalParams (AnyFunctionType *funcType,
1433
1453
CanGenericSignature genericSig,
@@ -4006,25 +4026,39 @@ Type ProtocolCompositionType::get(const ASTContext &C,
4006
4026
4007
4027
Type Superclass;
4008
4028
SmallVector<ProtocolDecl *, 4 > Protocols;
4029
+ ParameterizedProtocolMap Parameterized;
4009
4030
for (Type t : Members) {
4010
- addProtocols (t, Protocols, Superclass, HasExplicitAnyObject);
4031
+ addProtocols (t, Protocols, Parameterized, Superclass, HasExplicitAnyObject);
4011
4032
}
4012
-
4013
- // Minimize the set of protocols composed together.
4014
- ProtocolType::canonicalizeProtocols (Protocols);
4015
4033
4016
4034
// The presence of a superclass constraint makes AnyObject redundant.
4017
4035
if (Superclass)
4018
4036
HasExplicitAnyObject = false ;
4019
4037
4020
- // Form the set of canonical protocol types from the protocol
4021
- // declarations, and use that to build the canonical composition type.
4038
+ // If there are any parameterized protocols, the canonicalization
4039
+ // algorithm gets more complex.
4040
+
4041
+ // Form the set of canonical component types.
4022
4042
SmallVector<Type, 4 > CanTypes;
4023
4043
if (Superclass)
4024
4044
CanTypes.push_back (Superclass->getCanonicalType ());
4025
- llvm::transform (
4026
- Protocols, std::back_inserter (CanTypes),
4027
- [](ProtocolDecl *Proto) { return Proto->getDeclaredInterfaceType (); });
4045
+
4046
+ canonicalizeProtocols (Protocols, &Parameterized);
4047
+
4048
+ for (auto proto: Protocols) {
4049
+ // If we have a parameterized type for this protocol, use the
4050
+ // canonical type of that. Sema should prevent us from building
4051
+ // compositions with the same protocol and conflicting constraints.
4052
+ if (!Parameterized.empty ()) {
4053
+ auto it = Parameterized.find (proto);
4054
+ if (it != Parameterized.end ()) {
4055
+ CanTypes.push_back (it->second ->getCanonicalType ());
4056
+ continue ;
4057
+ }
4058
+ }
4059
+
4060
+ CanTypes.push_back (proto->getDeclaredInterfaceType ());
4061
+ }
4028
4062
4029
4063
// If one member remains and no layout constraint, return that type.
4030
4064
if (CanTypes.size () == 1 && !HasExplicitAnyObject)
0 commit comments