Skip to content

Commit 43a9f54

Browse files
committed
Repair Fingerprint Lookup Across Modules
Cross-module incremental builds require a stable source of fingerprint information for iterable decl contexts. This is provided by the incremental frontends when they produce partial swift module files. Embedded in these files is a table of fingerprints, which are consumed by merge-modules to construct a module-wide dependency graph that is then serialized into the final merged swift module file. Unfortunately, the implementation here iterated through the files in the module and asked for the first fingerprint that would load for a particular iterable decl context. If (more likely, when) the DeclID for that serialized iterable decl context collided with another DeclID in the wrong file, we would load that fingerprint instead. Locate up to the module-scope context for an iterable decl context and only load the fingerprint from there. This ensures that the fingerprints in the partial modules matches the fingerprints in the merged modules. rdar://77005039
1 parent 5900a0f commit 43a9f54

File tree

6 files changed

+45
-14
lines changed

6 files changed

+45
-14
lines changed

include/swift/AST/Module.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,6 @@ class ModuleDecl : public DeclContext, public TypeDecl {
594594
ObjCSelector selector,
595595
SmallVectorImpl<AbstractFunctionDecl *> &results) const;
596596

597-
Optional<Fingerprint>
598-
loadFingerprint(const IterableDeclContext *IDC) const;
599-
600597
/// Find all SPI names imported from \p importedModule by this module,
601598
/// collecting the identifiers in \p spiGroups.
602599
void lookupImportedSPIGroups(

lib/AST/Module.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -680,15 +680,6 @@ void ModuleDecl::lookupObjCMethods(
680680
FORWARD(lookupObjCMethods, (selector, results));
681681
}
682682

683-
Optional<Fingerprint>
684-
ModuleDecl::loadFingerprint(const IterableDeclContext *IDC) const {
685-
for (auto file : getFiles()) {
686-
if (auto FP = file->loadFingerprint(IDC))
687-
return FP;
688-
}
689-
return None;
690-
}
691-
692683
void ModuleDecl::lookupImportedSPIGroups(
693684
const ModuleDecl *importedModule,
694685
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {

lib/Parse/ParseRequests.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ ParseMembersRequest::evaluate(Evaluator &evaluator,
5252
IterableDeclContext *idc) const {
5353
SourceFile *sf = idc->getAsGenericContext()->getParentSourceFile();
5454
ASTContext &ctx = idc->getDecl()->getASTContext();
55+
auto fileUnit
56+
= dyn_cast<FileUnit>(idc->getAsGenericContext()->getModuleScopeContext());
5557
if (!sf) {
5658
// If there is no parent source file, this is a deserialized or synthesized
5759
// declaration context, in which case `getMembers()` has all of the members.
@@ -64,8 +66,8 @@ ParseMembersRequest::evaluate(Evaluator &evaluator,
6466
}
6567

6668
Optional<Fingerprint> fp = None;
67-
if (!idc->getDecl()->isImplicit()) {
68-
fp = idc->getDecl()->getModuleContext()->loadFingerprint(idc);
69+
if (!idc->getDecl()->isImplicit() && fileUnit) {
70+
fp = fileUnit->loadFingerprint(idc);
6971
}
7072
return FingerprintAndMembers{fp, ctx.AllocateCopy(members)};
7173
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public final class ClsA {
2+
public static func doit(value: Bool = true) {
3+
print("value: \(value)")
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public final class ClsA {
2+
public static func doit(value: Bool = false) {
3+
print("value: \(value)")
4+
}
5+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: cp %S/Inputs/incremental-imports/* %t
3+
// RUN: cp %t/A{-before,}.swift
4+
5+
6+
// RUN: %target-swift-frontend -emit-module -module-name IncrementalImports -o %t/IncrementalImports~A.swiftmodule -primary-file %t/A.swift
7+
// RUN: %target-swift-frontend -merge-modules -emit-module -module-name IncrementalImports -o %t/IncrementalImports.swiftmodule %t/IncrementalImports~A.swiftmodule
8+
9+
// RUN: llvm-bcanalyzer -dump %t/IncrementalImports.swiftmodule | %FileCheck %s --check-prefix=INCREMENTAL-IMPORTS-BASELINE
10+
11+
// INCREMENTAL-IMPORTS-BASELINE-LABEL: <INCREMENTAL_INFORMATION_BLOCK
12+
// Test for the fingerprint for the class
13+
// INCREMENTAL-IMPORTS-BASELINE-DAG: blob data = '7de0a38047d74950f4f2ced447ab0242'
14+
// And for its member
15+
// INCREMENTAL-IMPORTS-BASELINE-DAG: blob data = 'e79735e7b1e8c65831c70766207a75f3'
16+
// INCREMENTAL-IMPORTS-BASELINE-LABEL: </INCREMENTAL_INFORMATION_BLOCK>
17+
18+
// RUN: %empty-directory(%t)
19+
// RUN: cp %S/Inputs/incremental-imports/* %t
20+
// RUN: cp %t/A{-after,}.swift
21+
// RUN: %target-swift-frontend -emit-module -module-name IncrementalImports -o %t/IncrementalImports~A.swiftmodule -primary-file %t/A.swift
22+
// RUN: %target-swift-frontend -merge-modules -emit-module -module-name IncrementalImports -o %t/IncrementalImports.swiftmodule %t/IncrementalImports~A.swiftmodule
23+
24+
// RUN: llvm-bcanalyzer -dump %t/IncrementalImports.swiftmodule | %FileCheck %s --check-prefix=INCREMENTAL-IMPORTS-MUTATION
25+
26+
// INCREMENTAL-IMPORTS-MUTATION-LABEL: <INCREMENTAL_INFORMATION_BLOCK
27+
// Make sure the fingerprint for the class doesn't change
28+
// INCREMENTAL-IMPORTS-MUTATION-DAG: blob data = '7de0a38047d74950f4f2ced447ab0242'
29+
// Make sure the fingerprint for the member changes
30+
// INCREMENTAL-IMPORTS-MUTATION-DAG: blob data = '99bb01bb4d9177dc6f902d1f2326caad'
31+
// INCREMENTAL-IMPORTS-MUTATION-LABEL: </INCREMENTAL_INFORMATION_BLOCK>

0 commit comments

Comments
 (0)