Skip to content

Commit 8eaab36

Browse files
authored
Merge pull request swiftlang#2763 from MAJKFL/closure-capture-syntax-node-update
Replace expression in `ClosureCaptureSyntax` with initializer clause
2 parents 19332a2 + e3f6436 commit 8eaab36

File tree

17 files changed

+341
-257
lines changed

17 files changed

+341
-257
lines changed

CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -341,19 +341,13 @@ public let EXPR_NODES: [Node] = [
341341
),
342342
Child(
343343
name: "name",
344-
kind: .token(choices: [.token(.identifier)]),
345-
isOptional: true
344+
kind: .token(choices: [.token(.identifier), .keyword(.self)])
346345
),
347346
Child(
348-
name: "equal",
349-
deprecatedName: "assignToken",
350-
kind: .token(choices: [.token(.equal)]),
347+
name: "initializer",
348+
kind: .node(kind: .initializerClause),
351349
isOptional: true
352350
),
353-
Child(
354-
name: "expression",
355-
kind: .node(kind: .expr)
356-
),
357351
Child(
358352
name: "trailingComma",
359353
kind: .token(choices: [.token(.comma)]),

CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,22 +482,22 @@ class ValidateSyntaxNodes: XCTestCase {
482482
ValidationFailure(
483483
node: .enumCaseElement,
484484
message:
485-
"child 'rawValue' is named inconsistently with 'MatchingPatternConditionSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
485+
"child 'rawValue' is named inconsistently with 'ClosureCaptureSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
486486
),
487487
ValidationFailure(
488488
node: .enumCaseParameter,
489489
message:
490-
"child 'defaultValue' is named inconsistently with 'MatchingPatternConditionSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
490+
"child 'defaultValue' is named inconsistently with 'ClosureCaptureSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
491491
),
492492
ValidationFailure(
493493
node: .functionParameter,
494494
message:
495-
"child 'defaultValue' is named inconsistently with 'MatchingPatternConditionSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
495+
"child 'defaultValue' is named inconsistently with 'ClosureCaptureSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
496496
),
497497
ValidationFailure(
498498
node: .macroDecl,
499499
message:
500-
"child 'definition' is named inconsistently with 'MatchingPatternConditionSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
500+
"child 'definition' is named inconsistently with 'ClosureCaptureSyntax.initializer', which has the same type ('InitializerClauseSyntax')"
501501
),
502502
// MARK: Miscellaneous
503503
ValidationFailure(

Release Notes/601.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,28 @@
3131
- Description: `IncrementalEdit` is being dropped for `SourceEdit`. `SourceEdit` has deprecated compatibility layers to make it API-compatible with `IncrementalEdit`
3232
- Issue: https://github.com/apple/swift-syntax/issues/2532
3333
- Pull request: https://github.com/apple/swift-syntax/pull/2604
34+
35+
- `ClosureCaptureSyntax.init(leadingTrivia:specifier:name:equal:expression:trailingComma:trailingTrivia:)` deprecated in favor of a new `ClosureCaptureSyntax.init(leadingTrivia:_:specifier:_:name:_:initializer:_:trailingComma:_:trailingTrivia:)` initializer.
36+
- Description: `ClosureCaptureSyntax` now has an `initializer` property instead of `equal` and `expression`. Additionally, the `name` property is no longer optional.
37+
- Pull request: https://github.com/swiftlang/swift-syntax/pull/2763
3438

3539
## API-Incompatible Changes
3640

3741
- Moved `Radix` and `IntegerLiteralExprSyntax.radix` from `SwiftRefactor` to `SwiftSyntax`.
3842
- Description: Allows retrieving the radix value from the `literal.text`.
3943
- Issue: https://github.com/apple/swift-syntax/issues/405
4044
- Pull Request: https://github.com/apple/swift-syntax/pull/2605
41-
45+
4246
- `FixIt.Change` gained a new case `replaceChild(data:)`.
4347
- Description: The new case covers the replacement of a child node with another node.
4448
- Issue: https://github.com/swiftlang/swift-syntax/issues/2205
4549
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2758
4650
- Migration steps: In exhaustive switches over `FixIt.Change`, cover the new case.
4751

52+
- `ClosureCaptureSyntax.name` is no longer optional.
53+
- Description: Due to the new `ClosureCaptureSyntax` node structure, `name` property is non-optional.
54+
- Pull request: https://github.com/swiftlang/swift-syntax/pull/2763
55+
4856
## Template
4957

5058
- *Affected API or two word description*

Sources/SwiftLexicalLookup/IdentifiableSyntax.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,7 @@ import SwiftSyntax
3333

3434
@_spi(Experimental) extension ClosureCaptureSyntax: IdentifiableSyntax {
3535
@_spi(Experimental) public var identifier: TokenSyntax {
36-
/* Doesn't work with closures like:
37-
_ = { [y=1+2] in
38-
print(y)
39-
}
40-
*/
41-
expression.as(DeclReferenceExprSyntax.self)!.baseName
36+
name
4237
}
4338
}
4439

Sources/SwiftParser/Expressions.swift

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,7 +1615,7 @@ extension Parser {
16151615
}
16161616

16171617
extension Parser {
1618-
mutating func parseDefaultArgument() -> RawInitializerClauseSyntax {
1618+
mutating func parseInitializerClause() -> RawInitializerClauseSyntax {
16191619
let unexpectedBeforeEq: RawUnexpectedNodesSyntax?
16201620
let eq: RawTokenSyntax
16211621
if let comparison = self.consumeIfContextualPunctuator("==") {
@@ -1704,29 +1704,22 @@ extension Parser {
17041704
let specifier = self.parseClosureCaptureSpecifiers()
17051705

17061706
// The thing being capture specified is an identifier, or as an identifier
1707-
// followed by an expression.
1708-
let unexpectedBeforeName: RawUnexpectedNodesSyntax?
1709-
let name: RawTokenSyntax?
1710-
let unexpectedBeforeEqual: RawUnexpectedNodesSyntax?
1711-
let equal: RawTokenSyntax?
1712-
let expression: RawExprSyntax
1713-
if self.peek(isAt: .equal) {
1714-
// The name is a new declaration.
1715-
(unexpectedBeforeName, name) = self.expect(
1716-
.identifier,
1717-
TokenSpec(.self, remapping: .identifier),
1718-
default: .identifier
1719-
)
1720-
(unexpectedBeforeEqual, equal) = self.expect(.equal)
1721-
expression = self.parseExpression(flavor: .basic, pattern: .none)
1707+
// followed by an initializer clause.
1708+
let (unexpectedBeforeName, name) = self.expect(
1709+
.identifier,
1710+
TokenSpec(.self),
1711+
default: .identifier
1712+
)
1713+
1714+
let initializer: RawInitializerClauseSyntax?
1715+
if self.at(.equal) {
1716+
// The name is a new declaration with
1717+
// initializer clause.
1718+
initializer = self.parseInitializerClause()
17221719
} else {
1723-
// This is the simple case - the identifier is both the name and
1724-
// the expression to capture.
1725-
unexpectedBeforeName = nil
1726-
name = nil
1727-
unexpectedBeforeEqual = nil
1728-
equal = nil
1729-
expression = RawExprSyntax(self.parseIdentifierExpression(flavor: .basic))
1720+
// This is the simple case - the identifier is the name and
1721+
// the initializer clause is empty.
1722+
initializer = nil
17301723
}
17311724

17321725
keepGoing = self.consume(if: .comma)
@@ -1735,11 +1728,9 @@ extension Parser {
17351728
specifier: specifier,
17361729
unexpectedBeforeName,
17371730
name: name,
1738-
unexpectedBeforeEqual,
1739-
equal: equal,
1740-
expression: expression,
1731+
initializer: initializer,
17411732
trailingComma: keepGoing,
1742-
arena: self.arena
1733+
arena: arena
17431734
)
17441735
)
17451736
} while keepGoing != nil && self.hasProgressed(&loopProgress)

Sources/SwiftParser/Parameters.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ extension Parser {
129129

130130
let defaultValue: RawInitializerClauseSyntax?
131131
if self.at(.equal) || self.atContextualPunctuator("==") {
132-
defaultValue = self.parseDefaultArgument()
132+
defaultValue = self.parseInitializerClause()
133133
} else {
134134
defaultValue = nil
135135
}
@@ -234,7 +234,7 @@ extension Parser {
234234

235235
let defaultValue: RawInitializerClauseSyntax?
236236
if self.at(.equal) || self.atContextualPunctuator("==") {
237-
defaultValue = self.parseDefaultArgument()
237+
defaultValue = self.parseInitializerClause()
238238
} else {
239239
defaultValue = nil
240240
}

Sources/SwiftParser/generated/Parser+TokenSpecSet.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,58 @@ extension ClosureCaptureSpecifierSyntax {
560560
}
561561
}
562562

563+
extension ClosureCaptureSyntax {
564+
@_spi(Diagnostics)
565+
public enum NameOptions: TokenSpecSet {
566+
case identifier
567+
case `self`
568+
569+
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
570+
switch PrepareForKeywordMatch(lexeme) {
571+
case TokenSpec(.identifier):
572+
self = .identifier
573+
case TokenSpec(.self):
574+
self = .self
575+
default:
576+
return nil
577+
}
578+
}
579+
580+
public init?(token: TokenSyntax) {
581+
switch token {
582+
case TokenSpec(.identifier):
583+
self = .identifier
584+
case TokenSpec(.self):
585+
self = .self
586+
default:
587+
return nil
588+
}
589+
}
590+
591+
var spec: TokenSpec {
592+
switch self {
593+
case .identifier:
594+
return .identifier
595+
case .self:
596+
return .keyword(.self)
597+
}
598+
}
599+
600+
/// Returns a token that satisfies the `TokenSpec` of this case.
601+
///
602+
/// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text.
603+
@_spi(Diagnostics)
604+
public var tokenSyntax: TokenSyntax {
605+
switch self {
606+
case .identifier:
607+
return .identifier("")
608+
case .self:
609+
return .keyword(.self)
610+
}
611+
}
612+
}
613+
}
614+
563615
extension ClosureParameterSyntax {
564616
@_spi(Diagnostics)
565617
public enum FirstNameOptions: TokenSpecSet {

Sources/SwiftSyntax/Convenience.swift

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
extension ClosureCaptureSyntax {
14-
15-
/// Creates a ``ClosureCaptureSyntax`` with a `name`, and automatically adds an `equal` token to it since the name is non-optional.
16-
///
17-
/// - SeeAlso: ``ClosureCaptureSyntax/init(leadingTrivia:_:specifier:_:name:_:equal:_:expression:_:trailingComma:_:trailingTrivia:)``.
18-
///
19-
public init(
20-
leadingTrivia: Trivia? = nil,
21-
specifier: ClosureCaptureSpecifierSyntax? = nil,
22-
name: TokenSyntax,
23-
equal: TokenSyntax = TokenSyntax.equalToken(),
24-
expression: some ExprSyntaxProtocol,
25-
trailingComma: TokenSyntax? = nil,
26-
trailingTrivia: Trivia? = nil
27-
) {
28-
self.init(
29-
leadingTrivia: leadingTrivia,
30-
specifier: specifier,
31-
name: name as TokenSyntax?,
32-
equal: equal,
33-
expression: expression,
34-
trailingComma: trailingComma,
35-
trailingTrivia: trailingTrivia
36-
)
37-
}
38-
}
39-
4013
extension EnumCaseParameterSyntax {
4114

4215
/// Creates an ``EnumCaseParameterSyntax`` with a `firstName`, and automatically adds a `colon` to it.

0 commit comments

Comments
 (0)