Skip to content

Commit e5233b2

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 056ec21 commit e5233b2

File tree

7 files changed

+2361
-16
lines changed

7 files changed

+2361
-16
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.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: 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 = parseModuleSelector()
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: 151 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,151 @@ extension Parser {
4545
}
4646
}
4747

48+
private enum StructuralTokens: TokenSpecSet {
49+
case comma
50+
case colon
51+
case leftParen
52+
case leftBrace
53+
case leftSquare
54+
case leftAngle
55+
case rightParen
56+
case rightBrace
57+
case rightSquare
58+
case rightAngle
59+
60+
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
61+
switch lexeme.rawTokenKind {
62+
case .comma: self = .comma
63+
case .colon: self = .colon
64+
case .leftParen: self = .leftParen
65+
case .leftBrace: self = .leftBrace
66+
case .leftSquare: self = .leftSquare
67+
case .leftAngle: self = .leftAngle
68+
case .rightParen: self = .rightParen
69+
case .rightBrace: self = .rightBrace
70+
case .rightSquare: self = .rightSquare
71+
case .rightAngle: self = .rightAngle
72+
default: return nil
73+
}
74+
}
75+
76+
var spec: TokenSpec {
77+
switch self {
78+
case .comma: return .comma
79+
case .colon: return .colon
80+
case .leftParen: return .leftParen
81+
case .leftBrace: return .leftBrace
82+
case .leftSquare: return .leftSquare
83+
case .leftAngle: return .leftAngle
84+
case .rightParen: return .rightParen
85+
case .rightBrace: return .rightBrace
86+
case .rightSquare: return .rightSquare
87+
case .rightAngle: return .rightAngle
88+
}
89+
}
90+
}
91+
92+
extension TokenConsumer {
93+
/// Do the subsequent tokens have the form of a module selector? Encompasses some invalid syntax which nonetheless
94+
/// can be handled by `consumeModuleSelectorTokens()`.
95+
///
96+
/// - Postcondition: If `true`, either the current token or the next token is `.colonColon`.
97+
mutating func isAtModuleSelector() -> Bool {
98+
// If this is a module selector, the next token should be `::`.
99+
guard self.peek(isAt: .colonColon) else {
100+
// ...however, we will also allow the *current* token to be `::`. `consumeModuleSelectorTokens()` will create a
101+
// missing identifier.
102+
return self.at(.colonColon)
103+
}
104+
105+
// Technically the current token *should* be an identifier, but we also want to diagnose other tokens that might be
106+
// used by accident (particularly keywords and `_`). However, we don't want to consume tokens which would make the
107+
// surrounding structure mis-parse.
108+
return self.at(anyIn: StructuralTokens.self) == nil
109+
}
110+
111+
mutating func unlessPeekModuleSelector<T>(_ operation: (inout Self) -> T?) -> T? {
112+
var lookahead = self.lookahead()
113+
lookahead.skipSingle()
114+
if lookahead.isAtModuleSelector() {
115+
return nil
116+
}
117+
return operation(&self)
118+
}
119+
120+
/// If the subsequent tokens have the form of a module selector, valid or otherwise, consume and return them;
121+
/// otherwise consume nothing and return `nil`. Additionally consumes invalid chained module selectors.
122+
///
123+
/// Returns a tuple comprised of:
124+
///
125+
/// - `moduleNameOrUnexpected`: The module name if present; in a valid module selector, this will be a present
126+
/// identifier, but either of those can be untrue in invalid code.
127+
/// - `colonColonToken`: The `::` indicating this module selector. Always `.colonColon`, always present.
128+
/// - `extra`: Tokens for additional trailing module selectors. There is no situation in which two module selectors
129+
/// can be validly chained.
130+
mutating func consumeModuleSelectorTokens() -> (
131+
moduleNameOrUnexpected: Token, colonColonToken: Token, extra: [Token]
132+
)? {
133+
guard self.isAtModuleSelector() else {
134+
return nil
135+
}
136+
137+
let moduleName: Token
138+
let colonColonToken: Token
139+
140+
// Did we forget the module name?
141+
if let earlyColonColon = self.consume(if: .colonColon) {
142+
moduleName = self.missingToken(.identifier)
143+
colonColonToken = earlyColonColon
144+
} else {
145+
// Consume whatever comes before the `::`, plus the `::` itself. (Whether or not the "name" is an identifier is
146+
// checked elsewhere.)
147+
moduleName = self.consumeAnyToken()
148+
colonColonToken = self.eat(.colonColon)
149+
}
150+
151+
var extra: [Token] = []
152+
while self.isAtModuleSelector() {
153+
if !self.at(.colonColon) {
154+
extra.append(self.consumeAnyToken())
155+
}
156+
extra.append(self.eat(.colonColon))
157+
}
158+
return (moduleName, colonColonToken, extra)
159+
}
160+
}
161+
162+
extension Parser {
163+
/// Parses one or more module selectors, if present.
164+
mutating func parseModuleSelector() -> RawModuleSelectorSyntax? {
165+
guard let (moduleNameOrUnexpected, colonColon, extra) = consumeModuleSelectorTokens() else {
166+
return nil
167+
}
168+
169+
let leadingUnexpected: [RawSyntax]
170+
let moduleName: RawTokenSyntax
171+
let trailingUnexpected: [RawSyntax]
172+
173+
if moduleNameOrUnexpected.tokenKind == .identifier {
174+
leadingUnexpected = []
175+
moduleName = moduleNameOrUnexpected
176+
} else {
177+
leadingUnexpected = [RawSyntax(moduleNameOrUnexpected)]
178+
moduleName = RawTokenSyntax.init(missing: .identifier, arena: arena)
179+
}
180+
181+
trailingUnexpected = extra.map { RawSyntax($0) }
182+
183+
return RawModuleSelectorSyntax(
184+
RawUnexpectedNodesSyntax(leadingUnexpected, arena: arena),
185+
moduleName: moduleName,
186+
colonColon: colonColon,
187+
RawUnexpectedNodesSyntax(trailingUnexpected, arena: arena),
188+
arena: arena
189+
)
190+
}
191+
}
192+
48193
extension Parser {
49194
struct DeclNameOptions: OptionSet {
50195
var rawValue: UInt8
@@ -68,6 +213,9 @@ extension Parser {
68213
}
69214

70215
mutating func parseDeclReferenceExpr(_ flags: DeclNameOptions = []) -> RawDeclReferenceExprSyntax {
216+
// Consume a module selector if present.
217+
let moduleSelector = self.parseModuleSelector()
218+
71219
// Consume the base name.
72220
let base: RawTokenSyntax
73221
if let identOrSelf = self.consume(if: .identifier, .keyword(.self), .keyword(.Self))
@@ -89,7 +237,7 @@ extension Parser {
89237
// Parse an argument list, if the flags allow it and it's present.
90238
let args = self.parseArgLabelList(flags)
91239
return RawDeclReferenceExprSyntax(
92-
moduleSelector: nil,
240+
moduleSelector: moduleSelector,
93241
baseName: base,
94242
argumentNames: args,
95243
arena: self.arena
@@ -212,6 +360,7 @@ extension Parser {
212360
var keepGoing = self.consume(if: .period)
213361
var loopProgress = LoopProgressCondition()
214362
while keepGoing != nil && self.hasProgressed(&loopProgress) {
363+
let memberModuleSelector = self.parseModuleSelector()
215364
let (unexpectedBeforeName, name) = self.expect(
216365
.identifier,
217366
.keyword(.self),
@@ -228,7 +377,7 @@ extension Parser {
228377
RawMemberTypeSyntax(
229378
baseType: result,
230379
period: keepGoing!,
231-
moduleSelector: nil,
380+
moduleSelector: memberModuleSelector,
232381
unexpectedBeforeName,
233382
name: name,
234383
genericArgumentClause: generics,

0 commit comments

Comments
 (0)