@@ -1334,10 +1334,14 @@ Type TypeBase::getMetatypeInstanceType() {
13341334 return this ;
13351335}
13361336
1337+ using ParameterizedProtocolMap =
1338+ llvm::DenseMap<ProtocolDecl *, ParameterizedProtocolType *>;
1339+
13371340// / Collect the protocols in the existential type T into the given
13381341// / vector.
13391342static void addProtocols (Type T,
13401343 SmallVectorImpl<ProtocolDecl *> &Protocols,
1344+ ParameterizedProtocolMap &Parameterized,
13411345 Type &Superclass,
13421346 bool &HasExplicitAnyObject) {
13431347 if (auto Proto = T->getAs <ProtocolType>()) {
@@ -1349,7 +1353,14 @@ static void addProtocols(Type T,
13491353 if (PC->hasExplicitAnyObject ())
13501354 HasExplicitAnyObject = true ;
13511355 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 ());
13531364 return ;
13541365 }
13551366
@@ -1391,8 +1402,8 @@ bool ProtocolType::visitAllProtocols(
13911402 return false ;
13921403}
13931404
1394- void ProtocolType:: canonicalizeProtocols (
1395- SmallVectorImpl<ProtocolDecl *> &protocols ) {
1405+ static void canonicalizeProtocols (SmallVectorImpl<ProtocolDecl *> &protocols,
1406+ ParameterizedProtocolMap *parameterized ) {
13961407 llvm::SmallDenseMap<ProtocolDecl *, unsigned > known;
13971408 bool zappedAny = false ;
13981409
@@ -1424,6 +1435,10 @@ void ProtocolType::canonicalizeProtocols(
14241435
14251436 auto found = known.find (inherited);
14261437 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+
14271442 protocols[found->second ] = nullptr ;
14281443 zappedAny = true ;
14291444 }
@@ -1442,6 +1457,11 @@ void ProtocolType::canonicalizeProtocols(
14421457 llvm::array_pod_sort (protocols.begin (), protocols.end (), TypeDecl::compare);
14431458}
14441459
1460+ void ProtocolType::canonicalizeProtocols (
1461+ SmallVectorImpl<ProtocolDecl *> &protocols) {
1462+ return ::canonicalizeProtocols (protocols, nullptr );
1463+ }
1464+
14451465static void
14461466getCanonicalParams (AnyFunctionType *funcType,
14471467 CanGenericSignature genericSig,
@@ -4020,25 +4040,39 @@ Type ProtocolCompositionType::get(const ASTContext &C,
40204040
40214041 Type Superclass;
40224042 SmallVector<ProtocolDecl *, 4 > Protocols;
4043+ ParameterizedProtocolMap Parameterized;
40234044 for (Type t : Members) {
4024- addProtocols (t, Protocols, Superclass, HasExplicitAnyObject);
4045+ addProtocols (t, Protocols, Parameterized, Superclass, HasExplicitAnyObject);
40254046 }
4026-
4027- // Minimize the set of protocols composed together.
4028- ProtocolType::canonicalizeProtocols (Protocols);
40294047
40304048 // The presence of a superclass constraint makes AnyObject redundant.
40314049 if (Superclass)
40324050 HasExplicitAnyObject = false ;
40334051
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.
40364056 SmallVector<Type, 4 > CanTypes;
40374057 if (Superclass)
40384058 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+ }
40424076
40434077 // If one member remains and no layout constraint, return that type.
40444078 if (CanTypes.size () == 1 && !HasExplicitAnyObject)
0 commit comments