Skip to content

Commit dde0d8f

Browse files
committed
Generalize the Mangling of Constrained Existential Types
Upgrade the old mangling from a list of argument types to a list of requiremnets. For now, only same-type requirements may actually be mangled since those are all that are available to the surface language. Reconstruction of existential types now consists of demangling (a list of) base protocol(s), decoding the constraints, and converting the same-type constraints back into a list of arguments. rdar://96088707
1 parent 6a24087 commit dde0d8f

25 files changed

+496
-273
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ Types
638638
type ::= protocol-list 'p' // existential type
639639
type ::= protocol-list superclass 'Xc' // existential type with superclass
640640
type ::= protocol-list 'Xl' // existential type with AnyObject
641-
type ::= protocol-list 'y' (type* '_')* type* retroactive-conformance* 'XP' // parameterized protocol type
641+
type ::= protocol-list requirement* '_' 'XP' // constrained existential type
642642
type ::= type-list 't' // tuple
643643
type ::= type generic-signature 'u' // generic type
644644
type ::= 'x' // generic param, depth=0, idx=0
@@ -879,6 +879,7 @@ now codified into the ABI; the index 0 is therefore reserved.
879879
GENERIC-PARAM-INDEX ::= 'z' // depth = 0, idx = 0
880880
GENERIC-PARAM-INDEX ::= INDEX // depth = 0, idx = N+1
881881
GENERIC-PARAM-INDEX ::= 'd' INDEX INDEX // depth = M+1, idx = N
882+
GENERIC-PARAM-INDEX ::= 's' // depth = 0, idx = 0; Constrained existential 'Self' type
882883

883884
LAYOUT-CONSTRAINT ::= 'N' // NativeRefCountedObject
884885
LAYOUT-CONSTRAINT ::= 'R' // RefCountedObject

include/swift/AST/ASTDemangler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ class ASTBuilder {
119119

120120
Type createProtocolTypeFromDecl(ProtocolDecl *protocol);
121121

122-
Type createParameterizedProtocolType(Type base, ArrayRef<Type> args);
122+
Type createConstrainedExistentialType(Type base,
123+
ArrayRef<BuiltRequirement> constraints);
123124

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

include/swift/AST/ASTMangler.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ class ASTMangler : public Mangler {
343343
bool &isAssocTypeAtDepth);
344344

345345
void appendOpWithGenericParamIndex(StringRef,
346-
const GenericTypeParamType *paramTy);
346+
const GenericTypeParamType *paramTy,
347+
bool baseIsProtocolSelf = false);
347348

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

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

450460
void appendGenericSignatureParts(GenericSignature sig,
451461
ArrayRef<CanTypeWrapper<GenericTypeParamType>> params,
@@ -521,6 +531,9 @@ class ASTMangler : public Mangler {
521531
Demangle::AutoDiffFunctionKind kind,
522532
const AutoDiffConfig &config);
523533
void appendIndexSubset(IndexSubset *indexSubset);
534+
535+
void appendConstrainedExistential(Type base, GenericSignature sig,
536+
const ValueDecl *forDecl);
524537
};
525538

526539
} // end namespace Mangle

include/swift/Demangling/DemangleNodes.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ NODE(FunctionSignatureSpecializationReturn)
9898
NODE(FunctionSignatureSpecializationParamKind)
9999
NODE(FunctionSignatureSpecializationParamPayload)
100100
NODE(FunctionType)
101+
NODE(ConstrainedExistential)
102+
NODE(ConstrainedExistentialRequirementList)
103+
NODE(ConstrainedExistentialSelf)
101104
NODE(GenericPartialSpecialization)
102105
NODE(GenericPartialSpecializationNotReAbstracted)
103106
NODE(GenericProtocolWitnessTable)
@@ -170,7 +173,6 @@ NODE(EscapingObjCBlock)
170173
CONTEXT_NODE(OtherNominalType)
171174
CONTEXT_NODE(OwningAddressor)
172175
CONTEXT_NODE(OwningMutableAddressor)
173-
NODE(ParameterizedProtocol)
174176
NODE(PartialApplyForwarder)
175177
NODE(PartialApplyObjCForwarder)
176178
NODE(PostfixOperator)

include/swift/Demangling/Demangler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,8 @@ class Demangler : public NodeFactory {
584584
NodePointer demangleIndexSubset();
585585
NodePointer demangleDifferentiableFunctionType();
586586

587+
NodePointer demangleConstrainedExistentialRequirementList();
588+
587589
bool demangleBoundGenerics(Vector<NodePointer> &TypeListList,
588590
NodePointer &RetroactiveConformances);
589591

include/swift/Demangling/TypeDecoder.h

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ class TypeDecoder {
713713
forRequirement);
714714
}
715715

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

726-
llvm::SmallVector<BuiltType, 8> args;
726+
llvm::SmallVector<BuiltRequirement, 8> requirements;
727727

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

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

740-
return Builder.createParameterizedProtocolType(protocolType.getType(),
741-
args);
735+
return Builder.createConstrainedExistentialType(protocolType.getType(),
736+
requirements);
742737
}
738+
case NodeKind::ConstrainedExistentialSelf:
739+
return Builder.createGenericTypeParameterType(/*depth*/ 0, /*index*/ 0);
743740

744741
case NodeKind::Protocol:
745742
case NodeKind::ProtocolSymbolicReference: {

include/swift/Reflection/TypeRef.h

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -563,39 +563,48 @@ class ProtocolCompositionTypeRef final : public TypeRef {
563563
}
564564
};
565565

566-
class ParameterizedProtocolTypeRef final : public TypeRef {
566+
class ConstrainedExistentialTypeRef final : public TypeRef {
567567
const ProtocolCompositionTypeRef *Base;
568-
std::vector<const TypeRef *> Args;
568+
std::vector<TypeRefRequirement> Requirements;
569569

570570
static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol,
571-
std::vector<const TypeRef *> Args) {
571+
std::vector<TypeRefRequirement> Requirements) {
572572
TypeRefID ID;
573573
ID.addPointer(Protocol);
574-
for (auto Arg : Args) {
575-
ID.addPointer(Arg);
574+
for (auto reqt : Requirements) {
575+
ID.addPointer(reqt.getFirstType());
576+
if (reqt.getKind() != RequirementKind::Layout)
577+
ID.addPointer(reqt.getSecondType());
578+
else
579+
ID.addInteger(
580+
unsigned(0)); // FIXME: Layout constraints aren't implemented yet
581+
ID.addInteger(unsigned(reqt.getKind()));
576582
}
577583
return ID;
578584
}
579585

580586
public:
581-
ParameterizedProtocolTypeRef(const ProtocolCompositionTypeRef *Protocol,
582-
std::vector<const TypeRef *> Args)
583-
: TypeRef(TypeRefKind::ParameterizedProtocol), Base(Protocol),
584-
Args(Args) {}
587+
ConstrainedExistentialTypeRef(const ProtocolCompositionTypeRef *Protocol,
588+
std::vector<TypeRefRequirement> Requirements)
589+
: TypeRef(TypeRefKind::ConstrainedExistential), Base(Protocol),
590+
Requirements(Requirements) {}
585591

586592
template <typename Allocator>
587-
static const ParameterizedProtocolTypeRef *
593+
static const ConstrainedExistentialTypeRef *
588594
create(Allocator &A, const ProtocolCompositionTypeRef *Protocol,
589-
std::vector<const TypeRef *> Args) {
590-
FIND_OR_CREATE_TYPEREF(A, ParameterizedProtocolTypeRef, Protocol, Args);
595+
std::vector<TypeRefRequirement> Requirements) {
596+
FIND_OR_CREATE_TYPEREF(A, ConstrainedExistentialTypeRef, Protocol,
597+
Requirements);
591598
}
592599

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

595-
const std::vector<const TypeRef *> &getArgs() const { return Args; }
602+
const std::vector<TypeRefRequirement> &getRequirements() const {
603+
return Requirements;
604+
}
596605

597606
static bool classof(const TypeRef *TR) {
598-
return TR->getKind() == TypeRefKind::ParameterizedProtocol;
607+
return TR->getKind() == TypeRefKind::ConstrainedExistential;
599608
}
600609
};
601610

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -650,13 +650,12 @@ class TypeRefBuilder {
650650
isClassBound);
651651
}
652652

653-
const ParameterizedProtocolTypeRef *
654-
createParameterizedProtocolType(const TypeRef *base,
655-
llvm::ArrayRef<const TypeRef *> args) {
653+
const ConstrainedExistentialTypeRef *createConstrainedExistentialType(
654+
const TypeRef *base, llvm::ArrayRef<BuiltRequirement> constraints) {
656655
auto *baseProto = llvm::dyn_cast<ProtocolCompositionTypeRef>(base);
657656
if (!baseProto)
658657
return nullptr;
659-
return ParameterizedProtocolTypeRef::create(*this, baseProto, args);
658+
return ConstrainedExistentialTypeRef::create(*this, baseProto, constraints);
660659
}
661660

662661
const ExistentialMetatypeTypeRef *createExistentialMetatypeType(

include/swift/Reflection/TypeRefs.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ TYPEREF(BoundGeneric, TypeRef)
2222
TYPEREF(Tuple, TypeRef)
2323
TYPEREF(Function, TypeRef)
2424
TYPEREF(ProtocolComposition, TypeRef)
25-
TYPEREF(ParameterizedProtocol, TypeRef)
25+
TYPEREF(ConstrainedExistential, TypeRef)
2626
TYPEREF(Metatype, TypeRef)
2727
TYPEREF(ExistentialMetatype, TypeRef)
2828
TYPEREF(GenericTypeParameter, TypeRef)

lib/AST/ASTDemangler.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,12 +625,38 @@ Type ASTBuilder::createExistentialMetatypeType(Type instance,
625625
getMetatypeRepresentation(*repr));
626626
}
627627

628-
Type ASTBuilder::createParameterizedProtocolType(Type base,
629-
ArrayRef<Type> args) {
628+
Type ASTBuilder::createConstrainedExistentialType(
629+
Type base, ArrayRef<BuiltRequirement> constraints) {
630+
// FIXME: Generalize to other kinds of bases.
630631
if (!base->getAs<ProtocolType>())
631632
return Type();
632-
return ParameterizedProtocolType::get(base->getASTContext(),
633-
base->castTo<ProtocolType>(), args);
633+
auto baseTy = base->castTo<ProtocolType>();
634+
auto baseDecl = baseTy->getDecl();
635+
llvm::SmallDenseMap<Identifier, Type> cmap;
636+
for (const auto &req : constraints) {
637+
switch (req.getKind()) {
638+
case RequirementKind::Conformance:
639+
case RequirementKind::Superclass:
640+
case RequirementKind::Layout:
641+
continue;
642+
643+
case RequirementKind::SameType:
644+
if (auto *DMT = req.getFirstType()->getAs<DependentMemberType>())
645+
if (baseDecl->getAssociatedType(DMT->getName()))
646+
cmap[DMT->getName()] = req.getSecondType();
647+
}
648+
}
649+
llvm::SmallVector<Type, 4> args;
650+
for (auto *assocTy : baseDecl->getPrimaryAssociatedTypes()) {
651+
auto argTy = cmap.find(assocTy->getName());
652+
if (argTy == cmap.end()) {
653+
return Type();
654+
}
655+
args.push_back(argTy->getSecond());
656+
}
657+
auto constrainedBase =
658+
ParameterizedProtocolType::get(base->getASTContext(), baseTy, args);
659+
return ExistentialType::get(constrainedBase);
634660
}
635661

636662
Type ASTBuilder::createMetatypeType(Type instance,

0 commit comments

Comments
 (0)