Skip to content

Commit 0db0b44

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 handle module selectors in scoped `import` statements; the related test has been XFAILed.
1 parent 10a6ea9 commit 0db0b44

File tree

7 files changed

+2386
-33
lines changed

7 files changed

+2386
-33
lines changed

Sources/SwiftParser/Attributes.swift

Lines changed: 5 additions & 1 deletion
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()))

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.parseModuleSelectorIfPresent()
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: 25 additions & 6 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()
@@ -662,7 +668,7 @@ extension Parser {
662668

663669
// Parse the name portion.
664670
let declName: RawDeclReferenceExprSyntax
665-
if let indexOrSelf = self.consume(if: .integerLiteral, .keyword(.self)) {
671+
if !self.isAtModuleSelector(), let indexOrSelf = self.consume(if: .integerLiteral, .keyword(.self)) {
666672
// Handle "x.42" - a tuple index.
667673
declName = RawDeclReferenceExprSyntax(
668674
moduleSelector: nil,
@@ -1201,6 +1207,10 @@ extension Parser {
12011207
pattern: PatternContext,
12021208
flavor: ExprFlavor
12031209
) -> RawExprSyntax {
1210+
if self.isAtModuleSelector() && (!pattern.admitsBinding || !self.lookahead().isInBindingPatternPosition()) {
1211+
return self.parseIdentifierExpression(flavor: flavor)
1212+
}
1213+
12041214
switch self.at(anyIn: PrimaryExpressionStart.self) {
12051215
case (.integerLiteral, let handle)?:
12061216
let literal = self.eat(handle)
@@ -1248,11 +1258,11 @@ extension Parser {
12481258
// is the start of an enum or expr pattern.
12491259
if pattern.admitsBinding && self.lookahead().isInBindingPatternPosition() {
12501260
let identifier = self.eat(handle)
1251-
let pattern = RawIdentifierPatternSyntax(
1261+
let patternNode = RawIdentifierPatternSyntax(
12521262
identifier: identifier,
12531263
arena: self.arena
12541264
)
1255-
return RawExprSyntax(RawPatternExprSyntax(pattern: pattern, arena: self.arena))
1265+
return RawExprSyntax(RawPatternExprSyntax(pattern: patternNode, arena: self.arena))
12561266
}
12571267

12581268
return self.parseIdentifierExpression(flavor: flavor)
@@ -1385,6 +1395,7 @@ extension Parser {
13851395
)
13861396
pound = pound.tokenView.withTokenDiagnostic(tokenDiagnostic: diagnostic, arena: self.arena)
13871397
}
1398+
let moduleSelector = parseModuleSelectorIfPresent()
13881399
let unexpectedBeforeMacroName: RawUnexpectedNodesSyntax?
13891400
let macroName: RawTokenSyntax
13901401
if !self.atStartOfLine {
@@ -1432,7 +1443,7 @@ extension Parser {
14321443
return RawMacroExpansionExprSyntax(
14331444
unexpectedBeforePound,
14341445
pound: pound,
1435-
moduleSelector: nil,
1446+
moduleSelector: moduleSelector,
14361447
unexpectedBeforeMacroName,
14371448
macroName: macroName,
14381449
genericArgumentClause: generics,
@@ -1969,6 +1980,14 @@ extension Parser {
19691980
}
19701981
}
19711982

1983+
extension TokenConsumer {
1984+
mutating func atBinaryOperatorArgument() -> Bool {
1985+
var lookahead = self.lookahead()
1986+
_ = lookahead.consumeModuleSelectorTokens()
1987+
return lookahead.at(.binaryOperator) && lookahead.peek(isAt: .comma, .rightParen, .rightSquare)
1988+
}
1989+
}
1990+
19721991
extension Parser {
19731992
/// Parse the elements of an argument list.
19741993
///
@@ -2020,7 +2039,7 @@ extension Parser {
20202039
// this case lexes as a binary operator because it neither leads nor
20212040
// follows a proper subexpression.
20222041
let expr: RawExprSyntax
2023-
if self.at(.binaryOperator) && self.peek(isAt: .comma, .rightParen, .rightSquare) {
2042+
if self.atBinaryOperatorArgument() {
20242043
expr = RawExprSyntax(self.parseDeclReferenceExpr(.operators))
20252044
} else {
20262045
expr = self.parseExpression(flavor: flavor, pattern: pattern)
@@ -2400,9 +2419,9 @@ extension Parser {
24002419

24012420
unknownAttr = RawAttributeSyntax(
24022421
atSign: at,
2403-
unexpectedBeforeIdent,
24042422
attributeName: RawIdentifierTypeSyntax(
24052423
moduleSelector: nil,
2424+
unexpectedBeforeIdent,
24062425
name: ident,
24072426
genericArgumentClause: nil,
24082427
arena: self.arena

Sources/SwiftParser/Names.swift

Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,107 @@ extension Parser {
4545
}
4646
}
4747

48+
extension TokenConsumer {
49+
/// Do the subsequent tokens have the form of a module selector? Encompasses some invalid syntax which nonetheless
50+
/// can be handled by `consumeModuleSelectorTokens()`.
51+
///
52+
/// - Postcondition: If `true`, either the current token or the next token is `.colonColon`.
53+
mutating func isAtModuleSelector() -> Bool {
54+
// If this is a module selector, the next token should be `::`.
55+
guard self.peek(isAt: .colonColon) else {
56+
// ...however, we will also allow the *current* token to be `::`. `consumeModuleSelectorTokens()` will create a
57+
// missing identifier.
58+
return self.at(.colonColon)
59+
}
60+
61+
// Technically the current token *should* be an identifier, but we also want to diagnose other tokens that might be
62+
// used by accident or given special meanings later ('_', operators, certain keywords).
63+
return self.at(.identifier, .wildcard, .binaryOperator)
64+
|| self.at(.keyword(.self), .keyword(.Self), .keyword(.super)) || self.at(.keyword(.Any))
65+
}
66+
67+
mutating func unlessPeekModuleSelector<T>(_ operation: (inout Self) -> T?) -> T? {
68+
var lookahead = self.lookahead()
69+
lookahead.skipSingle()
70+
if lookahead.isAtModuleSelector() {
71+
return nil
72+
}
73+
return operation(&self)
74+
}
75+
76+
/// If the subsequent tokens have the form of a module selector, valid or otherwise, consume and return them;
77+
/// otherwise consume nothing and return `nil`. Additionally consumes invalid chained module selectors.
78+
///
79+
/// Returns a tuple comprised of:
80+
///
81+
/// - `moduleNameOrUnexpected`: The module name if present; in a valid module selector, this will be a present
82+
/// identifier, but either of those can be untrue in invalid code.
83+
/// - `colonColonToken`: The `::` indicating this module selector. Always `.colonColon`, always present.
84+
/// - `extra`: Tokens for additional trailing module selectors. There is no situation in which two module selectors
85+
/// can be validly chained.
86+
mutating func consumeModuleSelectorTokens() -> (
87+
moduleNameOrUnexpected: Token, colonColonToken: Token, extra: [Token]
88+
)? {
89+
guard self.isAtModuleSelector() else {
90+
return nil
91+
}
92+
93+
let moduleName: Token
94+
let colonColonToken: Token
95+
96+
// Did we forget the module name?
97+
if let earlyColonColon = self.consume(if: .colonColon) {
98+
moduleName = self.missingToken(.identifier)
99+
colonColonToken = earlyColonColon
100+
} else {
101+
// Consume whatever comes before the `::`, plus the `::` itself. (Whether or not the "name" is an identifier is
102+
// checked elsewhere.)
103+
moduleName = self.consumeAnyToken()
104+
colonColonToken = self.eat(.colonColon)
105+
}
106+
107+
var extra: [Token] = []
108+
while self.isAtModuleSelector() {
109+
if !self.at(.colonColon) {
110+
extra.append(self.consumeAnyToken())
111+
}
112+
extra.append(self.eat(.colonColon))
113+
}
114+
return (moduleName, colonColonToken, extra)
115+
}
116+
}
117+
118+
extension Parser {
119+
/// Parses one or more module selectors, if present.
120+
mutating func parseModuleSelectorIfPresent() -> RawModuleSelectorSyntax? {
121+
guard let (moduleNameOrUnexpected, colonColon, extra) = consumeModuleSelectorTokens() else {
122+
return nil
123+
}
124+
125+
let leadingUnexpected: [RawSyntax]
126+
let moduleName: RawTokenSyntax
127+
let trailingUnexpected: [RawSyntax]
128+
129+
if moduleNameOrUnexpected.tokenKind == .identifier {
130+
leadingUnexpected = []
131+
moduleName = moduleNameOrUnexpected
132+
} else {
133+
leadingUnexpected = [RawSyntax(moduleNameOrUnexpected)]
134+
moduleName = RawTokenSyntax(missing: .identifier, arena: arena)
135+
}
136+
137+
trailingUnexpected = extra.map { RawSyntax($0) }
138+
139+
return RawModuleSelectorSyntax(
140+
RawUnexpectedNodesSyntax(leadingUnexpected, arena: arena),
141+
moduleName: moduleName,
142+
colonColon: colonColon,
143+
RawUnexpectedNodesSyntax(trailingUnexpected, arena: arena),
144+
arena: arena
145+
)
146+
}
147+
}
148+
48149
extension Parser {
49150
struct DeclNameOptions: OptionSet {
50151
var rawValue: UInt8
@@ -68,6 +169,12 @@ extension Parser {
68169
}
69170

70171
mutating func parseDeclReferenceExpr(_ flags: DeclNameOptions = []) -> RawDeclReferenceExprSyntax {
172+
// Consume a module selector if present.
173+
let moduleSelector = self.parseModuleSelectorIfPresent()
174+
175+
// If a module selector is found, we parse the name after it according to SE-0071 rules.
176+
let allowKeywords = flags.contains(.keywords) || moduleSelector != nil
177+
71178
// Consume the base name.
72179
let base: RawTokenSyntax
73180
if let identOrSelf = self.consume(if: .identifier, .keyword(.self), .keyword(.Self))
@@ -80,7 +187,7 @@ extension Parser {
80187
let special = self.consume(if: .keyword(.`deinit`), .keyword(.`subscript`))
81188
{
82189
base = special
83-
} else if flags.contains(.keywords) && self.currentToken.isLexerClassifiedKeyword {
190+
} else if allowKeywords && self.currentToken.isLexerClassifiedKeyword {
84191
base = self.consumeAnyToken(remapping: .identifier)
85192
} else {
86193
base = missingToken(.identifier)
@@ -89,7 +196,7 @@ extension Parser {
89196
// Parse an argument list, if the flags allow it and it's present.
90197
let args = self.parseArgLabelList(flags)
91198
return RawDeclReferenceExprSyntax(
92-
moduleSelector: nil,
199+
moduleSelector: moduleSelector,
93200
baseName: base,
94201
argumentNames: args,
95202
arena: self.arena
@@ -212,12 +319,8 @@ extension Parser {
212319
var keepGoing = self.consume(if: .period)
213320
var loopProgress = LoopProgressCondition()
214321
while keepGoing != nil && self.hasProgressed(&loopProgress) {
215-
let (unexpectedBeforeName, name) = self.expect(
216-
.identifier,
217-
.keyword(.self),
218-
TokenSpec(.Self, remapping: .identifier),
219-
default: .identifier
220-
)
322+
let memberModuleSelector = self.parseModuleSelectorIfPresent()
323+
let name = self.parseMemberTypeName()
221324
let generics: RawGenericArgumentClauseSyntax?
222325
if self.at(prefix: "<") {
223326
generics = self.parseGenericArguments()
@@ -228,8 +331,7 @@ extension Parser {
228331
RawMemberTypeSyntax(
229332
baseType: result,
230333
period: keepGoing!,
231-
moduleSelector: nil,
232-
unexpectedBeforeName,
334+
moduleSelector: memberModuleSelector,
233335
name: name,
234336
genericArgumentClause: generics,
235337
arena: self.arena

0 commit comments

Comments
 (0)