diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 3d68b3e4601ea..630cfe4e890a1 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..0e3ea7ca6862e 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -443,8 +443,7 @@ class ASTMangler : public Mangler { /// Append any retroactive conformances. void appendRetroactiveConformances(Type type, GenericSignature sig); void appendRetroactiveConformances(SubstitutionMap subMap, - GenericSignature sig, - ModuleDecl *fromModule); + GenericSignature sig); void appendImplFunctionType(SILFunctionType *fn, GenericSignature sig, const ValueDecl *forDecl = nullptr); void appendOpaqueTypeArchetype(ArchetypeType *archetype, @@ -703,6 +702,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/APIDigester/ModuleAnalyzerNodes.cpp b/lib/APIDigester/ModuleAnalyzerNodes.cpp index bb7fb0fce582e..029d5e8fa3576 100644 --- a/lib/APIDigester/ModuleAnalyzerNodes.cpp +++ b/lib/APIDigester/ModuleAnalyzerNodes.cpp @@ -1633,7 +1633,9 @@ SwiftDeclCollector::constructTypeNode(Type T, TypeInitInfo Info) { ReplaceOpaqueTypesWithUnderlyingTypes replacer( /*inContext=*/nullptr, ResilienceExpansion::Maximal, /*isWholeModuleContext=*/false); - T = T.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes) + T = T.subst(replacer, replacer, + SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel) ->getCanonicalType(); } } diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 4df445740977c..c75557168fc1b 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" @@ -1871,20 +1872,11 @@ static bool isRetroactiveConformance(const RootProtocolConformance *root) { return conformance->isRetroactive(); } -/// Determine whether the given protocol conformance contains a retroactive -/// protocol conformance anywhere in it. -static bool containsRetroactiveConformance( - const ProtocolConformance *conformance, - ModuleDecl *module) { - // If the root conformance is retroactive, it's retroactive. - const RootProtocolConformance *rootConformance = - conformance->getRootConformance(); - if (isRetroactiveConformance(rootConformance) && - conformanceHasIdentity(rootConformance)) - return true; +template +static bool forEachConditionalConformance(const ProtocolConformance *conformance, + Fn fn) { + auto *rootConformance = conformance->getRootConformance(); - // If the conformance is conditional and any of the substitutions used to - // satisfy the conditions are retroactive, it's retroactive. auto subMap = conformance->getSubstitutionMap(); for (auto requirement : rootConformance->getConditionalRequirements()) { if (requirement.getKind() != RequirementKind::Conformance) @@ -1897,18 +1889,49 @@ static bool containsRetroactiveConformance( // for indexing purposes. continue; } - if (conformance.isConcrete() && - containsRetroactiveConformance(conformance.getConcrete(), module)) { + + if (fn(requirement.getFirstType().subst(subMap), conformance)) return true; - } } return false; } +/// Determine whether the given protocol conformance contains a retroactive +/// protocol conformance anywhere in it. +static bool containsRetroactiveConformance( + ProtocolConformanceRef conformanceRef) { + if (!conformanceRef.isPack() && !conformanceRef.isConcrete()) + return false; + + if (conformanceRef.isPack()) { + for (auto patternConf : conformanceRef.getPack()->getPatternConformances()) { + if (containsRetroactiveConformance(patternConf)) + return true; + } + + return false; + } + + auto *conformance = conformanceRef.getConcrete(); + + // If the root conformance is retroactive, it's retroactive. + const RootProtocolConformance *rootConformance = + conformance->getRootConformance(); + if (isRetroactiveConformance(rootConformance) && + conformanceHasIdentity(rootConformance)) + return true; + + // If the conformance is conditional and any of the substitutions used to + // satisfy the conditions are retroactive, it's retroactive. + return forEachConditionalConformance(conformance, + [&](Type substType, ProtocolConformanceRef substConf) -> bool { + return containsRetroactiveConformance(substConf); + }); +} + void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap, - GenericSignature sig, - ModuleDecl *fromModule) { + GenericSignature sig) { if (subMap.empty()) return; unsigned numProtocolRequirements = 0; @@ -1924,14 +1947,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)) continue; - appendConcreteProtocolConformance(conformance.getConcrete(), sig); + if (conformance.isConcrete()) + appendConcreteProtocolConformance(conformance.getConcrete(), sig); + else + appendPackProtocolConformance(conformance.getPack(), sig); + appendOperator("g", Index(numProtocolRequirements)); } } @@ -1954,7 +1981,7 @@ void ASTMangler::appendRetroactiveConformances(Type type, GenericSignature sig) subMap = type->getContextSubstitutionMap(module, nominal); } - appendRetroactiveConformances(subMap, sig, module); + appendRetroactiveConformances(subMap, sig); } void ASTMangler::appendSymbolicExtendedExistentialType( @@ -1977,11 +2004,7 @@ void ASTMangler::appendSymbolicExtendedExistentialType( for (auto argType : genInfo.Generalization.getReplacementTypes()) appendType(argType, sig, forDecl); - // What module should be used here? The existential isn't anchored - // to any given module; we should just treat conformances as - // retroactive if they're "objectively" retroactive. - appendRetroactiveConformances(genInfo.Generalization, sig, - /*from module*/ nullptr); + appendRetroactiveConformances(genInfo.Generalization, sig); } appendOperator("Xj"); @@ -2172,7 +2195,7 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn, } if (auto subs = fn->getInvocationSubstitutions()) { appendFlatGenericArgs(subs, sig, forDecl); - appendRetroactiveConformances(subs, sig, Mod); + appendRetroactiveConformances(subs, sig); } if (auto subs = fn->getPatternSubstitutions()) { appendGenericSignature(subs.getGenericSignature()); @@ -2181,7 +2204,7 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn, ? fn->getInvocationGenericSignature() : outerGenericSig; appendFlatGenericArgs(subs, sig, forDecl); - appendRetroactiveConformances(subs, sig, Mod); + appendRetroactiveConformances(subs, sig); } OpArgs.push_back('_'); @@ -2217,7 +2240,7 @@ void ASTMangler::appendOpaqueTypeArchetype(ArchetypeType *archetype, appendOpaqueDeclName(opaqueDecl); bool isFirstArgList = true; appendBoundGenericArgs(opaqueDecl, sig, subs, isFirstArgList, forDecl); - appendRetroactiveConformances(subs, sig, opaqueDecl->getParentModule()); + appendRetroactiveConformances(subs, sig); appendOperator("Qo", Index(genericParam->getIndex())); } else { @@ -4143,62 +4166,73 @@ 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(); } } void ASTMangler::appendConcreteProtocolConformance( const ProtocolConformance *conformance, GenericSignature sig) { - auto module = conformance->getDeclContext()->getParentModule(); - // Conforming type. Type conformingType = conformance->getType(); if (conformingType->hasArchetype()) conformingType = conformingType->mapTypeOutOfContext(); - appendType(conformingType->getCanonicalType(), sig); + appendType(conformingType->getReducedType(sig), sig); // Protocol conformance reference. appendProtocolConformanceRef(conformance->getRootConformance()); // Conditional conformance requirements. bool firstRequirement = true; - for (const auto &conditionalReq : conformance->getConditionalRequirements()) { - switch (conditionalReq.getKind()) { - case RequirementKind::SameShape: - llvm_unreachable("Same-shape requirement not supported here"); - case RequirementKind::Layout: - case RequirementKind::SameType: - case RequirementKind::Superclass: - continue; - - case RequirementKind::Conformance: { - auto type = conditionalReq.getFirstType(); - if (type->hasArchetype()) - type = type->mapTypeOutOfContext(); - CanType canType = type->getReducedType(sig); - auto proto = conditionalReq.getProtocolDecl(); - - ProtocolConformanceRef conformance; - - if (canType->isTypeParameter() || canType->is()){ - conformance = ProtocolConformanceRef(proto); - } else { - conformance = module->lookupConformance(canType, proto); - } - appendAnyProtocolConformance(sig, canType, conformance); + forEachConditionalConformance(conformance, + [&](Type substType, ProtocolConformanceRef substConf) -> bool { + if (substType->hasArchetype()) + substType = substType->mapTypeOutOfContext(); + CanType canType = substType->getReducedType(sig); + appendAnyProtocolConformance(sig, canType, substConf); appendListSeparator(firstRequirement); - break; - } - } - } + return false; + }); + if (firstRequirement) appendOperator("y"); 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..fa2c1d539d57e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4455,11 +4455,8 @@ case TypeKind::Id: auto sig = opaque->getDecl()->getGenericSignature(); auto newSubMap = SubstitutionMap::get(sig, - [&](SubstitutableType *t) -> Type { - auto index = sig->getGenericParamOrdinal(cast(t)); - return newSubs[index]; - }, - LookUpConformanceInModule(opaque->getDecl()->getModuleContext())); + QueryReplacementTypeArray{sig, newSubs}, + LookUpConformanceInModule(opaque->getDecl()->getModuleContext())); return OpaqueTypeArchetypeType::get(opaque->getDecl(), opaque->getInterfaceType(), newSubMap); @@ -5354,23 +5351,6 @@ Type TypeBase::openAnyExistentialType(OpenedArchetypeType *&opened, return opened; } -CanType swift::substOpaqueTypesWithUnderlyingTypes(CanType ty, - TypeExpansionContext context, - bool allowLoweredTypes) { - if (!context.shouldLookThroughOpaqueTypeArchetypes() || - !ty->hasOpaqueArchetype()) - return ty; - - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - context.getContext(), context.getResilienceExpansion(), - context.isWholeModuleContext()); - SubstOptions flags = SubstFlags::SubstituteOpaqueArchetypes; - if (allowLoweredTypes) - flags = - SubstFlags::SubstituteOpaqueArchetypes | SubstFlags::AllowLoweredTypes; - return ty.subst(replacer, replacer, flags)->getCanonicalType(); -} - AnyFunctionType *AnyFunctionType::getWithoutDifferentiability() const { SmallVector newParams; for (auto ¶m : getParams()) { diff --git a/lib/AST/TypeSubstitution.cpp b/lib/AST/TypeSubstitution.cpp index 9f1f2d4a9b5ad..f4524600c55e5 100644 --- a/lib/AST/TypeSubstitution.cpp +++ b/lib/AST/TypeSubstitution.cpp @@ -1016,7 +1016,9 @@ static Type substOpaqueTypesWithUnderlyingTypesRec( llvm::DenseSet &decls) { ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion, isWholeModuleContext, decls); - return ty.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); + return ty.subst(replacer, replacer, + SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); } /// Checks that \p dc has access to \p ty for the purposes of an opaque @@ -1162,6 +1164,23 @@ operator()(SubstitutableType *maybeOpaqueType) const { return substTy; } +CanType swift::substOpaqueTypesWithUnderlyingTypes(CanType ty, + TypeExpansionContext context, + bool allowLoweredTypes) { + if (!context.shouldLookThroughOpaqueTypeArchetypes() || + !ty->hasOpaqueArchetype()) + return ty; + + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + context.getContext(), context.getResilienceExpansion(), + context.isWholeModuleContext()); + SubstOptions flags = (SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); + if (allowLoweredTypes) + flags |= SubstFlags::AllowLoweredTypes; + return ty.subst(replacer, replacer, flags)->getCanonicalType(); +} + static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypesRec( ProtocolConformanceRef ref, Type origType, const DeclContext *inContext, ResilienceExpansion contextExpansion, bool isWholeModuleContext, @@ -1169,7 +1188,8 @@ static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypesRec( ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion, isWholeModuleContext, decls); return ref.subst(origType, replacer, replacer, - SubstFlags::SubstituteOpaqueArchetypes); + SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); } ProtocolConformanceRef swift::substOpaqueTypesWithUnderlyingTypes( diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index e542e67495f57..ddb03dec23c19 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/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 768e85f4458f1..013c9baf623ce 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -528,13 +528,9 @@ CanType IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type) { // Substitute away opaque types whose underlying types we're allowed to // assume are constant. if (type->hasOpaqueArchetype()) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - getSwiftModule(), ResilienceExpansion::Maximal, - getSILModule().isWholeModule()); - auto underlyingTy = - type.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes) - ->getCanonicalType(); - return underlyingTy; + auto context = getMaximalTypeExpansionContext(); + return swift::substOpaqueTypesWithUnderlyingTypes(type, context, + /*allowLoweredTypes=*/false); } return type; @@ -545,13 +541,11 @@ SILType IRGenModule::substOpaqueTypesWithUnderlyingTypes( // Substitute away opaque types whose underlying types we're allowed to // assume are constant. if (type.getASTType()->hasOpaqueArchetype()) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - getSwiftModule(), ResilienceExpansion::Maximal, - getSILModule().isWholeModule()); - auto underlyingTy = - type.subst(getSILModule(), replacer, replacer, genericSig, - SubstFlags::SubstituteOpaqueArchetypes); - return underlyingTy; + auto context = getMaximalTypeExpansionContext(); + return SILType::getPrimitiveType( + swift::substOpaqueTypesWithUnderlyingTypes(type.getASTType(), context, + /*allowLoweredTypes=*/true), + type.getCategory()); } return type; @@ -563,15 +557,11 @@ IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type, // Substitute away opaque types whose underlying types we're allowed to // assume are constant. if (type->hasOpaqueArchetype()) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - getSwiftModule(), ResilienceExpansion::Maximal, - getSILModule().isWholeModule()); - auto substConformance = conformance.subst( - type, replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); - auto underlyingTy = - type.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes) - ->getCanonicalType(); - return std::make_pair(underlyingTy, substConformance); + auto context = getMaximalTypeExpansionContext(); + return std::make_pair( + swift::substOpaqueTypesWithUnderlyingTypes(type, context, + /*allowLoweredTypes=*/false), + swift::substOpaqueTypesWithUnderlyingTypes(conformance, type, context)); } return std::make_pair(type, conformance); diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 462b53f21fa43..bc565776b2c4f 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -4800,14 +4800,16 @@ static bool areABICompatibleParamsOrReturns(SILType a, SILType b, if (aa.getASTType()->hasOpaqueArchetype()) opaqueTypesSubstituted = aa.subst(inFunction->getModule(), replacer, replacer, CanGenericSignature(), - SubstFlags::SubstituteOpaqueArchetypes); + SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); auto opaqueTypesSubstituted2 = bb; if (bb.getASTType()->hasOpaqueArchetype()) opaqueTypesSubstituted2 = bb.subst(inFunction->getModule(), replacer, replacer, CanGenericSignature(), - SubstFlags::SubstituteOpaqueArchetypes); + SubstFlags::SubstituteOpaqueArchetypes | + SubstFlags::PreservePackExpansionLevel); if (opaqueTypesSubstituted == opaqueTypesSubstituted2) continue; } 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/Generics/tuple-conformances.swift b/test/Generics/tuple-conformances.swift index cffc8a70aec15..b963769724f5d 100644 --- a/test/Generics/tuple-conformances.swift +++ b/test/Generics/tuple-conformances.swift @@ -96,18 +96,30 @@ extension Tuple: Equatable where repeat each Element: Equatable { // FIXME: Hack @_disfavoredOverload public static func ==(lhs: Self, rhs: Self) -> Bool { - var result = true - func update(lhs: E, rhs: E) { - result = result && (lhs == rhs) + for (l, r) in repeat (each lhs, each rhs) { + if l != r { return false } } - - repeat update(lhs: each lhs, rhs: each rhs) - return result + return true } } extension Tuple: Hashable where repeat each Element: Hashable { public func hash(into hasher: inout Hasher) { - repeat (each self).hash(into: &hasher) + for elt in repeat each self { + elt.hash(into: &hasher) + } } } + +extension Tuple: Comparable where repeat each Element: Comparable { + // FIXME: Hack + @_disfavoredOverload + public static func <(lhs: Self, rhs: Self) -> Bool { + for (l, r) in repeat (each lhs, each rhs) { + if l > r { return false } + if l < r { return true } + } + return false + } +} + diff --git a/test/IRGen/variadic_generic_opaque.swift b/test/IRGen/variadic_generic_opaque.swift index 218afccda5b66..f5f757a726ffa 100644 --- a/test/IRGen/variadic_generic_opaque.swift +++ b/test/IRGen/variadic_generic_opaque.swift @@ -1,11 +1,53 @@ -// 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" + +// Conditional same-shape requirement +public struct Outer { + public struct Inner {} +} + +extension Outer.Inner: P where (repeat (each T, each U)): Any {} + +func concreteOuterInner() -> some P { + Outer.Inner() +} \ No newline at end of file diff --git a/test/Reflection/opaque_associated_type_requirements.swift b/test/Reflection/opaque_associated_type_requirements.swift index c3a577141c31a..05de98ebaa7f6 100644 --- a/test/Reflection/opaque_associated_type_requirements.swift +++ b/test/Reflection/opaque_associated_type_requirements.swift @@ -10,20 +10,12 @@ // RUN: %target-swift-reflection-dump %t/AssociatedTypeRequirements | %FileCheck %s +// This test is useless and was just relying on a bug where we didn't substitute away +// known opaque return types in non-WMO mode. + // CHECK: ASSOCIATED TYPES: // CHECK: - AssociatedTypeRequirements.Foo : AssociatedTypeRequirements.myProto -// CHECK-NEXT: typealias PerformReturn = opaque type symbolic reference -// CHECK-NEXT: opaque type symbolic reference -// CHECK-NEXT: (bound_generic_struct AssociatedTypeRequirements.Bar - -// CHECK: conformance requirements: -// CHECK-NEXT: AssociatedTypeRequirements.protoA -// CHECK-NEXT: AssociatedTypeRequirements.protoB -// CHECK-NEXT: testModB.testModBProtocol - -// CHECK: same-type requirements: -// CHECK-NEXT: A.AssociatedTypeRequirements.protoB.K = Sf (Swift.Float) -// CHECK-NEXT: A.AssociatedTypeRequirements.protoA.T = 8testModB0aB7BStructV (testModB.testModBStruct) +// CHECK-NEXT: typealias PerformReturn = AssociatedTypeRequirements.Bar import testModB 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() +}