Skip to content

IR generation for constrained existentials #42317

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
19 changes: 19 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ Globals
global ::= global 'MN' // noncanonical specialized generic type metadata for global
global ::= global 'Mz' // canonical specialized generic type metadata caching token

global ::= global 'Mq' // global with a uniquing prefix

#if SWIFT_RUNTIME_VERSION >= 5.4
global ::= context (decl-name '_')+ 'WZ' // global variable one-time initialization function
global ::= context (decl-name '_')+ 'Wz' // global variable one-time initialization token
Expand Down Expand Up @@ -914,6 +916,23 @@ than the module of the conforming type or the conformed-to protocol), it is
mangled with its offset into the set of conformance requirements, the
root protocol conformance, and the suffix 'g'.

::

// No generalization signature, no type expression.
extended-existential-shape ::= generic-signature 'Xg' extended-existential-value-storage

// Generalization signature (the second one), no type expression.
extended-existential-shape ::= generic-signature generic-signature 'XG' extended-existential-value-storage

// No generalization signature, type expression.
extended-existential-shape ::= generic-signature type 'Xh' extended-existential-value-storage

// Generalization signature (the second one), type expression.
extended-existential-shape ::= generic-signature generic-signature type 'Xh' extended-existential-value-storage

extended-existential-value-storage ::= 'o' // opaque
extended-existential-value-storage ::= 'c' // class
extended-existential-value-storage ::= 'm' // metatype

Identifiers
~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ class ExtendedExistentialTypeShapeFlags {
(Data & ~SpecialKindMask) | (int_type(kind) << SpecialKindShift));
}
constexpr ExtendedExistentialTypeShapeFlags
withHasTypeExpresssion(bool hasTypeExpression) const {
withHasTypeExpression(bool hasTypeExpression) const {
return ExtendedExistentialTypeShapeFlags(
hasTypeExpression ? (Data | HasTypeExpression)
: (Data & ~HasTypeExpression));
Expand Down
32 changes: 12 additions & 20 deletions include/swift/AST/ExistentialLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#include "swift/Basic/ArrayRefView.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"

namespace swift {
class ProtocolDecl;
Expand All @@ -32,12 +32,12 @@ struct ExistentialLayout {
ExistentialLayout() {
hasExplicitAnyObject = false;
containsNonObjCProtocol = false;
singleProtocol = nullptr;
containsParameterized = false;
}

ExistentialLayout(ProtocolType *type);
ExistentialLayout(ProtocolCompositionType *type);
ExistentialLayout(ParameterizedProtocolType *type);
ExistentialLayout(CanProtocolType type);
ExistentialLayout(CanProtocolCompositionType type);
ExistentialLayout(CanParameterizedProtocolType type);

/// The explicit superclass constraint, if any.
Type explicitSuperclass;
Expand All @@ -48,6 +48,9 @@ struct ExistentialLayout {
/// Whether any protocol members are non-@objc.
bool containsNonObjCProtocol : 1;

/// Whether any protocol members are parameterized.s
bool containsParameterized : 1;

/// Return the kind of this existential (class/error/opaque).
Kind getKind() {
if (requiresClass())
Expand Down Expand Up @@ -87,28 +90,17 @@ struct ExistentialLayout {
/// constraints?
bool isErrorExistential() const;

static inline ProtocolType *getProtocolType(const Type &Ty) {
return cast<ProtocolType>(Ty.getPointer());
}
typedef ArrayRefView<Type,ProtocolType*,getProtocolType> ProtocolTypeArrayRef;

ProtocolTypeArrayRef getProtocols() const & {
if (singleProtocol)
return llvm::makeArrayRef(&singleProtocol, 1);
ArrayRef<ProtocolDecl*> getProtocols() const & {
return protocols;
}
/// The returned ArrayRef may point directly to \c this->singleProtocol, so
/// The returned ArrayRef points to internal storage, so
/// calling this on a temporary is likely to be incorrect.
ProtocolTypeArrayRef getProtocols() const && = delete;
ArrayRef<ProtocolDecl*> getProtocols() const && = delete;

LayoutConstraint getLayoutConstraint() const;

private:
// The protocol from a ProtocolType
Type singleProtocol;

/// Zero or more protocol constraints from a ProtocolCompositionType
ArrayRef<Type> protocols;
SmallVector<ProtocolDecl *, 4> protocols;

/// Zero or more primary associated type requirements from a
/// ParameterizedProtocolType
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ struct PointerAuthOptions : clang::PointerAuthOptions {

/// The swift async context entry in the extended frame info.
PointerAuthSchema AsyncContextExtendedFrameEntry;

/// Extended existential type shapes in flight.
PointerAuthSchema ExtendedExistentialTypeShape;

/// Non-unique extended existential type shapes in flight.
PointerAuthSchema NonUniqueExtendedExistentialTypeShape;
};

enum class JITDebugArtifact : unsigned {
Expand Down
41 changes: 40 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2772,6 +2772,7 @@ BEGIN_CAN_TYPE_WRAPPER(ExistentialMetatypeType, AnyMetatypeType)
MetatypeRepresentation repr) {
return CanExistentialMetatypeType(ExistentialMetatypeType::get(type, repr));
}
PROXY_CAN_TYPE_SIMPLE_GETTER(getExistentialInstanceType)
END_CAN_TYPE_WRAPPER(ExistentialMetatypeType, AnyMetatypeType)

/// ModuleType - This is the type given to a module value, e.g. the "Builtin" in
Expand Down Expand Up @@ -5258,6 +5259,9 @@ class ProtocolCompositionType final : public TypeBase,
}
};
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
CanTypeArrayRef getMembers() const {
return CanTypeArrayRef(getPointer()->getMembers());
}
END_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)

/// ParameterizedProtocolType - A type that constrains one or more primary
Expand Down Expand Up @@ -5295,11 +5299,19 @@ class ParameterizedProtocolType final : public TypeBase,
return Base;
}

ProtocolDecl *getProtocol() const {
return Base->getDecl();
}

ArrayRef<Type> getArgs() const {
return {getTrailingObjects<Type>(),
Bits.ParameterizedProtocolType.ArgCount};
}

bool requiresClass() const {
return getBaseType()->requiresClass();
}

void getRequirements(Type baseType, SmallVectorImpl<Requirement> &reqs) const;

void Profile(llvm::FoldingSetNodeID &ID) {
Expand All @@ -5321,12 +5333,36 @@ class ParameterizedProtocolType final : public TypeBase,
RecursiveTypeProperties properties);
};
BEGIN_CAN_TYPE_WRAPPER(ParameterizedProtocolType, Type)
PROXY_CAN_TYPE_SIMPLE_GETTER(getBaseType)
CanProtocolType getBaseType() const {
return CanProtocolType(getPointer()->getBaseType());
}
CanTypeArrayRef getArgs() const {
return CanTypeArrayRef(getPointer()->getArgs());
}
END_CAN_TYPE_WRAPPER(ParameterizedProtocolType, Type)

/// The generalized shape of an existential type.
struct ExistentialTypeGeneralization {
/// The generalized existential type. May refer to type parameters
/// from the generalization signature.
Type Shape;

/// The generalization signature and substitutions.
SubstitutionMap Generalization;

/// Retrieve the generalization for the given existential type.
///
/// Substituting the generalization substitutions into the shape
/// should produce the original existential type.
///
/// If there is a generic type substitution which can turn existential
/// type A into existential type B, then:
/// - the generalized shape types of A and B must be equal and
/// - the generic signatures of the generalization substitutions of
/// A and B must be equal.
static ExistentialTypeGeneralization get(Type existentialType);
};

/// An existential type, spelled with \c any .
///
/// In Swift 5 mode, a plain protocol name in type
Expand All @@ -5352,6 +5388,9 @@ class ExistentialType final : public TypeBase {
if (auto composition = ConstraintType->getAs<ProtocolCompositionType>())
return composition->requiresClass();

if (auto paramProtocol = ConstraintType->getAs<ParameterizedProtocolType>())
return paramProtocol->requiresClass();

return false;
}

Expand Down
3 changes: 3 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ NODE(CompileTimeConst)
NODE(OpaqueReturnTypeIndexed)
NODE(BackDeploymentThunk)
NODE(BackDeploymentFallback)
NODE(ExtendedExistentialTypeShape)
NODE(ExtendedExistentialValueStorage)
NODE(Uniquable)

#undef CONTEXT_NODE
#undef NODE
1 change: 1 addition & 0 deletions include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ class Demangler : public NodeFactory {
NodePointer demangleArchetype();
NodePointer demangleAssociatedTypeSimple(NodePointer GenericParamIdx);
NodePointer demangleAssociatedTypeCompound(NodePointer GenericParamIdx);
NodePointer demangleExtendedExistentialShape(char kind);

NodePointer popAssocTypeName();
NodePointer popAssocTypePath();
Expand Down
59 changes: 59 additions & 0 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ class LinkEntity {
// This field appears in SILFunction.
IsDynamicallyReplaceableImplShift = 8,
IsDynamicallyReplaceableImplMask = ~KindMask,

// These fields appear in ExtendedExistentialTypeShape.
ExtendedExistentialIsUniqueShift = 8,
ExtendedExistentialIsUniqueMask = 0x100,
ExtendedExistentialIsSharedShift = 9,
ExtendedExistentialIsSharedMask = 0x200,
ExtendedExistentialMetatypeDepthShift = 10,
ExtendedExistentialMetatypeDepthMask =
~(KindMask | ExtendedExistentialIsUniqueMask |
ExtendedExistentialIsSharedMask),
};
#define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
#define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
Expand Down Expand Up @@ -493,6 +503,11 @@ class LinkEntity {
/// Accessible function record, which describes a function that can be
/// looked up by name by the runtime.
AccessibleFunctionRecord,

/// Extended existential type shape.
/// Pointer is the (generalized) existential type.
/// SecondaryPointer is the GenericSignatureImpl*.
ExtendedExistentialTypeShape,
};
friend struct llvm::DenseMapInfo<LinkEntity>;

Expand Down Expand Up @@ -1352,6 +1367,24 @@ class LinkEntity {
return entity;
}

static LinkEntity forExtendedExistentialTypeShape(CanGenericSignature genSig,
CanExistentialType
existentialType,
unsigned metatypeDepth,
bool isUnique,
bool isShared) {
LinkEntity entity;
entity.Pointer = existentialType.getPointer();
entity.SecondaryPointer =
const_cast<GenericSignatureImpl*>(genSig.getPointer());
entity.Data =
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::ExtendedExistentialTypeShape))
| LINKENTITY_SET_FIELD(ExtendedExistentialIsUnique, unsigned(isUnique))
| LINKENTITY_SET_FIELD(ExtendedExistentialIsShared, unsigned(isShared))
| LINKENTITY_SET_FIELD(ExtendedExistentialMetatypeDepth, metatypeDepth);
return entity;
}

void mangle(llvm::raw_ostream &out) const;
void mangle(SmallVectorImpl<char> &buffer) const;
std::string mangleAsString() const;
Expand Down Expand Up @@ -1445,6 +1478,32 @@ class LinkEntity {
SecondaryPointer);
}

CanGenericSignature getExtendedExistentialTypeShapeGenSig() const {
assert(getKind() == Kind::ExtendedExistentialTypeShape);
return CanGenericSignature(
reinterpret_cast<const GenericSignatureImpl*>(SecondaryPointer));
}

CanExistentialType getExtendedExistentialTypeShapeType() const {
assert(getKind() == Kind::ExtendedExistentialTypeShape);
return cast<ExistentialType>(CanType(reinterpret_cast<TypeBase*>(Pointer)));
}

bool isExtendedExistentialTypeShapeUnique() const {
assert(getKind() == Kind::ExtendedExistentialTypeShape);
return LINKENTITY_GET_FIELD(Data, ExtendedExistentialIsUnique);
}

bool isExtendedExistentialTypeShapeShared() const {
assert(getKind() == Kind::ExtendedExistentialTypeShape);
return LINKENTITY_GET_FIELD(Data, ExtendedExistentialIsShared);
}

unsigned getExtendedExistentialTypeShapeMetatypeDepth() const {
assert(getKind() == Kind::ExtendedExistentialTypeShape);
return LINKENTITY_GET_FIELD(Data, ExtendedExistentialMetatypeDepth);
}

bool isDynamicallyReplaceable() const {
assert(getKind() == Kind::SILFunction);
return LINKENTITY_GET_FIELD(Data, IsDynamicallyReplaceableImpl);
Expand Down
30 changes: 30 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,36 @@ FUNCTION(GetExistentialMetadata,
ATTRS(NoUnwind, ReadOnly, WillReturn),
EFFECT(MetaData)) // ?

// const ExtendedExistentialTypeShape *
// swift_getExtendedExistentialTypeShape(
// const NonUniqueExtendedExistentialTypeShape *nonUnique);
FUNCTION(GetExtendedExistentialTypeShape,
swift_getExtendedExistentialTypeShape, C_CC, AlwaysAvailable,
RETURNS(TypeMetadataPtrTy),
ARGS(Int8PtrTy, Int8PtrPtrTy),
ATTRS(NoUnwind, ArgMemOnly, WillReturn),
EFFECT(MetaData)) // ?

// Metadata *swift_getExtendedExistentialTypeMetadata(
// const NonUniqueExtendedExistentialTypeShape *shape,
// const void * const *generalizationArgs);
FUNCTION(GetExtendedExistentialTypeMetadata,
swift_getExtendedExistentialTypeMetadata, C_CC, AlwaysAvailable,
RETURNS(TypeMetadataPtrTy),
ARGS(Int8PtrTy, Int8PtrPtrTy),
ATTRS(NoUnwind, ArgMemOnly, WillReturn),
EFFECT(MetaData)) // ?

// Metadata *swift_getExtendedExistentialTypeMetadata_unique(
// const ExtendedExistentialTypeShape *shape,
// const void * const *generalizationArgs);
FUNCTION(GetExtendedExistentialTypeMetadataUnique,
swift_getExtendedExistentialTypeMetadata_unique, C_CC, AlwaysAvailable,
RETURNS(TypeMetadataPtrTy),
ARGS(Int8PtrTy, Int8PtrPtrTy),
ATTRS(NoUnwind, ArgMemOnly, WillReturn),
EFFECT(MetaData)) // ?

// Metadata *swift_relocateClassMetadata(TypeContextDescriptor *descriptor,
// const void *pattern);
FUNCTION(RelocateClassMetadata,
Expand Down
3 changes: 3 additions & 0 deletions include/swift/SIL/FormalLinkage.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

namespace swift {

class CanGenericSignature;
class CanType;
class RootProtocolConformance;
class ValueDecl;
Expand Down Expand Up @@ -44,6 +45,8 @@ enum class FormalLinkage {

FormalLinkage getDeclLinkage(const ValueDecl *decl);
FormalLinkage getTypeLinkage(CanType formalType);
FormalLinkage getTypeLinkage_correct(CanType formalType);
FormalLinkage getGenericSignatureLinkage(CanGenericSignature signature);
SILLinkage getSILLinkage(FormalLinkage linkage,
ForDefinition_t forDefinition);
SILLinkage
Expand Down
8 changes: 4 additions & 4 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1045,8 +1045,7 @@ void ASTMangler::appendExistentialLayout(
bool First = true;
bool DroppedRequiresClass = false;
bool SawRequiresClass = false;
for (Type protoTy : layout.getProtocols()) {
auto proto = protoTy->castTo<ProtocolType>()->getDecl();
for (auto proto : layout.getProtocols()) {
// If we aren't allowed to emit marker protocols, suppress them here.
if (!AllowMarkerProtocols && proto->isMarkerProtocol()) {
if (proto->requiresClass())
Expand All @@ -1058,7 +1057,7 @@ void ASTMangler::appendExistentialLayout(
if (proto->requiresClass())
SawRequiresClass = true;

appendProtocolName(protoTy->castTo<ProtocolType>()->getDecl());
appendProtocolName(proto);
appendListSeparator(First);
}
if (First)
Expand Down Expand Up @@ -1258,7 +1257,8 @@ void ASTMangler::appendType(Type type, GenericSignature sig,

case TypeKind::Protocol: {
return appendExistentialLayout(
ExistentialLayout(cast<ProtocolType>(tybase)), sig, forDecl);
ExistentialLayout(CanProtocolType(cast<ProtocolType>(tybase))),
sig, forDecl);
}

case TypeKind::ProtocolComposition: {
Expand Down
Loading