diff --git a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift index 2f3ae245ae7..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( @@ -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 62ae35b6084..d33652ef0a8 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -413,7 +413,7 @@ extension Parser { } } - switch self.at(anyIn: AwaitTryMove.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,48 @@ 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 out of `outer switch` on failure. + break EXPR_PREFIX + } + + 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 - } - if next.rawTokenKind != .identifier, - next.rawTokenKind != .dollarIdentifier, - next.rawTokenKind != .keyword - { - fallthrough + // 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 out of the outer `switch`. + break EXPR_PREFIX } let consumeTok = self.eat(handle) @@ -502,8 +532,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 82460f6ea16..32cf7beff73 100644 --- a/Sources/SwiftParser/TokenSpecSet.swift +++ b/Sources/SwiftParser/TokenSpecSet.swift @@ -476,12 +476,13 @@ public enum TypeSpecifier: TokenSpecSet { // MARK: Expression start -enum AwaitTryMove: TokenSpecSet { +enum ExpressionModifierKeyword: TokenSpecSet { case awaitKeyword case _moveKeyword case _borrowKeyword case tryKeyword case consumeKeyword + case copyKeyword init?(lexeme: Lexer.Lexeme) { switch PrepareForKeywordMatch(lexeme) { @@ -490,6 +491,7 @@ enum AwaitTryMove: 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 AwaitTryMove: 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) } } @@ -695,13 +698,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 +718,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) diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index cd525cbaa7a..780b3becf4e 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: @@ -272,7 +274,7 @@ extension SyntaxKind { case .missingType: return "type" case .moveExpr: - return "'_move' expression" + return "'consume' expression" case .multipleTrailingClosureElement: return "trailing closure" case .namedOpaqueReturnType: 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 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 + } + } + """ + ) + } +} diff --git a/Tests/SwiftParserTest/translated/MoveExprTests.swift b/Tests/SwiftParserTest/translated/MoveExprTests.swift index 081a970ff1b..5a3a8a60a54 100644 --- a/Tests/SwiftParserTest/translated/MoveExprTests.swift +++ b/Tests/SwiftParserTest/translated/MoveExprTests.swift @@ -49,4 +49,53 @@ 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 + } + """ + ) + } + + func testConsumeVariableNameInCast() { + assertParse( + """ + class ParentKlass {} + class SubKlass : ParentKlass {} + + func test(_ x: SubKlass) { + switch x { + case let consume as ParentKlass: + fallthrough + } + } + """ + ) + } }