Skip to content

Generalize the Mangling of Constrained Existential Types #59763

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 1 commit into from
Jul 1, 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
3 changes: 2 additions & 1 deletion docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,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
type ::= protocol-list requirement* '_' 'XP' // constrained existential type
type ::= type-list 't' // tuple
type ::= type generic-signature 'u' // generic type
type ::= 'x' // generic param, depth=0, idx=0
Expand Down Expand Up @@ -879,6 +879,7 @@ now codified into the ABI; the index 0 is therefore reserved.
GENERIC-PARAM-INDEX ::= 'z' // depth = 0, idx = 0
GENERIC-PARAM-INDEX ::= INDEX // depth = 0, idx = N+1
GENERIC-PARAM-INDEX ::= 'd' INDEX INDEX // depth = M+1, idx = N
GENERIC-PARAM-INDEX ::= 's' // depth = 0, idx = 0; Constrained existential 'Self' type

LAYOUT-CONSTRAINT ::= 'N' // NativeRefCountedObject
LAYOUT-CONSTRAINT ::= 'R' // RefCountedObject
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ class ASTBuilder {

Type createProtocolTypeFromDecl(ProtocolDecl *protocol);

Type createParameterizedProtocolType(Type base, ArrayRef<Type> args);
Type createConstrainedExistentialType(Type base,
ArrayRef<BuiltRequirement> constraints);

Type createExistentialMetatypeType(Type instance,
Optional<Demangle::ImplMetatypeRepresentation> repr=None);
Expand Down
19 changes: 16 additions & 3 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ class ASTMangler : public Mangler {
bool &isAssocTypeAtDepth);

void appendOpWithGenericParamIndex(StringRef,
const GenericTypeParamType *paramTy);
const GenericTypeParamType *paramTy,
bool baseIsProtocolSelf = false);

/// Mangles a sugared type iff we are mangling for the debugger.
template <class T> void appendSugaredType(Type type,
Expand Down Expand Up @@ -444,8 +445,17 @@ class ASTMangler : public Mangler {
bool appendGenericSignature(GenericSignature sig,
GenericSignature contextSig = nullptr);

void appendRequirement(const Requirement &reqt,
GenericSignature sig);
/// Append a requirement to the mangling.
///
/// \param reqt The requirement to mangle
/// \param sig The generic signature.
/// \param lhsBaseIsProtocolSelf If \c true, mangle the base of the left-hand
/// side of the constraint with a special protocol 'Self' sentinel node. This
/// supports distinguishing requirements rooted at 'Self' in constrained
/// existentials from ambient generic parameters that would otherwise be
/// at e.g. (0, 0) as well.
void appendRequirement(const Requirement &reqt, GenericSignature sig,
bool lhsBaseIsProtocolSelf = false);

void appendGenericSignatureParts(GenericSignature sig,
ArrayRef<CanTypeWrapper<GenericTypeParamType>> params,
Expand Down Expand Up @@ -521,6 +531,9 @@ class ASTMangler : public Mangler {
Demangle::AutoDiffFunctionKind kind,
const AutoDiffConfig &config);
void appendIndexSubset(IndexSubset *indexSubset);

void appendConstrainedExistential(Type base, GenericSignature sig,
const ValueDecl *forDecl);
};

} // end namespace Mangle
Expand Down
4 changes: 3 additions & 1 deletion include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ NODE(FunctionSignatureSpecializationReturn)
NODE(FunctionSignatureSpecializationParamKind)
NODE(FunctionSignatureSpecializationParamPayload)
NODE(FunctionType)
NODE(ConstrainedExistential)
NODE(ConstrainedExistentialRequirementList)
NODE(ConstrainedExistentialSelf)
NODE(GenericPartialSpecialization)
NODE(GenericPartialSpecializationNotReAbstracted)
NODE(GenericProtocolWitnessTable)
Expand Down Expand Up @@ -170,7 +173,6 @@ NODE(EscapingObjCBlock)
CONTEXT_NODE(OtherNominalType)
CONTEXT_NODE(OwningAddressor)
CONTEXT_NODE(OwningMutableAddressor)
NODE(ParameterizedProtocol)
NODE(PartialApplyForwarder)
NODE(PartialApplyObjCForwarder)
NODE(PostfixOperator)
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,8 @@ class Demangler : public NodeFactory {
NodePointer demangleIndexSubset();
NodePointer demangleDifferentiableFunctionType();

NodePointer demangleConstrainedExistentialRequirementList();

bool demangleBoundGenerics(Vector<NodePointer> &TypeListList,
NodePointer &RetroactiveConformances);

Expand Down
25 changes: 11 additions & 14 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ class TypeDecoder {
forRequirement);
}

case NodeKind::ParameterizedProtocol: {
case NodeKind::ConstrainedExistential: {
if (Node->getNumChildren() < 2)
return MAKE_NODE_TYPE_ERROR(Node,
"fewer children (%zu) than required (2)",
Expand All @@ -723,23 +723,20 @@ class TypeDecoder {
if (protocolType.isError())
return protocolType;

llvm::SmallVector<BuiltType, 8> args;
llvm::SmallVector<BuiltRequirement, 8> requirements;

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

for (auto genericArg : *genericArgs) {
auto paramType = decodeMangledType(genericArg, depth + 1,
/*forRequirement=*/false);
if (paramType.isError())
return paramType;
args.push_back(paramType.getType());
}
decodeRequirement<BuiltType, BuiltRequirement, BuiltLayoutConstraint,
BuilderType>(reqts, requirements, Builder);

return Builder.createParameterizedProtocolType(protocolType.getType(),
args);
return Builder.createConstrainedExistentialType(protocolType.getType(),
requirements);
}
case NodeKind::ConstrainedExistentialSelf:
return Builder.createGenericTypeParameterType(/*depth*/ 0, /*index*/ 0);

case NodeKind::Protocol:
case NodeKind::ProtocolSymbolicReference: {
Expand Down
37 changes: 23 additions & 14 deletions include/swift/Reflection/TypeRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,39 +563,48 @@ class ProtocolCompositionTypeRef final : public TypeRef {
}
};

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

static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol,
std::vector<const TypeRef *> Args) {
std::vector<TypeRefRequirement> Requirements) {
TypeRefID ID;
ID.addPointer(Protocol);
for (auto Arg : Args) {
ID.addPointer(Arg);
for (auto reqt : Requirements) {
ID.addPointer(reqt.getFirstType());
if (reqt.getKind() != RequirementKind::Layout)
ID.addPointer(reqt.getSecondType());
else
ID.addInteger(
unsigned(0)); // FIXME: Layout constraints aren't implemented yet
ID.addInteger(unsigned(reqt.getKind()));
}
return ID;
}

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

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

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

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

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

Expand Down
7 changes: 3 additions & 4 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -650,13 +650,12 @@ class TypeRefBuilder {
isClassBound);
}

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

const ExistentialMetatypeTypeRef *createExistentialMetatypeType(
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Reflection/TypeRefs.def
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ TYPEREF(BoundGeneric, TypeRef)
TYPEREF(Tuple, TypeRef)
TYPEREF(Function, TypeRef)
TYPEREF(ProtocolComposition, TypeRef)
TYPEREF(ParameterizedProtocol, TypeRef)
TYPEREF(ConstrainedExistential, TypeRef)
TYPEREF(Metatype, TypeRef)
TYPEREF(ExistentialMetatype, TypeRef)
TYPEREF(GenericTypeParameter, TypeRef)
Expand Down
34 changes: 30 additions & 4 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,12 +625,38 @@ Type ASTBuilder::createExistentialMetatypeType(Type instance,
getMetatypeRepresentation(*repr));
}

Type ASTBuilder::createParameterizedProtocolType(Type base,
ArrayRef<Type> args) {
Type ASTBuilder::createConstrainedExistentialType(
Type base, ArrayRef<BuiltRequirement> constraints) {
// FIXME: Generalize to other kinds of bases.
if (!base->getAs<ProtocolType>())
return Type();
return ParameterizedProtocolType::get(base->getASTContext(),
base->castTo<ProtocolType>(), args);
auto baseTy = base->castTo<ProtocolType>();
auto baseDecl = baseTy->getDecl();
llvm::SmallDenseMap<Identifier, Type> cmap;
for (const auto &req : constraints) {
switch (req.getKind()) {
case RequirementKind::Conformance:
case RequirementKind::Superclass:
case RequirementKind::Layout:
continue;

case RequirementKind::SameType:
if (auto *DMT = req.getFirstType()->getAs<DependentMemberType>())
if (baseDecl->getAssociatedType(DMT->getName()))
cmap[DMT->getName()] = req.getSecondType();
}
}
llvm::SmallVector<Type, 4> args;
for (auto *assocTy : baseDecl->getPrimaryAssociatedTypes()) {
auto argTy = cmap.find(assocTy->getName());
if (argTy == cmap.end()) {
return Type();
}
args.push_back(argTy->getSecond());
}
auto constrainedBase =
ParameterizedProtocolType::get(base->getASTContext(), baseTy, args);
return ExistentialType::get(constrainedBase);
}

Type ASTBuilder::createMetatypeType(Type instance,
Expand Down
Loading