Skip to content

Commit 5608dc9

Browse files
authored
Sync latest TSC changes from master (#2952)
1 parent 93b9142 commit 5608dc9

34 files changed

+1155
-202
lines changed

swift-tools-support-core/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
xcuserdata/
66
.swiftpm
77
build
8+
.vscode

swift-tools-support-core/CODEOWNERS

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This file is a list of the people responsible for ensuring that patches for a
2+
# particular part of Swift are reviewed, either by themselves or by someone else.
3+
# They are also the gatekeepers for their part of Swift, with the final word on
4+
# what goes in or not.
5+
#
6+
# The list is sorted by surname and formatted to allow easy grepping and
7+
# beautification by scripts. The fields are: name (N), email (E), web-address
8+
# (W), PGP key ID and fingerprint (P), description (D), and snail-mail address
9+
# (S).
10+
11+
# N: Ankit Aggarwal
12+
13+
# D: Package Manager
14+
#
15+
# N: Anders Bertelrud
16+
17+
# D: Package Manager
18+
19+
# N: Daniel Dunbar
20+
21+
# D: Package Manager
22+
23+
###
24+
25+
# The following lines are used by GitHub to automatically recommend reviewers.
26+
27+
* @aciidb0mb3r @abertelrud @neonichu @friedbunny

swift-tools-support-core/Package.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.1
1+
// swift-tools-version:5.2
22

33
/*
44
This source file is part of the Swift.org open source project
@@ -83,3 +83,16 @@ let package = Package(
8383
dependencies: ["TSCUtility", "TSCTestSupport", "TSCTestSupportExecutable"]),
8484
]
8585
)
86+
87+
// FIXME: conditionalise these flags since SwiftPM 5.3 and earlier will crash
88+
// for platforms they don't know about.
89+
#if os(Windows)
90+
if let TSCBasic = package.targets.first(where: { $0.name == "TSCBasic" }) {
91+
TSCBasic.cxxSettings = [
92+
.define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])),
93+
]
94+
TSCBasic.linkerSettings = [
95+
.linkedLibrary("Pathcch", .when(platforms: [.windows])),
96+
]
97+
}
98+
#endif

swift-tools-support-core/Sources/TSCBasic/ByteString.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import Foundation
2121
/// strings, we wish to retain the flexibility to micro-optimize the memory
2222
/// allocation of the storage (for example, by inlining the storage for small
2323
/// strings or and by eliminating wasted space in growable arrays). For
24-
/// construction of byte arrays, clients should use the `OutputByteStream` class
24+
/// construction of byte arrays, clients should use the `WritableByteStream` class
2525
/// and then convert to a `ByteString` when complete.
2626
public struct ByteString: ExpressibleByArrayLiteral, Hashable {
2727
/// The buffer contents.
@@ -142,7 +142,7 @@ extension ByteString: CustomStringConvertible {
142142
/// ByteStreamable conformance for a ByteString.
143143
extension ByteString: ByteStreamable {
144144
@inlinable
145-
public func write(to stream: OutputByteStream) {
145+
public func write(to stream: WritableByteStream) {
146146
stream.write(_bytes)
147147
}
148148
}

swift-tools-support-core/Sources/TSCBasic/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ add_library(TSCBasic
3333
ObjectIdentifierProtocol.swift
3434
OrderedDictionary.swift
3535
OrderedSet.swift
36-
OutputByteStream.swift
36+
WritableByteStream.swift
3737
Path.swift
3838
PathShims.swift
3939
Process.swift
@@ -60,12 +60,14 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
6060
target_link_libraries(TSCBasic PUBLIC
6161
Foundation)
6262
endif()
63+
target_link_libraries(TSCBasic PRIVATE
64+
$<$<PLATFORM_ID:Windows>:Pathcch>)
6365
# NOTE(compnerd) workaround for CMake not setting up include flags yet
6466
set_target_properties(TSCBasic PROPERTIES
6567
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
6668

6769

68-
if(USE_CMAKE_INSTALL)
70+
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
6971
install(TARGETS TSCBasic
7072
ARCHIVE DESTINATION lib
7173
LIBRARY DESTINATION lib

swift-tools-support-core/Sources/TSCBasic/FileSystem.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public extension FileSystem {
230230
}
231231

232232
/// Write to a file from a stream producer.
233-
func writeFileContents(_ path: AbsolutePath, body: (OutputByteStream) -> Void) throws {
233+
func writeFileContents(_ path: AbsolutePath, body: (WritableByteStream) -> Void) throws {
234234
let contents = BufferedOutputByteStream()
235235
body(contents)
236236
try createDirectory(path.parentDirectory, recursive: true)
@@ -281,7 +281,19 @@ private class LocalFileSystem: FileSystem {
281281

282282
var currentWorkingDirectory: AbsolutePath? {
283283
let cwdStr = FileManager.default.currentDirectoryPath
284+
285+
#if _runtime(_ObjC)
286+
// The ObjC runtime indicates that the underlying Foundation has ObjC
287+
// interoperability in which case the return type of
288+
// `fileSystemRepresentation` is different from the Swift implementation
289+
// of Foundation.
284290
return try? AbsolutePath(validating: cwdStr)
291+
#else
292+
let fsr: UnsafePointer<Int8> = cwdStr.fileSystemRepresentation
293+
defer { fsr.deallocate() }
294+
295+
return try? AbsolutePath(validating: String(cString: fsr))
296+
#endif
285297
}
286298

287299
func changeCurrentWorkingDirectory(to path: AbsolutePath) throws {

swift-tools-support-core/Sources/TSCBasic/GraphAlgorithms.swift

Lines changed: 60 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -58,45 +58,44 @@ public func transitiveClosure<T>(
5858
public func topologicalSort<T: Hashable>(
5959
_ nodes: [T], successors: (T) throws -> [T]
6060
) throws -> [T] {
61-
// Stack represented as stackframes consisting from node-successors key-value pairs that
62-
// are being traversed.
63-
var stack: OrderedDictionary<T, ArraySlice<T>> = [:]
64-
// A set of already visited.
65-
var visited: Set<T> = []
66-
var result: [T] = []
67-
68-
// Implements a topological sort via iteration and reverse postorder DFS.
69-
for node in nodes {
70-
guard visited.insert(node).inserted else { continue }
71-
stack[node] = try successors(node).dropFirst(0)
72-
73-
// Peek the top of the stack
74-
while let (node, children) = stack.last {
75-
// Take the next successor for the given node.
76-
if let succ = children.first {
77-
// Drop the first successor from the children list and update the stack frame
78-
stack[node] = children.dropFirst()
79-
80-
if let _ = stack[succ] {
81-
// If the successor is already in this current stack, we have found a cycle.
82-
//
83-
// FIXME: We could easily include information on the cycle we found here.
84-
throw GraphError.unexpectedCycle
85-
}
86-
// Mark this node as visited -- we are done if it already was.
87-
guard visited.insert(succ).inserted else { continue }
88-
// Push it to the top of the stack
89-
stack[succ] = try successors(succ).dropFirst(0)
90-
} else {
91-
// Pop the node from the stack if all successors traversed.
92-
stack.removeValue(forKey: node)
93-
// Add to the result.
94-
result.append(node)
61+
// Implements a topological sort via recursion and reverse postorder DFS.
62+
func visit(_ node: T,
63+
_ stack: inout OrderedSet<T>, _ visited: inout Set<T>, _ result: inout [T],
64+
_ successors: (T) throws -> [T]) throws {
65+
// Mark this node as visited -- we are done if it already was.
66+
if !visited.insert(node).inserted {
67+
return
68+
}
69+
70+
// Otherwise, visit each adjacent node.
71+
for succ in try successors(node) {
72+
guard stack.append(succ) else {
73+
// If the successor is already in this current stack, we have found a cycle.
74+
//
75+
// FIXME: We could easily include information on the cycle we found here.
76+
throw GraphError.unexpectedCycle
9577
}
78+
try visit(succ, &stack, &visited, &result, successors)
79+
let popped = stack.removeLast()
80+
assert(popped == succ)
9681
}
82+
83+
// Add to the result.
84+
result.append(node)
9785
}
98-
// Make sure we popped all of the stack frames.
99-
assert(stack.isEmpty)
86+
87+
// FIXME: This should use a stack not recursion.
88+
var visited = Set<T>()
89+
var result = [T]()
90+
var stack = OrderedSet<T>()
91+
for node in nodes {
92+
precondition(stack.isEmpty)
93+
stack.append(node)
94+
try visit(node, &stack, &visited, &result, successors)
95+
let popped = stack.removeLast()
96+
assert(popped == node)
97+
}
98+
10099
return result.reversed()
101100
}
102101

@@ -114,41 +113,34 @@ public func findCycle<T: Hashable>(
114113
_ nodes: [T],
115114
successors: (T) throws -> [T]
116115
) rethrows -> (path: [T], cycle: [T])? {
117-
// Stack represented as stackframes consisting from node-successors key-value pairs that
118-
// are being traversed.
119-
var stack: OrderedDictionary<T, ArraySlice<T>> = [:]
120-
// A set of already visited
121-
var visited: Set<T> = []
122-
123-
for node in nodes {
124-
guard visited.insert(node).inserted else { continue }
125-
stack[node] = try successors(node).dropFirst(0)
126-
127-
// Peek the top of the stack
128-
while let (node, children) = stack.last {
129-
// Take the next successor for the given node.
130-
if let succ = children.first {
131-
// Drop the first successor from the children list and update the stack frame
132-
stack[node] = children.dropFirst()
133-
134-
if let _ = stack[succ] {
135-
let index = stack.firstIndex { $0.key == succ }!
136-
return (
137-
Array(stack[stack.startIndex..<index]).map { $0.key },
138-
Array(stack[index..<stack.endIndex]).map { $0.key })
139-
}
140-
// Mark this node as visited -- we are done if it already was.
141-
guard visited.insert(succ).inserted else { continue }
142-
// Push it to the top of the stack
143-
stack[succ] = try successors(succ).dropFirst(0)
144-
} else {
145-
// Pop the node from the stack if all successors traversed.
146-
stack.removeValue(forKey: node)
116+
// Ordered set to hold the current traversed path.
117+
var path = OrderedSet<T>()
118+
119+
// Function to visit nodes recursively.
120+
// FIXME: Convert to stack.
121+
func visit(_ node: T, _ successors: (T) throws -> [T]) rethrows -> (path: [T], cycle: [T])? {
122+
// If this node is already in the current path then we have found a cycle.
123+
if !path.append(node) {
124+
let index = path.firstIndex(of: node)!
125+
return (Array(path[path.startIndex..<index]), Array(path[index..<path.endIndex]))
126+
}
127+
128+
for succ in try successors(node) {
129+
if let cycle = try visit(succ, successors) {
130+
return cycle
147131
}
148132
}
133+
// No cycle found for this node, remove it from the path.
134+
let item = path.removeLast()
135+
assert(item == node)
136+
return nil
137+
}
138+
139+
for node in nodes {
140+
if let cycle = try visit(node, successors) {
141+
return cycle
142+
}
149143
}
150-
// Make sure we popped all of the stack frames.
151-
assert(stack.isEmpty)
152144
// Couldn't find any cycle in the graph.
153145
return nil
154146
}

swift-tools-support-core/Sources/TSCBasic/JSON.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,11 @@ extension JSON {
115115

116116
/// Support writing to a byte stream.
117117
extension JSON: ByteStreamable {
118-
public func write(to stream: OutputByteStream) {
118+
public func write(to stream: WritableByteStream) {
119119
write(to: stream, indent: nil)
120120
}
121121

122-
public func write(to stream: OutputByteStream, indent: Int?) {
122+
public func write(to stream: WritableByteStream, indent: Int?) {
123123
func indentStreamable(offset: Int? = nil) -> ByteStreamable {
124124
return Format.asRepeating(string: " ", count: indent.flatMap({ $0 + (offset ?? 0) }) ?? 0)
125125
}

0 commit comments

Comments
 (0)