@@ -33,6 +33,11 @@ extension TaskLocalMacro: PeerMacro {
3333 return [ ]
3434 }
3535
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+ }
3641 guard let firstBinding = varDecl. bindings. first else {
3742 throw DiagnosticsError (
3843 syntax: declaration,
@@ -46,18 +51,18 @@ extension TaskLocalMacro: PeerMacro {
4651 }
4752
4853 let type = firstBinding. typeAnnotation? . type
49- let explicitType : String
54+ let explicitTypeAnnotation : TypeAnnotationSyntax ?
5055 if let type {
51- explicitType = " : TaskLocal<\( type. trimmed) > "
56+ explicitTypeAnnotation = TypeAnnotationSyntax ( type : TypeSyntax ( " TaskLocal< \( type. trimmed) > " ) )
5257 } else {
53- explicitType = " "
58+ explicitTypeAnnotation = nil
5459 }
5560
56- let initialValue : Any
61+ let initialValue : ExprSyntax
5762 if let initializerValue = firstBinding. initializer? . value {
58- initialValue = initializerValue
63+ initialValue = ExprSyntax ( initializerValue)
5964 } else if let type, type. isOptional {
60- initialValue = " nil "
65+ initialValue = ExprSyntax ( NilLiteralExprSyntax ( ) )
6166 } else {
6267 throw DiagnosticsError (
6368 syntax: declaration,
@@ -66,16 +71,16 @@ extension TaskLocalMacro: PeerMacro {
6671
6772 // If the property is global, do not prefix the synthesised decl with 'static'
6873 let isGlobal = context. lexicalContext. isEmpty
69- let staticKeyword : String
74+ let staticKeyword : TokenSyntax ?
7075 if isGlobal {
71- staticKeyword = " "
76+ staticKeyword = nil
7277 } else {
73- staticKeyword = " static "
78+ staticKeyword = TokenSyntax . keyword ( . static, trailingTrivia : . space )
7479 }
7580
7681 return [
7782 """
78- \( raw : staticKeyword) let $ \( name) \( raw : explicitType ) = TaskLocal(wrappedValue: \( raw : initialValue) )
83+ \( staticKeyword) let $ \( name) \( explicitTypeAnnotation ) = TaskLocal(wrappedValue: \( initialValue) )
7984 """
8085 ]
8186 }
@@ -96,11 +101,11 @@ extension TaskLocalMacro: AccessorMacro {
96101 try requireStaticContext ( varDecl, in: context)
97102
98103 guard let firstBinding = varDecl. bindings. first else {
99- return [ ] // TODO: make error
104+ return [ ]
100105 }
101106
102107 guard let name = firstBinding. pattern. as ( IdentifierPatternSyntax . self) ? . identifier else {
103- return [ ] // TODO: make error
108+ return [ ]
104109 }
105110
106111 return [ " get { $ \( name) .get() } " ]
@@ -142,7 +147,7 @@ private func requireStaticContext(_ decl: VariableDeclSyntax,
142147 if diagnose {
143148 throw DiagnosticsError (
144149 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)
146151 }
147152
148153 return false
@@ -153,10 +158,19 @@ extension TypeSyntax {
153158 // has no type information, but at least for the common case for Optional<T>
154159 // and T? we can detect the optional.
155160 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+ }
160174 }
161175}
162176
@@ -185,8 +199,8 @@ struct TaskLocalMacroDiagnostic: DiagnosticMessage {
185199}
186200
187201extension DiagnosticsError {
188- init < S : SyntaxProtocol > (
189- syntax: S ,
202+ init (
203+ syntax: some SyntaxProtocol ,
190204 message: String ,
191205 domain: String = " Swift " ,
192206 id: TaskLocalMacroDiagnostic . ID ,
0 commit comments