Skip to content

Commit 5bd94d6

Browse files
committed
[Macros] Adapt to macro API changes and switch more testing to use it.
The API provided by macro evaluation has changed a bit. Adapt ASTGen to the new API, and use this as an opportunity to start moving more tests to using the shared libraries built into the toolchain.
1 parent d59b50f commit 5bd94d6

File tree

5 files changed

+87
-63
lines changed

5 files changed

+87
-63
lines changed

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import SwiftParser
22
import SwiftSyntax
3-
import _SwiftSyntaxMacros
3+
@_spi(Testing) import _SwiftSyntaxMacros
44

55
extension SyntaxProtocol {
66
func token(at position: AbsolutePosition) -> TokenSyntax? {
@@ -82,6 +82,18 @@ private func allocateUTF8String(
8282
}
8383
}
8484

85+
extension String {
86+
/// Drop everything up to and including the last '/' from the string.
87+
fileprivate func withoutPath() -> String {
88+
// Only keep everything after the last slash.
89+
if let lastSlash = lastIndex(of: "/") {
90+
return String(self[index(after: lastSlash)...])
91+
}
92+
93+
return self
94+
}
95+
}
96+
8597
@_cdecl("swift_ASTGen_evaluateMacro")
8698
@usableFromInline
8799
func evaluateMacro(
@@ -124,12 +136,9 @@ func evaluateMacro(
124136
return -1
125137
}
126138

127-
let converter = SourceLocationConverter(
128-
file: sourceFile.pointee.fileName, tree: sf
129-
)
130-
let context = MacroEvaluationContext(
139+
var context = MacroExpansionContext(
131140
moduleName: sourceFile.pointee.moduleName,
132-
sourceLocationConverter: converter
141+
fileName: sourceFile.pointee.fileName.withoutPath()
133142
)
134143

135144
let evaluatedSyntax: ExprSyntax = macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
@@ -138,11 +147,11 @@ func evaluateMacro(
138147
return ExprSyntax(parentExpansion)
139148
}
140149

141-
let expansion = exprMacro.apply(parentExpansion, in: context)
142-
// FIXME: Produce diagnostics.
143-
return expansion.rewritten
150+
return exprMacro.expand(parentExpansion, in: &context)
144151
}
145152

153+
// FIXME: Emit diagnostics accumulated in the
154+
146155
var evaluatedSyntaxStr = evaluatedSyntax.withoutTrivia().description
147156
evaluatedSyntaxStr.withUTF8 { utf8 in
148157
let evaluatedResultPtr = UnsafeMutablePointer<UInt8>.allocate(capacity: utf8.count + 1)
@@ -158,16 +167,3 @@ func evaluateMacro(
158167
return 0
159168
}
160169
}
161-
162-
// Makes sure that the type metadata for these macros can be found.
163-
public var allBuiltinMacros: [Any.Type] = [
164-
ColorLiteralMacro.self,
165-
ColumnMacro.self,
166-
FileIDMacro.self,
167-
FileLiteralMacro.self,
168-
FilePathMacro.self,
169-
FunctionMacro.self,
170-
ImageLiteralMacro.self,
171-
LineMacro.self,
172-
StringifyMacro.self
173-
]

lib/Sema/TypeCheckMacros.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,19 @@ MacroDefinition MacroDefinitionRequest::evaluate(
101101
ASTContext &ctx = macro->getASTContext();
102102

103103
#if SWIFT_SWIFT_PARSER
104-
105104
/// Look for the type metadata given the external module and type names.
106105
auto macroMetatype = lookupMacroTypeMetadataByExternalName(
107106
ctx, macro->externalModuleName.str(),
108107
macro->externalMacroTypeName.str());
109108
if (macroMetatype) {
110109
// Check whether the macro metatype can be handled as a compiler plugin.
111-
// We look here first, because compiler plugins are meant to be resilient.
112110
if (auto plugin = CompilerPlugin::fromMetatype(macroMetatype, ctx)) {
113111
// FIXME: Handle other kinds of macros.
114112
return MacroDefinition::forCompilerPlugin(
115113
MacroDefinition::Expression, plugin);
116114
}
117115

118-
// Otherwise, check whether the macro metatype can be handled as a builtin.
116+
// Check whether the macro metatype can be handled as a builtin.
119117
if (auto builtin = swift_ASTGen_resolveMacroType(macroMetatype)) {
120118
// Make sure we clean up after the macro.
121119
ctx.addCleanup([builtin]() {

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,55 @@ import SwiftSyntax
22
import SwiftSyntaxBuilder
33
import _SwiftSyntaxMacros
44

5-
public struct FileIDMacro: ExpressionMacro {
6-
public static func apply(
7-
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
8-
) -> MacroResult<ExprSyntax> {
9-
var fileName = context.sourceLocationConverter.location(
10-
for: .init(utf8Offset: 0)
11-
).file ?? "<unknown file>"
5+
/// Replace the label of the first element in the tuple with the given
6+
/// new label.
7+
private func replaceFirstLabel(
8+
of tuple: TupleExprElementListSyntax, with newLabel: String
9+
) -> TupleExprElementListSyntax{
10+
guard let firstElement = tuple.first else {
11+
return tuple
12+
}
13+
14+
return tuple.replacing(
15+
childAt: 0, with: firstElement.withLabel(.identifier(newLabel)))
16+
}
1217

13-
// Only keep everything after the last slash.
14-
if let lastSlash = fileName.lastIndex(of: "/") {
15-
fileName = String(fileName[fileName.index(after: lastSlash)...])
18+
public struct ColorLiteralMacro: ExpressionMacro {
19+
public static func expand(
20+
_ macro: MacroExpansionExprSyntax, in context: inout MacroExpansionContext
21+
) -> ExprSyntax {
22+
let argList = replaceFirstLabel(
23+
of: macro.argumentList, with: "_colorLiteralRed"
24+
)
25+
let initSyntax: ExprSyntax = ".init(\(argList))"
26+
if let leadingTrivia = macro.leadingTrivia {
27+
return initSyntax.withLeadingTrivia(leadingTrivia)
1628
}
29+
return initSyntax
30+
}
31+
}
1732

18-
let fileLiteral: ExprSyntax = #""\#(context.moduleName)/\#(fileName)""#
33+
public struct FileIDMacro: ExpressionMacro {
34+
public static func expand(
35+
_ macro: MacroExpansionExprSyntax, in context: inout MacroExpansionContext
36+
) -> ExprSyntax {
37+
let fileLiteral: ExprSyntax = #""\#(context.moduleName)/\#(context.fileName)""#
1938
if let leadingTrivia = macro.leadingTrivia {
20-
return MacroResult(fileLiteral.withLeadingTrivia(leadingTrivia))
39+
return fileLiteral.withLeadingTrivia(leadingTrivia)
40+
}
41+
return fileLiteral
42+
}
43+
}
44+
45+
public struct StringifyMacro: ExpressionMacro {
46+
public static func expand(
47+
_ macro: MacroExpansionExprSyntax, in context: inout MacroExpansionContext
48+
) -> ExprSyntax {
49+
guard let argument = macro.argumentList.first?.expression else {
50+
// FIXME: Create a diagnostic for the missing argument?
51+
return ExprSyntax(macro)
2152
}
22-
return MacroResult(fileLiteral)
53+
54+
return "(\(argument), \(StringLiteralExprSyntax(content: argument.description)))"
2355
}
2456
}

test/Macros/macro_external_exec.swift

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -emit-library-path=%t/%target-library-name(MacroDefinition) -working-directory=%t -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift
2+
// RUN: %target-build-swift -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
3+
// RUNx: %target-swift-frontend -dump-ast -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir %s -module-name MacroUser 2>&1 | %FileCheck --check-prefix CHECK-AST %s
34
// RUN: %target-build-swift -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -L %swift-host-lib-dir %s -o %t/main -module-name MacroUser
45
// RUN: %target-run %t/main | %FileCheck %s
56
// REQUIRES: executable_test
@@ -8,10 +9,29 @@
89
// REQUIRES: OS=macosx
910

1011
macro customFileID: String = MacroDefinition.FileIDMacro
12+
macro stringify<T>(_ value: T) -> (T, String) = MacroDefinition.StringifyMacro
1113

12-
func testFunc(a: Int, b: Int) {
14+
func testFileID(a: Int, b: Int) {
1315
// CHECK: MacroUser/macro_external_exec.swift
1416
print("Result is \(#customFileID)")
1517
}
1618
17-
testFunc(a: 1, b: 2)
19+
testFileID(a: 1, b: 2)
20+
21+
func testStringify(a: Int, b: Int) {
22+
let s = #stringify(a + b)
23+
24+
// CHECK-AST: macro_expansion_expr type='(Int, String)'{{.*}}name=stringify
25+
// CHECK-AST-NEXT: argument_list
26+
// CHECK-AST: tuple_expr type='(Int, String)' location=Macro expansion of #stringify
27+
28+
let (b, s2) = #stringify({ () -> Bool in return true })
29+
// CHECK-AST: macro_expansion_expr type='(() -> Bool, String)'{{.*}}name=stringify
30+
// CHECK-AST-NEXT: argument_list
31+
// CHECK-AST: tuple_expr type='(() -> Bool, String)' location=Macro expansion of #stringify
32+
33+
let (b2, s3) = #stringify<Double>(1 + 2)
34+
// CHECK-AST: macro_expansion_expr type='(Double, String)'{{.*}}name=stringify
35+
// CHECK-AST-NEXT: argument_list
36+
// CHECK-AST: tuple_expr type='(Double, String)' location=Macro expansion of #stringify
37+
}

test/Macros/macros.swift

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)