diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index a692b9e7b8863..ef5acf6422653 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -966,6 +966,7 @@ Property behaviors are implemented using private protocol conformances. any-protocol-conformance ::= concrete-protocol-conformance any-protocol-conformance ::= dependent-protocol-conformance + any-protocol-conformance ::= pack-protocol-conformance any-protocol-conformance-list ::= any-protocol-conformance '_' any-protocol-conformance-list any-protocol-conformance-list ::= empty-list @@ -980,6 +981,8 @@ Property behaviors are implemented using private protocol conformances. dependent-associated-conformance ::= type protocol dependent-protocol-conformance ::= dependent-protocol-conformance opaque-type 'HO' + pack-protocol-conformance ::= any-protocol-conformance-list 'HX' + A compact representation used to represent mangled protocol conformance witness arguments at runtime. The ``module`` is only specified for conformances that are "retroactive", meaning that the context in which the conformance is defined diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 9bb1df4feb6f1..ee1d3059b2914 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -703,6 +703,9 @@ class ASTMangler : public Mangler { void appendConcreteProtocolConformance( const ProtocolConformance *conformance, GenericSignature sig); + void appendPackProtocolConformance( + const PackConformance *conformance, + GenericSignature sig); void appendDependentProtocolConformance(const ConformancePath &path, GenericSignature sig); void appendOpParamForLayoutConstraint(LayoutConstraint Layout); diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 1f726f6f1e22c..afdd3bdb76318 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -51,6 +51,7 @@ NODE(ClangType) CONTEXT_NODE(Class) NODE(ClassMetadataBaseOffset) NODE(ConcreteProtocolConformance) +NODE(PackProtocolConformance) NODE(ConformanceAttachedMacroExpansion) CONTEXT_NODE(Constructor) NODE(CoroutineContinuationPrototype) diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h index 5ab3e4c983a60..67aee24cd2d90 100644 --- a/include/swift/Demangling/Demangler.h +++ b/include/swift/Demangling/Demangler.h @@ -587,6 +587,7 @@ class Demangler : public NodeFactory { NodePointer demangleRetroactiveProtocolConformanceRef(); NodePointer popAnyProtocolConformance(); NodePointer demangleConcreteProtocolConformance(); + NodePointer demanglePackProtocolConformance(); NodePointer popDependentProtocolConformance(); NodePointer demangleDependentProtocolConformanceRoot(); NodePointer demangleDependentProtocolConformanceInherited(); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 4df445740977c..5ec7ae62540c3 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -28,6 +28,7 @@ #include "swift/AST/MacroDiscriminatorContext.h" #include "swift/AST/Module.h" #include "swift/AST/Ownership.h" +#include "swift/AST/PackConformance.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" @@ -1874,8 +1875,22 @@ static bool isRetroactiveConformance(const RootProtocolConformance *root) { /// Determine whether the given protocol conformance contains a retroactive /// protocol conformance anywhere in it. static bool containsRetroactiveConformance( - const ProtocolConformance *conformance, + ProtocolConformanceRef conformanceRef, ModuleDecl *module) { + if (!conformanceRef.isPack() && !conformanceRef.isConcrete()) + return false; + + if (conformanceRef.isPack()) { + for (auto patternConf : conformanceRef.getPack()->getPatternConformances()) { + if (containsRetroactiveConformance(patternConf, module)) + return true; + } + + return false; + } + + auto *conformance = conformanceRef.getConcrete(); + // If the root conformance is retroactive, it's retroactive. const RootProtocolConformance *rootConformance = conformance->getRootConformance(); @@ -1897,8 +1912,7 @@ static bool containsRetroactiveConformance( // for indexing purposes. continue; } - if (conformance.isConcrete() && - containsRetroactiveConformance(conformance.getConcrete(), module)) { + if (containsRetroactiveConformance(conformance, module)) { return true; } } @@ -1924,14 +1938,18 @@ void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap, }; // Ignore abstract conformances. - if (!conformance.isConcrete()) + if (!conformance.isConcrete() && !conformance.isPack()) continue; // Skip non-retroactive conformances. - if (!containsRetroactiveConformance(conformance.getConcrete(), fromModule)) + if (!containsRetroactiveConformance(conformance, fromModule)) continue; - appendConcreteProtocolConformance(conformance.getConcrete(), sig); + if (conformance.isConcrete()) + appendConcreteProtocolConformance(conformance.getConcrete(), sig); + else + appendPackProtocolConformance(conformance.getPack(), sig); + appendOperator("g", Index(numProtocolRequirements)); } } @@ -4143,8 +4161,14 @@ void ASTMangler::appendAnyProtocolConformance( appendDependentProtocolConformance(conformancePath, opaqueSignature); appendType(conformingType, genericSig); appendOperator("HO"); - } else { + } else if (conformance.isConcrete()) { appendConcreteProtocolConformance(conformance.getConcrete(), genericSig); + } else if (conformance.isPack()) { + appendPackProtocolConformance(conformance.getPack(), genericSig); + } else { + llvm::errs() << "Bad conformance in mangler: "; + conformance.dump(llvm::errs()); + abort(); } } @@ -4199,6 +4223,32 @@ void ASTMangler::appendConcreteProtocolConformance( appendOperator("HC"); } +void ASTMangler::appendPackProtocolConformance( + const PackConformance *conformance, + GenericSignature sig) { + auto conformingType = conformance->getType(); + auto patternConformances = conformance->getPatternConformances(); + assert(conformingType->getNumElements() == patternConformances.size()); + + if (conformingType->getNumElements() == 0) { + appendOperator("y"); + } else { + bool firstField = true; + for (unsigned i = 0, e = conformingType->getNumElements(); i < e; ++i) { + auto type = conformingType->getElementType(i); + auto conf = patternConformances[i]; + + if (auto *expansionTy = type->getAs()) + type = expansionTy->getPatternType(); + + appendAnyProtocolConformance(sig, type->getCanonicalType(), conf); + appendListSeparator(firstField); + } + } + + appendOperator("HX"); +} + void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) { assert(layout); switch (layout->getKind()) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 8a7d3e4284040..efa2ba074059e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -5364,10 +5364,10 @@ CanType swift::substOpaqueTypesWithUnderlyingTypes(CanType ty, ReplaceOpaqueTypesWithUnderlyingTypes replacer( context.getContext(), context.getResilienceExpansion(), context.isWholeModuleContext()); - SubstOptions flags = SubstFlags::SubstituteOpaqueArchetypes; + SubstOptions flags = (SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); if (allowLoweredTypes) - flags = - SubstFlags::SubstituteOpaqueArchetypes | SubstFlags::AllowLoweredTypes; + flags |= SubstFlags::AllowLoweredTypes; return ty.subst(replacer, replacer, flags)->getCanonicalType(); } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 9d8b0f8a34055..662c971f3579a 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -996,6 +996,7 @@ NodePointer Demangler::demangleOperator() { case 'p': return createWithChild( Node::Kind::ProtocolConformanceRefInProtocolModule, popProtocol()); + case 'X': return demanglePackProtocolConformance(); // Runtime records (type/protocol/conformance/function) case 'c': @@ -1847,6 +1848,7 @@ NodePointer Demangler::popAnyProtocolConformance() { return popNode([](Node::Kind kind) { switch (kind) { case Node::Kind::ConcreteProtocolConformance: + case Node::Kind::PackProtocolConformance: case Node::Kind::DependentProtocolConformanceRoot: case Node::Kind::DependentProtocolConformanceInherited: case Node::Kind::DependentProtocolConformanceAssociated: @@ -1884,6 +1886,13 @@ NodePointer Demangler::demangleConcreteProtocolConformance() { type, conformanceRef, conditionalConformanceList); } +NodePointer Demangler::demanglePackProtocolConformance() { + NodePointer patternConformanceList = popAnyProtocolConformanceList(); + + return createWithChild(Node::Kind::PackProtocolConformance, + patternConformanceList); +} + NodePointer Demangler::popDependentProtocolConformance() { return popNode([](Node::Kind kind) { switch (kind) { diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 9c2687b13edd7..39c4d40353068 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -596,6 +596,7 @@ class NodePrinter { case Node::Kind::AnonymousContext: case Node::Kind::AnyProtocolConformanceList: case Node::Kind::ConcreteProtocolConformance: + case Node::Kind::PackProtocolConformance: case Node::Kind::DependentAssociatedConformance: case Node::Kind::DependentProtocolConformanceAssociated: case Node::Kind::DependentProtocolConformanceInherited: @@ -3106,12 +3107,31 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, printChildren(Node, depth); return nullptr; case Node::Kind::AnyProtocolConformanceList: - printChildren(Node, depth); + if (Node->getNumChildren() > 0) { + Printer << "("; + for (unsigned i = 0; i < Node->getNumChildren(); ++i) { + if (i > 0) + Printer << ", "; + print(Node->getChild(i), depth + 1); + } + Printer << ")"; + } return nullptr; case Node::Kind::ConcreteProtocolConformance: Printer << "concrete protocol conformance "; if (Node->hasIndex()) Printer << "#" << Node->getIndex() << " "; + print(Node->getChild(0), depth + 1); + Printer << " to "; + print(Node->getChild(1), depth + 1); + if (Node->getNumChildren() > 2 && + Node->getChild(2)->getNumChildren() > 0) { + Printer << " with conditional requirements: "; + print(Node->getChild(2), depth + 1); + } + return nullptr; + case Node::Kind::PackProtocolConformance: + Printer << "pack protocol conformance "; printChildren(Node, depth); return nullptr; case Node::Kind::DependentAssociatedConformance: @@ -3122,18 +3142,21 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, Printer << "dependent associated protocol conformance "; printOptionalIndex(Node->getChild(2)); print(Node->getChild(0), depth + 1); + Printer << " to "; print(Node->getChild(1), depth + 1); return nullptr; case Node::Kind::DependentProtocolConformanceInherited: Printer << "dependent inherited protocol conformance "; printOptionalIndex(Node->getChild(2)); print(Node->getChild(0), depth + 1); + Printer << " to "; print(Node->getChild(1), depth + 1); return nullptr; case Node::Kind::DependentProtocolConformanceRoot: Printer << "dependent root protocol conformance "; printOptionalIndex(Node->getChild(2)); print(Node->getChild(0), depth + 1); + Printer << " to "; print(Node->getChild(1), depth + 1); return nullptr; case Node::Kind::ProtocolConformanceRefInTypeModule: diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index f0a028a39a7de..52fc469254c34 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -517,6 +517,12 @@ ManglingError Remangler::mangleConcreteProtocolConformance(Node *node, return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); } +ManglingError Remangler::manglePackProtocolConformance(Node *node, + unsigned depth) { + // Pack conformances aren't in the old mangling + return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); +} + ManglingError Remangler::mangleAnyProtocolConformanceList(Node *node, unsigned depth) { // Conformance lists aren't in the old mangling diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 7879bb7c6705d..6fee8cdc04db5 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2614,6 +2614,14 @@ ManglingError Remangler::mangleConcreteProtocolConformance(Node *node, return ManglingError::Success; } +ManglingError Remangler::manglePackProtocolConformance(Node *node, + unsigned depth) { + RETURN_IF_ERROR( + mangleAnyProtocolConformanceList(node->getChild(0), depth + 1)); + Buffer << "HX"; + return ManglingError::Success; +} + ManglingError Remangler::mangleDependentProtocolConformanceRoot(Node *node, unsigned depth) { RETURN_IF_ERROR(mangleType(node->getChild(0), depth + 1)); @@ -2663,6 +2671,8 @@ ManglingError Remangler::mangleAnyProtocolConformance(Node *node, switch (node->getKind()) { case Node::Kind::ConcreteProtocolConformance: return mangleConcreteProtocolConformance(node, depth + 1); + case Node::Kind::PackProtocolConformance: + return manglePackProtocolConformance(node, depth + 1); case Node::Kind::DependentProtocolConformanceRoot: return mangleDependentProtocolConformanceRoot(node, depth + 1); case Node::Kind::DependentProtocolConformanceInherited: diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 868cf921ab19c..6f213b51c1950 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -472,3 +472,4 @@ $sSRyxG15Synchronization19AtomicRepresentableABRi_zrlMc ---> protocol conformanc $sSRyxG15Synchronization19AtomicRepresentableABRi0_zrlMc ---> protocol conformance descriptor for < where A: ~Swift.Escapable> Swift.UnsafeBufferPointer : Synchronization.AtomicRepresentable in Synchronization $sSRyxG15Synchronization19AtomicRepresentableABRi1_zrlMc ---> protocol conformance descriptor for < where A: ~Swift.> Swift.UnsafeBufferPointer : Synchronization.AtomicRepresentable in Synchronization +$s23variadic_generic_opaque2G2VyAA2S1V_AA2S2VQPGAA1PHPAeA1QHPyHC_AgaJHPyHCHX_HC ---> concrete protocol conformance variadic_generic_opaque.G2 to protocol conformance ref (type's module) variadic_generic_opaque.P with conditional requirements: (pack protocol conformance (concrete protocol conformance variadic_generic_opaque.S1 to protocol conformance ref (type's module) variadic_generic_opaque.Q, concrete protocol conformance variadic_generic_opaque.S2 to protocol conformance ref (type's module) variadic_generic_opaque.Q)) diff --git a/test/IRGen/variadic_generic_opaque.swift b/test/IRGen/variadic_generic_opaque.swift index 218afccda5b66..e679867248c32 100644 --- a/test/IRGen/variadic_generic_opaque.swift +++ b/test/IRGen/variadic_generic_opaque.swift @@ -1,11 +1,42 @@ -// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking - -// FIXME: Add more tests +// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking | %FileCheck %s public protocol P {} public struct G: P {} -public func returnsG(_ t: repeat each T) -> some P { +public func concreteG(_ t: repeat each T) -> some P { + return G() +} + +public func abstractG(_ t: T) -> some P { + return G() +} + +public func variadicG(_ t: repeat each T) -> some P { return G() } + +// Opaque return type is witnessed by a conditional conformance +protocol Q {} + +struct S1: Q {} +struct S2: Q {} + +struct G2 {} +extension G2: P where repeat each T: Q {} + +func concreteG2() -> some P { + G2() +} + +func abstractG2(_: T) -> some P { + G2() +} + +func variadicG2(_: repeat each T) -> some P { + G2() +} + +// CHECK: define private ptr @"get_witness_table 23variadic_generic_opaque2G2VyAA2S1V_AA2S2VQPGAA1PHPAeA1QHPyHC_AgaJHPyHCHX_HC" +// CHECK: define private ptr @"get_witness_table 23variadic_generic_opaque1QRzlAA2G2VyAA2S1V_xQPGAA1PHPAfaBHPyHC_xAaBHD1_HX_HC" +// CHECK: define private ptr @"get_witness_table Rvz23variadic_generic_opaque1QRzlAA2G2VyxxQp_QPGAA1PHPxAaBHD1__HX_HC" \ No newline at end of file diff --git a/test/SILGen/Inputs/variadic_generic_opaque_multifile_other.swift b/test/SILGen/Inputs/variadic_generic_opaque_multifile_other.swift new file mode 100644 index 0000000000000..433554b9e47b2 --- /dev/null +++ b/test/SILGen/Inputs/variadic_generic_opaque_multifile_other.swift @@ -0,0 +1,11 @@ +public protocol P { + func f() +} + +public struct G: P { + public func f() {} +} + +public func callee(_: repeat each T) -> some P { + G() +} diff --git a/test/SILGen/variadic_generic_opaque_multifile.swift b/test/SILGen/variadic_generic_opaque_multifile.swift new file mode 100644 index 0000000000000..434cd7fba4e2d --- /dev/null +++ b/test/SILGen/variadic_generic_opaque_multifile.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-frontend -emit-silgen -primary-file %s %S/Inputs/variadic_generic_opaque_multifile_other.swift -disable-availability-checking +// RUN: %target-swift-frontend -emit-silgen %s %S/Inputs/variadic_generic_opaque_multifile_other.swift -disable-availability-checking + +public func caller() { + callee(1, 2, 3).f() +}