Skip to content

Commit 7583e25

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 a07caa8 commit 7583e25

File tree

6 files changed

+175
-78
lines changed

6 files changed

+175
-78
lines changed

include/swift/AST/ASTContext.h

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

12011201
ModuleDecl *getModuleByIdentifier(Identifier ModuleID);
12021202

1203-
/// Looks up an already loaded module by its ABI name.
1204-
///
1205-
/// \returns The module if found, nullptr otherwise.
1206-
ModuleDecl *getLoadedModuleByABIName(StringRef ModuleName);
1203+
/// Looks up all modules whose real name or ABI name match ModuleName.
1204+
llvm::SmallVector<ModuleDecl *, 1>
1205+
getModulesByRealOrABIName(StringRef ModuleName);
12071206

12081207
/// Returns the standard library module, or null if the library isn't present.
12091208
///

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 ABI name. This function returns
261+
/// all modules that contain that name.
262+
llvm::SmallVector<ModuleDecl *, 1> findPotentialModules(NodePointer node);
263+
258264
Demangle::NodePointer findModuleNode(NodePointer node);
259265

260266
enum class ForeignModuleKind {

lib/AST/ASTContext.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,12 +2713,16 @@ ModuleDecl *ASTContext::getModuleByIdentifier(Identifier ModuleID) {
27132713
return getModule(builder.get());
27142714
}
27152715

2716-
ModuleDecl *ASTContext::getLoadedModuleByABIName(StringRef ModuleName) {
2717-
for (auto &[_, module] : getLoadedModules()) {
2718-
if (ModuleName == module->getABIName().str())
2719-
return module;
2720-
}
2721-
return nullptr;
2716+
llvm::SmallVector<ModuleDecl *, 1>
2717+
ASTContext::getModulesByRealOrABIName(StringRef ModuleName) {
2718+
llvm::SmallVector<ModuleDecl *, 1> modules;
2719+
2720+
for (auto &[_, module] : getLoadedModules())
2721+
if (ModuleName == module->getRealName().str() ||
2722+
ModuleName == module->getABIName().str())
2723+
modules.push_back(module);
2724+
2725+
return modules;
27222726
}
27232727

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

lib/AST/ASTDemangler.cpp

Lines changed: 89 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -264,25 +264,26 @@ 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);
272-
if (!opaqueDecl)
273-
return Type();
274-
SmallVector<Type, 8> allArgs;
275-
for (auto argSet : args) {
276-
allArgs.append(argSet.begin(), argSet.end());
277-
}
271+
for (ModuleDecl *module : potentialParentModules) {
272+
auto opaqueDecl = module->lookupOpaqueResultType(mangledName);
273+
if (!opaqueDecl)
274+
continue;
275+
SmallVector<Type, 8> allArgs;
276+
for (auto argSet : args) {
277+
allArgs.append(argSet.begin(), argSet.end());
278+
}
278279

279-
SubstitutionMap subs = createSubstitutionMapFromGenericArgs(
280-
opaqueDecl->getGenericSignature(), allArgs,
281-
LookUpConformanceInModule());
282-
Type interfaceType = opaqueDecl->getOpaqueGenericParams()[ordinal];
283-
return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs);
280+
SubstitutionMap subs = createSubstitutionMapFromGenericArgs(
281+
opaqueDecl->getGenericSignature(), allArgs,
282+
LookUpConformanceInModule());
283+
Type interfaceType = opaqueDecl->getOpaqueGenericParams()[ordinal];
284+
return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs);
285+
}
284286
}
285-
286287
// TODO: named opaque types
287288
return Type();
288289
}
@@ -1123,17 +1124,11 @@ ASTBuilder::createTypeDecl(NodePointer node,
11231124
return dyn_cast<GenericTypeDecl>(DC);
11241125
}
11251126

1126-
ModuleDecl *ASTBuilder::findModule(NodePointer node) {
1127+
llvm::SmallVector<ModuleDecl *, 1>
1128+
ASTBuilder::findPotentialModules(NodePointer node) {
11271129
assert(node->getKind() == Demangle::Node::Kind::Module);
11281130
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);
1131+
return Ctx.getModulesByRealOrABIName(moduleName);
11371132
}
11381133

11391134
Demangle::NodePointer
@@ -1223,8 +1218,17 @@ ASTBuilder::findDeclContext(NodePointer node) {
12231218
case Demangle::Node::Kind::BoundGenericTypeAlias:
12241219
return findDeclContext(node->getFirstChild());
12251220

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

12291233
case Demangle::Node::Kind::Class:
12301234
case Demangle::Node::Kind::Enum:
@@ -1237,20 +1241,24 @@ ASTBuilder::findDeclContext(NodePointer node) {
12371241
if (declNameNode->getKind() == Demangle::Node::Kind::LocalDeclName) {
12381242
// Find the AST node for the defining module.
12391243
auto moduleNode = findModuleNode(node);
1240-
if (!moduleNode) return nullptr;
1244+
if (!moduleNode)
1245+
return nullptr;
12411246

1242-
auto module = findModule(moduleNode);
1243-
if (!module) return nullptr;
1247+
auto potentialModules = findPotentialModules(moduleNode);
1248+
if (potentialModules.empty())
1249+
return nullptr;
12441250

12451251
// Look up the local type by its mangling.
12461252
auto mangling = Demangle::mangleNode(node);
1247-
if (!mangling.isSuccess()) return nullptr;
1253+
if (!mangling.isSuccess())
1254+
return nullptr;
12481255
auto mangledName = mangling.result();
12491256

1250-
auto decl = module->lookupLocalType(mangledName);
1251-
if (!decl) return nullptr;
1257+
for (auto *module : potentialModules)
1258+
if (auto *decl = module->lookupLocalType(mangledName))
1259+
return dyn_cast<DeclContext>(decl);
12521260

1253-
return dyn_cast<DeclContext>(decl);
1261+
return nullptr;
12541262
}
12551263

12561264
StringRef name;
@@ -1272,7 +1280,7 @@ ASTBuilder::findDeclContext(NodePointer node) {
12721280

12731281
// Ignore any other decl-name productions for now.
12741282
} else {
1275-
return nullptr;
1283+
return nullptr;;
12761284
}
12771285

12781286
// Do some special logic for foreign type declarations.
@@ -1284,22 +1292,33 @@ ASTBuilder::findDeclContext(NodePointer node) {
12841292
}
12851293
}
12861294

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

1292-
return findTypeDecl(dc, Ctx.getIdentifier(name),
1293-
privateDiscriminator, node->getKind());
1308+
if (auto *dc = findDeclContext(child))
1309+
if (auto typeDecl = findTypeDecl(dc, Ctx.getIdentifier(name),
1310+
privateDiscriminator, node->getKind()))
1311+
return typeDecl;
1312+
1313+
return nullptr;
12941314
}
12951315

12961316
case Demangle::Node::Kind::Global:
12971317
return findDeclContext(node->getChild(0));
12981318

12991319
case Demangle::Node::Kind::Extension: {
1300-
auto *moduleDecl = dyn_cast_or_null<ModuleDecl>(
1301-
findDeclContext(node->getChild(0)));
1302-
if (!moduleDecl)
1320+
auto moduleDecls = findPotentialModules(node->getFirstChild());
1321+
if (moduleDecls.empty())
13031322
return nullptr;
13041323

13051324
auto *nominalDecl = dyn_cast_or_null<NominalTypeDecl>(
@@ -1321,39 +1340,43 @@ ASTBuilder::findDeclContext(NodePointer node) {
13211340
// If the generic signature is equivalent to that of the nominal type,
13221341
// and we're in the same module, it's due to inverse requirements.
13231342
// Just return the nominal declaration.
1324-
if (genericSigMatchesNominal &&
1325-
nominalDecl->getParentModule() == moduleDecl) {
1326-
return nominalDecl;
1343+
for (auto *moduleDecl : moduleDecls) {
1344+
if (genericSigMatchesNominal &&
1345+
nominalDecl->getParentModule() == moduleDecl) {
1346+
return nominalDecl;
1347+
}
13271348
}
13281349
}
13291350

1330-
for (auto *ext : nominalDecl->getExtensions()) {
1331-
if (ext->getParentModule() != moduleDecl)
1332-
continue;
1333-
1334-
if (!ext->isConstrainedExtension()) {
1335-
if (!genericSig || genericSigMatchesNominal)
1336-
return ext;
1351+
for (auto *moduleDecl : moduleDecls) {
1352+
for (auto *ext : nominalDecl->getExtensions()) {
1353+
if (ext->getParentModule() != moduleDecl)
1354+
continue;
13371355

1338-
continue;
1339-
}
1356+
if (!ext->isConstrainedExtension()) {
1357+
if (!genericSig || genericSigMatchesNominal)
1358+
return ext;
13401359

1341-
if (!ext->isWrittenWithConstraints() && !genericSig)
1342-
return ext;
1360+
continue;
1361+
}
13431362

1344-
auto extSig = ext->getGenericSignature().getCanonicalSignature();
1345-
if (extSig == genericSig) {
1346-
return ext;
1347-
}
1363+
if (!ext->isWrittenWithConstraints() && !genericSig)
1364+
return ext;
13481365

1349-
// If the extension mangling doesn't include a generic signature, it
1350-
// might be because the nominal type suppresses conformance.
1351-
if (!genericSig) {
1352-
SmallVector<Requirement, 2> requirements;
1353-
SmallVector<InverseRequirement, 2> inverses;
1354-
extSig->getRequirementsWithInverses(requirements, inverses);
1355-
if (requirements.empty())
1366+
auto extSig = ext->getGenericSignature().getCanonicalSignature();
1367+
if (extSig == genericSig) {
13561368
return ext;
1369+
}
1370+
1371+
// If the extension mangling doesn't include a generic signature, it
1372+
// might be because the nominal type suppresses conformance.
1373+
if (!genericSig) {
1374+
SmallVector<Requirement, 2> requirements;
1375+
SmallVector<InverseRequirement, 2> inverses;
1376+
extSig->getRequirementsWithInverses(requirements, inverses);
1377+
if (requirements.empty())
1378+
return ext;
1379+
}
13571380
}
13581381
}
13591382

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>>>

test/TypeDecoder/different_abi_name.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// RUN: cd %t
88

99
// RUN: %target-build-swift -emit-library -emit-module -parse-as-library -module-abi-name Other -g %t/TheModule.swift
10-
// RUN: %target-build-swift -emit-executable -I %t -L %t -lTheModule %s -g -o %t/user -emit-module
10+
// RUN: %target-build-swift -emit-executable -I %t -L %t -lTheModule -g -o %t/user -emit-module %t/user.swift
1111

1212

1313
// RUN: sed -ne '/\/\/ *DEMANGLE-TYPE: /s/\/\/ *DEMANGLE-TYPE: *//p' < %s > %t/input

0 commit comments

Comments
 (0)