Skip to content

Commit f0abc07

Browse files
Merge pull request #681 from CodaFi/depshire
Revert #664
2 parents e32c869 + b74d808 commit f0abc07

File tree

4 files changed

+71
-162
lines changed

4 files changed

+71
-162
lines changed

Sources/SwiftDriver/IncrementalCompilation/IncrementalDependencyAndInputSetup.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ extension IncrementalCompilationState.IncrementalDependencyAndInputSetup {
226226
else {
227227
return buildInitialGraphFromSwiftDepsAndCollectInputsInvalidatedByChangedExternals()
228228
}
229-
guard graph.populateInputDependencySourceMap(for: .inputsAddedSincePriors) else {
229+
guard graph.populateInputDependencySourceMap() else {
230230
return nil
231231
}
232232
graph.dotFileWriter?.write(graph)
@@ -256,8 +256,7 @@ extension IncrementalCompilationState.IncrementalDependencyAndInputSetup {
256256
{
257257
let graph = ModuleDependencyGraph(self, .buildingWithoutAPrior)
258258
assert(outputFileMap.onlySourceFilesHaveSwiftDeps())
259-
260-
guard graph.populateInputDependencySourceMap(for: .buildingFromSwiftDeps) else {
259+
guard graph.populateInputDependencySourceMap() else {
261260
return nil
262261
}
263262

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraph.swift

Lines changed: 68 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,19 @@ import SwiftOptions
2424
@_spi(Testing) public var nodeFinder = NodeFinder()
2525

2626
/// Maps input files (e.g. .swift) to and from the DependencySource object.
27-
@_spi(Testing) public private(set) var inputDependencySourceMap = InputDependencySourceMap()
27+
///
28+
// FIXME: The map between swiftdeps and swift files is absolutely *not*
29+
// a bijection. In particular, more than one swiftdeps file can be encountered
30+
// in the course of deserializing priors *and* reading the output file map
31+
// *and* re-reading swiftdeps files after frontends complete
32+
// that correspond to the same swift file. These cause two problems:
33+
// - overwrites in this data structure that lose data and
34+
// - cache misses in `getInput(for:)` that cause the incremental build to
35+
// turn over when e.g. entries in the output file map change. This should be
36+
// replaced by a multi-map from swift files to dependency sources,
37+
// and a regular map from dependency sources to swift files -
38+
// since that direction really is one-to-one.
39+
@_spi(Testing) public private(set) var inputDependencySourceMap = BidirectionalMap<TypedVirtualPath, DependencySource>()
2840

2941
// The set of paths to external dependencies known to be in the graph
3042
public internal(set) var fingerprintedExternalDependencies = Set<FingerprintedExternalDependency>()
@@ -54,20 +66,22 @@ import SwiftOptions
5466
self.creationPhase = phase
5567
}
5668

57-
@_spi(Testing) public func source(requiredFor input: TypedVirtualPath,
58-
function: String = #function,
59-
file: String = #file,
60-
line: Int = #line) -> DependencySource {
61-
guard let source = inputDependencySourceMap.sourceIfKnown(for: input)
62-
else {
69+
private func addMapEntry(_ input: TypedVirtualPath, _ dependencySource: DependencySource) {
70+
assert(input.type == .swift && dependencySource.typedFile.type == .swiftDeps)
71+
inputDependencySourceMap[input] = dependencySource
72+
}
73+
74+
@_spi(Testing) public func getSource(for input: TypedVirtualPath,
75+
function: String = #function,
76+
file: String = #file,
77+
line: Int = #line) -> DependencySource {
78+
guard let source = inputDependencySourceMap[input] else {
6379
fatalError("\(input.file.basename) not found in inputDependencySourceMap, \(file):\(line) in \(function)")
6480
}
6581
return source
6682
}
67-
68-
@_spi(Testing) public func input(neededFor source: DependencySource) -> TypedVirtualPath? {
69-
guard let input = inputDependencySourceMap.input(ifKnownFor: source)
70-
else {
83+
@_spi(Testing) public func getInput(for source: DependencySource) -> TypedVirtualPath? {
84+
guard let input = inputDependencySourceMap[source] else {
7185
info.diagnosticEngine.emit(warning: "Failed to find source file for '\(source.file.basename)', recovering with a full rebuild. Next build will be incremental.")
7286
return nil
7387
}
@@ -141,7 +155,7 @@ extension ModuleDependencyGraph {
141155
return TransitivelyInvalidatedInputSet()
142156
}
143157
return collectInputsRequiringCompilationAfterProcessing(
144-
dependencySource: source(requiredFor: input))
158+
dependencySource: getSource(for: input))
145159
}
146160
}
147161

@@ -161,17 +175,17 @@ extension ModuleDependencyGraph {
161175
/// speculatively scheduled in the first wave.
162176
func collectInputsInvalidatedBy(input: TypedVirtualPath
163177
) -> TransitivelyInvalidatedInputArray {
164-
let changedSource = source(requiredFor: input)
178+
let changedSource = getSource(for: input)
165179
let allDependencySourcesToRecompile =
166180
collectSwiftDepsUsing(dependencySource: changedSource)
167181

168182
return allDependencySourcesToRecompile.compactMap {
169183
depedencySource in
170184
guard depedencySource != changedSource else {return nil}
171-
let dependentInput = inputDependencySourceMap.input(ifKnownFor: depedencySource)
185+
let dependentSource = inputDependencySourceMap[depedencySource]
172186
info.reporter?.report(
173-
"Found dependent of \(input.file.basename):", dependentInput)
174-
return dependentInput
187+
"Found dependent of \(input.file.basename):", dependentSource)
188+
return dependentSource
175189
}
176190
}
177191

@@ -188,7 +202,7 @@ extension ModuleDependencyGraph {
188202
/// Does the graph contain any dependency nodes for a given source-code file?
189203
func containsNodes(forSourceFile file: TypedVirtualPath) -> Bool {
190204
precondition(file.type == .swift)
191-
guard let source = inputDependencySourceMap.sourceIfKnown(for: file) else {
205+
guard let source = inputDependencySourceMap[file] else {
192206
return false
193207
}
194208
return containsNodes(forDependencySource: source)
@@ -198,46 +212,17 @@ extension ModuleDependencyGraph {
198212
return nodeFinder.findNodes(for: source).map {!$0.isEmpty}
199213
?? false
200214
}
201-
202-
/// Returns: false on error
203-
func populateInputDependencySourceMap(
204-
for purpose: InputDependencySourceMap.AdditionPurpose
205-
) -> Bool {
215+
216+
/// Return true on success
217+
func populateInputDependencySourceMap() -> Bool {
206218
let ofm = info.outputFileMap
207-
let diags = info.diagnosticEngine
208-
var allFound = true
209-
for input in info.inputFiles {
210-
if let source = ofm.dependencySource(for: input, diagnosticEngine: diags) {
211-
inputDependencySourceMap.addEntry(input, source, for: purpose)
212-
} else {
213-
// Don't break in order to report all failures.
214-
allFound = false
215-
}
216-
}
217-
return allFound
218-
}
219-
}
220-
extension OutputFileMap {
221-
fileprivate func dependencySource(
222-
for sourceFile: TypedVirtualPath,
223-
diagnosticEngine: DiagnosticsEngine
224-
) -> DependencySource? {
225-
assert(sourceFile.type == FileType.swift)
226-
guard let swiftDepsPath = existingOutput(inputFile: sourceFile.fileHandle,
227-
outputType: .swiftDeps)
228-
else {
229-
// The legacy driver fails silently here.
230-
diagnosticEngine.emit(
231-
.remarkDisabled("\(sourceFile.file.basename) has no swiftDeps file")
232-
)
233-
return nil
219+
let de = info.diagnosticEngine
220+
return info.inputFiles.reduce(true) { okSoFar, input in
221+
ofm.getDependencySource(for: input, diagnosticEngine: de)
222+
.map {source in addMapEntry(input, source); return okSoFar } ?? false
234223
}
235-
assert(VirtualPath.lookup(swiftDepsPath).extension == FileType.swiftDeps.rawValue)
236-
let typedSwiftDepsFile = TypedVirtualPath(file: swiftDepsPath, type: .swiftDeps)
237-
return DependencySource(typedSwiftDepsFile)
238224
}
239225
}
240-
241226
// MARK: - Scheduling the 2nd wave
242227
extension ModuleDependencyGraph {
243228
/// After `source` has been compiled, figure out what other source files need compiling.
@@ -247,7 +232,7 @@ extension ModuleDependencyGraph {
247232
func collectInputsRequiringCompilation(byCompiling input: TypedVirtualPath
248233
) -> TransitivelyInvalidatedInputSet? {
249234
precondition(input.type == .swift)
250-
let dependencySource = source(requiredFor: input)
235+
let dependencySource = getSource(for: input)
251236
return collectInputsRequiringCompilationAfterProcessing(
252237
dependencySource: dependencySource)
253238
}
@@ -342,7 +327,7 @@ extension ModuleDependencyGraph {
342327
) -> TransitivelyInvalidatedInputSet? {
343328
var invalidatedInputs = TransitivelyInvalidatedInputSet()
344329
for invalidatedSwiftDeps in collectSwiftDepsUsingInvalidated(nodes: directlyInvalidatedNodes) {
345-
guard let invalidatedInput = input(neededFor: invalidatedSwiftDeps) else {
330+
guard let invalidatedInput = getInput(for: invalidatedSwiftDeps) else {
346331
return nil
347332
}
348333
invalidatedInputs.insert(invalidatedInput)
@@ -466,6 +451,27 @@ extension ModuleDependencyGraph {
466451
}
467452
}
468453

454+
extension OutputFileMap {
455+
fileprivate func getDependencySource(
456+
for sourceFile: TypedVirtualPath,
457+
diagnosticEngine: DiagnosticsEngine
458+
) -> DependencySource? {
459+
assert(sourceFile.type == FileType.swift)
460+
guard let swiftDepsPath = existingOutput(inputFile: sourceFile.fileHandle,
461+
outputType: .swiftDeps)
462+
else {
463+
// The legacy driver fails silently here.
464+
diagnosticEngine.emit(
465+
.remarkDisabled("\(sourceFile.file.basename) has no swiftDeps file")
466+
)
467+
return nil
468+
}
469+
assert(VirtualPath.lookup(swiftDepsPath).extension == FileType.swiftDeps.rawValue)
470+
let typedSwiftDepsFile = TypedVirtualPath(file: swiftDepsPath, type: .swiftDeps)
471+
return DependencySource(typedSwiftDepsFile)
472+
}
473+
}
474+
469475
// MARK: - tracking traced nodes
470476
extension ModuleDependencyGraph {
471477

@@ -590,11 +596,10 @@ extension ModuleDependencyGraph {
590596
.record(def: dependencyKey, use: self.allNodes[useID])
591597
assert(isNewUse, "Duplicate use def-use arc in graph?")
592598
}
593-
for (input, dependencySource) in inputDependencySourceMap {
594-
graph.inputDependencySourceMap.addEntry(input,
595-
dependencySource,
596-
for: .readingPriors)
599+
for (input, source) in inputDependencySourceMap {
600+
graph.addMapEntry(input, source)
597601
}
602+
598603
return self.graph
599604
}
600605

@@ -890,7 +895,7 @@ extension ModuleDependencyGraph {
890895
}
891896
}
892897

893-
graph.inputDependencySourceMap.enumerateToSerializePriors { input, dependencySource in
898+
for (input, dependencySource) in graph.inputDependencySourceMap {
894899
self.addIdentifier(input.file.name)
895900
self.addIdentifier(dependencySource.file.name)
896901
}
@@ -1035,8 +1040,7 @@ extension ModuleDependencyGraph {
10351040
}
10361041
}
10371042
}
1038-
graph.inputDependencySourceMap.enumerateToSerializePriors {
1039-
input, dependencySource in
1043+
for (input, dependencySource) in graph.inputDependencySourceMap {
10401044
serializer.stream.writeRecord(serializer.abbreviations[.mapNode]!) {
10411045
$0.append(RecordID.mapNode)
10421046
$0.append(serializer.lookupIdentifierCode(for: input.file.name))
@@ -1154,7 +1158,7 @@ extension Set where Element == ModuleDependencyGraph.Node {
11541158
}
11551159
}
11561160

1157-
extension InputDependencySourceMap {
1161+
extension BidirectionalMap where T1 == TypedVirtualPath, T2 == DependencySource {
11581162
fileprivate func matches(_ other: Self) -> Bool {
11591163
self == other
11601164
}
@@ -1172,6 +1176,6 @@ extension ModuleDependencyGraph {
11721176
_ mockInput: TypedVirtualPath,
11731177
_ mockDependencySource: DependencySource
11741178
) {
1175-
inputDependencySourceMap.addEntry(mockInput, mockDependencySource, for: .mocking)
1179+
addMapEntry(mockInput, mockDependencySource)
11761180
}
11771181
}

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraphParts/InputDependencySourceMap.swift

Lines changed: 0 additions & 93 deletions
This file was deleted.

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraphParts/Tracer.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ extension ModuleDependencyGraph.Tracer {
121121
path.compactMap { node in
122122
node.dependencySource.map {
123123
source in
124-
graph.inputDependencySourceMap.input(ifKnownFor: source).map {
125-
input in
124+
graph.inputDependencySourceMap[source].map { input in
126125
"\(node.key) in \(input.file.basename)"
127126
}
128127
?? "\(node.key)"

0 commit comments

Comments
 (0)