[Compile Time Constant Extraction] Query nominal type conformances to get at the protocols, instead of getAllProtocols.

As it stands, for extension macros which add protocol conformances, the list of protocols specified on the macro's 'conformances:' parameter gets added in its entirety to the list of a nominal type's protocols in 'ConformanceLookupTable::addMacroGeneratedProtocols'. Whereas the macro itself, may only add *some* of the specified conformances. This means that `getAllProtocols` may contain a super-set of protocols captured in `getAllConformances`, some of which may not actually be generated by the macro.

This change narrowly fixes ConstExtract to query actual generated conformances. Though, potentially we should make 'ConformanceLookupTable::addMacroGeneratedProtocols' behave in a way that reflects the protocols the macro actually adds the conformances to, instead of the ones it may add conformances to.

Resolves rdar://130316531
This commit is contained in:
Artem Chikin
2024-06-25 12:29:29 -07:00
parent fbe7d89311
commit f5f0c0043d
3 changed files with 49 additions and 3 deletions

View File

@@ -984,12 +984,13 @@ void writeProperties(llvm::json::OStream &JSON,
void writeConformances(llvm::json::OStream &JSON,
const NominalTypeDecl &NomTypeDecl) {
JSON.attributeArray("conformances", [&] {
for (auto *Protocol : NomTypeDecl.getAllProtocols()) {
for (auto *Conformance : NomTypeDecl.getAllConformances()) {
auto Proto = Conformance->getProtocol();
// FIXME(noncopyable_generics): Should these be included?
if (Protocol->getInvertibleProtocolKind())
if (Proto->getInvertibleProtocolKind())
continue;
JSON.value(toFullyQualifiedProtocolNameString(*Protocol));
JSON.value(toFullyQualifiedProtocolNameString(*Proto));
}
});
}

View File

@@ -0,0 +1,28 @@
// REQUIRES: swift_swift_parser
// RUN: %empty-directory(%t)
// RUN: echo "[MyProto]" > %t/protocols.json
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/Macros.swift -g -no-toolchain-stdlib-rpath
// RUN: %target-swift-frontend -typecheck -emit-const-values-path %t/ExtractFromMacroExpansion.swiftconstvalues -const-gather-protocols-file %t/protocols.json -primary-file %s -load-plugin-library %t/%target-library-name(MacroDefinition)
// RUN: cat %t/ExtractFromMacroExpansion.swiftconstvalues 2>&1 | %FileCheck %s
protocol MyProto { }
protocol MyExtraProto { }
@attached(extension, conformances: MyProto, MyExtraProto)
macro specificExtensionMacro() = #externalMacro(module: "MacroDefinition", type: "AddSpecificExtensionMacro")
@specificExtensionMacro
struct MyStruct {
struct Inner { }
}
// CHECK: "typeName": "ExtractMacroExpandedConformances.MyStruct",
// CHECK: "mangledTypeName": "32ExtractMacroExpandedConformances8MyStructV",
// CHECK: "kind": "struct",
// CHECK: "conformances": [
// CHECK-DAG: "Swift.Sendable",
// CHECK-DAG: "Swift.BitwiseCopyable",
// CHECK-DAG: "ExtractMacroExpandedConformances.MyProto"
// CHECK-NOT: "ExtractMacroExpandedConformances.MyExtraProto"

View File

@@ -61,6 +61,23 @@ public struct AddExtensionMacro: ExtensionMacro {
}
}
public struct AddSpecificExtensionMacro: ExtensionMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
var extensions = [ExtensionDeclSyntax]()
let protocolNames = Set(protocols.compactMap { $0.as(IdentifierTypeSyntax.self)?.name.text })
if protocolNames.contains("MyProto") {
extensions.append(try ExtensionDeclSyntax("extension \(type.trimmed): MyProto") { })
}
return extensions
}
}
public struct AddPeerVarMacro: PeerMacro {
public static func expansion(
of node: AttributeSyntax,