Skip to content

Commit 7224178

Browse files
authored
[TaskLocal] Carry access control modifiers into synthesized property (#73475)
1 parent cd2bb3d commit 7224178

File tree

6 files changed

+93
-24
lines changed

6 files changed

+93
-24
lines changed

lib/Macros/Sources/SwiftMacros/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_swift_macro_library(SwiftMacros
1414
OptionSetMacro.swift
1515
DebugDescriptionMacro.swift
1616
DistributedResolvableMacro.swift
17+
SyntaxExtensions.swift
1718
TaskLocalMacro.swift
1819
SWIFT_DEPENDENCIES
1920
SwiftDiagnostics

lib/Macros/Sources/SwiftMacros/DistributedResolvableMacro.swift

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension DistributedResolvableMacro {
4545
return []
4646
}
4747

48-
let accessModifiers: String = proto.accessModifiersString
48+
let accessModifiers = proto.accessControlModifiers
4949

5050
let requirementStubs =
5151
proto.memberBlock.members // requirements
@@ -71,7 +71,7 @@ extension DistributedResolvableMacro {
7171
return [extensionDecl.cast(ExtensionDeclSyntax.self)]
7272
}
7373

74-
static func stubMethodDecl(access: String, _ requirement: MemberBlockItemListSyntax.Element) -> String {
74+
static func stubMethodDecl(access: DeclModifierListSyntax, _ requirement: MemberBlockItemListSyntax.Element) -> String {
7575
// do we need to stub a computed variable?
7676
if let variable = requirement.decl.as(VariableDeclSyntax.self) {
7777
var accessorStubs: [String] = []
@@ -142,7 +142,7 @@ extension DistributedResolvableMacro {
142142
""", id: .invalidApplication)
143143
}
144144

145-
let accessModifiers = proto.accessModifiersString
145+
let accessModifiers = proto.accessControlModifiers
146146

147147
for req in proto.genericWhereClause?.requirements ?? [] {
148148
switch req.requirement {
@@ -198,31 +198,16 @@ extension DistributedResolvableMacro {
198198
}
199199
}
200200

201-
private static func typealiasActorSystem(access: String, _ proto: ProtocolDeclSyntax, _ type: TypeSyntax) -> DeclSyntax {
202-
"\(raw: access)typealias ActorSystem = \(type)"
201+
private static func typealiasActorSystem(access: DeclModifierListSyntax,
202+
_ proto: ProtocolDeclSyntax,
203+
_ type: TypeSyntax) -> DeclSyntax {
204+
"\(access)typealias ActorSystem = \(type)"
203205
}
204206
}
205207

206208
// ===== -----------------------------------------------------------------------
207209
// MARK: Convenience Extensions
208210

209-
extension ProtocolDeclSyntax {
210-
var accessModifiersString: String {
211-
let modifiers = modifiers.filter { modifier in
212-
modifier.isAccessControl
213-
}
214-
215-
guard !modifiers.isEmpty else {
216-
return ""
217-
}
218-
219-
let string = modifiers
220-
.map { "\($0.trimmed)" }
221-
.joined(separator: " ")
222-
return "\(string) "
223-
}
224-
}
225-
226211
extension TypeSyntax {
227212
fileprivate var isActorSystem: Bool {
228213
self.trimmedDescription == "ActorSystem"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022-2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
// Common Syntax extensions used by standard library macros. //
13+
//===----------------------------------------------------------------------===//
14+
15+
import SwiftSyntax
16+
import SwiftSyntaxMacros
17+
import SwiftDiagnostics
18+
19+
extension DeclGroupSyntax {
20+
internal var accessControlModifiers: DeclModifierListSyntax {
21+
modifiers.filter { modifier in
22+
modifier.isAccessControl
23+
}
24+
}
25+
}
26+
27+
extension VariableDeclSyntax {
28+
internal var accessControlModifiers: DeclModifierListSyntax {
29+
modifiers.filter { modifier in
30+
modifier.isAccessControl
31+
}
32+
}
33+
}

lib/Macros/Sources/SwiftMacros/TaskLocalMacro.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ extension TaskLocalMacro: PeerMacro {
6969
message: "'@TaskLocal' property must have default value, or be optional", id: .mustBeVar)
7070
}
7171

72+
// Copy access modifiers
73+
let access = varDecl.accessControlModifiers
74+
7275
// If the property is global, do not prefix the synthesised decl with 'static'
7376
let isGlobal = context.lexicalContext.isEmpty
7477
let staticKeyword: TokenSyntax?
@@ -80,7 +83,7 @@ extension TaskLocalMacro: PeerMacro {
8083

8184
return [
8285
"""
83-
\(staticKeyword)let $\(name)\(explicitTypeAnnotation) = TaskLocal(wrappedValue: \(initialValue))
86+
\(access)\(staticKeyword)let $\(name)\(explicitTypeAnnotation) = TaskLocal(wrappedValue: \(initialValue))
8487
"""
8588
]
8689
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// REQUIRES: swift_swift_parser, asserts
2+
//
3+
// UNSUPPORTED: back_deploy_concurrency
4+
// REQUIRES: concurrency
5+
//
6+
// RUN: %empty-directory(%t)
7+
// RUN: %empty-directory(%t-scratch)
8+
9+
// RUN: %target-swift-frontend -disable-availability-checking -typecheck -verify -plugin-path %swift-plugin-dir -I %t -dump-macro-expansions %s -dump-macro-expansions 2>&1 | %FileCheck %s
10+
11+
struct Nein {
12+
@TaskLocal
13+
public static var example: String = "hello"
14+
}
15+
16+
// CHECK: public static let $example: TaskLocal<String> = TaskLocal(wrappedValue: "hello")
17+
//
18+
// CHECK: {
19+
// CHECK: get {
20+
// CHECK: $example.get()
21+
// CHECK: }
22+
// CHECK: }
23+
24+
struct Available {
25+
@available(OSX 10.9, *)
26+
struct AvailableValue {}
27+
28+
@TaskLocal
29+
@available(OSX 10.9, *)
30+
private static var example: AvailableValue?
31+
}
32+
33+
// CHECK: private static let $example: TaskLocal<AvailableValue?> = TaskLocal(wrappedValue: nil)
34+
//
35+
// CHECK: {
36+
// CHECK: get {
37+
// CHECK: $example.get()
38+
// CHECK: }
39+
// CHECK: }

test/Concurrency/Runtime/async_task_locals_basic.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift( -plugin-path %swift-plugin-dir -Xfrontend -disable-availability-checking -parse-as-library %import-libdispatch) | %FileCheck %s
1+
// RUN: %target-run-simple-swift( -plugin-path %swift-plugin-dir -parse-as-library %import-libdispatch) | %FileCheck %s
22

33
// REQUIRES: executable_test
44
// REQUIRES: concurrency
@@ -37,8 +37,16 @@ enum TL {
3737
}
3838

3939
@TaskLocal
40+
@available(SwiftStdlib 5.1, *)
4041
var globalTaskLocal: StringLike = StringLike("<not-set>")
4142

43+
@available(SwiftStdlib 5.10, *)
44+
struct LessAvailable {}
45+
46+
@TaskLocal
47+
@available(SwiftStdlib 5.10, *)
48+
var globalLessAvailable: LessAvailable?
49+
4250
@available(SwiftStdlib 5.1, *)
4351
final class ClassTaskLocal: Sendable {
4452
init() {

0 commit comments

Comments
 (0)