Skip to content

[5.10][Compile Time Constant Extraction] Extract from all macro expansions #70173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions lib/ConstExtract/ConstExtract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class NominalTypeConformanceCollector : public ASTWalker {
for (auto &Protocol : NTD->getAllProtocols())
if (Protocols.count(Protocol->getName().str().str()) != 0)
ConformanceTypeDecls.push_back(NTD);
// Visit peers expanded from macros
D->visitAuxiliaryDecls([&](Decl *decl) { decl->walk(*this); },
/*visitFreestandingExpanded=*/false);
return Action::Continue();
}
};
Expand Down Expand Up @@ -473,7 +476,7 @@ ConstantValueInfoRequest::evaluate(Evaluator &Evaluator,
Properties.push_back(extractTypePropertyInfo(Property));
}

for (auto Member : Decl->getMembers()) {
for (auto Member : Decl->getAllMembers()) {
auto *VD = dyn_cast<VarDecl>(Member);
// Ignore plain stored properties collected above,
// instead gather up remaining static and computed properties.
Expand All @@ -483,7 +486,7 @@ ConstantValueInfoRequest::evaluate(Evaluator &Evaluator,
}

for (auto Extension: Decl->getExtensions()) {
for (auto Member : Extension->getMembers()) {
for (auto Member : Extension->getAllMembers()) {
if (auto *VD = dyn_cast<VarDecl>(Member)) {
Properties.push_back(extractTypePropertyInfo(VD));
}
Expand Down
133 changes: 133 additions & 0 deletions test/ConstExtraction/ExtractFromMacroExpansion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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 { }

@freestanding(declaration, names: named(MacroAddedStruct))
macro AddMacroAddedStruct() = #externalMacro(module: "MacroDefinition", type: "AddStructDeclMacro")

@freestanding(declaration, names: named(macroAddedVar))
macro AddMacroAddedVar() = #externalMacro(module: "MacroDefinition", type: "AddVarDeclMacro")

@attached(extension, conformances: MyProto, names: prefixed(_extension_))
macro AddExtension() = #externalMacro(module: "MacroDefinition", type: "AddExtensionMacro")

@attached(peer, names: prefixed(_peer_))
macro AddPeerVar() = #externalMacro(module: "MacroDefinition", type: "AddPeerVarMacro")

@attached(member, names: prefixed(_member_))
macro AddMemberVar() = #externalMacro(module: "MacroDefinition", type: "AddMemberMacro")

@attached(memberAttribute)
macro AddMacro() = #externalMacro(module: "MacroDefinition", type: "AddMemberAttributeMacro")

@attached(accessor)
macro AddGetter() = #externalMacro(module: "MacroDefinition", type: "GetterMacro")

@attached(peer, names: prefixed(_Peer_))
macro AddPeerStruct() = #externalMacro(module: "MacroDefinition", type: "AddPeerStructMacro")


#AddMacroAddedStruct

@AddExtension
@AddMemberVar
@AddPeerStruct
struct MyStruct {
#AddMacroAddedVar

@AddPeerVar
struct Inner { }
}

@AddMacro
extension MyStruct {
func fromFunc() { }

@AddGetter
var fromVar = 123
}

// CHECK: "typeName": "ExtractFromMacroExpansion.MacroAddedStruct",
// CHECK: "properties": [
// CHECK: "label": "macroAddedStructMember",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "1"

// CHECK: "label": "_extension_MacroAddedStruct",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "3"


// CHECK: "typeName": "ExtractFromMacroExpansion.MyStruct",
// CHECK: "properties": [
// CHECK: "label": "macroAddedVar",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "2"

// CHECK: "label": "_peer_Inner",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "4"

// CHECK: "label": "_member_MyStruct",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "5"

// CHECK: "label": "_peer_fromFunc",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "4"

// CHECK: "label": "_peer_fromVar",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "4"

// CHECK: "label": "fromVar",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "123"

// CHECK: "label": "_extension_MyStruct",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "3"


// CHECK: "typeName": "ExtractFromMacroExpansion._Peer_MyStruct",
// CHECK: "properties": [
// CHECK: "label": "peerMacroVar",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "7"

// CHECK: "label": "macroAddedVar",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "2"

// CHECK: "label": "_peer_peerMacroVar",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "4"

// CHECK: "label": "_member__Peer_MyStruct",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "5"

// CHECK: "label": "_extension__Peer_MyStruct",
// CHECK: "type": "Swift.Int",
// CHECK: "valueKind": "RawLiteral",
// CHECK: "value": "3"
156 changes: 156 additions & 0 deletions test/ConstExtraction/Inputs/Macros.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import SwiftDiagnostics
import SwiftOperators
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct AddStructDeclMacro: DeclarationMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
return [
"""
@AddExtension
struct MacroAddedStruct {
var macroAddedStructMember = 1
}
"""
]
}
}

public struct AddVarDeclMacro: DeclarationMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
return [
"""
static let macroAddedVar = 2
"""
]
}
}

public struct AddExtensionMacro: 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] {
let typeName = declaration.declGroupName
return protocols.map {
("extension \(typeName): \($0) { }" as DeclSyntax)
.cast(ExtensionDeclSyntax.self)
} + [
("""
extension \(typeName) {
static let _extension_\(typeName) = 3
}
""" as DeclSyntax).cast(ExtensionDeclSyntax.self)
]
}
}

public struct AddPeerVarMacro: PeerMacro {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let name = declaration.declName
return [
"""
static var _peer_\(name) = 4
"""
]
}
}

public struct AddMemberMacro: MemberMacro {
public static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let typeName = declaration.declGroupName
return [
"""
static let _member_\(typeName) = 5
"""
]
}
}

public struct AddMemberAttributeMacro: MemberAttributeMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingAttributesFor member: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [AttributeSyntax] {
if member.isProtocol(DeclGroupSyntax.self) {
return ["@AddExtension"]
}
return ["@AddPeerVar"]
}
}

public struct GetterMacro: AccessorMacro {
public static func expansion(
of node: AttributeSyntax,
providingAccessorsOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [AccessorDeclSyntax] {
return ["get { 6 }"]
}
}

public struct AddPeerStructMacro: PeerMacro {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let name = declaration.declName
return [
"""
@AddExtension
@AddMemberVar
struct _Peer_\(name) {
#AddMacroAddedVar

@AddPeerVar
var peerMacroVar = 7
}
"""
]
}
}

extension DeclGroupSyntax {
var declGroupName: TokenSyntax {
if let structDecl = self.as(StructDeclSyntax.self) {
return structDecl.name.trimmed
}
fatalError("Not implemented")
}
}

extension DeclSyntaxProtocol {
var declName: TokenSyntax {
if let varDecl = self.as(VariableDeclSyntax.self),
let first = varDecl.bindings.first,
let pattern = first.pattern.as(IdentifierPatternSyntax.self) {
return pattern.identifier.trimmed
} else if let funcDecl = self.as(FunctionDeclSyntax.self) {
return funcDecl.name.trimmed
} else if let structDecl = self.as(StructDeclSyntax.self) {
return structDecl.name.trimmed
}
fatalError("Not implemented")
}
}