Skip to content

Commit b57df1e

Browse files
authored
Merge pull request #1986 from ahoppen/ahoppen/disallow-self-in-types
Disallow the `self`/`Self` keyword where it’s not allowed in types
2 parents 4c59d05 + c9453c3 commit b57df1e

File tree

14 files changed

+144
-122
lines changed

14 files changed

+144
-122
lines changed

CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public let TYPE_NODES: [Node] = [
300300
),
301301
Child(
302302
name: "name",
303-
kind: .token(choices: [.token(.identifier), .keyword(.self), .keyword(.Self)]),
303+
kind: .token(choices: [.token(.identifier), .keyword(.self)]),
304304
nameForDiagnostics: "name"
305305
),
306306
Child(
@@ -435,7 +435,6 @@ public let TYPE_NODES: [Node] = [
435435
name: "name",
436436
kind: .token(choices: [
437437
.token(.identifier),
438-
.keyword(.self),
439438
.keyword(.Self),
440439
.keyword(.Any),
441440
.token(.wildcard),

Sources/SwiftParser/Names.swift

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ extension Parser {
151151

152152
if self.lookahead().canParseBaseTypeForQualifiedDeclName() {
153153
type = RawExprSyntax(RawTypeExprSyntax(type: self.parseQualifiedTypeIdentifier(), arena: self.arena))
154-
period = self.consumePrefix(".", as: .period)
154+
period = self.expectWithoutRecovery(prefix: ".", as: .period)
155155
} else {
156156
type = nil
157157
period = nil
@@ -181,52 +181,70 @@ extension Parser {
181181
return RawTypeSyntax(self.parseAnyType())
182182
}
183183

184-
var result: RawTypeSyntax?
185-
var keepGoing: RawTokenSyntax? = nil
184+
let (unexpectedBeforeName, name) = self.expect(anyIn: IdentifierTypeSyntax.NameOptions.self, default: .identifier)
185+
let generics: RawGenericArgumentClauseSyntax?
186+
if self.atContextualPunctuator("<") {
187+
generics = self.parseGenericArguments()
188+
} else {
189+
generics = nil
190+
}
191+
192+
var result = RawTypeSyntax(
193+
RawIdentifierTypeSyntax(
194+
unexpectedBeforeName,
195+
name: name,
196+
genericArgumentClause: generics,
197+
arena: self.arena
198+
)
199+
)
200+
201+
// If qualified name base type cannot be parsed from the current
202+
// point (i.e. the next type identifier is not followed by a '.'),
203+
// then the next identifier is the final declaration name component.
204+
var backtrack = self.lookahead()
205+
guard
206+
backtrack.consume(ifPrefix: ".", as: .period) != nil,
207+
backtrack.canParseBaseTypeForQualifiedDeclName()
208+
else {
209+
return result
210+
}
211+
212+
var keepGoing = self.consume(if: .period)
186213
var loopProgress = LoopProgressCondition()
187-
repeat {
188-
let (unexpectedBeforeName, name) = self.expect(.identifier, .keyword(.self), .keyword(.Self), default: .identifier)
214+
while keepGoing != nil && self.hasProgressed(&loopProgress) {
215+
let (unexpectedBeforeName, name) = self.expect(.identifier, .keyword(.self), TokenSpec(.Self, remapping: .identifier), default: .identifier)
189216
let generics: RawGenericArgumentClauseSyntax?
190217
if self.atContextualPunctuator("<") {
191218
generics = self.parseGenericArguments()
192219
} else {
193220
generics = nil
194221
}
195-
if let keepGoing {
196-
result = RawTypeSyntax(
197-
RawMemberTypeSyntax(
198-
baseType: result!,
199-
period: keepGoing,
200-
unexpectedBeforeName,
201-
name: name,
202-
genericArgumentClause: generics,
203-
arena: self.arena
204-
)
205-
)
206-
} else {
207-
result = RawTypeSyntax(
208-
RawIdentifierTypeSyntax(
209-
unexpectedBeforeName,
210-
name: name,
211-
genericArgumentClause: generics,
212-
arena: self.arena
213-
)
222+
result = RawTypeSyntax(
223+
RawMemberTypeSyntax(
224+
baseType: result,
225+
period: keepGoing!,
226+
unexpectedBeforeName,
227+
name: name,
228+
genericArgumentClause: generics,
229+
arena: self.arena
214230
)
215-
}
231+
)
216232

217233
// If qualified name base type cannot be parsed from the current
218234
// point (i.e. the next type identifier is not followed by a '.'),
219235
// then the next identifier is the final declaration name component.
220236
var backtrack = self.lookahead()
221-
backtrack.consumePrefix(".", as: .period)
222-
guard backtrack.canParseBaseTypeForQualifiedDeclName() else {
237+
guard
238+
backtrack.consume(ifPrefix: ".", as: .period) != nil,
239+
backtrack.canParseBaseTypeForQualifiedDeclName()
240+
else {
223241
break
224242
}
225243

226244
keepGoing = self.consume(if: .period)
227-
} while keepGoing != nil && self.hasProgressed(&loopProgress)
245+
}
228246

229-
return result!
247+
return result
230248
}
231249
}
232250

Sources/SwiftParser/Parameters.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,11 @@ extension Parser {
9797

9898
let type: RawTypeSyntax
9999

100-
if colon.presence == .missing, let secondName = names.secondName, secondName.tokenText.isStartingWithUppercase {
100+
if colon.presence == .missing,
101+
let secondName = names.secondName,
102+
secondName.tokenKind == .identifier,
103+
secondName.tokenText.isStartingWithUppercase
104+
{
101105
// Synthesize the secondName parameter as a type node.
102106
type = RawTypeSyntax(
103107
RawIdentifierTypeSyntax(

Sources/SwiftParser/Parser.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ extension Parser {
635635
/// currently positioned at a keyword, consume that keyword and remap it
636636
/// to and identifier.
637637
/// - Returns: The consumed token and any unexpected tokens that were skipped.
638+
/// The token is always guaranteed to be of `TokenKind.identifier`
638639
mutating func expectIdentifier(
639640
keywordRecovery: Bool = false,
640641
allowSelfOrCapitalSelfAsIdentifier: Bool = false,

Sources/SwiftParser/Types.swift

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,20 @@ extension Parser {
270270
)
271271
)
272272
} else {
273-
let (name, generics) = self.parseTypeNameWithGenerics(allowKeywordAsName: true)
273+
let name: RawTokenSyntax
274+
if let handle = self.at(anyIn: MemberTypeSyntax.NameOptions.self)?.handle {
275+
name = self.eat(handle)
276+
} else if self.currentToken.isLexerClassifiedKeyword {
277+
name = self.consumeAnyToken(remapping: .identifier)
278+
} else {
279+
name = missingToken(.identifier)
280+
}
281+
let generics: RawGenericArgumentClauseSyntax?
282+
if self.atContextualPunctuator("<") {
283+
generics = self.parseGenericArguments()
284+
} else {
285+
generics = nil
286+
}
274287
base = RawTypeSyntax(
275288
RawMemberTypeSyntax(
276289
baseType: base,
@@ -322,30 +335,23 @@ extension Parser {
322335
)
323336
}
324337

325-
mutating func parseTypeNameWithGenerics(allowKeywordAsName: Bool) -> (RawTokenSyntax, RawGenericArgumentClauseSyntax?) {
326-
let name: RawTokenSyntax
327-
if let identOrSelf = self.consume(if: .identifier, .keyword(.self), .keyword(.Self)) {
328-
name = identOrSelf
329-
} else if allowKeywordAsName && self.currentToken.isLexerClassifiedKeyword {
330-
name = self.consumeAnyToken(remapping: .identifier)
331-
} else {
332-
name = missingToken(.identifier)
333-
}
334-
if self.atContextualPunctuator("<") {
335-
return (name, self.parseGenericArguments())
336-
}
337-
return (name, nil)
338-
}
339-
340338
/// Parse a type identifier.
341339
mutating func parseTypeIdentifier() -> RawTypeSyntax {
342340
if self.at(.keyword(.Any)) {
343341
return RawTypeSyntax(self.parseAnyType())
344342
}
345343

346-
let (name, generics) = parseTypeNameWithGenerics(allowKeywordAsName: false)
344+
let (unexpectedBeforeName, name) = self.expect(anyIn: IdentifierTypeSyntax.NameOptions.self, default: .identifier)
345+
let generics: RawGenericArgumentClauseSyntax?
346+
if self.atContextualPunctuator("<") {
347+
generics = self.parseGenericArguments()
348+
} else {
349+
generics = nil
350+
}
351+
347352
return RawTypeSyntax(
348353
RawIdentifierTypeSyntax(
354+
unexpectedBeforeName,
349355
name: name,
350356
genericArgumentClause: generics,
351357
arena: self.arena
@@ -479,6 +485,7 @@ extension Parser {
479485
if let first,
480486
second == nil,
481487
colon?.isMissing == true,
488+
first.tokenKind == .identifier,
482489
first.tokenText.isStartingWithUppercase
483490
{
484491
elements.append(

Sources/SwiftParser/generated/Parser+TokenSpecSet.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,6 @@ extension IdentifierTypeSyntax {
15591559
@_spi(Diagnostics)
15601560
public enum NameOptions: TokenSpecSet {
15611561
case identifier
1562-
case `self`
15631562
case `Self`
15641563
case `Any`
15651564
case wildcard
@@ -1568,8 +1567,6 @@ extension IdentifierTypeSyntax {
15681567
switch PrepareForKeywordMatch(lexeme) {
15691568
case TokenSpec(.identifier):
15701569
self = .identifier
1571-
case TokenSpec(.self):
1572-
self = .self
15731570
case TokenSpec(.Self):
15741571
self = .Self
15751572
case TokenSpec(.Any):
@@ -1585,8 +1582,6 @@ extension IdentifierTypeSyntax {
15851582
switch self {
15861583
case .identifier:
15871584
return .identifier
1588-
case .self:
1589-
return .keyword(.self)
15901585
case .Self:
15911586
return .keyword(.Self)
15921587
case .Any:
@@ -1604,8 +1599,6 @@ extension IdentifierTypeSyntax {
16041599
switch self {
16051600
case .identifier:
16061601
return .identifier("")
1607-
case .self:
1608-
return .keyword(.self)
16091602
case .Self:
16101603
return .keyword(.Self)
16111604
case .Any:
@@ -2097,16 +2090,13 @@ extension MemberTypeSyntax {
20972090
public enum NameOptions: TokenSpecSet {
20982091
case identifier
20992092
case `self`
2100-
case `Self`
21012093

21022094
init?(lexeme: Lexer.Lexeme) {
21032095
switch PrepareForKeywordMatch(lexeme) {
21042096
case TokenSpec(.identifier):
21052097
self = .identifier
21062098
case TokenSpec(.self):
21072099
self = .self
2108-
case TokenSpec(.Self):
2109-
self = .Self
21102100
default:
21112101
return nil
21122102
}
@@ -2118,8 +2108,6 @@ extension MemberTypeSyntax {
21182108
return .identifier
21192109
case .self:
21202110
return .keyword(.self)
2121-
case .Self:
2122-
return .keyword(.Self)
21232111
}
21242112
}
21252113

@@ -2133,8 +2121,6 @@ extension MemberTypeSyntax {
21332121
return .identifier("")
21342122
case .self:
21352123
return .keyword(.self)
2136-
case .Self:
2137-
return .keyword(.Self)
21382124
}
21392125
}
21402126
}

Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,6 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
14061406
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
14071407
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [
14081408
.tokenKind(.identifier),
1409-
.keyword("self"),
14101409
.keyword("Self"),
14111410
.keyword("Any"),
14121411
.tokenKind(.wildcard)
@@ -1805,7 +1804,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
18051804
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
18061805
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.period)]))
18071806
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
1808-
assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier), .keyword("self"), .keyword("Self")]))
1807+
assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier), .keyword("self")]))
18091808
assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self))
18101809
assertNoError(kind, 7, verify(layout[7], as: RawGenericArgumentClauseSyntax?.self))
18111810
assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self))

Sources/SwiftSyntax/generated/syntaxNodes/SyntaxTypeNodes.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ public struct FunctionTypeSyntax: TypeSyntaxProtocol, SyntaxHashable {
970970

971971
/// ### Children
972972
///
973-
/// - `name`: (`<identifier>` | `'self'` | `'Self'` | `'Any'` | `'_'`)
973+
/// - `name`: (`<identifier>` | `'Self'` | `'Any'` | `'_'`)
974974
/// - `genericArgumentClause`: ``GenericArgumentClauseSyntax``?
975975
public struct IdentifierTypeSyntax: TypeSyntaxProtocol, SyntaxHashable {
976976
public let _syntaxNode: Syntax
@@ -1218,7 +1218,7 @@ public struct ImplicitlyUnwrappedOptionalTypeSyntax: TypeSyntaxProtocol, SyntaxH
12181218
///
12191219
/// - `baseType`: ``TypeSyntax``
12201220
/// - `period`: `'.'`
1221-
/// - `name`: (`<identifier>` | `'self'` | `'Self'`)
1221+
/// - `name`: (`<identifier>` | `'self'`)
12221222
/// - `genericArgumentClause`: ``GenericArgumentClauseSyntax``?
12231223
public struct MemberTypeSyntax: TypeSyntaxProtocol, SyntaxHashable {
12241224
public let _syntaxNode: Syntax

Tests/SwiftParserTest/Assertions.swift

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -529,35 +529,6 @@ public struct AssertParseOptions: OptionSet {
529529
}
530530

531531
extension ParserTestCase {
532-
/// Same as `assertParse` overload with a `(String) -> S` `parse`,
533-
/// parsing the resulting `String` as a ``SourceFileSyntax``.
534-
func assertParse(
535-
_ markedSource: String,
536-
substructure expectedSubstructure: (some SyntaxProtocol)? = Optional<Syntax>.none,
537-
substructureAfterMarker: String = "START",
538-
diagnostics expectedDiagnostics: [DiagnosticSpec] = [],
539-
applyFixIts: [String]? = nil,
540-
fixedSource expectedFixedSource: String? = nil,
541-
options: AssertParseOptions = [],
542-
experimentalFeatures: Parser.ExperimentalFeatures? = nil,
543-
file: StaticString = #file,
544-
line: UInt = #line
545-
) {
546-
assertParse(
547-
markedSource,
548-
{ SourceFileSyntax.parse(from: &$0) },
549-
substructure: expectedSubstructure,
550-
substructureAfterMarker: substructureAfterMarker,
551-
diagnostics: expectedDiagnostics,
552-
applyFixIts: applyFixIts,
553-
fixedSource: expectedFixedSource,
554-
options: options,
555-
experimentalFeatures: experimentalFeatures,
556-
file: file,
557-
line: line
558-
)
559-
}
560-
561532
/// After a test case has been mutated, assert that the mutated source
562533
/// round-trips and doesn’t hit any assertion failures in the parser.
563534
fileprivate func assertRoundTrip<S: SyntaxProtocol>(
@@ -615,7 +586,7 @@ extension ParserTestCase {
615586
/// `nil` to enable the default set of features provided by the test case.
616587
func assertParse<S: SyntaxProtocol>(
617588
_ markedSource: String,
618-
_ parse: (inout Parser) -> S,
589+
_ parse: (inout Parser) -> S = { SourceFileSyntax.parse(from: &$0) },
619590
substructure expectedSubstructure: (some SyntaxProtocol)? = Optional<Syntax>.none,
620591
substructureAfterMarker: String = "START",
621592
diagnostics expectedDiagnostics: [DiagnosticSpec] = [],

Tests/SwiftParserTest/AttributeTests.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,24 @@ final class AttributeTests: ParserTestCase {
220220
) {}
221221
"""
222222
)
223+
224+
assertParse(
225+
"""
226+
@derivative(of: 1️⃣Self.other)
227+
func foo() {}
228+
""",
229+
substructure: Syntax(TokenSyntax.keyword(.Self)),
230+
substructureAfterMarker: "1️⃣"
231+
)
232+
233+
assertParse(
234+
"""
235+
@derivative(of: Foo.1️⃣Self.other)
236+
func foo() {}
237+
""",
238+
substructure: Syntax(TokenSyntax.identifier("Self")),
239+
substructureAfterMarker: "1️⃣"
240+
)
223241
}
224242

225243
func testTransposeAttribute() {

0 commit comments

Comments
 (0)