Skip to content

Add unsafe expression syntax under an experimental feature flag unsafeExpression #2937

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -41,6 +42,8 @@ public enum ExperimentalFeature: String, CaseIterable {
return "ValueGenerics"
case .abiAttribute:
return "ABIAttribute"
case .unsafeExpression:
return "WarnUnsafe"
}
}

Expand All @@ -63,6 +66,8 @@ public enum ExperimentalFeature: String, CaseIterable {
return "value generics"
case .abiAttribute:
return "@abi attribute"
case .unsafeExpression:
return "'unsafe' expression"
}
}

Expand Down
17 changes: 17 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 22 additions & 4 deletions Sources/SwiftOperators/OperatorTable+Folding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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.

Expand Down
13 changes: 13 additions & 0 deletions Sources/SwiftParser/Expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftParser/TokenSpecSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
}
}
Expand All @@ -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)
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/SwiftParser/generated/ExperimentalFeatures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -68,6 +71,8 @@ extension Parser.ExperimentalFeatures {
self = .valueGenerics
case "ABIAttribute":
self = .abiAttribute
case "WarnUnsafe":
self = .unsafeExpression
default:
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 10 additions & 0 deletions Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
14 changes: 14 additions & 0 deletions Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
6 changes: 4 additions & 2 deletions Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
])
}
}
Expand Down Expand Up @@ -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),
Expand Down
12 changes: 12 additions & 0 deletions Sources/SwiftSyntax/generated/SyntaxEnum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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")
}
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftSyntax/generated/SyntaxKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
19 changes: 19 additions & 0 deletions Sources/SwiftSyntax/generated/SyntaxRewriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
Loading