Skip to content

Allow type variables to appear inside opened existential archetypes #76238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1446,19 +1446,6 @@ class ASTContext final {
/// like `<T>`.
CanGenericSignature getSingleGenericParameterSignature() const;

/// Retrieve a generic signature with a single type parameter conforming
/// to the given protocol or composition type, like <T: P>.
///
/// The opened archetype may have a different set of conformances from the
/// corresponding existential. The opened archetype conformances are dictated
/// by the ABI for generic arguments, while the existential value conformances
/// are dictated by their layout (see \c Type::getExistentialLayout()). In
/// particular, the opened archetype signature does not have requirements for
/// conformances inherited from superclass constraints while existential
/// values do.
CanGenericSignature getOpenedExistentialSignature(Type type,
GenericSignature parentSig);

/// Retrieve a generic signature with a single type parameter conforming
/// to the given protocol or composition type, like <T: P>.
///
Expand Down
25 changes: 24 additions & 1 deletion include/swift/AST/TypeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifndef SWIFT_AST_TYPETRANSFORM_H
#define SWIFT_AST_TYPETRANSFORM_H

#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/SILLayout.h"

namespace swift {
Expand Down Expand Up @@ -136,7 +137,29 @@ case TypeKind::Id:
newSubMap);
}

case TypeKind::OpenedArchetype:
case TypeKind::OpenedArchetype: {
auto *local = cast<LocalArchetypeType>(base);
if (auto result = asDerived().transformLocalArchetypeType(local, pos))
return *result;

auto *env = local->getGenericEnvironment();

auto genericSig = env->getGenericSignature();
auto existentialTy = env->getOpenedExistentialType();
auto subMap = env->getOuterSubstitutions();
auto uuid = env->getOpenedExistentialUUID();

auto newSubMap = asDerived().transformSubMap(subMap);
if (newSubMap == subMap)
return t;
if (!newSubMap)
return Type();

auto *newEnv = GenericEnvironment::forOpenedExistential(
genericSig, existentialTy, newSubMap, uuid);
return newEnv->mapTypeIntoContext(local->getInterfaceType());
}

case TypeKind::ElementArchetype: {
auto *local = cast<LocalArchetypeType>(base);
if (auto result = asDerived().transformLocalArchetypeType(local, pos))
Expand Down
12 changes: 0 additions & 12 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6785,15 +6785,6 @@ class OpenedArchetypeType final : public LocalArchetypeType,
ArrayRef<ProtocolDecl *> conformsTo, Type superclass,
LayoutConstraint layout);

public:
/// Compute the parameter that serves as the \c Self type for an opened
/// archetype from the given outer generic signature.
///
/// This type is a generic parameter one level deeper
/// than the deepest generic context depth.
static Type getSelfInterfaceTypeFromContext(GenericSignature parentSig,
ASTContext &ctx);

public:
/// Get or create an archetype that represents the opened type
/// of an existential value.
Expand All @@ -6814,9 +6805,6 @@ class OpenedArchetypeType final : public LocalArchetypeType,
/// \param existential The existential type or existential metatype to open.
static Type getAny(Type existential);

/// Retrieve the ID number of this opened existential.
UUID getOpenedExistentialID() const;

static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::OpenedArchetype;
}
Expand Down
33 changes: 13 additions & 20 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
/// Register a re-mapping for local archetypes such as opened existentials.
void registerLocalArchetypeRemapping(GenericEnvironment *From,
GenericEnvironment *To) {
ASSERT(From->getGenericSignature()->getMaxDepth()
== To->getGenericSignature()->getMaxDepth());
ASSERT(From->getGenericSignature().getPointer()
== To->getGenericSignature().getPointer());

auto result = Functor.LocalArchetypeSubs.insert(std::make_pair(From, To));
assert(result.second);
Expand Down Expand Up @@ -380,14 +380,14 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {

void remapRootOpenedType(CanOpenedArchetypeType archetypeTy) {
auto *origEnv = archetypeTy->getGenericEnvironment();

auto genericSig = origEnv->getGenericSignature();
auto existentialTy = origEnv->getOpenedExistentialType();
auto subMap = origEnv->getOuterSubstitutions();
ASSERT(!subMap && "Transform the substitution map!");
auto origExistentialTy = origEnv->getOpenedExistentialType()
->getCanonicalType();

auto substExistentialTy = getOpASTType(origExistentialTy);
auto *newEnv = GenericEnvironment::forOpenedExistential(
substExistentialTy, UUID::fromTime());
genericSig, existentialTy, getOpSubstitutionMap(subMap),
UUID::fromTime());

registerLocalArchetypeRemapping(origEnv, newEnv);
}
Expand Down Expand Up @@ -2675,7 +2675,7 @@ template<typename ImplClass>
void
SILCloner<ImplClass>::visitOpenExistentialAddrInst(OpenExistentialAddrInst *Inst) {
// Create a new archetype for this opened existential type.
remapRootOpenedType(Inst->getType().castTo<OpenedArchetypeType>());
remapRootOpenedType(Inst->getDefinedOpenedArchetype());

getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Expand All @@ -2688,7 +2688,7 @@ template <typename ImplClass>
void SILCloner<ImplClass>::visitOpenExistentialValueInst(
OpenExistentialValueInst *Inst) {
// Create a new archetype for this opened existential type.
remapRootOpenedType(Inst->getType().castTo<OpenedArchetypeType>());
remapRootOpenedType(Inst->getDefinedOpenedArchetype());

getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Expand All @@ -2704,14 +2704,7 @@ template<typename ImplClass>
void
SILCloner<ImplClass>::
visitOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *Inst) {
// Create a new archetype for this opened existential type.
auto openedType = Inst->getType().getASTType();
auto exType = Inst->getOperand()->getType().getASTType();
while (auto exMetatype = dyn_cast<ExistentialMetatypeType>(exType)) {
exType = exMetatype->getExistentialInstanceType()->getCanonicalType();
openedType = cast<MetatypeType>(openedType).getInstanceType();
}
remapRootOpenedType(cast<OpenedArchetypeType>(openedType));
remapRootOpenedType(Inst->getDefinedOpenedArchetype());

if (!Inst->getOperand()->getType().canUseExistentialRepresentation(
ExistentialRepresentation::Class)) {
Expand All @@ -2735,7 +2728,7 @@ void
SILCloner<ImplClass>::
visitOpenExistentialRefInst(OpenExistentialRefInst *Inst) {
// Create a new archetype for this opened existential type.
remapRootOpenedType(Inst->getType().castTo<OpenedArchetypeType>());
remapRootOpenedType(Inst->getDefinedOpenedArchetype());

getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Expand All @@ -2752,7 +2745,7 @@ void
SILCloner<ImplClass>::
visitOpenExistentialBoxInst(OpenExistentialBoxInst *Inst) {
// Create a new archetype for this opened existential type.
remapRootOpenedType(Inst->getType().castTo<OpenedArchetypeType>());
remapRootOpenedType(Inst->getDefinedOpenedArchetype());

getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst, getBuilder().createOpenExistentialBox(
Expand All @@ -2766,7 +2759,7 @@ void
SILCloner<ImplClass>::
visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *Inst) {
// Create a new archetype for this opened existential type.
remapRootOpenedType(Inst->getType().castTo<OpenedArchetypeType>());
remapRootOpenedType(Inst->getDefinedOpenedArchetype());

getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Expand Down
90 changes: 27 additions & 63 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,6 @@ struct ASTContext::Implementation {
/// The single-parameter generic signature with no constraints, <T>.
CanGenericSignature SingleGenericParameterSignature;

/// The existential signature <T : P> for each P.
llvm::DenseMap<std::pair<CanType, const GenericSignatureImpl *>, CanGenericSignature>
ExistentialSignatures;

/// The element signature for a generic signature, which contains a clone
/// of the context generic signature with new type parameters and requirements
/// for opened pack elements in the given shape equivalence class.
Expand Down Expand Up @@ -851,7 +847,6 @@ void ASTContext::Implementation::dump(llvm::raw_ostream &os) const {
SIZE_AND_BYTES(AssociativityCache);
SIZE_AND_BYTES(DelayedConformanceDiags);
SIZE_AND_BYTES(LazyContexts);
SIZE_AND_BYTES(ExistentialSignatures);
SIZE_AND_BYTES(ElementSignatures);
SIZE_AND_BYTES(Overrides);
SIZE_AND_BYTES(DefaultWitnesses);
Expand Down Expand Up @@ -5342,22 +5337,21 @@ CanTypeWrapper<OpenedArchetypeType> OpenedArchetypeType::getNew(

CanOpenedArchetypeType OpenedArchetypeType::get(CanType existential,
std::optional<UUID> knownID) {
assert(existential->isExistentialType());
assert(!existential->hasTypeParameter());

auto interfaceType = OpenedArchetypeType::getSelfInterfaceTypeFromContext(
GenericSignature(), existential->getASTContext());
auto &ctx = existential->getASTContext();
auto existentialSig = ctx.getOpenedExistentialSignature(existential);

if (!knownID)
knownID = UUID::fromTime();

auto *genericEnv = GenericEnvironment::forOpenedExistential(
existential, *knownID);
existentialSig.OpenedSig,
existentialSig.Shape,
existentialSig.Generalization,
*knownID);

// Map the interface type into that environment.
auto result = genericEnv->mapTypeIntoContext(interfaceType)
->castTo<OpenedArchetypeType>();
return CanOpenedArchetypeType(result);
return cast<OpenedArchetypeType>(
genericEnv->mapTypeIntoContext(existentialSig.SelfType)
->getCanonicalType());
}

Type OpenedArchetypeType::getAny(Type existential) {
Expand Down Expand Up @@ -5547,8 +5541,10 @@ GenericEnvironment *GenericEnvironment::forOpaqueType(
GenericEnvironment *
GenericEnvironment::forOpenedExistential(Type existential, UUID uuid) {
auto &ctx = existential->getASTContext();
auto signature = ctx.getOpenedExistentialSignature(existential, GenericSignature());
return forOpenedExistential(signature, existential, SubstitutionMap(), uuid);
auto existentialSig = ctx.getOpenedExistentialSignature(existential);
return forOpenedExistential(existentialSig.OpenedSig,
existentialSig.Shape,
existentialSig.Generalization, uuid);
}

/// Create a new generic environment for an opened archetype.
Expand Down Expand Up @@ -6136,83 +6132,51 @@ CanGenericSignature ASTContext::getSingleGenericParameterSignature() const {
return canonicalSig;
}

Type OpenedArchetypeType::getSelfInterfaceTypeFromContext(GenericSignature parentSig,
ASTContext &ctx) {
return GenericTypeParamType::get(/*isParameterPack=*/ false,
parentSig.getNextDepth(), /*index=*/ 0,
ctx);
}

CanGenericSignature
ASTContext::getOpenedExistentialSignature(Type type, GenericSignature parentSig) {
assert(type->isExistentialType());

if (auto existential = type->getAs<ExistentialType>())
type = existential->getConstraintType();

const CanType constraint = type->getCanonicalType();

auto canParentSig = parentSig.getCanonicalSignature();
auto key = std::make_pair(constraint, canParentSig.getPointer());
auto found = getImpl().ExistentialSignatures.find(key);
if (found != getImpl().ExistentialSignatures.end())
return found->second;

LocalArchetypeRequirementCollector collector(*this, canParentSig);
collector.addOpenedExistential(type);
auto genericSig = buildGenericSignature(
*this, collector.OuterSig, collector.Params, collector.Requirements,
/*allowInverses=*/true).getCanonicalSignature();

auto result = getImpl().ExistentialSignatures.insert(
std::make_pair(key, genericSig));
ASSERT(result.second);

return genericSig;
}

OpenedExistentialSignature
ASTContext::getOpenedExistentialSignature(Type type) {
assert(type->isExistentialType());

if (auto existential = type->getAs<ExistentialType>())
type = existential->getConstraintType();

const CanType constraint = type->getCanonicalType();
auto canType = type->getCanonicalType();

// The constraint type might contain type variables.
auto properties = constraint->getRecursiveProperties();
auto properties = canType->getRecursiveProperties();
auto arena = getArena(properties);

// Check the cache.
const auto &sigs = getImpl().getArena(arena).ExistentialSignatures;
auto found = sigs.find(constraint);
auto found = sigs.find(canType);
if (found != sigs.end())
return found->second;

OpenedExistentialSignature existentialSig;

// Generalize the existential type, to move type variables and primary
// archetypes into the substitution map.
auto gen = ExistentialTypeGeneralization::get(constraint);
auto gen = ExistentialTypeGeneralization::get(canType);

existentialSig.Shape = gen.Shape->getCanonicalType();
existentialSig.Generalization = gen.Generalization;

// Now, we have an existential type written with type parameters only.
// Open the generalization signature by adding a new generic parameter
// for `Self`.
auto parentSig = gen.Generalization.getGenericSignature();
existentialSig.OpenedSig =
getOpenedExistentialSignature(gen.Shape, parentSig);
auto canParentSig = parentSig.getCanonicalSignature();

LocalArchetypeRequirementCollector collector(*this, canParentSig);
collector.addOpenedExistential(gen.Shape);
existentialSig.OpenedSig = buildGenericSignature(
*this, collector.OuterSig, collector.Params, collector.Requirements,
/*allowInverses=*/true).getCanonicalSignature();

// Stash the `Self` type.
existentialSig.SelfType =
OpenedArchetypeType::getSelfInterfaceTypeFromContext(parentSig, *this)
existentialSig.OpenedSig.getGenericParams().back()
->getCanonicalType();

// Cache the result.
auto result = getImpl().getArena(arena).ExistentialSignatures.insert(
std::make_pair(constraint, existentialSig));
std::make_pair(canType, existentialSig));
ASSERT(result.second);

return existentialSig;
Expand Down
7 changes: 5 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4219,10 +4219,13 @@ namespace {
void visitOpenedArchetypeType(OpenedArchetypeType *T, StringRef label) {
printArchetypeCommon(T, "opened_archetype_type", label);

printFieldQuoted(T->getOpenedExistentialID(), "opened_existential_id");
auto *env = T->getGenericEnvironment();
printFieldQuoted(env->getOpenedExistentialUUID(), "opened_existential_id");

printArchetypeCommonRec(T);
printRec(T->getGenericEnvironment()->getOpenedExistentialType(), "opened_existential");
printRec(env->getOpenedExistentialType(), "opened_existential");
if (auto subMap = env->getOuterSubstitutions())
printRec(subMap, "substitutions");

printFoot();
}
Expand Down
8 changes: 6 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6967,8 +6967,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {

void visitOpenedArchetypeType(OpenedArchetypeType *T) {
if (Options.PrintForSIL) {
Printer << "@opened(\"" << T->getOpenedExistentialID() << "\", ";
visit(T->getGenericEnvironment()->getOpenedExistentialType());
auto *env = T->getGenericEnvironment();

Printer << "@opened(\"" << env->getOpenedExistentialUUID() << "\", ";
auto existentialTy = env->maybeApplyOuterContextSubstitutions(
env->getOpenedExistentialType());
visit(existentialTy);
Printer << ") ";

llvm::DenseMap<CanType, Identifier> newAlternativeTypeNames;
Expand Down
Loading