Skip to content

Commit ab30cc9

Browse files
committed
Parse module selectors in permitted locations
1 parent d2e4867 commit ab30cc9

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
@@ -1817,6 +1817,19 @@ class Parser {
18171817
void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc,
18181818
bool isAttr = false);
18191819

1820+
/// Attempts to parse a \c module-selector if one is present.
1821+
///
1822+
/// \verbatim
1823+
/// module-selector: identifier '::'
1824+
/// \endverbatim
1825+
///
1826+
/// \return \c None if no selector is present or a selector is present but
1827+
/// is not allowed; an instance with an empty \c Identifier if a
1828+
/// selector is present but has no valid identifier; an instance with
1829+
/// a valid \c Identifier if a selector is present and includes a
1830+
/// module name.
1831+
std::optional<Located<Identifier>> parseModuleSelector();
1832+
18201833
enum class DeclNameFlag : uint8_t {
18211834
/// If passed, operator basenames are allowed.
18221835
AllowOperators = 1 << 0,
@@ -1829,6 +1842,9 @@ class Parser {
18291842
/// not ordinary identifiers.
18301843
AllowKeywordsUsingSpecialNames = AllowKeywords | 1 << 2,
18311844

1845+
/// If passed, module selectors are not permitted on this declaration name.
1846+
ModuleSelectorUnsupported = 1 << 3,
1847+
18321848
/// If passed, compound names with argument lists are allowed, unless they
18331849
/// have empty argument lists.
18341850
AllowCompoundNames = 1 << 4,
@@ -1876,7 +1892,8 @@ class Parser {
18761892
SourceLoc &rightAngleLoc, ArgumentList *&argList, bool isExprBasic,
18771893
DiagRef diag);
18781894

1879-
ParserResult<Expr> parseExprIdentifier(bool allowKeyword);
1895+
ParserResult<Expr> parseExprIdentifier(bool allowKeyword,
1896+
bool allowModuleSelector = true);
18801897
Expr *parseExprEditorPlaceholder(Token PlaceholderTok,
18811898
Identifier PlaceholderId);
18821899

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;
@@ -4269,11 +4272,15 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
42694272
.warnUntilSwiftVersion(6);
42704273
}
42714274

4275+
bool hasModuleSelector = Context.LangOpts.hasFeature(Feature::ModuleSelector)
4276+
&& peekToken().is(tok::colon_colon);
4277+
42724278
// If this not an identifier, the attribute is malformed.
42734279
if (Tok.isNot(tok::identifier) &&
42744280
Tok.isNot(tok::kw_in) &&
42754281
Tok.isNot(tok::kw_inout) &&
4276-
Tok.isNot(tok::kw_rethrows)) {
4282+
Tok.isNot(tok::kw_rethrows) &&
4283+
!hasModuleSelector) {
42774284

42784285
if (Tok.is(tok::code_complete)) {
42794286
if (CodeCompletionCallbacks) {
@@ -4294,7 +4301,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
42944301

42954302
// If the attribute follows the new representation, switch
42964303
// over to the alternate parsing path.
4297-
std::optional<DeclAttrKind> DK =
4304+
std::optional<DeclAttrKind> DK = hasModuleSelector ? std::nullopt :
42984305
DeclAttribute::getAttrKindFromString(Tok.getText());
42994306
if (DK == DeclAttrKind::Rethrows) {
43004307
DK = DeclAttrKind::AtRethrows;
@@ -4306,7 +4313,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
43064313
auto checkInvalidAttrName =
43074314
[&](StringRef invalidName, StringRef correctName, DeclAttrKind kind,
43084315
std::optional<Diag<StringRef, StringRef>> diag = std::nullopt) {
4309-
if (!DK && Tok.getText() == invalidName) {
4316+
if (!DK && !hasModuleSelector && Tok.getText() == invalidName) {
43104317
DK = kind;
43114318

43124319
if (diag) {
@@ -4370,7 +4377,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
43704377
DeclAttrKind::Preconcurrency,
43714378
diag::attr_renamed_warning);
43724379

4373-
if (!DK && Tok.getText() == "warn_unused_result") {
4380+
if (!DK && !hasModuleSelector && Tok.getText() == "warn_unused_result") {
43744381
// The behavior created by @warn_unused_result is now the default. Emit a
43754382
// Fix-It to remove.
43764383
SourceLoc attrLoc = consumeToken();
@@ -4445,9 +4452,10 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
44454452
return parseNewDeclAttribute(Attributes, AtLoc, *DK, isFromClangAttribute);
44464453
}
44474454

4448-
if (TypeAttribute::getAttrKindFromString(Tok.getText()).has_value())
4455+
if (!hasModuleSelector &&
4456+
TypeAttribute::getAttrKindFromString(Tok.getText()).has_value())
44494457
diagnose(Tok, diag::type_attribute_applied_to_decl);
4450-
else if (Tok.isContextualKeyword("unknown")) {
4458+
else if (!hasModuleSelector && Tok.isContextualKeyword("unknown")) {
44514459
diagnose(Tok, diag::unknown_attr_name, "unknown");
44524460
} else {
44534461
// Change the context to create a custom attribute syntax.
@@ -5780,6 +5788,8 @@ static void skipAttribute(Parser &P) {
57805788
// Parse the attribute name, which can be qualified, have
57815789
// generic arguments, and so on.
57825790
do {
5791+
P.parseModuleSelector();
5792+
57835793
if (!(P.consumeIf(tok::identifier) || P.consumeIf(tok::kw_rethrows)) &&
57845794
!P.consumeIf(tok::code_complete))
57855795
return;
@@ -10330,9 +10340,11 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
1033010340
return makeParserCodeCompletionResult<OperatorDecl>();
1033110341
}
1033210342

10343+
// TODO: We could support module selectors for precedence groups if we
10344+
// implemented the lookup for it.
1033310345
groupName = parseDeclNameRef(groupLoc,
1033410346
diag::operator_decl_expected_precedencegroup,
10335-
{});
10347+
DeclNameFlag::ModuleSelectorUnsupported);
1033610348

1033710349
if (Context.TypeCheckerOpts.EnableOperatorDesignatedTypes) {
1033810350
// Designated types have been removed; consume the list (mainly for source
@@ -10630,7 +10642,7 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
1063010642
auto name = parseDeclNameRef(nameLoc,
1063110643
{ diag::expected_precedencegroup_relation,
1063210644
attrName },
10633-
{});
10645+
DeclNameFlag::ModuleSelectorUnsupported);
1063410646
if (!name) {
1063510647
return abortBody();
1063610648
}

0 commit comments

Comments
 (0)