|
20 | 20 | #include "swift/AST/Availability.h" |
21 | 21 | #include "swift/AST/ConformanceLookup.h" |
22 | 22 | #include "swift/AST/Decl.h" |
| 23 | +#include "swift/AST/GenericEnvironment.h" |
23 | 24 | #include "swift/AST/InFlightSubstitution.h" |
24 | 25 | #include "swift/AST/Module.h" |
25 | 26 | #include "swift/AST/PackConformance.h" |
@@ -250,29 +251,58 @@ ProtocolConformanceRef |
250 | 251 | ProtocolConformanceRef::getAssociatedConformance(Type conformingType, |
251 | 252 | Type assocType, |
252 | 253 | ProtocolDecl *protocol) const { |
253 | | - // If this is a pack conformance, project the associated conformances. |
| 254 | + // If this is a pack conformance, project the associated conformances from |
| 255 | + // each pack element. |
254 | 256 | if (isPack()) { |
255 | 257 | auto *pack = getPack(); |
256 | 258 | assert(conformingType->isEqual(pack->getType())); |
257 | 259 | return ProtocolConformanceRef( |
258 | 260 | pack->getAssociatedConformance(assocType, protocol)); |
259 | 261 | } |
260 | 262 |
|
261 | | - // If this is a concrete conformance, look up the associated conformance. |
| 263 | + // If this is a concrete conformance, project the associated conformance. |
262 | 264 | if (isConcrete()) { |
263 | 265 | auto conformance = getConcrete(); |
264 | 266 | assert(conformance->getType()->isEqual(conformingType)); |
265 | 267 | return conformance->getAssociatedConformance(assocType, protocol); |
266 | 268 | } |
267 | 269 |
|
268 | | - // Otherwise, apply the substitution {self -> conformingType} |
269 | | - // to the abstract conformance requirement laid upon the dependent type |
270 | | - // by the protocol. |
271 | | - auto subMap = |
272 | | - SubstitutionMap::getProtocolSubstitutions(getRequirement(), |
273 | | - conformingType, *this); |
274 | | - auto abstractConf = ProtocolConformanceRef(protocol); |
275 | | - return abstractConf.subst(assocType, subMap); |
| 270 | + // An associated conformance of an archetype might be known to be |
| 271 | + // a concrete conformance, if the subject type is fixed to a concrete |
| 272 | + // type in the archetype's generic signature. We don't actually have |
| 273 | + // any way to recover the conformance in this case, except via global |
| 274 | + // conformance lookup. |
| 275 | + // |
| 276 | + // However, if we move to a first-class representation of abstract |
| 277 | + // conformances where they store their subject types, we can also |
| 278 | + // cache the lookups inside the abstract conformance instance too. |
| 279 | + if (auto archetypeType = conformingType->getAs<ArchetypeType>()) { |
| 280 | + conformingType = archetypeType->getInterfaceType(); |
| 281 | + auto *genericEnv = archetypeType->getGenericEnvironment(); |
| 282 | + |
| 283 | + auto subjectType = assocType.transformRec( |
| 284 | + [&](TypeBase *t) -> std::optional<Type> { |
| 285 | + if (isa<GenericTypeParamType>(t)) |
| 286 | + return conformingType; |
| 287 | + return std::nullopt; |
| 288 | + }); |
| 289 | + |
| 290 | + return lookupConformance( |
| 291 | + genericEnv->mapTypeIntoContext(subjectType), |
| 292 | + protocol); |
| 293 | + } |
| 294 | + |
| 295 | + // Associated conformances of type parameters and type variables |
| 296 | + // are always abstract, because we don't know the output generic |
| 297 | + // signature of the substitution (or in the case of type variables, |
| 298 | + // we have no visibility into constraints). See the parallel hack |
| 299 | + // to handle this in SubstitutionMap::lookupConformance(). |
| 300 | + CONDITIONAL_ASSERT(conformingType->isTypeParameter() || |
| 301 | + conformingType->isTypeVariableOrMember() || |
| 302 | + conformingType->is<UnresolvedType>() || |
| 303 | + conformingType->is<PlaceholderType>()); |
| 304 | + |
| 305 | + return ProtocolConformanceRef(protocol); |
276 | 306 | } |
277 | 307 |
|
278 | 308 | /// Check of all types used by the conformance are canonical. |
|
0 commit comments