Skip to content

Commit aee69f4

Browse files
authored
Merge pull request swiftlang#51 from nkcsgexi/remove-atomic
Remove calls to stdlib private functions.
2 parents 98447f5 + 49fa793 commit aee69f4

File tree

7 files changed

+57
-73
lines changed

7 files changed

+57
-73
lines changed

Sources/SwiftSyntax/AtomicCache.swift

Lines changed: 0 additions & 63 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--------------------- LazyNonThreadSafeCache.swift -------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 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+
13+
import Foundation
14+
15+
/// LazyNonThreadSafeCache is a wrapper class around an uninitialized value.
16+
/// It takes a closure that will be used to create the value when needed.
17+
///
18+
/// FIXME: the cache is no longer thread-safe. We need stdlib to provide proper
19+
/// APIs to ensure thread safety
20+
class LazyNonThreadSafeCache<Value: AnyObject> {
21+
/// The cached pointer that will be filled in the first time `value` is
22+
/// accessed.
23+
private var _cachedValue: AnyObject?
24+
25+
/// The value inside this cache. If the value has not been initialized when
26+
/// this value is requested, then the closure will be called and its resulting
27+
/// value will be stored in the cache.
28+
/// - Parameter create: The closure that will return the fully realized value
29+
/// inside the cache.
30+
func value(_ create: () -> Value) -> Value {
31+
if _cachedValue == nil {
32+
_cachedValue = create()
33+
}
34+
return _cachedValue as! Value
35+
}
36+
37+
/// Get the raw cache with the right type for debugging purposes.
38+
/// - note: Only for use in the debugger!
39+
@available(*, deprecated, message: "Only for use in the debugger.")
40+
var unsafeValue: Value? {
41+
return _cachedValue as? Value
42+
}
43+
}

Sources/SwiftSyntax/RawSyntax.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ final class RawSyntax {
9393
/// incremental parses
9494
let id: SyntaxNodeId
9595

96-
var _contentLength = AtomicCache<Box<SourceLength>>()
96+
var _contentLength = LazyNonThreadSafeCache<Box<SourceLength>>()
9797

9898
/// The length of this node excluding its leading and trailing trivia
9999
var contentLength: SourceLength {

Sources/SwiftSyntax/SyntaxData.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ final class SyntaxData: Equatable {
3636
let indexInParent: Int
3737
weak var parent: SyntaxData?
3838

39-
let childCaches: [AtomicCache<SyntaxData>]
39+
let childCaches: [LazyNonThreadSafeCache<SyntaxData>]
4040

41-
private let positionCache: AtomicCache<Box<AbsolutePosition>>
41+
private let positionCache: LazyNonThreadSafeCache<Box<AbsolutePosition>>
4242

4343
fileprivate func calculatePosition() -> AbsolutePosition {
4444
guard let parent = parent else {
@@ -92,8 +92,8 @@ final class SyntaxData: Equatable {
9292
self.raw = raw
9393
self.indexInParent = indexInParent
9494
self.parent = parent
95-
self.childCaches = raw.layout.map { _ in AtomicCache<SyntaxData>() }
96-
self.positionCache = AtomicCache<Box<AbsolutePosition>>()
95+
self.childCaches = raw.layout.map { _ in LazyNonThreadSafeCache<SyntaxData>() }
96+
self.positionCache = LazyNonThreadSafeCache<Box<AbsolutePosition>>()
9797
}
9898

9999
/// The index path from this node to the root. This can be used to uniquely

Sources/SwiftSyntax/SyntaxNodes.swift.gyb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public protocol ${node.name}: Syntax {}
6666
% for line in dedented_lines(node.description):
6767
/// ${line}
6868
% end
69+
/// Syntax nodes are not thread-safe.
6970
public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable {
7071
% if node.children:
7172
enum Cursor: Int {

Tests/LinuxMain.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ XCTMain({ () -> [XCTestCaseEntry] in
66
testCase(AbsolutePositionTestCase.allTests),
77
testCase(DecodeSyntaxTestCase.allTests),
88
testCase(DiagnosticTestCase.allTests),
9-
testCase(LazyCachingTestCase.allTests),
9+
// We need to make syntax node thread safe to enable these tests
10+
// testCase(LazyCachingTestCase.allTests),
1011
testCase(ParseFileTestCase.allTests),
1112
testCase(SyntaxChildrenAPITestCase.allTests),
1213
testCase(SyntaxCollectionsAPITestCase.allTests),

Tests/SwiftSyntaxTest/LazyCaching.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@ import SwiftSyntax
44
public class LazyCachingTestCase: XCTestCase {
55

66
public static let allTests = [
7-
("testPathological", testPathological),
8-
("testTwoAccesses", testTwoAccesses),
7+
("testPathological", disabledtestPathological),
8+
("testTwoAccesses", disabledtestTwoAccesses),
99
]
1010

11-
public func testPathological() {
11+
// FIXME: re-enable this test when syntax nodes are thread safe
12+
public func disabledtestPathological() {
1213
let tuple = SyntaxFactory.makeVoidTupleType()
1314

1415
DispatchQueue.concurrentPerform(iterations: 100) { _ in
1516
XCTAssertEqual(tuple.leftParen, tuple.leftParen)
1617
}
1718
}
1819

19-
public func testTwoAccesses() {
20+
// FIXME: re-enable this test when syntax nodes are thread safe
21+
public func disabledtestTwoAccesses() {
2022
let tuple = SyntaxFactory.makeVoidTupleType()
2123

2224
let queue1 = DispatchQueue(label: "queue1")

0 commit comments

Comments
 (0)