Skip to content

Commit d60b079

Browse files
committed
Better formalize module selector diagnostics
• The same method is now always used to parse module selectors, whether or not they are valid • A parameter to this method describes the reason for invalidity, and is used to generate its diagnostics. • This also helps set up future changes
1 parent 5794c53 commit d60b079

File tree

8 files changed

+241
-157
lines changed

8 files changed

+241
-157
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,18 @@ ERROR(forbidden_extended_escaping_string,none,
9595

9696
ERROR(expected_identifier_in_module_selector,none,
9797
"expected identifier in module selector", ())
98-
ERROR(module_selector_not_allowed_here,none,
99-
"name cannot be qualified with module selector here", ())
100-
ERROR(module_selector_not_allowed_in_decl,none,
101-
"%select{%1|name of %1 declaration}0 cannot be qualified with module "
102-
"selector", (bool, StringRef))
98+
ERROR(module_selector_not_allowed,none,
99+
"%select{%error|name in %1 declaration|captured variable name|"
100+
"parameter name|generic parameter name|argument label|SPI group|"
101+
"Objective-C name|name of sibling declaration|precedence group name|"
102+
"attribute parameter value|%error}0 cannot be qualified with a module "
103+
"selector",
104+
(uint8_t, StringRef))
105+
NOTE(fixit_remove_module_selector,none,
106+
"remove module selector from this name", ())
107+
NOTE(fixit_capture_with_explicit_name,none,
108+
"explicitly capture into a variable named '%0'",
109+
(StringRef))
103110

104111
//------------------------------------------------------------------------------
105112
// MARK: Lexer diagnostics

include/swift/Parse/Parser.h

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -543,21 +543,6 @@ class Parser {
543543
/// identifiers in addition to a standalone '$'.
544544
void diagnoseDollarIdentifier(const Token &tok, bool diagnoseDollarPrefix);
545545

546-
/// If the next two tokens appear to form a module selector, consume them and
547-
/// diagnose an error. Call this method before consuming an identifier that
548-
/// should *not* have a module selector before it.
549-
///
550-
/// \param KindName A string describing the name or declaration being written.
551-
/// \param IsDef If \c true, the identifier defines a declaration's name, and
552-
/// \p KindName should be a string describing the declaration; if \c false,
553-
/// the identifier does something else, and \p KindName should be a more
554-
/// complete string.
555-
///
556-
/// \returns true if a module selector was consumed and an error was diagnosed;
557-
/// false otherwise.
558-
bool
559-
diagnoseAndConsumeIfModuleSelector(StringRef KindName, bool IsDef = true);
560-
561546
/// Retrieve the location just past the end of the previous
562547
/// source location.
563548
SourceLoc getEndOfPreviousLoc() const;
@@ -1821,6 +1806,84 @@ class Parser {
18211806
void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc,
18221807
bool isAttr = false);
18231808

1809+
/// The reason we are trying to parse a module selector. Other than
1810+
/// \c Allowed, all reasons indicate an error should be emitted.
1811+
enum class ModuleSelectorReason : uint8_t {
1812+
/// Use of a module selector is allowed.
1813+
Allowed,
1814+
1815+
/// Not allowed; this is the name of a declaration. The string parameter
1816+
/// describes the declaration in question (e.g. a class, struct, etc.).
1817+
///
1818+
/// If a Decl subclass also cannot have its name prefixed at its use sites
1819+
/// (like ParamDecls), it will have a separate reason from this one.
1820+
NameInDecl,
1821+
1822+
/// Not allowed; this the name of a variable being captured. Has a special
1823+
/// fix-it transforming `Mod::foo` into `foo = Mod::foo`.
1824+
Capture,
1825+
1826+
/// Not allowed; this is the name of a parameter being declared.
1827+
ParamDecl,
1828+
1829+
/// Not allowed; this is the name of a generic parameter being declared.
1830+
GenericParamDecl,
1831+
1832+
/// Not allowed; this is an argument label at either a declaration or
1833+
/// use site.
1834+
ArgumentLabel,
1835+
1836+
/// Not allowed; this is the name of an SPI group for the @_spi attribute.
1837+
SPIGroup,
1838+
1839+
/// Not allowed; this is an Objective-C selector or class name, so it will
1840+
/// be used at runtime where the module selector would have no effect.
1841+
ObjCName,
1842+
1843+
/// Not allowed; this is the name of a sibling to the current declaration
1844+
/// and has some kind of special contextual lookup.
1845+
///
1846+
/// It may be possible to support module selectors on these in the future,
1847+
/// but at the moment these are all compiler-internal attributes and it
1848+
/// doesn't seem worth the effort.
1849+
SiblingDeclName,
1850+
1851+
/// Not allowed; this is the name of a precedence group, either at its
1852+
/// declaration site (where it makes no sense to use a module selector) or
1853+
/// at a use site (where it might make sense, but is not currently
1854+
/// implemented).
1855+
PrecedenceGroup,
1856+
1857+
/// Not allowed; this is a specially-handled keyword or identifier in an
1858+
/// attribute's argument list.
1859+
AttrParameter,
1860+
};
1861+
1862+
/// Attempts to parse a \c module-selector if one is present.
1863+
///
1864+
/// \verbatim
1865+
/// module-selector: identifier '::'
1866+
/// \endverbatim
1867+
///
1868+
/// At most use sites, this is actually called to parse a module selector
1869+
/// which should \em not be present in the source code, but which users might
1870+
/// plausibly write incorrectly. The \p reason argument indicates what the
1871+
/// name that is about to be parsed is, and therefore why there should not be
1872+
/// a module selector there.
1873+
///
1874+
/// \param reason If not \c Allowed, gives a reason why a \c module-selector
1875+
/// should not be present in the source here.
1876+
/// \param declKindName For \c ModuleSelectorReason::NameInDecl, the kind of
1877+
/// declaration whose name we are parsing. Otherwise unused.
1878+
///
1879+
/// \return \c None if no selector is present or a selector is present but
1880+
/// is not allowed; an instance with an empty \c Identifier if a
1881+
/// selector is present but has no valid identifier; an instance with
1882+
/// a valid \c Identifier if a selector is present and includes a
1883+
/// module name.
1884+
std::optional<Located<Identifier>>
1885+
parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName = "");
1886+
18241887
enum class DeclNameFlag : uint8_t {
18251888
/// If passed, operator basenames are allowed.
18261889
AllowOperators = 1 << 0,
@@ -1833,10 +1896,6 @@ class Parser {
18331896
/// not ordinary identifiers.
18341897
AllowKeywordsUsingSpecialNames = AllowKeywords | 1 << 2,
18351898

1836-
/// If passed, a module selector (ModuleName::) is permitted before the base
1837-
/// name.
1838-
AllowModuleSelector = 1 << 3,
1839-
18401899
/// If passed, compound names with argument lists are allowed, unless they
18411900
/// have empty argument lists.
18421901
AllowCompoundNames = 1 << 4,
@@ -1871,8 +1930,9 @@ class Parser {
18711930
/// unqualified-decl-name:
18721931
/// unqualified-decl-base-name
18731932
/// unqualified-decl-base-name '(' ((identifier | '_') ':') + ')'
1874-
DeclNameRef parseDeclNameRef(DeclNameLoc &loc, DiagRef diag,
1875-
DeclNameOptions flags);
1933+
DeclNameRef parseDeclNameRef(
1934+
DeclNameLoc &loc, DiagRef diag, DeclNameOptions flags,
1935+
ModuleSelectorReason modSelReason = ModuleSelectorReason::Allowed);
18761936

18771937
/// Parse macro expansion.
18781938
///

lib/Parse/ParseDecl.cpp

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,8 @@ bool Parser::parseSpecializeAttributeArguments(
671671
DeclNameFlag::AllowZeroArgCompoundNames |
672672
DeclNameFlag::AllowKeywordsUsingSpecialNames |
673673
DeclNameFlag::AllowOperators |
674-
DeclNameFlag::AllowLowercaseAndUppercaseSelf);
674+
DeclNameFlag::AllowLowercaseAndUppercaseSelf,
675+
ModuleSelectorReason::SiblingDeclName);
675676
}
676677
}
677678
if (ParamLabel == "spiModule") {
@@ -687,7 +688,7 @@ bool Parser::parseSpecializeAttributeArguments(
687688
consumeToken();
688689
return false;
689690
}
690-
diagnoseAndConsumeIfModuleSelector("SPI group");
691+
parseModuleSelector(ModuleSelectorReason::SPIGroup);
691692
auto text = Tok.getText();
692693
spiGroups.push_back(Context.getIdentifier(text));
693694
consumeToken();
@@ -1117,7 +1118,8 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
11171118
MemberNameLoc, diag::attr_implements_expected_member_name,
11181119
DeclNameFlag::AllowZeroArgCompoundNames |
11191120
DeclNameFlag::AllowOperators |
1120-
DeclNameFlag::AllowLowercaseAndUppercaseSelf);
1121+
DeclNameFlag::AllowLowercaseAndUppercaseSelf,
1122+
ModuleSelectorReason::SiblingDeclName);
11211123
if (!MemberName) {
11221124
Status.setIsParseError();
11231125
}
@@ -1588,8 +1590,7 @@ static bool parseQualifiedDeclName(Parser &P, Diag<> nameParseError,
15881590
Parser::DeclNameFlag::AllowZeroArgCompoundNames |
15891591
Parser::DeclNameFlag::AllowKeywordsUsingSpecialNames |
15901592
Parser::DeclNameFlag::AllowOperators |
1591-
Parser::DeclNameFlag::AllowLowercaseAndUppercaseSelf |
1592-
Parser::DeclNameFlag::AllowModuleSelector);
1593+
Parser::DeclNameFlag::AllowLowercaseAndUppercaseSelf);
15931594
// The base type is optional, but the final unqualified declaration name is
15941595
// not. If name could not be parsed, return true for error.
15951596
if (!original.Name)
@@ -2498,8 +2499,7 @@ static std::optional<Identifier> parseSingleAttrOptionImpl(
24982499
P.consumeToken(tok::code_complete);
24992500
}
25002501

2501-
P.diagnoseAndConsumeIfModuleSelector("keyword in attribute arguments",
2502-
/*IsDef=*/true);
2502+
P.parseModuleSelector(Parser::ModuleSelectorReason::AttrParameter);
25032503

25042504
StringRef parsedName = P.Tok.getText();
25052505
if (!P.consumeIf(tok::identifier)) {
@@ -2975,7 +2975,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
29752975
return makeParserSuccess();
29762976
}
29772977

2978-
diagnoseAndConsumeIfModuleSelector("SPI group");
2978+
parseModuleSelector(ModuleSelectorReason::SPIGroup);
29792979

29802980
auto text = Tok.getText();
29812981
// An spi group name can be '_' as in @_spi(_), a specifier for implicit import of the SPI.
@@ -3540,8 +3540,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
35403540
DeclNameFlag::AllowZeroArgCompoundNames |
35413541
DeclNameFlag::AllowKeywordsUsingSpecialNames |
35423542
DeclNameFlag::AllowOperators |
3543-
DeclNameFlag::AllowLowercaseAndUppercaseSelf |
3544-
DeclNameFlag::AllowModuleSelector);
3543+
DeclNameFlag::AllowLowercaseAndUppercaseSelf);
35453544
}
35463545

35473546
// Parse the matching ')'.
@@ -4517,8 +4516,7 @@ bool Parser::parseConventionAttributeInternal(SourceLoc atLoc, SourceLoc attrLoc
45174516
DeclNameLoc unusedLoc;
45184517
witnessMethodProtocol = parseDeclNameRef(
45194518
unusedLoc, diag::convention_attribute_witness_method_expected_protocol,
4520-
DeclNameFlag::AllowLowercaseAndUppercaseSelf
4521-
| DeclNameFlag::AllowModuleSelector);
4519+
DeclNameFlag::AllowLowercaseAndUppercaseSelf);
45224520
}
45234521

45244522
// Parse the ')'. We can't use parseMatchingToken if we're in
@@ -6695,27 +6693,11 @@ ParserStatus Parser::parseInheritance(
66956693
return Status;
66966694
}
66976695

6698-
bool Parser::diagnoseAndConsumeIfModuleSelector(StringRef KindName,
6699-
bool IsDefinition) {
6700-
if (!Context.LangOpts.hasFeature(Feature::ModuleSelector) ||
6701-
peekToken().isNot(tok::colon_colon))
6702-
return false;
6703-
6704-
// Diagnose an error and consume the module selector so we can continue.
6705-
SourceLoc start = consumeToken();
6706-
SourceLoc end = consumeToken(tok::colon_colon);
6707-
diagnose(end, diag::module_selector_not_allowed_in_decl, IsDefinition,
6708-
KindName)
6709-
.fixItRemove({start, end});
6710-
6711-
return true;
6712-
}
6713-
67146696
static ParserStatus
67156697
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc,
67166698
StringRef DeclKindName,
67176699
llvm::function_ref<bool(const Token &)> canRecover) {
6718-
P.diagnoseAndConsumeIfModuleSelector(DeclKindName);
6700+
P.parseModuleSelector(Parser::ModuleSelectorReason::NameInDecl, DeclKindName);
67196701

67206702
if (P.Tok.is(tok::identifier)) {
67216703
Loc = P.consumeIdentifier(Result, /*diagnoseDollarPrefix=*/true);
@@ -7559,7 +7541,7 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc,
75597541
if (SpecifierLoc.isValid() && P.Tok.is(tok::l_paren)) {
75607542
StartLoc = P.consumeToken(tok::l_paren);
75617543

7562-
P.diagnoseAndConsumeIfModuleSelector("accessor parameter");
7544+
P.parseModuleSelector(Parser::ModuleSelectorReason::ParamDecl);
75637545

75647546
if (P.Tok.isNot(tok::identifier)) {
75657547
P.diagnose(P.Tok, diag::expected_accessor_parameter_name,
@@ -9174,8 +9156,6 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags,
91749156
break;
91759157
}
91769158

9177-
diagnoseAndConsumeIfModuleSelector("enum 'case'");
9178-
91799159
if (Tok.is(tok::identifier)) {
91809160
Status |= parseIdentifierDeclName(
91819161
*this, Name, NameLoc, "enum 'case'", [](const Token &next) {
@@ -10142,11 +10122,9 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
1014210122

1014310123
// TODO: We could support module selectors for precedence groups if we
1014410124
// implemented the lookup for it.
10145-
diagnoseAndConsumeIfModuleSelector("precedence group specifier",
10146-
/*isDef=*/false);
1014710125
groupName = parseDeclNameRef(groupLoc,
1014810126
diag::operator_decl_expected_precedencegroup,
10149-
{});
10127+
{}, ModuleSelectorReason::PrecedenceGroup);
1015010128

1015110129
if (Context.TypeCheckerOpts.EnableOperatorDesignatedTypes) {
1015210130
// Designated types have been removed; consume the list (mainly for source
@@ -10241,7 +10219,7 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
1024110219
return nullptr;
1024210220
}
1024310221

10244-
diagnoseAndConsumeIfModuleSelector("precedence group");
10222+
parseModuleSelector(ModuleSelectorReason::PrecedenceGroup);
1024510223

1024610224
Identifier name;
1024710225
SourceLoc nameLoc;
@@ -10446,7 +10424,8 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
1044610424
auto name = parseDeclNameRef(nameLoc,
1044710425
{ diag::expected_precedencegroup_relation,
1044810426
attrName },
10449-
{});
10427+
{},
10428+
ModuleSelectorReason::PrecedenceGroup);
1045010429
if (!name) {
1045110430
return abortBody();
1045210431
}

0 commit comments

Comments
 (0)