@@ -1334,10 +1334,14 @@ Type TypeBase::getMetatypeInstanceType() {
1334
1334
return this ;
1335
1335
}
1336
1336
1337
+ using ParameterizedProtocolMap =
1338
+ llvm::DenseMap<ProtocolDecl *, ParameterizedProtocolType *>;
1339
+
1337
1340
// / Collect the protocols in the existential type T into the given
1338
1341
// / vector.
1339
1342
static void addProtocols (Type T,
1340
1343
SmallVectorImpl<ProtocolDecl *> &Protocols,
1344
+ ParameterizedProtocolMap &Parameterized,
1341
1345
Type &Superclass,
1342
1346
bool &HasExplicitAnyObject) {
1343
1347
if (auto Proto = T->getAs <ProtocolType>()) {
@@ -1349,7 +1353,14 @@ static void addProtocols(Type T,
1349
1353
if (PC->hasExplicitAnyObject ())
1350
1354
HasExplicitAnyObject = true ;
1351
1355
for (auto P : PC->getMembers ())
1352
- addProtocols (P, Protocols, Superclass, HasExplicitAnyObject);
1356
+ addProtocols (P, Protocols, Parameterized, Superclass,
1357
+ HasExplicitAnyObject);
1358
+ return ;
1359
+ }
1360
+
1361
+ if (auto PP = T->getAs <ParameterizedProtocolType>()) {
1362
+ Parameterized.insert ({PP->getProtocol (), PP});
1363
+ Protocols.push_back (PP->getProtocol ());
1353
1364
return ;
1354
1365
}
1355
1366
@@ -1391,8 +1402,8 @@ bool ProtocolType::visitAllProtocols(
1391
1402
return false ;
1392
1403
}
1393
1404
1394
- void ProtocolType:: canonicalizeProtocols (
1395
- SmallVectorImpl<ProtocolDecl *> &protocols ) {
1405
+ static void canonicalizeProtocols (SmallVectorImpl<ProtocolDecl *> &protocols,
1406
+ ParameterizedProtocolMap *parameterized ) {
1396
1407
llvm::SmallDenseMap<ProtocolDecl *, unsigned > known;
1397
1408
bool zappedAny = false ;
1398
1409
@@ -1424,6 +1435,10 @@ void ProtocolType::canonicalizeProtocols(
1424
1435
1425
1436
auto found = known.find (inherited);
1426
1437
if (found != known.end ()) {
1438
+ // Don't zap protocols associated with parameterized types.
1439
+ if (parameterized && parameterized->count (inherited))
1440
+ return TypeWalker::Action::Continue;
1441
+
1427
1442
protocols[found->second ] = nullptr ;
1428
1443
zappedAny = true ;
1429
1444
}
@@ -1442,6 +1457,11 @@ void ProtocolType::canonicalizeProtocols(
1442
1457
llvm::array_pod_sort (protocols.begin (), protocols.end (), TypeDecl::compare);
1443
1458
}
1444
1459
1460
+ void ProtocolType::canonicalizeProtocols (
1461
+ SmallVectorImpl<ProtocolDecl *> &protocols) {
1462
+ return ::canonicalizeProtocols (protocols, nullptr );
1463
+ }
1464
+
1445
1465
static void
1446
1466
getCanonicalParams (AnyFunctionType *funcType,
1447
1467
CanGenericSignature genericSig,
@@ -4020,25 +4040,39 @@ Type ProtocolCompositionType::get(const ASTContext &C,
4020
4040
4021
4041
Type Superclass;
4022
4042
SmallVector<ProtocolDecl *, 4 > Protocols;
4043
+ ParameterizedProtocolMap Parameterized;
4023
4044
for (Type t : Members) {
4024
- addProtocols (t, Protocols, Superclass, HasExplicitAnyObject);
4045
+ addProtocols (t, Protocols, Parameterized, Superclass, HasExplicitAnyObject);
4025
4046
}
4026
-
4027
- // Minimize the set of protocols composed together.
4028
- ProtocolType::canonicalizeProtocols (Protocols);
4029
4047
4030
4048
// The presence of a superclass constraint makes AnyObject redundant.
4031
4049
if (Superclass)
4032
4050
HasExplicitAnyObject = false ;
4033
4051
4034
- // Form the set of canonical protocol types from the protocol
4035
- // declarations, and use that to build the canonical composition type.
4052
+ // If there are any parameterized protocols, the canonicalization
4053
+ // algorithm gets more complex.
4054
+
4055
+ // Form the set of canonical component types.
4036
4056
SmallVector<Type, 4 > CanTypes;
4037
4057
if (Superclass)
4038
4058
CanTypes.push_back (Superclass->getCanonicalType ());
4039
- llvm::transform (
4040
- Protocols, std::back_inserter (CanTypes),
4041
- [](ProtocolDecl *Proto) { return Proto->getDeclaredInterfaceType (); });
4059
+
4060
+ canonicalizeProtocols (Protocols, &Parameterized);
4061
+
4062
+ for (auto proto: Protocols) {
4063
+ // If we have a parameterized type for this protocol, use the
4064
+ // canonical type of that. Sema should prevent us from building
4065
+ // compositions with the same protocol and conflicting constraints.
4066
+ if (!Parameterized.empty ()) {
4067
+ auto it = Parameterized.find (proto);
4068
+ if (it != Parameterized.end ()) {
4069
+ CanTypes.push_back (it->second ->getCanonicalType ());
4070
+ continue ;
4071
+ }
4072
+ }
4073
+
4074
+ CanTypes.push_back (proto->getDeclaredInterfaceType ());
4075
+ }
4042
4076
4043
4077
// If one member remains and no layout constraint, return that type.
4044
4078
if (CanTypes.size () == 1 && !HasExplicitAnyObject)
0 commit comments