Skip to content

Commit 6a42ae1

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 b909122 commit 6a42ae1

File tree

8 files changed

+239
-163
lines changed

8 files changed

+239
-163
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,17 @@ ERROR(forbidden_extended_escaping_string,none,
9393

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

102108
//------------------------------------------------------------------------------
103109
// MARK: Lexer diagnostics

include/swift/Parse/Parser.h

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -644,21 +644,6 @@ class Parser {
644644
Context.getIdentifier(tok.getText()));
645645
}
646646

647-
/// If the next two tokens appear to form a module selector, consume them and
648-
/// diagnose an error. Call this method before consuming an identifier that
649-
/// should *not* have a module selector before it.
650-
///
651-
/// \param KindName A string describing the name or declaration being written.
652-
/// \param IsDef If \c true, the identifier defines a declaration's name, and
653-
/// \p KindName should be a string describing the declaration; if \c false,
654-
/// the identifier does something else, and \p KindName should be a more
655-
/// complete string.
656-
///
657-
/// \returns true if a module selector was consumed and an error was diagnosed;
658-
/// false otherwise.
659-
bool
660-
diagnoseAndConsumeIfModuleSelector(StringRef KindName, bool IsDef = true);
661-
662647
/// Retrieve the location just past the end of the previous
663648
/// source location.
664649
SourceLoc getEndOfPreviousLoc() const;
@@ -1630,6 +1615,80 @@ class Parser {
16301615
/// \param loc The location of the label (empty if it doesn't exist)
16311616
void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc);
16321617

1618+
/// The reason we are trying to parse a module selector. Other than
1619+
/// \c Allowed, all reasons indicate an error should be emitted.
1620+
enum class ModuleSelectorReason : uint8_t {
1621+
/// Use of a module selector is allowed.
1622+
Allowed,
1623+
1624+
/// Not allowed; this is the name of a declaration. The string parameter
1625+
/// describes the declaration in question (e.g. a class, struct, etc.).
1626+
///
1627+
/// If a Decl subclass also cannot have its name prefixed at its use sites
1628+
/// (like ParamDecls), it will have a separate reason from this one.
1629+
NameInDecl,
1630+
1631+
/// Not allowed; this the name of a variable being captured. Has a special
1632+
/// fix-it transforming `Mod::foo` into `foo = Mod::foo`.
1633+
Capture,
1634+
1635+
/// Not allowed; this is the name of a parameter being declared.
1636+
ParamDecl,
1637+
1638+
/// Not allowed; this is the name of a generic parameter being declared.
1639+
GenericParamDecl,
1640+
1641+
/// Not allowed; this is an argument label at either a declaration or
1642+
/// use site.
1643+
ArgumentLabel,
1644+
1645+
/// Not allowed; this is the name of an SPI group for the @_spi attribute.
1646+
SPIGroup,
1647+
1648+
/// Not allowed; this is an Objective-C selector or class name, so it will
1649+
/// be used at runtime where the module selector would have no effect.
1650+
ObjCName,
1651+
1652+
/// Not allowed; this is the name of a sibling to the current declaration
1653+
/// and has some kind of special contextual lookup.
1654+
///
1655+
/// It may be possible to support module selectors on these in the future,
1656+
/// but at the moment these are all compiler-internal attributes and it
1657+
/// doesn't seem worth the effort.
1658+
SiblingDeclName,
1659+
1660+
/// Not allowed; this is the name of a precedence group, either at its
1661+
/// declaration site (where it makes no sense to use a module selector) or
1662+
/// at a use site (where it might make sense, but is not currently
1663+
/// implemented).
1664+
PrecedenceGroup,
1665+
};
1666+
1667+
/// Attempts to parse a \c module-selector if one is present.
1668+
///
1669+
/// \verbatim
1670+
/// module-selector: identifier '::'
1671+
/// \endverbatim
1672+
///
1673+
/// At most use sites, this is actually called to parse a module selector
1674+
/// which should \em not be present in the source code, but which users might
1675+
/// plausibly write incorrectly. The \p reason argument indicates what the
1676+
/// name that is about to be parsed is, and therefore why there should not be
1677+
/// a module selector there.
1678+
///
1679+
/// \param reason If not \c Allowed, gives a reason why a \c module-selector
1680+
/// should not be present in the source here.
1681+
/// \param declKindName For \c ModuleSelectorReason::NameInDecl, the kind of
1682+
/// declaration whose name we are parsing. Otherwise unused.
1683+
///
1684+
/// \return \c None if no selector is present or a selector is present but
1685+
/// is not allowed; an instance with an empty \c Identifier if a
1686+
/// selector is present but has no valid identifier; an instance with
1687+
/// a valid \c Identifier if a selector is present and includes a
1688+
/// module name.
1689+
Optional<Located<Identifier>>
1690+
parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName = "");
1691+
16331692
enum class DeclNameFlag : uint8_t {
16341693
/// If passed, operator basenames are allowed.
16351694
AllowOperators = 1 << 0,
@@ -1642,10 +1701,6 @@ class Parser {
16421701
/// not ordinary identifiers.
16431702
AllowKeywordsUsingSpecialNames = AllowKeywords | 1 << 2,
16441703

1645-
/// If passed, a module selector (ModuleName::) is permitted before the base
1646-
/// name.
1647-
AllowModuleSelector = 1 << 3,
1648-
16491704
/// If passed, compound names with argument lists are allowed, unless they
16501705
/// have empty argument lists.
16511706
AllowCompoundNames = 1 << 4,
@@ -1675,8 +1730,9 @@ class Parser {
16751730
/// unqualified-decl-name:
16761731
/// unqualified-decl-base-name
16771732
/// unqualified-decl-base-name '(' ((identifier | '_') ':') + ')'
1678-
DeclNameRef parseDeclNameRef(DeclNameLoc &loc, const Diagnostic &diag,
1679-
DeclNameOptions flags);
1733+
DeclNameRef parseDeclNameRef(
1734+
DeclNameLoc &loc, const Diagnostic &diag, DeclNameOptions flags,
1735+
ModuleSelectorReason modSelReason = ModuleSelectorReason::Allowed);
16801736

16811737
ParserResult<Expr> parseExprIdentifier();
16821738
Expr *parseExprEditorPlaceholder(Token PlaceholderTok,

lib/Parse/ParseDecl.cpp

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,8 @@ bool Parser::parseSpecializeAttributeArguments(
670670
targetFunctionLoc, diag::attr_specialize_expected_function,
671671
DeclNameFlag::AllowZeroArgCompoundNames |
672672
DeclNameFlag::AllowKeywordsUsingSpecialNames |
673-
DeclNameFlag::AllowOperators);
673+
DeclNameFlag::AllowOperators,
674+
ModuleSelectorReason::SiblingDeclName);
674675
}
675676
}
676677
if (ParamLabel == "spiModule") {
@@ -686,7 +687,7 @@ bool Parser::parseSpecializeAttributeArguments(
686687
consumeToken();
687688
return false;
688689
}
689-
diagnoseAndConsumeIfModuleSelector("SPI group");
690+
parseModuleSelector(ModuleSelectorReason::SPIGroup);
690691
auto text = Tok.getText();
691692
spiGroups.push_back(Context.getIdentifier(text));
692693
consumeToken();
@@ -815,7 +816,8 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
815816
MemberName = parseDeclNameRef(MemberNameLoc,
816817
diag::attr_implements_expected_member_name,
817818
DeclNameFlag::AllowZeroArgCompoundNames |
818-
DeclNameFlag::AllowOperators);
819+
DeclNameFlag::AllowOperators,
820+
ModuleSelectorReason::SiblingDeclName);
819821
if (!MemberName) {
820822
Status.setIsParseError();
821823
}
@@ -1193,8 +1195,7 @@ static bool parseQualifiedDeclName(Parser &P, Diag<> nameParseError,
11931195
original.Loc, nameParseError,
11941196
Parser::DeclNameFlag::AllowZeroArgCompoundNames |
11951197
Parser::DeclNameFlag::AllowKeywordsUsingSpecialNames |
1196-
Parser::DeclNameFlag::AllowOperators |
1197-
Parser::DeclNameFlag::AllowModuleSelector);
1198+
Parser::DeclNameFlag::AllowOperators);
11981199
// The base type is optional, but the final unqualified declaration name is
11991200
// not. If name could not be parsed, return true for error.
12001201
if (!original.Name)
@@ -1862,7 +1863,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
18621863
return false;
18631864
}
18641865

1865-
diagnoseAndConsumeIfModuleSelector("SPI group");
1866+
parseModuleSelector(ModuleSelectorReason::SPIGroup);
18661867

18671868
auto text = Tok.getText();
18681869
spiGroups.push_back(Context.getIdentifier(text));
@@ -1974,10 +1975,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
19741975
return false;
19751976
}
19761977

1977-
diagnoseAndConsumeIfModuleSelector(
1978-
"Objective-C class name in @_swift_native_objc_runtime_base",
1979-
/*IsDef=*/true);
1980-
1978+
parseModuleSelector(ModuleSelectorReason::ObjCName);
19811979
if (Tok.isNot(tok::identifier)) {
19821980
diagnose(Loc, diag::swift_native_objc_runtime_base_must_be_identifier);
19831981
return false;
@@ -2495,8 +2493,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
24952493
diag::attr_dynamic_replacement_expected_function,
24962494
DeclNameFlag::AllowZeroArgCompoundNames |
24972495
DeclNameFlag::AllowKeywordsUsingSpecialNames |
2498-
DeclNameFlag::AllowOperators |
2499-
DeclNameFlag::AllowModuleSelector);
2496+
DeclNameFlag::AllowOperators);
25002497
}
25012498

25022499
// Parse the matching ')'.
@@ -2599,14 +2596,14 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
25992596
}
26002597

26012598
case DAK_ProjectedValueProperty: {
2602-
diagnoseAndConsumeIfModuleSelector("@_projectedValueProperty attribute");
2603-
26042599
if (!consumeIf(tok::l_paren)) {
26052600
diagnose(Loc, diag::attr_expected_lparen, AttrName,
26062601
DeclAttribute::isDeclModifier(DK));
26072602
return false;
26082603
}
26092604

2605+
parseModuleSelector(ModuleSelectorReason::SiblingDeclName);
2606+
26102607
if (Tok.isNot(tok::identifier)) {
26112608
diagnose(Loc, diag::projection_value_property_not_identifier);
26122609
return false;
@@ -3142,8 +3139,7 @@ bool Parser::parseConventionAttributeInternal(
31423139

31433140
DeclNameLoc unusedLoc;
31443141
convention.WitnessMethodProtocol = parseDeclNameRef(unusedLoc,
3145-
diag::convention_attribute_witness_method_expected_protocol,
3146-
DeclNameFlag::AllowModuleSelector);
3142+
diag::convention_attribute_witness_method_expected_protocol, {});
31473143
}
31483144

31493145
// Parse the ')'. We can't use parseMatchingToken if we're in
@@ -4822,27 +4818,11 @@ ParserStatus Parser::parseInheritance(
48224818
return Status;
48234819
}
48244820

4825-
bool Parser::diagnoseAndConsumeIfModuleSelector(StringRef KindName,
4826-
bool IsDefinition) {
4827-
if (!Context.LangOpts.EnableExperimentalModuleSelector ||
4828-
peekToken().isNot(tok::colon_colon))
4829-
return false;
4830-
4831-
// Diagnose an error and consume the module selector so we can continue.
4832-
SourceLoc start = consumeToken();
4833-
SourceLoc end = consumeToken(tok::colon_colon);
4834-
diagnose(end, diag::module_selector_not_allowed_in_decl, IsDefinition,
4835-
KindName)
4836-
.fixItRemove({start, end});
4837-
4838-
return true;
4839-
}
4840-
48414821
static ParserStatus
48424822
parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc,
48434823
StringRef DeclKindName,
48444824
llvm::function_ref<bool(const Token &)> canRecover) {
4845-
P.diagnoseAndConsumeIfModuleSelector(DeclKindName);
4825+
P.parseModuleSelector(Parser::ModuleSelectorReason::NameInDecl, DeclKindName);
48464826

48474827
if (P.Tok.is(tok::identifier)) {
48484828
Loc = P.consumeIdentifier(Result, /*diagnoseDollarPrefix=*/true);
@@ -5759,7 +5739,7 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc,
57595739
SyntaxParsingContext ParamCtx(P.SyntaxContext, SyntaxKind::AccessorParameter);
57605740
StartLoc = P.consumeToken(tok::l_paren);
57615741

5762-
P.diagnoseAndConsumeIfModuleSelector("accessor parameter");
5742+
P.parseModuleSelector(Parser::ModuleSelectorReason::ParamDecl);
57635743

57645744
if (P.Tok.isNot(tok::identifier)) {
57655745
P.diagnose(P.Tok, diag::expected_accessor_parameter_name,
@@ -7245,8 +7225,6 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags,
72457225
break;
72467226
}
72477227

7248-
diagnoseAndConsumeIfModuleSelector("enum 'case'");
7249-
72507228
if (Tok.is(tok::identifier)) {
72517229
Status |= parseIdentifierDeclName(
72527230
*this, Name, NameLoc, "enum 'case'", [](const Token &next) {
@@ -8164,11 +8142,10 @@ parsePrecedenceGroupNameList(Parser &P, Fn takeGroupName) {
81648142

81658143
// TODO: We could support module selectors for precedence groups if we
81668144
// implemented the lookup for it.
8167-
P.diagnoseAndConsumeIfModuleSelector("precedence group specifier",
8168-
/*isDef=*/false);
81698145
DeclNameLoc nameLoc;
81708146
auto name = P.parseDeclNameRef(nameLoc,
8171-
diag::expected_group_name_in_precedencegroup_list, {});
8147+
diag::expected_group_name_in_precedencegroup_list, {},
8148+
Parser::ModuleSelectorReason::PrecedenceGroup);
81728149
if (!name)
81738150
return makeParserError();
81748151

@@ -8307,7 +8284,7 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
83078284
return nullptr;
83088285
}
83098286

8310-
diagnoseAndConsumeIfModuleSelector("precedence group");
8287+
parseModuleSelector(ModuleSelectorReason::PrecedenceGroup);
83118288

83128289
Identifier name;
83138290
SourceLoc nameLoc;

0 commit comments

Comments
 (0)