Skip to content

Generalize the tracking of opened archetypes to cover pack element archetypes #62589

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 3 commits into from
Dec 15, 2022
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
6 changes: 4 additions & 2 deletions include/swift/AST/TypeNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ ABSTRACT_TYPE(Substitutable, Type)
ABSTRACT_TYPE(Archetype, SubstitutableType)
ALWAYS_CANONICAL_TYPE(PrimaryArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(OpaqueTypeArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(OpenedArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(ElementArchetype, ArchetypeType)
ABSTRACT_TYPE(LocalArchetype, ArchetypeType)
ALWAYS_CANONICAL_TYPE(OpenedArchetype, LocalArchetypeType)
ALWAYS_CANONICAL_TYPE(ElementArchetype, LocalArchetypeType)
TYPE_RANGE(LocalArchetype, OpenedArchetype, ElementArchetype)
ALWAYS_CANONICAL_TYPE(PackArchetype, ArchetypeType)
TYPE_RANGE(Archetype, PrimaryArchetype, PackArchetype)
TYPE(GenericTypeParam, SubstitutableType)
Expand Down
60 changes: 52 additions & 8 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ class RecursiveTypeProperties {
/// This type contains a parameterized existential type \c any P<T>.
HasParameterizedExistential = 0x2000,

Last_Property = HasParameterizedExistential
/// This type contains an ElementArchetype.
HasElementArchetype = 0x4000,

Last_Property = HasElementArchetype
};
enum { BitWidth = countBitsUsed(Property::Last_Property) };

Expand Down Expand Up @@ -212,9 +215,19 @@ class RecursiveTypeProperties {
bool hasDependentMember() const { return Bits & HasDependentMember; }

/// Does a type with these properties structurally contain an
/// archetype?
/// opened existential archetype?
bool hasOpenedExistential() const { return Bits & HasOpenedExistential; }

/// Does a type with these properties structurally contain an
/// opened element archetype?
bool hasElementArchetype() const { return Bits & HasElementArchetype; }

/// Does a type with these properties structurally contain a local
/// archetype?
bool hasLocalArchetype() const {
return hasOpenedExistential() || hasElementArchetype();
}

/// Does a type with these properties structurally contain a
/// reference to DynamicSelf?
bool hasDynamicSelf() const { return Bits & HasDynamicSelf; }
Expand Down Expand Up @@ -629,6 +642,16 @@ class alignas(1 << TypeAlignInBits) TypeBase
return getRecursiveProperties().hasOpenedExistential();
}

/// Determine whether the type involves an opened element archetype.
bool hasElementArchetype() const {
return getRecursiveProperties().hasElementArchetype();
}

/// Determine whether the type involves a local archetype.
bool hasLocalArchetype() const {
return getRecursiveProperties().hasLocalArchetype();
}

bool hasParameterPack() const {
return getRecursiveProperties().hasParameterPack();
}
Expand Down Expand Up @@ -5914,8 +5937,29 @@ class ReplaceOpaqueTypesWithUnderlyingTypes {
bool isWholeModule() const { return inContextAndIsWholeModule.getInt(); }
};

/// An archetype that's only valid in a portion of a local context.
class LocalArchetypeType : public ArchetypeType {
protected:
using ArchetypeType::ArchetypeType;

public:
LocalArchetypeType *getRoot() const {
return cast<LocalArchetypeType>(ArchetypeType::getRoot());
}

static bool classof(const TypeBase *type) {
return type->getKind() == TypeKind::OpenedArchetype ||
type->getKind() == TypeKind::ElementArchetype;
}
};
BEGIN_CAN_TYPE_WRAPPER(LocalArchetypeType, ArchetypeType)
CanLocalArchetypeType getRoot() const {
return CanLocalArchetypeType(getPointer()->getRoot());
}
END_CAN_TYPE_WRAPPER(LocalArchetypeType, ArchetypeType)

/// An archetype that represents the dynamic type of an opened existential.
class OpenedArchetypeType final : public ArchetypeType,
class OpenedArchetypeType final : public LocalArchetypeType,
private ArchetypeTrailingObjects<OpenedArchetypeType>
{
friend TrailingObjects;
Expand Down Expand Up @@ -6016,11 +6060,11 @@ class OpenedArchetypeType final : public ArchetypeType,
ArrayRef<ProtocolDecl *> conformsTo, Type superclass,
LayoutConstraint layout);
};
BEGIN_CAN_TYPE_WRAPPER(OpenedArchetypeType, ArchetypeType)
BEGIN_CAN_TYPE_WRAPPER(OpenedArchetypeType, LocalArchetypeType)
CanOpenedArchetypeType getRoot() const {
return CanOpenedArchetypeType(getPointer()->getRoot());
}
END_CAN_TYPE_WRAPPER(OpenedArchetypeType, ArchetypeType)
END_CAN_TYPE_WRAPPER(OpenedArchetypeType, LocalArchetypeType)

/// A wrapper around a shape type to use in ArchetypeTrailingObjects
/// for PackArchetypeType.
Expand Down Expand Up @@ -6065,7 +6109,7 @@ BEGIN_CAN_TYPE_WRAPPER(PackArchetypeType, ArchetypeType)
END_CAN_TYPE_WRAPPER(PackArchetypeType, ArchetypeType)

/// An archetype that represents the element type of a pack archetype.
class ElementArchetypeType final : public ArchetypeType,
class ElementArchetypeType final : public LocalArchetypeType,
private ArchetypeTrailingObjects<ElementArchetypeType>
{
friend TrailingObjects;
Expand Down Expand Up @@ -6104,11 +6148,11 @@ class ElementArchetypeType final : public ArchetypeType,
ArrayRef<ProtocolDecl *> conformsTo, Type superclass,
LayoutConstraint layout);
};
BEGIN_CAN_TYPE_WRAPPER(ElementArchetypeType, ArchetypeType)
BEGIN_CAN_TYPE_WRAPPER(ElementArchetypeType, LocalArchetypeType)
CanElementArchetypeType getRoot() const {
return CanElementArchetypeType(getPointer()->getRoot());
}
END_CAN_TYPE_WRAPPER(ElementArchetypeType, ArchetypeType)
END_CAN_TYPE_WRAPPER(ElementArchetypeType, LocalArchetypeType)

template<typename Type>
const Type *ArchetypeType::getSubclassTrailingObjects() const {
Expand Down
8 changes: 4 additions & 4 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -685,13 +685,13 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
return getResultsImpl().getTypes();
}

/// Run the given function for each opened archetype this instruction
/// Run the given function for each local archetype this instruction
/// defines, passing the value that should be used to record the
/// dependency.
void forEachDefinedOpenedArchetype(
llvm::function_ref<void(CanOpenedArchetypeType archetype,
void forEachDefinedLocalArchetype(
llvm::function_ref<void(CanLocalArchetypeType archetype,
SILValue typeDependency)> function) const;
bool definesOpenedArchetypes() const;
bool definesLocalArchetypes() const;

MemoryBehavior getMemoryBehavior() const;
ReleasingBehavior getReleasingBehavior() const;
Expand Down
42 changes: 21 additions & 21 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,22 +345,22 @@ class SILModule {
/// projections, shared between all functions in the module.
std::unique_ptr<IndexTrieNode> indexTrieRoot;

/// A mapping from root opened archetypes to the instructions which define
/// A mapping from root local archetypes to the instructions which define
/// them.
///
/// The value is either a SingleValueInstruction or a PlaceholderValue, in case
/// an opened archetype definition is looked up during parsing or
/// deserializing SIL, where opened archetypes can be forward referenced.
/// The value is either a SingleValueInstruction or a PlaceholderValue,
/// in case a local archetype definition is looked up during parsing or
/// deserializing SIL, where local archetypes can be forward referenced.
///
/// In theory we wouldn't need to have the SILFunction in the key, because
/// opened archetypes \em should be unique across the module. But currently
/// in some rare cases SILGen re-uses the same opened archetype for multiple
/// local archetypes \em should be unique across the module. But currently
/// in some rare cases SILGen re-uses the same local archetype for multiple
/// functions.
using OpenedArchetypeKey = std::pair<OpenedArchetypeType *, SILFunction *>;
llvm::DenseMap<OpenedArchetypeKey, SILValue> RootOpenedArchetypeDefs;
using LocalArchetypeKey = std::pair<LocalArchetypeType *, SILFunction *>;
llvm::DenseMap<LocalArchetypeKey, SILValue> RootLocalArchetypeDefs;

/// The number of PlaceholderValues in RootOpenedArchetypeDefs.
int numUnresolvedOpenedArchetypes = 0;
/// The number of PlaceholderValues in RootLocalArchetypeDefs.
int numUnresolvedLocalArchetypes = 0;

/// The options passed into this SILModule.
const SILOptions &Options;
Expand Down Expand Up @@ -444,31 +444,31 @@ class SILModule {
regDeserializationNotificationHandlerForAllFuncOME = true;
}

/// Returns the instruction which defines the given root opened archetype,
/// Returns the instruction which defines the given root local archetype,
/// e.g. an open_existential_addr.
///
/// In case the opened archetype is not defined yet (e.g. during parsing or
/// In case the local archetype is not defined yet (e.g. during parsing or
/// deserialization), a PlaceholderValue is returned. This should not be the
/// case outside of parsing or deserialization.
SILValue getRootOpenedArchetypeDef(CanOpenedArchetypeType archetype,
SILFunction *inFunction);
SILValue getRootLocalArchetypeDef(CanLocalArchetypeType archetype,
SILFunction *inFunction);

/// Returns the instruction which defines the given root opened archetype,
/// Returns the instruction which defines the given root local archetype,
/// e.g. an open_existential_addr.
///
/// In contrast to getOpenedArchetypeDef, it is required that all opened
/// In contrast to getLocalArchetypeDef, it is required that all local
/// archetypes are resolved.
SingleValueInstruction *
getRootOpenedArchetypeDefInst(CanOpenedArchetypeType archetype,
SILFunction *inFunction) {
getRootLocalArchetypeDefInst(CanLocalArchetypeType archetype,
SILFunction *inFunction) {
return cast<SingleValueInstruction>(
getRootOpenedArchetypeDef(archetype, inFunction));
getRootLocalArchetypeDef(archetype, inFunction));
}

/// Returns true if there are unresolved opened archetypes in the module.
/// Returns true if there are unresolved local archetypes in the module.
///
/// This should only be the case during parsing or deserialization.
bool hasUnresolvedOpenedArchetypeDefinitions();
bool hasUnresolvedLocalArchetypeDefinitions();

/// Get a unique index for a struct or class field in layout order.
///
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace swift {
/// this is the task of the type visitor invoking it.
/// \returns The found opened archetype or empty type otherwise.
CanOpenedArchetypeType getOpenedArchetypeOf(CanType Ty);
CanLocalArchetypeType getLocalArchetypeOf(CanType Ty);

/// How an existential type container is represented.
enum class ExistentialRepresentation {
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3837,7 +3837,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
static RecursiveTypeProperties
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
Type result) {
static_assert(RecursiveTypeProperties::BitWidth == 14,
static_assert(RecursiveTypeProperties::BitWidth == 15,
"revisit this if you add new recursive type properties");
RecursiveTypeProperties properties;

Expand Down Expand Up @@ -4464,7 +4464,7 @@ CanSILFunctionType SILFunctionType::get(
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));

RecursiveTypeProperties properties;
static_assert(RecursiveTypeProperties::BitWidth == 14,
static_assert(RecursiveTypeProperties::BitWidth == 15,
"revisit this if you add new recursive type properties");
for (auto &param : params)
properties |= param.getInterfaceType()->getRecursiveProperties();
Expand Down
19 changes: 11 additions & 8 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3964,11 +3964,12 @@ OpenedArchetypeType::OpenedArchetypeType(
GenericEnvironment *environment, Type interfaceType,
ArrayRef<ProtocolDecl *> conformsTo, Type superclass,
LayoutConstraint layout)
: ArchetypeType(TypeKind::OpenedArchetype, interfaceType->getASTContext(),
RecursiveTypeProperties::HasArchetype
| RecursiveTypeProperties::HasOpenedExistential,
interfaceType, conformsTo, superclass, layout,
environment)
: LocalArchetypeType(TypeKind::OpenedArchetype,
interfaceType->getASTContext(),
RecursiveTypeProperties::HasArchetype
| RecursiveTypeProperties::HasOpenedExistential,
interfaceType, conformsTo, superclass, layout,
environment)
{
assert(!interfaceType->isParameterPack());
}
Expand Down Expand Up @@ -4022,9 +4023,11 @@ ElementArchetypeType::ElementArchetypeType(
const ASTContext &Ctx, GenericEnvironment *GenericEnv, Type InterfaceType,
ArrayRef<ProtocolDecl *> ConformsTo, Type Superclass,
LayoutConstraint Layout)
: ArchetypeType(TypeKind::ElementArchetype, Ctx,
RecursiveTypeProperties::HasArchetype, InterfaceType,
ConformsTo, Superclass, Layout, GenericEnv) {
: LocalArchetypeType(TypeKind::ElementArchetype, Ctx,
RecursiveTypeProperties::HasArchetype |
RecursiveTypeProperties::HasElementArchetype,
InterfaceType,
ConformsTo, Superclass, Layout, GenericEnv) {
}

CanTypeWrapper<ElementArchetypeType> ElementArchetypeType::getNew(
Expand Down
10 changes: 5 additions & 5 deletions lib/SIL/IR/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1531,17 +1531,17 @@ const ValueBase *SILInstructionResultArray::back() const {
// Defined opened archetypes
//===----------------------------------------------------------------------===//

bool SILInstruction::definesOpenedArchetypes() const {
bool SILInstruction::definesLocalArchetypes() const {
bool definesAny = false;
forEachDefinedOpenedArchetype([&](CanOpenedArchetypeType type,
SILValue dependency) {
forEachDefinedLocalArchetype([&](CanLocalArchetypeType type,
SILValue dependency) {
definesAny = true;
});
return definesAny;
}

void SILInstruction::forEachDefinedOpenedArchetype(
llvm::function_ref<void(CanOpenedArchetypeType, SILValue)> fn) const {
void SILInstruction::forEachDefinedLocalArchetype(
llvm::function_ref<void(CanLocalArchetypeType, SILValue)> fn) const {
switch (getKind()) {
#define SINGLE_VALUE_SINGLE_OPEN(TYPE) \
case SILInstructionKind::TYPE: { \
Expand Down
32 changes: 16 additions & 16 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static void *allocateTrailingInst(SILFunction &F, CountTypes... counts) {

namespace {
class TypeDependentOperandCollector {
SmallVector<CanOpenedArchetypeType, 4> rootOpenedArchetypes;
SmallVector<CanLocalArchetypeType, 4> rootLocalArchetypes;
bool hasDynamicSelf = false;
public:
void collect(CanType type);
Expand All @@ -72,27 +72,27 @@ class TypeDependentOperandCollector {

}

/// Collect root open archetypes from a given type into \p RootOpenedArchetypes.
/// \p RootOpenedArchetypes is being used as a set. We don't use a real set type
/// Collect root open archetypes from a given type into \p RootLocalArchetypes.
/// \p RootLocalArchetypes is being used as a set. We don't use a real set type
/// here for performance reasons.
void TypeDependentOperandCollector::collect(CanType type) {
if (!type)
return;
if (type->hasDynamicSelfType())
hasDynamicSelf = true;
if (!type->hasOpenedExistential())
if (!type->hasLocalArchetype())
return;
type.visit([&](CanType t) {
if (const auto opened = dyn_cast<OpenedArchetypeType>(t)) {
const auto root = opened.getRoot();
if (const auto local = dyn_cast<LocalArchetypeType>(t)) {
const auto root = local.getRoot();

// Add this root opened archetype if it was not seen yet.
// Add this root local archetype if it was not seen yet.
// We don't use a set here, because the number of open archetypes
// is usually very small and using a real set may introduce too
// much overhead.
if (std::find(rootOpenedArchetypes.begin(), rootOpenedArchetypes.end(),
root) == rootOpenedArchetypes.end())
rootOpenedArchetypes.push_back(root);
if (std::find(rootLocalArchetypes.begin(), rootLocalArchetypes.end(),
root) == rootLocalArchetypes.end())
rootLocalArchetypes.push_back(root);
}
});
}
Expand All @@ -112,12 +112,12 @@ void TypeDependentOperandCollector::collect(SubstitutionMap subs) {
void TypeDependentOperandCollector::addTo(SmallVectorImpl<SILValue> &operands,
SILFunction &F) {
size_t firstArchetypeOperand = operands.size();
for (CanOpenedArchetypeType archetype : rootOpenedArchetypes) {
SILValue def = F.getModule().getRootOpenedArchetypeDef(archetype, &F);
for (CanLocalArchetypeType archetype : rootLocalArchetypes) {
SILValue def = F.getModule().getRootLocalArchetypeDef(archetype, &F);
assert(def->getFunction() == &F &&
"def of root opened archetype is in wrong function");
"def of root local archetype is in wrong function");

// The archetypes in rootOpenedArchetypes have already been uniqued,
// The archetypes in rootLocalArchetypes have already been uniqued,
// but a single instruction can open multiple archetypes (e.g.
// open_pack_element), so we also unique the actual operand values.
// As above, we assume there are very few values in practice and so
Expand All @@ -130,9 +130,9 @@ void TypeDependentOperandCollector::addTo(SmallVectorImpl<SILValue> &operands,
operands.push_back(F.getDynamicSelfMetadata());
}

/// Collects all root opened archetypes from a type and a substitution list, and
/// Collects all root local archetypes from a type and a substitution list, and
/// forms a corresponding list of operands.
/// We need to know the number of root opened archetypes to estimate the number
/// We need to know the number of root local archetypes to estimate the number
/// of corresponding operands for the instruction being formed, because we need
/// to reserve enough memory for these operands.
template <class... Sources>
Expand Down
Loading