Skip to content

Commit 989058c

Browse files
committed
Implement syntax and parsing for value generics
1 parent bef1ba1 commit 989058c

File tree

11 files changed

+221
-52
lines changed

11 files changed

+221
-52
lines changed

CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,12 @@ public let GENERIC_NODES: [Node] = [
9393
kind: .collection(kind: .attributeList, collectionElementName: "Attribute", defaultsToEmpty: true)
9494
),
9595
Child(
96-
name: "eachKeyword",
97-
deprecatedName: "each",
98-
kind: .token(choices: [.keyword(.each)]),
99-
nameForDiagnostics: "parameter pack specifier",
96+
name: "specifier",
97+
kind: .token(choices: [
98+
.keyword(.each),
99+
.keyword(.let)
100+
]),
101+
nameForDiagnostics: "specifier",
100102
isOptional: true
101103
),
102104
Child(

Sources/SwiftParser/Declarations.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,18 @@ extension Parser {
431431
repeat {
432432
let attributes = self.parseAttributeList()
433433

434-
// Parse the 'each' keyword for a type parameter pack 'each T'.
435-
var each = self.consume(if: .keyword(.each))
434+
var specifier: Token? = nil
435+
436+
// Parse the 'each' keyword for a type parameter pack 'each T' or a
437+
// 'let' keyword for a value parameter 'let N: Int'.
438+
if let each = self.consume(if: .keyword(.each)) {
439+
specifier = each
440+
} else if let `let` = self.consume(if: .keyword(.let)) {
441+
specifier = `let`
442+
}
436443

437-
let (unexpectedBetweenEachAndName, name) = self.expectIdentifier(allowSelfOrCapitalSelfAsIdentifier: true)
438-
if attributes.isEmpty && each == nil && unexpectedBetweenEachAndName == nil && name.isMissing
444+
let (unexpectedBetweenSpecifierAndName, name) = self.expectIdentifier(allowSelfOrCapitalSelfAsIdentifier: true)
445+
if attributes.isEmpty && specifier == nil && unexpectedBetweenSpecifierAndName == nil && name.isMissing
439446
&& elements.isEmpty && !self.at(prefix: ">")
440447
{
441448
break
@@ -445,8 +452,8 @@ extension Parser {
445452
let unexpectedBetweenNameAndColon: RawUnexpectedNodesSyntax?
446453
if let ellipsis = self.consume(ifPrefix: "...", as: .ellipsis) {
447454
unexpectedBetweenNameAndColon = RawUnexpectedNodesSyntax([ellipsis], arena: self.arena)
448-
if each == nil {
449-
each = missingToken(.each)
455+
if specifier == nil {
456+
specifier = missingToken(.each)
450457
}
451458
} else {
452459
unexpectedBetweenNameAndColon = nil
@@ -481,8 +488,8 @@ extension Parser {
481488
elements.append(
482489
RawGenericParameterSyntax(
483490
attributes: attributes,
484-
eachKeyword: each,
485-
unexpectedBetweenEachAndName,
491+
specifier: specifier,
492+
unexpectedBetweenSpecifierAndName,
486493
name: name,
487494
unexpectedBetweenNameAndColon,
488495
colon: colon,

Sources/SwiftParser/generated/Parser+TokenSpecSet.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,58 @@ extension FunctionParameterSyntax {
18521852
}
18531853
}
18541854

1855+
extension GenericParameterSyntax {
1856+
@_spi(Diagnostics)
1857+
public enum SpecifierOptions: TokenSpecSet {
1858+
case each
1859+
case `let`
1860+
1861+
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
1862+
switch PrepareForKeywordMatch(lexeme) {
1863+
case TokenSpec(.each):
1864+
self = .each
1865+
case TokenSpec(.let):
1866+
self = .let
1867+
default:
1868+
return nil
1869+
}
1870+
}
1871+
1872+
public init?(token: TokenSyntax) {
1873+
switch token {
1874+
case TokenSpec(.each):
1875+
self = .each
1876+
case TokenSpec(.let):
1877+
self = .let
1878+
default:
1879+
return nil
1880+
}
1881+
}
1882+
1883+
var spec: TokenSpec {
1884+
switch self {
1885+
case .each:
1886+
return .keyword(.each)
1887+
case .let:
1888+
return .keyword(.let)
1889+
}
1890+
}
1891+
1892+
/// Returns a token that satisfies the `TokenSpec` of this case.
1893+
///
1894+
/// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text.
1895+
@_spi(Diagnostics)
1896+
public var tokenSyntax: TokenSyntax {
1897+
switch self {
1898+
case .each:
1899+
return .keyword(.each)
1900+
case .let:
1901+
return .keyword(.let)
1902+
}
1903+
}
1904+
}
1905+
}
1906+
18551907
extension IdentifierPatternSyntax {
18561908
@_spi(Diagnostics)
18571909
public enum IdentifierOptions: TokenSpecSet {

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,15 +1022,16 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
10221022
return .skipChildren
10231023
}
10241024
// Emit a custom diagnostic for an unexpected '...' after the type name.
1025-
if node.eachKeyword?.isPresent ?? false {
1025+
if node.specifier?.isPresent ?? false {
10261026
removeToken(
10271027
node.unexpectedBetweenNameAndColon,
10281028
where: { $0.tokenKind == .ellipsis },
10291029
message: { _ in .typeParameterPackEllipsis }
10301030
)
10311031
} else if let unexpected = node.unexpectedBetweenNameAndColon,
10321032
let unexpectedEllipsis = unexpected.onlyPresentToken(where: { $0.tokenKind == .ellipsis }),
1033-
let each = node.eachKeyword
1033+
let specifier = node.specifier,
1034+
specifier.tokenKind == .keyword(.each)
10341035
{
10351036
addDiagnostic(
10361037
unexpected,
@@ -1040,11 +1041,11 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
10401041
message: ReplaceTokensFixIt(replaceTokens: [unexpectedEllipsis], replacements: [.keyword(.each)]),
10411042
changes: [
10421043
.makeMissing(unexpected),
1043-
.makePresent(each, trailingTrivia: .space),
1044+
.makePresent(specifier, trailingTrivia: .space)
10441045
]
10451046
)
10461047
],
1047-
handledNodes: [unexpected.id, each.id]
1048+
handledNodes: [unexpected.id, specifier.id]
10481049
)
10491050
}
10501051
if let inheritedTypeName = node.inheritedType?.as(IdentifierTypeSyntax.self)?.name {

Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String? {
168168
return "type"
169169
case \FunctionParameterSyntax.defaultValue:
170170
return "default value"
171-
case \GenericParameterSyntax.eachKeyword:
172-
return "parameter pack specifier"
171+
case \GenericParameterSyntax.specifier:
172+
return "specifier"
173173
case \GenericParameterSyntax.name:
174174
return "name"
175175
case \GenericParameterSyntax.inheritedType:

Sources/SwiftRefactor/OpaqueParameterToGeneric.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fileprivate class SomeParameterRewriter: SyntaxRewriter {
6060

6161
let genericParam = GenericParameterSyntax(
6262
attributes: [],
63-
eachKeyword: nil,
63+
specifier: nil,
6464
name: paramNameSyntax,
6565
colon: colon,
6666
inheritedType: inheritedType,

Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,12 +1551,12 @@ public func childName(_ keyPath: AnyKeyPath) -> String? {
15511551
return "unexpectedBeforeAttributes"
15521552
case \GenericParameterSyntax.attributes:
15531553
return "attributes"
1554-
case \GenericParameterSyntax.unexpectedBetweenAttributesAndEachKeyword:
1555-
return "unexpectedBetweenAttributesAndEachKeyword"
1556-
case \GenericParameterSyntax.eachKeyword:
1557-
return "eachKeyword"
1558-
case \GenericParameterSyntax.unexpectedBetweenEachKeywordAndName:
1559-
return "unexpectedBetweenEachKeywordAndName"
1554+
case \GenericParameterSyntax.unexpectedBetweenAttributesAndSpecifier:
1555+
return "unexpectedBetweenAttributesAndSpecifier"
1556+
case \GenericParameterSyntax.specifier:
1557+
return "specifier"
1558+
case \GenericParameterSyntax.unexpectedBetweenSpecifierAndName:
1559+
return "unexpectedBetweenSpecifierAndName"
15601560
case \GenericParameterSyntax.name:
15611561
return "name"
15621562
case \GenericParameterSyntax.unexpectedBetweenNameAndColon:

Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,9 @@ public struct RawGenericParameterSyntax: RawSyntaxNodeProtocol {
390390
public init(
391391
_ unexpectedBeforeAttributes: RawUnexpectedNodesSyntax? = nil,
392392
attributes: RawAttributeListSyntax,
393-
_ unexpectedBetweenAttributesAndEachKeyword: RawUnexpectedNodesSyntax? = nil,
394-
eachKeyword: RawTokenSyntax?,
395-
_ unexpectedBetweenEachKeywordAndName: RawUnexpectedNodesSyntax? = nil,
393+
_ unexpectedBetweenAttributesAndSpecifier: RawUnexpectedNodesSyntax? = nil,
394+
specifier: RawTokenSyntax?,
395+
_ unexpectedBetweenSpecifierAndName: RawUnexpectedNodesSyntax? = nil,
396396
name: RawTokenSyntax,
397397
_ unexpectedBetweenNameAndColon: RawUnexpectedNodesSyntax? = nil,
398398
colon: RawTokenSyntax?,
@@ -408,9 +408,9 @@ public struct RawGenericParameterSyntax: RawSyntaxNodeProtocol {
408408
layout.initialize(repeating: nil)
409409
layout[0] = unexpectedBeforeAttributes?.raw
410410
layout[1] = attributes.raw
411-
layout[2] = unexpectedBetweenAttributesAndEachKeyword?.raw
412-
layout[3] = eachKeyword?.raw
413-
layout[4] = unexpectedBetweenEachKeywordAndName?.raw
411+
layout[2] = unexpectedBetweenAttributesAndSpecifier?.raw
412+
layout[3] = specifier?.raw
413+
layout[4] = unexpectedBetweenSpecifierAndName?.raw
414414
layout[5] = name.raw
415415
layout[6] = unexpectedBetweenNameAndColon?.raw
416416
layout[7] = colon?.raw
@@ -431,15 +431,15 @@ public struct RawGenericParameterSyntax: RawSyntaxNodeProtocol {
431431
layoutView.children[1].map(RawAttributeListSyntax.init(raw:))!
432432
}
433433

434-
public var unexpectedBetweenAttributesAndEachKeyword: RawUnexpectedNodesSyntax? {
434+
public var unexpectedBetweenAttributesAndSpecifier: RawUnexpectedNodesSyntax? {
435435
layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:))
436436
}
437437

438-
public var eachKeyword: RawTokenSyntax? {
438+
public var specifier: RawTokenSyntax? {
439439
layoutView.children[3].map(RawTokenSyntax.init(raw:))
440440
}
441441

442-
public var unexpectedBetweenEachKeywordAndName: RawUnexpectedNodesSyntax? {
442+
public var unexpectedBetweenSpecifierAndName: RawUnexpectedNodesSyntax? {
443443
layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:))
444444
}
445445

Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1357,7 +1357,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
13571357
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
13581358
assertNoError(kind, 1, verify(layout[1], as: RawAttributeListSyntax.self))
13591359
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
1360-
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.keyword("each")]))
1360+
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.keyword("each"), .keyword("let")]))
13611361
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
13621362
assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)]))
13631363
assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self))

Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ public struct GenericParameterClauseSyntax: SyntaxProtocol, SyntaxHashable, _Lea
532532
/// ### Children
533533
///
534534
/// - `attributes`: ``AttributeListSyntax``
535-
/// - `eachKeyword`: `each`?
535+
/// - `specifier`: (`each` | `let`)?
536536
/// - `name`: `<identifier>`
537537
/// - `colon`: `:`?
538538
/// - `inheritedType`: ``TypeSyntax``?
@@ -558,9 +558,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
558558
leadingTrivia: Trivia? = nil,
559559
_ unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil,
560560
attributes: AttributeListSyntax = [],
561-
_ unexpectedBetweenAttributesAndEachKeyword: UnexpectedNodesSyntax? = nil,
562-
eachKeyword: TokenSyntax? = nil,
563-
_ unexpectedBetweenEachKeywordAndName: UnexpectedNodesSyntax? = nil,
561+
_ unexpectedBetweenAttributesAndSpecifier: UnexpectedNodesSyntax? = nil,
562+
specifier: TokenSyntax? = nil,
563+
_ unexpectedBetweenSpecifierAndName: UnexpectedNodesSyntax? = nil,
564564
name: TokenSyntax,
565565
_ unexpectedBetweenNameAndColon: UnexpectedNodesSyntax? = nil,
566566
colon: TokenSyntax? = nil,
@@ -576,9 +576,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
576576
self = withExtendedLifetime((SyntaxArena(), (
577577
unexpectedBeforeAttributes,
578578
attributes,
579-
unexpectedBetweenAttributesAndEachKeyword,
580-
eachKeyword,
581-
unexpectedBetweenEachKeywordAndName,
579+
unexpectedBetweenAttributesAndSpecifier,
580+
specifier,
581+
unexpectedBetweenSpecifierAndName,
582582
name,
583583
unexpectedBetweenNameAndColon,
584584
colon,
@@ -591,9 +591,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
591591
let layout: [RawSyntax?] = [
592592
unexpectedBeforeAttributes?.raw,
593593
attributes.raw,
594-
unexpectedBetweenAttributesAndEachKeyword?.raw,
595-
eachKeyword?.raw,
596-
unexpectedBetweenEachKeywordAndName?.raw,
594+
unexpectedBetweenAttributesAndSpecifier?.raw,
595+
specifier?.raw,
596+
unexpectedBetweenSpecifierAndName?.raw,
597597
name.raw,
598598
unexpectedBetweenNameAndColon?.raw,
599599
colon?.raw,
@@ -659,7 +659,7 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
659659
.cast(GenericParameterSyntax.self)
660660
}
661661

662-
public var unexpectedBetweenAttributesAndEachKeyword: UnexpectedNodesSyntax? {
662+
public var unexpectedBetweenAttributesAndSpecifier: UnexpectedNodesSyntax? {
663663
get {
664664
return Syntax(self).child(at: 2)?.cast(UnexpectedNodesSyntax.self)
665665
}
@@ -670,8 +670,10 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
670670

671671
/// ### Tokens
672672
///
673-
/// For syntax trees generated by the parser, this is guaranteed to be `each`.
674-
public var eachKeyword: TokenSyntax? {
673+
/// For syntax trees generated by the parser, this is guaranteed to be one of the following kinds:
674+
/// - `each`
675+
/// - `let`
676+
public var specifier: TokenSyntax? {
675677
get {
676678
return Syntax(self).child(at: 3)?.cast(TokenSyntax.self)
677679
}
@@ -680,7 +682,7 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
680682
}
681683
}
682684

683-
public var unexpectedBetweenEachKeywordAndName: UnexpectedNodesSyntax? {
685+
public var unexpectedBetweenSpecifierAndName: UnexpectedNodesSyntax? {
684686
get {
685687
return Syntax(self).child(at: 4)?.cast(UnexpectedNodesSyntax.self)
686688
}
@@ -773,9 +775,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta
773775
public static let structure: SyntaxNodeStructure = .layout([
774776
\Self.unexpectedBeforeAttributes,
775777
\Self.attributes,
776-
\Self.unexpectedBetweenAttributesAndEachKeyword,
777-
\Self.eachKeyword,
778-
\Self.unexpectedBetweenEachKeywordAndName,
778+
\Self.unexpectedBetweenAttributesAndSpecifier,
779+
\Self.specifier,
780+
\Self.unexpectedBetweenSpecifierAndName,
779781
\Self.name,
780782
\Self.unexpectedBetweenNameAndColon,
781783
\Self.colon,

0 commit comments

Comments
 (0)