Skip to content

Commit 14eefd1

Browse files
authored
Merge pull request #39376 from apple/es-mod-alias1
Introduce a module alias option to the frontend. Validate and convert the input to a module alias map to be used by import resolution and sema. rdar://83316886
2 parents f34e321 + 8a6ee37 commit 14eefd1

File tree

7 files changed

+107
-1
lines changed

7 files changed

+107
-1
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,14 @@ ERROR(error_stdlib_module_name,none,
150150
"module name \"%0\" is reserved for the standard library"
151151
"%select{|; use -module-name flag to specify an alternate name}1",
152152
(StringRef, bool))
153-
154153
ERROR(error_stdlib_not_found,Fatal,
155154
"unable to load standard library for target '%0'", (StringRef))
155+
ERROR(error_module_alias_invalid_format,none,
156+
"invalid module alias format \"%0\"; make sure to use the format '-module-alias alias_name=underlying_name'", (StringRef))
157+
ERROR(error_module_alias_forbidden_name,none,
158+
"invalid module alias \"%0\"; make sure the alias differs from the module name, module ABI name, module link name, and a standard library name", (StringRef))
159+
ERROR(error_module_alias_duplicate,none,
160+
"duplicate module alias; the name \"%0\" is already used for a module alias or an underlying name", (StringRef))
156161

157162
ERROR(error_unable_to_load_supplementary_output_file_map, none,
158163
"unable to load supplementary output file map '%0': %1",

include/swift/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/Frontend/FrontendInputsAndOutputs.h"
1919
#include "swift/Frontend/InputFile.h"
2020
#include "llvm/ADT/Hashing.h"
21+
#include "llvm/ADT/StringMap.h"
2122

2223
#include <string>
2324
#include <vector>
@@ -48,6 +49,9 @@ class FrontendOptions {
4849
/// An Objective-C header to import and make implicitly visible.
4950
std::string ImplicitObjCHeaderPath;
5051

52+
/// The map of aliases and underlying names of imported or referenced modules.
53+
llvm::StringMap<StringRef> ModuleAliasMap;
54+
5155
/// The name of the module that the frontend is building.
5256
std::string ModuleName;
5357

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,11 @@ def module_name : Separate<["-"], "module-name">,
430430
def module_name_EQ : Joined<["-"], "module-name=">, Flags<[FrontendOption]>,
431431
Alias<module_name>;
432432

433+
def module_alias : Separate<["-"], "module-alias">,
434+
Flags<[FrontendOption]>,
435+
MetaVarName<"<alias_name=underlying_name>">,
436+
HelpText<"If a source file imports or references module <alias_name>, the underlying name is used for the contents of the file">;
437+
433438
def module_link_name : Separate<["-"], "module-link-name">,
434439
Flags<[FrontendOption, ModuleInterfaceOption]>,
435440
HelpText<"Library to link against when using this module">;

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ bool ArgsToFrontendOptionsConverter::convert(
244244
if (const Arg *A = Args.getLastArg(OPT_module_link_name))
245245
Opts.ModuleLinkName = A->getValue();
246246

247+
// This must be called after computing module name, module abi name,
248+
// and module link name.
249+
if (computeModuleAliases())
250+
return true;
251+
247252
if (const Arg *A = Args.getLastArg(OPT_access_notes_path))
248253
Opts.AccessNotesPath = A->getValue();
249254

@@ -498,7 +503,65 @@ bool ArgsToFrontendOptionsConverter::setUpImmediateArgs() {
498503
return false;
499504
}
500505

506+
bool ArgsToFrontendOptionsConverter::computeModuleAliases() {
507+
auto list = Args.getAllArgValues(options::OPT_module_alias);
508+
if (!list.empty()) {
509+
auto validate = [this](StringRef value, bool allowModuleName) -> bool
510+
{
511+
if (!allowModuleName) {
512+
if (value == Opts.ModuleName ||
513+
value == Opts.ModuleABIName ||
514+
value == Opts.ModuleLinkName) {
515+
Diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
516+
return false;
517+
}
518+
}
519+
if (value == STDLIB_NAME) {
520+
Diags.diagnose(SourceLoc(), diag::error_module_alias_forbidden_name, value);
521+
return false;
522+
}
523+
if (!Lexer::isIdentifier(value)) {
524+
Diags.diagnose(SourceLoc(), diag::error_bad_module_name, value, false);
525+
return false;
526+
}
527+
return true;
528+
};
529+
530+
for (auto item: list) {
531+
auto str = StringRef(item);
532+
// splits to an alias and the underlying name
533+
auto pair = str.split('=');
534+
auto lhs = pair.first;
535+
auto rhs = pair.second;
536+
537+
if (rhs.empty()) { // '=' is missing
538+
Diags.diagnose(SourceLoc(), diag::error_module_alias_invalid_format, str);
539+
return true;
540+
}
541+
if (!validate(lhs, false) || !validate(rhs, true)) {
542+
return true;
543+
}
544+
545+
// First, add the underlying name as a key to prevent it from being
546+
// used as an alias
547+
if (!Opts.ModuleAliasMap.insert({rhs, StringRef()}).second) {
548+
Diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, rhs);
549+
return true;
550+
}
551+
// Next, add the alias as a key and the underlying name as a value to the map
552+
auto underlyingName = Opts.ModuleAliasMap.find(rhs)->first();
553+
if (!Opts.ModuleAliasMap.insert({lhs, underlyingName}).second) {
554+
Diags.diagnose(SourceLoc(), diag::error_module_alias_duplicate, lhs);
555+
return true;
556+
}
557+
}
558+
}
559+
return false;
560+
}
561+
501562
bool ArgsToFrontendOptionsConverter::computeModuleName() {
563+
assert(Opts.ModuleAliasMap.empty() && "Module name must be computed before computing module aliases");
564+
502565
const Arg *A = Args.getLastArg(options::OPT_module_name);
503566
if (A) {
504567
Opts.ModuleName = A->getValue();

lib/Frontend/ArgsToFrontendOptionsConverter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ArgsToFrontendOptionsConverter {
3737
void computeDebugTimeOptions();
3838
bool computeFallbackModuleName();
3939
bool computeModuleName();
40+
bool computeModuleAliases();
4041
bool computeMainAndSupplementaryOutputFilenames();
4142
void computeDumpScopeMapLocations();
4243
void computeHelpOptions();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func quip() {
2+
}
3+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Tests for invalid module alias format and values.
2+
3+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias foo=bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS %s
4+
// INVALID_MODULE_ALIAS: error: invalid module alias "foo"; make sure the alias differs from the module name, module ABI name, module link name, and a standard library name
5+
6+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias Swift=Bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS1 %s
7+
// 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+
9+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar=bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS2 %s
10+
// INVALID_MODULE_ALIAS2: error: duplicate module alias; the name "bar" is already used for a module alias or an underlying name
11+
12+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar=baz -module-alias baz=cat 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS3 %s
13+
// INVALID_MODULE_ALIAS3: error: duplicate module alias; the name "baz" is already used for a module alias or an underlying name
14+
15+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_ALIAS4 %s
16+
// INVALID_MODULE_ALIAS4: error: invalid module alias format "bar"; make sure to use the format '-module-alias alias_name=underlying_name'
17+
18+
// RUN: not %target-swift-frontend -emit-silgen -parse-as-library %S/Inputs/invalid-module-alias.swift -module-name foo -module-alias bar=c-a.t 2>&1 | %FileCheck -check-prefix=INVALID_MODULE_NAME %s
19+
// INVALID_MODULE_NAME: error: module name "c-a.t" is not a valid identifier
20+
21+
// These should succeed.
22+
// RUN: %target-swift-frontend -emit-silgen %S/Inputs/invalid-module-alias.swift > /dev/null
23+
// RUN: %target-swift-frontend -emit-silgen -parse-as-library -module-name foo %S/Inputs/invalid-module-alias.swift -module-alias bar=cat > /dev/null
24+
// RUN: %target-swift-frontend -typecheck -parse-as-library -module-name foo %S/Inputs/invalid-module-alias.swift -module-alias bar=cat
25+

0 commit comments

Comments
 (0)