diff --git a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift index 6da75f84254..4b6381d1e77 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift @@ -21,6 +21,7 @@ public enum ExperimentalFeature: String, CaseIterable { case coroutineAccessors case valueGenerics case abiAttribute + case unsafeExpression /// The name of the feature as it is written in the compiler's `Features.def` file. public var featureName: String { @@ -41,6 +42,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "ValueGenerics" case .abiAttribute: return "ABIAttribute" + case .unsafeExpression: + return "WarnUnsafe" } } @@ -63,6 +66,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "value generics" case .abiAttribute: return "@abi attribute" + case .unsafeExpression: + return "'unsafe' expression" } } diff --git a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift index 7a3185a867a..7aad34d15ec 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift @@ -180,6 +180,23 @@ public let EXPR_NODES: [Node] = [ ] ), + Node( + kind: .unsafeExpr, + base: .expr, + experimentalFeature: .unsafeExpression, + nameForDiagnostics: "'unsafe' expression", + children: [ + Child( + name: "unsafeKeyword", + kind: .token(choices: [.keyword(.unsafe)]) + ), + Child( + name: "expression", + kind: .node(kind: .expr) + ), + ] + ), + Node( kind: .binaryOperatorExpr, base: .expr, diff --git a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift index 1d9e97b0e29..5038fa3d39c 100644 --- a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift +++ b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift @@ -299,6 +299,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon case unresolvedAsExpr case unresolvedIsExpr case unresolvedTernaryExpr + case unsafeExpr case valueBindingPattern case variableDecl case versionComponent diff --git a/Sources/SwiftOperators/OperatorTable+Folding.swift b/Sources/SwiftOperators/OperatorTable+Folding.swift index 121e5f6146f..06371c9f50a 100644 --- a/Sources/SwiftOperators/OperatorTable+Folding.swift +++ b/Sources/SwiftOperators/OperatorTable+Folding.swift @@ -11,9 +11,9 @@ //===----------------------------------------------------------------------===// #if compiler(>=6) -public import SwiftSyntax +@_spi(ExperimentalLanguageFeatures) public import SwiftSyntax #else -import SwiftSyntax +@_spi(ExperimentalLanguageFeatures) import SwiftSyntax #endif extension ExprSyntax { @@ -104,8 +104,8 @@ extension OperatorTable { op: ExprSyntax, rhs: ExprSyntax ) -> ExprSyntax { - // If the left-hand side is a "try" or "await", hoist it up to encompass - // the right-hand side as well. + // If the left-hand side is a "try", "await", or "unsafe", hoist it up to + // encompass the right-hand side as well. if let tryExpr = lhs.as(TryExprSyntax.self) { return ExprSyntax( TryExprSyntax( @@ -138,6 +138,24 @@ extension OperatorTable { ) } + if let unsafeExpr = lhs.as(UnsafeExprSyntax.self) { + return ExprSyntax( + UnsafeExprSyntax( + leadingTrivia: unsafeExpr.leadingTrivia, + unsafeExpr.unexpectedBeforeUnsafeKeyword, + unsafeKeyword: unsafeExpr.unsafeKeyword, + unsafeExpr.unexpectedBetweenUnsafeKeywordAndExpression, + expression: makeBinaryOperationExpr( + lhs: unsafeExpr.expression, + op: op, + rhs: rhs + ), + unsafeExpr.unexpectedAfterExpression, + trailingTrivia: unsafeExpr.trailingTrivia + ) + ) + } + // The form of the binary operation depends on the operator itself, // which will be one of the unresolved infix operators. diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 620912bcaea..bf1c9fba52d 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -444,6 +444,19 @@ extension Parser { arena: self.arena ) ) + case (.unsafe, let handle)?: + let unsafeTok = self.eat(handle) + let sub = self.parseSequenceExpressionElement( + flavor: flavor, + pattern: pattern + ) + return RawExprSyntax( + RawUnsafeExprSyntax( + unsafeKeyword: unsafeTok, + expression: sub, + arena: self.arena + ) + ) case (._move, let handle)?: let moveKeyword = self.eat(handle) let sub = self.parseSequenceExpressionElement( diff --git a/Sources/SwiftParser/TokenSpecSet.swift b/Sources/SwiftParser/TokenSpecSet.swift index e3eb5126ffa..2806c15440d 100644 --- a/Sources/SwiftParser/TokenSpecSet.swift +++ b/Sources/SwiftParser/TokenSpecSet.swift @@ -700,6 +700,7 @@ enum ExpressionModifierKeyword: TokenSpecSet { case `repeat` case each case any + case unsafe init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) { switch PrepareForKeywordMatch(lexeme) { @@ -713,6 +714,7 @@ enum ExpressionModifierKeyword: TokenSpecSet { case TokenSpec(.repeat): self = .repeat case TokenSpec(.each): self = .each case TokenSpec(.any): self = .any + case TokenSpec(.unsafe) where experimentalFeatures.contains(.unsafeExpression): self = .unsafe default: return nil } } @@ -729,6 +731,7 @@ enum ExpressionModifierKeyword: TokenSpecSet { case .repeat: return .keyword(.repeat) case .each: return .keyword(.each) case .any: return .keyword(.any) + case .unsafe: return .keyword(.unsafe) } } } diff --git a/Sources/SwiftParser/generated/ExperimentalFeatures.swift b/Sources/SwiftParser/generated/ExperimentalFeatures.swift index c999428f365..a5a8e2c21d1 100644 --- a/Sources/SwiftParser/generated/ExperimentalFeatures.swift +++ b/Sources/SwiftParser/generated/ExperimentalFeatures.swift @@ -48,6 +48,9 @@ extension Parser.ExperimentalFeatures { /// Whether to enable the parsing of @abi attribute. public static let abiAttribute = Self (rawValue: 1 << 7) + /// Whether to enable the parsing of 'unsafe' expression. + public static let unsafeExpression = Self (rawValue: 1 << 8) + /// Creates a new value representing the experimental feature with the /// given name, or returns nil if the name is not recognized. public init?(name: String) { @@ -68,6 +71,8 @@ extension Parser.ExperimentalFeatures { self = .valueGenerics case "ABIAttribute": self = .abiAttribute + case "WarnUnsafe": + self = .unsafeExpression default: return nil } diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index 094815a0d2d..3bab4943b4f 100644 --- a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift @@ -399,6 +399,8 @@ extension SyntaxKind { return "'is'" case .unresolvedTernaryExpr: return "ternary operator" + case .unsafeExpr: + return "'unsafe' expression" case .valueBindingPattern: return "value binding pattern" case .variableDecl: diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index 75ae283f668..566b0142125 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -3387,6 +3387,16 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "colon" case \UnresolvedTernaryExprSyntax.unexpectedAfterColon: return "unexpectedAfterColon" + case \UnsafeExprSyntax.unexpectedBeforeUnsafeKeyword: + return "unexpectedBeforeUnsafeKeyword" + case \UnsafeExprSyntax.unsafeKeyword: + return "unsafeKeyword" + case \UnsafeExprSyntax.unexpectedBetweenUnsafeKeywordAndExpression: + return "unexpectedBetweenUnsafeKeywordAndExpression" + case \UnsafeExprSyntax.expression: + return "expression" + case \UnsafeExprSyntax.unexpectedAfterExpression: + return "unexpectedAfterExpression" case \ValueBindingPatternSyntax.unexpectedBeforeBindingSpecifier: return "unexpectedBeforeBindingSpecifier" case \ValueBindingPatternSyntax.bindingSpecifier: diff --git a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift index dc6991cd0f5..7289ed7f8e2 100644 --- a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift @@ -2268,6 +2268,20 @@ open class SyntaxAnyVisitor: SyntaxVisitor { visitAnyPost(node._syntaxNode) } + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + override open func visit(_ node: UnsafeExprSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + override open func visitPost(_ node: UnsafeExprSyntax) { + visitAnyPost(node._syntaxNode) + } + override open func visit(_ node: ValueBindingPatternSyntax) -> SyntaxVisitorContinueKind { return visitAny(node._syntaxNode) } diff --git a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift index 1dd414f2cd5..210d83d4fea 100644 --- a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift +++ b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift @@ -542,7 +542,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { public init?(_ node: __shared some SyntaxProtocol) { switch node.raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, ._canImportExpr, ._canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .doExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, ._canImportExpr, ._canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .doExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr, .unsafeExpr: self._syntaxNode = node._syntaxNode default: return nil @@ -619,7 +619,8 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { .node(TypeExprSyntax.self), .node(UnresolvedAsExprSyntax.self), .node(UnresolvedIsExprSyntax.self), - .node(UnresolvedTernaryExprSyntax.self) + .node(UnresolvedTernaryExprSyntax.self), + .node(UnsafeExprSyntax.self) ]) } } @@ -1789,6 +1790,7 @@ extension Syntax { .node(UnresolvedAsExprSyntax.self), .node(UnresolvedIsExprSyntax.self), .node(UnresolvedTernaryExprSyntax.self), + .node(UnsafeExprSyntax.self), .node(ValueBindingPatternSyntax.self), .node(VariableDeclSyntax.self), .node(VersionComponentListSyntax.self), diff --git a/Sources/SwiftSyntax/generated/SyntaxEnum.swift b/Sources/SwiftSyntax/generated/SyntaxEnum.swift index 439e8dca904..b801ba4011b 100644 --- a/Sources/SwiftSyntax/generated/SyntaxEnum.swift +++ b/Sources/SwiftSyntax/generated/SyntaxEnum.swift @@ -305,6 +305,10 @@ public enum SyntaxEnum: Sendable { case unresolvedAsExpr(UnresolvedAsExprSyntax) case unresolvedIsExpr(UnresolvedIsExprSyntax) case unresolvedTernaryExpr(UnresolvedTernaryExprSyntax) + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + case unsafeExpr(UnsafeExprSyntax) case valueBindingPattern(ValueBindingPatternSyntax) case variableDecl(VariableDeclSyntax) case versionComponentList(VersionComponentListSyntax) @@ -869,6 +873,8 @@ extension Syntax { return .unresolvedIsExpr(UnresolvedIsExprSyntax(self)!) case .unresolvedTernaryExpr: return .unresolvedTernaryExpr(UnresolvedTernaryExprSyntax(self)!) + case .unsafeExpr: + return .unsafeExpr(UnsafeExprSyntax(self)!) case .valueBindingPattern: return .valueBindingPattern(ValueBindingPatternSyntax(self)!) case .variableDecl: @@ -1041,6 +1047,10 @@ public enum ExprSyntaxEnum { case unresolvedAsExpr(UnresolvedAsExprSyntax) case unresolvedIsExpr(UnresolvedIsExprSyntax) case unresolvedTernaryExpr(UnresolvedTernaryExprSyntax) + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + case unsafeExpr(UnsafeExprSyntax) } extension ExprSyntax { @@ -1153,6 +1163,8 @@ extension ExprSyntax { return .unresolvedIsExpr(UnresolvedIsExprSyntax(self)!) case .unresolvedTernaryExpr: return .unresolvedTernaryExpr(UnresolvedTernaryExprSyntax(self)!) + case .unsafeExpr: + return .unsafeExpr(UnsafeExprSyntax(self)!) default: preconditionFailure("unknown Expr syntax kind") } diff --git a/Sources/SwiftSyntax/generated/SyntaxKind.swift b/Sources/SwiftSyntax/generated/SyntaxKind.swift index c88765ee1f6..b3bd4e49111 100644 --- a/Sources/SwiftSyntax/generated/SyntaxKind.swift +++ b/Sources/SwiftSyntax/generated/SyntaxKind.swift @@ -305,6 +305,10 @@ public enum SyntaxKind: Sendable { case unresolvedAsExpr case unresolvedIsExpr case unresolvedTernaryExpr + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + case unsafeExpr case valueBindingPattern case variableDecl case versionComponentList @@ -994,6 +998,8 @@ public enum SyntaxKind: Sendable { return UnresolvedIsExprSyntax.self case .unresolvedTernaryExpr: return UnresolvedTernaryExprSyntax.self + case .unsafeExpr: + return UnsafeExprSyntax.self case .valueBindingPattern: return ValueBindingPatternSyntax.self case .variableDecl: diff --git a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift index 9090c0a3ab5..e91d2adb0c8 100644 --- a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift +++ b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift @@ -2020,6 +2020,16 @@ open class SyntaxRewriter { return ExprSyntax(UnresolvedTernaryExprSyntax(unsafeCasting: visitChildren(node._syntaxNode))) } + /// Visit a `UnsafeExprSyntax`. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + open func visit(_ node: UnsafeExprSyntax) -> ExprSyntax { + return ExprSyntax(UnsafeExprSyntax(unsafeCasting: visitChildren(node._syntaxNode))) + } + /// Visit a ``ValueBindingPatternSyntax``. /// - Parameter node: the node that is being visited /// - Returns: the rewritten node @@ -3504,6 +3514,11 @@ open class SyntaxRewriter { Syntax(visit(UnresolvedTernaryExprSyntax(unsafeCasting: node))) } + @inline(never) + private func visitUnsafeExprSyntaxImpl(_ node: Syntax) -> Syntax { + Syntax(visit(UnsafeExprSyntax(unsafeCasting: node))) + } + @inline(never) private func visitValueBindingPatternSyntaxImpl(_ node: Syntax) -> Syntax { Syntax(visit(ValueBindingPatternSyntax(unsafeCasting: node))) @@ -4136,6 +4151,8 @@ open class SyntaxRewriter { return self.visitUnresolvedIsExprSyntaxImpl(_:) case .unresolvedTernaryExpr: return self.visitUnresolvedTernaryExprSyntaxImpl(_:) + case .unsafeExpr: + return self.visitUnsafeExprSyntaxImpl(_:) case .valueBindingPattern: return self.visitValueBindingPatternSyntaxImpl(_:) case .variableDecl: @@ -4714,6 +4731,8 @@ open class SyntaxRewriter { return visitUnresolvedIsExprSyntaxImpl(node) case .unresolvedTernaryExpr: return visitUnresolvedTernaryExprSyntaxImpl(node) + case .unsafeExpr: + return visitUnsafeExprSyntaxImpl(node) case .valueBindingPattern: return visitValueBindingPatternSyntaxImpl(node) case .variableDecl: diff --git a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift index 511790c81fd..89dbf80a3ad 100644 --- a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift @@ -3334,6 +3334,24 @@ open class SyntaxVisitor { open func visitPost(_ node: UnresolvedTernaryExprSyntax) { } + /// Visiting `UnsafeExprSyntax` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + open func visit(_ node: UnsafeExprSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting `UnsafeExprSyntax` and its descendants. + /// - node: the node we just finished visiting. + #if compiler(>=5.8) + @_spi(ExperimentalLanguageFeatures) + #endif + open func visitPost(_ node: UnsafeExprSyntax) { + } + /// Visiting ``ValueBindingPatternSyntax`` specifically. /// - Parameter node: the node we are visiting. /// - Returns: how should we continue visiting. @@ -5673,6 +5691,14 @@ open class SyntaxVisitor { visitPost(UnresolvedTernaryExprSyntax(unsafeCasting: node)) } + @inline(never) + private func visitUnsafeExprSyntaxImpl(_ node: Syntax) { + if visit(UnsafeExprSyntax(unsafeCasting: node)) == .visitChildren { + visitChildren(node) + } + visitPost(UnsafeExprSyntax(unsafeCasting: node)) + } + @inline(never) private func visitValueBindingPatternSyntaxImpl(_ node: Syntax) { if visit(ValueBindingPatternSyntax(unsafeCasting: node)) == .visitChildren { @@ -6341,6 +6367,8 @@ open class SyntaxVisitor { return self.visitUnresolvedIsExprSyntaxImpl(_:) case .unresolvedTernaryExpr: return self.visitUnresolvedTernaryExprSyntaxImpl(_:) + case .unsafeExpr: + return self.visitUnsafeExprSyntaxImpl(_:) case .valueBindingPattern: return self.visitValueBindingPatternSyntaxImpl(_:) case .variableDecl: @@ -6919,6 +6947,8 @@ open class SyntaxVisitor { self.visitUnresolvedIsExprSyntaxImpl(node) case .unresolvedTernaryExpr: self.visitUnresolvedTernaryExprSyntaxImpl(node) + case .unsafeExpr: + self.visitUnsafeExprSyntaxImpl(node) case .valueBindingPattern: self.visitValueBindingPatternSyntaxImpl(node) case .variableDecl: diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesEF.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesEF.swift index 376db16d670..7ac0c48d843 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesEF.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesEF.swift @@ -988,7 +988,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, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .doExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, ._canImportExpr, ._canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .doExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr, .unsafeExpr: return true default: return false diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift index 4a2489c4ba0..0de57b84777 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesTUVWXYZ.swift @@ -1955,6 +1955,79 @@ public struct RawUnresolvedTernaryExprSyntax: RawExprSyntaxNodeProtocol { } } +#if compiler(>=5.8) +@_spi(ExperimentalLanguageFeatures) +#endif +@_spi(RawSyntax) +public struct RawUnsafeExprSyntax: RawExprSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .unsafeExpr + } + + 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( + _ unexpectedBeforeUnsafeKeyword: RawUnexpectedNodesSyntax? = nil, + unsafeKeyword: RawTokenSyntax, + _ unexpectedBetweenUnsafeKeywordAndExpression: RawUnexpectedNodesSyntax? = nil, + expression: some RawExprSyntaxNodeProtocol, + _ unexpectedAfterExpression: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { + let raw = RawSyntax.makeLayout( + kind: .unsafeExpr, uninitializedCount: 5, arena: arena) { layout in + layout.initialize(repeating: nil) + layout[0] = unexpectedBeforeUnsafeKeyword?.raw + layout[1] = unsafeKeyword.raw + layout[2] = unexpectedBetweenUnsafeKeywordAndExpression?.raw + layout[3] = expression.raw + layout[4] = unexpectedAfterExpression?.raw + } + self.init(unchecked: raw) + } + + public var unexpectedBeforeUnsafeKeyword: RawUnexpectedNodesSyntax? { + layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var unsafeKeyword: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedBetweenUnsafeKeywordAndExpression: 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 RawValueBindingPatternSyntax: RawPatternSyntaxNodeProtocol { @_spi(RawSyntax) diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index 5350e0f27cb..c46645b2dc1 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -2973,6 +2973,14 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.colon)])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) } + func validateUnsafeExprSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { + assert(layout.count == 5) + assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.keyword("unsafe")])) + 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)) + } func validateValueBindingPatternSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { assert(layout.count == 5) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) @@ -3632,6 +3640,8 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { validateUnresolvedIsExprSyntax(kind: kind, layout: layout) case .unresolvedTernaryExpr: validateUnresolvedTernaryExprSyntax(kind: kind, layout: layout) + case .unsafeExpr: + validateUnsafeExprSyntax(kind: kind, layout: layout) case .valueBindingPattern: validateValueBindingPatternSyntax(kind: kind, layout: layout) case .variableDecl: diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift index 1f06653f5b2..2c9705a89c0 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift @@ -3272,6 +3272,128 @@ public struct UnresolvedTernaryExprSyntax: ExprSyntaxProtocol, SyntaxHashable, _ ]) } +// MARK: - UnsafeExprSyntax + +/// - Note: Requires experimental feature `unsafeExpression`. +/// +/// ### Children +/// +/// - `unsafeKeyword`: `unsafe` +/// - `expression`: ``ExprSyntax`` +#if compiler(>=5.8) +@_spi(ExperimentalLanguageFeatures) +#endif +public struct UnsafeExprSyntax: ExprSyntaxProtocol, SyntaxHashable, _LeafExprSyntaxNodeProtocol { + public let _syntaxNode: Syntax + + public init?(_ node: __shared some SyntaxProtocol) { + guard node.raw.kind == .unsafeExpr else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + @_transparent + init(unsafeCasting node: Syntax) { + self._syntaxNode = node + } + + /// - Parameters: + /// - leadingTrivia: Trivia to be prepended to the leading trivia of the node’s first token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + /// - trailingTrivia: Trivia to be appended to the trailing trivia of the node’s last token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeUnsafeKeyword: UnexpectedNodesSyntax? = nil, + unsafeKeyword: TokenSyntax = .keyword(.unsafe), + _ unexpectedBetweenUnsafeKeywordAndExpression: 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. + self = withExtendedLifetime((SyntaxArena(), ( + unexpectedBeforeUnsafeKeyword, + unsafeKeyword, + unexpectedBetweenUnsafeKeywordAndExpression, + expression, + unexpectedAfterExpression + ))) { (arena, _) in + let layout: [RawSyntax?] = [ + unexpectedBeforeUnsafeKeyword?.raw, + unsafeKeyword.raw, + unexpectedBetweenUnsafeKeywordAndExpression?.raw, + expression.raw, + unexpectedAfterExpression?.raw + ] + let raw = RawSyntax.makeLayout( + kind: SyntaxKind.unsafeExpr, + from: layout, + arena: arena, + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia + ) + return Syntax.forRoot(raw, rawNodeArena: arena).cast(Self.self) + } + } + + public var unexpectedBeforeUnsafeKeyword: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 0)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 0, with: Syntax(value), arena: SyntaxArena()).cast(UnsafeExprSyntax.self) + } + } + + /// ### Tokens + /// + /// For syntax trees generated by the parser, this is guaranteed to be `unsafe`. + public var unsafeKeyword: TokenSyntax { + get { + return Syntax(self).child(at: 1)!.cast(TokenSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 1, with: Syntax(value), arena: SyntaxArena()).cast(UnsafeExprSyntax.self) + } + } + + public var unexpectedBetweenUnsafeKeywordAndExpression: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 2)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 2, with: Syntax(value), arena: SyntaxArena()).cast(UnsafeExprSyntax.self) + } + } + + public var expression: ExprSyntax { + get { + return Syntax(self).child(at: 3)!.cast(ExprSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 3, with: Syntax(value), arena: SyntaxArena()).cast(UnsafeExprSyntax.self) + } + } + + public var unexpectedAfterExpression: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 4)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 4, with: Syntax(value), arena: SyntaxArena()).cast(UnsafeExprSyntax.self) + } + } + + public static let structure: SyntaxNodeStructure = .layout([ + \Self.unexpectedBeforeUnsafeKeyword, + \Self.unsafeKeyword, + \Self.unexpectedBetweenUnsafeKeywordAndExpression, + \Self.expression, + \Self.unexpectedAfterExpression + ]) +} + // MARK: - ValueBindingPatternSyntax /// ### Children diff --git a/Tests/SwiftParserTest/ExpressionTests.swift b/Tests/SwiftParserTest/ExpressionTests.swift index 90498d7179a..1038026eb26 100644 --- a/Tests/SwiftParserTest/ExpressionTests.swift +++ b/Tests/SwiftParserTest/ExpressionTests.swift @@ -2188,6 +2188,40 @@ final class StatementExpressionTests: ParserTestCase { ) } + func testUnsafeExpr() { + assertParse( + """ + func f() { + let x = unsafe y + } + """, + experimentalFeatures: .unsafeExpression + ) + + assertParse( + """ + func f() { + let x = unsafe1️⃣ y + } + """, + diagnostics: [ + DiagnosticSpec( + message: "consecutive statements on a line must be separated by newline or ';'", + fixIts: [ + "insert newline", + "insert ';'", + ] + ) + ], + fixedSource: """ + func f() { + let x = unsafe + y + } + """ + ) + } + func testUnterminatedInterpolationAtEndOfMultilineStringLiteral() { assertParse( #"""