Skip to content

Commit d856f48

Browse files
authored
Merge pull request #1167 from hborla/pack-expansion-syntax
[Variadic Generics] Change pack expansion types and expressions to use the `repeat` syntax.
2 parents f5f45e2 + 09dcf74 commit d856f48

26 files changed

+991
-434
lines changed

CodeGeneration/Sources/SyntaxSupport/gyb_generated/ExprNodes.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,19 @@ public let EXPR_NODES: [Node] = [
229229
])
230230
]),
231231

232+
Node(name: "PackExpansionExpr",
233+
nameForDiagnostics: nil,
234+
kind: "Expr",
235+
children: [
236+
Child(name: "RepeatKeyword",
237+
kind: "RepeatToken",
238+
tokenChoices: [
239+
"Repeat"
240+
]),
241+
Child(name: "PatternExpr",
242+
kind: "Expr")
243+
]),
244+
232245
Node(name: "PackElementExpr",
233246
nameForDiagnostics: nil,
234247
kind: "Expr",

CodeGeneration/Sources/SyntaxSupport/gyb_generated/TypeNodes.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,13 @@ public let TYPE_NODES: [Node] = [
206206
nameForDiagnostics: "variadic expansion",
207207
kind: "Type",
208208
children: [
209-
Child(name: "PatternType",
210-
kind: "Type"),
211-
Child(name: "Ellipsis",
212-
kind: "EllipsisToken",
209+
Child(name: "RepeatKeyword",
210+
kind: "RepeatToken",
213211
tokenChoices: [
214-
"Ellipsis"
215-
])
212+
"Repeat"
213+
]),
214+
Child(name: "PatternType",
215+
kind: "Type")
216216
]),
217217

218218
Node(name: "PackReferenceType",

Sources/SwiftParser/Expressions.swift

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ extension TokenConsumer {
3838
return true
3939
}
4040
}
41+
42+
// 'repeat' is the start of a pack expansion expression.
43+
if (self.at(.repeatKeyword)) {
44+
// FIXME: 'repeat' followed by '{' could still be a pack
45+
// expansion, but we need to do more lookahead to figure out
46+
// whether the '{' is the start of a closure expression or a
47+
// brace statement for 'repeat { ... } while'
48+
let backtrack = self.lookahead()
49+
return backtrack.peek().tokenKind != .leftBrace
50+
}
51+
4152
return false
4253
}
4354
}
@@ -501,6 +512,14 @@ extension Parser {
501512
) -> RawExprSyntax {
502513
// First check to see if we have the start of a regex literal `/.../`.
503514
// tryLexRegexLiteral(/*forUnappliedOperator*/ false)
515+
516+
// 'repeat' is the start of a pack expansion expression.
517+
if (self.at(.repeatKeyword)) {
518+
return RawExprSyntax(
519+
parsePackExpansionExpr(flavor, pattern: pattern)
520+
)
521+
}
522+
504523
switch self.at(anyIn: ExpressionPrefixOperator.self) {
505524
case (.prefixAmpersand, let handle)?:
506525
let amp = self.eat(handle)
@@ -1173,7 +1192,7 @@ extension Parser {
11731192
}
11741193

11751194
if let each = self.consumeIfContextualKeyword("each") {
1176-
let packRef = self.parseExpression()
1195+
let packRef = self.parseSequenceExpressionElement(flavor, pattern: pattern)
11771196
return RawExprSyntax(
11781197
RawPackElementExprSyntax(
11791198
eachKeyword: each,
@@ -1351,6 +1370,31 @@ extension Parser {
13511370
}
13521371
}
13531372

1373+
extension Parser {
1374+
/// Parse a pack expansion as an expression.
1375+
///
1376+
///
1377+
/// Grammar
1378+
/// =======
1379+
///
1380+
/// pack-expansion-expression → 'repeat' pattern-expression
1381+
/// pattern-expression → expression
1382+
@_spi(RawSyntax)
1383+
public mutating func parsePackExpansionExpr(
1384+
_ flavor: ExprFlavor,
1385+
pattern: PatternContext
1386+
) -> RawPackExpansionExprSyntax {
1387+
let repeatKeyword = self.consumeAnyToken()
1388+
let patternExpr = self.parseExpression(flavor, pattern: pattern)
1389+
1390+
return RawPackExpansionExprSyntax(
1391+
repeatKeyword: repeatKeyword,
1392+
patternExpr: patternExpr,
1393+
arena: self.arena
1394+
)
1395+
}
1396+
}
1397+
13541398
extension Parser {
13551399
/// Parse a string literal expression.
13561400
///

Sources/SwiftParser/Patterns.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ extension Parser.Lookahead {
373373
// If the next token can be an argument label, we might have a name.
374374
if nextTok.canBeArgumentLabel(allowDollarIdentifier: true) {
375375
// If the first name wasn't "isolated", we're done.
376-
if !self.atContextualKeyword("isolated") && !self.atContextualKeyword("some") && !self.atContextualKeyword("any") && !self.atContextualKeyword("each") {
376+
if !self.atContextualKeyword("isolated") && !self.atContextualKeyword("some") && !self.atContextualKeyword("any") && !self.atContextualKeyword("each") && !self.at(.repeatKeyword) {
377377
return true
378378
}
379379

Sources/SwiftParser/Statements.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,6 @@ extension Parser.Lookahead {
12521252
.guardKeyword?,
12531253
.whileKeyword?,
12541254
.doKeyword?,
1255-
.repeatKeyword?,
12561255
.forKeyword?,
12571256
.breakKeyword?,
12581257
.continueKeyword?,
@@ -1261,6 +1260,12 @@ extension Parser.Lookahead {
12611260
.yield?,
12621261
.poundAssertKeyword?:
12631262
return true
1263+
case .repeatKeyword?:
1264+
// 'repeat' followed by anything other than a brace stmt
1265+
// is a pack expansion expression.
1266+
// FIXME: 'repeat' followed by '{' could be a pack expansion
1267+
// with a closure pattern.
1268+
return self.peek().tokenKind == .leftBrace
12641269
case .yieldAsIdentifier?:
12651270
switch self.peek().tokenKind {
12661271
case .prefixAmpersand:

Sources/SwiftParser/Types.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,19 @@ extension Parser {
2525
/// type → opaque-type
2626
@_spi(RawSyntax)
2727
public mutating func parseType(misplacedSpecifiers: [RawTokenSyntax] = []) -> RawTypeSyntax {
28-
let type = self.parseTypeScalar(misplacedSpecifiers: misplacedSpecifiers)
29-
30-
// Parse pack expansion 'T...'.
31-
if self.currentToken.isEllipsis {
32-
let ellipsis = self.consumeAnyToken(remapping: .ellipsis)
28+
// Parse pack expansion 'repeat T'.
29+
if let repeatKeyword = self.consume(if: .repeatKeyword) {
30+
let type = self.parseTypeScalar(misplacedSpecifiers: misplacedSpecifiers)
3331
return RawTypeSyntax(
3432
RawPackExpansionTypeSyntax(
33+
repeatKeyword: repeatKeyword,
3534
patternType: type,
36-
ellipsis: ellipsis,
3735
arena: self.arena
3836
)
3937
)
4038
}
41-
return type
39+
40+
return self.parseTypeScalar(misplacedSpecifiers: misplacedSpecifiers)
4241
}
4342

4443
mutating func parseTypeScalar(misplacedSpecifiers: [RawTokenSyntax] = []) -> RawTypeSyntax {
@@ -677,6 +676,9 @@ extension Parser.Lookahead {
677676
}
678677

679678
mutating func canParseTypeScalar() -> Bool {
679+
// 'repeat' starts a pack expansion type
680+
self.consume(if: .repeatKeyword)
681+
680682
self.skipTypeAttributeList()
681683

682684
guard self.canParseSimpleOrCompositionType() else {
@@ -702,11 +704,7 @@ extension Parser.Lookahead {
702704
}
703705

704706
mutating func canParseSimpleOrCompositionType() -> Bool {
705-
if self.atContextualKeyword("each") {
706-
return self.canParseSimpleType();
707-
}
708-
709-
if self.atContextualKeyword("some") || self.atContextualKeyword("any") {
707+
if self.atContextualKeyword("some") || self.atContextualKeyword("any") || self.atContextualKeyword("each") {
710708
self.consumeAnyToken()
711709
}
712710

@@ -753,6 +751,8 @@ extension Parser.Lookahead {
753751
}
754752
case .wildcardKeyword:
755753
self.consumeAnyToken()
754+
case .repeatKeyword:
755+
return true
756756
default:
757757
return false
758758
}

Sources/SwiftSyntax/Documentation.docc/gyb_generated/SwiftSyntax.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ allows Swift tools to parse, inspect, generate, and transform Swift source code.
118118
- <doc:SwiftSyntax/NilLiteralExprSyntax>
119119
- <doc:SwiftSyntax/DiscardAssignmentExprSyntax>
120120
- <doc:SwiftSyntax/AssignmentExprSyntax>
121+
- <doc:SwiftSyntax/PackExpansionExprSyntax>
121122
- <doc:SwiftSyntax/PackElementExprSyntax>
122123
- <doc:SwiftSyntax/SequenceExprSyntax>
123124
- <doc:SwiftSyntax/SymbolicReferenceExprSyntax>

Sources/SwiftSyntax/Raw/gyb_generated/RawSyntaxNodes.swift

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public struct RawExprSyntax: RawExprSyntaxNodeProtocol {
6565

6666
public static func isKindOf(_ raw: RawSyntax) -> Bool {
6767
switch raw.kind {
68-
case .missingExpr, .inOutExpr, .poundColumnExpr, .tryExpr, .awaitExpr, .moveExpr, .borrowExpr, .identifierExpr, .superRefExpr, .nilLiteralExpr, .discardAssignmentExpr, .assignmentExpr, .packElementExpr, .sequenceExpr, .symbolicReferenceExpr, .prefixOperatorExpr, .binaryOperatorExpr, .arrowExpr, .infixOperatorExpr, .floatLiteralExpr, .tupleExpr, .arrayExpr, .dictionaryExpr, .integerLiteralExpr, .booleanLiteralExpr, .unresolvedTernaryExpr, .ternaryExpr, .memberAccessExpr, .unresolvedIsExpr, .isExpr, .unresolvedAsExpr, .asExpr, .typeExpr, .closureExpr, .unresolvedPatternExpr, .functionCallExpr, .subscriptExpr, .optionalChainingExpr, .forcedValueExpr, .postfixUnaryExpr, .specializeExpr, .stringLiteralExpr, .regexLiteralExpr, .keyPathExpr, .macroExpansionExpr, .postfixIfConfigExpr, .editorPlaceholderExpr: return true
68+
case .missingExpr, .inOutExpr, .poundColumnExpr, .tryExpr, .awaitExpr, .moveExpr, .borrowExpr, .identifierExpr, .superRefExpr, .nilLiteralExpr, .discardAssignmentExpr, .assignmentExpr, .packExpansionExpr, .packElementExpr, .sequenceExpr, .symbolicReferenceExpr, .prefixOperatorExpr, .binaryOperatorExpr, .arrowExpr, .infixOperatorExpr, .floatLiteralExpr, .tupleExpr, .arrayExpr, .dictionaryExpr, .integerLiteralExpr, .booleanLiteralExpr, .unresolvedTernaryExpr, .ternaryExpr, .memberAccessExpr, .unresolvedIsExpr, .isExpr, .unresolvedAsExpr, .asExpr, .typeExpr, .closureExpr, .unresolvedPatternExpr, .functionCallExpr, .subscriptExpr, .optionalChainingExpr, .forcedValueExpr, .postfixUnaryExpr, .specializeExpr, .stringLiteralExpr, .regexLiteralExpr, .keyPathExpr, .macroExpansionExpr, .postfixIfConfigExpr, .editorPlaceholderExpr: return true
6969
default: return false
7070
}
7171
}
@@ -1645,6 +1645,66 @@ public struct RawAssignmentExprSyntax: RawExprSyntaxNodeProtocol {
16451645
}
16461646
}
16471647

1648+
@_spi(RawSyntax)
1649+
public struct RawPackExpansionExprSyntax: RawExprSyntaxNodeProtocol {
1650+
1651+
@_spi(RawSyntax)
1652+
public var layoutView: RawSyntaxLayoutView {
1653+
return raw.layoutView!
1654+
}
1655+
1656+
public static func isKindOf(_ raw: RawSyntax) -> Bool {
1657+
return raw.kind == .packExpansionExpr
1658+
}
1659+
1660+
public var raw: RawSyntax
1661+
init(raw: RawSyntax) {
1662+
assert(Self.isKindOf(raw))
1663+
self.raw = raw
1664+
}
1665+
1666+
public init?<Node: RawSyntaxNodeProtocol>(_ other: Node) {
1667+
guard Self.isKindOf(other.raw) else { return nil }
1668+
self.init(raw: other.raw)
1669+
}
1670+
1671+
public init(
1672+
_ unexpectedBeforeRepeatKeyword: RawUnexpectedNodesSyntax? = nil,
1673+
repeatKeyword: RawTokenSyntax,
1674+
_ unexpectedBetweenRepeatKeywordAndPatternExpr: RawUnexpectedNodesSyntax? = nil,
1675+
patternExpr: RawExprSyntax,
1676+
_ unexpectedAfterPatternExpr: RawUnexpectedNodesSyntax? = nil,
1677+
arena: __shared SyntaxArena
1678+
) {
1679+
let raw = RawSyntax.makeLayout(
1680+
kind: .packExpansionExpr, uninitializedCount: 5, arena: arena) { layout in
1681+
layout.initialize(repeating: nil)
1682+
layout[0] = unexpectedBeforeRepeatKeyword?.raw
1683+
layout[1] = repeatKeyword.raw
1684+
layout[2] = unexpectedBetweenRepeatKeywordAndPatternExpr?.raw
1685+
layout[3] = patternExpr.raw
1686+
layout[4] = unexpectedAfterPatternExpr?.raw
1687+
}
1688+
self.init(raw: raw)
1689+
}
1690+
1691+
public var unexpectedBeforeRepeatKeyword: RawUnexpectedNodesSyntax? {
1692+
layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:))
1693+
}
1694+
public var repeatKeyword: RawTokenSyntax {
1695+
layoutView.children[1].map(RawTokenSyntax.init(raw:))!
1696+
}
1697+
public var unexpectedBetweenRepeatKeywordAndPatternExpr: RawUnexpectedNodesSyntax? {
1698+
layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:))
1699+
}
1700+
public var patternExpr: RawExprSyntax {
1701+
layoutView.children[3].map(RawExprSyntax.init(raw:))!
1702+
}
1703+
public var unexpectedAfterPatternExpr: RawUnexpectedNodesSyntax? {
1704+
layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:))
1705+
}
1706+
}
1707+
16481708
@_spi(RawSyntax)
16491709
public struct RawPackElementExprSyntax: RawExprSyntaxNodeProtocol {
16501710

@@ -16820,38 +16880,38 @@ public struct RawPackExpansionTypeSyntax: RawTypeSyntaxNodeProtocol {
1682016880
}
1682116881

1682216882
public init(
16823-
_ unexpectedBeforePatternType: RawUnexpectedNodesSyntax? = nil,
16883+
_ unexpectedBeforeRepeatKeyword: RawUnexpectedNodesSyntax? = nil,
16884+
repeatKeyword: RawTokenSyntax,
16885+
_ unexpectedBetweenRepeatKeywordAndPatternType: RawUnexpectedNodesSyntax? = nil,
1682416886
patternType: RawTypeSyntax,
16825-
_ unexpectedBetweenPatternTypeAndEllipsis: RawUnexpectedNodesSyntax? = nil,
16826-
ellipsis: RawTokenSyntax,
16827-
_ unexpectedAfterEllipsis: RawUnexpectedNodesSyntax? = nil,
16887+
_ unexpectedAfterPatternType: RawUnexpectedNodesSyntax? = nil,
1682816888
arena: __shared SyntaxArena
1682916889
) {
1683016890
let raw = RawSyntax.makeLayout(
1683116891
kind: .packExpansionType, uninitializedCount: 5, arena: arena) { layout in
1683216892
layout.initialize(repeating: nil)
16833-
layout[0] = unexpectedBeforePatternType?.raw
16834-
layout[1] = patternType.raw
16835-
layout[2] = unexpectedBetweenPatternTypeAndEllipsis?.raw
16836-
layout[3] = ellipsis.raw
16837-
layout[4] = unexpectedAfterEllipsis?.raw
16893+
layout[0] = unexpectedBeforeRepeatKeyword?.raw
16894+
layout[1] = repeatKeyword.raw
16895+
layout[2] = unexpectedBetweenRepeatKeywordAndPatternType?.raw
16896+
layout[3] = patternType.raw
16897+
layout[4] = unexpectedAfterPatternType?.raw
1683816898
}
1683916899
self.init(raw: raw)
1684016900
}
1684116901

16842-
public var unexpectedBeforePatternType: RawUnexpectedNodesSyntax? {
16902+
public var unexpectedBeforeRepeatKeyword: RawUnexpectedNodesSyntax? {
1684316903
layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:))
1684416904
}
16845-
public var patternType: RawTypeSyntax {
16846-
layoutView.children[1].map(RawTypeSyntax.init(raw:))!
16905+
public var repeatKeyword: RawTokenSyntax {
16906+
layoutView.children[1].map(RawTokenSyntax.init(raw:))!
1684716907
}
16848-
public var unexpectedBetweenPatternTypeAndEllipsis: RawUnexpectedNodesSyntax? {
16908+
public var unexpectedBetweenRepeatKeywordAndPatternType: RawUnexpectedNodesSyntax? {
1684916909
layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:))
1685016910
}
16851-
public var ellipsis: RawTokenSyntax {
16852-
layoutView.children[3].map(RawTokenSyntax.init(raw:))!
16911+
public var patternType: RawTypeSyntax {
16912+
layoutView.children[3].map(RawTypeSyntax.init(raw:))!
1685316913
}
16854-
public var unexpectedAfterEllipsis: RawUnexpectedNodesSyntax? {
16914+
public var unexpectedAfterPatternType: RawUnexpectedNodesSyntax? {
1685516915
layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:))
1685616916
}
1685716917
}

Sources/SwiftSyntax/Raw/gyb_generated/RawSyntaxValidation.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,14 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
272272
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self))
273273
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
274274
break
275+
case .packExpansionExpr:
276+
assert(layout.count == 5)
277+
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
278+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self))
279+
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
280+
assertNoError(kind, 3, verify(layout[3], as: RawExprSyntax.self))
281+
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
282+
break
275283
case .packElementExpr:
276284
assert(layout.count == 5)
277285
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
@@ -2449,9 +2457,9 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
24492457
case .packExpansionType:
24502458
assert(layout.count == 5)
24512459
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
2452-
assertNoError(kind, 1, verify(layout[1], as: RawTypeSyntax.self))
2460+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self))
24532461
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
2454-
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self))
2462+
assertNoError(kind, 3, verify(layout[3], as: RawTypeSyntax.self))
24552463
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
24562464
break
24572465
case .packReferenceType:

Sources/SwiftSyntax/generated/Misc.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ extension Syntax {
199199
.node(OptionalPatternSyntax.self),
200200
.node(OptionalTypeSyntax.self),
201201
.node(PackElementExprSyntax.self),
202+
.node(PackExpansionExprSyntax.self),
202203
.node(PackExpansionTypeSyntax.self),
203204
.node(PackReferenceTypeSyntax.self),
204205
.node(ParameterClauseSyntax.self),
@@ -651,6 +652,8 @@ extension SyntaxKind {
651652
return OptionalTypeSyntax.self
652653
case .packElementExpr:
653654
return PackElementExprSyntax.self
655+
case .packExpansionExpr:
656+
return PackExpansionExprSyntax.self
654657
case .packExpansionType:
655658
return PackExpansionTypeSyntax.self
656659
case .packReferenceType:
@@ -1186,6 +1189,8 @@ extension SyntaxKind {
11861189
return "optional type"
11871190
case .packElementExpr:
11881191
return nil
1192+
case .packExpansionExpr:
1193+
return nil
11891194
case .packExpansionType:
11901195
return "variadic expansion"
11911196
case .packReferenceType:

0 commit comments

Comments
 (0)