@@ -24,19 +24,7 @@ import SwiftOptions
24
24
@_spi ( Testing) public var nodeFinder = NodeFinder ( )
25
25
26
26
/// Maps input files (e.g. .swift) to and from the DependencySource object.
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 > ( )
27
+ @_spi ( Testing) public private( set) var inputDependencySourceMap = InputDependencySourceMap ( )
40
28
41
29
// The set of paths to external dependencies known to be in the graph
42
30
public internal( set) var fingerprintedExternalDependencies = Set < FingerprintedExternalDependency > ( )
@@ -66,22 +54,20 @@ import SwiftOptions
66
54
self . creationPhase = phase
67
55
}
68
56
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 {
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 {
79
63
fatalError ( " \( input. file. basename) not found in inputDependencySourceMap, \( file) : \( line) in \( function) " )
80
64
}
81
65
return source
82
66
}
83
- @_spi ( Testing) public func getInput( for source: DependencySource ) -> TypedVirtualPath ? {
84
- guard let input = inputDependencySourceMap [ source] else {
67
+
68
+ @_spi ( Testing) public func input( neededFor source: DependencySource ) -> TypedVirtualPath ? {
69
+ guard let input = inputDependencySourceMap. input ( ifKnownFor: source)
70
+ else {
85
71
info. diagnosticEngine. emit ( warning: " Failed to find source file for ' \( source. file. basename) ', recovering with a full rebuild. Next build will be incremental. " )
86
72
return nil
87
73
}
@@ -155,7 +141,7 @@ extension ModuleDependencyGraph {
155
141
return TransitivelyInvalidatedInputSet ( )
156
142
}
157
143
return collectInputsRequiringCompilationAfterProcessing (
158
- dependencySource: getSource ( for : input) )
144
+ dependencySource: source ( requiredFor : input) )
159
145
}
160
146
}
161
147
@@ -177,17 +163,17 @@ extension ModuleDependencyGraph {
177
163
/// speculatively scheduled in the first wave.
178
164
func collectInputsInvalidatedBy( input: TypedVirtualPath
179
165
) -> TransitivelyInvalidatedInputArray {
180
- let changedSource = getSource ( for : input)
166
+ let changedSource = source ( requiredFor : input)
181
167
let allDependencySourcesToRecompile =
182
168
collectSwiftDepsUsing ( dependencySource: changedSource)
183
169
184
170
return allDependencySourcesToRecompile. compactMap {
185
171
depedencySource in
186
172
guard depedencySource != changedSource else { return nil }
187
- let dependentSource = inputDependencySourceMap [ depedencySource]
173
+ let dependentInput = inputDependencySourceMap. input ( ifKnownFor : depedencySource)
188
174
info. reporter? . report (
189
- " Found dependent of \( input. file. basename) : " , dependentSource )
190
- return dependentSource
175
+ " Found dependent of \( input. file. basename) : " , dependentInput )
176
+ return dependentInput
191
177
}
192
178
}
193
179
@@ -204,7 +190,7 @@ extension ModuleDependencyGraph {
204
190
/// Does the graph contain any dependency nodes for a given source-code file?
205
191
func containsNodes( forSourceFile file: TypedVirtualPath ) -> Bool {
206
192
precondition ( file. type == . swift)
207
- guard let source = inputDependencySourceMap [ file] else {
193
+ guard let source = inputDependencySourceMap. sourceIfKnown ( for : file) else {
208
194
return false
209
195
}
210
196
return containsNodes ( forDependencySource: source)
@@ -214,17 +200,46 @@ extension ModuleDependencyGraph {
214
200
return nodeFinder. findNodes ( for: source) . map { !$0. isEmpty}
215
201
?? false
216
202
}
217
-
218
- /// Return true on success
219
- func populateInputDependencySourceMap( ) -> Bool {
203
+
204
+ /// Returns: false on error
205
+ func populateInputDependencySourceMap(
206
+ for purpose: InputDependencySourceMap . AdditionPurpose
207
+ ) -> Bool {
220
208
let ofm = info. outputFileMap
221
- let de = info. diagnosticEngine
222
- return info. inputFiles. reduce ( true ) { okSoFar, input in
223
- ofm. getDependencySource ( for: input, diagnosticEngine: de)
224
- . map { source in addMapEntry ( input, source) ; return okSoFar } ?? false
209
+ let diags = info. diagnosticEngine
210
+ var allFound = true
211
+ for input in info. inputFiles {
212
+ if let source = ofm. dependencySource ( for: input, diagnosticEngine: diags) {
213
+ inputDependencySourceMap. addEntry ( input, source, for: purpose)
214
+ } else {
215
+ // Don't break in order to report all failures.
216
+ allFound = false
217
+ }
225
218
}
219
+ return allFound
226
220
}
227
221
}
222
+ extension OutputFileMap {
223
+ fileprivate func dependencySource(
224
+ for sourceFile: TypedVirtualPath ,
225
+ diagnosticEngine: DiagnosticsEngine
226
+ ) -> DependencySource ? {
227
+ assert ( sourceFile. type == FileType . swift)
228
+ guard let swiftDepsPath = existingOutput ( inputFile: sourceFile. fileHandle,
229
+ outputType: . swiftDeps)
230
+ else {
231
+ // The legacy driver fails silently here.
232
+ diagnosticEngine. emit (
233
+ . remarkDisabled( " \( sourceFile. file. basename) has no swiftDeps file " )
234
+ )
235
+ return nil
236
+ }
237
+ assert ( VirtualPath . lookup ( swiftDepsPath) . extension == FileType . swiftDeps. rawValue)
238
+ let typedSwiftDepsFile = TypedVirtualPath ( file: swiftDepsPath, type: . swiftDeps)
239
+ return DependencySource ( typedSwiftDepsFile)
240
+ }
241
+ }
242
+
228
243
// MARK: - Scheduling the 2nd wave
229
244
extension ModuleDependencyGraph {
230
245
/// After `source` has been compiled, figure out what other source files need compiling.
@@ -234,7 +249,7 @@ extension ModuleDependencyGraph {
234
249
func collectInputsRequiringCompilation( byCompiling input: TypedVirtualPath
235
250
) -> TransitivelyInvalidatedInputSet ? {
236
251
precondition ( input. type == . swift)
237
- let dependencySource = getSource ( for : input)
252
+ let dependencySource = source ( requiredFor : input)
238
253
return collectInputsRequiringCompilationAfterProcessing (
239
254
dependencySource: dependencySource)
240
255
}
@@ -329,7 +344,7 @@ extension ModuleDependencyGraph {
329
344
) -> TransitivelyInvalidatedInputSet ? {
330
345
var invalidatedInputs = TransitivelyInvalidatedInputSet ( )
331
346
for invalidatedSwiftDeps in collectSwiftDepsUsingInvalidated ( nodes: directlyInvalidatedNodes) {
332
- guard let invalidatedInput = getInput ( for : invalidatedSwiftDeps) else {
347
+ guard let invalidatedInput = input ( neededFor : invalidatedSwiftDeps) else {
333
348
return nil
334
349
}
335
350
invalidatedInputs. insert ( invalidatedInput)
@@ -406,27 +421,6 @@ extension ModuleDependencyGraph {
406
421
}
407
422
}
408
423
409
- extension OutputFileMap {
410
- fileprivate func getDependencySource(
411
- for sourceFile: TypedVirtualPath ,
412
- diagnosticEngine: DiagnosticsEngine
413
- ) -> DependencySource ? {
414
- assert ( sourceFile. type == FileType . swift)
415
- guard let swiftDepsPath = existingOutput ( inputFile: sourceFile. fileHandle,
416
- outputType: . swiftDeps)
417
- else {
418
- // The legacy driver fails silently here.
419
- diagnosticEngine. emit (
420
- . remarkDisabled( " \( sourceFile. file. basename) has no swiftDeps file " )
421
- )
422
- return nil
423
- }
424
- assert ( VirtualPath . lookup ( swiftDepsPath) . extension == FileType . swiftDeps. rawValue)
425
- let typedSwiftDepsFile = TypedVirtualPath ( file: swiftDepsPath, type: . swiftDeps)
426
- return DependencySource ( typedSwiftDepsFile)
427
- }
428
- }
429
-
430
424
// MARK: - tracking traced nodes
431
425
extension ModuleDependencyGraph {
432
426
@@ -551,10 +545,11 @@ extension ModuleDependencyGraph {
551
545
. record ( def: dependencyKey, use: self . allNodes [ useID] )
552
546
assert ( isNewUse, " Duplicate use def-use arc in graph? " )
553
547
}
554
- for (input, source) in inputDependencySourceMap {
555
- graph. addMapEntry ( input, source)
548
+ for (input, dependencySource) in inputDependencySourceMap {
549
+ graph. inputDependencySourceMap. addEntry ( input,
550
+ dependencySource,
551
+ for: . readingPriors)
556
552
}
557
-
558
553
return self . graph
559
554
}
560
555
@@ -850,7 +845,7 @@ extension ModuleDependencyGraph {
850
845
}
851
846
}
852
847
853
- for ( input, dependencySource) in graph . inputDependencySourceMap {
848
+ graph . inputDependencySourceMap . enumerateToSerializePriors { input, dependencySource in
854
849
self . addIdentifier ( input. file. name)
855
850
self . addIdentifier ( dependencySource. file. name)
856
851
}
@@ -995,7 +990,8 @@ extension ModuleDependencyGraph {
995
990
}
996
991
}
997
992
}
998
- for (input, dependencySource) in graph. inputDependencySourceMap {
993
+ graph. inputDependencySourceMap. enumerateToSerializePriors {
994
+ input, dependencySource in
999
995
serializer. stream. writeRecord ( serializer. abbreviations [ . mapNode] !) {
1000
996
$0. append ( RecordID . mapNode)
1001
997
$0. append ( serializer. lookupIdentifierCode ( for: input. file. name) )
@@ -1113,7 +1109,7 @@ extension Set where Element == ModuleDependencyGraph.Node {
1113
1109
}
1114
1110
}
1115
1111
1116
- extension BidirectionalMap where T1 == TypedVirtualPath , T2 == DependencySource {
1112
+ extension InputDependencySourceMap {
1117
1113
fileprivate func matches( _ other: Self ) -> Bool {
1118
1114
self == other
1119
1115
}
@@ -1131,6 +1127,6 @@ extension ModuleDependencyGraph {
1131
1127
_ mockInput: TypedVirtualPath ,
1132
1128
_ mockDependencySource: DependencySource
1133
1129
) {
1134
- addMapEntry ( mockInput, mockDependencySource)
1130
+ inputDependencySourceMap . addEntry ( mockInput, mockDependencySource, for : . mocking )
1135
1131
}
1136
1132
}
0 commit comments