Skip to content

Commit a8e4e72

Browse files
authored
[Serialization] Delay all actions in the same module together. (#8123)
Back in December DougG added code to delay the formation of generic environments until all declarations from a particular module had been deserialized, to avoid circular dependencies caused by too-eager deserialization of protocol members. This worked great for fully-built modules, but still had some problems with module merging, the phase of multi-file compilation where the "partial" swiftmodules that correspond to each source file in a target are loaded and remitted as a single swiftmodule. Fix this by picking one of the partial swiftmodules as the representative one for delayed actions, and wait until deserialization is complete for /all/ of the serialized ASTs in the same target to form the generic environments. rdar://problem/30984417
1 parent e78445b commit a8e4e72

File tree

10 files changed

+62
-19
lines changed

10 files changed

+62
-19
lines changed

include/swift/Serialization/ModuleFile.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class ModuleFile : public LazyMemberLoader {
8383
/// Declaration contexts with delayed generic environments, which will be
8484
/// completed as a pending action.
8585
///
86+
/// This should only be used on the module returned by
87+
/// getModuleFileForDelayedActions().
88+
///
8689
/// FIXME: This is needed because completing a generic environment can
8790
/// require the type checker, which might be gone if we delay generic
8891
/// environments too far. It is a hack.
@@ -93,7 +96,8 @@ class ModuleFile : public LazyMemberLoader {
9396
ModuleFile &MF;
9497

9598
public:
96-
DeserializingEntityRAII(ModuleFile &MF) : MF(MF) {
99+
DeserializingEntityRAII(ModuleFile &mf)
100+
: MF(mf.getModuleFileForDelayedActions()) {
97101
++MF.NumCurrentDeserializingEntities;
98102
}
99103
~DeserializingEntityRAII() {
@@ -108,6 +112,13 @@ class ModuleFile : public LazyMemberLoader {
108112
};
109113
friend class DeserializingEntityRAII;
110114

115+
/// Picks a specific ModuleFile instance to serve as the "delayer" for the
116+
/// entire module.
117+
///
118+
/// This is usually \c this, but when there are partial swiftmodules all
119+
/// loaded for the same module it may be different.
120+
ModuleFile &getModuleFileForDelayedActions();
121+
111122
/// Finish any pending actions that were waiting for the topmost entity to
112123
/// be deserialized.
113124
void finishPendingActions();

lib/Serialization/Deserialization.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,24 @@ static bool skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
285285
#endif
286286
}
287287

288+
ModuleFile &ModuleFile::getModuleFileForDelayedActions() {
289+
assert(FileContext && "cannot delay actions before associating with a file");
290+
ModuleDecl *associatedModule = getAssociatedModule();
291+
292+
// Check for the common case.
293+
if (associatedModule->getFiles().size() == 1)
294+
return *this;
295+
296+
for (FileUnit *file : associatedModule->getFiles())
297+
if (auto *serialized = dyn_cast<SerializedASTFile>(file))
298+
return serialized->File;
299+
300+
llvm_unreachable("should always have FileContext in the list of files");
301+
}
302+
288303
void ModuleFile::finishPendingActions() {
304+
assert(&getModuleFileForDelayedActions() == this &&
305+
"wrong module used for delayed actions");
289306
while (!DelayedGenericEnvironments.empty()) {
290307
// Force completion of the last generic environment.
291308
auto genericEnvDC = DelayedGenericEnvironments.back();
@@ -990,7 +1007,8 @@ void ModuleFile::configureGenericEnvironment(
9901007
// creation.
9911008
if (auto genericSig = sigOrEnv.dyn_cast<GenericSignature *>()) {
9921009
genericDecl->setLazyGenericEnvironment(this, genericSig, envID);
993-
DelayedGenericEnvironments.push_back(genericDecl);
1010+
ModuleFile &delayedActionFile = getModuleFileForDelayedActions();
1011+
delayedActionFile.DelayedGenericEnvironments.push_back(genericDecl);
9941012
return;
9951013
}
9961014

lib/Serialization/ModuleFile.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,11 @@ Status ModuleFile::associateWithFileContext(FileUnit *file,
12791279
return getStatus();
12801280
}
12811281

1282-
ModuleFile::~ModuleFile() = default;
1282+
ModuleFile::~ModuleFile() {
1283+
assert(DelayedGenericEnvironments.empty() &&
1284+
"either finishPendingActions() was never called, or someone forgot "
1285+
"to use getModuleFileForDelayedActions()");
1286+
}
12831287

12841288
void ModuleFile::lookupValue(DeclName name,
12851289
SmallVectorImpl<ValueDecl*> &results) {

test/Serialization/Inputs/circular-associated-type/a.swift

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

test/Serialization/Inputs/circular-associated-type/c.swift

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public protocol A {
2+
associatedtype T : B
3+
}
4+
5+
public protocol SubProto30984417: BaseProto30984417 {}

test/Serialization/Inputs/circular-associated-type/b.swift renamed to test/Serialization/Inputs/circular-protocols/b.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ public protocol BB {
55
public protocol B {
66
associatedtype T : BB
77
}
8+
9+
public protocol BaseProto30984417 {
10+
func toConcrete() -> SubProtoImpl30984417
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
extension B {
2+
public init?<T : A>(_: T) where T.T == Self {
3+
return nil
4+
}
5+
}
6+
7+
public class SubProtoImpl30984417: SubProto30984417 {
8+
public func toConcrete() -> SubProtoImpl30984417 { return self }
9+
}

test/Serialization/multi-file-associated-type-circularity.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
3+
// RUN: %target-swift-frontend -emit-module -module-name Multi -o %t/a.swiftmodule -primary-file %S/Inputs/circular-protocols/a.swift %S/Inputs/circular-protocols/b.swift %S/Inputs/circular-protocols/c.swift
4+
// RUN: %target-swift-frontend -emit-module -module-name Multi -o %t/b.swiftmodule -primary-file %S/Inputs/circular-protocols/b.swift %S/Inputs/circular-protocols/a.swift %S/Inputs/circular-protocols/c.swift
5+
// RUN: %target-swift-frontend -emit-module -module-name Multi -o %t/c.swiftmodule -primary-file %S/Inputs/circular-protocols/c.swift %S/Inputs/circular-protocols/a.swift %S/Inputs/circular-protocols/b.swift
6+
7+
// RUN: %target-swift-frontend -parse-as-library -emit-module -module-name Multi %t/a.swiftmodule %t/b.swiftmodule %t/c.swiftmodule -o %t
8+

0 commit comments

Comments
 (0)