Skip to content

Commit 9a11e04

Browse files
authored
Merge pull request #66639 from artemcm/ConstExtractConformanceInfo
[Compile Time Constant Extraction] Add extraction of all conformances and type aliases of applicable nominal types
2 parents b91328c + 3f0c0f0 commit 9a11e04

11 files changed

+402
-35
lines changed

lib/ConstExtract/ConstExtract.cpp

Lines changed: 174 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,21 @@ std::string toFullyQualifiedTypeNameString(const swift::Type &Type) {
7171
Options.AlwaysDesugarArraySliceTypes = true;
7272
Options.AlwaysDesugarDictionaryTypes = true;
7373
Options.AlwaysDesugarOptionalTypes = true;
74+
Options.OpaqueReturnTypePrinting =
75+
PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword;
7476
Type.print(OutputStream, Options);
7577
OutputStream.flush();
7678
return TypeNameOutput;
7779
}
7880

81+
std::string toFullyQualifiedProtocolNameString(const swift::ProtocolDecl &Protocol) {
82+
// Protocols cannot be nested in other declarations, so the only fully-qualified
83+
// context is the declaring module name.
84+
return Protocol.getParentModule()->getNameStr().str() + "." + Protocol.getNameStr().str();
85+
}
86+
7987
std::string toMangledTypeNameString(const swift::Type &Type) {
80-
return Mangle::ASTMangler().mangleTypeWithoutPrefix(Type);
88+
return Mangle::ASTMangler().mangleTypeWithoutPrefix(Type->getCanonicalType());
8189
}
8290

8391
} // namespace
@@ -803,46 +811,178 @@ void writeAttrInformation(llvm::json::OStream &JSON,
803811
});
804812
}
805813

814+
void writeParameterizedProtocolSameTypeRequirements(
815+
llvm::json::OStream &JSON,
816+
const ParameterizedProtocolType &ParameterizedProtoTy) {
817+
auto Protocol = ParameterizedProtoTy.getProtocol();
818+
auto ProtocolTy = ParameterizedProtoTy.getBaseType();
819+
auto Requirements = Protocol->getProtocolRequirements();
820+
auto ParameterTypeNames = Protocol->getPrimaryAssociatedTypeNames();
821+
auto ProtocolArguments = ParameterizedProtoTy.getArgs();
822+
llvm::dbgs() << Requirements.size() << "\n";
823+
assert(ProtocolArguments.size() >= ParameterTypeNames.size());
824+
825+
for (size_t i = 0; i < ProtocolArguments.size(); ++i) {
826+
auto ProtocolArgumentTy = ProtocolArguments[i];
827+
std::string ArgumentName = ParameterTypeNames.size() > i
828+
? ParameterTypeNames[i].first.str().str()
829+
: "unknown";
830+
831+
JSON.object([&] {
832+
auto QualifiedTypeAliasName = toFullyQualifiedProtocolNameString(
833+
*ParameterizedProtoTy.getProtocol()) +
834+
"." + ArgumentName;
835+
JSON.attribute("typeAliasName", QualifiedTypeAliasName);
836+
JSON.attribute("substitutedTypeName",
837+
toFullyQualifiedTypeNameString(ProtocolArgumentTy));
838+
JSON.attribute("substitutedMangledTypeName",
839+
toMangledTypeNameString(ProtocolArgumentTy));
840+
});
841+
}
842+
}
843+
844+
void writeOpaqueTypeProtocolCompositionSameTypeRequirements(
845+
llvm::json::OStream &JSON,
846+
const ProtocolCompositionType &ProtocolCompositionTy) {
847+
for (auto CompositionMemberProto : ProtocolCompositionTy.getMembers()) {
848+
if (auto ParameterizedProtoTy =
849+
CompositionMemberProto->getAs<ParameterizedProtocolType>()) {
850+
writeParameterizedProtocolSameTypeRequirements(JSON,
851+
*ParameterizedProtoTy);
852+
}
853+
}
854+
}
855+
856+
void writeSubstitutedOpaqueTypeAliasDetails(
857+
llvm::json::OStream &JSON, const OpaqueTypeArchetypeType &OpaqueTy) {
858+
JSON.attributeArray("opaqueTypeProtocolRequirements", [&] {
859+
auto ConformsToProtocols = OpaqueTy.getConformsTo();
860+
for (auto Proto : ConformsToProtocols) {
861+
JSON.value(toFullyQualifiedProtocolNameString(*Proto));
862+
}
863+
});
864+
JSON.attributeArray("opaqueTypeSameTypeRequirements", [&] {
865+
auto GenericSig = OpaqueTy.getDecl()
866+
->getNamingDecl()
867+
->getInnermostDeclContext()
868+
->getGenericSignatureOfContext();
869+
auto ConstraintTy = OpaqueTy.getExistentialType();
870+
if (auto existential = ConstraintTy->getAs<ExistentialType>())
871+
ConstraintTy = existential->getConstraintType();
872+
873+
// Opaque archetype substitutions are always canonical, so
874+
// re-sugar the constraint type using the owning
875+
// declaration's generic parameter names.
876+
if (GenericSig)
877+
ConstraintTy = GenericSig->getSugaredType(ConstraintTy);
878+
879+
if (auto ParameterizedProtoTy =
880+
ConstraintTy->getAs<ParameterizedProtocolType>()) {
881+
writeParameterizedProtocolSameTypeRequirements(JSON,
882+
*ParameterizedProtoTy);
883+
} else if (auto ProtocolCompositionTy =
884+
ConstraintTy->getAs<ProtocolCompositionType>()) {
885+
writeOpaqueTypeProtocolCompositionSameTypeRequirements(
886+
JSON, *ProtocolCompositionTy);
887+
}
888+
});
889+
}
890+
891+
void writeAssociatedTypeAliases(llvm::json::OStream &JSON,
892+
const NominalTypeDecl &NomTypeDecl) {
893+
JSON.attributeArray("associatedTypeAliases", [&] {
894+
for (auto &Conformance : NomTypeDecl.getAllConformances()) {
895+
Conformance->forEachTypeWitness(
896+
[&](AssociatedTypeDecl *assoc, Type type, TypeDecl *typeDecl) {
897+
JSON.object([&] {
898+
JSON.attribute("typeAliasName", assoc->getName().str().str());
899+
JSON.attribute("substitutedTypeName",
900+
toFullyQualifiedTypeNameString(type));
901+
JSON.attribute("substitutedMangledTypeName",
902+
toMangledTypeNameString(type));
903+
if (auto OpaqueTy = dyn_cast<OpaqueTypeArchetypeType>(type)) {
904+
writeSubstitutedOpaqueTypeAliasDetails(JSON, *OpaqueTy);
905+
}
906+
});
907+
return false;
908+
});
909+
}
910+
});
911+
}
912+
913+
void writeProperties(llvm::json::OStream &JSON,
914+
const ConstValueTypeInfo &TypeInfo,
915+
const NominalTypeDecl &NomTypeDecl) {
916+
JSON.attributeArray("properties", [&] {
917+
for (const auto &PropertyInfo : TypeInfo.Properties) {
918+
JSON.object([&] {
919+
const auto *decl = PropertyInfo.VarDecl;
920+
JSON.attribute("label", decl->getName().str().str());
921+
JSON.attribute("type", toFullyQualifiedTypeNameString(decl->getType()));
922+
JSON.attribute("mangledTypeName", toMangledTypeNameString(decl->getType()));
923+
JSON.attribute("isStatic", decl->isStatic() ? "true" : "false");
924+
JSON.attribute("isComputed", !decl->hasStorage() ? "true" : "false");
925+
writeLocationInformation(JSON, decl->getLoc(),
926+
decl->getDeclContext()->getASTContext());
927+
writeValue(JSON, PropertyInfo.Value);
928+
writePropertyWrapperAttributes(JSON, PropertyInfo.PropertyWrappers,
929+
decl->getASTContext());
930+
writeRuntimeMetadataAttributes(JSON,
931+
PropertyInfo.RuntimeMetadataAttributes,
932+
decl->getASTContext());
933+
writeResultBuilderInformation(JSON, &NomTypeDecl, decl);
934+
writeAttrInformation(JSON, decl->getAttrs());
935+
});
936+
}
937+
});
938+
}
939+
940+
void writeConformances(llvm::json::OStream &JSON,
941+
const NominalTypeDecl &NomTypeDecl) {
942+
JSON.attributeArray("conformances", [&] {
943+
for (auto &Protocol : NomTypeDecl.getAllProtocols()) {
944+
JSON.value(toFullyQualifiedProtocolNameString(*Protocol));
945+
}
946+
});
947+
}
948+
949+
void writeTypeName(llvm::json::OStream &JSON, const TypeDecl &TypeDecl) {
950+
JSON.attribute("typeName",
951+
toFullyQualifiedTypeNameString(
952+
TypeDecl.getDeclaredInterfaceType()));
953+
JSON.attribute("mangledTypeName",
954+
toMangledTypeNameString(TypeDecl.getDeclaredInterfaceType()));
955+
}
956+
957+
void writeNominalTypeKind(llvm::json::OStream &JSON,
958+
const NominalTypeDecl &NomTypeDecl) {
959+
JSON.attribute(
960+
"kind",
961+
NomTypeDecl.getDescriptiveKindName(NomTypeDecl.getDescriptiveKind())
962+
.str());
963+
}
964+
806965
bool writeAsJSONToFile(const std::vector<ConstValueTypeInfo> &ConstValueInfos,
807966
llvm::raw_ostream &OS) {
808967
llvm::json::OStream JSON(OS, 2);
809968
JSON.array([&] {
810969
for (const auto &TypeInfo : ConstValueInfos) {
970+
assert(isa<NominalTypeDecl>(TypeInfo.TypeDecl) &&
971+
"Expected Nominal Type Decl for a conformance");
972+
const auto *NomTypeDecl = cast<NominalTypeDecl>(TypeInfo.TypeDecl);
973+
const auto SourceLoc =
974+
extractNearestSourceLoc(NomTypeDecl->getInnermostDeclContext());
975+
const auto &Ctx = NomTypeDecl->getInnermostDeclContext()->getASTContext();
976+
811977
JSON.object([&] {
812-
const auto *TypeDecl = TypeInfo.TypeDecl;
813-
JSON.attribute("typeName", toFullyQualifiedTypeNameString(
814-
TypeDecl->getDeclaredInterfaceType()));
815-
JSON.attribute(
816-
"kind",
817-
TypeDecl->getDescriptiveKindName(TypeDecl->getDescriptiveKind())
818-
.str());
819-
writeLocationInformation(
820-
JSON, extractNearestSourceLoc(TypeDecl->getInnermostDeclContext()),
821-
TypeDecl->getInnermostDeclContext()->getASTContext());
822-
JSON.attributeArray("properties", [&] {
823-
for (const auto &PropertyInfo : TypeInfo.Properties) {
824-
JSON.object([&] {
825-
const auto *decl = PropertyInfo.VarDecl;
826-
JSON.attribute("label", decl->getName().str().str());
827-
JSON.attribute("type",
828-
toFullyQualifiedTypeNameString(decl->getType()));
829-
JSON.attribute("isStatic", decl->isStatic() ? "true" : "false");
830-
JSON.attribute("isComputed",
831-
!decl->hasStorage() ? "true" : "false");
832-
writeLocationInformation(JSON, decl->getLoc(),
833-
decl->getDeclContext()->getASTContext());
834-
writeValue(JSON, PropertyInfo.Value);
835-
writePropertyWrapperAttributes(
836-
JSON, PropertyInfo.PropertyWrappers, decl->getASTContext());
837-
writeRuntimeMetadataAttributes(
838-
JSON, PropertyInfo.RuntimeMetadataAttributes, decl->getASTContext());
839-
writeResultBuilderInformation(JSON, TypeDecl, decl);
840-
writeAttrInformation(JSON, decl->getAttrs());
841-
});
842-
}
843-
});
978+
writeTypeName(JSON, *NomTypeDecl);
979+
writeNominalTypeKind(JSON, *NomTypeDecl);
980+
writeLocationInformation(JSON, SourceLoc, Ctx);
981+
writeConformances(JSON, *NomTypeDecl);
982+
writeAssociatedTypeAliases(JSON, *NomTypeDecl);
983+
writeProperties(JSON, TypeInfo, *NomTypeDecl);
844984
writeEnumCases(JSON, TypeInfo.EnumElements);
845-
writeAttrInformation(JSON, TypeDecl->getAttrs());
985+
writeAttrInformation(JSON, NomTypeDecl->getAttrs());
846986
});
847987
}
848988
});

lib/Option/features.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
},
3333
{
3434
"name": "package-name-if-supported"
35+
},
36+
{
37+
"name": "const-extract-complete-metadata"
3538
}
3639
]
3740
}

test/ConstExtraction/ExtractAnnotations.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,19 @@ public struct DeprecatedAnnotations: MyProto {}
3030
// CHECK: [
3131
// CHECK-NEXT: {
3232
// CHECK-NEXT: "typeName": "ExtractAnnotations.Annotations",
33+
// CHECK-NEXT: "mangledTypeName": "18ExtractAnnotations0B0V",
3334
// CHECK-NEXT: "kind": "struct",
3435
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractAnnotations.swift",
3536
// CHECK-NEXT: "line": 9,
37+
// CHECK-NEXT: "conformances": [
38+
// CHECK-NEXT: "ExtractAnnotations.MyProto"
39+
// CHECK-NEXT: ],
40+
// CHECK-NEXT: "associatedTypeAliases": [],
3641
// CHECK-NEXT: "properties": [
3742
// CHECK-NEXT: {
3843
// CHECK-NEXT: "label": "available1",
3944
// CHECK-NEXT: "type": "Swift.String",
45+
// CHECK-NEXT: "mangledTypeName": "SS",
4046
// CHECK-NEXT: "isStatic": "false",
4147
// CHECK-NEXT: "isComputed": "true",
4248
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractAnnotations.swift",
@@ -61,6 +67,7 @@ public struct DeprecatedAnnotations: MyProto {}
6167
// CHECK-NEXT: {
6268
// CHECK-NEXT: "label": "deprecated1",
6369
// CHECK-NEXT: "type": "Swift.String",
70+
// CHECK-NEXT: "mangledTypeName": "SS",
6471
// CHECK-NEXT: "isStatic": "false",
6572
// CHECK-NEXT: "isComputed": "true",
6673
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractAnnotations.swift",
@@ -85,6 +92,7 @@ public struct DeprecatedAnnotations: MyProto {}
8592
// CHECK-NEXT: {
8693
// CHECK-NEXT: "label": "renamed1",
8794
// CHECK-NEXT: "type": "Swift.String",
95+
// CHECK-NEXT: "mangledTypeName": "SS",
8896
// CHECK-NEXT: "isStatic": "false",
8997
// CHECK-NEXT: "isComputed": "true",
9098
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractAnnotations.swift",
@@ -104,6 +112,7 @@ public struct DeprecatedAnnotations: MyProto {}
104112
// CHECK-NEXT: {
105113
// CHECK-NEXT: "label": "introduced1",
106114
// CHECK-NEXT: "type": "Swift.String",
115+
// CHECK-NEXT: "mangledTypeName": "SS",
107116
// CHECK-NEXT: "isStatic": "false",
108117
// CHECK-NEXT: "isComputed": "true",
109118
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractAnnotations.swift",
@@ -123,9 +132,14 @@ public struct DeprecatedAnnotations: MyProto {}
123132
// CHECK-NEXT: },
124133
// CHECK-NEXT: {
125134
// CHECK-NEXT: "typeName": "ExtractAnnotations.DeprecatedAnnotations",
135+
// CHECK-NEXT: "mangledTypeName": "18ExtractAnnotations010DeprecatedB0V",
126136
// CHECK-NEXT: "kind": "struct",
127137
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractAnnotations.swift",
128138
// CHECK-NEXT: "line": 28,
139+
// CHECK-NEXT: "conformances": [
140+
// CHECK-NEXT: "ExtractAnnotations.MyProto"
141+
// CHECK-NEXT: ],
142+
// CHECK-NEXT: "associatedTypeAliases": [],
129143
// CHECK-NEXT: "properties": [],
130144
// CHECK-NEXT: "availabilityAttributes": [
131145
// CHECK-NEXT: {

test/ConstExtraction/ExtractCalls.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,19 @@ public struct Bat {
3939
// CHECK: [
4040
// CHECK-NEXT: {
4141
// CHECK-NEXT: "typeName": "ExtractCalls.Foo",
42+
// CHECK-NEXT: "mangledTypeName": "12ExtractCalls3FooV",
4243
// CHECK-NEXT: "kind": "struct",
4344
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
4445
// CHECK-NEXT: "line": 9,
46+
// CHECK-NEXT: "conformances": [
47+
// CHECK-NEXT: "ExtractCalls.MyProto"
48+
// CHECK-NEXT: ],
49+
// CHECK-NEXT: "associatedTypeAliases": [],
4550
// CHECK-NEXT: "properties": [
4651
// CHECK-NEXT: {
4752
// CHECK-NEXT: "label": "init1",
4853
// CHECK-NEXT: "type": "ExtractCalls.Bar",
54+
// CHECK-NEXT: "mangledTypeName": "12ExtractCalls3BarV",
4955
// CHECK-NEXT: "isStatic": "false",
5056
// CHECK-NEXT: "isComputed": "false",
5157
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
@@ -59,6 +65,7 @@ public struct Bat {
5965
// CHECK-NEXT: {
6066
// CHECK-NEXT: "label": "init2",
6167
// CHECK-NEXT: "type": "ExtractCalls.Bat",
68+
// CHECK-NEXT: "mangledTypeName": "12ExtractCalls3BatV",
6269
// CHECK-NEXT: "isStatic": "false",
6370
// CHECK-NEXT: "isComputed": "false",
6471
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
@@ -85,6 +92,7 @@ public struct Bat {
8592
// CHECK-NEXT: {
8693
// CHECK-NEXT: "label": "init3",
8794
// CHECK-NEXT: "type": "ExtractCalls.Bat",
95+
// CHECK-NEXT: "mangledTypeName": "12ExtractCalls3BatV",
8896
// CHECK-NEXT: "isStatic": "false",
8997
// CHECK-NEXT: "isComputed": "false",
9098
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
@@ -110,6 +118,7 @@ public struct Bat {
110118
// CHECK-NEXT: {
111119
// CHECK-NEXT: "label": "func1",
112120
// CHECK-NEXT: "type": "Swift.Int",
121+
// CHECK-NEXT: "mangledTypeName": "Si",
113122
// CHECK-NEXT: "isStatic": "false",
114123
// CHECK-NEXT: "isComputed": "false",
115124
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
@@ -119,6 +128,7 @@ public struct Bat {
119128
// CHECK-NEXT: {
120129
// CHECK-NEXT: "label": "init4",
121130
// CHECK-NEXT: "type": "Swift.Optional<ExtractCalls.Bar>",
131+
// CHECK-NEXT: "mangledTypeName": "12ExtractCalls3BarVSg",
122132
// CHECK-NEXT: "isStatic": "true",
123133
// CHECK-NEXT: "isComputed": "false",
124134
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
@@ -132,6 +142,7 @@ public struct Bat {
132142
// CHECK-NEXT: {
133143
// CHECK-NEXT: "label": "ext1",
134144
// CHECK-NEXT: "type": "ExtractCalls.Foo.Boo",
145+
// CHECK-NEXT: "mangledTypeName": "12ExtractCalls3FooV3BooV",
135146
// CHECK-NEXT: "isStatic": "false",
136147
// CHECK-NEXT: "isComputed": "true",
137148
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",

0 commit comments

Comments
 (0)