Skip to content

Commit 9afff03

Browse files
committed
AST: Re-implement ProtocolConformanceRef::getAssociatedConformance() as a primitive
1 parent a911693 commit 9afff03

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

lib/AST/ProtocolConformanceRef.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/Availability.h"
2121
#include "swift/AST/ConformanceLookup.h"
2222
#include "swift/AST/Decl.h"
23+
#include "swift/AST/GenericEnvironment.h"
2324
#include "swift/AST/InFlightSubstitution.h"
2425
#include "swift/AST/Module.h"
2526
#include "swift/AST/PackConformance.h"
@@ -250,29 +251,58 @@ ProtocolConformanceRef
250251
ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
251252
Type assocType,
252253
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.
254256
if (isPack()) {
255257
auto *pack = getPack();
256258
assert(conformingType->isEqual(pack->getType()));
257259
return ProtocolConformanceRef(
258260
pack->getAssociatedConformance(assocType, protocol));
259261
}
260262

261-
// If this is a concrete conformance, look up the associated conformance.
263+
// If this is a concrete conformance, project the associated conformance.
262264
if (isConcrete()) {
263265
auto conformance = getConcrete();
264266
assert(conformance->getType()->isEqual(conformingType));
265267
return conformance->getAssociatedConformance(assocType, protocol);
266268
}
267269

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);
276306
}
277307

278308
/// Check of all types used by the conformance are canonical.

0 commit comments

Comments
 (0)