From 628a64c5f9eea0627665bcdc902a767e2f7dcc5e Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 17 May 2023 14:10:57 -0700 Subject: [PATCH 1/7] Rename AwaitTryMove -> ExpressionModifierKeyword at @ahoppen's request. --- Sources/SwiftParser/Expressions.swift | 2 +- Sources/SwiftParser/TokenSpecSet.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 62ae35b6084..96ea1d82f3d 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -413,7 +413,7 @@ extension Parser { } } - switch self.at(anyIn: AwaitTryMove.self) { + switch self.at(anyIn: ExpressionModifierKeyword.self) { case (.awaitKeyword, let handle)?: let awaitTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( diff --git a/Sources/SwiftParser/TokenSpecSet.swift b/Sources/SwiftParser/TokenSpecSet.swift index 82460f6ea16..4674a4fed96 100644 --- a/Sources/SwiftParser/TokenSpecSet.swift +++ b/Sources/SwiftParser/TokenSpecSet.swift @@ -476,7 +476,7 @@ public enum TypeSpecifier: TokenSpecSet { // MARK: Expression start -enum AwaitTryMove: TokenSpecSet { +enum ExpressionModifierKeyword: TokenSpecSet { case awaitKeyword case _moveKeyword case _borrowKeyword @@ -695,13 +695,13 @@ enum PrimaryExpressionStart: TokenSpecSet { /// - `MatchingPatternStart` /// - `PrimaryExpressionStart` enum ExpressionStart: TokenSpecSet { - case awaitTryMove(AwaitTryMove) + case awaitTryMove(ExpressionModifierKeyword) case expressionPrefixOperator(ExpressionPrefixOperator) case primaryExpressionStart(PrimaryExpressionStart) case ifOrSwitch(IfOrSwitch) init?(lexeme: Lexer.Lexeme) { - if let subset = AwaitTryMove(lexeme: lexeme) { + if let subset = ExpressionModifierKeyword(lexeme: lexeme) { self = .awaitTryMove(subset) } else if let subset = ExpressionPrefixOperator(lexeme: lexeme) { self = .expressionPrefixOperator(subset) @@ -715,7 +715,7 @@ enum ExpressionStart: TokenSpecSet { } static var allCases: [ExpressionStart] { - return AwaitTryMove.allCases.map(Self.awaitTryMove) + return ExpressionModifierKeyword.allCases.map(Self.awaitTryMove) + ExpressionPrefixOperator.allCases.map(Self.expressionPrefixOperator) + PrimaryExpressionStart.allCases.map(Self.primaryExpressionStart) + IfOrSwitch.allCases.map(Self.ifOrSwitch) From 895977a5ea2e4e851f0205ca4fdc850ff5c9be6b Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 15 May 2023 17:41:18 -0700 Subject: [PATCH 2/7] [copy-operator] Add parsing support for copy operator. I followed the same model that we used for consume, namely we need an identifier to copy. This ensures that if we have a function called copy or a variable called copy, we do not break source stability. rdar://101862423 --- .../Sources/SyntaxSupport/ExprNodes.swift | 16 ++ .../Sources/SyntaxSupport/KeywordSpec.swift | 1 + Sources/SwiftParser/Expressions.swift | 37 +++- Sources/SwiftParser/TokenSpecSet.swift | 3 + .../translated/CopyExprTests.swift | 182 ++++++++++++++++++ 5 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 Tests/SwiftParserTest/translated/CopyExprTests.swift diff --git a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift index 2f3ae245ae7..3211263877a 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift @@ -1204,6 +1204,22 @@ public let EXPR_NODES: [Node] = [ ] ), + Node( + name: "CopyExpr", + nameForDiagnostics: "'copy' expression", + kind: "Expr", + children: [ + Child( + name: "CopyKeyword", + kind: .token(choices: [.keyword(text: "copy")]) + ), + Child( + name: "Expression", + kind: .node(kind: "Expr") + ), + ] + ), + Node( name: "MultipleTrailingClosureElementList", nameForDiagnostics: nil, diff --git a/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift b/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift index 61944d83cbd..7263fdc8e03 100644 --- a/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift +++ b/CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift @@ -110,6 +110,7 @@ public let KEYWORDS: [KeywordSpec] = [ KeywordSpec("class", isLexerClassified: true, requiresTrailingSpace: true), KeywordSpec("compiler"), KeywordSpec("consume"), + KeywordSpec("copy"), KeywordSpec("consuming"), KeywordSpec("continue", isLexerClassified: true, requiresTrailingSpace: true), KeywordSpec("convenience"), diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 96ea1d82f3d..f3a7342683d 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -413,7 +413,7 @@ extension Parser { } } - switch self.at(anyIn: ExpressionModifierKeyword.self) { + EXPR_PREFIX: switch self.at(anyIn: ExpressionModifierKeyword.self) { case (.awaitKeyword, let handle)?: let awaitTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( @@ -474,18 +474,46 @@ extension Parser { ) ) + case (.copyKeyword, let handle)?: + // `copy` is only contextually a keyword, if it's followed by an + // identifier or keyword on the same line. We do this to ensure that we do + // not break any copy functions defined by users. This is following with + // what we have done for the consume keyword. + switch self.peek() { + case TokenSpec(.identifier, allowAtStartOfLine: false), + TokenSpec(.dollarIdentifier, allowAtStartOfLine: false), + TokenSpec(.self, allowAtStartOfLine: false): + break + default: + break EXPR_PREFIX // Break out of `outer switch` on failure. + } + + let copyTok = self.eat(handle) + let sub = self.parseSequenceExpressionElement( + flavor, + forDirective: forDirective, + pattern: pattern + ) + return RawExprSyntax( + RawCopyExprSyntax( + copyKeyword: copyTok, + expression: sub, + arena: self.arena + ) + ) + case (.consumeKeyword, let handle)?: // `consume` is only contextually a keyword, if it's followed by an // identifier or keyword on the same line. let next = peek() if next.isAtStartOfLine { - fallthrough + break } if next.rawTokenKind != .identifier, next.rawTokenKind != .dollarIdentifier, next.rawTokenKind != .keyword { - fallthrough + break } let consumeTok = self.eat(handle) @@ -502,8 +530,9 @@ extension Parser { ) ) case nil: - return self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern) + break } + return self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern) } /// Parse an optional prefix operator followed by an expression. diff --git a/Sources/SwiftParser/TokenSpecSet.swift b/Sources/SwiftParser/TokenSpecSet.swift index 4674a4fed96..32cf7beff73 100644 --- a/Sources/SwiftParser/TokenSpecSet.swift +++ b/Sources/SwiftParser/TokenSpecSet.swift @@ -482,6 +482,7 @@ enum ExpressionModifierKeyword: TokenSpecSet { case _borrowKeyword case tryKeyword case consumeKeyword + case copyKeyword init?(lexeme: Lexer.Lexeme) { switch PrepareForKeywordMatch(lexeme) { @@ -490,6 +491,7 @@ enum ExpressionModifierKeyword: TokenSpecSet { case TokenSpec(._borrow): self = ._borrowKeyword case TokenSpec(.try): self = .tryKeyword case TokenSpec(.consume): self = .consumeKeyword + case TokenSpec(.copy): self = .copyKeyword default: return nil } } @@ -500,6 +502,7 @@ enum ExpressionModifierKeyword: TokenSpecSet { case ._moveKeyword: return .keyword(._move) case ._borrowKeyword: return .keyword(._borrow) case .consumeKeyword: return .keyword(.consume) + case .copyKeyword: return .keyword(.copy) case .tryKeyword: return .keyword(.try) } } diff --git a/Tests/SwiftParserTest/translated/CopyExprTests.swift b/Tests/SwiftParserTest/translated/CopyExprTests.swift new file mode 100644 index 00000000000..dbee930eebf --- /dev/null +++ b/Tests/SwiftParserTest/translated/CopyExprTests.swift @@ -0,0 +1,182 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// This test file has been translated from swift/test/Parse/copy_expr.swift + +import XCTest + +final class CopyExprTests: XCTestCase { + func testGlobal() { + assertParse( + """ + var global: Int = 5 + func testGlobal() { + let _ = copy global + } + """ + ) + } + + func testLet() { + assertParse( + """ + func testLet() { + let t = String() + let _ = copy t + } + """ + ) + } + + func testVar() { + assertParse( + """ + func testVar() { + var t = String() + t = String() + let _ = copy t + } + """ + ) + } + + func testStillAbleToCallFunctionCalledCopy() { + assertParse( + """ + func copy() {} + func copy(_: String) {} + func copy(_: String, _: Int) {} + func copy(x: String, y: Int) {} + + func useCopyFunc() { + var s = String() + var i = global + + copy() + copy(s) + copy(i) // expected-error{{cannot convert value of type 'Int' to expected argument type 'String'}} + copy(s, i) + copy(i, s) // expected-error{{unnamed argument #2 must precede unnamed argument #1}} + copy(x: s, y: i) + copy(y: i, x: s) // expected-error{{argument 'x' must precede argument 'y'}} + } + """ + ) + } + + // Ensure we can still parse a variable named copy. + func testUseCopyVariable() { + assertParse( + """ + func useCopyVar(copy: inout String) { + let s = copy + copy = s + + // We can copy from a variable named `copy` + let t = copy copy + copy = t + + // We can do member access and subscript a variable named `copy` + let i = copy.startIndex + let _ = copy[i] + } + """ + ) + } + + func testPropertyWrapperWithCopy() { + assertParse( + """ + @propertyWrapper + struct FooWrapper { + var value: T + + init(wrappedValue: T) { value = wrappedValue } + + var wrappedValue: T { + get { value } + nonmutating set {} + } + var projectedValue: T { + get { value } + nonmutating set {} + } + } + + struct Foo { + @FooWrapper var wrapperTest: String + + func copySelf() { + _ = copy self + } + + func copyPropertyWrapper() { + // should still parse, even if it doesn't semantically work out + _ = copy wrapperTest // expected-error{{can only be applied to lvalues}} + _ = copy _wrapperTest // expected-error{{can only be applied to lvalues}} + _ = copy $wrapperTest // expected-error{{can only be applied to lvalues}} + } + } + """ + ) + } + + func testAsCaseStmt() { + assertParse( + """ + class ParentKlass {} + class SubKlass : ParentKlass {} + + func test(_ s: SubKlass) { + switch s { + case let copy as ParentKlass: + fallthrough + } + } + """ + ) + } + + func testParseCanCopyClosureDollarIdentifier() { + assertParse( + """ + class Klass {} + let f: (Klass) -> () = { + let _ = copy $0 + } + """ + ) + } + + func testForLoop() { + assertParse( + """ + func test() { + for copy in 1..<1024 { + } + } + """ + ) + } + + func testCopySelf() { + assertParse( + """ + class Klass { + func test() { + let _ = copy self + } + } + """ + ) + } +} From 379058fcdb94bb5a64d25a38e708499c6e1bb123 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 15 May 2023 17:57:31 -0700 Subject: [PATCH 3/7] Generated code for copy expr. --- .../SyntaxKindNameForDiagnostics.swift | 2 + .../generated/SwiftSyntax.md | 1 + .../generated/ChildNameForKeyPath.swift | 10 ++ Sources/SwiftSyntax/generated/Keyword.swift | 4 + .../generated/SyntaxAnyVisitor.swift | 8 ++ .../generated/SyntaxBaseNodes.swift | 6 +- .../SwiftSyntax/generated/SyntaxEnum.swift | 3 + .../SwiftSyntax/generated/SyntaxKind.swift | 3 + .../generated/SyntaxRewriter.swift | 25 ++++ .../generated/SyntaxTransform.swift | 14 +++ .../SwiftSyntax/generated/SyntaxVisitor.swift | 25 ++++ .../generated/raw/RawSyntaxNodes.swift | 72 ++++++++++- .../generated/raw/RawSyntaxValidation.swift | 7 ++ .../syntaxNodes/SyntaxExprNodes.swift | 116 ++++++++++++++++++ 14 files changed, 293 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index cd525cbaa7a..a2103ab77aa 100644 --- a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift @@ -109,6 +109,8 @@ extension SyntaxKind { return "@convention(...) arguments" case .conventionWitnessMethodAttributeArguments: return "@convention(...) arguments for witness methods" + case .copyExpr: + return "'copy' expression" case .declModifier: return "modifier" case .declName: diff --git a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md index a05f4d4bbd0..c9dbd06736e 100644 --- a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md +++ b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md @@ -96,6 +96,7 @@ allows Swift tools to parse, inspect, generate, and transform Swift source code. - - - +- - - - diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index f6b3c528944..b36398ffb06 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -787,6 +787,16 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "protocolName" case \ConventionWitnessMethodAttributeArgumentsSyntax.unexpectedAfterProtocolName: return "unexpectedAfterProtocolName" + case \CopyExprSyntax.unexpectedBeforeCopyKeyword: + return "unexpectedBeforeCopyKeyword" + case \CopyExprSyntax.copyKeyword: + return "copyKeyword" + case \CopyExprSyntax.unexpectedBetweenCopyKeywordAndExpression: + return "unexpectedBetweenCopyKeywordAndExpression" + case \CopyExprSyntax.expression: + return "expression" + case \CopyExprSyntax.unexpectedAfterExpression: + return "unexpectedAfterExpression" case \DeclModifierDetailSyntax.unexpectedBeforeLeftParen: return "unexpectedBeforeLeftParen" case \DeclModifierDetailSyntax.leftParen: diff --git a/Sources/SwiftSyntax/generated/Keyword.swift b/Sources/SwiftSyntax/generated/Keyword.swift index 8850df97b64..c0b6d85f1a5 100644 --- a/Sources/SwiftSyntax/generated/Keyword.swift +++ b/Sources/SwiftSyntax/generated/Keyword.swift @@ -86,6 +86,7 @@ public enum Keyword: UInt8, Hashable { case `class` case compiler case consume + case copy case consuming case `continue` case convenience @@ -268,6 +269,8 @@ public enum Keyword: UInt8, Hashable { self = ._spi case "case": self = .`case` + case "copy": + self = .copy case "each": self = .each case "else": @@ -826,6 +829,7 @@ public enum Keyword: UInt8, Hashable { "class", "compiler", "consume", + "copy", "consuming", "continue", "convenience", diff --git a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift index 26bc197d0f6..c99e9a84d82 100644 --- a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift @@ -573,6 +573,14 @@ open class SyntaxAnyVisitor: SyntaxVisitor { visitAnyPost(node._syntaxNode) } + override open func visit(_ node: CopyExprSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + override open func visitPost(_ node: CopyExprSyntax) { + visitAnyPost(node._syntaxNode) + } + override open func visit(_ node: DeclModifierDetailSyntax) -> SyntaxVisitorContinueKind { return visitAny(node._syntaxNode) } diff --git a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift index 41f00c3c629..678b4008615 100644 --- a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift +++ b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift @@ -206,7 +206,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { public init?(_ node: some SyntaxProtocol) { switch node.raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forcedValueExpr, .functionCallExpr, .identifierExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .moveExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .postfixIfConfigExpr, .postfixUnaryExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .specializeExpr, .stringLiteralExpr, .subscriptExpr, .superRefExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedPatternExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .copyExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forcedValueExpr, .functionCallExpr, .identifierExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .moveExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .postfixIfConfigExpr, .postfixUnaryExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .specializeExpr, .stringLiteralExpr, .subscriptExpr, .superRefExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedPatternExpr, .unresolvedTernaryExpr: self._syntaxNode = node._syntaxNode default: return nil @@ -218,7 +218,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { /// is undefined. internal init(_ data: SyntaxData) { switch data.raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forcedValueExpr, .functionCallExpr, .identifierExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .moveExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .postfixIfConfigExpr, .postfixUnaryExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .specializeExpr, .stringLiteralExpr, .subscriptExpr, .superRefExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedPatternExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .copyExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forcedValueExpr, .functionCallExpr, .identifierExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .moveExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .postfixIfConfigExpr, .postfixUnaryExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .specializeExpr, .stringLiteralExpr, .subscriptExpr, .superRefExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedPatternExpr, .unresolvedTernaryExpr: break default: preconditionFailure("Unable to create ExprSyntax from \(data.raw.kind)") @@ -265,6 +265,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { .node(CanImportExprSyntax.self), .node(CanImportVersionInfoSyntax.self), .node(ClosureExprSyntax.self), + .node(CopyExprSyntax.self), .node(DictionaryExprSyntax.self), .node(DiscardAssignmentExprSyntax.self), .node(EditorPlaceholderExprSyntax.self), @@ -751,6 +752,7 @@ extension Syntax { .node(ContinueStmtSyntax.self), .node(ConventionAttributeArgumentsSyntax.self), .node(ConventionWitnessMethodAttributeArgumentsSyntax.self), + .node(CopyExprSyntax.self), .node(DeclModifierDetailSyntax.self), .node(DeclModifierSyntax.self), .node(DeclNameArgumentListSyntax.self), diff --git a/Sources/SwiftSyntax/generated/SyntaxEnum.swift b/Sources/SwiftSyntax/generated/SyntaxEnum.swift index e4e14f88b1a..dfa61a4a617 100644 --- a/Sources/SwiftSyntax/generated/SyntaxEnum.swift +++ b/Sources/SwiftSyntax/generated/SyntaxEnum.swift @@ -80,6 +80,7 @@ public enum SyntaxEnum { case continueStmt(ContinueStmtSyntax) case conventionAttributeArguments(ConventionAttributeArgumentsSyntax) case conventionWitnessMethodAttributeArguments(ConventionWitnessMethodAttributeArgumentsSyntax) + case copyExpr(CopyExprSyntax) case declModifierDetail(DeclModifierDetailSyntax) case declModifier(DeclModifierSyntax) case declNameArgumentList(DeclNameArgumentListSyntax) @@ -426,6 +427,8 @@ public extension Syntax { return .conventionAttributeArguments(ConventionAttributeArgumentsSyntax(self)!) case .conventionWitnessMethodAttributeArguments: return .conventionWitnessMethodAttributeArguments(ConventionWitnessMethodAttributeArgumentsSyntax(self)!) + case .copyExpr: + return .copyExpr(CopyExprSyntax(self)!) case .declModifierDetail: return .declModifierDetail(DeclModifierDetailSyntax(self)!) case .declModifier: diff --git a/Sources/SwiftSyntax/generated/SyntaxKind.swift b/Sources/SwiftSyntax/generated/SyntaxKind.swift index c231d4b7a48..f9bee40132d 100644 --- a/Sources/SwiftSyntax/generated/SyntaxKind.swift +++ b/Sources/SwiftSyntax/generated/SyntaxKind.swift @@ -80,6 +80,7 @@ public enum SyntaxKind { case continueStmt case conventionAttributeArguments case conventionWitnessMethodAttributeArguments + case copyExpr case declModifierDetail case declModifier case declNameArgumentList @@ -543,6 +544,8 @@ public enum SyntaxKind { return ConventionAttributeArgumentsSyntax.self case .conventionWitnessMethodAttributeArguments: return ConventionWitnessMethodAttributeArgumentsSyntax.self + case .copyExpr: + return CopyExprSyntax.self case .declModifierDetail: return DeclModifierDetailSyntax.self case .declModifier: diff --git a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift index 1a64ce6d402..acaeb408747 100644 --- a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift +++ b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift @@ -480,6 +480,13 @@ open class SyntaxRewriter { return Syntax(visitChildren(node)).cast(ConventionWitnessMethodAttributeArgumentsSyntax.self) } + /// Visit a `CopyExprSyntax`. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + open func visit(_ node: CopyExprSyntax) -> ExprSyntax { + return ExprSyntax(visitChildren(node)) + } + /// Visit a `DeclModifierDetailSyntax`. /// - Parameter node: the node that is being visited /// - Returns: the rewritten node @@ -2920,6 +2927,20 @@ open class SyntaxRewriter { return Syntax(visit(node)) } + /// Implementation detail of visit(_:). Do not call directly. + private func visitImplCopyExprSyntax(_ data: SyntaxData) -> Syntax { + let node = CopyExprSyntax(data) + // Accessing _syntaxNode directly is faster than calling Syntax(node) + visitPre(node._syntaxNode) + defer { + visitPost(node._syntaxNode) + } + if let newNode = visitAny(node._syntaxNode) { + return newNode + } + return Syntax(visit(node)) + } + /// Implementation detail of visit(_:). Do not call directly. private func visitImplDeclModifierDetailSyntax(_ data: SyntaxData) -> Syntax { let node = DeclModifierDetailSyntax(data) @@ -6004,6 +6025,8 @@ open class SyntaxRewriter { return visitImplConventionAttributeArgumentsSyntax case .conventionWitnessMethodAttributeArguments: return visitImplConventionWitnessMethodAttributeArgumentsSyntax + case .copyExpr: + return visitImplCopyExprSyntax case .declModifierDetail: return visitImplDeclModifierDetailSyntax case .declModifier: @@ -6560,6 +6583,8 @@ open class SyntaxRewriter { return visitImplConventionAttributeArgumentsSyntax(data) case .conventionWitnessMethodAttributeArguments: return visitImplConventionWitnessMethodAttributeArgumentsSyntax(data) + case .copyExpr: + return visitImplCopyExprSyntax(data) case .declModifierDetail: return visitImplDeclModifierDetailSyntax(data) case .declModifier: diff --git a/Sources/SwiftSyntax/generated/SyntaxTransform.swift b/Sources/SwiftSyntax/generated/SyntaxTransform.swift index a25e6d24156..a54ca1c679c 100644 --- a/Sources/SwiftSyntax/generated/SyntaxTransform.swift +++ b/Sources/SwiftSyntax/generated/SyntaxTransform.swift @@ -344,6 +344,11 @@ public protocol SyntaxTransformVisitor { /// - Returns: the sum of whatever the child visitors return. func visit(_ node: ConventionWitnessMethodAttributeArgumentsSyntax) -> ResultType + /// Visiting `CopyExprSyntax` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: the sum of whatever the child visitors return. + func visit(_ node: CopyExprSyntax) -> ResultType + /// Visiting `DeclModifierDetailSyntax` specifically. /// - Parameter node: the node we are visiting. /// - Returns: the sum of whatever the child visitors return. @@ -1845,6 +1850,13 @@ extension SyntaxTransformVisitor { visitAny(Syntax(node)) } + /// Visiting `CopyExprSyntax` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: nil by default. + public func visit(_ node: CopyExprSyntax) -> ResultType { + visitAny(Syntax(node)) + } + /// Visiting `DeclModifierDetailSyntax` specifically. /// - Parameter node: the node we are visiting. /// - Returns: nil by default. @@ -3435,6 +3447,8 @@ extension SyntaxTransformVisitor { return visit(derived) case .conventionWitnessMethodAttributeArguments(let derived): return visit(derived) + case .copyExpr(let derived): + return visit(derived) case .declModifierDetail(let derived): return visit(derived) case .declModifier(let derived): diff --git a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift index 81235127efc..8d00a1b2d84 100644 --- a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift @@ -814,6 +814,18 @@ open class SyntaxVisitor { open func visitPost(_ node: ConventionWitnessMethodAttributeArgumentsSyntax) { } + /// Visiting `CopyExprSyntax` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + open func visit(_ node: CopyExprSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting `CopyExprSyntax` and its descendents. + /// - node: the node we just finished visiting. + open func visitPost(_ node: CopyExprSyntax) { + } + /// Visiting `DeclModifierDetailSyntax` specifically. /// - Parameter node: the node we are visiting. /// - Returns: how should we continue visiting. @@ -4037,6 +4049,17 @@ open class SyntaxVisitor { visitPost(node) } + /// Implementation detail of doVisit(_:_:). Do not call directly. + private func visitImplCopyExprSyntax(_ data: SyntaxData) { + let node = CopyExprSyntax(data) + let needsChildren = (visit(node) == .visitChildren) + // Avoid calling into visitChildren if possible. + if needsChildren && !node.raw.layoutView!.children.isEmpty { + visitChildren(node) + } + visitPost(node) + } + /// Implementation detail of doVisit(_:_:). Do not call directly. private func visitImplDeclModifierDetailSyntax(_ data: SyntaxData) { let node = DeclModifierDetailSyntax(data) @@ -6462,6 +6485,8 @@ open class SyntaxVisitor { visitImplConventionAttributeArgumentsSyntax(data) case .conventionWitnessMethodAttributeArguments: visitImplConventionWitnessMethodAttributeArgumentsSyntax(data) + case .copyExpr: + visitImplCopyExprSyntax(data) case .declModifierDetail: visitImplDeclModifierDetailSyntax(data) case .declModifier: diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift index 176747a612b..b3d0f3cd215 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift @@ -5441,6 +5441,76 @@ public struct RawConventionWitnessMethodAttributeArgumentsSyntax: RawSyntaxNodeP } } +@_spi(RawSyntax) +public struct RawCopyExprSyntax: RawExprSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .copyExpr + } + + public var raw: RawSyntax + + init(raw: RawSyntax) { + precondition(Self.isKindOf(raw)) + self.raw = raw + } + + private init(unchecked raw: RawSyntax) { + self.raw = raw + } + + public init?(_ other: some RawSyntaxNodeProtocol) { + guard Self.isKindOf(other.raw) else { + return nil + } + self.init(unchecked: other.raw) + } + + public init( + _ unexpectedBeforeCopyKeyword: RawUnexpectedNodesSyntax? = nil, + copyKeyword: RawTokenSyntax, + _ unexpectedBetweenCopyKeywordAndExpression: RawUnexpectedNodesSyntax? = nil, + expression: RawExprSyntax, + _ unexpectedAfterExpression: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { + let raw = RawSyntax.makeLayout( + kind: .copyExpr, uninitializedCount: 5, arena: arena) { layout in + layout.initialize(repeating: nil) + layout[0] = unexpectedBeforeCopyKeyword?.raw + layout[1] = copyKeyword.raw + layout[2] = unexpectedBetweenCopyKeywordAndExpression?.raw + layout[3] = expression.raw + layout[4] = unexpectedAfterExpression?.raw + } + self.init(unchecked: raw) + } + + public var unexpectedBeforeCopyKeyword: RawUnexpectedNodesSyntax? { + layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var copyKeyword: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedBetweenCopyKeywordAndExpression: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var expression: RawExprSyntax { + layoutView.children[3].map(RawExprSyntax.init(raw:))! + } + + public var unexpectedAfterExpression: RawUnexpectedNodesSyntax? { + layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) + } +} + @_spi(RawSyntax) public struct RawDeclModifierDetailSyntax: RawSyntaxNodeProtocol { @_spi(RawSyntax) @@ -8515,7 +8585,7 @@ public struct RawExprSyntax: RawExprSyntaxNodeProtocol { public static func isKindOf(_ raw: RawSyntax) -> Bool { switch raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forcedValueExpr, .functionCallExpr, .identifierExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .moveExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .postfixIfConfigExpr, .postfixUnaryExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .specializeExpr, .stringLiteralExpr, .subscriptExpr, .superRefExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedPatternExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .copyExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forcedValueExpr, .functionCallExpr, .identifierExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .moveExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .postfixIfConfigExpr, .postfixUnaryExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .specializeExpr, .stringLiteralExpr, .subscriptExpr, .superRefExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedPatternExpr, .unresolvedTernaryExpr: return true default: return false diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index 6ba7ae1ff09..abb33872e7a 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -783,6 +783,13 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) + case .copyExpr: + assert(layout.count == 5) + assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.keyword("copy")])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 3, verify(layout[3], as: RawExprSyntax.self)) + assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) case .declModifierDetail: assert(layout.count == 7) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift index e581eac3c6e..835d5a85adc 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift @@ -1472,6 +1472,122 @@ public struct ClosureExprSyntax: ExprSyntaxProtocol, SyntaxHashable { } } +// MARK: - CopyExprSyntax + + +public struct CopyExprSyntax: ExprSyntaxProtocol, SyntaxHashable { + public let _syntaxNode: Syntax + + public init?(_ node: some SyntaxProtocol) { + guard node.raw.kind == .copyExpr else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + /// Creates a `CopyExprSyntax` node from the given `SyntaxData`. This assumes + /// that the `SyntaxData` is of the correct kind. If it is not, the behaviour + /// is undefined. + internal init(_ data: SyntaxData) { + precondition(data.raw.kind == .copyExpr) + self._syntaxNode = Syntax(data) + } + + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeCopyKeyword: UnexpectedNodesSyntax? = nil, + copyKeyword: TokenSyntax = .keyword(.copy), + _ unexpectedBetweenCopyKeywordAndExpression: UnexpectedNodesSyntax? = nil, + expression: some ExprSyntaxProtocol, + _ unexpectedAfterExpression: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + + ) { + // Extend the lifetime of all parameters so their arenas don't get destroyed + // before they can be added as children of the new arena. + let data: SyntaxData = withExtendedLifetime((SyntaxArena(), ( + unexpectedBeforeCopyKeyword, + copyKeyword, + unexpectedBetweenCopyKeywordAndExpression, + expression, + unexpectedAfterExpression + ))) {(arena, _) in + let layout: [RawSyntax?] = [ + unexpectedBeforeCopyKeyword?.raw, + copyKeyword.raw, + unexpectedBetweenCopyKeywordAndExpression?.raw, + expression.raw, + unexpectedAfterExpression?.raw + ] + let raw = RawSyntax.makeLayout( + kind: SyntaxKind.copyExpr, + from: layout, + arena: arena, + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia + + ) + return SyntaxData.forRoot(raw) + } + self.init(data) + } + + public var unexpectedBeforeCopyKeyword: UnexpectedNodesSyntax? { + get { + return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = CopyExprSyntax(data.replacingChild(at: 0, with: value?.raw, arena: SyntaxArena())) + } + } + + public var copyKeyword: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = CopyExprSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedBetweenCopyKeywordAndExpression: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = CopyExprSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + + public var expression: ExprSyntax { + get { + return ExprSyntax(data.child(at: 3, parent: Syntax(self))!) + } + set(value) { + self = CopyExprSyntax(data.replacingChild(at: 3, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterExpression: UnexpectedNodesSyntax? { + get { + return data.child(at: 4, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = CopyExprSyntax(data.replacingChild(at: 4, with: value?.raw, arena: SyntaxArena())) + } + } + + public static var structure: SyntaxNodeStructure { + return .layout([ + \Self.unexpectedBeforeCopyKeyword, + \Self.copyKeyword, + \Self.unexpectedBetweenCopyKeywordAndExpression, + \Self.expression, + \Self.unexpectedAfterExpression + ]) + } +} + // MARK: - DictionaryExprSyntax From 4e2633d38028ca210e1f4a7349afe9af23e47c4a Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 17 May 2023 13:37:21 -0700 Subject: [PATCH 4/7] [consume-operator] Fix diagnostics so we say consume operator instead of move operator and add consume tests. rdar://109413392 --- .../Sources/SyntaxSupport/ExprNodes.swift | 2 +- .../translated/MoveExprTests.swift | 36 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift index 3211263877a..b2cdcdb327f 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift @@ -1190,7 +1190,7 @@ public let EXPR_NODES: [Node] = [ // The move expr Node( name: "MoveExpr", - nameForDiagnostics: "'_move' expression", + nameForDiagnostics: "'consume' expression", kind: "Expr", children: [ Child( diff --git a/Tests/SwiftParserTest/translated/MoveExprTests.swift b/Tests/SwiftParserTest/translated/MoveExprTests.swift index 081a970ff1b..cd011e4fefb 100644 --- a/Tests/SwiftParserTest/translated/MoveExprTests.swift +++ b/Tests/SwiftParserTest/translated/MoveExprTests.swift @@ -49,4 +49,38 @@ final class MoveExprTests: XCTestCase { ) } -} + func testConsumeExpr1() { + assertParse( + """ + var global: Int = 5 + func testGlobal() { + let _ = consume global + } + """ + ) + } + + func testConsumeExpr2() { + assertParse( + """ + func testLet() { + let t = String() + let _ = consume t + } + """ + ) + } + + func testConsumeExpr3() { + assertParse( + """ + func testVar() { + var t = String() + t = String() + let _ = consume t + } + """ + ) + } +}} + From ac4556e255017781de22b4fd76ae07b0c392f06c Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 17 May 2023 13:39:53 -0700 Subject: [PATCH 5/7] Update generated code for previous commit. --- .../generated/SyntaxKindNameForDiagnostics.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index a2103ab77aa..780b3becf4e 100644 --- a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift @@ -274,7 +274,7 @@ extension SyntaxKind { case .missingType: return "type" case .moveExpr: - return "'_move' expression" + return "'consume' expression" case .multipleTrailingClosureElement: return "trailing closure" case .namedOpaqueReturnType: From bc84e48c957a43af73051ec20ed25bccfb4f3765 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 17 May 2023 14:18:33 -0700 Subject: [PATCH 6/7] [consume] Change how we parse consume to match copy so we properly handle consume used as a name in case stmt as pattern match. rdar://109413278 --- Sources/SwiftParser/Expressions.swift | 18 +++++++++--------- .../translated/MoveExprTests.swift | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index f3a7342683d..d81fccb9f58 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -504,16 +504,16 @@ extension Parser { case (.consumeKeyword, let handle)?: // `consume` is only contextually a keyword, if it's followed by an - // identifier or keyword on the same line. - let next = peek() - if next.isAtStartOfLine { - break - } - if next.rawTokenKind != .identifier, - next.rawTokenKind != .dollarIdentifier, - next.rawTokenKind != .keyword - { + // identifier or keyword on the same line. We do this to ensure that we do + // not break any copy functions defined by users. This is following with + // what we have done for the consume keyword. + switch self.peek() { + case TokenSpec(.identifier, allowAtStartOfLine: false), + TokenSpec(.dollarIdentifier, allowAtStartOfLine: false), + TokenSpec(.self, allowAtStartOfLine: false): break + default: + break EXPR_PREFIX // break out of the outer `switch` } let consumeTok = self.eat(handle) diff --git a/Tests/SwiftParserTest/translated/MoveExprTests.swift b/Tests/SwiftParserTest/translated/MoveExprTests.swift index cd011e4fefb..c7da48df34b 100644 --- a/Tests/SwiftParserTest/translated/MoveExprTests.swift +++ b/Tests/SwiftParserTest/translated/MoveExprTests.swift @@ -82,5 +82,20 @@ final class MoveExprTests: XCTestCase { """ ) } -}} + + func testConsumeVariableNameInCast() { + assertParse( + """ + class ParentKlass {} + class SubKlass : ParentKlass {} + + func test(_ x: SubKlass) { + switch x { + case let consume as ParentKlass: + fallthrough + } + } + """) + } +} From b3d38fddb357511085eced00b6a7cd285bd32349 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 18 May 2023 00:22:10 -0700 Subject: [PATCH 7/7] Fix swift-format errors. --- Sources/SwiftParser/Expressions.swift | 14 ++++++++------ .../SwiftParserTest/translated/MoveExprTests.swift | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index d81fccb9f58..d33652ef0a8 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -481,11 +481,12 @@ extension Parser { // what we have done for the consume keyword. switch self.peek() { case TokenSpec(.identifier, allowAtStartOfLine: false), - TokenSpec(.dollarIdentifier, allowAtStartOfLine: false), - TokenSpec(.self, allowAtStartOfLine: false): + TokenSpec(.dollarIdentifier, allowAtStartOfLine: false), + TokenSpec(.self, allowAtStartOfLine: false): break default: - break EXPR_PREFIX // Break out of `outer switch` on failure. + // Break out of `outer switch` on failure. + break EXPR_PREFIX } let copyTok = self.eat(handle) @@ -509,11 +510,12 @@ extension Parser { // what we have done for the consume keyword. switch self.peek() { case TokenSpec(.identifier, allowAtStartOfLine: false), - TokenSpec(.dollarIdentifier, allowAtStartOfLine: false), - TokenSpec(.self, allowAtStartOfLine: false): + TokenSpec(.dollarIdentifier, allowAtStartOfLine: false), + TokenSpec(.self, allowAtStartOfLine: false): break default: - break EXPR_PREFIX // break out of the outer `switch` + // Break out of the outer `switch`. + break EXPR_PREFIX } let consumeTok = self.eat(handle) diff --git a/Tests/SwiftParserTest/translated/MoveExprTests.swift b/Tests/SwiftParserTest/translated/MoveExprTests.swift index c7da48df34b..5a3a8a60a54 100644 --- a/Tests/SwiftParserTest/translated/MoveExprTests.swift +++ b/Tests/SwiftParserTest/translated/MoveExprTests.swift @@ -95,7 +95,7 @@ final class MoveExprTests: XCTestCase { fallthrough } } - """) + """ + ) } } -