From d553dce2d8fa8eda862b37b18c2a6a52c4ab981c Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 29 Jun 2023 14:47:36 -0700 Subject: [PATCH] [Compile Time Constant Extraction] Refactor collection of opaque type requirements To reduce duplication of logic with other parts of the compiler, instead of destructuring the constraint type, write the requirements in the opaque type declaration's generic signature. --- lib/ConstExtract/ConstExtract.cpp | 96 ++++++------------- .../ExtractOpaqueGenericTypealias.swift | 57 +++++++++++ .../ExtractOpaqueTypealias.swift | 10 +- 3 files changed, 91 insertions(+), 72 deletions(-) create mode 100644 test/ConstExtraction/ExtractOpaqueGenericTypealias.swift diff --git a/lib/ConstExtract/ConstExtract.cpp b/lib/ConstExtract/ConstExtract.cpp index 669878075f8b1..481ca9cd9aa84 100644 --- a/lib/ConstExtract/ConstExtract.cpp +++ b/lib/ConstExtract/ConstExtract.cpp @@ -811,79 +811,41 @@ void writeAttrInformation(llvm::json::OStream &JSON, }); } -void writeParameterizedProtocolSameTypeRequirements( - llvm::json::OStream &JSON, - const ParameterizedProtocolType &ParameterizedProtoTy) { - auto Protocol = ParameterizedProtoTy.getProtocol(); - auto ProtocolTy = ParameterizedProtoTy.getBaseType(); - auto Requirements = Protocol->getProtocolRequirements(); - auto ParameterTypeNames = Protocol->getPrimaryAssociatedTypeNames(); - auto ProtocolArguments = ParameterizedProtoTy.getArgs(); - llvm::dbgs() << Requirements.size() << "\n"; - assert(ProtocolArguments.size() >= ParameterTypeNames.size()); - - for (size_t i = 0; i < ProtocolArguments.size(); ++i) { - auto ProtocolArgumentTy = ProtocolArguments[i]; - std::string ArgumentName = ParameterTypeNames.size() > i - ? ParameterTypeNames[i].first.str().str() - : "unknown"; - - JSON.object([&] { - auto QualifiedTypeAliasName = toFullyQualifiedProtocolNameString( - *ParameterizedProtoTy.getProtocol()) + - "." + ArgumentName; - JSON.attribute("typeAliasName", QualifiedTypeAliasName); - JSON.attribute("substitutedTypeName", - toFullyQualifiedTypeNameString(ProtocolArgumentTy)); - JSON.attribute("substitutedMangledTypeName", - toMangledTypeNameString(ProtocolArgumentTy)); - }); - } -} - -void writeOpaqueTypeProtocolCompositionSameTypeRequirements( - llvm::json::OStream &JSON, - const ProtocolCompositionType &ProtocolCompositionTy) { - for (auto CompositionMemberProto : ProtocolCompositionTy.getMembers()) { - if (auto ParameterizedProtoTy = - CompositionMemberProto->getAs()) { - writeParameterizedProtocolSameTypeRequirements(JSON, - *ParameterizedProtoTy); - } - } -} - void writeSubstitutedOpaqueTypeAliasDetails( llvm::json::OStream &JSON, const OpaqueTypeArchetypeType &OpaqueTy) { + auto Signature = OpaqueTy.getDecl()->getOpaqueInterfaceGenericSignature(); + JSON.attributeArray("opaqueTypeProtocolRequirements", [&] { - auto ConformsToProtocols = OpaqueTy.getConformsTo(); - for (auto Proto : ConformsToProtocols) { - JSON.value(toFullyQualifiedProtocolNameString(*Proto)); + for (const auto Requirement : Signature.getRequirements()) { + // Ignore requirements whose subject type is that of the owner decl + if (!Requirement.getFirstType()->isEqual(OpaqueTy.getInterfaceType())) + continue; + if (Requirement.getKind() == RequirementKind::Conformance) + JSON.value( + toFullyQualifiedProtocolNameString(*Requirement.getProtocolDecl())); } }); + JSON.attributeArray("opaqueTypeSameTypeRequirements", [&] { - auto GenericSig = OpaqueTy.getDecl() - ->getNamingDecl() - ->getInnermostDeclContext() - ->getGenericSignatureOfContext(); - auto ConstraintTy = OpaqueTy.getExistentialType(); - if (auto existential = ConstraintTy->getAs()) - ConstraintTy = existential->getConstraintType(); - - // Opaque archetype substitutions are always canonical, so - // re-sugar the constraint type using the owning - // declaration's generic parameter names. - if (GenericSig) - ConstraintTy = GenericSig->getSugaredType(ConstraintTy); - - if (auto ParameterizedProtoTy = - ConstraintTy->getAs()) { - writeParameterizedProtocolSameTypeRequirements(JSON, - *ParameterizedProtoTy); - } else if (auto ProtocolCompositionTy = - ConstraintTy->getAs()) { - writeOpaqueTypeProtocolCompositionSameTypeRequirements( - JSON, *ProtocolCompositionTy); + for (const auto Requirement : Signature.getRequirements()) { + if (Requirement.getKind() == RequirementKind::SameType) { + auto TypeAliasType = Requirement.getFirstType(); + auto TypeWitness = Requirement.getSecondType(); + JSON.object([&] { + auto TypeAliasName = toFullyQualifiedTypeNameString(TypeAliasType); + if (auto DependentMemberTy = + TypeAliasType->getAs()) + if (const auto *Assoc = DependentMemberTy->getAssocType()) + TypeAliasName = + toFullyQualifiedProtocolNameString(*Assoc->getProtocol()) + + "." + DependentMemberTy->getName().str().str(); + JSON.attribute("typeAliasName", TypeAliasName); + JSON.attribute("substitutedTypeName", + toFullyQualifiedTypeNameString(TypeWitness)); + JSON.attribute("substitutedMangledTypeName", + toMangledTypeNameString(TypeWitness)); + }); + } } }); } diff --git a/test/ConstExtraction/ExtractOpaqueGenericTypealias.swift b/test/ConstExtraction/ExtractOpaqueGenericTypealias.swift new file mode 100644 index 0000000000000..a94b941c0b58b --- /dev/null +++ b/test/ConstExtraction/ExtractOpaqueGenericTypealias.swift @@ -0,0 +1,57 @@ +// REQUIRES: OS=macosx +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/includes) +// RUN: echo "[myProto]" > %t/protocols.json + +// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.15 -typecheck -emit-const-values-path %t/ExtractOpaqueGenericTypealias.swiftconstvalues -const-gather-protocols-file %t/protocols.json -primary-file %s -I %t/includes +// RUN: cat %t/ExtractOpaqueGenericTypealias.swiftconstvalues 2>&1 | %FileCheck %s + +protocol myProto { + associatedtype T + func foo() -> T +} + +protocol protoA { + associatedtype T +} + +struct A : protoA { + typealias T = K +} + +struct Foo : myProto { + func foo() -> some protoA { return A() } + func bar(_ param : L) {} +} + +// CHECK: [ +// CHECK-NEXT: { +// CHECK-NEXT: "typeName": "ExtractOpaqueGenericTypealias.Foo", +// CHECK-NEXT: "mangledTypeName": "29ExtractOpaqueGenericTypealias3FooVyxG", +// CHECK-NEXT: "kind": "generic struct", +// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractOpaqueGenericTypealias.swift", +// CHECK-NEXT: "line": 22, +// CHECK-NEXT: "conformances": [ +// CHECK-NEXT: "ExtractOpaqueGenericTypealias.myProto", +// CHECK-NEXT: "Swift.Sendable" +// CHECK-NEXT: ], +// CHECK-NEXT: "associatedTypeAliases": [ +// CHECK-NEXT: { +// CHECK-NEXT: "typeAliasName": "T", +// CHECK-NEXT: "substitutedTypeName": "some ExtractOpaqueGenericTypealias.protoA", +// CHECK-NEXT: "substitutedMangledTypeName": "29ExtractOpaqueGenericTypealias3FooV3fooQryFQOyx_Qo_", +// CHECK-NEXT: "opaqueTypeProtocolRequirements": [ +// CHECK-NEXT: "ExtractOpaqueGenericTypealias.protoA" +// CHECK-NEXT: ], +// CHECK-NEXT: "opaqueTypeSameTypeRequirements": [ +// CHECK-NEXT: { +// CHECK-NEXT: "typeAliasName": "ExtractOpaqueGenericTypealias.protoA.T", +// CHECK-NEXT: "substitutedTypeName": "Swift.Int", +// CHECK-NEXT: "substitutedMangledTypeName": "Si" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "properties": [] +// CHECK-NEXT: } +// CHECK-NEXT: ] diff --git a/test/ConstExtraction/ExtractOpaqueTypealias.swift b/test/ConstExtraction/ExtractOpaqueTypealias.swift index a30e739481d01..92fee013ac132 100644 --- a/test/ConstExtraction/ExtractOpaqueTypealias.swift +++ b/test/ConstExtraction/ExtractOpaqueTypealias.swift @@ -56,15 +56,15 @@ private func baz() -> some protoA & protoB & testModBProt // CHECK-NEXT: ], // CHECK-NEXT: "opaqueTypeSameTypeRequirements": [ // CHECK-NEXT: { -// CHECK-NEXT: "typeAliasName": "ExtractOpaqueTypealias.protoA.T", -// CHECK-NEXT: "substitutedTypeName": "testModB.testModBStruct", -// CHECK-NEXT: "substitutedMangledTypeName": "8testModB0aB7BStructV" -// CHECK-NEXT: }, -// CHECK-NEXT: { // CHECK-NEXT: "typeAliasName": "ExtractOpaqueTypealias.protoB.K", // CHECK-NEXT: "substitutedTypeName": "Swift.Float", // CHECK-NEXT: "substitutedMangledTypeName": "Sf" // CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: "typeAliasName": "ExtractOpaqueTypealias.protoA.T", +// CHECK-NEXT: "substitutedTypeName": "testModB.testModBStruct", +// CHECK-NEXT: "substitutedMangledTypeName": "8testModB0aB7BStructV" +// CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ],