Skip to content

[6.0] Allow borrowing without underscore in pattern matches. #2600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CodeGeneration/Sources/SyntaxSupport/PatternNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ public let PATTERN_NODES: [Node] = [
kind: .token(choices: [
.keyword(.let), .keyword(.var), .keyword(.inout),
.keyword(._mutating), .keyword(._borrowing), .keyword(._consuming),
.keyword(.borrowing),
])
),
Child(
Expand Down
3 changes: 2 additions & 1 deletion Sources/SwiftParser/Patterns.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ extension Parser.Lookahead {
// TODO: the other ownership modifiers (borrowing/consuming/mutating) more
// than likely need to be made contextual as well before finalizing their
// grammar.
case ._borrowing where experimentalFeatures.contains(.borrowingSwitch):
case ._borrowing where experimentalFeatures.contains(.borrowingSwitch),
.borrowing where experimentalFeatures.contains(.borrowingSwitch):
return peek(isAt: TokenSpec(.identifier, allowAtStartOfLine: false))
default:
// Other keywords can be parsed unconditionally.
Expand Down
9 changes: 9 additions & 0 deletions Sources/SwiftParser/generated/Parser+TokenSpecSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3905,6 +3905,7 @@ extension ValueBindingPatternSyntax {
@_spi(ExperimentalLanguageFeatures)
#endif
case _consuming
case borrowing

init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
switch PrepareForKeywordMatch(lexeme) {
Expand All @@ -3920,6 +3921,8 @@ extension ValueBindingPatternSyntax {
self = ._borrowing
case TokenSpec(._consuming) where experimentalFeatures.contains(.referenceBindings):
self = ._consuming
case TokenSpec(.borrowing):
self = .borrowing
default:
return nil
}
Expand All @@ -3939,6 +3942,8 @@ extension ValueBindingPatternSyntax {
self = ._borrowing
case TokenSpec(._consuming):
self = ._consuming
case TokenSpec(.borrowing):
self = .borrowing
default:
return nil
}
Expand All @@ -3958,6 +3963,8 @@ extension ValueBindingPatternSyntax {
return .keyword(._borrowing)
case ._consuming:
return .keyword(._consuming)
case .borrowing:
return .keyword(.borrowing)
}
}

Expand All @@ -3979,6 +3986,8 @@ extension ValueBindingPatternSyntax {
return .keyword(._borrowing)
case ._consuming:
return .keyword(._consuming)
case .borrowing:
return .keyword(.borrowing)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2706,7 +2706,8 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
.keyword("inout"),
.keyword("_mutating"),
.keyword("_borrowing"),
.keyword("_consuming")
.keyword("_consuming"),
.keyword("borrowing")
]))
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
assertNoError(kind, 3, verify(layout[3], as: RawPatternSyntax.self))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3256,7 +3256,7 @@ public struct UnresolvedTernaryExprSyntax: ExprSyntaxProtocol, SyntaxHashable, _

/// ### Children
///
/// - `bindingSpecifier`: (`let` | `var` | `inout` | `_mutating` | `_borrowing` | `_consuming`)
/// - `bindingSpecifier`: (`let` | `var` | `inout` | `_mutating` | `_borrowing` | `_consuming` | `borrowing`)
/// - `pattern`: ``PatternSyntax``
public struct ValueBindingPatternSyntax: PatternSyntaxProtocol, SyntaxHashable, _LeafPatternSyntaxNodeProtocol {
public let _syntaxNode: Syntax
Expand Down Expand Up @@ -3327,6 +3327,7 @@ public struct ValueBindingPatternSyntax: PatternSyntaxProtocol, SyntaxHashable,
/// - `_mutating`
/// - `_borrowing`
/// - `_consuming`
/// - `borrowing`
public var bindingSpecifier: TokenSyntax {
get {
return Syntax(self).child(at: 1)!.cast(TokenSyntax.self)
Expand Down
45 changes: 21 additions & 24 deletions Tests/SwiftParserTest/translated/MatchingPatternsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -612,125 +612,122 @@ final class MatchingPatternsTests: ParserTestCase {
assertParse(
"""
switch 42 {
case _borrowing .foo(): // parses as `_borrowing.foo()` as before
case borrowing .foo(): // parses as `borrowing.foo()` as before
break
}
""",
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("_borrowing"))),
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("borrowing"))),
experimentalFeatures: .borrowingSwitch
)

assertParse(
"""
switch 42 {
case _borrowing (): // parses as `_borrowing()` as before
case borrowing (): // parses as `borrowing()` as before
break
}
""",
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("_borrowing"))),
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("borrowing"))),
experimentalFeatures: .borrowingSwitch
)

assertParse(
"""
switch 42 {
case _borrowing x: // parses as binding
case borrowing x: // parses as binding
break
}
""",
substructure: PatternSyntax(
ValueBindingPatternSyntax(
bindingSpecifier: .keyword(._borrowing),
bindingSpecifier: .keyword(.borrowing),
pattern: PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("x")))
)
),
experimentalFeatures: .borrowingSwitch
)
)

assertParse(
"""
switch bar {
case .payload(_borrowing x): // parses as binding
case .payload(borrowing x): // parses as binding
break
}
""",
substructure: PatternSyntax(
ValueBindingPatternSyntax(
bindingSpecifier: .keyword(._borrowing),
bindingSpecifier: .keyword(.borrowing),
pattern: PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("x")))
)
),
experimentalFeatures: .borrowingSwitch
)
)

assertParse(
"""
switch bar {
case _borrowing x.member: // parses as var introducer surrounding postfix expression (which never is valid)
case borrowing x.member: // parses as var introducer surrounding postfix expression (which never is valid)
break
}
""",
substructure: PatternSyntax(
ValueBindingPatternSyntax(
bindingSpecifier: .keyword(._borrowing),
bindingSpecifier: .keyword(.borrowing),
pattern: ExpressionPatternSyntax(
expression: MemberAccessExprSyntax(
base: DeclReferenceExprSyntax(baseName: .identifier("x")),
declName: DeclReferenceExprSyntax(baseName: .identifier("member"))
)
)
)
),
experimentalFeatures: .borrowingSwitch
)
)
assertParse(
"""
switch 42 {
case let _borrowing: // parses as let binding named '_borrowing'
case let borrowing: // parses as let binding named 'borrowing'
break
}
""",
substructure: PatternSyntax(
ValueBindingPatternSyntax(
bindingSpecifier: .keyword(.let),
pattern: PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("_borrowing")))
pattern: PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("borrowing")))
)
),
experimentalFeatures: .borrowingSwitch
)
assertParse(
"""
switch 42 {
case _borrowing + _borrowing: // parses as expr pattern
case borrowing + borrowing: // parses as expr pattern
break
}
""",
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("_borrowing"))),
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("borrowing"))),
experimentalFeatures: .borrowingSwitch
)
assertParse(
"""
switch 42 {
case _borrowing(let _borrowing): // parses as let binding named '_borrowing' inside a case pattern named 'borrowing'
case borrowing(let borrowing): // parses as let binding named 'borrowing' inside a case pattern named 'borrowing'
break
}
""",
substructure: PatternSyntax(
ValueBindingPatternSyntax(
bindingSpecifier: .keyword(.let),
pattern: PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("_borrowing")))
pattern: PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("borrowing")))
)
),
experimentalFeatures: .borrowingSwitch
)
assertParse(
"""
switch 42 {
case {}(_borrowing + _borrowing): // parses as expr pattern
case {}(borrowing + borrowing): // parses as expr pattern
break
}
""",
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("_borrowing"))),
substructure: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("borrowing"))),
Comment on lines -733 to +730
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to continue having tests for _borrowing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My hope is that the warning I added in swiftlang/swift#72996 will get the early adopters over the new syntax so I can clean up the temporary syntax in a follow up commit.

experimentalFeatures: .borrowingSwitch
)
}
Expand Down