Skip to content

Commit e550944

Browse files
authored
Merge pull request #61941 from xymus/module-alias-disambiguate
[ModuleInterface] Avoid ambiguities in swiftinterfaces by writing aliases for module names
2 parents 9c321c0 + 66586b5 commit e550944

19 files changed

+226
-26
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include "llvm/Support/raw_ostream.h"
2525
#include "swift/AST/PrintOptions.h"
2626

27+
// Prefix to use when printing module names in module interfaces to avoid
28+
// ambiguities with type names, in AliasModuleNames mode.
29+
#define MODULE_DISAMBIGUATING_PREFIX "Module___"
30+
2731
namespace swift {
2832
class Decl;
2933
class DeclContext;
@@ -162,7 +166,8 @@ class ASTPrinter {
162166
PrintNameContext NameContext = PrintNameContext::Normal);
163167

164168
/// Called when printing the referenced name of a module.
165-
virtual void printModuleRef(ModuleEntity Mod, Identifier Name);
169+
virtual void printModuleRef(ModuleEntity Mod, Identifier Name,
170+
const PrintOptions &Options);
166171

167172
/// Called before printing a synthesized extension.
168173
virtual void printSynthesizedExtensionPre(const ExtensionDecl *ED,

include/swift/AST/PrintOptions.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ struct PrintOptions {
466466
/// of the alias.
467467
bool PrintTypeAliasUnderlyingType = false;
468468

469+
/// Use aliases when printing references to modules to avoid ambiguities
470+
/// with types sharing a name with a module.
471+
bool AliasModuleNames = false;
472+
469473
/// When printing an Optional<T>, rather than printing 'T?', print
470474
/// 'T!'. Used as a modifier only when we know we're printing
471475
/// something that was declared as an implicitly unwrapped optional
@@ -601,7 +605,7 @@ struct PrintOptions {
601605
return result;
602606
}
603607

604-
/// Retrieve the set of options suitable for interface generation.
608+
/// Retrieve the set of options suitable for IDE interface generation.
605609
static PrintOptions printInterface(bool printFullConvention) {
606610
PrintOptions result =
607611
printForDiagnostics(AccessLevel::Public, printFullConvention);
@@ -636,7 +640,8 @@ struct PrintOptions {
636640
static PrintOptions printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
637641
bool preferTypeRepr,
638642
bool printFullConvention,
639-
bool printSPIs);
643+
bool printSPIs,
644+
bool aliasModuleNames);
640645

641646
/// Retrieve the set of options suitable for "Generated Interfaces", which
642647
/// are a prettified representation of the public API of a module, to be

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ struct ModuleInterfaceOptions {
3333
/// interface, or should we fully-qualify them?
3434
bool PreserveTypesAsWritten = false;
3535

36+
/// Use aliases when printing references to modules to avoid ambiguities
37+
/// with types sharing a name with a module.
38+
bool AliasModuleNames = false;
39+
3640
/// See \ref FrontendOptions.PrintFullConvention.
3741
/// [TODO: Clang-type-plumbing] This check should go away.
3842
bool PrintFullConvention = false;

include/swift/Option/FrontendOptions.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,15 @@ def module_interface_preserve_types_as_written :
904904
HelpText<"When emitting a module interface, preserve types as they were "
905905
"written in the source">;
906906

907+
def alias_module_names_in_module_interface :
908+
Flag<["-"], "alias-module-names-in-module-interface">,
909+
HelpText<"When emitting a module interface, disambiguate modules using "
910+
"distinct alias names">;
911+
def disable_alias_module_names_in_module_interface :
912+
Flag<["-"], "disable-alias-module-names-in-module-interface">,
913+
HelpText<"When emitting a module interface, disable disambiguating modules "
914+
"using distinct alias names">;
915+
907916
def experimental_spi_imports :
908917
Flag<["-"], "experimental-spi-imports">,
909918
HelpText<"Enable experimental support for SPI imports">;

lib/AST/ASTPrinter.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) {
131131
PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
132132
bool preferTypeRepr,
133133
bool printFullConvention,
134-
bool printSPIs) {
134+
bool printSPIs,
135+
bool aliasModuleNames) {
135136
PrintOptions result;
136137
result.IsForSwiftInterface = true;
137138
result.PrintLongAttrsOnSeparateLines = true;
@@ -152,6 +153,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
152153
result.OpaqueReturnTypePrinting =
153154
OpaqueReturnTypePrintingMode::StableReference;
154155
result.PreferTypeRepr = preferTypeRepr;
156+
result.AliasModuleNames = aliasModuleNames;
155157
if (printFullConvention)
156158
result.PrintFunctionRepresentationAttrs =
157159
PrintOptions::FunctionRepresentationMode::Full;
@@ -365,7 +367,11 @@ void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
365367
printName(Name, Context);
366368
}
367369

368-
void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name) {
370+
void ASTPrinter::printModuleRef(ModuleEntity Mod, Identifier Name,
371+
const PrintOptions &Options) {
372+
if (Options.AliasModuleNames)
373+
printTextImpl(MODULE_DISAMBIGUATING_PREFIX);
374+
369375
printName(Name);
370376
}
371377

@@ -2493,7 +2499,7 @@ void PrintAST::visitImportDecl(ImportDecl *decl) {
24932499
Name = Declaring->getRealName();
24942500
}
24952501
}
2496-
Printer.printModuleRef(Mods.front(), Name);
2502+
Printer.printModuleRef(Mods.front(), Name, Options);
24972503
Mods = Mods.slice(1);
24982504
} else {
24992505
Printer << Elem.Item.str();
@@ -5381,7 +5387,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
53815387
}
53825388
}
53835389

5384-
Printer.printModuleRef(Mod, Name);
5390+
Printer.printModuleRef(Mod, Name, Options);
53855391
Printer << ".";
53865392
}
53875393

@@ -5728,7 +5734,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
57285734
Printer << "module<";
57295735
// Should print the module real name in case module aliasing is
57305736
// used (see -module-alias), since that's the actual binary name.
5731-
Printer.printModuleRef(T->getModule(), T->getModule()->getRealName());
5737+
Printer.printModuleRef(T->getModule(), T->getModule()->getRealName(),
5738+
Options);
57325739
Printer << ">";
57335740
}
57345741

lib/AST/TypeRepr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ void ComponentIdentTypeRepr::printImpl(ASTPrinter &Printer,
269269
const PrintOptions &Opts) const {
270270
if (auto *TD = dyn_cast_or_null<TypeDecl>(getBoundDecl())) {
271271
if (auto MD = dyn_cast<ModuleDecl>(TD))
272-
Printer.printModuleRef(MD, getNameRef().getBaseIdentifier());
272+
Printer.printModuleRef(MD, getNameRef().getBaseIdentifier(), Opts);
273273
else
274274
Printer.printTypeRef(Type(), TD, getNameRef().getBaseIdentifier());
275275
} else {

lib/ClangImporter/ClangImporter.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,20 +1926,26 @@ bool ClangImporter::canImportModule(ImportPath::Module modulePath,
19261926
ModuleDecl *ClangImporter::Implementation::loadModuleClang(
19271927
SourceLoc importLoc, ImportPath::Module path) {
19281928
auto &clangHeaderSearch = getClangPreprocessor().getHeaderSearchInfo();
1929+
auto realModuleName = SwiftContext.getRealModuleName(path.front().Item).str();
19291930

19301931
// Look up the top-level module first, to see if it exists at all.
19311932
clang::Module *clangModule = clangHeaderSearch.lookupModule(
1932-
path.front().Item.str(), /*ImportLoc=*/clang::SourceLocation(),
1933+
realModuleName, /*ImportLoc=*/clang::SourceLocation(),
19331934
/*AllowSearch=*/true, /*AllowExtraModuleMapSearch=*/true);
19341935
if (!clangModule)
19351936
return nullptr;
19361937

19371938
// Convert the Swift import path over to a Clang import path.
19381939
SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, 4>
19391940
clangPath;
1941+
bool isTopModuleComponent = true;
19401942
for (auto component : path) {
1943+
StringRef item = isTopModuleComponent? realModuleName:
1944+
component.Item.str();
1945+
isTopModuleComponent = false;
1946+
19411947
clangPath.emplace_back(
1942-
getClangPreprocessor().getIdentifierInfo(component.Item.str()),
1948+
getClangPreprocessor().getIdentifierInfo(item),
19431949
exportSourceLoc(component.Loc));
19441950
}
19451951

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -755,15 +755,12 @@ bool ModuleAliasesConverter::computeModuleAliases(std::vector<std::string> args,
755755
if (!allowModuleName) {
756756
if (value == options.ModuleName ||
757757
value == options.ModuleABIName ||
758-
value == options.ModuleLinkName) {
758+
value == options.ModuleLinkName ||
759+
value == STDLIB_NAME) {
759760
diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
760761
return false;
761762
}
762763
}
763-
if (value == STDLIB_NAME) {
764-
diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
765-
return false;
766-
}
767764
if (!Lexer::isIdentifier(value)) {
768765
diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false);
769766
return false;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
368368

369369
Opts.PreserveTypesAsWritten |=
370370
Args.hasArg(OPT_module_interface_preserve_types_as_written);
371+
Opts.AliasModuleNames |=
372+
Args.hasFlag(OPT_alias_module_names_in_module_interface,
373+
OPT_disable_alias_module_names_in_module_interface,
374+
false);
371375
Opts.PrintFullConvention |=
372376
Args.hasArg(OPT_experimental_print_full_convention);
373377
Opts.ExperimentalSPIImports |=

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1027,9 +1027,10 @@ class ModuleInterfaceLoaderImpl {
10271027
}
10281028
// Set up a builder if we need to build the module. It'll also set up
10291029
// the genericSubInvocation we'll need to use to compute the cache paths.
1030+
Identifier realName = ctx.getRealModuleName(ctx.getIdentifier(moduleName));
10301031
ImplicitModuleInterfaceBuilder builder(
10311032
ctx.SourceMgr, diagsToUse,
1032-
astDelegate, interfacePath, moduleName, cacheDir,
1033+
astDelegate, interfacePath, realName.str(), cacheDir,
10331034
prebuiltCacheDir, backupInterfaceDir, StringRef(),
10341035
Opts.disableInterfaceLock,
10351036
ctx.IgnoreAdjacentModules, diagnosticLoc,

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,32 @@ static void printToolVersionAndFlagsComment(raw_ostream &out,
5858
out << "// " SWIFT_COMPILER_VERSION_KEY ": "
5959
<< ToolsVersion << "\n";
6060
out << "// " SWIFT_MODULE_FLAGS_KEY ": "
61-
<< Opts.Flags << "\n";
61+
<< Opts.Flags;
62+
63+
// Insert additional -module-alias flags
64+
if (Opts.AliasModuleNames) {
65+
llvm::SmallSet<StringRef, 2> aliasTargets;
66+
StringRef moduleName = M->getNameStr();
67+
aliasTargets.insert(M->getNameStr());
68+
out << " -module-alias " << MODULE_DISAMBIGUATING_PREFIX <<
69+
moduleName << "=" << moduleName;
70+
71+
SmallVector<ImportedModule> imports;
72+
M->getImportedModules(imports,
73+
{ModuleDecl::ImportFilterKind::Default,
74+
ModuleDecl::ImportFilterKind::Exported,
75+
ModuleDecl::ImportFilterKind::SPIOnly,
76+
ModuleDecl::ImportFilterKind::SPIAccessControl});
77+
for (ImportedModule import: imports) {
78+
StringRef importedName = import.importedModule->getNameStr();
79+
if (aliasTargets.insert(importedName).second) {
80+
out << " -module-alias " << MODULE_DISAMBIGUATING_PREFIX <<
81+
importedName << "=" << importedName;
82+
}
83+
}
84+
}
85+
out << "\n";
86+
6287
if (!Opts.IgnorableFlags.empty()) {
6388
out << "// " SWIFT_MODULE_FLAGS_IGNORABLE_KEY ": "
6489
<< Opts.IgnorableFlags << "\n";
@@ -295,6 +320,8 @@ static void printImports(raw_ostream &out,
295320
}
296321

297322
out << "import ";
323+
if (Opts.AliasModuleNames)
324+
out << MODULE_DISAMBIGUATING_PREFIX;
298325
importedModule->getReverseFullModuleName().printForward(out);
299326

300327
// Write the access path we should be honoring but aren't.
@@ -758,7 +785,8 @@ bool swift::emitSwiftInterface(raw_ostream &out,
758785
printImports(out, Opts, M);
759786

760787
const PrintOptions printOptions = PrintOptions::printSwiftInterfaceFile(
761-
M, Opts.PreserveTypesAsWritten, Opts.PrintFullConvention, Opts.PrintSPIs);
788+
M, Opts.PreserveTypesAsWritten, Opts.PrintFullConvention, Opts.PrintSPIs,
789+
Opts.AliasModuleNames);
762790
InheritedProtocolCollector::PerTypeMap inheritedProtocolMap;
763791

764792
SmallVector<Decl *, 16> topLevelDecls;

lib/IDE/ModuleInterfacePrinting.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ class ClangCommentPrinter : public ASTPrinter {
8080
PrintNameContext NameContext) override {
8181
return OtherPrinter.printTypeRef(T, TD, Name, NameContext);
8282
}
83-
void printModuleRef(ModuleEntity Mod, Identifier Name) override {
84-
return OtherPrinter.printModuleRef(Mod, Name);
83+
void printModuleRef(ModuleEntity Mod, Identifier Name,
84+
const PrintOptions &Options) override {
85+
return OtherPrinter.printModuleRef(Mod, Name, Options);
8586
}
8687
void printSynthesizedExtensionPre(const ExtensionDecl *ED,
8788
TypeOrExtensionDecl Target,

lib/Sema/ImportResolution.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,8 @@ getModuleImpl(ImportPath::Module modulePath, ModuleDecl *loadingModule,
371371
//
372372
// FIXME: We'd like to only use this in SIL mode, but unfortunately we use it
373373
// for clang overlays as well.
374-
if (moduleID.Item == loadingModule->getName() && modulePath.size() == 1) {
374+
if (ctx.getRealModuleName(moduleID.Item) == loadingModule->getName() &&
375+
modulePath.size() == 1) {
375376
if (auto importer = ctx.getClangModuleLoader())
376377
return importer->loadModule(moduleID.Loc, modulePath);
377378
return nullptr;

test/Frontend/module-alias-invalid-input.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %s -module-name foo -module-alias Swift=Bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS1 %s
77
// INVALID_MODULE_ALIAS1: error: invalid module alias "Swift"; make sure the alias differs from the module name, module ABI name, module link name, and a standard library name
8+
// RUN: %target-swift-frontend -emit-silgen -parse-as-library %s -module-name foo -module-alias Bar=Swift -verify
89

910
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %s -module-name foo -module-alias bar=bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS2 %s
1011
// INVALID_MODULE_ALIAS2: error: duplicate module alias; the name "bar" is already used for a module alias or an underlying name
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/// Test that the AliasModuleNames mode avoids ambiguities in swiftinterfaces
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t
5+
6+
// RUN: %target-swift-frontend -emit-module -module-name AmbiguousLib \
7+
// RUN: -swift-version 5 -enable-library-evolution \
8+
// RUN: -o %t/AmbiguousLib.swiftmodule \
9+
// RUN: -emit-module-interface-path %t/AmbiguousLib.swiftinterface \
10+
// RUN: %t/AmbiguousLib.swift
11+
// RUN: %target-swift-typecheck-module-from-interface(%t/AmbiguousLib.swiftinterface)
12+
13+
// RUN: %target-swift-frontend -emit-module -module-name AmbiguousClientName \
14+
// RUN: -swift-version 5 -enable-library-evolution \
15+
// RUN: -o %t/AmbiguousClientName.swiftmodule \
16+
// RUN: -emit-module-interface-path %t/AmbiguousClientName.swiftinterface \
17+
// RUN: %t/AmbiguousClientName.swift -I%t \
18+
// RUN: -alias-module-names-in-module-interface
19+
// RUN: %target-swift-typecheck-module-from-interface(%t/AmbiguousClientName.swiftinterface) -I%t
20+
21+
//--- module.modulemap
22+
module AmbiguousClientName {
23+
header "AmbiguousClientName.h"
24+
}
25+
26+
module SomeClangModule {
27+
header "SomeClangModule.h"
28+
}
29+
30+
//--- AmbiguousClientName.h
31+
struct UnderlyingType {};
32+
void underlyingFunc() {}
33+
34+
//--- SomeClangModule.h
35+
struct CType {};
36+
37+
//--- AmbiguousLib.swift
38+
39+
// 1. AmbiguousLib defined a type named AmbiguousLib
40+
public struct AmbiguousLib {
41+
public struct Nested {}
42+
}
43+
44+
// 2. A lib defines a type of the same name as a client's module
45+
public struct AmbiguousClientName {
46+
}
47+
48+
//--- AmbiguousClientName.swift
49+
50+
@_exported import AmbiguousClientName
51+
import AmbiguousLib
52+
import SomeClangModule
53+
54+
public struct SomeType {
55+
@inlinable
56+
public func inlinableFunc() {
57+
var x: AmbiguousClientName
58+
}
59+
}
60+
61+
public func refToLocalType(_ a: SomeType) {}
62+
public func refToNestedInLib(_ a: AmbiguousLib.Nested) {}
63+
64+
public func refToStdlib(_ a: Swift.Int) {}
65+
public func refToUnderlying(_ a: UnderlyingType) {}
66+
public func refToC(_ a: CType) {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// Check that we can alias a module imported from a swiftinterface
2+
// RUN: %empty-directory(%t)
3+
// RUN: split-file %s %t
4+
5+
// RUN: %target-swift-frontend -emit-module -module-name Lib \
6+
// RUN: -swift-version 5 -enable-library-evolution \
7+
// RUN: -o %t/Lib.swiftmodule \
8+
// RUN: -emit-module-interface-path %t/Lib.swiftinterface \
9+
// RUN: %t/Lib.swift
10+
11+
/// We can alias an imported module built from a swiftmodule
12+
// RUN: %target-swift-frontend -typecheck -module-name Client \
13+
// RUN: -swift-version 5 \
14+
// RUN: -module-alias AliasedLib=Lib \
15+
// RUN: %t/Client.swift -I%t
16+
17+
/// We can alias an imported module built from a swiftinterface
18+
// RUN: rm %t/Lib.swiftmodule
19+
// RUN: %target-swift-frontend -typecheck -module-name Client \
20+
// RUN: -swift-version 5 \
21+
// RUN: -module-alias AliasedLib=Lib \
22+
// RUN: %t/Client.swift -I%t
23+
24+
//--- Lib.swift
25+
public func foo() {}
26+
27+
//--- Client.swift
28+
import AliasedLib
29+
30+
func main() {
31+
AliasedLib.foo()
32+
}

0 commit comments

Comments
 (0)