From 6bccd9fd7e92cd70f2078a371e4fb509a42941ae Mon Sep 17 00:00:00 2001 From: James Paolantonio Date: Tue, 17 Jan 2023 15:32:35 -0500 Subject: [PATCH] [Compile Time Constant Extraction] Extract result builder-type information --- lib/ConstExtract/ConstExtract.cpp | 35 +++++- .../ExtractResultBuilders.swift | 102 ++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 test/ConstExtraction/ExtractResultBuilders.swift diff --git a/lib/ConstExtract/ConstExtract.cpp b/lib/ConstExtract/ConstExtract.cpp index c0f3a8b73bbe4..2085f65f358f1 100644 --- a/lib/ConstExtract/ConstExtract.cpp +++ b/lib/ConstExtract/ConstExtract.cpp @@ -646,6 +646,37 @@ void writeEnumCases( }); } +void writeResultBuilderInformation(llvm::json::OStream &JSON, + const swift::NominalTypeDecl *TypeDecl, + const swift::VarDecl *VarDecl) { + if (auto *attr = VarDecl->getAttachedResultBuilder()) { + JSON.attributeObject("resultBuilder", [&] { + JSON.attribute("type", toFullyQualifiedTypeNameString(attr->getType())); + }); + + return; + } + + for (ProtocolDecl *Decl : + TypeDecl->getLocalProtocols(ConformanceLookupKind::All)) { + for (auto Member : Decl->getMembers()) { + if (auto *VD = dyn_cast(Member)) { + if (VD->getName() != VarDecl->getName()) + continue; + + if (auto *attr = VD->getAttachedResultBuilder()) { + JSON.attributeObject("resultBuilder", [&] { + JSON.attribute("type", + toFullyQualifiedTypeNameString(attr->getType())); + }); + } + + return; + } + } + } +} + bool writeAsJSONToFile(const std::vector &ConstValueInfos, llvm::raw_fd_ostream &OS) { llvm::json::OStream JSON(OS, 2); @@ -653,7 +684,8 @@ bool writeAsJSONToFile(const std::vector &ConstValueInfos, for (const auto &TypeInfo : ConstValueInfos) { JSON.object([&] { const auto *TypeDecl = TypeInfo.TypeDecl; - JSON.attribute("typeName", toFullyQualifiedTypeNameString(TypeDecl->getDeclaredInterfaceType())); + JSON.attribute("typeName", toFullyQualifiedTypeNameString( + TypeDecl->getDeclaredInterfaceType())); JSON.attribute( "kind", TypeDecl->getDescriptiveKindName(TypeDecl->getDescriptiveKind()) @@ -672,6 +704,7 @@ bool writeAsJSONToFile(const std::vector &ConstValueInfos, writeFileInformation(JSON, decl); writeValue(JSON, PropertyInfo.Value); writeAttributes(JSON, PropertyInfo.PropertyWrappers); + writeResultBuilderInformation(JSON, TypeDecl, decl); }); } }); diff --git a/test/ConstExtraction/ExtractResultBuilders.swift b/test/ConstExtraction/ExtractResultBuilders.swift new file mode 100644 index 0000000000000..3ceeeb43e49f6 --- /dev/null +++ b/test/ConstExtraction/ExtractResultBuilders.swift @@ -0,0 +1,102 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/inputs) +// RUN: echo "[FooProvider]" > %t/inputs/protocols.json + +// RUN: %target-swift-frontend -typecheck -emit-const-values-path %t/ExtractResultBuilders.swiftconstvalues -const-gather-protocols-file %t/inputs/protocols.json -primary-file %s +// RUN: cat %t/ExtractResultBuilders.swiftconstvalues 2>&1 | %FileCheck %s + +public struct Foo { + let name: String +} + +@resultBuilder +public enum FooBuilder { + public static func buildExpression(_ component: Foo) -> Foo { + component + } + + public static func buildBlock(_ components: Foo...) -> [Foo] { + components + } +} + +public protocol FooProvider { + @FooBuilder + static var foos: [Foo] { get } +} + +public struct MyFooProvider: FooProvider { + @FooBuilder + public static var foos: [Foo] { + Foo(name: "AAA") + Foo(name: "BBB") + } + + @FooBuilder + public static var fooTwo: [Foo] { + Foo(name: "111") + Foo(name: "222") + } +} + +public struct MyFooProviderInferred: FooProvider { + public static var foos: [Foo] { + Foo(name: "CCC") + Foo(name: "DDD") + } +} + +// CHECK: [ +// CHECK-NEXT: { +// CHECK-NEXT: "typeName": "ExtractResultBuilders.MyFooProvider", +// CHECK-NEXT: "kind": "struct", +// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractResultBuilders.swift", +// CHECK-NEXT: "line": 28, +// CHECK-NEXT: "properties": [ +// CHECK-NEXT: { +// CHECK-NEXT: "label": "foos", +// CHECK-NEXT: "type": "[ExtractResultBuilders.Foo]", +// CHECK-NEXT: "isStatic": "true", +// CHECK-NEXT: "isComputed": "true", +// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractResultBuilders.swift", +// CHECK-NEXT: "line": 30, +// CHECK-NEXT: "valueKind": "Runtime", +// CHECK-NEXT: "resultBuilder": { +// CHECK-NEXT: "type": "ExtractResultBuilders.FooBuilder" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "label": "fooTwo", +// CHECK-NEXT: "type": "[ExtractResultBuilders.Foo]", +// CHECK-NEXT: "isStatic": "true", +// CHECK-NEXT: "isComputed": "true", +// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractResultBuilders.swift", +// CHECK-NEXT: "line": 36, +// CHECK-NEXT: "valueKind": "Runtime", +// CHECK-NEXT: "resultBuilder": { +// CHECK-NEXT: "type": "ExtractResultBuilders.FooBuilder" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "typeName": "ExtractResultBuilders.MyFooProviderInferred", +// CHECK-NEXT: "kind": "struct", +// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractResultBuilders.swift", +// CHECK-NEXT: "line": 42, +// CHECK-NEXT: "properties": [ +// CHECK-NEXT: { +// CHECK-NEXT: "label": "foos", +// CHECK-NEXT: "type": "[ExtractResultBuilders.Foo]", +// CHECK-NEXT: "isStatic": "true", +// CHECK-NEXT: "isComputed": "true", +// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractResultBuilders.swift", +// CHECK-NEXT: "line": 43, +// CHECK-NEXT: "valueKind": "Runtime", +// CHECK-NEXT: "resultBuilder": { +// CHECK-NEXT: "type": "ExtractResultBuilders.FooBuilder" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ]