Skip to content

Commit d0e4ba3

Browse files
committed
Serialization: Use nested type lookup table for cross-module references also
Fixes a class of deserialization issues in the merge-modules step. The setup was the following: - File A defines a typealias A whose underlying type is a nested type S of a type T, defined in a different module. - File B defines an extension of T, and the extension member's type references A. When deserializing A, we would proceed to deserialize the underlying type, which references T.S. This would first deserialize T and perform a name lookup to find S, which would deserialize all members, including pulling in extensions. Deserialization of the extension defined in file B would then fail, because the declaration for A is not yet available. We had a previous fix for these problems in the single-module case; a per-file lookup table mapping mangled nested type names to declarations, allowing a nested type to be deserialized without pulling in all members and extensions of its parent type. This patch generalizes the nested type lookup table allowing it to be used to resolve cross-module references as well. Also, we were only writing out the nested type table when serializing a partial swiftmodule corresponding to a source file. Removing this check allows the nested type table to be serialized for modules built with WMO enabled as well, such as the standard library. Fixes <rdar://problem/30976604> and <https://bugs.swift.org/browse/SR-4208>.
1 parent bb4d90f commit d0e4ba3

File tree

5 files changed

+71
-46
lines changed

5 files changed

+71
-46
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,55 +1338,55 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
13381338
case XREF_TYPE_PATH_PIECE: {
13391339
if (values.size() == 1) {
13401340
ModuleDecl *module = values.front()->getModuleContext();
1341-
if (module == this->getAssociatedModule()) {
1342-
// Fast path for nested types in the same module.
1343-
IdentifierID IID;
1344-
bool onlyInNominal = false;
1345-
XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
1346-
Identifier memberName = getIdentifier(IID);
1347-
pathTrace.addValue(memberName);
1348-
1349-
llvm::PrettyStackTraceString message{
1350-
"If you're seeing a crash here, try passing "
1351-
"-Xfrontend -disable-serialization-nested-type-lookup-table"};
1352-
1353-
TypeDecl *nestedType = nullptr;
1354-
if (onlyInNominal) {
1355-
// Only look in the file containing the type itself.
1356-
const DeclContext *dc = values.front()->getDeclContext();
1357-
auto *serializedFile =
1358-
dyn_cast<SerializedASTFile>(dc->getModuleScopeContext());
1359-
if (serializedFile) {
1360-
nestedType =
1361-
serializedFile->File.lookupNestedType(memberName,
1362-
values.front());
1363-
}
1364-
} else {
1365-
// Fault in extensions, then ask every serialized AST in the module.
1366-
(void)cast<NominalTypeDecl>(values.front())->getExtensions();
1367-
for (FileUnit *file : module->getFiles()) {
1368-
if (file == getFile())
1369-
continue;
1370-
auto *serializedFile = dyn_cast<SerializedASTFile>(file);
1371-
if (!serializedFile)
1372-
continue;
1373-
nestedType =
1374-
serializedFile->File.lookupNestedType(memberName,
1375-
values.front());
1376-
if (nestedType)
1377-
break;
1378-
}
1379-
}
13801341

1381-
if (nestedType) {
1382-
values.clear();
1383-
values.push_back(nestedType);
1384-
++NumNestedTypeShortcuts;
1385-
break;
1342+
// Fast path for nested types that avoids deserializing all
1343+
// members of the parent type.
1344+
IdentifierID IID;
1345+
bool onlyInNominal = false;
1346+
XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
1347+
Identifier memberName = getIdentifier(IID);
1348+
pathTrace.addValue(memberName);
1349+
1350+
llvm::PrettyStackTraceString message{
1351+
"If you're seeing a crash here, try passing "
1352+
"-Xfrontend -disable-serialization-nested-type-lookup-table"};
1353+
1354+
TypeDecl *nestedType = nullptr;
1355+
if (onlyInNominal) {
1356+
// Only look in the file containing the type itself.
1357+
const DeclContext *dc = values.front()->getDeclContext();
1358+
auto *serializedFile =
1359+
dyn_cast<SerializedASTFile>(dc->getModuleScopeContext());
1360+
if (serializedFile) {
1361+
nestedType =
1362+
serializedFile->File.lookupNestedType(memberName,
1363+
values.front());
13861364
}
1365+
} else {
1366+
// Fault in extensions, then ask every serialized AST in the module.
1367+
(void)cast<NominalTypeDecl>(values.front())->getExtensions();
1368+
for (FileUnit *file : module->getFiles()) {
1369+
if (file == getFile())
1370+
continue;
1371+
auto *serializedFile = dyn_cast<SerializedASTFile>(file);
1372+
if (!serializedFile)
1373+
continue;
1374+
nestedType =
1375+
serializedFile->File.lookupNestedType(memberName,
1376+
values.front());
1377+
if (nestedType)
1378+
break;
1379+
}
1380+
}
13871381

1388-
pathTrace.removeLast();
1382+
if (nestedType) {
1383+
values.clear();
1384+
values.push_back(nestedType);
1385+
++NumNestedTypeShortcuts;
1386+
break;
13891387
}
1388+
1389+
pathTrace.removeLast();
13901390
}
13911391
LLVM_FALLTHROUGH;
13921392
}

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4445,7 +4445,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC,
44454445
index_block::ObjCMethodTableLayout ObjCMethodTable(Out);
44464446
writeObjCMethodTable(ObjCMethodTable, objcMethods);
44474447

4448-
if (DC.is<SourceFile *>() && enableNestedTypeLookupTable &&
4448+
if (enableNestedTypeLookupTable &&
44494449
!nestedTypeDecls.empty()) {
44504450
index_block::NestedTypeDeclsLayout NestedTypeDeclsTable(Out);
44514451
writeNestedTypeDeclsTable(NestedTypeDeclsTable, nestedTypeDecls);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public struct X {
2+
public typealias A = Int
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import other
2+
3+
typealias B = X.A
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
3+
// Build the other module, which consists of a single source file.
4+
5+
// RUN: %target-swift-frontend -emit-module -module-name other -o %t/multi-module-nested-type-1.swiftmodule -primary-file %S/Inputs/multi-module-nested-type-1.swift
6+
// RUN: %target-swift-frontend -emit-module -module-name other -o %t/other.swiftmodule %t/multi-module-nested-type-1.swiftmodule
7+
8+
// Build this module, which consists of two source files.
9+
10+
// RUN: %target-swift-frontend -emit-module -module-name me -o %t/multi-module-nested-type-2.swiftmodule -primary-file %S/Inputs/multi-module-nested-type-2.swift %s -I %t
11+
// RUN: %target-swift-frontend -emit-module -module-name me -o %t/multi-module-nested-type-3.swiftmodule %S/Inputs/multi-module-nested-type-2.swift -primary-file %s -I %t
12+
13+
// RUN: %target-swift-frontend -emit-module -module-name me -o %t/me.swiftmodule %t/multi-module-nested-type-2.swiftmodule %t/multi-module-nested-type-3.swiftmodule -I %t
14+
15+
import other
16+
17+
extension X {
18+
func takesB(_: B) {}
19+
}

0 commit comments

Comments
 (0)