Skip to content

Commit f754205

Browse files
authored
Merge pull request #1171 from CodaFi/time-lords
Replace Foundation.Date with TimePoint
2 parents 07d469f + 742e4c2 commit f754205

18 files changed

+281
-166
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import TSCBasic
1313
import SwiftOptions
1414

15-
import struct Foundation.Date
1615
import class Dispatch.DispatchQueue
1716

1817
import enum TSCUtility.Diagnostics
@@ -179,7 +178,7 @@ public struct Driver {
179178
@_spi(Testing) public let inputFiles: [TypedVirtualPath]
180179

181180
/// The last time each input file was modified, recorded at the start of the build.
182-
@_spi(Testing) public let recordedInputModificationDates: [TypedVirtualPath: Date]
181+
@_spi(Testing) public let recordedInputModificationDates: [TypedVirtualPath: TimePoint]
183182

184183
/// The mapping from input files to output files for each kind.
185184
let outputFileMap: OutputFileMap?

Sources/SwiftDriver/Execution/DriverExecutor.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import TSCBasic
14-
import struct Foundation.Date
1514
import struct Foundation.Data
1615
import class Foundation.JSONDecoder
1716
import var Foundation.EXIT_SUCCESS
@@ -25,23 +24,23 @@ public protocol DriverExecutor {
2524
@discardableResult
2625
func execute(job: Job,
2726
forceResponseFiles: Bool,
28-
recordedInputModificationDates: [TypedVirtualPath: Date]) throws -> ProcessResult
27+
recordedInputModificationDates: [TypedVirtualPath: TimePoint]) throws -> ProcessResult
2928

3029
/// Execute multiple jobs, tracking job status using the provided execution delegate.
3130
/// Pass in the `IncrementalCompilationState` to allow for incremental compilation.
3231
func execute(workload: DriverExecutorWorkload,
3332
delegate: JobExecutionDelegate,
3433
numParallelJobs: Int,
3534
forceResponseFiles: Bool,
36-
recordedInputModificationDates: [TypedVirtualPath: Date]
35+
recordedInputModificationDates: [TypedVirtualPath: TimePoint]
3736
) throws
3837

3938
/// Execute multiple jobs, tracking job status using the provided execution delegate.
4039
func execute(jobs: [Job],
4140
delegate: JobExecutionDelegate,
4241
numParallelJobs: Int,
4342
forceResponseFiles: Bool,
44-
recordedInputModificationDates: [TypedVirtualPath: Date]
43+
recordedInputModificationDates: [TypedVirtualPath: TimePoint]
4544
) throws
4645

4746
/// Launch a process with the given command line and report the result.
@@ -86,7 +85,7 @@ extension DriverExecutor {
8685
func execute<T: Decodable>(job: Job,
8786
capturingJSONOutputAs outputType: T.Type,
8887
forceResponseFiles: Bool,
89-
recordedInputModificationDates: [TypedVirtualPath: Date]) throws -> T {
88+
recordedInputModificationDates: [TypedVirtualPath: TimePoint]) throws -> T {
9089
let result = try execute(job: job,
9190
forceResponseFiles: forceResponseFiles,
9291
recordedInputModificationDates: recordedInputModificationDates)
@@ -111,7 +110,7 @@ extension DriverExecutor {
111110
delegate: JobExecutionDelegate,
112111
numParallelJobs: Int,
113112
forceResponseFiles: Bool,
114-
recordedInputModificationDates: [TypedVirtualPath: Date]
113+
recordedInputModificationDates: [TypedVirtualPath: TimePoint]
115114
) throws {
116115
try execute(
117116
workload: .all(jobs),

Sources/SwiftDriver/IncrementalCompilation/BuildRecord.swift

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212
import TSCBasic
1313
@_implementationOnly import Yams
14-
import struct Foundation.Date
1514

1615
/// Holds the info about inputs needed to plan incremenal compilation
1716
/// A.k.a. BuildRecord was the legacy name
@@ -20,16 +19,16 @@ public struct BuildRecord {
2019
/// When testing, the argsHash may be missing from the build record
2120
public let argsHash: String?
2221
/// Next compile, will compare an input mod time against the start time of the previous build
23-
public let buildStartTime: Date
22+
public let buildStartTime: TimePoint
2423
/// Next compile, will compare an output mod time against the end time of the previous build
25-
public let buildEndTime: Date
24+
public let buildEndTime: TimePoint
2625
/// The date is the modification time of the main input file the last time the driver ran
2726
public let inputInfos: [VirtualPath: InputInfo]
2827

2928
public init(argsHash: String?,
3029
swiftVersion: String,
31-
buildStartTime: Date,
32-
buildEndTime: Date,
30+
buildStartTime: TimePoint,
31+
buildEndTime: TimePoint,
3332
inputInfos: [VirtualPath: InputInfo]) {
3433
self.argsHash = argsHash
3534
self.swiftVersion = swiftVersion
@@ -67,8 +66,8 @@ public extension BuildRecord {
6766
var argsHash: String?
6867
var swiftVersion: String?
6968
// Legacy driver does not disable incremental if no buildTime field.
70-
var buildStartTime: Date = .distantPast
71-
var buildEndTime: Date = .distantFuture
69+
var buildStartTime: TimePoint = .distantPast
70+
var buildEndTime: TimePoint = .distantFuture
7271
var inputInfos: [VirtualPath: InputInfo]?
7372
for (key, value) in sections {
7473
guard let k = key.string else {
@@ -138,7 +137,7 @@ public extension BuildRecord {
138137
_ node: Yams.Node,
139138
forInputInfo: Bool,
140139
_ failedToReadOutOfDateMap: (String) -> Void
141-
) -> Date? {
140+
) -> TimePoint? {
142141
guard let vals = node.sequence else {
143142
failedToReadOutOfDateMap(
144143
forInputInfo
@@ -153,7 +152,7 @@ public extension BuildRecord {
153152
failedToReadOutOfDateMap("could not read time value in build record")
154153
return nil
155154
}
156-
return Date(legacyDriverSecs: secs, nanos: ns)
155+
return TimePoint(seconds: UInt64(secs), nanoseconds: UInt32(ns))
157156
}
158157

159158
private static func decodeInputInfos(
@@ -197,11 +196,11 @@ extension BuildRecord {
197196
init(jobs: [Job],
198197
finishedJobResults: [BuildRecordInfo.JobResult],
199198
skippedInputs: Set<TypedVirtualPath>?,
200-
compilationInputModificationDates: [TypedVirtualPath: Date],
199+
compilationInputModificationDates: [TypedVirtualPath: TimePoint],
201200
actualSwiftVersion: String,
202201
argsHash: String!,
203-
timeBeforeFirstJob: Date,
204-
timeAfterLastJob: Date
202+
timeBeforeFirstJob: TimePoint,
203+
timeAfterLastJob: TimePoint
205204
) {
206205
let jobResultsByInput = Dictionary(uniqueKeysWithValues:
207206
finishedJobResults.flatMap { entry in
@@ -256,10 +255,9 @@ extension BuildRecord {
256255
}
257256
}
258257

259-
private static func encode(_ date: Date, tag tagString: String? = nil) -> Yams.Node {
260-
let secsAndNanos = date.legacyDriverSecsAndNanos
258+
private static func encode(_ date: TimePoint, tag tagString: String? = nil) -> Yams.Node {
261259
return Yams.Node(
262-
secsAndNanos.map {Yams.Node(String($0))},
260+
[ Yams.Node(String(date.seconds)), Yams.Node(String(date.nanoseconds)) ],
263261
tagString.map {Yams.Tag(Yams.Tag.Name(rawValue: $0))} ?? .implicit,
264262
.flow)
265263
}

Sources/SwiftDriver/IncrementalCompilation/BuildRecordInfo.swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import TSCBasic
1414
import SwiftOptions
15-
import struct Foundation.Date
1615
import class Dispatch.DispatchQueue
1716

1817
/// Holds information required to read and write the build record (aka
@@ -38,9 +37,9 @@ import class Dispatch.DispatchQueue
3837
let fileSystem: FileSystem
3938
let currentArgsHash: String
4039
@_spi(Testing) public let actualSwiftVersion: String
41-
@_spi(Testing) public let timeBeforeFirstJob: Date
40+
@_spi(Testing) public let timeBeforeFirstJob: TimePoint
4241
let diagnosticEngine: DiagnosticsEngine
43-
let compilationInputModificationDates: [TypedVirtualPath: Date]
42+
let compilationInputModificationDates: [TypedVirtualPath: TimePoint]
4443

4544
private var finishedJobResults = [JobResult]()
4645
// A confinement queue that protects concurrent access to the
@@ -53,9 +52,9 @@ import class Dispatch.DispatchQueue
5352
fileSystem: FileSystem,
5453
currentArgsHash: String,
5554
actualSwiftVersion: String,
56-
timeBeforeFirstJob: Date,
55+
timeBeforeFirstJob: TimePoint,
5756
diagnosticEngine: DiagnosticsEngine,
58-
compilationInputModificationDates: [TypedVirtualPath: Date])
57+
compilationInputModificationDates: [TypedVirtualPath: TimePoint])
5958
{
6059
self.buildRecordPath = buildRecordPath
6160
self.fileSystem = fileSystem
@@ -77,7 +76,7 @@ import class Dispatch.DispatchQueue
7776
outputFileMap: OutputFileMap?,
7877
incremental: Bool,
7978
parsedOptions: ParsedOptions,
80-
recordedInputModificationDates: [TypedVirtualPath: Date]
79+
recordedInputModificationDates: [TypedVirtualPath: TimePoint]
8180
) {
8281
// Cannot write a buildRecord without a path.
8382
guard let buildRecordPath = Self.computeBuildRecordPath(
@@ -100,7 +99,7 @@ import class Dispatch.DispatchQueue
10099
fileSystem: fileSystem,
101100
currentArgsHash: currentArgsHash,
102101
actualSwiftVersion: actualSwiftVersion,
103-
timeBeforeFirstJob: Date(),
102+
timeBeforeFirstJob: .now(),
104103
diagnosticEngine: diagnosticEngine,
105104
compilationInputModificationDates: compilationInputModificationDates)
106105
}
@@ -165,7 +164,7 @@ import class Dispatch.DispatchQueue
165164
actualSwiftVersion: actualSwiftVersion,
166165
argsHash: currentArgsHash,
167166
timeBeforeFirstJob: timeBeforeFirstJob,
168-
timeAfterLastJob: Date())
167+
timeAfterLastJob: .now())
169168
}
170169

171170
guard let contents = buildRecord.encode(currentArgsHash: currentArgsHash,

Sources/SwiftDriver/IncrementalCompilation/FirstWaveComputer.swift

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import TSCBasic
14-
import struct Foundation.Date
1514
import class Dispatch.DispatchQueue
1615

1716
extension IncrementalCompilationState {
@@ -257,21 +256,13 @@ extension IncrementalCompilationState.FirstWaveComputer {
257256
) -> [ChangedInput] {
258257
jobsInPhases.compileGroups.compactMap { group in
259258
let input = group.primaryInput
260-
let modDate = buildRecordInfo.compilationInputModificationDates[input]
261-
?? Date.distantFuture
259+
let modDate = buildRecordInfo.compilationInputModificationDates[input] ?? .distantFuture
262260
let inputInfo = outOfDateBuildRecord.inputInfos[input.file]
263261
let previousCompilationStatus = inputInfo?.status ?? .newlyAdded
264262
let previousModTime = inputInfo?.previousModTime
265263

266-
// Because legacy driver reads/writes dates wrt 1970,
267-
// and because converting time intervals to/from Dates from 1970
268-
// exceeds Double precision, must not compare dates directly
269-
var datesMatch: Bool {
270-
modDate.timeIntervalSince1970 == previousModTime?.timeIntervalSince1970
271-
}
272-
273264
switch previousCompilationStatus {
274-
case .upToDate where datesMatch:
265+
case .upToDate where modDate == previousModTime:
275266
reporter?.report("May skip current input:", input)
276267
return nil
277268

@@ -286,7 +277,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
286277
}
287278
return ChangedInput(typedFile: input,
288279
status: previousCompilationStatus,
289-
datesMatch: datesMatch)
280+
datesMatch: modDate == previousModTime)
290281
}
291282
}
292283

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState+Extensions.swift

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212
import TSCBasic
1313
import SwiftOptions
14-
import struct Foundation.Date
1514
import protocol Foundation.LocalizedError
1615

1716
/// In a separate file to ensure that ``IncrementalCompilationState/protectedState``
@@ -50,9 +49,9 @@ extension IncrementalCompilationState {
5049
/// Compiler options related to incremental builds.
5150
let incrementalOptions: IncrementalCompilationState.Options
5251
/// The last time this compilation was started. Used to compare against e.g. input file mod dates.
53-
let buildStartTime: Date
52+
let buildStartTime: TimePoint
5453
/// The last time this compilation finished. Used to compare against output file mod dates
55-
let buildEndTime: Date
54+
let buildEndTime: TimePoint
5655
}
5756
}
5857

@@ -175,8 +174,7 @@ extension IncrementalCompilationState {
175174
report(skipping: false, "No outputs")
176175
return false
177176
}
178-
guard .distantPast < oldestOutputModTime
179-
else {
177+
guard .distantPast < oldestOutputModTime else {
180178
report(skipping: false, "Missing output", oldestOutput)
181179
return false
182180
}
@@ -189,29 +187,29 @@ extension IncrementalCompilationState {
189187
return true
190188
}
191189

192-
private func findOldestOutputForSkipping(postCompileJob: Job) -> (TypedVirtualPath, Date)? {
193-
var oldestOutputAndModTime: (TypedVirtualPath, Date)? = nil
190+
private func findOldestOutputForSkipping(postCompileJob: Job) -> (TypedVirtualPath, TimePoint)? {
191+
var oldestOutputAndModTime: (TypedVirtualPath, TimePoint)? = nil
194192
for output in postCompileJob.outputs {
195-
guard let outputModTime = modTime(output)
196-
else {
197-
oldestOutputAndModTime = (output, .distantPast)
198-
break
193+
guard let outputModTime = try? self.fileSystem.lastModificationTime(for: output.file) else {
194+
return (output, .distantPast)
199195
}
200-
oldestOutputAndModTime = oldestOutputAndModTime.map {
201-
$0.1 < outputModTime ? $0 : (output, outputModTime)
196+
197+
if let candidate = oldestOutputAndModTime {
198+
oldestOutputAndModTime = candidate.1 < outputModTime ? candidate : (output, outputModTime)
199+
} else {
200+
oldestOutputAndModTime = (output, outputModTime)
202201
}
203-
?? (output, outputModTime)
204202
}
205203
return oldestOutputAndModTime
206204
}
207-
private func findAnInputOf( postCompileJob: Job, newerThan outputModTime: Date) -> TypedVirtualPath? {
205+
private func findAnInputOf( postCompileJob: Job, newerThan outputModTime: TimePoint) -> TypedVirtualPath? {
208206
postCompileJob.inputs.first { input in
209-
outputModTime < (modTime(input) ?? .distantFuture)
207+
guard let modTime = try? self.fileSystem.lastModificationTime(for: input.file) else {
208+
return false
209+
}
210+
return outputModTime < modTime
210211
}
211212
}
212-
private func modTime(_ path: TypedVirtualPath) -> Date? {
213-
try? fileSystem.lastModificationTime(for: path.file)
214-
}
215213
}
216214

217215

Sources/SwiftDriver/IncrementalCompilation/IncrementalDependencyAndInputSetup.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import TSCBasic
1414
import SwiftOptions
15-
import struct Foundation.Date
1615
import class Dispatch.DispatchQueue
1716

1817
// Initial incremental state computation
@@ -121,8 +120,8 @@ extension IncrementalCompilationState {
121120
@_spi(Testing) public let dependencyDotFilesIncludeExternals: Bool = true
122121
@_spi(Testing) public let dependencyDotFilesIncludeAPINotes: Bool = false
123122

124-
@_spi(Testing) public let buildStartTime: Date
125-
@_spi(Testing) public let buildEndTime: Date
123+
@_spi(Testing) public let buildStartTime: TimePoint
124+
@_spi(Testing) public let buildEndTime: TimePoint
126125

127126
// Do not try to reuse a graph from a different compilation, so check
128127
// the build record.
@@ -249,11 +248,10 @@ extension IncrementalCompilationState.IncrementalDependencyAndInputSetup {
249248
graphIfPresent = nil
250249
}
251250
catch let ModuleDependencyGraph.ReadError.timeTravellingPriors(priorsModTime: priorsModTime,
252-
buildStartTime: buildStartTime,
253-
priorsTimeIntervalSinceStart: priorsTimeIntervalSinceStart) {
251+
buildStartTime: buildStartTime) {
254252
diagnosticEngine.emit(
255253
warning: "Will not do cross-module incremental builds, priors saved at \(priorsModTime)), " +
256-
"but the previous build started at \(buildStartTime) [priorsTimeIntervalSinceStart: \(priorsTimeIntervalSinceStart)], at '\(dependencyGraphPath)'")
254+
"but the previous build started at \(buildStartTime), at '\(dependencyGraphPath)'")
257255
graphIfPresent = nil
258256
}
259257
catch {

Sources/SwiftDriver/IncrementalCompilation/InputInfo.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import TSCBasic
14-
import struct Foundation.Date
1514

1615
/// Contains information about the current status of an input to the incremental
1716
/// build.
@@ -24,9 +23,9 @@ import struct Foundation.Date
2423
/// The current status of the input file.
2524
/*@_spi(Testing)*/ public let status: Status
2625
/// The last known modification time of this input.
27-
/*@_spi(Testing)*/ public let previousModTime: Date
26+
/*@_spi(Testing)*/ public let previousModTime: TimePoint
2827

29-
/*@_spi(Testing)*/ public init(status: Status, previousModTime: Date) {
28+
/*@_spi(Testing)*/ public init(status: Status, previousModTime: TimePoint) {
3029
self.status = status
3130
self.previousModTime = previousModTime
3231
}
@@ -119,7 +118,7 @@ fileprivate extension ProcessResult {
119118

120119
// MARK: - reading
121120
public extension InputInfo {
122-
init?(tag: String, previousModTime: Date,
121+
init?(tag: String, previousModTime: TimePoint,
123122
failedToReadOutOfDateMap: (String) -> Void
124123
) {
125124
guard let status = Status(identifier: tag) else {

0 commit comments

Comments
 (0)