diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h index 7133f7927a2d8..12e113f900529 100644 --- a/include/swift/AST/GenericEnvironment.h +++ b/include/swift/AST/GenericEnvironment.h @@ -232,11 +232,21 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final /// Create a new generic environment for an opened existential. /// /// \param existential The subject existential type + /// \param uuid The unique identifier for this opened existential + static GenericEnvironment * + forOpenedExistential(Type existential, UUID uuid); + + /// Create a new generic environment for an opened existential. + /// + /// \param signature The opened existential signature + /// \param existential The generalized existential type /// \param outerSubs The substitution map containing archetypes from the /// outer generic context /// \param uuid The unique identifier for this opened existential static GenericEnvironment * - forOpenedExistential(Type existential, SubstitutionMap outerSubs, UUID uuid); + forOpenedExistential(GenericSignature signature, + Type existential, SubstitutionMap outerSubs, + UUID uuid); /// Create a new generic environment for an opened element. /// diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index 51d5f9ce01e1d..822e0f1ad345c 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -324,6 +324,19 @@ struct LookUpConformanceInOverrideSubs { ProtocolDecl *proto) const; }; +// Substitute the outer generic parameters from a substitution map, ignoring +/// inner generic parameters with a given depth. +struct OuterSubstitutions { + SubstitutionMap subs; + unsigned depth; + + bool isUnsubstitutedTypeParameter(Type type) const; + Type operator()(SubstitutableType *type) const; + ProtocolConformanceRef operator()(CanType dependentType, + Type conformingReplacementType, + ProtocolDecl *conformedProtocol) const; +}; + } // end namespace swift namespace llvm { diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index cb1c668bc46ee..cb00ab9726d08 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -387,7 +387,7 @@ class SILCloner : protected SILInstructionVisitor { auto substExistentialTy = getOpASTType(origExistentialTy); auto *newEnv = GenericEnvironment::forOpenedExistential( - substExistentialTy, subMap, UUID::fromTime()); + substExistentialTy, UUID::fromTime()); registerLocalArchetypeRemapping(origEnv, newEnv); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 18e6740b7fb0f..f92975b7b22c7 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5350,9 +5350,8 @@ CanOpenedArchetypeType OpenedArchetypeType::get(CanType existential, if (!knownID) knownID = UUID::fromTime(); - auto *genericEnv = - GenericEnvironment::forOpenedExistential( - existential, SubstitutionMap(), *knownID); + auto *genericEnv = GenericEnvironment::forOpenedExistential( + existential, *knownID); // Map the interface type into that environment. auto result = genericEnv->mapTypeIntoContext(interfaceType) @@ -5543,10 +5542,19 @@ GenericEnvironment *GenericEnvironment::forOpaqueType( return env; } +/// Create a new generic environment for an opened archetype. +GenericEnvironment * +GenericEnvironment::forOpenedExistential(Type existential, UUID uuid) { + auto &ctx = existential->getASTContext(); + auto signature = ctx.getOpenedExistentialSignature(existential, GenericSignature()); + return forOpenedExistential(signature, existential, SubstitutionMap(), uuid); +} + /// Create a new generic environment for an opened archetype. GenericEnvironment * GenericEnvironment::forOpenedExistential( - Type existential, SubstitutionMap subs, UUID uuid) { + GenericSignature signature, Type existential, + SubstitutionMap subs, UUID uuid) { assert(existential->isExistentialType()); // TODO: We could attempt to preserve type sugar in the substitution map. @@ -5568,15 +5576,13 @@ GenericEnvironment::forOpenedExistential( if (found != environments.end()) { auto *existingEnv = found->second; assert(existingEnv->getOpenedExistentialType()->isEqual(existential)); + assert(existingEnv->getGenericSignature().getPointer() == signature.getPointer()); assert(existingEnv->getOuterSubstitutions() == subs); assert(existingEnv->getOpenedExistentialUUID() == uuid); return existingEnv; } - auto parentSig = subs.getGenericSignature().getCanonicalSignature(); - auto signature = ctx.getOpenedExistentialSignature(existential, parentSig); - // Allocate and construct the new environment. unsigned numGenericParams = signature.getGenericParams().size(); size_t bytes = totalSizeToAlloc { private: Type visitProtocolType(CanProtocolType type) { // Simple protocol types have no sub-structure. - assert(!type.getParent() || !type.getParent()->isSpecialized()); return type; } diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 0bfc959d1e758..6411b9019ebaa 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -291,48 +291,6 @@ GenericEnvironment::getMappingIfPresent(GenericParamKey key) const { return std::nullopt; } -namespace { - -/// Substitute the outer generic parameters from a substitution map, ignoring -/// innter generic parameters with a given depth. -struct SubstituteOuterFromSubstitutionMap { - SubstitutionMap subs; - unsigned depth; - - /// Whether this is a type parameter that should not be substituted. - bool isUnsubstitutedTypeParameter(Type type) const { - if (!type->isTypeParameter()) - return false; - - if (auto depMemTy = type->getAs()) - return isUnsubstitutedTypeParameter(depMemTy->getBase()); - - if (auto genericParam = type->getAs()) - return genericParam->getDepth() >= depth; - - return false; - } - - Type operator()(SubstitutableType *type) const { - if (isUnsubstitutedTypeParameter(type)) - return Type(type); - - return QuerySubstitutionMap{subs}(type); - } - - ProtocolConformanceRef operator()(CanType dependentType, - Type conformingReplacementType, - ProtocolDecl *conformedProtocol) const { - if (isUnsubstitutedTypeParameter(dependentType)) - return ProtocolConformanceRef(conformedProtocol); - - return LookUpConformanceInSubstitutionMap(subs)( - dependentType, conformingReplacementType, conformedProtocol); - } -}; - -} - Type GenericEnvironment::maybeApplyOuterContextSubstitutions(Type type) const { switch (getKind()) { @@ -342,10 +300,8 @@ GenericEnvironment::maybeApplyOuterContextSubstitutions(Type type) const { case Kind::OpenedElement: case Kind::Opaque: { - auto packElements = getGenericSignature().getInnermostGenericParams(); - auto elementDepth = packElements.front()->getDepth(); - SubstituteOuterFromSubstitutionMap replacer{ - getOuterSubstitutions(), elementDepth}; + OuterSubstitutions replacer{ + getOuterSubstitutions(), getGenericSignature()->getMaxDepth()}; return type.subst(replacer, replacer); } } diff --git a/lib/AST/LocalArchetypeRequirementCollector.cpp b/lib/AST/LocalArchetypeRequirementCollector.cpp index 3e5398262e759..fcf1b57c0ace9 100644 --- a/lib/AST/LocalArchetypeRequirementCollector.cpp +++ b/lib/AST/LocalArchetypeRequirementCollector.cpp @@ -29,6 +29,9 @@ LocalArchetypeRequirementCollector::LocalArchetypeRequirementCollector( : Context(ctx), OuterSig(sig), Depth(sig.getNextDepth()) {} void LocalArchetypeRequirementCollector::addOpenedExistential(Type constraint) { + if (auto existential = constraint->getAs()) + constraint = existential->getConstraintType(); + assert(constraint->isConstraintType() || constraint->getClassOrBoundGenericClass()); assert(OuterSig || !constraint->hasTypeParameter() && @@ -134,10 +137,9 @@ GenericSignature swift::buildGenericSignatureWithCapturedEnvironments( break; case GenericEnvironment::Kind::OpenedExistential: { - auto constraint = genericEnv->getOpenedExistentialType(); - if (auto existential = constraint->getAs()) - constraint = existential->getConstraintType()->mapTypeOutOfContext(); - collector.addOpenedExistential(constraint); + auto existentialTy = genericEnv->getOpenedExistentialType() + ->mapTypeOutOfContext(); + collector.addOpenedExistential(existentialTy); continue; } case GenericEnvironment::Kind::OpenedElement: { diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 2be3a132f1d89..019b881a6a868 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -666,3 +666,35 @@ SubstitutionMap SubstitutionMap::mapIntoTypeExpansionContext( SubstFlags::SubstituteOpaqueArchetypes | SubstFlags::PreservePackExpansionLevel); } + +bool OuterSubstitutions::isUnsubstitutedTypeParameter(Type type) const { + if (!type->isTypeParameter()) + return false; + + if (auto depMemTy = type->getAs()) + return isUnsubstitutedTypeParameter(depMemTy->getBase()); + + if (auto genericParam = type->getAs()) + return genericParam->getDepth() >= depth; + + return false; +} + +Type OuterSubstitutions::operator()(SubstitutableType *type) const { + if (isUnsubstitutedTypeParameter(type)) + return Type(type); + + return QuerySubstitutionMap{subs}(type); +} + +ProtocolConformanceRef OuterSubstitutions::operator()( + CanType dependentType, + Type conformingReplacementType, + ProtocolDecl *conformedProtocol) const { + if (isUnsubstitutedTypeParameter(dependentType)) + return ProtocolConformanceRef(conformedProtocol); + + return LookUpConformanceInSubstitutionMap(subs)( + dependentType, conformingReplacementType, conformedProtocol); +} + diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 166b7f39519c1..49d2783937033 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3398,7 +3398,10 @@ Type ArchetypeType::getExistentialType() const { auto genericSig = genericEnv->getGenericSignature(); auto existentialType = genericSig->getExistentialType(interfaceType); - return genericEnv->mapTypeIntoContext(existentialType); + if (existentialType->hasTypeParameter()) + existentialType = genericEnv->mapTypeIntoContext(existentialType); + + return existentialType; } bool ArchetypeType::requiresClass() const { diff --git a/lib/SILOptimizer/Utils/Existential.cpp b/lib/SILOptimizer/Utils/Existential.cpp index 64655b421c1ba..9ca2114a3f255 100644 --- a/lib/SILOptimizer/Utils/Existential.cpp +++ b/lib/SILOptimizer/Utils/Existential.cpp @@ -12,6 +12,7 @@ #include "swift/SILOptimizer/Utils/Existential.h" #include "swift/AST/ConformanceLookup.h" +#include "swift/AST/LocalArchetypeRequirementCollector.h" #include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Assertions.h" #include "swift/SIL/BasicBlockUtils.h" @@ -250,15 +251,20 @@ void ConcreteExistentialInfo::initializeSubstitutionMap( // Construct a single-generic-parameter substitution map directly to the // ConcreteType with this existential's full list of conformances. // - // NOTE: getOpenedExistentialSignature() generates the signature for passing an + // NOTE: LocalArchetypeRequirementCollector 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().getOpenedExistentialSignature(ExistentialType, - GenericSignature()); + + auto &ctx = M->getASTContext(); + LocalArchetypeRequirementCollector collector(ctx, CanGenericSignature()); + collector.addOpenedExistential(ExistentialType); + auto ExistentialSig = buildGenericSignature( + ctx, collector.OuterSig, collector.Params, collector.Requirements, + /*allowInverses=*/true).getCanonicalSignature(); + ExistentialSubs = SubstitutionMap::get( ExistentialSig, [&](SubstitutableType *type) { return ConcreteType; }, [&](CanType /*depType*/, Type /*replaceType*/, diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 2c156e62d2355..70a3e27206f44 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2265,26 +2265,14 @@ static bool isMainDispatchQueueMember(ConstraintLocator *locator) { return true; } -/// Transforms `refTy` as follows. -/// -/// For each occurrence of a type **type** that satisfies `predicateFn` in -/// covariant position: -/// 1. **type** is projected to a type parameter using `projectionFn`. -/// 2. If the type parameter is not bound to a concrete type, it is type-erased -/// to the most specific upper bounds using `existentialSig` and substituted -/// for **type**. Otherwise, the concrete type is transformed recursively. -/// The result is substituted for **type** unless it is an identity -/// transform. -/// -/// `baseTy` is used as a ready substitution for the `Self` generic parameter. -/// -/// @param force If `true`, proceeds regardless of a type's variance position. +/// For each occurrence of a type **type** in `refTy` that satisfies +/// `predicateFn` in covariant position, **type** is erased to an +/// existential using `eraseFn`. static Type typeEraseExistentialSelfReferences( - Type refTy, Type baseTy, TypePosition outermostPosition, - GenericSignature existentialSig, llvm::function_ref containsFn, + Type refTy, TypePosition outermostPosition, + llvm::function_ref containsFn, llvm::function_ref predicateFn, - llvm::function_ref projectionFn, bool force) { - assert(baseTy->isExistentialType()); + llvm::function_ref eraseFn) { if (!containsFn(refTy)) return refTy; @@ -2298,8 +2286,8 @@ static Type typeEraseExistentialSelfReferences( if (t->is()) { const auto instanceTy = t->getMetatypeInstanceType(); auto erasedTy = typeEraseExistentialSelfReferences( - instanceTy, baseTy, currPos, existentialSig, containsFn, - predicateFn, projectionFn, force); + instanceTy, currPos, + containsFn, predicateFn, eraseFn); if (instanceTy.getPointer() == erasedTy.getPointer()) { return Type(t); } @@ -2327,8 +2315,8 @@ static Type typeEraseExistentialSelfReferences( for (auto replacementType : opaque->getSubstitutions().getReplacementTypes()) { auto erasedReplacementType = typeEraseExistentialSelfReferences( - replacementType, baseTy, TypePosition::Covariant, - existentialSig, containsFn, predicateFn, projectionFn, force); + replacementType, TypePosition::Covariant, + containsFn, predicateFn, eraseFn); if (erasedReplacementType.getPointer() != replacementType.getPointer()) return opaque->getExistentialType(); @@ -2340,8 +2328,8 @@ static Type typeEraseExistentialSelfReferences( if (auto parameterized = dyn_cast(t)) { for (auto argType : parameterized->getArgs()) { auto erasedArgType = typeEraseExistentialSelfReferences( - argType, baseTy, TypePosition::Covariant, existentialSig, - containsFn, predicateFn, projectionFn, force); + argType, TypePosition::Covariant, + containsFn, predicateFn, eraseFn); if (erasedArgType.getPointer() != argType.getPointer()) return parameterized->getBaseType(); } @@ -2351,9 +2339,8 @@ static Type typeEraseExistentialSelfReferences( auto objTy = lvalue->getObjectType(); auto erasedTy = typeEraseExistentialSelfReferences( - objTy, baseTy, currPos, - existentialSig, containsFn, predicateFn, projectionFn, - force); + objTy, currPos, + containsFn, predicateFn, eraseFn); if (erasedTy.getPointer() == objTy.getPointer()) return Type(lvalue); @@ -2367,52 +2354,10 @@ static Type typeEraseExistentialSelfReferences( return std::nullopt; } - auto paramTy = projectionFn(t); - if (!paramTy) + auto erasedTy = eraseFn(t, currPos); + if (!erasedTy) return Type(t); - assert(paramTy->isTypeParameter()); - - // This can happen with invalid code. - if (!existentialSig->isValidTypeParameter(paramTy)) { - return Type(t); - } - - // If the type parameter is fixed to a concrete type, recurse into it. - if (const auto concreteTy = existentialSig->getConcreteType(paramTy)) { - auto erasedTy = typeEraseExistentialSelfReferences( - concreteTy, baseTy, currPos, existentialSig, - [](Type t) { return t->hasTypeParameter(); }, - [](Type t) { return t->isTypeParameter(); }, - [](Type t) { return t; }, force); - if (erasedTy.getPointer() == concreteTy.getPointer()) { - return Type(t); - } - - return erasedTy; - } - - if (!force) { - switch (currPos) { - case TypePosition::Covariant: - break; - - case TypePosition::Contravariant: - case TypePosition::Invariant: - case TypePosition::Shape: - return Type(t); - } - } - - Type erasedTy; - - // The upper bounds of 'Self' is the existential base type. - if (paramTy->is()) { - erasedTy = baseTy; - } else { - erasedTy = existentialSig->getExistentialType(paramTy); - } - return erasedTy; }); } @@ -2422,23 +2367,53 @@ Type constraints::typeEraseOpenedExistentialReference( TypePosition outermostPosition) { auto existentialSig = type->getASTContext().getOpenedExistentialSignature( - existentialBaseType, GenericSignature()); - auto selfGP = existentialSig.getGenericParams()[0]; + existentialBaseType); + + auto applyOuterSubstitutions = [&](Type t) -> Type { + if (t->hasTypeParameter()) { + auto outerSubs = existentialSig.Generalization; + unsigned depth = existentialSig.OpenedSig->getMaxDepth(); + OuterSubstitutions replacer{outerSubs, depth}; + return t.subst(replacer, replacer); + } + + return t; + }; + + auto erase = [&](Type paramTy, TypePosition currPos) -> Type { + switch (currPos) { + case TypePosition::Covariant: + break; + + case TypePosition::Contravariant: + case TypePosition::Invariant: + case TypePosition::Shape: + return Type(); + } + + // The upper bounds of 'Self' is the existential base type. + if (paramTy->is()) + return existentialBaseType; + + return applyOuterSubstitutions( + existentialSig.OpenedSig->getExistentialType(paramTy)); + }; return typeEraseExistentialSelfReferences( - type, existentialBaseType, outermostPosition, existentialSig, + type, + outermostPosition, /*containsFn=*/[](Type t) { return t->hasTypeVariable(); }, /*predicateFn=*/[](Type t) { return t->isTypeVariableOrMember(); }, - /*projectionFn=*/[&](Type t) { + /*eraseFn=*/[&](Type t, TypePosition currPos) -> Type { bool found = false; - auto result = t.transformRec([&](Type t) -> std::optional { + auto paramTy = t.transformRec([&](Type t) -> std::optional { if (t.getPointer() == openedTypeVar) { found = true; - return selfGP; + return existentialSig.SelfType; } return std::nullopt; }); @@ -2446,34 +2421,55 @@ Type constraints::typeEraseOpenedExistentialReference( if (!found) return Type(); - assert(result->isTypeParameter()); - return result; - }, - /*force=*/false); + assert(paramTy->isTypeParameter()); + + // This can happen with invalid code. + if (!existentialSig.OpenedSig->isValidTypeParameter(paramTy)) { + return Type(t); + } + + // Check if this existential fixes this `Self`-rooted type to something + // in the existential's outer generic signature. + Type reducedTy = existentialSig.OpenedSig.getReducedType(paramTy); + if (!reducedTy->isEqual(paramTy)) { + reducedTy = applyOuterSubstitutions(reducedTy); + + auto erasedTy = typeEraseExistentialSelfReferences( + reducedTy, currPos, + [&](Type t) { return t->hasTypeParameter(); }, + [&](Type t) { return t->isTypeParameter(); }, + [&](Type t, TypePosition currPos) { return erase(t, currPos); }); + if (erasedTy.getPointer() == reducedTy.getPointer()) { + return Type(t); + } + + return erasedTy; + } + + return erase(paramTy, currPos); + }); } Type constraints::typeEraseOpenedArchetypesFromEnvironment( Type type, GenericEnvironment *env) { assert(env->getKind() == GenericEnvironment::Kind::OpenedExistential); - auto sig = env->getGenericSignature(); - return typeEraseExistentialSelfReferences( - type, env->getOpenedExistentialType(), TypePosition::Covariant, sig, + type, + TypePosition::Covariant, /*containsFn=*/[](Type t) { return t->hasOpenedExistential(); }, /*predicateFn=*/[](Type t) { return t->is(); }, - /*projectionFn=*/[&](Type t) { + /*eraseFn=*/[&](Type t, TypePosition currPos) { auto *openedTy = t->castTo(); if (openedTy->getGenericEnvironment() == env) - return openedTy->getInterfaceType(); + return openedTy->getExistentialType(); return Type(); - }, - /*force=*/true); + }); } static bool isExistentialMemberAccessWithExplicitBaseExpression( diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 30f6f29ef5935..193801be73e12 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2863,7 +2863,7 @@ TypeResolver::resolveOpenedExistentialArchetype( // The opened existential type is formed by mapping the interface type // into a new opened generic environment. auto *env = GenericEnvironment::forOpenedExistential( - constraintType->getCanonicalType(), SubstitutionMap(), + constraintType->getCanonicalType(), openedAttr->getUUID()); return env->mapTypeIntoContext(interfaceType); } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 8def1b99521f8..6762860e058cc 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1660,7 +1660,10 @@ Expected ModuleFile::getGenericEnvironmentChecked( switch (GenericEnvironmentKind(kind)) { case GenericEnvironmentKind::OpenedExistential: genericEnv = GenericEnvironment::forOpenedExistential( - existentialOrShapeTypeOrError.get(), contextSubsOrError.get(), UUID::fromTime()); + genericSigOrError.get(), + existentialOrShapeTypeOrError.get(), + contextSubsOrError.get(), + UUID::fromTime()); break; case GenericEnvironmentKind::OpenedElement: diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index b55bb4d504eda..0c37af03e7c1d 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 886; // SIL function thunk kind +const uint16_t SWIFTMODULE_VERSION_MINOR = 887; // extravagant opened existentials /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index ef2f249a1c949..c963a77f537d2 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1667,7 +1667,7 @@ void Serializer::writeASTBlockEntity(const GenericEnvironment *genericEnv) { case GenericEnvironment::Kind::OpenedExistential: { auto kind = GenericEnvironmentKind::OpenedExistential; auto existentialTypeID = addTypeRef(genericEnv->getOpenedExistentialType()); - auto parentSigID = addGenericSignatureRef(GenericSignature()); + auto parentSigID = addGenericSignatureRef(genericEnv->getGenericSignature()); auto contextSubs = genericEnv->getOuterSubstitutions(); auto subsID = addSubstitutionMapRef(contextSubs); @@ -1681,8 +1681,7 @@ void Serializer::writeASTBlockEntity(const GenericEnvironment *genericEnv) { case GenericEnvironment::Kind::OpenedElement: { auto kind = GenericEnvironmentKind::OpenedElement; auto shapeClassID = addTypeRef(genericEnv->getOpenedElementShapeClass()); - auto parentSig = genericEnv->getGenericSignature(); - auto parentSigID = addGenericSignatureRef(parentSig); + auto parentSigID = addGenericSignatureRef(genericEnv->getGenericSignature()); auto contextSubs = genericEnv->getOuterSubstitutions(); auto subsID = addSubstitutionMapRef(contextSubs);