forked from apple/swift
/
function_builder_availability.swift
129 lines (104 loc) · 3.41 KB
/
function_builder_availability.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// RUN: %target-typecheck-verify-swift -target x86_64-apple-macosx10.50
// REQUIRES: OS=macosx
enum Either<T,U> {
case first(T)
case second(U)
}
@_functionBuilder
struct TupleBuilder {
static func buildBlock<T1>(_ t1: T1) -> (T1) {
return (t1)
}
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
return (t1, t2)
}
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3)
-> (T1, T2, T3) {
return (t1, t2, t3)
}
static func buildBlock<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4)
-> (T1, T2, T3, T4) {
return (t1, t2, t3, t4)
}
static func buildBlock<T1, T2, T3, T4, T5>(
_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5
) -> (T1, T2, T3, T4, T5) {
return (t1, t2, t3, t4, t5)
}
static func buildDo<T>(_ value: T) -> T { return value }
static func buildIf<T>(_ value: T?) -> T? { return value }
static func buildEither<T,U>(first value: T) -> Either<T,U> {
return .first(value)
}
static func buildEither<T,U>(second value: U) -> Either<T,U> {
return .second(value)
}
}
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) {
print(body(cond))
}
@available(OSX, introduced: 10.9)
func globalFuncAvailableOn10_9() -> Int { return 9 }
@available(OSX, introduced: 10.51)
func globalFuncAvailableOn10_51() -> Int { return 10 }
@available(OSX, introduced: 10.52)
struct Only10_52 { }
@available(OSX, introduced: 10.52)
func globalFuncAvailableOn10_52() -> Only10_52 { .init() }
tuplify(true) { cond in
globalFuncAvailableOn10_9()
if #available(OSX 10.51, *) {
globalFuncAvailableOn10_51()
tuplify(false) { cond2 in
if cond, #available(OSX 10.52, *) { // expected-warning{{function builder 'TupleBuilder' does not implement `buildLimitedAvailability`; this code may crash on earlier versions of the OS}}
cond2
globalFuncAvailableOn10_52()
} else {
globalFuncAvailableOn10_52() // expected-error{{'globalFuncAvailableOn10_52()' is only available in macOS 10.52 or newer}}
// expected-note@-1{{add 'if #available' version check}}
}
}
}
}
// Function builder that can perform type erasure for #available.
@_functionBuilder
struct TupleBuilderAvailability {
static func buildBlock<T1>(_ t1: T1) -> (T1) {
return (t1)
}
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
return (t1, t2)
}
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3)
-> (T1, T2, T3) {
return (t1, t2, t3)
}
static func buildBlock<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4)
-> (T1, T2, T3, T4) {
return (t1, t2, t3, t4)
}
static func buildBlock<T1, T2, T3, T4, T5>(
_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5
) -> (T1, T2, T3, T4, T5) {
return (t1, t2, t3, t4, t5)
}
static func buildDo<T>(_ value: T) -> T { return value }
static func buildIf<T>(_ value: T?) -> T? { return value }
static func buildEither<T,U>(first value: T) -> Either<T,U> {
return .first(value)
}
static func buildEither<T,U>(second value: U) -> Either<T,U> {
return .second(value)
}
static func buildLimitedAvailability<T>(_ value: T) -> Any {
return value
}
}
func tuplifyWithAvailabilityErasure<T>(_ cond: Bool, @TupleBuilderAvailability body: (Bool) -> T) {
print(body(cond))
}
tuplifyWithAvailabilityErasure(true) { cond in
if cond, #available(OSX 10.52, *) {
globalFuncAvailableOn10_52()
}
}