Skip to content

Plumb Through Parameterized Protocol Existentials #41743

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 8 commits into from
Mar 9, 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
1 change: 1 addition & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ Types
type ::= protocol-list 'p' // existential type
type ::= protocol-list superclass 'Xc' // existential type with superclass
type ::= protocol-list 'Xl' // existential type with AnyObject
type ::= protocol-list 'y' (type* '_')* type* retroactive-conformance* 'Xp' // parameterized protocol type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer a more general mangling that could accommodate arbitrary requirements in the future.

type ::= type-list 't' // tuple
type ::= type generic-signature 'u' // generic type
type ::= 'x' // generic param, depth=0, idx=0
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class ASTBuilder {
bool isClassBound,
bool forRequirement = true);

Type createParameterizedProtocolType(Type base, ArrayRef<Type> args);

Type createExistentialMetatypeType(Type instance,
Optional<Demangle::ImplMetatypeRepresentation> repr=None);

Expand Down
50 changes: 45 additions & 5 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,10 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
IsNonAccessing : 1
);

SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32,
SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32+20,
: NumPadBits,
NumConformances : 32
NumConformances : 32,
NumArgumentConversions : 20
);

SWIFT_INLINE_BITFIELD_FULL(UnresolvedSpecializeExpr, Expr, 32,
Expand Down Expand Up @@ -3244,20 +3245,35 @@ class CollectionUpcastConversionExpr : public ImplicitConversionExpr {
/// "Appropriate kind" means e.g. a concrete/existential metatype if the
/// result is an existential metatype.
class ErasureExpr final : public ImplicitConversionExpr,
private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef> {
private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef,
CollectionUpcastConversionExpr::ConversionPair> {
friend TrailingObjects;
using ConversionPair = CollectionUpcastConversionExpr::ConversionPair;

ErasureExpr(Expr *subExpr, Type type,
ArrayRef<ProtocolConformanceRef> conformances)
ArrayRef<ProtocolConformanceRef> conformances,
ArrayRef<ConversionPair> argConversions)
: ImplicitConversionExpr(ExprKind::Erasure, subExpr, type) {
Bits.ErasureExpr.NumConformances = conformances.size();
std::uninitialized_copy(conformances.begin(), conformances.end(),
getTrailingObjects<ProtocolConformanceRef>());

Bits.ErasureExpr.NumArgumentConversions = argConversions.size();
std::uninitialized_copy(argConversions.begin(), argConversions.end(),
getTrailingObjects<ConversionPair>());
}

public:
static ErasureExpr *create(ASTContext &ctx, Expr *subExpr, Type type,
ArrayRef<ProtocolConformanceRef> conformances);
ArrayRef<ProtocolConformanceRef> conformances,
ArrayRef<ConversionPair> argConversions);

size_t numTrailingObjects(OverloadToken<ProtocolConformanceRef>) const {
return Bits.ErasureExpr.NumConformances;
}
size_t numTrailingObjects(OverloadToken<ConversionPair>) const {
return Bits.ErasureExpr.NumArgumentConversions;
}

/// Retrieve the mapping specifying how the type of the subexpression
/// maps to the resulting existential type. If the resulting existential
Expand All @@ -3274,6 +3290,30 @@ class ErasureExpr final : public ImplicitConversionExpr,
Bits.ErasureExpr.NumConformances };
}

/// Retrieve the conversion expressions mapping requirements from any
/// parameterized existentials involved in this erasure.
///
/// If the destination type is not a parameterized protocol type,
/// this array will be empty
ArrayRef<ConversionPair> getArgumentConversions() const {
return {getTrailingObjects<ConversionPair>(),
Bits.ErasureExpr.NumArgumentConversions };
}

/// Retrieve the conversion expressions mapping requirements from any
/// parameterized existentials involved in this erasure.
///
/// If the destination type is not a parameterized protocol type,
/// this array will be empty
MutableArrayRef<ConversionPair> getArgumentConversions() {
return {getTrailingObjects<ConversionPair>(),
Bits.ErasureExpr.NumArgumentConversions };
}

void setArgumentConversion(unsigned i, const ConversionPair &p) {
getArgumentConversions()[i] = p;
}

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::Erasure;
}
Expand Down
12 changes: 8 additions & 4 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6417,9 +6417,10 @@ inline bool TypeBase::isAnyExistentialType() {
}

inline bool CanType::isExistentialTypeImpl(CanType type) {
return (isa<ProtocolType>(type) ||
isa<ProtocolCompositionType>(type) ||
isa<ExistentialType>(type));
return isa<ProtocolType>(type) ||
isa<ProtocolCompositionType>(type) ||
isa<ExistentialType>(type) ||
isa<ParameterizedProtocolType>(type);
}

inline bool CanType::isAnyExistentialTypeImpl(CanType type) {
Expand Down Expand Up @@ -6515,6 +6516,8 @@ inline NominalTypeDecl *CanType::getNominalOrBoundGenericNominal() const {
return Ty->getDecl();
if (auto Ty = dyn_cast<ExistentialType>(*this))
return Ty->getConstraintType()->getNominalOrBoundGenericNominal();
if (auto Ty = dyn_cast<ParameterizedProtocolType>(*this))
return Ty->getBaseType()->getNominalOrBoundGenericNominal();
return nullptr;
}

Expand All @@ -6525,7 +6528,8 @@ inline NominalTypeDecl *TypeBase::getAnyNominal() {
inline Type TypeBase::getNominalParent() {
if (auto existential = getAs<ExistentialType>())
return existential->getConstraintType()->getNominalParent();

if (auto ppt = getAs<ParameterizedProtocolType>())
return ppt->getBaseType()->getNominalParent();
return castTo<AnyGenericType>()->getParent();
}

Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ NODE(EscapingObjCBlock)
CONTEXT_NODE(OtherNominalType)
CONTEXT_NODE(OwningAddressor)
CONTEXT_NODE(OwningMutableAddressor)
NODE(ParameterizedProtocol)
NODE(PartialApplyForwarder)
NODE(PartialApplyObjCForwarder)
NODE(PostfixOperator)
Expand Down
28 changes: 28 additions & 0 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,34 @@ class TypeDecoder {
forRequirement);
}

case NodeKind::ParameterizedProtocol: {
if (Node->getNumChildren() < 2)
return MAKE_NODE_TYPE_ERROR(Node,
"fewer children (%zu) than required (2)",
Node->getNumChildren());

auto protocolType = decodeMangledType(Node->getChild(0), depth + 1);
if (protocolType.isError())
return protocolType;

llvm::SmallVector<BuiltType, 8> args;

const auto &genericArgs = Node->getChild(1);
if (genericArgs->getKind() != NodeKind::TypeList)
return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList");

for (auto genericArg : *genericArgs) {
auto paramType = decodeMangledType(genericArg, depth + 1,
/*forRequirement=*/false);
if (paramType.isError())
return paramType;
args.push_back(paramType.getType());
}

return Builder.createParameterizedProtocolType(protocolType.getType(),
args);
}

case NodeKind::Protocol:
case NodeKind::ProtocolSymbolicReference: {
if (auto Proto = decodeMangledProtocolType(Node, depth + 1)) {
Expand Down
36 changes: 36 additions & 0 deletions include/swift/Reflection/TypeRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,42 @@ class ProtocolCompositionTypeRef final : public TypeRef {
}
};

class ParameterizedProtocolTypeRef final : public TypeRef {
const ProtocolCompositionTypeRef *Base;
std::vector<const TypeRef *> Args;

static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol,
std::vector<const TypeRef *> Args) {
TypeRefID ID;
ID.addPointer(Protocol);
for (auto Arg : Args) {
ID.addPointer(Arg);
}
return ID;
}

public:
ParameterizedProtocolTypeRef(const ProtocolCompositionTypeRef *Protocol,
std::vector<const TypeRef *> Args)
: TypeRef(TypeRefKind::ParameterizedProtocol), Base(Protocol),
Args(Args) {}

template <typename Allocator>
static const ParameterizedProtocolTypeRef *
create(Allocator &A, const ProtocolCompositionTypeRef *Protocol,
std::vector<const TypeRef *> Args) {
FIND_OR_CREATE_TYPEREF(A, ParameterizedProtocolTypeRef, Protocol, Args);
}

const ProtocolCompositionTypeRef *getBase() const { return Base; }

const std::vector<const TypeRef *> &getArgs() const { return Args; }

static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::ParameterizedProtocol;
}
};

class MetatypeTypeRef final : public TypeRef {
const TypeRef *InstanceType;
bool WasAbstract;
Expand Down
9 changes: 9 additions & 0 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,15 @@ class TypeRefBuilder {
isClassBound);
}

const ParameterizedProtocolTypeRef *
createParameterizedProtocolType(const TypeRef *base,
llvm::ArrayRef<const TypeRef *> args) {
auto *baseProto = llvm::dyn_cast<ProtocolCompositionTypeRef>(base);
if (!baseProto)
return nullptr;
return ParameterizedProtocolTypeRef::create(*this, baseProto, args);
}

const ExistentialMetatypeTypeRef *createExistentialMetatypeType(
const TypeRef *instance,
llvm::Optional<Demangle::ImplMetatypeRepresentation> repr = None) {
Expand Down
1 change: 1 addition & 0 deletions include/swift/Reflection/TypeRefs.def
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TYPEREF(BoundGeneric, TypeRef)
TYPEREF(Tuple, TypeRef)
TYPEREF(Function, TypeRef)
TYPEREF(ProtocolComposition, TypeRef)
TYPEREF(ParameterizedProtocol, TypeRef)
TYPEREF(Metatype, TypeRef)
TYPEREF(ExistentialMetatype, TypeRef)
TYPEREF(GenericTypeParameter, TypeRef)
Expand Down
6 changes: 4 additions & 2 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4444,7 +4444,8 @@ CanTypeWrapper<OpenedArchetypeType>
OpenedArchetypeType::get(CanType existential, GenericSignature parentSig,
Optional<UUID> knownID) {
assert(existential->isExistentialType());
auto interfaceType = OpenedArchetypeType::getSelfInterfaceTypeFromContext(parentSig, existential->getASTContext());
auto interfaceType = OpenedArchetypeType::getSelfInterfaceTypeFromContext(
parentSig, existential->getASTContext());
return get(existential, interfaceType, parentSig, knownID);
}

Expand Down Expand Up @@ -4510,7 +4511,8 @@ CanType OpenedArchetypeType::getAny(CanType existential, Type interfaceType,

CanType OpenedArchetypeType::getAny(CanType existential,
GenericSignature parentSig) {
auto interfaceTy = OpenedArchetypeType::getSelfInterfaceTypeFromContext(parentSig, existential->getASTContext());
auto interfaceTy = OpenedArchetypeType::getSelfInterfaceTypeFromContext(
parentSig, existential->getASTContext());
return getAny(existential, interfaceTy, parentSig);
}

Expand Down
8 changes: 8 additions & 0 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,14 @@ Type ASTBuilder::createExistentialMetatypeType(Type instance,
getMetatypeRepresentation(*repr));
}

Type ASTBuilder::createParameterizedProtocolType(Type base,
ArrayRef<Type> args) {
if (!base->getAs<ProtocolType>())
return Type();
return ParameterizedProtocolType::get(base->getASTContext(),
base->castTo<ProtocolType>(), args);
}

Type ASTBuilder::createMetatypeType(Type instance,
Optional<Demangle::ImplMetatypeRepresentation> repr) {
if (!repr)
Expand Down
10 changes: 8 additions & 2 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1269,8 +1269,11 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
}

case TypeKind::ParameterizedProtocol: {
llvm::errs() << "Not implemented\n";
abort();
auto layout = type->getExistentialLayout();
appendExistentialLayout(layout, sig, forDecl);
bool isFirstArgList = true;
appendBoundGenericArgs(type, sig, isFirstArgList, forDecl);
return appendOperator("XP");
}

case TypeKind::Existential: {
Expand Down Expand Up @@ -1574,6 +1577,9 @@ void ASTMangler::appendBoundGenericArgs(Type type, GenericSignature sig,
if (Type parent = nominalType->getParent())
appendBoundGenericArgs(parent->getDesugaredType(), sig, isFirstArgList,
forDecl);
} else if (auto *ppt = dyn_cast<ParameterizedProtocolType>(typePtr)) {
assert(!ppt->getBaseType()->getParent());
genericArgs = ppt->getArgs();
} else {
auto boundType = cast<BoundGenericType>(typePtr);
genericArgs = boundType->getGenericArgs();
Expand Down
19 changes: 19 additions & 0 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,25 @@ class Verifier : public ASTWalker {
verifyCheckedBase(E);
}

bool shouldVerify(ErasureExpr *expr) {
if (!shouldVerify(cast<Expr>(expr)))
return false;

for (auto &elt : expr->getArgumentConversions()) {
assert(!OpaqueValues.count(elt.OrigValue));
OpaqueValues[elt.OrigValue] = 0;
}

return true;
}

void cleanup(ErasureExpr *expr) {
for (auto &elt : expr->getArgumentConversions()) {
assert(OpaqueValues.count(elt.OrigValue));
OpaqueValues.erase(elt.OrigValue);
}
}

void verifyChecked(ErasureExpr *E) {
PrettyStackTraceExpr debugStack(Ctx, "verifying ErasureExpr", E);

Expand Down
24 changes: 23 additions & 1 deletion lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,29 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
}
return nullptr;
}


Expr *visitErasureExpr(ErasureExpr *E) {
if (Expr *E2 = doIt(E->getSubExpr())) {
E->setSubExpr(E2);
} else {
return nullptr;
}

for (unsigned i = 0; i < E->getArgumentConversions().size(); ++i) {
const auto &conv = E->getArgumentConversions()[i];
auto kConv = conv.Conversion;
if (!kConv) {
return nullptr;
} else if (Expr *E2 = doIt(kConv)) {
E->setArgumentConversion(i, {conv.OrigValue, E2});
} else {
return nullptr;
}
}

return E;
}

Expr *visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E) {
if (Expr *E2 = doIt(E->getSubExpr())) {
E->setSubExpr(E2);
Expand Down
14 changes: 8 additions & 6 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1178,14 +1178,16 @@ SequenceExpr *SequenceExpr::create(ASTContext &ctx, ArrayRef<Expr*> elements) {
assert(elements.size() & 1 && "even number of elements in sequence");
size_t bytes = totalSizeToAlloc<Expr *>(elements.size());
void *Buffer = ctx.Allocate(bytes, alignof(SequenceExpr));
return ::new(Buffer) SequenceExpr(elements);
return ::new (Buffer) SequenceExpr(elements);
}

ErasureExpr *ErasureExpr::create(ASTContext &ctx, Expr *subExpr, Type type,
ArrayRef<ProtocolConformanceRef> conformances){
auto size = totalSizeToAlloc<ProtocolConformanceRef>(conformances.size());
ArrayRef<ProtocolConformanceRef> conformances,
ArrayRef<ConversionPair> argConversions) {
auto size = totalSizeToAlloc<ProtocolConformanceRef, ConversionPair>(conformances.size(),
argConversions.size());
auto mem = ctx.Allocate(size, alignof(ErasureExpr));
return ::new(mem) ErasureExpr(subExpr, type, conformances);
return ::new (mem) ErasureExpr(subExpr, type, conformances, argConversions);
}

UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
Expand All @@ -1194,8 +1196,8 @@ UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
SourceLoc RAngleLoc) {
auto size = totalSizeToAlloc<TypeRepr *>(UnresolvedParams.size());
auto mem = ctx.Allocate(size, alignof(UnresolvedSpecializeExpr));
return ::new(mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
UnresolvedParams, RAngleLoc);
return ::new (mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
UnresolvedParams, RAngleLoc);
}

CaptureListEntry::CaptureListEntry(PatternBindingDecl *PBD) : PBD(PBD) {
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ NominalTypeDecl *CanType::getAnyNominal() const {
GenericTypeDecl *CanType::getAnyGeneric() const {
if (auto existential = dyn_cast<ExistentialType>(*this))
return existential->getConstraintType()->getAnyGeneric();
if (auto ppt = dyn_cast<ParameterizedProtocolType>(*this))
return ppt->getBaseType()->getDecl();
if (auto Ty = dyn_cast<AnyGenericType>(*this))
return Ty->getDecl();
return nullptr;
Expand Down
Loading