|
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