@@ -33,6 +33,11 @@ extension TaskLocalMacro: PeerMacro {
33
33
return [ ]
34
34
}
35
35
36
+ guard varDecl. bindings. count == 1 else {
37
+ throw DiagnosticsError (
38
+ syntax: declaration,
39
+ message: " '@TaskLocal' property must have exactly one binding " , id: . incompatibleDecl)
40
+ }
36
41
guard let firstBinding = varDecl. bindings. first else {
37
42
throw DiagnosticsError (
38
43
syntax: declaration,
@@ -46,18 +51,18 @@ extension TaskLocalMacro: PeerMacro {
46
51
}
47
52
48
53
let type = firstBinding. typeAnnotation? . type
49
- let explicitType : String
54
+ let explicitTypeAnnotation : TypeAnnotationSyntax ?
50
55
if let type {
51
- explicitType = " : TaskLocal<\( type. trimmed) > "
56
+ explicitTypeAnnotation = TypeAnnotationSyntax ( type : TypeSyntax ( " TaskLocal< \( type. trimmed) > " ) )
52
57
} else {
53
- explicitType = " "
58
+ explicitTypeAnnotation = nil
54
59
}
55
60
56
- let initialValue : Any
61
+ let initialValue : ExprSyntax
57
62
if let initializerValue = firstBinding. initializer? . value {
58
- initialValue = initializerValue
63
+ initialValue = ExprSyntax ( initializerValue)
59
64
} else if let type, type. isOptional {
60
- initialValue = " nil "
65
+ initialValue = ExprSyntax ( NilLiteralExprSyntax ( ) )
61
66
} else {
62
67
throw DiagnosticsError (
63
68
syntax: declaration,
@@ -66,16 +71,16 @@ extension TaskLocalMacro: PeerMacro {
66
71
67
72
// If the property is global, do not prefix the synthesised decl with 'static'
68
73
let isGlobal = context. lexicalContext. isEmpty
69
- let staticKeyword : String
74
+ let staticKeyword : TokenSyntax ?
70
75
if isGlobal {
71
- staticKeyword = " "
76
+ staticKeyword = nil
72
77
} else {
73
- staticKeyword = " static "
78
+ staticKeyword = TokenSyntax . keyword ( . static, trailingTrivia : . space )
74
79
}
75
80
76
81
return [
77
82
"""
78
- \( raw : staticKeyword) let $ \( name) \( raw : explicitType ) = TaskLocal(wrappedValue: \( raw : initialValue) )
83
+ \( staticKeyword) let $ \( name) \( explicitTypeAnnotation ) = TaskLocal(wrappedValue: \( initialValue) )
79
84
"""
80
85
]
81
86
}
@@ -96,11 +101,11 @@ extension TaskLocalMacro: AccessorMacro {
96
101
try requireStaticContext ( varDecl, in: context)
97
102
98
103
guard let firstBinding = varDecl. bindings. first else {
99
- return [ ] // TODO: make error
104
+ return [ ]
100
105
}
101
106
102
107
guard let name = firstBinding. pattern. as ( IdentifierPatternSyntax . self) ? . identifier else {
103
- return [ ] // TODO: make error
108
+ return [ ]
104
109
}
105
110
106
111
return [ " get { $ \( name) .get() } " ]
@@ -142,7 +147,7 @@ private func requireStaticContext(_ decl: VariableDeclSyntax,
142
147
if diagnose {
143
148
throw DiagnosticsError (
144
149
syntax: decl,
145
- message: " '@TaskLocal' can only be applied to 'static' property " , id: . mustBeStatic)
150
+ message: " '@TaskLocal' can only be applied to 'static' property, or global variables " , id: . mustBeStatic)
146
151
}
147
152
148
153
return false
@@ -153,10 +158,19 @@ extension TypeSyntax {
153
158
// has no type information, but at least for the common case for Optional<T>
154
159
// and T? we can detect the optional.
155
160
fileprivate var isOptional : Bool {
156
- let strRepr = " \( self ) "
157
- return strRepr. last == " ? " ||
158
- strRepr. starts ( with: " Optional< " ) ||
159
- strRepr. starts ( with: " Swift.Optional< " )
161
+ switch self . as ( TypeSyntaxEnum . self) {
162
+ case . optionalType:
163
+ return true
164
+ case . identifierType( let identifierType) :
165
+ return identifierType. name. text == " Optional "
166
+ case . memberType( let memberType) :
167
+ guard let baseIdentifier = memberType. baseType. as ( IdentifierTypeSyntax . self) ,
168
+ baseIdentifier. name. text == " Swift " else {
169
+ return false
170
+ }
171
+ return memberType. name. text == " Optional "
172
+ default : return false
173
+ }
160
174
}
161
175
}
162
176
@@ -185,8 +199,8 @@ struct TaskLocalMacroDiagnostic: DiagnosticMessage {
185
199
}
186
200
187
201
extension DiagnosticsError {
188
- init < S : SyntaxProtocol > (
189
- syntax: S ,
202
+ init (
203
+ syntax: some SyntaxProtocol ,
190
204
message: String ,
191
205
domain: String = " Swift " ,
192
206
id: TaskLocalMacroDiagnostic . ID ,
0 commit comments