Skip to content

Commit 8c7d550

Browse files
committed
Allow :: as an alias for . in scoped imports
1 parent 77fb537 commit 8c7d550

File tree

3 files changed

+66
-17
lines changed

3 files changed

+66
-17
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ NOTE(extra_whitespace_module_selector,none,
101101
"remove extraneous whitespace after '::'", ())
102102
ERROR(module_selector_submodule_not_allowed,none,
103103
"module selector cannot specify a submodule", ())
104+
NOTE(replace_module_selector_with_member_lookup,none,
105+
"replace '::' with '.'", ())
104106

105107
//------------------------------------------------------------------------------
106108
// MARK: Lexer diagnostics

lib/Parse/ParseDecl.cpp

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6663,27 +6663,55 @@ ParserResult<ImportDecl> Parser::parseDeclImport(ParseDeclOptions Flags,
66636663
}
66646664

66656665
ImportPath::Builder importPath;
6666-
bool HasNext;
6667-
do {
6668-
if (Tok.is(tok::code_complete)) {
6669-
consumeToken();
6670-
if (CodeCompletionCallbacks) {
6671-
CodeCompletionCallbacks->completeImportDecl(importPath);
6672-
}
6673-
return makeParserCodeCompletionStatus();
6666+
if (Kind != ImportKind::Module && isAtModuleSelector()) {
6667+
// First, parse as much as possible.
6668+
importPath.push_back(*parseModuleSelector());
6669+
6670+
Identifier declName;
6671+
SourceLoc declNameLoc;
6672+
if (Tok.isAtStartOfLine()) {
6673+
diagnose(getEndOfPreviousLoc(),
6674+
diag::expected_identifier_after_module_selector);
6675+
} else {
6676+
parseAnyIdentifier(declName, declNameLoc,
6677+
diag::expected_identifier_after_module_selector,
6678+
/*diagnoseDollarPrefix=*/true);
66746679
}
6675-
importPath.push_back(Identifier(), Tok.getLoc());
6676-
if (parseAnyIdentifier(importPath.back().Item,
6677-
/*diagnoseDollarPrefix=*/false,
6678-
diag::expected_identifier_in_decl, "import"))
6679-
return nullptr;
6680-
if (Tok.is(tok::oper_postfix)) {
6680+
importPath.push_back(declName, declNameLoc);
6681+
6682+
// If either identifier failed to parse, bail.
6683+
for (auto &elem : importPath) {
6684+
if (elem.Item.empty())
6685+
return nullptr;
6686+
}
6687+
} else {
6688+
bool HasNext;
6689+
do {
6690+
if (Tok.is(tok::code_complete)) {
6691+
consumeToken();
6692+
if (CodeCompletionCallbacks) {
6693+
CodeCompletionCallbacks->completeImportDecl(importPath);
6694+
}
6695+
return makeParserCodeCompletionStatus();
6696+
}
6697+
importPath.push_back(Identifier(), Tok.getLoc());
6698+
if (parseAnyIdentifier(importPath.back().Item,
6699+
/*diagnoseDollarPrefix=*/false,
6700+
diag::expected_identifier_in_decl, "import"))
6701+
return nullptr;
6702+
if (Tok.is(tok::oper_postfix)) {
66816703
diagnose(Tok, diag::unexpected_operator_in_import_path)
66826704
.fixItRemove(Tok.getLoc());
66836705
return nullptr;
6684-
}
6685-
HasNext = consumeIf(tok::period);
6686-
} while (HasNext);
6706+
}
6707+
if (Tok.is(tok::colon_colon)) {
6708+
diagnose(Tok, diag::module_selector_submodule_not_allowed);
6709+
diagnose(Tok, diag::replace_module_selector_with_member_lookup)
6710+
.fixItReplace(Tok.getLoc(), ".");
6711+
}
6712+
HasNext = consumeIf(tok::period) || consumeIf(tok::colon_colon);
6713+
} while (HasNext);
6714+
}
66876715

66886716
if (Tok.is(tok::code_complete)) {
66896717
// We omit the code completion token if it immediately follows the module

test/Parse/module_selector.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@
55

66
// REQUIRES: swift_feature_ModuleSelector
77

8+
// ModuleSelectorImports
9+
import struct ModuleSelectorTestingKit::A
10+
11+
import struct _::A
12+
// expected-error@-1 {{'_' cannot be used as an identifier here}}
13+
// expected-note@-2 {{if this name is unavoidable, use backticks to escape it}} {{15-16=`_`}}
14+
15+
import struct ModuleSelectorTestingKit::Submodule::A
16+
// expected-legacy-error@-1 {{module selector cannot specify a submodule}} {{41-52=}}
17+
18+
import struct ModuleSelectorTestingKit.Submodule::A
19+
// expected-error@-1 {{module selector cannot specify a submodule}}
20+
// expected-note@-2 {{replace '::' with '.'}} {{49-51=.}}
21+
22+
import ctypes::bits
23+
// expected-error@-1 {{module selector cannot specify a submodule}}
24+
// expected-note@-2 {{replace '::' with '.'}} {{14-16=.}}
25+
26+
827
// ModuleSelectorCorrectCode
928
extension ModuleSelectorTestingKit::A {}
1029

0 commit comments

Comments
 (0)