Skip to content

Commit 141c96f

Browse files
committed
Account for multiple modules when looking up the DeclContext of a type
When looking up the decl context of a type, ASTDemangler has to take into account that there are multiple different modules where that type could've come from. This is due to two facts: - Thanks to the `-module-abi-name` flag, multiple modules can share the same ABI name (which is the module name that is usually used when mangling a type). - In some situations mangling can use the module's real name, for example, when mangling for the debugger or USRs coupled with @_originallyDefinedIn. rdar://134095412
1 parent db0b5db commit 141c96f

File tree

8 files changed

+221
-46
lines changed

8 files changed

+221
-46
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,10 +1200,15 @@ class ASTContext final {
12001200

12011201
ModuleDecl *getModuleByIdentifier(Identifier ModuleID);
12021202

1203-
/// Looks up an already loaded module by its ABI name.
1203+
/// Looks up all modules whose real name or ABI name match ModuleName.
12041204
///
1205-
/// \returns The module if found, nullptr otherwise.
1206-
ModuleDecl *getLoadedModuleByABIName(StringRef ModuleName);
1205+
/// Modules that are being looked up by ABI name are only found if they are a
1206+
/// dependency of a module that has that same name as its real name, as there
1207+
/// is no efficient way to lazily load a module by ABI name.
1208+
llvm::ArrayRef<ModuleDecl *> getModulesByRealOrABIName(StringRef ModuleName);
1209+
1210+
/// Notifies the AST context that a loaded module's ABI name will change.
1211+
void moduleABINameWillChange(ModuleDecl *module, Identifier newName);
12071212

12081213
/// Returns the standard library module, or null if the library isn't present.
12091214
///

include/swift/AST/ASTDemangler.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,13 @@ class ASTBuilder {
254254
NominalTypeDecl *nominalDecl,
255255
NodePointer node);
256256
DeclContext *findDeclContext(NodePointer node);
257-
ModuleDecl *findModule(NodePointer node);
257+
258+
/// Find all the ModuleDecls that correspond to a module node's identifier.
259+
/// The module name encoded in the node is either the module's real or ABI
260+
/// name. Multiple modules can share the same name. This function returns
261+
/// all modules that contain that name.
262+
llvm::ArrayRef<ModuleDecl *> findPotentialModules(NodePointer node);
263+
258264
Demangle::NodePointer findModuleNode(NodePointer node);
259265

260266
enum class ForeignModuleKind {

include/swift/AST/Module.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,9 +473,7 @@ class ModuleDecl
473473
Identifier getABIName() const;
474474

475475
/// Set the ABI name of the module;
476-
void setABIName(Identifier name) {
477-
ModuleABIName = name;
478-
}
476+
void setABIName(Identifier name);
479477

480478
/// Get the package name of this module
481479
/// FIXME: remove this and bump module version rdar://104723918

lib/AST/ASTContext.cpp

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ struct ASTContext::Implementation {
275275
/// DenseMap.
276276
llvm::MapVector<Identifier, ModuleDecl *> LoadedModules;
277277

278+
/// The map from a module's name to a vector of modules that share that name.
279+
/// The name can be either the module's real name of the module's ABI name.
280+
llvm::DenseMap<Identifier, llvm::SmallVector<ModuleDecl *, 1>> NameToModules;
281+
278282
// FIXME: This is a StringMap rather than a StringSet because StringSet
279283
// doesn't allow passing in a pre-existing allocator.
280284
llvm::StringMap<Identifier::Aligner, llvm::BumpPtrAllocator&>
@@ -839,6 +843,7 @@ void ASTContext::Implementation::dump(llvm::raw_ostream &os) const {
839843
<< llvm::capacity_in_bytes(Name) << "\n"
840844

841845
SIZE(LoadedModules);
846+
SIZE(NameToModules);
842847
SIZE(IdentifierTable);
843848
SIZE(Cleanups);
844849
SIZE_AND_BYTES(ModuleLoaders);
@@ -2323,12 +2328,63 @@ void ASTContext::addLoadedModule(ModuleDecl *M) {
23232328
// and a source file has 'import Foo', a module called Bar (real name)
23242329
// will be loaded and added to the map.
23252330
getImpl().LoadedModules[M->getRealName()] = M;
2331+
2332+
// Add the module to the mapping from module name to list of modules that
2333+
// share that name.
2334+
getImpl().NameToModules[M->getRealName()].push_back(M);
2335+
2336+
// If the ABI name differs from the real name, also add the module to the list
2337+
// that share that ABI name.
2338+
if (M->getRealName() != M->getABIName())
2339+
getImpl().NameToModules[M->getABIName()].push_back(M);
23262340
}
23272341

23282342
void ASTContext::removeLoadedModule(Identifier RealName) {
2343+
// First remove the module from the mappings of names to modules.
2344+
if (ModuleDecl *M = getLoadedModule(RealName)) {
2345+
auto eraseModule = [&](ModuleDecl *module) {
2346+
return module->getRealName() == RealName;
2347+
};
2348+
auto &vector = getImpl().NameToModules[M->getRealName()];
2349+
llvm::erase_if(vector, eraseModule);
2350+
if (M->getRealName() != M->getABIName()) {
2351+
auto &vector = getImpl().NameToModules[M->getABIName()];
2352+
llvm::erase_if(vector, eraseModule);
2353+
}
2354+
}
2355+
23292356
getImpl().LoadedModules.erase(RealName);
23302357
}
23312358

2359+
void ASTContext::moduleABINameWillChange(ModuleDecl *module,
2360+
Identifier newName) {
2361+
auto it = llvm::find_if(getLoadedModules(),
2362+
[&](auto pair) { return pair.second == module; });
2363+
2364+
// If this module isn't in the loaded modules list (perhaps because there is
2365+
// no memory cache) theere's nothing to do.
2366+
if (it == getLoadedModules().end())
2367+
return;
2368+
2369+
// If the names are the same there's nothing to do.
2370+
if (module->getABIName() == newName)
2371+
return;
2372+
2373+
// If the real and ABI names are different, ASTContext needs to remove the
2374+
// module from the mapping whose key is the old ABI name.
2375+
if (module->getRealName() != module->getABIName()) {
2376+
auto &vector = getImpl().NameToModules[module->getABIName()];
2377+
llvm::erase_if(vector,
2378+
[&](ModuleDecl *current) { return module == current; });
2379+
}
2380+
2381+
// Now add the module to the vector that's mapped from the new name, if it's
2382+
// not there already.
2383+
auto &vector = getImpl().NameToModules[newName];
2384+
if (llvm::find(vector, module) == vector.end())
2385+
vector.push_back(module);
2386+
}
2387+
23322388
void ASTContext::setIgnoreAdjacentModules(bool value) {
23332389
IgnoreAdjacentModules = value;
23342390
}
@@ -2715,12 +2771,21 @@ ModuleDecl *ASTContext::getModuleByIdentifier(Identifier ModuleID) {
27152771
return getModule(builder.get());
27162772
}
27172773

2718-
ModuleDecl *ASTContext::getLoadedModuleByABIName(StringRef ModuleName) {
2719-
for (auto &[_, module] : getLoadedModules()) {
2720-
if (ModuleName == module->getABIName().str())
2721-
return module;
2722-
}
2723-
return nullptr;
2774+
llvm::ArrayRef<ModuleDecl *>
2775+
ASTContext::getModulesByRealOrABIName(StringRef ModuleName) {
2776+
auto Identifier = getIdentifier(ModuleName);
2777+
auto it = getImpl().NameToModules.find(Identifier);
2778+
if (it != getImpl().NameToModules.end())
2779+
return it->second;
2780+
2781+
// If we didn't find the module it might have not been loaded yet, try
2782+
// triggering a module load and searching again.
2783+
getModuleByName(ModuleName);
2784+
it = getImpl().NameToModules.find(Identifier);
2785+
if (it != getImpl().NameToModules.end())
2786+
return it->second;
2787+
2788+
return {};
27242789
}
27252790

27262791
ModuleDecl *ASTContext::getStdlibModule(bool loadIfAbsent) {

lib/AST/ASTDemangler.cpp

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,15 @@ Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor,
264264
auto moduleNode = findModuleNode(definingDecl);
265265
if (!moduleNode)
266266
return Type();
267-
auto parentModule = findModule(moduleNode);
268-
if (!parentModule)
267+
auto potentialParentModules = findPotentialModules(moduleNode);
268+
if (potentialParentModules.empty())
269269
return Type();
270270

271-
auto opaqueDecl = parentModule->lookupOpaqueResultType(mangledName);
271+
OpaqueTypeDecl *opaqueDecl = nullptr;
272+
for (auto module : potentialParentModules)
273+
if (auto decl = module->lookupOpaqueResultType(mangledName))
274+
opaqueDecl = decl;
275+
272276
if (!opaqueDecl)
273277
return Type();
274278
SmallVector<Type, 8> allArgs;
@@ -1123,17 +1127,11 @@ ASTBuilder::createTypeDecl(NodePointer node,
11231127
return dyn_cast<GenericTypeDecl>(DC);
11241128
}
11251129

1126-
ModuleDecl *ASTBuilder::findModule(NodePointer node) {
1130+
llvm::ArrayRef<ModuleDecl *>
1131+
ASTBuilder::findPotentialModules(NodePointer node) {
11271132
assert(node->getKind() == Demangle::Node::Kind::Module);
11281133
const auto moduleName = node->getText();
1129-
// Respect the module's ABI name when we're trying to resolve
1130-
// mangled names. But don't touch anything under the Swift stdlib's
1131-
// umbrella.
1132-
if (moduleName != STDLIB_NAME)
1133-
if (auto *Module = Ctx.getLoadedModuleByABIName(moduleName))
1134-
return Module;
1135-
1136-
return Ctx.getModuleByName(moduleName);
1134+
return Ctx.getModulesByRealOrABIName(moduleName);
11371135
}
11381136

11391137
Demangle::NodePointer
@@ -1223,8 +1221,17 @@ ASTBuilder::findDeclContext(NodePointer node) {
12231221
case Demangle::Node::Kind::BoundGenericTypeAlias:
12241222
return findDeclContext(node->getFirstChild());
12251223

1226-
case Demangle::Node::Kind::Module:
1227-
return findModule(node);
1224+
case Demangle::Node::Kind::Module: {
1225+
// A Module node is not enough information to find the decl context.
1226+
// The reason being that the module name in a mangled name can either be
1227+
// the module's ABI name, which is potentially not unique (due to the
1228+
// -module-abi-name flag), or the module's real name, if mangling for the
1229+
// debugger or USR together with the OriginallyDefinedIn attribute for
1230+
// example.
1231+
assert(false && "Looked up module as decl context directly!");
1232+
auto modules = findPotentialModules(node);
1233+
return modules.empty() ? nullptr : modules[0];
1234+
}
12281235

12291236
case Demangle::Node::Kind::Class:
12301237
case Demangle::Node::Kind::Enum:
@@ -1237,20 +1244,24 @@ ASTBuilder::findDeclContext(NodePointer node) {
12371244
if (declNameNode->getKind() == Demangle::Node::Kind::LocalDeclName) {
12381245
// Find the AST node for the defining module.
12391246
auto moduleNode = findModuleNode(node);
1240-
if (!moduleNode) return nullptr;
1247+
if (!moduleNode)
1248+
return nullptr;
12411249

1242-
auto module = findModule(moduleNode);
1243-
if (!module) return nullptr;
1250+
auto potentialModules = findPotentialModules(moduleNode);
1251+
if (potentialModules.empty())
1252+
return nullptr;
12441253

12451254
// Look up the local type by its mangling.
12461255
auto mangling = Demangle::mangleNode(node);
1247-
if (!mangling.isSuccess()) return nullptr;
1256+
if (!mangling.isSuccess())
1257+
return nullptr;
12481258
auto mangledName = mangling.result();
12491259

1250-
auto decl = module->lookupLocalType(mangledName);
1251-
if (!decl) return nullptr;
1260+
for (auto *module : potentialModules)
1261+
if (auto *decl = module->lookupLocalType(mangledName))
1262+
return dyn_cast<DeclContext>(decl);
12521263

1253-
return dyn_cast<DeclContext>(decl);
1264+
return nullptr;
12541265
}
12551266

12561267
StringRef name;
@@ -1284,22 +1295,33 @@ ASTBuilder::findDeclContext(NodePointer node) {
12841295
}
12851296
}
12861297

1287-
DeclContext *dc = findDeclContext(node->getChild(0));
1288-
if (!dc) {
1298+
auto child = node->getFirstChild();
1299+
if (child->getKind() == Node::Kind::Module) {
1300+
auto potentialModules = findPotentialModules(child);
1301+
if (potentialModules.empty())
1302+
return nullptr;
1303+
1304+
for (auto *module : potentialModules)
1305+
if (auto typeDecl = findTypeDecl(module, Ctx.getIdentifier(name),
1306+
privateDiscriminator, node->getKind()))
1307+
return typeDecl;
12891308
return nullptr;
12901309
}
12911310

1292-
return findTypeDecl(dc, Ctx.getIdentifier(name),
1293-
privateDiscriminator, node->getKind());
1311+
if (auto *dc = findDeclContext(child))
1312+
if (auto typeDecl = findTypeDecl(dc, Ctx.getIdentifier(name),
1313+
privateDiscriminator, node->getKind()))
1314+
return typeDecl;
1315+
1316+
return nullptr;
12941317
}
12951318

12961319
case Demangle::Node::Kind::Global:
12971320
return findDeclContext(node->getChild(0));
12981321

12991322
case Demangle::Node::Kind::Extension: {
1300-
auto *moduleDecl = dyn_cast_or_null<ModuleDecl>(
1301-
findDeclContext(node->getChild(0)));
1302-
if (!moduleDecl)
1323+
auto moduleDecls = findPotentialModules(node->getFirstChild());
1324+
if (moduleDecls.empty())
13031325
return nullptr;
13041326

13051327
auto *nominalDecl = dyn_cast_or_null<NominalTypeDecl>(
@@ -1321,14 +1343,23 @@ ASTBuilder::findDeclContext(NodePointer node) {
13211343
// If the generic signature is equivalent to that of the nominal type,
13221344
// and we're in the same module, it's due to inverse requirements.
13231345
// Just return the nominal declaration.
1324-
if (genericSigMatchesNominal &&
1325-
nominalDecl->getParentModule() == moduleDecl) {
1326-
return nominalDecl;
1346+
for (auto *moduleDecl : moduleDecls) {
1347+
if (genericSigMatchesNominal &&
1348+
nominalDecl->getParentModule() == moduleDecl) {
1349+
return nominalDecl;;
1350+
}
13271351
}
13281352
}
13291353

13301354
for (auto *ext : nominalDecl->getExtensions()) {
1331-
if (ext->getParentModule() != moduleDecl)
1355+
bool found = false;
1356+
for (ModuleDecl *module : moduleDecls) {
1357+
if (ext->getParentModule() == module) {
1358+
found = true;
1359+
break;
1360+
}
1361+
}
1362+
if (!found)
13321363
continue;
13331364

13341365
if (!ext->isConstrainedExtension()) {

lib/AST/Module.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,11 @@ Identifier ModuleDecl::getABIName() const {
19561956
return getName();
19571957
}
19581958

1959+
void ModuleDecl::setABIName(Identifier name) {
1960+
getASTContext().moduleABINameWillChange(this, name);
1961+
ModuleABIName = name;
1962+
}
1963+
19591964
StringRef ModuleDecl::getModuleFilename() const {
19601965
// FIXME: Audit uses of this function and figure out how to migrate them to
19611966
// per-file names. Modules can consist of more than one file.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Tests that reconstructing from mangled names whose types are defined in modules
2+
// with clashing ABI names works.
3+
4+
// RUN: %empty-directory(%t)
5+
// RUN: split-file %s %t
6+
// RUN: cd %t
7+
8+
// RUN: %target-build-swift -emit-library -emit-module -parse-as-library -module-name Foo -module-abi-name Bar -g %t/Foo.swift
9+
// RUN: %target-build-swift -emit-executable -I %t -L %t -lFoo -g -emit-module -module-name Bar -module-abi-name Bar %t/Bar.swift
10+
11+
12+
// RUN: sed -ne '/\/\/ *DEMANGLE-TYPE: /s/\/\/ *DEMANGLE-TYPE: *//p' < %s > %t/input
13+
// RUN: %lldb-moduleimport-test-with-sdk %t/Bar -qualify-types=1 -type-from-mangled=%t/input | %FileCheck %s --check-prefix=CHECK-TYPE
14+
15+
//--- Foo.swift
16+
public class One {
17+
let i = 42
18+
public init() {
19+
}
20+
}
21+
22+
public class Generic<T> {
23+
let t: T
24+
public init(t: T) {
25+
self.t = t
26+
}
27+
}
28+
29+
//--- Bar.swift
30+
import Foo
31+
32+
public class Two {
33+
let j = 98
34+
public init() {
35+
}
36+
}
37+
38+
public class Generic2<T> {
39+
let t: T
40+
public init(t: T) {
41+
self.t = t
42+
}
43+
}
44+
45+
46+
let one = Foo.One()
47+
let two = Bar.Two()
48+
let generic1 = Foo.Generic<Bar.Two>(t: two)
49+
let generic2 = Bar.Generic2<Foo.Generic<Bar.Two>>(t: generic1)
50+
let generic3 = Foo.Generic<Bar.Generic2<Foo.Generic<Bar.Two>>>(t: generic2)
51+
52+
// DEMANGLE-TYPE: $s3Bar3OneCD
53+
// CHECK-TYPE: Foo.One
54+
55+
// DEMANGLE-TYPE: $s3Bar3TwoCD
56+
// CHECK-TYPE: Bar.Two
57+
58+
// DEMANGLE-TYPE: $s3Bar7GenericCyAA3TwoCGD
59+
// CHECK-TYPE: Foo.Generic<Bar.Two>
60+
61+
// DEMANGLE-TYPE: $s3Bar8Generic2CyAA7GenericCyAA3TwoCGGD
62+
// CHECK-TYPE: Bar.Generic2<Foo.Generic<Bar.Two>>
63+
64+
// DEMANGLE-TYPE: $s3Bar7GenericCyAA8Generic2CyACyAA3TwoCGGGD
65+
// CHECK-TYPE: Foo.Generic<Bar.Generic2<Foo.Generic<Bar.Two>>>

0 commit comments

Comments
 (0)