Skip to content

Commit 15462d1

Browse files
committed
Diagnose invalid module selectors in more places
When a module selector does not start with an identifier, we often end up trying to parse whatever token it *does* have there as something else, which doesn't handle the module selector well. Correct this by speculatively parsing invalid selectors in various places.
1 parent d60b079 commit 15462d1

File tree

6 files changed

+165
-5
lines changed

6 files changed

+165
-5
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ ERROR(forbidden_extended_escaping_string,none,
9696
ERROR(expected_identifier_in_module_selector,none,
9797
"expected identifier in module selector", ())
9898
ERROR(module_selector_not_allowed,none,
99-
"%select{%error|name in %1 declaration|captured variable name|"
99+
"%select{%error|%error|name in %1 declaration|captured variable name|"
100100
"parameter name|generic parameter name|argument label|SPI group|"
101101
"Objective-C name|name of sibling declaration|precedence group name|"
102102
"attribute parameter value|%error}0 cannot be qualified with a module "

include/swift/Parse/Parser.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1807,11 +1807,16 @@ class Parser {
18071807
bool isAttr = false);
18081808

18091809
/// The reason we are trying to parse a module selector. Other than
1810-
/// \c Allowed, all reasons indicate an error should be emitted.
1810+
/// \c Allowed and \c InvalidOnly, all reasons indicate an error should be
1811+
/// emitted.
18111812
enum class ModuleSelectorReason : uint8_t {
18121813
/// Use of a module selector is allowed.
18131814
Allowed,
18141815

1816+
/// Only parse (and diagnose) invalid module selectors here; if the module
1817+
/// selector is valid, return \c None and leave it for later.
1818+
InvalidOnly,
1819+
18151820
/// Not allowed; this is the name of a declaration. The string parameter
18161821
/// describes the declaration in question (e.g. a class, struct, etc.).
18171822
///

lib/Parse/Lexer.cpp

Lines changed: 4 additions & 1 deletion
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':

lib/Parse/ParseExpr.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,9 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
611611
/// '&' expr-unary(Mode)
612612
///
613613
ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
614+
// If we have an invalid module selector, consume that first.
615+
parseModuleSelector(ModuleSelectorReason::InvalidOnly);
616+
614617
UnresolvedDeclRefExpr *Operator;
615618

616619
// First check to see if we have the start of a regex literal `/.../`.
@@ -1268,6 +1271,8 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
12681271
Tok.setKind(tok::period);
12691272
consumeToken();
12701273

1274+
parseModuleSelector(ModuleSelectorReason::InvalidOnly);
1275+
12711276
// Handle "x.42" - a tuple index.
12721277
if (Tok.is(tok::integer_literal)) {
12731278
DeclNameRef name(Context.getIdentifier(Tok.getText()));
@@ -1639,6 +1644,9 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
16391644
/// expr-selector
16401645
///
16411646
ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
1647+
// If we have an invalid module selector, consume that first.
1648+
parseModuleSelector(ModuleSelectorReason::InvalidOnly);
1649+
16421650
switch (Tok.getKind()) {
16431651
case tok::integer_literal: {
16441652
StringRef Text = copyAndStripUnderscores(Tok.getText());
@@ -2275,6 +2283,13 @@ parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName) {
22752283
if (peekToken().isNot(tok::colon_colon) && Tok.isNot(tok::colon_colon))
22762284
return std::nullopt;
22772285

2286+
// Leave these paired tokens to be diagnosed by a future call to
2287+
// `parseModuleSelector()` at the next token, rather than consuming them as
2288+
// malformed module names and causing more errors later in the parser.
2289+
if (Tok.isAny(tok::l_paren, tok::l_brace, tok::l_angle, tok::l_square,
2290+
tok::r_paren, tok::r_brace, tok::r_angle, tok::r_square))
2291+
return std::nullopt;
2292+
22782293
// We will parse the selector whether or not it's allowed, then early return
22792294
// if it's disallowed, then diagnose any other errors in what we parsed. This
22802295
// will make sure we always consume the module selector's tokens, but don't
@@ -2283,8 +2298,15 @@ parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName) {
22832298

22842299
SourceLoc nameLoc;
22852300
Identifier moduleName;
2286-
if (Tok.is(tok::identifier))
2301+
if (Tok.is(tok::identifier)) {
2302+
// If we are only supposed to consume invalid selectors, leave this for
2303+
// later.
2304+
if (reason == ModuleSelectorReason::InvalidOnly) {
2305+
return std::nullopt;
2306+
}
2307+
22872308
nameLoc = consumeIdentifier(moduleName, /*diagnoseDollarPrefix=*/true);
2309+
}
22882310
else if (Tok.is(tok::colon_colon))
22892311
// Let nameLoc and colonColonLoc both point to the tok::colon_colon.
22902312
nameLoc = Tok.getLoc();
@@ -2293,7 +2315,8 @@ parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName) {
22932315

22942316
auto colonColonLoc = consumeToken(tok::colon_colon);
22952317

2296-
if (reason != ModuleSelectorReason::Allowed) {
2318+
if (reason != ModuleSelectorReason::Allowed &&
2319+
reason != ModuleSelectorReason::InvalidOnly) {
22972320
diagnose(colonColonLoc, diag::module_selector_not_allowed,
22982321
(uint8_t)reason, declKindName);
22992322

lib/Parse/ParseType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ ParserResult<TypeRepr> Parser::parseSILBoxType(GenericParamList *generics,
402402
///
403403
ParserResult<TypeRepr> Parser::parseTypeScalar(
404404
Diag<> MessageID, ParseTypeReason reason) {
405+
// If we have an invalid module selector, consume that first.
406+
parseModuleSelector(ModuleSelectorReason::InvalidOnly);
407+
405408
// Start a context for creating type syntax.
406409
ParserStatus status;
407410

test/NameLookup/module_selector.swift

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// * Cross-import overlays
1414
// * Key paths
1515
// * Key path dynamic member lookup
16+
// * Custom type attributes (and coverage of type attrs generally is sparse)
1617
//
1718
// It also might not cover all combinations of name lookup paths and inputs.
1819

@@ -495,6 +496,131 @@ func badModuleNames() {
495496
// expected-error@-1 {{'NonexistentModule::MyChildType' is not a member type of struct 'ModuleSelectorTestingKit.A'}}
496497
}
497498

499+
struct BadModuleSelectorSyntax { // expected-note {{in declaration of 'BadModuleSelectorSyntax'}}
500+
var a: ::Int
501+
// expected-error@-1 {{expected identifier in module selector}}
502+
503+
var b: (::Int)
504+
// expected-error@-1 {{expected identifier in module selector}}
505+
506+
var c: *::Int
507+
// expected-error@-1 {{expected identifier in module selector}}
508+
509+
var d: _::Int
510+
// expected-error@-1 {{expected identifier in module selector}}
511+
512+
var e: Self::Int
513+
// expected-error@-1 {{expected identifier in module selector}}
514+
515+
var f: self::Int
516+
// expected-error@-1 {{expected identifier in module selector}}
517+
518+
var g: inout::Int
519+
// expected-error@-1 {{expected identifier in module selector}}
520+
521+
var h: Any::Int
522+
// expected-error@-1 {{expected identifier in module selector}}
523+
524+
var aArray: [::Int]
525+
// expected-error@-1 {{expected identifier in module selector}}
526+
527+
var bArray: [(::Int)]
528+
// expected-error@-1 {{expected identifier in module selector}}
529+
530+
var cArray: [*::Int]
531+
// expected-error@-1 {{expected identifier in module selector}}
532+
533+
var dArray: [_::Int]
534+
// expected-error@-1 {{expected identifier in module selector}}
535+
536+
var eArray: [Self::Int]
537+
// expected-error@-1 {{expected identifier in module selector}}
538+
539+
var fArray: [self::Int]
540+
// expected-error@-1 {{expected identifier in module selector}}
541+
542+
var gArray: [inout::Int]
543+
// expected-error@-1 {{expected identifier in module selector}}
544+
545+
var hArray: [Any::Int]
546+
// expected-error@-1 {{expected identifier in module selector}}
547+
548+
var aIndex: String.::Index
549+
// expected-error@-1 {{expected identifier in module selector}}
550+
551+
// FIXME: This gets interpreted as a single `.*` operator; may not be ideal.
552+
var cIndex: String.*::Index
553+
// expected-error@-1 {{consecutive declarations on a line must be separated by ';'}}
554+
// expected-error@-2 {{expected declaration}}
555+
556+
var dIndex: String._::Index
557+
// expected-error@-1 {{expected identifier in module selector}}
558+
559+
var eIndex: String.Self::Index
560+
// expected-error@-1 {{expected identifier in module selector}}
561+
562+
var fIndex: String.self::Index
563+
// expected-error@-1 {{expected identifier in module selector}}
564+
565+
var gIndex: String.inout::Index
566+
// expected-error@-1 {{expected identifier in module selector}}
567+
568+
var hIndex: String.Any::Index
569+
// expected-error@-1 {{expected identifier in module selector}}
570+
571+
func inExpr() {
572+
::print()
573+
// expected-error@-1 {{expected identifier in module selector}}
574+
575+
(::print())
576+
// expected-error@-1 {{expected identifier in module selector}}
577+
578+
*::print()
579+
// expected-error@-1 {{expected identifier in module selector}}
580+
581+
_::print()
582+
// expected-error@-1 {{expected identifier in module selector}}
583+
584+
Self::print()
585+
// expected-error@-1 {{expected identifier in module selector}}
586+
587+
self::print()
588+
// expected-error@-1 {{expected identifier in module selector}}
589+
590+
inout::print()
591+
// expected-error@-1 {{expected identifier in module selector}}
592+
593+
Any::print()
594+
// expected-error@-1 {{expected identifier in module selector}}
595+
596+
_ = 1.::magnitude
597+
// expected-error@-1 {{expected identifier in module selector}}
598+
599+
_ = (1.::magnitude)
600+
// expected-error@-1 {{expected identifier in module selector}}
601+
602+
// FIXME: This gets interpreted as a single `.*` operator; may not be ideal.
603+
_ = 1.*::magnitude
604+
// expected-error@-1 {{expected identifier in module selector}}
605+
// expected-error@-2 {{cannot find operator '.*' in scope}}
606+
607+
_ = 1._::magnitude
608+
// expected-error@-1 {{expected identifier in module selector}}
609+
610+
_ = 1.Self::magnitude
611+
// expected-error@-1 {{expected identifier in module selector}}
612+
613+
_ = 1.self::magnitude
614+
// expected-error@-1 {{expected identifier in module selector}}
615+
616+
_ = 1.inout::magnitude
617+
// expected-error@-1 {{expected identifier in module selector}}
618+
619+
_ = 1.Any::magnitude
620+
// expected-error@-1 {{expected identifier in module selector}}
621+
}
622+
}
623+
498624
@_spi(main::Private)
499625
// expected-error@-1 {{SPI group cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{7-13=}}
500626
public struct BadImplementsAttr: CustomStringConvertible {

0 commit comments

Comments
 (0)