Files
swift-mirror/test/Macros/macro_expand_peers.swift
2025-09-18 16:41:07 -07:00

346 lines
10 KiB
Swift

// REQUIRES: swift_swift_parser, executable_test
// For _Concurrency.
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
// RUN: %empty-directory(%t)
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -parse-as-library -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
// RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -parse-as-library -disable-availability-checking -DTEST_DIAGNOSTICS
// Check with the imported macro library vs. the local declaration of the macro.
// RUN: %target-swift-frontend -swift-version 5 -emit-module -o %t/macro_library.swiftmodule %S/Inputs/macro_library.swift -module-name macro_library -load-plugin-library %t/%target-library-name(MacroDefinition)
// RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -parse-as-library -disable-availability-checking -DIMPORT_MACRO_LIBRARY -I %t -DTEST_DIAGNOSTICS
// RUN: %target-swift-frontend -swift-version 5 -typecheck -load-plugin-library %t/%target-library-name(MacroDefinition) -parse-as-library %s -disable-availability-checking -dump-macro-expansions > %t/expansions-dump.txt 2>&1
// RUN: %FileCheck -check-prefix=CHECK-DUMP %s < %t/expansions-dump.txt
// RUN: %target-build-swift -swift-version 5 -Xfrontend -disable-availability-checking -load-plugin-library %t/%target-library-name(MacroDefinition) -parse-as-library %s -o %t/main -module-name MacroUser -g
// RUN: %target-codesign %t/main
// RUN: %target-run %t/main | %FileCheck %s -check-prefix=CHECK-EXEC
// Emit module while skipping function bodies
// RUN: %target-swift-frontend -swift-version 5 -emit-module -load-plugin-library %t/%target-library-name(MacroDefinition) -parse-as-library %s -disable-availability-checking -o %t/macro_expand_peers.swiftmodule -experimental-skip-non-inlinable-function-bodies-without-types
#if IMPORT_MACRO_LIBRARY
import macro_library
#else
@attached(peer, names: overloaded)
macro addCompletionHandler() = #externalMacro(module: "MacroDefinition", type: "AddCompletionHandler")
@attached(peer, names: suffixed(Builder))
macro AddClassReferencingSelf() = #externalMacro(module: "MacroDefinition", type: "AddClassReferencingSelfMacro")
@attached(peer, names: named(value))
macro declareVarValuePeer() = #externalMacro(module: "MacroDefinition", type: "VarValueMacro")
#endif
@attached(peer, names: arbitrary)
macro addCompletionHandlerArbitrarily(_: Int) = #externalMacro(module: "MacroDefinition", type: "AddCompletionHandler")
struct S {
#if IMPORT_MACRO_LIBRARY
@macro_library.addCompletionHandler // test module qualified macro lookup
func f(a: Int, for b: String, _ value: Double) async -> String {
return b
}
#else
@addCompletionHandler
func f(a: Int, for b: String, _ value: Double) async -> String {
return b
}
#endif
// CHECK-DUMP: @__swiftmacro_18macro_expand_peers1SV1f20addCompletionHandlerfMp_.swift
// CHECK-DUMP: func f(a: Int, for b: String, _ value: Double, completionHandler: @escaping (String) -> Void) {
// CHECK-DUMP: Task {
// CHECK-DUMP: completionHandler(await f(a: a, for: b, value))
// CHECK-DUMP: }
// CHECK-DUMP: }
func useOverload(_ body: @escaping (String) -> Void) {
self.f(a: 1, for: "hahaha local", 2.0) {
body($0)
}
}
}
extension S {
@addCompletionHandler
func g(a: Int, for b: String, _ value: Double) async -> String {
return b
}
// CHECK-DUMP: @__swiftmacro_18macro_expand_peers1SV1g20addCompletionHandlerfMp_.swift
// CHECK-DUMP: func g(a: Int, for b: String, _ value: Double, completionHandler: @escaping (String) -> Void) {
// CHECK-DUMP: Task {
// CHECK-DUMP: completionHandler(await g(a: a, for: b, value))
// CHECK-DUMP: }
// CHECK-DUMP: }
}
func useCompletionHandlerG(s: S, _ body: @escaping (String) -> Void) {
s.g(a: 1, for: "hahaha local", 2.0) {
body($0)
}
}
class C {
@addCompletionHandler
func f(a: Int, for b: String, _ value: Double) async -> String {
return b
}
}
@addCompletionHandler
func f(a: Int, for b: String, _ value: Double) async -> String {
return b
}
func useOverload(_ body: @escaping (String) -> Void) {
f(a: 1, for: "hahaha global", 2.0) {
body($0)
}
}
@attached(peer)
macro wrapInType() = #externalMacro(module: "MacroDefinition", type: "WrapInType")
@wrapInType
func global(a: Int, b: String) {
print(a, b)
}
// CHECK-DUMP: @__swiftmacro_18macro_expand_peers6global10wrapInTypefMp_.swift
// CHECK-DUMP: struct $s18macro_expand_peers6global10wrapInTypefMp_6globalfMu0_ {
// CHECK-DUMP: func $s18macro_expand_peers6global10wrapInTypefMp_6globalfMu_(a: Int, b: String) {
// CHECK-DUMP: global(a: a, b: b)
// CHECK-DUMP: }
// CHECK-DUMP: }
@main
struct Main {
static func main() async {
let result1 = await withCheckedContinuation { cont in
S().useOverload {
cont.resume(returning: $0)
}
}
print(result1)
// CHECK-EXEC: hahaha local
let result2 = await withCheckedContinuation { cont in
useOverload {
cont.resume(returning: $0)
}
}
print(result2)
// CHECK-EXEC: hahaha global
// CHECK-EXEC: MyWrapperThingy<Swift.Int>(storage: 5)
print(S3(x: 5))
}
}
@AddClassReferencingSelf
protocol MyProto { }
// Reference cycles amongst arbitrary peer macros and macro arguments.
let x = 10
let y = 10
struct S2 {
@addCompletionHandlerArbitrarily(x)
func f(a: Int, for b: String, _ value: Double) async -> String {
return b
}
@addCompletionHandlerArbitrarily(y)
func g(a: Int, for b: String, _ value: Double) async -> String {
return b
}
#if TEST_DIAGNOSTICS
// expected-error@+1 {{cannot find 'nonexistent' in scope}}
@addCompletionHandlerArbitrarily(nonexistent)
func h(a: Int, for b: String, _ value: Double) async -> String {
return b
}
#endif
}
#if TEST_DIAGNOSTICS
// Peer macros cannot introduce arbitrary names at global scope
//expected-error@+1 {{'peer' macros are not allowed to introduce arbitrary names at global scope}}
@addCompletionHandlerArbitrarily(x)
func h(a: Int, for b: String, _ value: Double) async -> String {
return b
}
#endif
// Stored properties generated by a peer macro
@attached(accessor)
@attached(peer, names: prefixed(_))
macro myPropertyWrapper() =
#externalMacro(module: "MacroDefinition", type: "PropertyWrapperMacro")
struct MyWrapperThingy<T> {
var storage: T
var wrappedValue: T {
get {
print("Getting value \(storage)")
return storage
}
set {
print("Setting value \(newValue)")
storage = newValue
}
}
}
struct S3 {
@myPropertyWrapper
var x: Int = 0
init(x: Int) {
self._x = MyWrapperThingy(storage: x)
}
}
@declareVarValuePeer
struct Date {
@declareVarValuePeer
func foo() {}
}
func testVarPeer() {
_ = value
_ = Date().value
}
#if TEST_DIAGNOSTICS
// Macros cannot be attached to function parameters
// expected-error@+1{{'peer' macro cannot be attached to parameter ('x')}}
func test(@declareVarValuePeer x: Int) {}
#endif
// Stored properties added via peer macros.
@attached(peer, names: named(_foo))
macro AddPeerStoredProperty() =
#externalMacro(module: "MacroDefinition", type: "AddPeerStoredPropertyMacro")
struct SomeStructWithPeerProperties {
@AddPeerStoredProperty
var foo: String = "hello"
}
func testStructWithPeers() {
let x = SomeStructWithPeerProperties()
print(x)
}
#if TEST_DIAGNOSTICS
@available(*, deprecated, message: "This macro is deprecated.")
@attached(peer, names: overloaded)
macro deprecatedAddCompletionHandler() = #externalMacro(module: "MacroDefinition", type: "AddCompletionHandler")
// expected-warning@+1{{'deprecatedAddCompletionHandler()' is deprecated: This macro is deprecated.}}
@deprecatedAddCompletionHandler
func fDeprecated(a: Int, for b: String, _ value: Double) async -> String {
return b
}
#endif
protocol MyType {
associatedtype Value
associatedtype Entity
}
@attached(peer, names: named(bar))
macro Wrapper<Value>(
get: (Value.Entity) async throws -> Value.Value
) = #externalMacro(module: "MacroDefinition", type: "WrapperMacro")
where Value: MyType
@attached(peer)
macro _AddPeer() = #externalMacro(module: "MacroDefinition", type: "WrapperMacro")
@attached(memberAttribute)
public macro AddMemberPeers() = #externalMacro(module: "MacroDefinition", type: "AddMemberPeersMacro")
struct Thing: MyType {
typealias Entity = [Int]
typealias Value = Int
}
@AddMemberPeers
struct Test {
@Wrapper<Thing>(
get: { p1 in
p1.count // Error: Cannot find 'p1' in scope
}
)
var doesNotWork: Thing
}
// Ensure that we don't crash when using closures within attached macros.
struct Trait {
init(_: () -> Void) {}
}
@attached(peer) macro trait(_ trait: Trait) = #externalMacro(module: "MacroDefinition", type: "EmptyPeerMacro")
@trait(Trait {})
func closureInPeerMacroCrash() {}
@trait(Trait {})
@trait(Trait {})
@trait(Trait {})
func closuresInPeerMacroCrash() {}
@trait(Trait {})
@trait(Trait {})
@trait(Trait {})
var closuresInPeerMacroOnVariableCrash: Int = 0
// Test that macros can't be used in @abi
#if swift(>=5.3) && TEST_DIAGNOSTICS
struct ABIAttrWithAttachedMacro {
// expected-error@+1 {{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}}
@abi(@addCompletionHandler func fn1() async)
@addCompletionHandler func fn1() async {}
/*
expected-expansion@-2:44{{
expected-error@2:8{{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}}
expected-error@2:35{{invalid redeclaration of 'fn1()'}}
expected-error@4:23{{argument passed to call that takes no arguments}}
}}
expected-note@-7 3{{in expansion of macro 'addCompletionHandler' on instance method 'fn1()' here}}
expected-note@-9 {{'fn1()' previously declared here}}
*/
// expected-error@+1 {{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}}
@abi(@addCompletionHandler func fn2() async)
func fn2() async {}
@abi(func fn3() async)
@addCompletionHandler func fn3() async {}
/*
expected-expansion@-2:44{{
expected-error@1:11{{invalid redeclaration of 'fn3()'}}
expected-error@3:23{{argument passed to call that takes no arguments}}
}}
expected-note@-6 2{{in expansion of macro 'addCompletionHandler' on instance method 'fn3()' here}}
expected-note@-8 {{'fn3()' previously declared here}}
*/
}
#endif