mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fix ExistentialSpecializer: inherited conformance
The ExistentialSpecializer incorrectly assumed that an existential's conformances match an opened archetype. They don't. Opened archetypes strip inherited conformances per the ABI for generic argument passing. Existential values retain those inherited conformances (for some inexplicable reason). - Rename ASTContext::getExistentialSignature() to getOpenedArchetypeSiganture() because it was doing exactly the wrong thing for existentials. - Fix ConcreteExistentialInfo to produce the correct SubstitutionMap. - Fix ExistentialSpecializer to generate the correct conformances for init_existential by adding a collectExistentialConformances() helper. Fixes <rdar://problem/57025861> "Assertion failed: (conformances.size() == numConformanceRequirements)" in ExistentialSpecializer on inlined code
This commit is contained in:
@@ -243,11 +243,34 @@ void ConcreteExistentialInfo::initializeSubstitutionMap(
|
||||
|
||||
// Construct a single-generic-parameter substitution map directly to the
|
||||
// ConcreteType with this existential's full list of conformances.
|
||||
//
|
||||
// NOTE: getOpenedArchetypeSignature() generates the signature for passing an
|
||||
// opened existential as a generic parameter. No opened archetypes are
|
||||
// actually involved here--the API is only used as a convenient way to create
|
||||
// a substitution map. Since opened archetypes have different conformances
|
||||
// than their corresponding existential, ExistentialConformances needs to be
|
||||
// filtered when using it with this (phony) generic signature.
|
||||
CanGenericSignature ExistentialSig =
|
||||
M->getASTContext().getExistentialSignature(ExistentialType,
|
||||
M->getSwiftModule());
|
||||
ExistentialSubs = SubstitutionMap::get(ExistentialSig, {ConcreteType},
|
||||
ExistentialConformances);
|
||||
M->getASTContext().getOpenedArchetypeSignature(ExistentialType,
|
||||
M->getSwiftModule());
|
||||
ExistentialSubs = SubstitutionMap::get(
|
||||
ExistentialSig, [&](SubstitutableType *type) { return ConcreteType; },
|
||||
[&](CanType /*depType*/, Type /*replaceType*/,
|
||||
ProtocolDecl *proto) -> ProtocolConformanceRef {
|
||||
// Directly providing ExistentialConformances to the SubstitionMap will
|
||||
// fail because of the mismatch between opened archetype conformance and
|
||||
// existential value conformance. Instead, provide a conformance lookup
|
||||
// function that pulls only the necessary conformances out of
|
||||
// ExistentialConformances. This assumes that existential conformances
|
||||
// are a superset of opened archetype conformances.
|
||||
auto iter =
|
||||
llvm::find_if(ExistentialConformances,
|
||||
[&](const ProtocolConformanceRef &conformance) {
|
||||
return conformance.getRequirement() == proto;
|
||||
});
|
||||
assert(iter != ExistentialConformances.end() && "missing conformance");
|
||||
return *iter;
|
||||
});
|
||||
assert(isValid());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user