Skip to content

Commit 8422e4a

Browse files
committed
Parse module selectors in permitted locations
1 parent 53d7406 commit 8422e4a

File tree

8 files changed

+991
-66
lines changed

8 files changed

+991
-66
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ ERROR(forbidden_interpolated_string,none,
9393
ERROR(forbidden_extended_escaping_string,none,
9494
"%0 cannot be an extended escaping string literal", (StringRef))
9595

96+
ERROR(expected_identifier_in_module_selector,none,
97+
"expected module name in module selector", ())
98+
ERROR(expected_identifier_after_module_selector,none,
99+
"expected identifier after module selector", ())
100+
NOTE(extra_whitespace_module_selector,none,
101+
"remove extraneous whitespace after '::'", ())
102+
ERROR(module_selector_submodule_not_allowed,none,
103+
"module selector cannot specify a submodule", ())
104+
96105
//------------------------------------------------------------------------------
97106
// MARK: Lexer diagnostics
98107
//------------------------------------------------------------------------------

include/swift/Parse/Parser.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,19 @@ class Parser {
18091809
void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc,
18101810
bool isAttr = false);
18111811

1812+
/// Attempts to parse a \c module-selector if one is present.
1813+
///
1814+
/// \verbatim
1815+
/// module-selector: identifier '::'
1816+
/// \endverbatim
1817+
///
1818+
/// \return \c None if no selector is present or a selector is present but
1819+
/// is not allowed; an instance with an empty \c Identifier if a
1820+
/// selector is present but has no valid identifier; an instance with
1821+
/// a valid \c Identifier if a selector is present and includes a
1822+
/// module name.
1823+
std::optional<Located<Identifier>> parseModuleSelector();
1824+
18121825
enum class DeclNameFlag : uint8_t {
18131826
/// If passed, operator basenames are allowed.
18141827
AllowOperators = 1 << 0,
@@ -1821,6 +1834,9 @@ class Parser {
18211834
/// not ordinary identifiers.
18221835
AllowKeywordsUsingSpecialNames = AllowKeywords | 1 << 2,
18231836

1837+
/// If passed, module selectors are not permitted on this declaration name.
1838+
ModuleSelectorUnsupported = 1 << 3,
1839+
18241840
/// If passed, compound names with argument lists are allowed, unless they
18251841
/// have empty argument lists.
18261842
AllowCompoundNames = 1 << 4,
@@ -1868,7 +1884,8 @@ class Parser {
18681884
SourceLoc &rightAngleLoc, ArgumentList *&argList, bool isExprBasic,
18691885
DiagRef diag);
18701886

1871-
ParserResult<Expr> parseExprIdentifier(bool allowKeyword);
1887+
ParserResult<Expr> parseExprIdentifier(bool allowKeyword,
1888+
bool allowModuleSelector = true);
18721889
Expr *parseExprEditorPlaceholder(Token PlaceholderTok,
18731890
Identifier PlaceholderId);
18741891

lib/Parse/Lexer.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,9 +819,12 @@ static bool isLeftBound(const char *tokBegin, const char *bufferBegin) {
819819
static bool isRightBound(const char *tokEnd, bool isLeftBound,
820820
const char *codeCompletionPtr) {
821821
switch (*tokEnd) {
822+
case ':': // ':' is an expression separator; '::' is not
823+
return tokEnd[1] == ':';
824+
822825
case ' ': case '\r': case '\n': case '\t': // whitespace
823826
case ')': case ']': case '}': // closing delimiters
824-
case ',': case ';': case ':': // expression separators
827+
case ',': case ';': // expression separators
825828
return false;
826829

827830
case '\0':
@@ -2765,7 +2768,7 @@ void Lexer::lexImpl() {
27652768
case '\\': return formToken(tok::backslash, TokStart);
27662769

27672770
case ':':
2768-
if (CurPtr[0] == ':') {
2771+
if (CurPtr[0] == ':' && LangOpts.hasFeature(Feature::ModuleSelector)) {
27692772
CurPtr++;
27702773
return formToken(tok::colon_colon, TokStart);
27712774
}
@@ -2879,6 +2882,7 @@ Token Lexer::getTokenAtLocation(const SourceManager &SM, SourceLoc Loc,
28792882
// Use fake language options; language options only affect validity
28802883
// and the exact token produced.
28812884
LangOptions FakeLangOpts;
2885+
FakeLangOpts.enableFeature(Feature::ModuleSelector);
28822886

28832887
// Here we return comments as tokens because either the caller skipped
28842888
// comments and normally we won't be at the beginning of a comment token

lib/Parse/ParseDecl.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,8 @@ bool Parser::parseSpecializeAttributeArguments(
682682
DeclNameFlag::AllowZeroArgCompoundNames |
683683
DeclNameFlag::AllowKeywordsUsingSpecialNames |
684684
DeclNameFlag::AllowOperators |
685-
DeclNameFlag::AllowLowercaseAndUppercaseSelf);
685+
DeclNameFlag::AllowLowercaseAndUppercaseSelf |
686+
DeclNameFlag::ModuleSelectorUnsupported);
686687
}
687688
}
688689
if (ParamLabel == "spiModule") {
@@ -1136,7 +1137,8 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
11361137
MemberNameLoc, diag::attr_implements_expected_member_name,
11371138
DeclNameFlag::AllowZeroArgCompoundNames |
11381139
DeclNameFlag::AllowOperators |
1139-
DeclNameFlag::AllowLowercaseAndUppercaseSelf);
1140+
DeclNameFlag::AllowLowercaseAndUppercaseSelf |
1141+
DeclNameFlag::ModuleSelectorUnsupported);
11401142
if (!MemberName) {
11411143
Status.setIsParseError();
11421144
}
@@ -1159,7 +1161,7 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
11591161
return Status;
11601162
}
11611163

1162-
// FIXME(ModQual): Reject module qualification on MemberName.
1164+
assert(MemberName.getModuleSelector().empty());
11631165
return ParserResult<ImplementsAttr>(
11641166
ImplementsAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc),
11651167
ProtocolType.get(), MemberName.getFullName(),
@@ -2440,7 +2442,8 @@ Parser::parseMacroRoleAttribute(
24402442
(DeclNameFlag::AllowOperators | DeclNameFlag::AllowKeywords |
24412443
DeclNameFlag::AllowKeywordsUsingSpecialNames |
24422444
DeclNameFlag::AllowCompoundNames |
2443-
DeclNameFlag::AllowZeroArgCompoundNames));
2445+
DeclNameFlag::AllowZeroArgCompoundNames |
2446+
DeclNameFlag::ModuleSelectorUnsupported));
24442447
if (!name) {
24452448
status.setIsParseError();
24462449
return status;
@@ -4245,11 +4248,15 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
42454248
.warnUntilSwiftVersion(6);
42464249
}
42474250

4251+
bool hasModuleSelector = Context.LangOpts.hasFeature(Feature::ModuleSelector)
4252+
&& peekToken().is(tok::colon_colon);
4253+
42484254
// If this not an identifier, the attribute is malformed.
42494255
if (Tok.isNot(tok::identifier) &&
42504256
Tok.isNot(tok::kw_in) &&
42514257
Tok.isNot(tok::kw_inout) &&
4252-
Tok.isNot(tok::kw_rethrows)) {
4258+
Tok.isNot(tok::kw_rethrows) &&
4259+
!hasModuleSelector) {
42534260

42544261
if (Tok.is(tok::code_complete)) {
42554262
if (CodeCompletionCallbacks) {
@@ -4270,7 +4277,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
42704277

42714278
// If the attribute follows the new representation, switch
42724279
// over to the alternate parsing path.
4273-
std::optional<DeclAttrKind> DK =
4280+
std::optional<DeclAttrKind> DK = hasModuleSelector ? std::nullopt :
42744281
DeclAttribute::getAttrKindFromString(Tok.getText());
42754282
if (DK == DeclAttrKind::Rethrows) {
42764283
DK = DeclAttrKind::AtRethrows;
@@ -4282,7 +4289,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
42824289
auto checkInvalidAttrName =
42834290
[&](StringRef invalidName, StringRef correctName, DeclAttrKind kind,
42844291
std::optional<Diag<StringRef, StringRef>> diag = std::nullopt) {
4285-
if (!DK && Tok.getText() == invalidName) {
4292+
if (!DK && !hasModuleSelector && Tok.getText() == invalidName) {
42864293
DK = kind;
42874294

42884295
if (diag) {
@@ -4346,7 +4353,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
43464353
DeclAttrKind::Preconcurrency,
43474354
diag::attr_renamed_warning);
43484355

4349-
if (!DK && Tok.getText() == "warn_unused_result") {
4356+
if (!DK && !hasModuleSelector && Tok.getText() == "warn_unused_result") {
43504357
// The behavior created by @warn_unused_result is now the default. Emit a
43514358
// Fix-It to remove.
43524359
SourceLoc attrLoc = consumeToken();
@@ -4421,9 +4428,10 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
44214428
return parseNewDeclAttribute(Attributes, AtLoc, *DK, isFromClangAttribute);
44224429
}
44234430

4424-
if (TypeAttribute::getAttrKindFromString(Tok.getText()).has_value())
4431+
if (!hasModuleSelector &&
4432+
TypeAttribute::getAttrKindFromString(Tok.getText()).has_value())
44254433
diagnose(Tok, diag::type_attribute_applied_to_decl);
4426-
else if (Tok.isContextualKeyword("unknown")) {
4434+
else if (!hasModuleSelector && Tok.isContextualKeyword("unknown")) {
44274435
diagnose(Tok, diag::unknown_attr_name, "unknown");
44284436
} else {
44294437
// Change the context to create a custom attribute syntax.
@@ -5756,6 +5764,8 @@ static void skipAttribute(Parser &P) {
57565764
// Parse the attribute name, which can be qualified, have
57575765
// generic arguments, and so on.
57585766
do {
5767+
P.parseModuleSelector();
5768+
57595769
if (!(P.consumeIf(tok::identifier) || P.consumeIf(tok::kw_rethrows)) &&
57605770
!P.consumeIf(tok::code_complete))
57615771
return;
@@ -10300,9 +10310,11 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
1030010310
return makeParserCodeCompletionResult<OperatorDecl>();
1030110311
}
1030210312

10313+
// TODO: We could support module selectors for precedence groups if we
10314+
// implemented the lookup for it.
1030310315
groupName = parseDeclNameRef(groupLoc,
1030410316
diag::operator_decl_expected_precedencegroup,
10305-
{});
10317+
DeclNameFlag::ModuleSelectorUnsupported);
1030610318

1030710319
if (Context.TypeCheckerOpts.EnableOperatorDesignatedTypes) {
1030810320
// Designated types have been removed; consume the list (mainly for source
@@ -10600,7 +10612,7 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
1060010612
auto name = parseDeclNameRef(nameLoc,
1060110613
{ diag::expected_precedencegroup_relation,
1060210614
attrName },
10603-
{});
10615+
DeclNameFlag::ModuleSelectorUnsupported);
1060410616
if (!name) {
1060510617
return abortBody();
1060610618
}

0 commit comments

Comments
 (0)