Skip to content

Update SwiftSyntax to Swift 5.7 #1627

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

Closed
wants to merge 5 commits into from
Closed
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
2 changes: 1 addition & 1 deletion CodeGeneration/Sources/SyntaxSupport/TokenSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class TokenSpec {
self.name = name
self.kind = kind
self.nameForDiagnostics = nameForDiagnostics
if let unprefixedKind = unprefixedKind {
if let unprefixedKind {
self.unprefixedKind = unprefixedKind
} else {
self.unprefixedKind = kind
Expand Down
6 changes: 5 additions & 1 deletion CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ public extension Child {
/// function parameter. Otherwise, return `nil`.
var defaultInitialization: InitializerClauseSyntax? {
if isOptional || isUnexpectedNodes {
return InitializerClauseSyntax(value: NilLiteralExprSyntax())
if type.isBaseType && kind.isNodeChoicesEmpty {
return InitializerClauseSyntax(value: ExprSyntax("\(type.buildable).none"))
} else {
return InitializerClauseSyntax(value: NilLiteralExprSyntax())
}
}
guard let token = token, isToken else {
return type.defaultValue.map { InitializerClauseSyntax(value: $0) }
Expand Down
6 changes: 3 additions & 3 deletions CodeGeneration/Sources/Utils/SyntaxBuildableType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public struct SyntaxBuildableType: Hashable {
}

/// Wraps a type in an optional depending on whether `isOptional` is true.
public func optionalWrapped<TypeNode: TypeSyntaxProtocol>(type: TypeNode) -> TypeSyntax {
public func optionalWrapped(type: some TypeSyntaxProtocol) -> TypeSyntax {
if isOptional {
return TypeSyntax(OptionalTypeSyntax(wrappedType: type))
} else {
Expand All @@ -169,7 +169,7 @@ public struct SyntaxBuildableType: Hashable {
}

/// Wraps a type in an optional chaining depending on whether `isOptional` is true.
public func optionalChained<ExprNode: ExprSyntaxProtocol>(expr: ExprNode) -> ExprSyntax {
public func optionalChained(expr: some ExprSyntaxProtocol) -> ExprSyntax {
if isOptional {
return ExprSyntax(OptionalChainingExprSyntax(expression: expr))
} else {
Expand All @@ -178,7 +178,7 @@ public struct SyntaxBuildableType: Hashable {
}

/// Wraps a type in a force unwrap expression depending on whether `isOptional` is true.
public func forceUnwrappedIfNeeded<ExprNode: ExprSyntaxProtocol>(expr: ExprNode) -> ExprSyntax {
public func forceUnwrappedIfNeeded(expr: some ExprSyntaxProtocol) -> ExprSyntax {
if isOptional {
return ExprSyntax(ForcedValueExprSyntax(expression: expr))
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ let lookupTable = ArrayExprSyntax(leftSquare: .leftSquareBracketToken(trailingTr
let keywordFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
try! EnumDeclSyntax(
"""
@frozen // FIXME: Not actually stable, works around a miscompile
public enum Keyword: UInt8, Hashable
"""
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
for (name, choices) in enums {
try EnumDeclSyntax(
"""
@frozen // FIXME: Not actually stable, works around a miscompile
public enum \(raw: name): RawSyntaxNodeProtocol
"""
) {
Expand All @@ -72,7 +71,7 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}

try InitializerDeclSyntax("public init?<T>(_ other: T) where T : RawSyntaxNodeProtocol") {
try InitializerDeclSyntax("public init?(_ other: some RawSyntaxNodeProtocol)") {
for (swiftName, typeName) in choices {
StmtSyntax(
"""
Expand Down Expand Up @@ -145,7 +144,7 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {

DeclSyntax(
"""
public init?<Node: RawSyntaxNodeProtocol>(_ other: Node) {
public init?(_ other: some RawSyntaxNodeProtocol) {
guard Self.isKindOf(other.raw) else { return nil }
self.init(unchecked: other.raw)
}
Expand All @@ -155,7 +154,7 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
if node.isBase {
DeclSyntax(
"""
public init<Node: Raw\(raw: node.name)NodeProtocol>(_ other: Node) {
public init(_ other: some Raw\(raw: node.name)NodeProtocol) {
self.init(unchecked: other.raw)
}
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
DeclSyntax(
#"""
func assertNoError(_ nodeKind: SyntaxKind, _ index: Int, _ error: ValidationError?) {
if let error = error {
if let error {
let (file, line) = error.fileAndLine
assertionFailure("""
Error validating child at index \(index) of \(nodeKind):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ let syntaxBaseNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
DeclSyntax(
"""
/// Create a `\(raw: node.name)` node from a specialized syntax node.
public init<S: \(raw: node.name)Protocol>(_ syntax: S) {
public init(_ syntax: some \(raw: node.name)Protocol) {
// We know this cast is going to succeed. Go through init(_: SyntaxData)
// to do a sanity check and verify the kind matches in debug builds and get
// maximum performance in release builds.
Expand All @@ -75,7 +75,7 @@ let syntaxBaseNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
DeclSyntax(
"""
/// Create a `\(raw: node.name)` node from a specialized optional syntax node.
public init?<S: \(raw: node.name)Protocol>(_ syntax: S?) {
public init?(_ syntax: (some \(raw: node.name)Protocol)?) {
guard let syntax = syntax else { return nil }
self.init(syntax)
}
Expand Down Expand Up @@ -103,7 +103,7 @@ let syntaxBaseNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
"""
)

try InitializerDeclSyntax("public init?<S: SyntaxProtocol>(_ node: S)") {
try InitializerDeclSyntax("public init?(_ node: some SyntaxProtocol)") {
try SwitchExprSyntax("switch node.raw.kind") {
SwitchCaseListSyntax {
SwitchCaseSyntax(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ let syntaxCollectionsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
if let collectionElementChoices = node.collectionElementChoices, !collectionElementChoices.isEmpty {
try EnumDeclSyntax(
"""
@frozen // FIXME: Not actually stable, works around a miscompile
public enum Element: SyntaxChildChoices
"""
) {
Expand All @@ -81,7 +80,7 @@ let syntaxCollectionsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
if choiceNode.isBase {
DeclSyntax(
"""
public init<Node: \(raw: choiceNode.name)Protocol>(_ node: Node) {
public init(_ node: some \(raw: choiceNode.name)Protocol) {
self = .\(raw: choiceNode.swiftSyntaxKind)(\(raw: choiceNode.name)(node))
}
"""
Expand All @@ -98,7 +97,7 @@ let syntaxCollectionsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}

try InitializerDeclSyntax("public init?<S: SyntaxProtocol>(_ node: S)") {
try InitializerDeclSyntax("public init?(_ node: some SyntaxProtocol)") {
for choiceName in node.collectionElementChoices ?? [] {
let choiceNode = SYNTAX_NODE_MAP[choiceName]!
StmtSyntax(
Expand Down Expand Up @@ -144,7 +143,7 @@ let syntaxCollectionsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {

DeclSyntax(
"""
public init?<S: SyntaxProtocol>(_ node: S) {
public init?(_ node: some SyntaxProtocol) {
guard node.raw.kind == .\(raw: node.swiftSyntaxKind) else { return nil }
self._syntaxNode = node._syntaxNode
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ let syntaxEnumFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
try! EnumDeclSyntax(
"""
/// Enum to exhaustively switch over all different syntax nodes.
@frozen // FIXME: Not actually stable, works around a miscompile
public enum SyntaxEnum
"""
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ let syntaxKindFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
try! EnumDeclSyntax(
"""
/// Enumerates the known kinds of Syntax represented in the Syntax tree.
@frozen // FIXME: Not actually stable, works around a miscompile
public enum SyntaxKind
"""
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax {

DeclSyntax(
"""
public init?<S: SyntaxProtocol>(_ node: S) {
public init?(_ node: some SyntaxProtocol) {
guard node.raw.kind == .\(raw: node.swiftSyntaxKind) else { return nil }
self._syntaxNode = node._syntaxNode
}
Expand All @@ -77,7 +77,7 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax {
"""
)

try! InitializerDeclSyntax("\(node.generateInitializerDeclHeader(optionalBaseAsMissing: false))") {
try! InitializerDeclSyntax("\(node.generateInitializerDeclHeader())") {
let parameters = ClosureParameterListSyntax {
for child in node.children {
ClosureParameterSyntax(firstName: .identifier(child.swiftName))
Expand Down Expand Up @@ -149,53 +149,6 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax {
ExprSyntax("self.init(data)")
}

if node.hasOptionalBaseTypeChild {
// TODO: Remove when we no longer support compiling in Swift 5.6. Change the
// above constructor to use `Optional<BaseType>.none` instead.
try! InitializerDeclSyntax(
"""
/// This initializer exists solely because Swift 5.6 does not support
/// `Optional<ConcreteType>.none` as a default value of a generic parameter.
/// The above initializer thus defaults to `nil` instead, but that means it
/// is not actually callable when either not passing the defaulted parameter,
/// or passing `nil`.
///
/// Hack around that limitation using this initializer, which takes a
/// `Missing*` syntax node instead. `Missing*` is used over the base type as
/// the base type would allow implicit conversion from a string literal,
/// which the above initializer doesn't support.
\(node.generateInitializerDeclHeader(optionalBaseAsMissing: true))
"""
) {
FunctionCallExprSyntax(callee: ExprSyntax("self.init")) {
TupleExprElementSyntax(label: "leadingTrivia", expression: ExprSyntax("leadingTrivia"))
for child in node.children {
if child.hasOptionalBaseType {
TupleExprElementSyntax(
leadingTrivia: .newline,
label: .identifier(child.swiftName),
colon: .colonToken(),
expression: ExprSyntax("Optional<\(raw: child.typeName)>.none")
)
} else if child.isUnexpectedNodes {
TupleExprElementSyntax(
leadingTrivia: .newline,
expression: ExprSyntax("\(raw: child.swiftName)")
)
} else {
TupleExprElementSyntax(
leadingTrivia: .newline,
label: .identifier(child.swiftName),
colon: .colonToken(),
expression: ExprSyntax("\(raw: child.swiftName)")
)
}
}
TupleExprElementSyntax(label: "trailingTrivia", expression: ExprSyntax("trailingTrivia"))
}
}
}

for (index, child) in node.children.enumerated() {
// ===================
// Children properties
Expand Down Expand Up @@ -306,7 +259,7 @@ private func generateSyntaxChildChoices(for child: Child) throws -> EnumDeclSynt
if let choiceNode = SYNTAX_NODE_MAP[choice.syntaxKind], choiceNode.isBase {
DeclSyntax(
"""
public init<Node: \(raw: choiceNode.name)Protocol>(_ node: Node) {
public init(_ node: some \(raw: choiceNode.name)Protocol) {
self = .\(raw: choice.swiftName)(\(raw: choiceNode.name)(node))
}
"""
Expand All @@ -323,7 +276,7 @@ private func generateSyntaxChildChoices(for child: Child) throws -> EnumDeclSynt
}
}

try! InitializerDeclSyntax("public init?<S: SyntaxProtocol>(_ node: S)") {
try! InitializerDeclSyntax("public init?(_ node: some SyntaxProtocol)") {
for choice in choices {
StmtSyntax(
"""
Expand Down Expand Up @@ -353,49 +306,35 @@ private func generateSyntaxChildChoices(for child: Child) throws -> EnumDeclSynt
}

fileprivate extension Node {
func generateInitializerDeclHeader(optionalBaseAsMissing: Bool) -> PartialSyntaxNodeString {
func generateInitializerDeclHeader() -> PartialSyntaxNodeString {
if children.isEmpty {
return "public init()"
}

var genericParamNames: [String: Int] = [:]
var genericParams: [String] = []

func createFunctionParameterSyntax(for child: Child) -> FunctionParameterSyntax {
var paramType: String
var paramType: TypeSyntax
if !child.kind.isNodeChoicesEmpty {
paramType = child.name
paramType = "\(raw: child.name)"
} else if child.hasBaseType {
if optionalBaseAsMissing {
paramType = "Missing\(child.typeName)"
} else {
// If we have a base type, make the initializer generic over its
// protocol instead.
let index = child.swiftName.index(child.swiftName.startIndex, offsetBy: 1)
paramType = child.swiftName[..<index].uppercased()

let paramCount = (genericParamNames[paramType] ?? 0) + 1
genericParamNames[paramType] = paramCount

if paramCount > 1 {
paramType += "\(paramCount)"
}
genericParams.append("\(paramType): \(child.typeName)Protocol")
}
paramType = "some \(raw: child.typeName)Protocol"
} else {
paramType = child.typeName
paramType = "\(raw: child.typeName)"
}

if child.isOptional {
paramType += "?"
if paramType.is(ConstrainedSugarTypeSyntax.self) {
paramType = "(\(paramType))?"
} else {
paramType = "\(paramType)?"
}
}

return FunctionParameterSyntax(
leadingTrivia: .newline,
firstName: child.isUnexpectedNodes ? .wildcardToken(trailingTrivia: .space) : .identifier(child.swiftName),
secondName: child.isUnexpectedNodes ? .identifier(child.swiftName) : nil,
colon: .colonToken(),
type: TypeSyntax(stringLiteral: paramType),
type: paramType,
defaultArgument: child.defaultInitialization
)
}
Expand All @@ -411,26 +350,10 @@ fileprivate extension Node {
.with(\.leadingTrivia, .newline)
}

if genericParams.isEmpty {
return """
public init(
\(params)
)
"""
} else {
let generics = GenericParameterClauseSyntax(
genericParameterList: GenericParameterListSyntax {
for param in genericParams {
GenericParameterSyntax(name: .identifier(param))
}
}
return """
public init(
\(params)
)

return """
public init\(generics)(
\(params)
)
"""
}
"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}

if let newLayout = newLayout {
if let newLayout {
// A child node was rewritten. Build the updated node.

// Sanity check, ensure the new children are the same length.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,15 @@ let syntaxTransformFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {

DeclSyntax(
"""
public func visit<T: SyntaxChildChoices>(_ node: T) -> ResultType {
public func visit(_ node: some SyntaxChildChoices) -> ResultType {
return visit(Syntax(node))
}
"""
)

DeclSyntax(
"""
public func visitChildren<SyntaxType: SyntaxProtocol>(_ node: SyntaxType) -> [ResultType] {
public func visitChildren(_ node: some SyntaxProtocol) -> [ResultType] {
let syntaxNode = Syntax(node)
return NonNilRawSyntaxChildren(syntaxNode, viewMode: .sourceAccurate).map { rawChild in
let child = Syntax(SyntaxData(rawChild, parent: syntaxNode))
Expand Down
Loading