Skip to content

Commit e27a511

Browse files
committed
Parse module selectors in most valid locations
This commit ports over tests from the compiler’s (future) `test/NameLookup/module_selector.swift` file and makes sure the correct uses parse as expected. It also tests that ill-formed module selectors (ones with a missing or non-identifier module name) are diagnosed correctly. This commit doesn’t fully handle recovery from module selectors inserted at invalid locations; the test cases that require recovery are XFAILed.
1 parent 0321c86 commit e27a511

File tree

8 files changed

+2512
-35
lines changed

8 files changed

+2512
-35
lines changed

Sources/SwiftParser/Attributes.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,11 @@ extension Parser {
230230
)
231231
}
232232

233-
switch peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) {
233+
// An attribute qualified by a module selector is *always* a custom attribute, even if it has the same name (or
234+
// module name) as a builtin attribute.
235+
let builtinAttr = self.unlessPeekModuleSelector { $0.peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) }
236+
237+
switch builtinAttr {
234238
case .abi:
235239
return parseAttribute(argumentMode: .required) { parser in
236240
return (nil, .abiArguments(parser.parseABIAttributeArguments()))
@@ -692,7 +696,11 @@ extension Parser {
692696
case (.target, let handle)?:
693697
let label = self.eat(handle)
694698
let (unexpectedBeforeColon, colon) = self.expect(.colon)
695-
let declName = self.parseDeclReferenceExpr([.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators])
699+
let moduleSelector = self.parseModuleSelector()
700+
let declName = self.parseDeclReferenceExpr(
701+
moduleSelector: moduleSelector,
702+
[.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators]
703+
)
696704
let comma = self.consume(if: .comma)
697705
elements.append(
698706
.specializeTargetFunctionArgument(
@@ -795,14 +803,17 @@ extension Parser {
795803
mutating func parseImplementsAttributeArguments() -> RawImplementsAttributeArgumentsSyntax {
796804
let type = self.parseType()
797805
let (unexpectedBeforeComma, comma) = self.expect(.comma)
798-
let declName = self.parseDeclReferenceExpr([
799-
.zeroArgCompoundNames,
800-
.operators,
801-
])
806+
807+
// You can't put a module selector on the member name--it's meaningless because the member has to come from the
808+
// same module as the protocol.
809+
let moduleSelector = self.parseModuleSelector()
810+
let declName = self.parseDeclReferenceExpr(moduleSelector: nil, [.zeroArgCompoundNames, .operators])
811+
802812
return RawImplementsAttributeArgumentsSyntax(
803813
type: type,
804814
unexpectedBeforeComma,
805815
comma: comma,
816+
unexpected(moduleSelector),
806817
declName: declName,
807818
arena: self.arena
808819
)
@@ -942,6 +953,7 @@ extension Parser {
942953
mutating func parseDynamicReplacementAttributeArguments() -> RawDynamicReplacementAttributeArgumentsSyntax {
943954
let (unexpectedBeforeLabel, label) = self.expect(.keyword(.for))
944955
let (unexpectedBeforeColon, colon) = self.expect(.colon)
956+
945957
let declName: RawDeclReferenceExprSyntax
946958
if label.isMissing && colon.isMissing && self.atStartOfLine {
947959
declName = RawDeclReferenceExprSyntax(
@@ -951,9 +963,11 @@ extension Parser {
951963
arena: self.arena
952964
)
953965
} else {
954-
declName = self.parseDeclReferenceExpr([
955-
.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators,
956-
])
966+
let moduleSelector = self.parseModuleSelector()
967+
declName = self.parseDeclReferenceExpr(
968+
moduleSelector: moduleSelector,
969+
[.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators]
970+
)
957971
}
958972
return RawDynamicReplacementAttributeArgumentsSyntax(
959973
unexpectedBeforeLabel,
@@ -1018,7 +1032,7 @@ extension Parser {
10181032
unexpectedBeforeValue = unexpected
10191033
value = .token(token)
10201034
case "metadata":
1021-
unexpectedBeforeValue = nil
1035+
unexpectedBeforeValue = unexpected(self.parseModuleSelector())
10221036
if let identifier = self.consume(if: .identifier) {
10231037
value = .token(identifier)
10241038
} else {

Sources/SwiftParser/Declarations.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2191,11 +2191,15 @@ extension Parser {
21912191
)
21922192
pound = pound.tokenView.withTokenDiagnostic(tokenDiagnostic: diagnostic, arena: self.arena)
21932193
}
2194+
2195+
let moduleSelector: RawModuleSelectorSyntax?
21942196
let unexpectedBeforeMacro: RawUnexpectedNodesSyntax?
21952197
let macro: RawTokenSyntax
21962198
if !self.atStartOfLine {
2199+
moduleSelector = self.parseModuleSelector()
21972200
(unexpectedBeforeMacro, macro) = self.expectIdentifier(allowKeywordsAsIdentifier: true)
21982201
} else {
2202+
moduleSelector = nil
21992203
unexpectedBeforeMacro = nil
22002204
macro = self.missingToken(.identifier)
22012205
}
@@ -2243,7 +2247,7 @@ extension Parser {
22432247
modifiers: attrs.modifiers,
22442248
unexpectedBeforePound,
22452249
pound: pound,
2246-
moduleSelector: nil,
2250+
moduleSelector: moduleSelector,
22472251
unexpectedBeforeMacro,
22482252
macroName: macro,
22492253
genericArgumentClause: generics,

Sources/SwiftParser/Expressions.swift

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818

1919
extension TokenConsumer {
2020
mutating func atStartOfExpression() -> Bool {
21+
if self.isAtModuleSelector() {
22+
var lookahead = self.lookahead()
23+
_ = lookahead.consumeModuleSelectorTokens()
24+
return lookahead.atStartOfExpression()
25+
}
26+
2127
switch self.at(anyIn: ExpressionStart.self) {
2228
case (.awaitTryMove, let handle)?:
2329
var lookahead = self.lookahead()
@@ -572,6 +578,11 @@ extension Parser {
572578
flavor: ExprFlavor,
573579
pattern: PatternContext = .none
574580
) -> RawExprSyntax {
581+
if let moduleSelector = self.parseModuleSelector() {
582+
let qualifiedExpr = self.parseUnaryExpression(flavor: flavor, pattern: pattern)
583+
return attach(moduleSelector, to: qualifiedExpr)
584+
}
585+
575586
// Try parse a single value statement as an expression (e.g do/if/switch).
576587
// Note we do this here in parseUnaryExpression as we don't allow postfix
577588
// syntax to be attached to such expressions to avoid ambiguities such as postfix
@@ -660,19 +671,22 @@ extension Parser {
660671
return (unexpectedPeriod, period, declName, nil)
661672
}
662673

674+
let moduleSelector = parseModuleSelector()
675+
663676
// Parse the name portion.
664677
let declName: RawDeclReferenceExprSyntax
665678
if let indexOrSelf = self.consume(if: .integerLiteral, .keyword(.self)) {
666679
// Handle "x.42" - a tuple index.
667680
declName = RawDeclReferenceExprSyntax(
681+
unexpected(moduleSelector),
668682
moduleSelector: nil,
669683
baseName: indexOrSelf,
670684
argumentNames: nil,
671685
arena: self.arena
672686
)
673687
} else {
674688
// Handle an arbitrary declaration name.
675-
declName = self.parseDeclReferenceExpr([.keywords, .compoundNames])
689+
declName = self.parseDeclReferenceExpr(moduleSelector: moduleSelector, [.keywords, .compoundNames])
676690
}
677691

678692
// Parse the generic arguments, if any.
@@ -1248,11 +1262,11 @@ extension Parser {
12481262
// is the start of an enum or expr pattern.
12491263
if pattern.admitsBinding && self.lookahead().isInBindingPatternPosition() {
12501264
let identifier = self.eat(handle)
1251-
let pattern = RawIdentifierPatternSyntax(
1265+
let patternNode = RawIdentifierPatternSyntax(
12521266
identifier: identifier,
12531267
arena: self.arena
12541268
)
1255-
return RawExprSyntax(RawPatternExprSyntax(pattern: pattern, arena: self.arena))
1269+
return RawExprSyntax(RawPatternExprSyntax(pattern: patternNode, arena: self.arena))
12561270
}
12571271

12581272
return self.parseIdentifierExpression(flavor: flavor)
@@ -1316,7 +1330,10 @@ extension Parser {
13161330
)
13171331
}
13181332

1319-
let declName = self.parseDeclReferenceExpr([.keywords, .compoundNames])
1333+
// If there's a module selector after the period, parse and use it.
1334+
let moduleSelector = self.parseModuleSelector()
1335+
let declName = self.parseDeclReferenceExpr(moduleSelector: moduleSelector, [.keywords, .compoundNames])
1336+
13201337
return RawExprSyntax(
13211338
RawMemberAccessExprSyntax(
13221339
base: nil,
@@ -1354,7 +1371,8 @@ extension Parser {
13541371
case .attributeArguments: options.insert(.keywordsUsingSpecialNames)
13551372
}
13561373

1357-
let declName = self.parseDeclReferenceExpr(options)
1374+
// If something up the call stack has parsed a module selector, it will be attached using `attach(_:to:)`.
1375+
let declName = self.parseDeclReferenceExpr(moduleSelector: nil, options)
13581376
guard self.withLookahead({ $0.canParseAsGenericArgumentList() }) else {
13591377
return RawExprSyntax(declName)
13601378
}
@@ -1385,6 +1403,7 @@ extension Parser {
13851403
)
13861404
pound = pound.tokenView.withTokenDiagnostic(tokenDiagnostic: diagnostic, arena: self.arena)
13871405
}
1406+
let moduleSelector = parseModuleSelector()
13881407
let unexpectedBeforeMacroName: RawUnexpectedNodesSyntax?
13891408
let macroName: RawTokenSyntax
13901409
if !self.atStartOfLine {
@@ -1432,7 +1451,7 @@ extension Parser {
14321451
return RawMacroExpansionExprSyntax(
14331452
unexpectedBeforePound,
14341453
pound: pound,
1435-
moduleSelector: nil,
1454+
moduleSelector: moduleSelector,
14361455
unexpectedBeforeMacroName,
14371456
macroName: macroName,
14381457
genericArgumentClause: generics,
@@ -1746,6 +1765,7 @@ extension Parser {
17461765
extension Parser {
17471766
mutating func parseAnonymousClosureArgument() -> RawDeclReferenceExprSyntax {
17481767
let (unexpectedBeforeBaseName, baseName) = self.expect(.dollarIdentifier)
1768+
// If something up the call stack has parsed a module selector, it will be attached using `attach(_:to:)`.
17491769
return RawDeclReferenceExprSyntax(
17501770
moduleSelector: nil,
17511771
unexpectedBeforeBaseName,
@@ -1969,6 +1989,14 @@ extension Parser {
19691989
}
19701990
}
19711991

1992+
extension TokenConsumer {
1993+
mutating func atBinaryOperatorArgument() -> Bool {
1994+
var lookahead = self.lookahead()
1995+
_ = lookahead.consumeModuleSelectorTokens()
1996+
return lookahead.at(.binaryOperator) && lookahead.peek(isAt: .comma, .rightParen, .rightSquare)
1997+
}
1998+
}
1999+
19722000
extension Parser {
19732001
/// Parse the elements of an argument list.
19742002
///
@@ -2020,8 +2048,9 @@ extension Parser {
20202048
// this case lexes as a binary operator because it neither leads nor
20212049
// follows a proper subexpression.
20222050
let expr: RawExprSyntax
2023-
if self.at(.binaryOperator) && self.peek(isAt: .comma, .rightParen, .rightSquare) {
2024-
expr = RawExprSyntax(self.parseDeclReferenceExpr(.operators))
2051+
if self.atBinaryOperatorArgument() {
2052+
let moduleSelector = self.parseModuleSelector()
2053+
expr = RawExprSyntax(self.parseDeclReferenceExpr(moduleSelector: moduleSelector, .operators))
20252054
} else {
20262055
expr = self.parseExpression(flavor: flavor, pattern: pattern)
20272056
}
@@ -2400,9 +2429,9 @@ extension Parser {
24002429

24012430
unknownAttr = RawAttributeSyntax(
24022431
atSign: at,
2403-
unexpectedBeforeIdent,
24042432
attributeName: RawIdentifierTypeSyntax(
24052433
moduleSelector: nil,
2434+
unexpectedBeforeIdent,
24062435
name: ident,
24072436
genericArgumentClause: nil,
24082437
arena: self.arena

0 commit comments

Comments
 (0)