Skip to content

Commit a3e1604

Browse files
authored
Merge pull request #2785 from Azoy/integer-generics
Implement syntax and parsing for value generics
2 parents 918c260 + c04a6d3 commit a3e1604

File tree

13 files changed

+243
-71
lines changed

13 files changed

+243
-71
lines changed

CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift

+7-4
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,13 @@ 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+
deprecatedName: "eachKeyword",
98+
kind: .token(choices: [
99+
.keyword(.each),
100+
.keyword(.let),
101+
]),
102+
nameForDiagnostics: "specifier",
100103
isOptional: true
101104
),
102105
Child(

Release Notes/601.md

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## New APIs
44

5+
- `GenericParameterSyntax` now has a new `specifier` property.
6+
- Description: With the introduction of value generics, generic parameters can now be optionally preceded by either a `let` or an `each`. The `specifier` property captures the token representing which one was parsed.
7+
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2785
8+
59
- `IntegerLiteralExprSyntax` and `FloatLiteralExprSyntax` now have a computed `representedLiteralValue` property.
610
- Description: Allows retrieving the represented literal value when valid.
711
- Issue: https://github.com/apple/swift-syntax/issues/405
@@ -27,6 +31,10 @@
2731

2832
## Deprecations
2933

34+
- `GenericParameterSyntax` deprecated `eachKeyword` in favor of `specifier`
35+
- Description: `specifier` is now used to grab either the `each` keyword for a generic parameter or the `let` keyword.
36+
- Pull request: https://github.com/swiftlang/swift-syntax/pull/2785
37+
3038
- `IncrementalEdit` deprecated in favor of `SourceEdit`
3139
- Description: `IncrementalEdit` is being dropped for `SourceEdit`. `SourceEdit` has deprecated compatibility layers to make it API-compatible with `IncrementalEdit`
3240
- Issue: https://github.com/apple/swift-syntax/issues/2532

Sources/SwiftParser/Declarations.swift

+9-8
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,12 @@ 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+
// Parse the 'each' keyword for a type parameter pack 'each T' or a
435+
// 'let' keyword for a value parameter 'let N: Int'.
436+
var specifier = self.consume(if: .keyword(.each), .keyword(.let))
436437

437-
let (unexpectedBetweenEachAndName, name) = self.expectIdentifier(allowSelfOrCapitalSelfAsIdentifier: true)
438-
if attributes.isEmpty && each == nil && unexpectedBetweenEachAndName == nil && name.isMissing
438+
let (unexpectedBetweenSpecifierAndName, name) = self.expectIdentifier(allowSelfOrCapitalSelfAsIdentifier: true)
439+
if attributes.isEmpty && specifier == nil && unexpectedBetweenSpecifierAndName == nil && name.isMissing
439440
&& elements.isEmpty && !self.at(prefix: ">")
440441
{
441442
break
@@ -445,8 +446,8 @@ extension Parser {
445446
let unexpectedBetweenNameAndColon: RawUnexpectedNodesSyntax?
446447
if let ellipsis = self.consume(ifPrefix: "...", as: .ellipsis) {
447448
unexpectedBetweenNameAndColon = RawUnexpectedNodesSyntax([ellipsis], arena: self.arena)
448-
if each == nil {
449-
each = missingToken(.each)
449+
if specifier == nil {
450+
specifier = missingToken(.each)
450451
}
451452
} else {
452453
unexpectedBetweenNameAndColon = nil
@@ -481,8 +482,8 @@ extension Parser {
481482
elements.append(
482483
RawGenericParameterSyntax(
483484
attributes: attributes,
484-
eachKeyword: each,
485-
unexpectedBetweenEachAndName,
485+
specifier: specifier,
486+
unexpectedBetweenSpecifierAndName,
486487
name: name,
487488
unexpectedBetweenNameAndColon,
488489
colon: colon,

Sources/SwiftParser/generated/Parser+TokenSpecSet.swift

+52
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

+5-4
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

+2-2
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

+1-1
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

+6-6
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/RenamedChildrenCompatibility.swift

+19-19
Original file line numberDiff line numberDiff line change
@@ -3610,45 +3610,45 @@ extension GenericParameterClauseSyntax {
36103610
}
36113611

36123612
extension GenericParameterSyntax {
3613-
@available(*, deprecated, renamed: "unexpectedBetweenAttributesAndEachKeyword")
3614-
public var unexpectedBetweenAttributesAndEach: UnexpectedNodesSyntax? {
3613+
@available(*, deprecated, renamed: "unexpectedBetweenAttributesAndSpecifier")
3614+
public var unexpectedBetweenAttributesAndEachKeyword: UnexpectedNodesSyntax? {
36153615
get {
3616-
return unexpectedBetweenAttributesAndEachKeyword
3616+
return unexpectedBetweenAttributesAndSpecifier
36173617
}
36183618
set {
3619-
unexpectedBetweenAttributesAndEachKeyword = newValue
3619+
unexpectedBetweenAttributesAndSpecifier = newValue
36203620
}
36213621
}
36223622

3623-
@available(*, deprecated, renamed: "eachKeyword")
3624-
public var each: TokenSyntax? {
3623+
@available(*, deprecated, renamed: "specifier")
3624+
public var eachKeyword: TokenSyntax? {
36253625
get {
3626-
return eachKeyword
3626+
return specifier
36273627
}
36283628
set {
3629-
eachKeyword = newValue
3629+
specifier = newValue
36303630
}
36313631
}
36323632

3633-
@available(*, deprecated, renamed: "unexpectedBetweenEachKeywordAndName")
3634-
public var unexpectedBetweenEachAndName: UnexpectedNodesSyntax? {
3633+
@available(*, deprecated, renamed: "unexpectedBetweenSpecifierAndName")
3634+
public var unexpectedBetweenEachKeywordAndName: UnexpectedNodesSyntax? {
36353635
get {
3636-
return unexpectedBetweenEachKeywordAndName
3636+
return unexpectedBetweenSpecifierAndName
36373637
}
36383638
set {
3639-
unexpectedBetweenEachKeywordAndName = newValue
3639+
unexpectedBetweenSpecifierAndName = newValue
36403640
}
36413641
}
36423642

3643-
@available(*, deprecated, renamed: "GenericParameterSyntax(leadingTrivia:_:attributes:_:eachKeyword:_:name:_:colon:_:inheritedType:_:trailingComma:_:trailingTrivia:)")
3643+
@available(*, deprecated, renamed: "GenericParameterSyntax(leadingTrivia:_:attributes:_:specifier:_:name:_:colon:_:inheritedType:_:trailingComma:_:trailingTrivia:)")
36443644
@_disfavoredOverload
36453645
public init(
36463646
leadingTrivia: Trivia? = nil,
36473647
_ unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil,
36483648
attributes: AttributeListSyntax = [],
3649-
_ unexpectedBetweenAttributesAndEach: UnexpectedNodesSyntax? = nil,
3650-
each: TokenSyntax? = nil,
3651-
_ unexpectedBetweenEachAndName: UnexpectedNodesSyntax? = nil,
3649+
_ unexpectedBetweenAttributesAndEachKeyword: UnexpectedNodesSyntax? = nil,
3650+
eachKeyword: TokenSyntax? = nil,
3651+
_ unexpectedBetweenEachKeywordAndName: UnexpectedNodesSyntax? = nil,
36523652
name: TokenSyntax,
36533653
_ unexpectedBetweenNameAndColon: UnexpectedNodesSyntax? = nil,
36543654
colon: TokenSyntax? = nil,
@@ -3663,9 +3663,9 @@ extension GenericParameterSyntax {
36633663
leadingTrivia: leadingTrivia,
36643664
unexpectedBeforeAttributes,
36653665
attributes: attributes,
3666-
unexpectedBetweenAttributesAndEach,
3667-
eachKeyword: each,
3668-
unexpectedBetweenEachAndName,
3666+
unexpectedBetweenAttributesAndEachKeyword,
3667+
specifier: eachKeyword,
3668+
unexpectedBetweenEachKeywordAndName,
36693669
name: name,
36703670
unexpectedBetweenNameAndColon,
36713671
colon: colon,

Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift

+9-9
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

+1-1
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))

0 commit comments

Comments
 (0)