@@ -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,32 +54,15 @@ 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 {
79
- fatalError ( " \( input. file) not found in map: \( inputDependencySourceMap) , \( file) : \( line) in \( function) " )
80
- }
81
- return source
82
- }
83
-
84
- @_spi ( Testing) public func getInput( for source: DependencySource ) -> TypedVirtualPath ? {
85
- guard let input =
86
- info. simulateGetInputFailure ? nil
87
- : inputDependencySourceMap [ source]
57
+ @_spi ( Testing) public func sourceRequired( for input: TypedVirtualPath ,
58
+ function: String = #function,
59
+ file: String = #file,
60
+ line: Int = #line) -> DependencySource {
61
+ guard let source = inputDependencySourceMap. sourceIfKnown ( for: input)
88
62
else {
89
- info. diagnosticEngine. emit ( warning: " Failed to find source file for ' \( source. file. basename) ', recovering with a full rebuild. Next build will be incremental. " )
90
- info. reporter? . report (
91
- " \( info. simulateGetInputFailure ? " Simulating i " : " I " ) nput not found in inputDependencySourceMap; created for: \( creationPhase) , now: \( phase) " )
92
- return nil
63
+ fatalError ( " \( input. file. basename) not found in inputDependencySourceMap, \( file) : \( line) in \( function) " )
93
64
}
94
- return input
65
+ return source
95
66
}
96
67
}
97
68
@@ -161,7 +132,7 @@ extension ModuleDependencyGraph {
161
132
return TransitivelyInvalidatedInputSet ( )
162
133
}
163
134
return collectInputsRequiringCompilationAfterProcessing (
164
- dependencySource: getSource ( for: input) )
135
+ dependencySource: sourceRequired ( for: input) )
165
136
}
166
137
}
167
138
@@ -183,17 +154,16 @@ extension ModuleDependencyGraph {
183
154
/// speculatively scheduled in the first wave.
184
155
func collectInputsInvalidatedBy( input: TypedVirtualPath
185
156
) -> TransitivelyInvalidatedInputArray {
186
- let changedSource = getSource ( for: input)
157
+ let changedSource = sourceRequired ( for: input)
187
158
let allDependencySourcesToRecompile =
188
159
collectSwiftDepsUsing ( dependencySource: changedSource)
189
160
190
161
return allDependencySourcesToRecompile. compactMap {
191
162
dependencySource in
192
163
guard dependencySource != changedSource else { return nil }
193
- let dependentSource = inputDependencySourceMap [ dependencySource]
194
- info. reporter? . report (
195
- " Found dependent of \( input. file. basename) : " , dependentSource)
196
- return dependentSource
164
+ let inputToRecompile = inputDependencySourceMap. inputIfKnown ( for: dependencySource)
165
+ info. reporter? . report ( " Found dependent of \( input. file. basename) : " , inputToRecompile)
166
+ return inputToRecompile
197
167
}
198
168
}
199
169
@@ -210,7 +180,7 @@ extension ModuleDependencyGraph {
210
180
/// Does the graph contain any dependency nodes for a given source-code file?
211
181
func containsNodes( forSourceFile file: TypedVirtualPath ) -> Bool {
212
182
precondition ( file. type == . swift)
213
- guard let source = inputDependencySourceMap [ file] else {
183
+ guard let source = inputDependencySourceMap. sourceIfKnown ( for : file) else {
214
184
return false
215
185
}
216
186
return containsNodes ( forDependencySource: source)
@@ -220,17 +190,46 @@ extension ModuleDependencyGraph {
220
190
return nodeFinder. findNodes ( for: source) . map { !$0. isEmpty}
221
191
?? false
222
192
}
223
-
224
- /// Return true on success
225
- func populateInputDependencySourceMap( ) -> Bool {
193
+
194
+ /// - Returns: false on error
195
+ func populateInputDependencySourceMap(
196
+ `for` purpose: InputDependencySourceMap . AdditionPurpose
197
+ ) -> Bool {
226
198
let ofm = info. outputFileMap
227
- let de = info. diagnosticEngine
228
- return info. inputFiles. reduce ( true ) { okSoFar, input in
229
- ofm. getDependencySource ( for: input, diagnosticEngine: de)
230
- . map { source in addMapEntry ( input, source) ; return okSoFar } ?? false
199
+ let diags = info. diagnosticEngine
200
+ var allFound = true
201
+ for input in info. inputFiles {
202
+ if let source = ofm. dependencySource ( for: input, diagnosticEngine: diags) {
203
+ inputDependencySourceMap. addEntry ( input, source, for: purpose)
204
+ } else {
205
+ // Don't break in order to report all failures.
206
+ allFound = false
207
+ }
208
+ }
209
+ return allFound
210
+ }
211
+ }
212
+ extension OutputFileMap {
213
+ fileprivate func dependencySource(
214
+ for sourceFile: TypedVirtualPath ,
215
+ diagnosticEngine: DiagnosticsEngine
216
+ ) -> DependencySource ? {
217
+ assert ( sourceFile. type == FileType . swift)
218
+ guard let swiftDepsPath = existingOutput ( inputFile: sourceFile. fileHandle,
219
+ outputType: . swiftDeps)
220
+ else {
221
+ // The legacy driver fails silently here.
222
+ diagnosticEngine. emit (
223
+ . remarkDisabled( " \( sourceFile. file. basename) has no swiftDeps file " )
224
+ )
225
+ return nil
231
226
}
227
+ assert ( VirtualPath . lookup ( swiftDepsPath) . extension == FileType . swiftDeps. rawValue)
228
+ let typedSwiftDepsFile = TypedVirtualPath ( file: swiftDepsPath, type: . swiftDeps)
229
+ return DependencySource ( typedSwiftDepsFile)
232
230
}
233
231
}
232
+
234
233
// MARK: - Scheduling the 2nd wave
235
234
extension ModuleDependencyGraph {
236
235
/// After `source` has been compiled, figure out what other source files need compiling.
@@ -240,7 +239,7 @@ extension ModuleDependencyGraph {
240
239
func collectInputsRequiringCompilation( byCompiling input: TypedVirtualPath
241
240
) -> TransitivelyInvalidatedInputSet ? {
242
241
precondition ( input. type == . swift)
243
- let dependencySource = getSource ( for: input)
242
+ let dependencySource = sourceRequired ( for: input)
244
243
return collectInputsRequiringCompilationAfterProcessing (
245
244
dependencySource: dependencySource)
246
245
}
@@ -327,8 +326,10 @@ extension ModuleDependencyGraph {
327
326
) -> TransitivelyInvalidatedInputSet ? {
328
327
var invalidatedInputs = TransitivelyInvalidatedInputSet ( )
329
328
for invalidatedSwiftDeps in collectSwiftDepsUsingInvalidated ( nodes: directlyInvalidatedNodes) {
330
- guard let invalidatedInput = getInput ( for: invalidatedSwiftDeps)
329
+ guard let invalidatedInput = inputDependencySourceMap . inputIfKnown ( for: invalidatedSwiftDeps)
331
330
else {
331
+ info. diagnosticEngine. emit (
332
+ warning: " Failed to find source file for ' \( invalidatedSwiftDeps. file. basename) ', recovering with a full rebuild. Next build will be incremental. " )
332
333
return nil
333
334
}
334
335
invalidatedInputs. insert ( invalidatedInput)
@@ -405,27 +406,6 @@ extension ModuleDependencyGraph {
405
406
}
406
407
}
407
408
408
- extension OutputFileMap {
409
- fileprivate func getDependencySource(
410
- for sourceFile: TypedVirtualPath ,
411
- diagnosticEngine: DiagnosticsEngine
412
- ) -> DependencySource ? {
413
- assert ( sourceFile. type == FileType . swift)
414
- guard let swiftDepsPath = existingOutput ( inputFile: sourceFile. fileHandle,
415
- outputType: . swiftDeps)
416
- else {
417
- // The legacy driver fails silently here.
418
- diagnosticEngine. emit (
419
- . remarkDisabled( " \( sourceFile. file. basename) has no swiftDeps file " )
420
- )
421
- return nil
422
- }
423
- assert ( VirtualPath . lookup ( swiftDepsPath) . extension == FileType . swiftDeps. rawValue)
424
- let typedSwiftDepsFile = TypedVirtualPath ( file: swiftDepsPath, type: . swiftDeps)
425
- return DependencySource ( typedSwiftDepsFile)
426
- }
427
- }
428
-
429
409
// MARK: - tracking traced nodes
430
410
extension ModuleDependencyGraph {
431
411
@@ -550,10 +530,11 @@ extension ModuleDependencyGraph {
550
530
. record ( def: dependencyKey, use: self . allNodes [ useID] )
551
531
assert ( isNewUse, " Duplicate use def-use arc in graph? " )
552
532
}
553
- for (input, source) in inputDependencySourceMap {
554
- graph. addMapEntry ( input, source)
533
+ for (input, dependencySource) in inputDependencySourceMap {
534
+ graph. inputDependencySourceMap. addEntry ( input,
535
+ dependencySource,
536
+ for: . readingPriors)
555
537
}
556
-
557
538
return self . graph
558
539
}
559
540
@@ -849,7 +830,7 @@ extension ModuleDependencyGraph {
849
830
}
850
831
}
851
832
852
- for ( input, dependencySource) in graph . inputDependencySourceMap {
833
+ graph . inputDependencySourceMap . enumerateToSerializePriors { input, dependencySource in
853
834
self . addIdentifier ( input. file. name)
854
835
self . addIdentifier ( dependencySource. file. name)
855
836
}
@@ -994,7 +975,8 @@ extension ModuleDependencyGraph {
994
975
}
995
976
}
996
977
}
997
- for (input, dependencySource) in graph. inputDependencySourceMap {
978
+ graph. inputDependencySourceMap. enumerateToSerializePriors {
979
+ input, dependencySource in
998
980
serializer. stream. writeRecord ( serializer. abbreviations [ . mapNode] !) {
999
981
$0. append ( RecordID . mapNode)
1000
982
$0. append ( serializer. lookupIdentifierCode ( for: input. file. name) )
@@ -1112,7 +1094,7 @@ extension Set where Element == ModuleDependencyGraph.Node {
1112
1094
}
1113
1095
}
1114
1096
1115
- extension BidirectionalMap where T1 == TypedVirtualPath , T2 == DependencySource {
1097
+ extension InputDependencySourceMap {
1116
1098
fileprivate func matches( _ other: Self ) -> Bool {
1117
1099
self == other
1118
1100
}
@@ -1130,6 +1112,6 @@ extension ModuleDependencyGraph {
1130
1112
_ mockInput: TypedVirtualPath ,
1131
1113
_ mockDependencySource: DependencySource
1132
1114
) {
1133
- addMapEntry ( mockInput, mockDependencySource)
1115
+ inputDependencySourceMap . addEntry ( mockInput, mockDependencySource, for : . mocking )
1134
1116
}
1135
1117
}
0 commit comments