Skip to content
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
12 changes: 11 additions & 1 deletion include/swift/AST/GenericEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
13 changes: 13 additions & 0 deletions include/swift/AST/SubstitutionMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {

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

registerLocalArchetypeRemapping(origEnv, newEnv);
}
Expand Down
20 changes: 13 additions & 7 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand All @@ -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<SubstitutionMap,
Expand Down
1 change: 0 additions & 1 deletion lib/AST/ExistentialGeneralization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ class Generalizer : public CanTypeVisitor<Generalizer, Type> {
private:
Type visitProtocolType(CanProtocolType type) {
// Simple protocol types have no sub-structure.
assert(!type.getParent() || !type.getParent()->isSpecialized());
return type;
}

Expand Down
48 changes: 2 additions & 46 deletions lib/AST/GenericEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DependentMemberType>())
return isUnsubstitutedTypeParameter(depMemTy->getBase());

if (auto genericParam = type->getAs<GenericTypeParamType>())
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()) {
Expand All @@ -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);
}
}
Expand Down
10 changes: 6 additions & 4 deletions lib/AST/LocalArchetypeRequirementCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ LocalArchetypeRequirementCollector::LocalArchetypeRequirementCollector(
: Context(ctx), OuterSig(sig), Depth(sig.getNextDepth()) {}

void LocalArchetypeRequirementCollector::addOpenedExistential(Type constraint) {
if (auto existential = constraint->getAs<ExistentialType>())
constraint = existential->getConstraintType();

assert(constraint->isConstraintType() ||
constraint->getClassOrBoundGenericClass());
assert(OuterSig || !constraint->hasTypeParameter() &&
Expand Down Expand Up @@ -134,10 +137,9 @@ GenericSignature swift::buildGenericSignatureWithCapturedEnvironments(
break;

case GenericEnvironment::Kind::OpenedExistential: {
auto constraint = genericEnv->getOpenedExistentialType();
if (auto existential = constraint->getAs<ExistentialType>())
constraint = existential->getConstraintType()->mapTypeOutOfContext();
collector.addOpenedExistential(constraint);
auto existentialTy = genericEnv->getOpenedExistentialType()
->mapTypeOutOfContext();
collector.addOpenedExistential(existentialTy);
continue;
}
case GenericEnvironment::Kind::OpenedElement: {
Expand Down
32 changes: 32 additions & 0 deletions lib/AST/SubstitutionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DependentMemberType>())
return isUnsubstitutedTypeParameter(depMemTy->getBase());

if (auto genericParam = type->getAs<GenericTypeParamType>())
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);
}

5 changes: 4 additions & 1 deletion lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
14 changes: 10 additions & 4 deletions lib/SILOptimizer/Utils/Existential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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*/,
Expand Down
Loading