Skip to content

Commit 5f9ae5d

Browse files
committed
Forbid newline after ::
This restricts the code styles developers can use, but makes it less likely to eat syntax that was meant to belong to a different statement after an incomplete line.
1 parent 2807c92 commit 5f9ae5d

File tree

5 files changed

+154
-46
lines changed

5 files changed

+154
-46
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,8 @@ extension Parser {
453453
// Special case: scoped import with module selector-style syntax. This always has exactly two path components
454454
// separated by '::'.
455455
if hasImportKind,
456-
let (moduleNameOrUnexpected, colonColon, unexpectedAfterColonColon) = self.consumeModuleSelectorTokens()
456+
let (moduleNameOrUnexpected, colonColon, unexpectedAfterColonColon, skipQualifiedName) =
457+
self.consumeModuleSelectorTokens()
457458
{
458459
// Is the token in module name position really a module name?
459460
let unexpectedBeforeModuleName: RawUnexpectedNodesSyntax?, moduleName: RawTokenSyntax
@@ -465,7 +466,7 @@ extension Parser {
465466
moduleName = self.missingToken(.identifier)
466467
}
467468

468-
let declName = self.parseAnyIdentifier()
469+
let declName = skipQualifiedName ? self.missingToken(.identifier) : self.parseAnyIdentifier()
469470

470471
elements = [
471472
RawImportPathComponentSyntax(
@@ -2238,13 +2239,17 @@ extension Parser {
22382239
}
22392240

22402241
let moduleSelector: RawModuleSelectorSyntax?
2242+
if !self.atStartOfLine {
2243+
(moduleSelector, _) = self.parseModuleSelectorIfPresent()
2244+
} else {
2245+
moduleSelector = nil
2246+
}
2247+
22412248
let unexpectedBeforeMacro: RawUnexpectedNodesSyntax?
22422249
let macro: RawTokenSyntax
22432250
if !self.atStartOfLine {
2244-
moduleSelector = self.parseModuleSelectorIfPresent()
22452251
(unexpectedBeforeMacro, macro) = self.expectIdentifier(allowKeywordsAsIdentifier: true)
22462252
} else {
2247-
moduleSelector = nil
22482253
unexpectedBeforeMacro = nil
22492254
macro = self.missingToken(.identifier)
22502255
}

Sources/SwiftParser/Expressions.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,14 @@ extension Parser {
13951395
)
13961396
pound = pound.tokenView.withTokenDiagnostic(tokenDiagnostic: diagnostic, arena: self.arena)
13971397
}
1398-
let moduleSelector = parseModuleSelectorIfPresent()
1398+
1399+
let moduleSelector: RawModuleSelectorSyntax?
1400+
if !self.atStartOfLine {
1401+
(moduleSelector, _) = self.parseModuleSelectorIfPresent()
1402+
} else {
1403+
moduleSelector = nil
1404+
}
1405+
13991406
let unexpectedBeforeMacroName: RawUnexpectedNodesSyntax?
14001407
let macroName: RawTokenSyntax
14011408
if !self.atStartOfLine {

Sources/SwiftParser/Names.swift

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ extension TokenConsumer {
8383
/// - `colonColonToken`: The `::` indicating this module selector. Always `.colonColon`, always present.
8484
/// - `extra`: Tokens for additional trailing module selectors. There is no situation in which two module selectors
8585
/// can be validly chained.
86+
/// - `skipQualifiedName`: True if the next token should be interpreted as a different statement.
8687
mutating func consumeModuleSelectorTokens() -> (
87-
moduleNameOrUnexpected: Token, colonColonToken: Token, extra: [Token]
88+
moduleNameOrUnexpected: Token, colonColonToken: Token, extra: [Token], skipQualifiedName: Bool
8889
)? {
8990
guard self.isAtModuleSelector() else {
9091
return nil
@@ -111,15 +112,18 @@ extension TokenConsumer {
111112
}
112113
extra.append(self.eat(.colonColon))
113114
}
114-
return (moduleName, colonColonToken, extra)
115+
116+
let afterContainsAnyNewline = self.atStartOfLine
117+
118+
return (moduleName, colonColonToken, extra, afterContainsAnyNewline)
115119
}
116120
}
117121

118122
extension Parser {
119123
/// Parses one or more module selectors, if present.
120-
mutating func parseModuleSelectorIfPresent() -> RawModuleSelectorSyntax? {
121-
guard let (moduleNameOrUnexpected, colonColon, extra) = consumeModuleSelectorTokens() else {
122-
return nil
124+
mutating func parseModuleSelectorIfPresent() -> (moduleSelector: RawModuleSelectorSyntax?, skipQualifiedName: Bool) {
125+
guard let (moduleNameOrUnexpected, colonColon, extra, skipQualifiedName) = consumeModuleSelectorTokens() else {
126+
return (nil, false)
123127
}
124128

125129
let leadingUnexpected: [RawSyntax]
@@ -136,12 +140,15 @@ extension Parser {
136140

137141
trailingUnexpected = extra.map { RawSyntax($0) }
138142

139-
return RawModuleSelectorSyntax(
140-
RawUnexpectedNodesSyntax(leadingUnexpected, arena: arena),
141-
moduleName: moduleName,
142-
colonColon: colonColon,
143-
RawUnexpectedNodesSyntax(trailingUnexpected, arena: arena),
144-
arena: arena
143+
return (
144+
moduleSelector: RawModuleSelectorSyntax(
145+
RawUnexpectedNodesSyntax(leadingUnexpected, arena: arena),
146+
moduleName: moduleName,
147+
colonColon: colonColon,
148+
RawUnexpectedNodesSyntax(trailingUnexpected, arena: arena),
149+
arena: arena
150+
),
151+
skipQualifiedName: skipQualifiedName
145152
)
146153
}
147154
}
@@ -170,14 +177,17 @@ extension Parser {
170177

171178
mutating func parseDeclReferenceExpr(_ flags: DeclNameOptions = []) -> RawDeclReferenceExprSyntax {
172179
// Consume a module selector if present.
173-
let moduleSelector = self.parseModuleSelectorIfPresent()
180+
let (moduleSelector, skipQualifiedName) = self.parseModuleSelectorIfPresent()
174181

175182
// If a module selector is found, we parse the name after it according to SE-0071 rules.
176183
let allowKeywords = flags.contains(.keywords) || moduleSelector != nil
177184

178185
// Consume the base name.
179186
let base: RawTokenSyntax
180-
if let identOrSelf = self.consume(if: .identifier, .keyword(.self), .keyword(.Self))
187+
if skipQualifiedName {
188+
// No line break allowed between '::' and its subject, so the identifier is missing.
189+
base = missingToken(.identifier)
190+
} else if let identOrSelf = self.consume(if: .identifier, .keyword(.self), .keyword(.Self))
181191
?? self.consume(if: .keyword(.`init`))
182192
{
183193
base = identOrSelf
@@ -319,13 +329,19 @@ extension Parser {
319329
var keepGoing = self.consume(if: .period)
320330
var loopProgress = LoopProgressCondition()
321331
while keepGoing != nil && self.hasProgressed(&loopProgress) {
322-
let memberModuleSelector = self.parseModuleSelectorIfPresent()
323-
let name = self.parseMemberTypeName()
332+
let (memberModuleSelector, skipQualifiedName) = self.parseModuleSelectorIfPresent()
333+
let name: RawTokenSyntax
324334
let generics: RawGenericArgumentClauseSyntax?
325-
if self.at(prefix: "<") {
326-
generics = self.parseGenericArguments()
327-
} else {
335+
if skipQualifiedName {
336+
name = missingToken(.identifier)
328337
generics = nil
338+
} else {
339+
name = self.parseMemberTypeName()
340+
if self.at(prefix: "<") {
341+
generics = self.parseGenericArguments()
342+
} else {
343+
generics = nil
344+
}
329345
}
330346
result = RawTypeSyntax(
331347
RawMemberTypeSyntax(
@@ -338,7 +354,7 @@ extension Parser {
338354
)
339355
)
340356

341-
guard hasAnotherMember() else {
357+
guard !skipQualifiedName && hasAnotherMember() else {
342358
break
343359
}
344360

Sources/SwiftParser/Types.swift

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,19 @@ extension Parser {
293293
)
294294
)
295295
} else {
296-
let memberModuleSelector = self.parseModuleSelectorIfPresent()
297-
let name: RawTokenSyntax = self.parseMemberTypeName()
296+
let (memberModuleSelector, skipQualifiedName) = self.parseModuleSelectorIfPresent()
297+
let name: RawTokenSyntax
298298
let generics: RawGenericArgumentClauseSyntax?
299-
if self.at(prefix: "<") {
300-
generics = self.parseGenericArguments()
301-
} else {
299+
if skipQualifiedName {
300+
name = missingToken(.identifier)
302301
generics = nil
302+
} else {
303+
name = self.parseMemberTypeName()
304+
if self.at(prefix: "<") {
305+
generics = self.parseGenericArguments()
306+
} else {
307+
generics = nil
308+
}
303309
}
304310
base = RawTypeSyntax(
305311
RawMemberTypeSyntax(
@@ -312,6 +318,9 @@ extension Parser {
312318
arena: self.arena
313319
)
314320
)
321+
if skipQualifiedName {
322+
break
323+
}
315324
}
316325
continue
317326
}
@@ -374,25 +383,31 @@ extension Parser {
374383

375384
/// Parse a type identifier.
376385
mutating func parseTypeIdentifier() -> RawIdentifierTypeSyntax {
377-
let moduleSelector = self.parseModuleSelectorIfPresent()
386+
let (moduleSelector, skipQualifiedName) = self.parseModuleSelectorIfPresent()
378387

379388
if moduleSelector == nil && self.at(.keyword(.Any)) {
380389
return self.parseAnyType()
381390
}
382391

383392
let unexpectedBeforeName: RawUnexpectedNodesSyntax?, name: RawTokenSyntax
384-
if moduleSelector == nil {
385-
(unexpectedBeforeName, name) = self.expect(anyIn: IdentifierTypeSyntax.NameOptions.self, default: .identifier)
386-
} else {
387-
// A name after a module selector gets parsed like a member
388-
unexpectedBeforeName = nil
389-
name = self.parseMemberTypeName()
390-
}
391393
let generics: RawGenericArgumentClauseSyntax?
392-
if self.at(prefix: "<") {
393-
generics = self.parseGenericArguments()
394-
} else {
394+
if skipQualifiedName {
395+
unexpectedBeforeName = nil
396+
name = missingToken(.identifier)
395397
generics = nil
398+
} else {
399+
if moduleSelector == nil {
400+
(unexpectedBeforeName, name) = self.expect(anyIn: IdentifierTypeSyntax.NameOptions.self, default: .identifier)
401+
} else {
402+
// A name after a module selector gets parsed like a member
403+
unexpectedBeforeName = nil
404+
name = self.parseMemberTypeName()
405+
}
406+
if self.at(prefix: "<") {
407+
generics = self.parseGenericArguments()
408+
} else {
409+
generics = nil
410+
}
396411
}
397412

398413
return RawIdentifierTypeSyntax(

Tests/SwiftParserTest/translated/ModuleSelectorTests.swift

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,16 @@ final class ModuleSelectorTests: ParserTestCase {
454454
)
455455
assertParse(
456456
"""
457-
_ = Swift::
457+
_ = Swift::1️⃣
458458
print
459459
""",
460-
substructure: makeDeclRef(moduleSelector: "Swift", baseName: "print")
460+
diagnostics: [
461+
DiagnosticSpec(message: "expected identifier", fixIts: ["insert identifier"])
462+
],
463+
fixedSource: """
464+
_ = Swift::<#identifier#>
465+
print
466+
"""
461467
)
462468
assertParse(
463469
"""
@@ -468,10 +474,16 @@ final class ModuleSelectorTests: ParserTestCase {
468474
)
469475
assertParse(
470476
"""
471-
_ = Swift ::
477+
_ = Swift ::1️⃣
472478
print
473479
""",
474-
substructure: makeDeclRef(moduleSelector: "Swift", baseName: "print")
480+
diagnostics: [
481+
DiagnosticSpec(message: "expected identifier", fixIts: ["insert identifier"])
482+
],
483+
fixedSource: """
484+
_ = Swift ::<#identifier#>
485+
print
486+
"""
475487
)
476488
assertParse(
477489
"""
@@ -483,10 +495,17 @@ final class ModuleSelectorTests: ParserTestCase {
483495
assertParse(
484496
"""
485497
_ = Swift
486-
::
498+
::1️⃣
487499
print
488500
""",
489-
substructure: makeDeclRef(moduleSelector: "Swift", baseName: "print")
501+
diagnostics: [
502+
DiagnosticSpec(message: "expected identifier", fixIts: ["insert identifier"])
503+
],
504+
fixedSource: """
505+
_ = Swift
506+
::<#identifier#>
507+
print
508+
"""
490509
)
491510
}
492511

@@ -1773,6 +1792,20 @@ final class ModuleSelectorTests: ParserTestCase {
17731792
),
17741793
experimentalFeatures: [.moduleSelector, .doExpressions]
17751794
)
1795+
assertParse(
1796+
"""
1797+
let x = Swift::1️⃣
1798+
do { 1 }
1799+
""",
1800+
diagnostics: [
1801+
DiagnosticSpec(message: "expected identifier in variable", fixIts: ["insert identifier"])
1802+
],
1803+
fixedSource: """
1804+
let x = Swift::<#identifier#>
1805+
do { 1 }
1806+
""",
1807+
experimentalFeatures: [.moduleSelector, .doExpressions]
1808+
)
17761809
assertParse(
17771810
"let x = Swift::if1️⃣ y { 1 } 2️⃣else { 0 }",
17781811
diagnostics: [
@@ -1790,6 +1823,19 @@ final class ModuleSelectorTests: ParserTestCase {
17901823
y { 1 } else { 0 }
17911824
"""
17921825
)
1826+
assertParse(
1827+
"""
1828+
let x = Swift::1️⃣
1829+
if y { 1 } else { 0 }
1830+
""",
1831+
diagnostics: [
1832+
DiagnosticSpec(message: "expected identifier in variable", fixIts: ["insert identifier"])
1833+
],
1834+
fixedSource: """
1835+
let x = Swift::<#identifier#>
1836+
if y { 1 } else { 0 }
1837+
"""
1838+
)
17931839
assertParse(
17941840
"""
17951841
let x = Swift::switch1️⃣ y2️⃣ {
@@ -1825,6 +1871,25 @@ final class ModuleSelectorTests: ParserTestCase {
18251871
}
18261872
"""
18271873
)
1874+
assertParse(
1875+
"""
1876+
let x = Swift::1️⃣
1877+
switch y {
1878+
case true: 1
1879+
case false: 0
1880+
}
1881+
""",
1882+
diagnostics: [
1883+
DiagnosticSpec(message: "expected identifier in variable", fixIts: ["insert identifier"])
1884+
],
1885+
fixedSource: """
1886+
let x = Swift::<#identifier#>
1887+
switch y {
1888+
case true: 1
1889+
case false: 0
1890+
}
1891+
"""
1892+
)
18281893
assertParse(
18291894
"fn(Swift::1️⃣&x)",
18301895
diagnostics: [

0 commit comments

Comments
 (0)