Skip to content

Commit 14d4235

Browse files
authored
[Serialization] Fast lookup of nested types in modules with overlays (#20024)
Previously, the fast path for nested types only worked when the nested type was defined in a Swift module or a Clang module without an overlay; this is because it was originally designed to fix circularity issues when merging partial modules for a single target. By having a Swift overlay module pass through requests for nested types to the underlying Clang module, we get the fast-path behavior in more cases. (The one case where it /won't/ kick in is if the overlay has a nested type that shadows a nested type from the Clang module, but that's probably pretty rare!)
1 parent 1c0778b commit 14d4235

File tree

10 files changed

+95
-29
lines changed

10 files changed

+95
-29
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ STATISTIC(NumNormalProtocolConformancesLoaded,
4444
STATISTIC(NumNormalProtocolConformancesCompleted,
4545
"# of normal protocol conformances completed");
4646
STATISTIC(NumNestedTypeShortcuts,
47-
"# of same-module nested types resolved without lookup");
47+
"# of nested types resolved without full lookup");
4848

4949
using namespace swift;
5050
using namespace swift::serialization;
@@ -1444,10 +1444,6 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
14441444
if (!extensionModule)
14451445
extensionModule = baseType->getModuleContext();
14461446

1447-
// FIXME: If 'importedFromClang' is true but 'extensionModule' is an
1448-
// overlay module, the search below will fail and we'll fall back to
1449-
// the slow path.
1450-
14511447
// Fault in extensions, then ask every file in the module.
14521448
(void)baseType->getExtensions();
14531449
TypeDecl *nestedType = nullptr;
@@ -1460,10 +1456,16 @@ ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
14601456
}
14611457

14621458
if (nestedType) {
1463-
values.clear();
1464-
values.push_back(nestedType);
1465-
++NumNestedTypeShortcuts;
1466-
break;
1459+
SmallVector<ValueDecl *, 1> singleValueBuffer{nestedType};
1460+
filterValues(/*expectedTy*/Type(), extensionModule, genericSig,
1461+
/*isType*/true, /*inProtocolExt*/false,
1462+
importedFromClang, /*isStatic*/false, /*ctorInit*/None,
1463+
singleValueBuffer);
1464+
if (!singleValueBuffer.empty()) {
1465+
values.assign({nestedType});
1466+
++NumNestedTypeShortcuts;
1467+
break;
1468+
}
14671469
}
14681470

14691471
pathTrace.removeLast();

lib/Serialization/ModuleFile.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,25 +1575,29 @@ TypeDecl *ModuleFile::lookupNestedType(Identifier name,
15751575
const NominalTypeDecl *parent) {
15761576
PrettyStackTraceModuleFile stackEntry(*this);
15771577

1578-
if (!NestedTypeDecls)
1579-
return nullptr;
1578+
if (NestedTypeDecls) {
1579+
auto iter = NestedTypeDecls->find(name);
1580+
if (iter != NestedTypeDecls->end()) {
1581+
for (std::pair<DeclID, DeclID> entry : *iter) {
1582+
assert(entry.first);
1583+
auto declOrOffset = Decls[entry.first - 1];
1584+
if (!declOrOffset.isComplete())
1585+
continue;
15801586

1581-
auto iter = NestedTypeDecls->find(name);
1582-
if (iter == NestedTypeDecls->end())
1583-
return nullptr;
1587+
Decl *decl = declOrOffset;
1588+
if (decl != parent)
1589+
continue;
1590+
return cast<TypeDecl>(getDecl(entry.second));
1591+
}
1592+
}
1593+
}
15841594

1585-
auto data = *iter;
1586-
for (std::pair<DeclID, DeclID> entry : data) {
1587-
assert(entry.first);
1588-
auto declOrOffset = Decls[entry.first - 1];
1589-
if (!declOrOffset.isComplete())
1590-
continue;
1595+
if (!ShadowedModule)
1596+
return nullptr;
15911597

1592-
Decl *decl = declOrOffset;
1593-
if (decl != parent)
1594-
continue;
1595-
return cast<TypeDecl>(getDecl(entry.second));
1596-
}
1598+
for (FileUnit *file : ShadowedModule->getFiles())
1599+
if (auto *nestedType = file->lookupNestedType(name, parent))
1600+
return nestedType;
15971601

15981602
return nullptr;
15991603
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
struct Base {
2+
int dummy;
3+
};
4+
5+
struct Nested {
6+
int dummy;
7+
} __attribute((swift_name("Base.NestedFromClang")));
8+
9+
struct NestedAndShadowed {
10+
int dummy;
11+
} __attribute((swift_name("Base.NestedAndShadowed")));
12+
13+
struct NestedAndShadowed getShadowedFromClang();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module HasOverlay {
2+
header "HasOverlay.h"
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@_exported import HasOverlay
2+
3+
extension Base {
4+
public struct NestedFromSwift {}
5+
public struct NestedAndShadowed {
6+
init(dummy: ()) {}
7+
}
8+
}
9+
10+
public var shadowedFromSwift = Base.NestedAndShadowed(dummy: ())
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import main
2+
import HasOverlay
3+
4+
func test() {
5+
var a = getShadowedFromClang()
6+
a = main.shadowedFromClang // okay
7+
a = HasOverlay.shadowedFromSwift // expected-error {{cannot assign}}
8+
9+
var b = HasOverlay.shadowedFromSwift
10+
b = main.shadowedFromSwift // okay
11+
b = getShadowedFromClang() // expected-error {{cannot assign}}
12+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// REQUIRES: asserts
99

1010
// CHECK: Statistics
11-
// CHECK: 1 Serialization - # of same-module nested types resolved without lookup
11+
// CHECK: 1 Serialization - # of nested types resolved without full lookup
1212

1313
// Note the Optional here and below; this was once necessary to produce a crash.
1414
// Without it, the type of the parameter is initialized "early" enough to not

test/Serialization/multi-file-nested-type-extension.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// REQUIRES: asserts
1111

1212
// CHECK: Statistics
13-
// CHECK: 1 Serialization - # of same-module nested types resolved without lookup
13+
// CHECK: 1 Serialization - # of nested types resolved without full lookup
1414

1515
// Note the Optional here and below; this was once necessary to produce a crash.
1616
// Without it, the type of the parameter is initialized "early" enough to not

test/Serialization/multi-file-nested-type-simple.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515

1616
// REQUIRES: asserts
1717

18-
// CHECK: 4 Serialization - # of same-module nested types resolved without lookup
18+
// CHECK: 4 Serialization - # of nested types resolved without full lookup
1919
// DISABLED: Statistics
20-
// DISABLED-NOT: same-module nested types resolved without lookup
20+
// DISABLED-NOT: nested types resolved without full lookup
2121

2222
public func useTypes(
2323
_: Outer.Inner,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/HasOverlay.swiftmodule %S/Inputs/nested-type-with-overlay/overlay.swift -I %S/Inputs/nested-type-with-overlay -module-name HasOverlay
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/main~partial.swiftmodule -primary-file %s -module-name main -I %t -I %S/Inputs/nested-type-helper
5+
// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/main.swiftmodule %t/main~partial.swiftmodule -print-stats -module-name main -I %t -I %S/Inputs/nested-type-with-overlay 2>&1 | %FileCheck %s
6+
7+
// RUN: %target-swift-frontend -emit-silgen %S/Inputs/nested-type-with-overlay/verify.swift -I %t -I %S/Inputs/nested-type-with-overlay -verify
8+
9+
// REQUIRES: asserts
10+
11+
// CHECK: 3 Serialization - # of nested types resolved without full lookup
12+
// Unfortunately this isn't 4 because of the shadowed nested type from Clang.
13+
14+
import HasOverlay
15+
16+
public func resolveNestedTypes(
17+
_: Base.NestedFromClang,
18+
_: Base.NestedFromSwift
19+
) {}
20+
21+
public var shadowedFromClang = getShadowedFromClang()
22+
public var shadowedFromSwift = HasOverlay.shadowedFromSwift

0 commit comments

Comments
 (0)