diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index d0ae2da94fef6..667bf22329f92 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -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 @@ -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 diff --git a/include/swift/AST/ASTDemangler.h b/include/swift/AST/ASTDemangler.h index f00299d896dd9..486d65f720b04 100644 --- a/include/swift/AST/ASTDemangler.h +++ b/include/swift/AST/ASTDemangler.h @@ -119,7 +119,8 @@ class ASTBuilder { Type createProtocolTypeFromDecl(ProtocolDecl *protocol); - Type createParameterizedProtocolType(Type base, ArrayRef args); + Type createConstrainedExistentialType(Type base, + ArrayRef constraints); Type createExistentialMetatypeType(Type instance, Optional repr=None); diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index c27d63245db9f..5939cb61498a8 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -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 void appendSugaredType(Type type, @@ -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> params, @@ -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 diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index bdb63526fdfc1..c86c998d0b326 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -98,6 +98,9 @@ NODE(FunctionSignatureSpecializationReturn) NODE(FunctionSignatureSpecializationParamKind) NODE(FunctionSignatureSpecializationParamPayload) NODE(FunctionType) +NODE(ConstrainedExistential) +NODE(ConstrainedExistentialRequirementList) +NODE(ConstrainedExistentialSelf) NODE(GenericPartialSpecialization) NODE(GenericPartialSpecializationNotReAbstracted) NODE(GenericProtocolWitnessTable) @@ -170,7 +173,6 @@ NODE(EscapingObjCBlock) CONTEXT_NODE(OtherNominalType) CONTEXT_NODE(OwningAddressor) CONTEXT_NODE(OwningMutableAddressor) -NODE(ParameterizedProtocol) NODE(PartialApplyForwarder) NODE(PartialApplyObjCForwarder) NODE(PostfixOperator) diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h index 16662ab06b32c..6c72de49bb300 100644 --- a/include/swift/Demangling/Demangler.h +++ b/include/swift/Demangling/Demangler.h @@ -584,6 +584,8 @@ class Demangler : public NodeFactory { NodePointer demangleIndexSubset(); NodePointer demangleDifferentiableFunctionType(); + NodePointer demangleConstrainedExistentialRequirementList(); + bool demangleBoundGenerics(Vector &TypeListList, NodePointer &RetroactiveConformances); diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index d8ef4b940e5f3..76463521bb874 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -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)", @@ -723,23 +723,20 @@ class TypeDecoder { if (protocolType.isError()) return protocolType; - llvm::SmallVector args; + llvm::SmallVector 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(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: { diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h index 3227b91ac80ae..9e20f97525648 100644 --- a/include/swift/Reflection/TypeRef.h +++ b/include/swift/Reflection/TypeRef.h @@ -563,39 +563,48 @@ class ProtocolCompositionTypeRef final : public TypeRef { } }; -class ParameterizedProtocolTypeRef final : public TypeRef { +class ConstrainedExistentialTypeRef final : public TypeRef { const ProtocolCompositionTypeRef *Base; - std::vector Args; + std::vector Requirements; static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol, - std::vector Args) { + std::vector 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 Args) - : TypeRef(TypeRefKind::ParameterizedProtocol), Base(Protocol), - Args(Args) {} + ConstrainedExistentialTypeRef(const ProtocolCompositionTypeRef *Protocol, + std::vector Requirements) + : TypeRef(TypeRefKind::ConstrainedExistential), Base(Protocol), + Requirements(Requirements) {} template - static const ParameterizedProtocolTypeRef * + static const ConstrainedExistentialTypeRef * create(Allocator &A, const ProtocolCompositionTypeRef *Protocol, - std::vector Args) { - FIND_OR_CREATE_TYPEREF(A, ParameterizedProtocolTypeRef, Protocol, Args); + std::vector Requirements) { + FIND_OR_CREATE_TYPEREF(A, ConstrainedExistentialTypeRef, Protocol, + Requirements); } const ProtocolCompositionTypeRef *getBase() const { return Base; } - const std::vector &getArgs() const { return Args; } + const std::vector &getRequirements() const { + return Requirements; + } static bool classof(const TypeRef *TR) { - return TR->getKind() == TypeRefKind::ParameterizedProtocol; + return TR->getKind() == TypeRefKind::ConstrainedExistential; } }; diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index ce3712456bb44..ac1b62068fc2a 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -650,13 +650,12 @@ class TypeRefBuilder { isClassBound); } - const ParameterizedProtocolTypeRef * - createParameterizedProtocolType(const TypeRef *base, - llvm::ArrayRef args) { + const ConstrainedExistentialTypeRef *createConstrainedExistentialType( + const TypeRef *base, llvm::ArrayRef constraints) { auto *baseProto = llvm::dyn_cast(base); if (!baseProto) return nullptr; - return ParameterizedProtocolTypeRef::create(*this, baseProto, args); + return ConstrainedExistentialTypeRef::create(*this, baseProto, constraints); } const ExistentialMetatypeTypeRef *createExistentialMetatypeType( diff --git a/include/swift/Reflection/TypeRefs.def b/include/swift/Reflection/TypeRefs.def index 61baf077fd505..e95845700b539 100644 --- a/include/swift/Reflection/TypeRefs.def +++ b/include/swift/Reflection/TypeRefs.def @@ -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) diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index fe6a49e429068..22ff7781af4f8 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -625,12 +625,38 @@ Type ASTBuilder::createExistentialMetatypeType(Type instance, getMetatypeRepresentation(*repr)); } -Type ASTBuilder::createParameterizedProtocolType(Type base, - ArrayRef args) { +Type ASTBuilder::createConstrainedExistentialType( + Type base, ArrayRef constraints) { + // FIXME: Generalize to other kinds of bases. if (!base->getAs()) return Type(); - return ParameterizedProtocolType::get(base->getASTContext(), - base->castTo(), args); + auto baseTy = base->castTo(); + auto baseDecl = baseTy->getDecl(); + llvm::SmallDenseMap 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()) + if (baseDecl->getAssociatedType(DMT->getName())) + cmap[DMT->getName()] = req.getSecondType(); + } + } + llvm::SmallVector 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, diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 0709b66022277..da9c8af35ed54 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1233,7 +1233,12 @@ void ASTMangler::appendType(Type type, GenericSignature sig, case TypeKind::ExistentialMetatype: { ExistentialMetatypeType *EMT = cast(tybase); - appendType(EMT->getInstanceType(), sig, forDecl); + if (EMT->getInstanceType()->isExistentialType() && + EMT->hasParameterizedExistential()) + appendConstrainedExistential(EMT->getInstanceType(), sig, forDecl); + else + appendType(EMT->getInstanceType(), sig, forDecl); + if (EMT->hasRepresentation()) { appendOperator("Xm", getMetatypeRepresentationOp(EMT->getRepresentation())); @@ -1283,17 +1288,16 @@ void ASTMangler::appendType(Type type, GenericSignature sig, return appendExistentialLayout(layout, sig, forDecl); } - case TypeKind::ParameterizedProtocol: { - auto layout = type->getExistentialLayout(); - appendExistentialLayout(layout, sig, forDecl); - bool isFirstArgList = true; - appendBoundGenericArgs(type, sig, isFirstArgList, forDecl); - return appendOperator("XP"); - } + case TypeKind::ParameterizedProtocol: + llvm_unreachable("Handled by generalized existential mangling!"); case TypeKind::Existential: { - auto constraint = cast(tybase)->getConstraintType(); - return appendType(constraint, sig, forDecl); + auto *ET = cast(tybase); + if (tybase->hasParameterizedExistential()) { + return appendConstrainedExistential(ET->getConstraintType(), sig, + forDecl); + } + return appendType(ET->getConstraintType(), sig, forDecl); } case TypeKind::UnboundGeneric: @@ -1490,8 +1494,9 @@ GenericTypeParamType *ASTMangler::appendAssocType(DependentMemberType *DepTy, return nullptr; } -void ASTMangler::appendOpWithGenericParamIndex(StringRef Op, - const GenericTypeParamType *paramTy) { +void ASTMangler::appendOpWithGenericParamIndex( + StringRef Op, const GenericTypeParamType *paramTy, + bool baseIsProtocolSelf) { llvm::SmallVector OpBuf(Op.begin(), Op.end()); if (paramTy->getDepth() > 0) { OpBuf.push_back('d'); @@ -1500,7 +1505,11 @@ void ASTMangler::appendOpWithGenericParamIndex(StringRef Op, Index(paramTy->getIndex())); } if (paramTy->getIndex() == 0) { - OpBuf.push_back('z'); + if (baseIsProtocolSelf) { + OpBuf.push_back('s'); + } else { + OpBuf.push_back('z'); + } return appendOperator(StringRef(OpBuf.data(), OpBuf.size())); } appendOperator(Op, Index(paramTy->getIndex() - 1)); @@ -1600,9 +1609,6 @@ void ASTMangler::appendBoundGenericArgs(Type type, GenericSignature sig, if (Type parent = nominalType->getParent()) appendBoundGenericArgs(parent->getDesugaredType(), sig, isFirstArgList, forDecl); - } else if (auto *ppt = dyn_cast(typePtr)) { - assert(!ppt->getBaseType()->getParent()); - genericArgs = ppt->getArgs(); } else { auto boundType = cast(typePtr); genericArgs = boundType->getGenericArgs(); @@ -2797,7 +2803,8 @@ bool ASTMangler::appendGenericSignature(GenericSignature sig, } void ASTMangler::appendRequirement(const Requirement &reqt, - GenericSignature sig) { + GenericSignature sig, + bool lhsBaseIsProtocolSelf) { Type FirstTy = reqt.getFirstType()->getCanonicalType(); @@ -2820,7 +2827,6 @@ void ASTMangler::appendRequirement(const Requirement &reqt, } if (auto *DT = FirstTy->getAs()) { - bool isAssocTypeAtDepth = false; if (tryMangleTypeSubstitution(DT, sig)) { switch (reqt.getKind()) { case RequirementKind::Conformance: @@ -2836,6 +2842,7 @@ void ASTMangler::appendRequirement(const Requirement &reqt, } llvm_unreachable("bad requirement type"); } + bool isAssocTypeAtDepth = false; GenericTypeParamType *gpBase = appendAssocType(DT, sig, isAssocTypeAtDepth); addTypeSubstitution(DT, sig); @@ -2843,17 +2850,18 @@ void ASTMangler::appendRequirement(const Requirement &reqt, switch (reqt.getKind()) { case RequirementKind::Conformance: return appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RP" : "Rp", - gpBase); + gpBase, lhsBaseIsProtocolSelf); case RequirementKind::Layout: - appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RM" : "Rm", gpBase); + appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RM" : "Rm", gpBase, + lhsBaseIsProtocolSelf); appendOpParamForLayoutConstraint(reqt.getLayoutConstraint()); return; case RequirementKind::Superclass: return appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RC" : "Rc", - gpBase); + gpBase, lhsBaseIsProtocolSelf); case RequirementKind::SameType: return appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RT" : "Rt", - gpBase); + gpBase, lhsBaseIsProtocolSelf); } llvm_unreachable("bad requirement type"); } @@ -3493,3 +3501,59 @@ std::string ASTMangler::mangleDistributedThunk(const FuncDecl *thunk) { false); return mangleEntity(thunk, SymbolKind::DistributedThunk); } + +static void gatherExistentialRequirements(SmallVectorImpl &reqs, + ParameterizedProtocolType *PPT) { + auto protoTy = PPT->getBaseType(); + PPT->getRequirements(protoTy->getDecl()->getSelfInterfaceType(), reqs); +} + +void ASTMangler::appendConstrainedExistential(Type base, GenericSignature sig, + const ValueDecl *forDecl) { + auto layout = base->getExistentialLayout(); + appendExistentialLayout(layout, sig, forDecl); + SmallVector requirements; + assert(!base->is() && + "plain protocol type constraint has no generalization structure"); + if (auto *PCT = base->getAs()) { + for (auto memberTy : PCT->getMembers()) { + if (auto *PPT = memberTy->getAs()) + gatherExistentialRequirements(requirements, PPT); + } + } else { + auto *PPT = base->castTo(); + gatherExistentialRequirements(requirements, PPT); + } + + assert(!requirements.empty() && "Unconstrained existential?"); + // Sort the requirements to canonicalize their order. + llvm::array_pod_sort( + requirements.begin(), requirements.end(), + [](const Requirement *lhs, const Requirement *rhs) -> int { + return lhs->compare(*rhs); + }); + + bool firstRequirement = true; + for (const auto &reqt : requirements) { + switch (reqt.getKind()) { + case RequirementKind::Layout: + case RequirementKind::Conformance: + case RequirementKind::Superclass: + // The surface language cannot express these requirements yet, so + // we have no mangling for them. + assert(false && "Unexpected requirement in constrained existential!"); + continue; + + case RequirementKind::SameType: { + break; + } + } + + appendRequirement(reqt, sig, /*baseIsProtocolSelf*/ true); + if (firstRequirement) { + appendOperator("_"); + firstRequirement = false; + } + } + return appendOperator("XP"); +} diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 318853d8360b4..9e60609f00fc3 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1819,12 +1819,6 @@ NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal, case Node::Kind::Constructor: // Well, not really a nominal type. return createWithChildren(Node::Kind::BoundGenericFunction, Nominal, args); - case Node::Kind::Type: - if (!Nominal->hasChildren()) - return nullptr; - if (Nominal->getFirstChild()->getKind() != Node::Kind::ProtocolList) - return nullptr; - return createWithChildren(Node::Kind::ParameterizedProtocol, Nominal, args); default: return nullptr; } @@ -2368,6 +2362,9 @@ NodePointer Demangler::demangleGenericParamIndex() { if (nextIf('z')) { return getDependentGenericParamType(0, 0); } + if (nextIf('s')) { + return createNode(Node::Kind::ConstrainedExistentialSelf); + } return getDependentGenericParamType(0, demangleIndex() + 1); } @@ -3271,20 +3268,10 @@ NodePointer Demangler::demangleSpecialType() { MTR, Type)); } case 'P': { - NodePointer RetroactiveConformances; - Vector TypeListList(*this, 4); - - if (!demangleBoundGenerics(TypeListList, RetroactiveConformances)) - return nullptr; - - NodePointer Type = popNode(Node::Kind::Type); - if (!Type) - return nullptr; - - NodePointer BoundNode = demangleBoundGenericArgs(Type, TypeListList, 0); - NodePointer NTy = createType(BoundNode); - addSubstitution(NTy); - return NTy; + NodePointer Reqs = demangleConstrainedExistentialRequirementList(); + NodePointer Base = popNode(Node::Kind::Type); + return createType( + createWithChildren(Node::Kind::ConstrainedExistential, Base, Reqs)); } case 'p': return createType(createWithChild(Node::Kind::ExistentialMetatype, @@ -3576,6 +3563,22 @@ NodePointer Demangler::demangleProtocolListType() { return createType(ProtoList); } +NodePointer Demangler::demangleConstrainedExistentialRequirementList() { + NodePointer ReqList = + createNode(Node::Kind::ConstrainedExistentialRequirementList); + bool firstElem = false; + do { + firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr); + NodePointer Req = popNode(isRequirement); + if (!Req) + return nullptr; + ReqList->addChild(Req, *this); + } while (!firstElem); + + ReqList->reverseChildren(); + return ReqList; +} + NodePointer Demangler::demangleGenericSignature(bool hasParamCounts) { NodePointer Sig = createNode(Node::Kind::DependentGenericSignature); if (hasParamCounts) { diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 3e2f1505a1f6f..51c28d8512c00 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -306,7 +306,9 @@ class NodePrinter { case Node::Kind::MetatypeRepresentation: case Node::Kind::Module: case Node::Kind::Tuple: - case Node::Kind::ParameterizedProtocol: + case Node::Kind::ConstrainedExistential: + case Node::Kind::ConstrainedExistentialRequirementList: + case Node::Kind::ConstrainedExistentialSelf: case Node::Kind::Protocol: case Node::Kind::ProtocolSymbolicReference: case Node::Kind::ReturnType: @@ -2277,8 +2279,16 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, } return nullptr; } - case Node::Kind::ParameterizedProtocol: { - printBoundGeneric(Node, depth); + case Node::Kind::ConstrainedExistential: { + Printer << "any "; + print(Node->getChild(0), depth + 1); + Printer << "<"; + print(Node->getChild(1), depth + 1); + Printer << ">"; + return nullptr; + } + case Node::Kind::ConstrainedExistentialRequirementList: { + printChildren(Node, depth, ", "); return nullptr; } case Node::Kind::ExistentialMetatype: { @@ -2295,6 +2305,9 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, Printer << ".Type"; return nullptr; } + case Node::Kind::ConstrainedExistentialSelf: + Printer << "Self"; + return nullptr; case Node::Kind::MetatypeRepresentation: { Printer << Node->getText(); return nullptr; diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 5ccc0795fc7ae..3c87f8efe7965 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2719,8 +2719,17 @@ ManglingError Remangler::mangleObjCAsyncCompletionHandlerImpl(Node *node, unsigned depth) { return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); } -ManglingError Remangler::mangleParameterizedProtocol(Node *node, - unsigned int depth) { +ManglingError Remangler::mangleConstrainedExistential(Node *node, + unsigned int depth) { + return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); +} +ManglingError +Remangler::mangleConstrainedExistentialRequirementList(Node *node, + unsigned int depth) { + return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); +} +ManglingError Remangler::mangleConstrainedExistentialSelf(Node *node, + unsigned int depth) { return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); } ManglingError Remangler::mangleUniquable(Node *node, unsigned int depth) { diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 1a02f900158a2..a8fe085f9862a 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -416,6 +416,11 @@ bool Remangler::mangleStandardSubstitution(Node *node) { void Remangler::mangleDependentGenericParamIndex(Node *node, const char *nonZeroPrefix, char zeroOp) { + if (node->getKind() == Node::Kind::ConstrainedExistentialSelf) { + Buffer << 's'; + return; + } + auto paramDepth = node->getChild(0)->getIndex(); auto index = node->getChild(1)->getIndex(); @@ -449,7 +454,8 @@ Remangler::mangleConstrainedType(Node *node, unsigned depth) { node = getChildOfType(node->getFirstChild()); } - if (node->getKind() != Node::Kind::DependentGenericParamType) { + if (node->getKind() != Node::Kind::DependentGenericParamType && + node->getKind() != Node::Kind::ConstrainedExistentialSelf) { RETURN_IF_ERROR(mangle(node, depth + 1)); if (!Chain.size()) return std::pair{-1, nullptr}; @@ -601,7 +607,7 @@ ManglingError Remangler::mangleGenericArgs(Node *node, char &Separator, break; } - case Node::Kind::ParameterizedProtocol: { + case Node::Kind::ConstrainedExistential: { Buffer << Separator; Separator = '_'; RETURN_IF_ERROR(mangleChildNodes(node->getChild(1), depth + 1)); @@ -1225,15 +1231,32 @@ ManglingError Remangler::mangleErrorType(Node *node, unsigned depth) { return ManglingError::Success; } -ManglingError Remangler::mangleParameterizedProtocol(Node *node, - unsigned int depth) { - RETURN_IF_ERROR(mangleType(node->getChild(0), depth + 1)); - char separator = 'y'; - RETURN_IF_ERROR(mangleGenericArgs(node, separator, depth + 1)); +ManglingError Remangler::mangleConstrainedExistential(Node *node, + unsigned int depth) { + RETURN_IF_ERROR(mangleChildNode(node, 0, depth + 1)); + RETURN_IF_ERROR(mangleChildNode(node, 1, depth + 1)); Buffer << "XP"; return ManglingError::Success; } +ManglingError +Remangler::mangleConstrainedExistentialRequirementList(Node *node, + unsigned int depth) { + assert(node->getNumChildren() > 0); + bool FirstElem = true; + for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; ++Idx) { + RETURN_IF_ERROR(mangleChildNode(node, Idx, depth + 1)); + mangleListSeparator(FirstElem); + } + return ManglingError::Success; +} + +ManglingError Remangler::mangleConstrainedExistentialSelf(Node *node, + unsigned int depth) { + Buffer << "s"; + return ManglingError::Success; +} + ManglingError Remangler::mangleExistentialMetatype(Node *node, unsigned depth) { if (node->getFirstChild()->getKind() == Node::Kind::MetatypeRepresentation) { RETURN_IF_ERROR(mangleChildNode(node, 1, depth + 1)); @@ -3529,7 +3552,7 @@ bool Demangle::isSpecialized(Node *node) { case Node::Kind::BoundGenericTypeAlias: case Node::Kind::BoundGenericProtocol: case Node::Kind::BoundGenericFunction: - case Node::Kind::ParameterizedProtocol: + case Node::Kind::ConstrainedExistential: return true; case Node::Kind::Structure: @@ -3632,7 +3655,7 @@ ManglingErrorOr Demangle::getUnspecialized(Node *node, return nominalType; } - case Node::Kind::ParameterizedProtocol: { + case Node::Kind::ConstrainedExistential: { NodePointer unboundType = node->getChild(0); DEMANGLER_ASSERT(unboundType->getKind() == Node::Kind::Type, unboundType); return unboundType; diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index 58ac7286658f1..ddd29592d4da3 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -1440,16 +1440,23 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) { return createErrorExistentialTypeInfo(IGM, layout); } - // Note: Protocol composition types are not nominal, but we name them anyway. - if (auto existential = T->getAs()) { - T = existential->getConstraintType()->getCanonicalType(); - } llvm::StructType *type; - if (isa(T) || isa(T)) + if (T->hasParameterizedExistential()) { type = IGM.createNominalType(T); - else - type = IGM.createNominalType(cast(T.getPointer())); - + } else { + // Note: Protocol composition types are not nominal, but we name them + // anyway. + if (auto existential = T->getAs()) { + T = existential->getConstraintType()->getCanonicalType(); + } + + if (isa(T)) + type = IGM.createNominalType(T); + else + type = + IGM.createNominalType(cast(T.getPointer())); + } + assert(type->isOpaque() && "creating existential type in concrete struct"); // In an opaque metadata, the first two fields are the fixed buffer diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp index cd1ba11440aae..34d09ba5b691b 100644 --- a/lib/IRGen/IRGenMangler.cpp +++ b/lib/IRGen/IRGenMangler.cpp @@ -230,13 +230,17 @@ std::string IRGenMangler::mangleTypeForLLVMTypeName(CanType Ty) { // To make LLVM IR more readable we always add a 'T' prefix so that type names // don't start with a digit and don't need to be quoted. Buffer << 'T'; - if (auto existential = Ty->getAs()) - Ty = existential->getConstraintType()->getCanonicalType(); - if (auto P = dyn_cast(Ty)) { - appendProtocolName(P->getDecl(), /*allowStandardSubstitution=*/false); - appendOperator("P"); - } else { + if (Ty->is() && Ty->hasParameterizedExistential()) { appendType(Ty, nullptr); + } else { + if (auto existential = Ty->getAs()) + Ty = existential->getConstraintType()->getCanonicalType(); + if (auto P = dyn_cast(Ty)) { + appendProtocolName(P->getDecl(), /*allowStandardSubstitution=*/false); + appendOperator("P"); + } else { + appendType(Ty, nullptr); + } } return finalize(); } diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index 742a398300c39..8dd80ef049ba2 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -1758,7 +1758,7 @@ class HasFixedSize } bool - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { return true; } @@ -1879,7 +1879,7 @@ class HasSingletonMetatype } MetatypeRepresentation - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { return MetatypeRepresentation::Thin; } @@ -2330,8 +2330,8 @@ class LowerType } const TypeInfo * - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { - return visitProtocolCompositionTypeRef(PPT->getBase()); + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { + return visitProtocolCompositionTypeRef(CET->getBase()); } const TypeInfo *visitMetatypeTypeRef(const MetatypeTypeRef *M) { diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index b95f3ff8e7d3c..74611dfca8909 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -238,11 +238,11 @@ class PrintTypeRef : public TypeRefVisitor { } void - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { - printHeader("parameterized_protocol"); - printRec(PPT->getBase()); - for (auto param : PPT->getArgs()) - printRec(param); + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { + printHeader("constrained_existential_type"); + printRec(CET->getBase()); + for (auto req : CET->getRequirements()) + visitTypeRefRequirement(req); stream << ")"; } @@ -311,6 +311,27 @@ class PrintTypeRef : public TypeRefVisitor { stream << ")"; } + void visitTypeRefRequirement(const TypeRefRequirement &req) { + printHeader("requirement "); + switch (req.getKind()) { + case RequirementKind::Conformance: + case RequirementKind::Superclass: + printRec(req.getFirstType()); + stream << " : "; + printRec(req.getSecondType()); + break; + case RequirementKind::SameType: + printRec(req.getFirstType()); + stream << " == "; + printRec(req.getSecondType()); + break; + case RequirementKind::Layout: + stream << "layout requirement"; + break; + } + stream << ")"; + } + void visitSILBoxTypeWithLayoutTypeRef(const SILBoxTypeWithLayoutTypeRef *SB) { printHeader("sil_box_with_layout\n"); Indent += 2; @@ -333,24 +354,7 @@ class PrintTypeRef : public TypeRefVisitor { } Indent -= 2; for (auto &req : SB->getRequirements()) { - printHeader("requirement "); - switch (req.getKind()) { - case RequirementKind::Conformance: - case RequirementKind::Superclass: - printRec(req.getFirstType()); - stream << " : "; - printRec(req.getSecondType()); - break; - case RequirementKind::SameType: - printRec(req.getFirstType()); - stream << " == "; - printRec(req.getSecondType()); - break; - case RequirementKind::Layout: - stream << "layout requirement"; - break; - } - stream << ")"; + visitTypeRefRequirement(req); } stream << ")"; stream << ")"; @@ -431,8 +435,8 @@ struct TypeRefIsConcrete } bool - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { - return visit(PPT->getBase()); + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { + return visit(CET->getBase()); } bool visitMetatypeTypeRef(const MetatypeTypeRef *M) { @@ -777,13 +781,14 @@ class DemanglingForTypeRef } Demangle::NodePointer - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { - auto node = Dem.createNode(Node::Kind::ParameterizedProtocol); - node->addChild(visit(PPT->getBase()), Dem); - auto genericArgsList = Dem.createNode(Node::Kind::TypeList); - for (auto param : PPT->getArgs()) - genericArgsList->addChild(visit(param), Dem); - node->addChild(genericArgsList, Dem); + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { + auto node = Dem.createNode(Node::Kind::ConstrainedExistential); + node->addChild(visit(CET->getBase()), Dem); + auto constraintList = + Dem.createNode(Node::Kind::ConstrainedExistentialRequirementList); + for (auto req : CET->getRequirements()) + constraintList->addChild(visitTypeRefRequirement(req), Dem); + node->addChild(constraintList, Dem); return node; } @@ -858,6 +863,37 @@ class DemanglingForTypeRef return node; } + Demangle::NodePointer visitTypeRefRequirement(const TypeRefRequirement &req) { + switch (req.getKind()) { + case RequirementKind::Conformance: + case RequirementKind::Superclass: + case RequirementKind::SameType: { + Node::Kind kind; + switch (req.getKind()) { + case RequirementKind::Conformance: + kind = Node::Kind::DependentGenericConformanceRequirement; + break; + case RequirementKind::Superclass: + // A DependentGenericSuperclasseRequirement kind seems to be missing. + kind = Node::Kind::DependentGenericConformanceRequirement; + break; + case RequirementKind::SameType: + kind = Node::Kind::DependentGenericSameTypeRequirement; + break; + default: + llvm_unreachable("Unhandled requirement kind"); + } + auto r = Dem.createNode(kind); + r->addChild(visit(req.getFirstType()), Dem); + r->addChild(visit(req.getSecondType()), Dem); + return r; + } + case RequirementKind::Layout: + // Not implemented. + return nullptr; + } + } + Demangle::NodePointer visitSILBoxTypeWithLayoutTypeRef(const SILBoxTypeWithLayoutTypeRef *SB) { auto node = Dem.createNode(Node::Kind::SILBoxTypeWithLayout); @@ -888,35 +924,10 @@ class DemanglingForTypeRef ++index; } for (auto &req : SB->getRequirements()) { - switch (req.getKind()) { - case RequirementKind::Conformance: - case RequirementKind::Superclass: - case RequirementKind::SameType: { - Node::Kind kind; - switch (req.getKind()) { - case RequirementKind::Conformance: - kind = Node::Kind::DependentGenericConformanceRequirement; - break; - case RequirementKind::Superclass: - // A DependentGenericSuperclasseRequirement kind seems to be missing. - kind = Node::Kind::DependentGenericConformanceRequirement; - break; - case RequirementKind::SameType: - kind = Node::Kind::DependentGenericSameTypeRequirement; - break; - default: - llvm_unreachable("unreachable"); - } - auto r = Dem.createNode(kind); - r->addChild(visit(req.getFirstType()), Dem); - r->addChild(visit(req.getSecondType()), Dem); - signature->addChild(r, Dem); - break; - } - case RequirementKind::Layout: - // Not implemented. - break; - } + auto *r = visitTypeRefRequirement(req); + if (!r) + continue; + signature->addChild(r, Dem); } node->addChild(signature, Dem); auto list = Dem.createNode(Node::Kind::TypeList); @@ -1102,12 +1113,9 @@ class ThickenMetatype } const TypeRef * - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { - std::vector ThickArgs; - for (auto Param : PPT->getArgs()) - ThickArgs.push_back(visit(Param)); - return ParameterizedProtocolTypeRef::create(Builder, PPT->getBase(), - ThickArgs); + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { + return ConstrainedExistentialTypeRef::create(Builder, CET->getBase(), + CET->getRequirements()); } const TypeRef *visitMetatypeTypeRef(const MetatypeTypeRef *M) { @@ -1257,13 +1265,40 @@ class TypeRefSubstitution return EM; } + llvm::Optional + visitTypeRefRequirement(const TypeRefRequirement &req) { + auto newFirst = visit(req.getFirstType()); + if (!newFirst) + return None; + + switch (req.getKind()) { + case RequirementKind::Conformance: + case RequirementKind::Superclass: + case RequirementKind::SameType: { + auto newSecond = visit(req.getFirstType()); + if (!newSecond) + return None; + return TypeRefRequirement(req.getKind(), newFirst, newSecond); + } + case RequirementKind::Layout: + return TypeRefRequirement(req.getKind(), newFirst, + req.getLayoutConstraint()); + } + + llvm_unreachable("Unhandled RequirementKind in switch."); + } + const TypeRef * - visitParameterizedProtocolTypeRef(const ParameterizedProtocolTypeRef *PPT) { - std::vector substArg; - for (auto Param : PPT->getArgs()) - substArg.push_back(visit(Param)); - return ParameterizedProtocolTypeRef::create(Builder, PPT->getBase(), - substArg); + visitConstrainedExistentialTypeRef(const ConstrainedExistentialTypeRef *CET) { + std::vector constraints; + for (auto Req : CET->getRequirements()) { + auto substReq = visitTypeRefRequirement(Req); + if (!substReq) + continue; + constraints.emplace_back(*substReq); + } + return ConstrainedExistentialTypeRef::create(Builder, CET->getBase(), + constraints); } const TypeRef * diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 66871d9a9dab1..1500423e8cd2e 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -1323,6 +1323,29 @@ class DecodedMetadataBuilder { /// Ownership information related to the metadata we are trying to lookup. TypeReferenceOwnership ReferenceOwnership; +public: + struct BuiltLayoutConstraint { + bool operator==(BuiltLayoutConstraint rhs) const { return true; } + operator bool() const { return true; } + }; + using BuiltLayoutConstraint = BuiltLayoutConstraint; +#if LLVM_PTR_SIZE == 4 + /// Unfortunately the alignment of TypeRef is too large to squeeze in 3 extra + /// bits on (some?) 32-bit systems. + class BigBuiltTypeIntPair { + BuiltType Ptr; + RequirementKind Int; + + public: + BigBuiltTypeIntPair(BuiltType ptr, RequirementKind i) : Ptr(ptr), Int(i) {} + RequirementKind getInt() const { return Int; } + BuiltType getPointer() const { return Ptr; } + uint64_t getOpaqueValue() const { + return (uint64_t)Ptr | ((uint64_t)Int << 32); + } + }; +#endif + public: DecodedMetadataBuilder(Demangler &demangler, SubstGenericParameterFn substGenericParameter, @@ -1338,6 +1361,23 @@ class DecodedMetadataBuilder { using BuiltSubstitution = std::pair; using BuiltSubstitutionMap = llvm::ArrayRef; using BuiltGenericTypeParam = const Metadata *; + struct Requirement : public RequirementBase, + +#endif + BuiltLayoutConstraint> { + Requirement(RequirementKind kind, BuiltType first, BuiltType second) + : RequirementBase(kind, first, second) {} + Requirement(RequirementKind kind, BuiltType first, + BuiltLayoutConstraint second) + : RequirementBase(kind, first, second) {} + }; + using BuiltRequirement = Requirement; BuiltType decodeMangledType(NodePointer node, bool forRequirement = true) { @@ -1533,8 +1573,8 @@ class DecodedMetadataBuilder { } TypeLookupErrorOr - createParameterizedProtocolType(BuiltType base, - llvm::ArrayRef args) const { + createConstrainedExistentialType(BuiltType base, + llvm::ArrayRef rs) const { // FIXME: Runtime plumbing. return BuiltType(); } @@ -1661,11 +1701,6 @@ class DecodedMetadataBuilder { } using BuiltSILBoxField = llvm::PointerIntPair; - struct BuiltLayoutConstraint { - bool operator==(BuiltLayoutConstraint rhs) const { return true; } - operator bool() const { return true; } - }; - using BuiltLayoutConstraint = BuiltLayoutConstraint; BuiltLayoutConstraint getLayoutConstraint(LayoutConstraintKind kind) { return {}; } @@ -1675,38 +1710,6 @@ class DecodedMetadataBuilder { return {}; } -#if LLVM_PTR_SIZE == 4 - /// Unfortunately the alignment of TypeRef is too large to squeeze in 3 extra - /// bits on (some?) 32-bit systems. - class BigBuiltTypeIntPair { - BuiltType Ptr; - RequirementKind Int; - public: - BigBuiltTypeIntPair(BuiltType ptr, RequirementKind i) : Ptr(ptr), Int(i) {} - RequirementKind getInt() const { return Int; } - BuiltType getPointer() const { return Ptr; } - uint64_t getOpaqueValue() const { - return (uint64_t)Ptr | ((uint64_t)Int << 32); - } - }; -#endif - - struct Requirement : public RequirementBase, - -#endif - BuiltLayoutConstraint> { - Requirement(RequirementKind kind, BuiltType first, BuiltType second) - : RequirementBase(kind, first, second) {} - Requirement(RequirementKind kind, BuiltType first, - BuiltLayoutConstraint second) - : RequirementBase(kind, first, second) {} - }; - using BuiltRequirement = Requirement; - TypeLookupErrorOr createSILBoxTypeWithLayout( llvm::ArrayRef Fields, llvm::ArrayRef Substitutions, diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index ec58479364818..89cc59b5343d4 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -428,9 +428,8 @@ $s1A3bar1aySSYt_tF ---> A.bar(a: _const Swift.String) -> () $s1t1fyyFSiAA3StrVcs7KeyPathCyADSiGcfu_SiADcfu0_33_556644b740b1b333fecb81e55a7cce98ADSiTf3npk_n ---> function signature specialization ]> of implicit closure #2 (t.Str) -> Swift.Int in implicit closure #1 (Swift.KeyPath) -> (t.Str) -> Swift.Int in t.f() -> () $s21back_deploy_attribute0A12DeployedFuncyyFTwb ---> back deployment thunk for back_deploy_attribute.backDeployedFunc() -> () $s21back_deploy_attribute0A12DeployedFuncyyFTwB ---> back deployment fallback for back_deploy_attribute.backDeployedFunc() -> () -$s4test3FooVAAyyAA1P_pyxqd__XPlF ---> test.Foo.test(test.P) -> () -$s4test3FooVAAyyAA1P_pyxXPF ---> test.Foo.test(test.P) -> () +$s4test3fooyyAA1P_px1TRts_XPlF ---> test.foo(any test.P) -> () +$s4test3fooyyAA1P_pSS1TAaCPRts_Si1UAERtsXPF ---> test.foo(any test.P) -> () $s4test3FooVAAyyAA1P_pF ---> test.Foo.test(test.P) -> () -$s4test3FooVAAyyAA1P_pyqd__XPAaDRd__lF ---> test.Foo.test(test.P) -> () $sxxxIxzCXxxxesy -> $sxxxIxzCXxxxesy $Sxxx_x_xxIxzCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC$x -> $Sxxx_x_xxIxzCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC$x diff --git a/test/IRGen/existential_shape_metadata.swift b/test/IRGen/existential_shape_metadata.swift index 694bc8d679761..3f2935814c53d 100644 --- a/test/IRGen/existential_shape_metadata.swift +++ b/test/IRGen/existential_shape_metadata.swift @@ -1,16 +1,16 @@ // RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -disable-availability-checking | %IRGenFileCheck %s -// CHECK-LABEL: @"$sl26existential_shape_metadata2Q0_pyxXPXGMq" = linkonce_odr hidden constant +// CHECK-LABEL: @"$sl26existential_shape_metadata2Q0_px1TRts_XPXGMq" = linkonce_odr hidden constant // CHECK-SAME: { i32 {{.*}}sub ([[INT]] ptrtoint (i8** @{{[0-9]+}} to [[INT]]) // CHECK-SAME: i32 6400, -// CHECK-SAME: i32 {{.*}} @"flat unique 26existential_shape_metadata2Q0_pyxXP" +// CHECK-SAME: i32 {{.*}} @"flat unique 26existential_shape_metadata2Q0_px1TAaBPRts_XP" // CHECK-SAME: i16 2, i16 2, i16 3, i16 0, // CHECK-SAME: i16 1, i16 0, i16 1, i16 0, i32 1, -// CHECK-LABEL: @"$sl26existential_shape_metadata2R033_881A0B6978EB4286E7CFF1E27030ACACLL_pyxXPXG" = internal constant +// CHECK-LABEL: @"$sl26existential_shape_metadata2R033_881A0B6978EB4286E7CFF1E27030ACACLL_px1TRts_XPXG" = internal constant // CHECK-SAME: { i32 6400, // This could use a symbolic reference because this doesn't have to be uniqued. -// CHECK-SAME: i32 {{.*}} @"flat unique 26existential_shape_metadata2R033_881A0B6978EB4286E7CFF1E27030ACACLL_pyxXP" +// CHECK-SAME: i32 {{.*}} @"flat unique 26existential_shape_metadata2R033_881A0B6978EB4286E7CFF1E27030ACACLL_px1TAabCLLPRts_XP" // CHECK-SAME: i16 2, i16 2, i16 3, i16 0, // CHECK-SAME: i16 1, i16 0, i16 1, i16 0, i32 1, @@ -37,24 +37,24 @@ private struct C {} // CHECK-LABEL: define{{.*}} @"$s26existential_shape_metadata12testConcrete public func testConcrete() -> Any.Type { - // CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pySiXPMa"([[INT]] 0) + // CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pSi1TAaBPRts_XPMa"([[INT]] 0) // CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK: ret %swift.type* [[METADATA]] return (any Q0).self } -// CHECK-LABEL: define{{.*}} linkonce_odr hidden swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pySiXPMa"( +// CHECK-LABEL: define{{.*}} linkonce_odr hidden swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pSi1TAaBPRts_XPMa"( // CHECK: [[ENTRY:.*]]: // CHECK: [[ARGS:%.*]] = alloca [1 x i8*], align - // CHECK: [[LOAD:%.*]] = load %swift.type*, %swift.type** @"$s26existential_shape_metadata2Q0_pySiXPML", align + // CHECK: [[LOAD:%.*]] = load %swift.type*, %swift.type** @"$s26existential_shape_metadata2Q0_pSi1TAaBPRts_XPML", align // CHECK: [[NULL:%.*]] = icmp eq %swift.type* [[LOAD]], null // CHECK: br i1 [[NULL]], label %[[CACHE_IS_NULL:.*]], label %[[CONT:.*]] // CHECK: [[CACHE_IS_NULL]]: // CHECK: [[T0:%.*]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[ARGS]], i32 0, i32 0 // CHECK: store i8* bitcast (%swift.type* @"$sSiN" to i8*), i8** [[T0]], align // CHECK: [[T0:%.*]] = bitcast [1 x i8*]* [[ARGS]] to i8** - // CHECK: [[CALL:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_pyxXPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) - // CHECK: store atomic %swift.type* [[CALL]], %swift.type** @"$s26existential_shape_metadata2Q0_pySiXPML" release, align + // CHECK: [[CALL:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_px1TRts_XPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) + // CHECK: store atomic %swift.type* [[CALL]], %swift.type** @"$s26existential_shape_metadata2Q0_pSi1TAaBPRts_XPML" release, align // CHECK: br label %[[CONT]] // CHECK: [[CONT]]: // CHECK: [[METADATA:%.*]] = phi %swift.type* [ [[LOAD]], %[[ENTRY]] ], [ [[CALL]], %[[CACHE_IS_NULL]] ] @@ -70,7 +70,7 @@ public func testDependent(t: T.Type) -> Any.Type { // CHECK: [[T1:%.*]] = bitcast %swift.type* %T to i8* // CHECK: store i8* [[T1]], i8** [[T0]], align // CHECK: [[T0:%.*]] = bitcast [1 x i8*]* [[ARGS]] to i8** - // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_pyxXPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) + // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_px1TRts_XPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) // CHECK: ret %swift.type* [[METADATA]] return (any Q0).self } @@ -85,7 +85,7 @@ public func testComplexApplication(t: T.Type) -> Any.Type { // CHECK: [[T1:%.*]] = bitcast %swift.type* [[B_T]] to i8* // CHECK: store i8* [[T1]], i8** [[T0]], align // CHECK: [[T0:%.*]] = bitcast [1 x i8*]* [[ARGS]] to i8** - // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_pyxXPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) + // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_px1TRts_XPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) // CHECK: ret %swift.type* [[METADATA]] return (any Q0>).self } @@ -99,7 +99,7 @@ public func test_private(t: T.Type) -> Any.Type { // CHECK: store i8* [[T1]], i8** [[T0]], align // CHECK: [[T0:%.*]] = bitcast [1 x i8*]* [[ARGS]] to i8** // FIXME: this should be unique? - // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata_unique({{.*}}@"$sl26existential_shape_metadata2R033_881A0B6978EB4286E7CFF1E27030ACACLL_pyxXPXG{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) + // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata_unique({{.*}}@"$sl26existential_shape_metadata2R033_881A0B6978EB4286E7CFF1E27030ACACLL_px1TRts_XPXG{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) // CHECK: ret %swift.type* [[METADATA]] return (any R0).self } @@ -108,7 +108,7 @@ public func test_private(t: T.Type) -> Any.Type { // change anything: the shape is still public. // CHECK-LABEL: define{{.*}} @"$s26existential_shape_metadata23test_privateApplication public func test_privateApplication(t: T.Type) -> Any.Type { - // CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pyAA1C33_881A0B6978EB4286E7CFF1E27030ACACLLVXPMa"([[INT]] 0) + // CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pAA1C33_881A0B6978EB4286E7CFF1E27030ACACLLV1TAaBPRts_XPMa"([[INT]] 0) // CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK: ret %swift.type* [[METADATA]] return (any Q0).self @@ -116,9 +116,9 @@ public func test_privateApplication(t: T.Type) -> Any.Type { // FIXME: this accessor should have internal linkage, but we compute // formal linkage wrong for types -// CHECK-LABEL: define{{.*}} linkonce_odr hidden swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pyAA1C33_881A0B6978EB4286E7CFF1E27030ACACLLVXPMa"( +// CHECK-LABEL: define{{.*}} linkonce_odr hidden swiftcc %swift.metadata_response @"$s26existential_shape_metadata2Q0_pAA1C33_881A0B6978EB4286E7CFF1E27030ACACLLV1TAaBPRts_XPMa"( // CHECK: [[ARGS:%.*]] = alloca [1 x i8*], align // CHECK: [[T0:%.*]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[ARGS]], i32 0, i32 0 // CHECK: store i8* {{.*}}"$s26existential_shape_metadata1C33_881A0B6978EB4286E7CFF1E27030ACACLLVMf"{{.*}}, i8** [[T0]], align // CHECK: [[T0:%.*]] = bitcast [1 x i8*]* [[ARGS]] to i8** - // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_pyxXPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) + // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getExtendedExistentialTypeMetadata({{.*}}@"$sl26existential_shape_metadata2Q0_px1TRts_XPXGMq{{(\.ptrauth)?}}" to i8*), i8** [[T0]]) diff --git a/test/SILGen/parameterized_existentials.swift b/test/SILGen/parameterized_existentials.swift index 4f40475c49646..252ced960083b 100644 --- a/test/SILGen/parameterized_existentials.swift +++ b/test/SILGen/parameterized_existentials.swift @@ -24,7 +24,7 @@ struct S: Q { struct R { var force: () -> any P - // CHECK-LABEL: sil hidden [ossa] @$s13parameterized1RV5forceACyxq_q0_GAA1P_pyxq_q0_XPyc_tcfC : $@convention(method) (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> () -> @out P<τ_0_0, τ_0_1, τ_0_2> for , @thin R.Type) -> @owned R { + // CHECK-LABEL: sil hidden [ossa] @$s13parameterized1RV5forceACyxq_q0_GAA1P_px1TRts_q_1URtsq0_1VRtsXPyc_tcfC : $@convention(method) (@owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> () -> @out P<τ_0_0, τ_0_1, τ_0_2> for , @thin R.Type) -> @owned R { } // CHECK-LABEL: sil hidden [ossa] @$s13parameterized6upcastyAA1P_pAA1SVF : $@convention(thin) (S) -> @out P { @@ -75,26 +75,26 @@ func reuse(_ k: () -> any P) {} func upcastResult() { // CHECK: [[RES_FN:%.*]] = function_ref @$s13parameterized12upcastResultyyFAA1SVyXEfU_ : $@convention(thin) () -> S // CHECK: [[THICK_RES_FN:%.*]] = thin_to_thick_function [[RES_FN]] : $@convention(thin) () -> S to $@noescape @callee_guaranteed () -> S - // CHECK: [[S_TO_P_RES_THUNK_FN:%.*]] = function_ref @$s13parameterized1SVIgd_AA1P_pySiSSSfXPIegr_TR : $@convention(thin) (@noescape @callee_guaranteed () -> S) -> @out P + // CHECK: [[S_TO_P_RES_THUNK_FN:%.*]] = function_ref @$s13parameterized1SVIgd_AA1P_pSi1TAaDPRts_SS1UAFRtsSf1VAFRtsXPIegr_TR : $@convention(thin) (@noescape @callee_guaranteed () -> S) -> @out P // CHECK: [[PARTIAL_RES_THUNK_FN:%.*]] = partial_apply [callee_guaranteed] [[S_TO_P_RES_THUNK_FN]]([[THICK_RES_FN]]) : $@convention(thin) (@noescape @callee_guaranteed () -> S) -> @out P // CHECK: [[NOESCAPE_RES_THUNK_FN:%.*]] = convert_escape_to_noescape [not_guaranteed] [[PARTIAL_RES_THUNK_FN]] : $@callee_guaranteed () -> @out P to $@noescape @callee_guaranteed () -> @out P - // CHECK: [[REUSE_FN:%.*]] = function_ref @$s13parameterized5reuseyyAA1P_pySiSSSfXPyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> @out P) -> () + // CHECK: [[REUSE_FN:%.*]] = function_ref @$s13parameterized5reuseyyAA1P_pSi1TAaCPRts_SS1UAERtsSf1VAERtsXPyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> @out P) -> () // CHECK: {{%.*}} = apply [[REUSE_FN]]([[NOESCAPE_RES_THUNK_FN]]) : $@convention(thin) (@noescape @callee_guaranteed () -> @out P) -> () reuse({ () -> S in S() }) - // CHECK: [[RES_Q_FN:%.*]] = function_ref @$s13parameterized12upcastResultyyFAA1Q_pySiSSSfXPyXEfU0_ : $@convention(thin) () -> @out Q + // CHECK: [[RES_Q_FN:%.*]] = function_ref @$s13parameterized12upcastResultyyFAA1Q_pSi1XAaCPRts_SS1YAERtsSf1ZAERtsXPyXEfU0_ : $@convention(thin) () -> @out Q // CHECK: [[THICK_NOESCAPE_RES_Q_FN:%.*]] = thin_to_thick_function [[RES_Q_FN]] : $@convention(thin) () -> @out Q to $@noescape @callee_guaranteed () -> @out Q - // CHECK: [[P_TO_Q_RES_THUNK_FN:%.*]] = function_ref @$s13parameterized1Q_pySiSSSfXPIgr_AA1P_pySiSSSfXPIegr_TR : $@convention(thin) (@noescape @callee_guaranteed () -> @out Q) -> @out P + // CHECK: [[P_TO_Q_RES_THUNK_FN:%.*]] = function_ref @$s13parameterized1Q_pSi1XAaBPRts_SS1YADRtsSf1ZADRtsXPIgr_AA1P_pSi1TAaJPRts_SS1UALRtsSf1VALRtsXPIegr_TR : $@convention(thin) (@noescape @callee_guaranteed () -> @out Q) -> @out P // CHECK: [[PARTIAL_P_TO_Q_RES_THUNK_FN:%.*]] = partial_apply [callee_guaranteed] [[P_TO_Q_RES_THUNK_FN]]([[THICK_NOESCAPE_RES_Q_FN]]) : $@convention(thin) (@noescape @callee_guaranteed () -> @out Q) -> @out P // CHECK: [[NOESCAPE_PARTIAL_P_TO_Q_RES_THUNK_FN:%.*]] = convert_escape_to_noescape [not_guaranteed] [[PARTIAL_P_TO_Q_RES_THUNK_FN]] : $@callee_guaranteed () -> @out P to $@noescape @callee_guaranteed () -> @out P - // CHECK: [[REUSE_FN:%.*]] = function_ref @$s13parameterized5reuseyyAA1P_pySiSSSfXPyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> @out P) -> () + // CHECK: [[REUSE_FN:%.*]] = function_ref @$s13parameterized5reuseyyAA1P_pSi1TAaCPRts_SS1UAERtsSf1VAERtsXPyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> @out P) -> () // CHECK: {{%.*}} = apply [[REUSE_FN]]([[NOESCAPE_PARTIAL_P_TO_Q_RES_THUNK_FN]]) : $@convention(thin) (@noescape @callee_guaranteed () -> @out P) -> () reuse({ () -> any Q in S() }) } -// CHECK-LABEL: sil hidden [ossa] @$s13parameterized5forceAA1P_pyxq_q0_XPyr1_lF : $@convention(thin) () -> @out P { +// CHECK-LABEL: sil hidden [ossa] @$s13parameterized5forceAA1P_px1TRts_q_1URtsq0_1VRtsXPyr1_lF : $@convention(thin) () -> @out P { func force() -> any P { return R(force: { force() }).force() } diff --git a/test/SILOptimizer/cast_folding_parameterized_protocol.swift b/test/SILOptimizer/cast_folding_parameterized_protocol.swift index aab2fa9b18497..48637841ceef5 100644 --- a/test/SILOptimizer/cast_folding_parameterized_protocol.swift +++ b/test/SILOptimizer/cast_folding_parameterized_protocol.swift @@ -49,7 +49,7 @@ public func concrete_to_existential(_ x: X, _ yt: Y, _ yi: Y) { use(yi as! any Q) } -// CHECK-LABEL: sil @$s35cast_folding_parameterized_protocol23existential_to_concreteyyxm_AA1P_pyxXPtlF : $@convention(thin) (@thick T.Type, @in_guaranteed P) -> () +// CHECK-LABEL: sil @$s35cast_folding_parameterized_protocol23existential_to_concreteyyxm_AA1P_px1TRts_XPtlF : $@convention(thin) (@thick T.Type, @in_guaranteed P) -> () public func existential_to_concrete(_: T.Type, _ p: any P) { // CHECK: unconditional_checked_cast_addr P in {{%.*}} : $*P to X in {{%.*}} : $*X _ = p as! X @@ -61,7 +61,7 @@ public func existential_to_concrete(_: T.Type, _ p: any P) { _ = p as! Y } -// CHECK-LABEL: sil @$s35cast_folding_parameterized_protocol015existential_to_E0yyAA1P_pyxXP_AA1Q_ptlF : $@convention(thin) (@in_guaranteed P, @in_guaranteed Q) -> () +// CHECK-LABEL: sil @$s35cast_folding_parameterized_protocol015existential_to_E0yyAA1P_px1TRts_XP_AA1Q_ptlF : $@convention(thin) (@in_guaranteed P, @in_guaranteed Q) -> () public func existential_to_existential(_ p: any P, _ q: any Q) { // CHECK: unconditional_checked_cast_addr P in {{%.*}} : $*P to Q in {{%.*}} : $*Q _ = p as! any Q diff --git a/unittests/runtime/SpecifierDSL.h b/unittests/runtime/SpecifierDSL.h index 5ed328c3b3c13..f87c40891257d 100644 --- a/unittests/runtime/SpecifierDSL.h +++ b/unittests/runtime/SpecifierDSL.h @@ -58,18 +58,17 @@ struct MemberTypeSpecifier { struct ProtocolTypeSpecifier { ProtocolSpecifier protocol; }; -struct ParameterizedProtocolTypeSpecifier { +struct ConstrainedExistentialTypeSpecifier { ProtocolSpecifier base; std::vector> args; }; struct ProtocolCompositionTypeSpecifier { std::vector components; }; -struct TypeSpecifier : TaggedUnion { +struct TypeSpecifier + : TaggedUnion { using TaggedUnion::TaggedUnion; }; @@ -137,8 +136,7 @@ inline TypeSpecifier parameterizedProtocol(ProtocolSpecifier &&base, Specs &&...specs) { std::vector> args; addParameterizedProtocolArguments(args, std::forward(specs)...); - return ParameterizedProtocolTypeSpecifier{std::move(base), - std::move(args)}; + return ConstrainedExistentialTypeSpecifier{std::move(base), std::move(args)}; } /// A class which "demangles" various DSL specifiers into demangle @@ -212,8 +210,8 @@ class Demangler { {node(Kind::TypeList, components)}); } - NodePointer demangleParameterizedProtocolType( - const ParameterizedProtocolTypeSpecifier &spec) { + NodePointer demangleConstrainedExistentialType( + const ConstrainedExistentialTypeSpecifier &spec) { // Demangle the base protocol and then wrap it up like the tree expects, // which for some reason is this. auto base = demangleProtocol(spec.base); @@ -222,14 +220,29 @@ class Demangler { {node(Kind::Type, {base})})}); - std::vector argVector; + std::vector reqVector; + bool firstReq = false; for (auto &arg: spec.args) { - // TODO: also include the associated type names - argVector.push_back(demangleType(arg.second)); + auto depType = + node(Kind::Type, + {node(Kind::DependentMemberType, + {node(Kind::Type, + {factory.createNode(Kind::ConstrainedExistentialSelf), + node(Kind::DependentAssociatedTypeRef, + {factory.createNode(Kind::Identifier, arg.first), + node(Kind::Type, + {demangleProtocol(spec.base)})})})})}); + auto constraintType = demangleType(arg.second); + reqVector.push_back(node(Kind::DependentGenericSameTypeRequirement, + {depType, constraintType})); + if (firstReq) { + reqVector.push_back(node(Kind::FirstElementMarker, {})); + firstReq = false; + } } - auto args = node(Kind::TypeList, argVector); - return node(Kind::ParameterizedProtocol, - {base, args}); + NodePointer constraints = + node(Node::Kind::ConstrainedExistentialRequirementList, reqVector); + return node(Kind::ConstrainedExistential, {base, constraints}); } NodePointer demangleTypeImpl(const TypeSpecifier &spec) { @@ -240,7 +253,7 @@ class Demangler { CASE(MemberType) CASE(ProtocolType) CASE(ProtocolCompositionType) - CASE(ParameterizedProtocolType) + CASE(ConstrainedExistentialType) #undef CASE swift_unreachable("unknown type specifier"); }