mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Preamble macros introduce code at the beginning of a function body. Allow them to introduce declarations as well, so long as the macro declaration properly declares the names it introduces. This allows all sorts of exciting macros that introduce (e.g.) new local variables that one can use.
111 lines
3.1 KiB
Swift
111 lines
3.1 KiB
Swift
// REQUIRES: swift_swift_parser, executable_test, asserts, concurrency
|
|
// RUN: %empty-directory(%t)
|
|
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath -swift-version 5
|
|
|
|
// Diagnostics testing
|
|
// RUN: %target-typecheck-verify-swift -swift-version 5 -enable-experimental-feature BodyMacros -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS
|
|
|
|
// Execution testing
|
|
// RUN: %target-build-swift -swift-version 5 -g -enable-experimental-feature BodyMacros -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser
|
|
// RUN: %target-codesign %t/main
|
|
// RUN: %target-run %t/main | %FileCheck %s
|
|
|
|
@attached(body)
|
|
macro Remote() = #externalMacro(module: "MacroDefinition", type: "RemoteBodyMacro")
|
|
|
|
@attached(preamble)
|
|
macro Traced() = #externalMacro(module: "MacroDefinition", type: "TracedPreambleMacro")
|
|
|
|
@attached(preamble, names: named(logger))
|
|
macro Logged() = #externalMacro(module: "MacroDefinition", type: "LoggerMacro")
|
|
|
|
protocol ConjureRemoteValue {
|
|
static func conjureValue() -> Self
|
|
}
|
|
|
|
extension String: ConjureRemoteValue {
|
|
static func conjureValue() -> String { "" }
|
|
}
|
|
|
|
struct Logger {
|
|
func log(entering function: String) {
|
|
print("Logger entering \(function)")
|
|
}
|
|
|
|
func log(_ message: String) {
|
|
print("--- \(message)")
|
|
}
|
|
|
|
func log(exiting function: String) {
|
|
print("Logger exiting \(function)")
|
|
}
|
|
}
|
|
|
|
func log(_ message: String) {
|
|
print(message)
|
|
}
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func remoteCall<Result: ConjureRemoteValue>(function: String, arguments: [String: Any]) async throws -> Result {
|
|
let printedArgs = arguments.keys.sorted().map { key in
|
|
"\(key): \(arguments[key]!)"
|
|
}.joined(separator: ", ")
|
|
print("Remote call \(function)(\(printedArgs))")
|
|
return Result.conjureValue()
|
|
}
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
@Remote
|
|
func f(a: Int, b: String) async throws -> String
|
|
|
|
@Traced
|
|
func doubleTheValue(value: Int) -> Int {
|
|
return value * 2
|
|
}
|
|
|
|
@Logged
|
|
func useLogger() {
|
|
let x = 1
|
|
logger.log("use it")
|
|
print(x)
|
|
}
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
@Remote
|
|
@Traced
|
|
@Logged
|
|
func g(a: Int, b: String) async throws -> String {
|
|
doesNotTypeCheck()
|
|
}
|
|
|
|
#if compiler(>=5.11) && TEST_DIAGNOSTICS
|
|
@available(SwiftStdlib 5.1, *)
|
|
@Remote
|
|
func h(a: Int, b: String) async throws -> String {
|
|
does not
|
|
// expected-error@-1{{consecutive statements on a line must be separated by ';'}}
|
|
parse
|
|
}
|
|
#endif
|
|
|
|
// CHECK: Entering doubleTheValue(value: 7)
|
|
// CHECK-NEXT: Exiting doubleTheValue(value:)
|
|
_ = doubleTheValue(value: 7)
|
|
|
|
if #available(SwiftStdlib 5.1, *) {
|
|
// CHECK: Remote call f(a: 5, b: Hello)
|
|
print(try await f(a: 5, b: "Hello"))
|
|
|
|
// CHECK: Entering g(a: 5, b: World)
|
|
// CHECK: Logger entering g(a: 5, b: World)
|
|
// CHECK: Remote call g(a: 5, b: World)
|
|
// CHECK: Logger exiting g(a:b:)
|
|
// CHECK: Exiting g(a:b:)
|
|
print(try await g(a: 5, b: "World"))
|
|
}
|
|
|
|
// CHECK: Logger entering useLogger()
|
|
// CHECK: --- use it
|
|
// CHECK: Logger exiting useLogger()
|
|
useLogger()
|