Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
adc9f33
Make `SyntaxArena` SPI
rintaro Jan 2, 2025
13d758a
Describe an RFC process to request feedback for public API changes
ahoppen Sep 29, 2024
0082a7f
Merge pull request #2930 from rintaro/syntax-arena-spi
rintaro Jan 7, 2025
b64f80d
[Syntax] Use BumpPtrAllocator for Syntax node internals
rintaro Dec 17, 2024
8fff0de
Workaround for rdar://141977987
rintaro Dec 24, 2024
6a8b21a
Merge pull request #2925 from rintaro/syntax-data-arena
rintaro Jan 7, 2025
d3157cc
Remove default values for leftParen and rightParen parameters in the …
TTOzzi Jan 8, 2025
71e1cee
Revert "[Syntax] Use BumpPtrAllocator for Syntax node internals"
rintaro Jan 9, 2025
56a746d
Merge pull request #2931 from TTOzzi/fix-FunctionCallExprSyntax-build…
ahoppen Jan 9, 2025
a57f3be
Merge pull request #2933 from swiftlang/revert-2925-syntax-data-arena
rintaro Jan 9, 2025
4dbdae7
Revert "Revert "[Syntax] Use BumpPtrAllocator for Syntax node interna…
rintaro Jan 9, 2025
aac9d60
Merge pull request #2863 from ahoppen/rfc-process
ahoppen Jan 9, 2025
f5e0fa1
Merge pull request #2934 from swiftlang/revert-2933-revert-2925-synta…
rintaro Jan 9, 2025
37fa0c8
Allow custom derivate registration for _modify accessors (#2932)
asl Jan 10, 2025
b069dbf
Add `unsafe` expression syntax under an experimental feature flag `un…
DougGregor Jan 10, 2025
dd45e8d
Regenerate with the addition of UnsafeExprSyntax
DougGregor Jan 10, 2025
33db278
Parse `unsafe` expression
DougGregor Jan 10, 2025
3883e3c
[Syntax] Let SyntaxIdentifier use RawSyntax.ID directly
rintaro Jan 8, 2025
090945d
[Perf] Optimize TokenSequence
rintaro Jan 11, 2025
68852dc
Reformat
DougGregor Jan 11, 2025
2f1a271
Merge pull request #2937 from DougGregor/unsafe-expression
DougGregor Jan 11, 2025
00f5b14
Merge pull request #2938 from rintaro/syntaxidentifier-root-id
rintaro Jan 11, 2025
f0db832
Merge pull request #2939 from rintaro/perf-token-sequence
rintaro Jan 13, 2025
de9eb3b
Compute the lexical context of an accessor macro based on the pre-rew…
ahoppen Jan 10, 2025
fd232f9
Merge pull request #2936 from ahoppen/closure-in-accessor
ahoppen Jan 15, 2025
f679ae9
[Syntax] Use no-op PlatformMutex implemtation for wasm32-unknown-wasi
rintaro Jan 20, 2025
3751769
Merge remote-tracking branch 'origin/main' into 2944-test
kkebo Jan 20, 2025
e5692b4
Merge remote-tracking branch 'rintaro/wasi-nothread' into 2944-test
kkebo Jan 20, 2025
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
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,13 @@ Once you've pushed your branch, you should see an option on this repository's pa
> [!TIP]
> If you are stuck, it’s encouraged to submit a PR that describes the issue you’re having, e.g. if there are tests that are failing, build failures you can’t resolve, or if you have architectural questions. We’re happy to work with you to resolve those issue.

## Opening a PR for Release Branch
### Opening a PR for Release Branch

See the [dedicated section][section] on the Swift project website.
See the [dedicated section](https://www.swift.org/contributing/#release-branch-pull-requests) on the Swift project website.

[section]: https://www.swift.org/contributing/#release-branch-pull-requests
## Changing public API

If you are modifying public API, request feedback for these changes from the community by opening a RFC as described by the [RFC Process](Contributor%20Documentation/RFC%20Process.md).

## Review and CI Testing

Expand Down
2 changes: 1 addition & 1 deletion CodeGeneration/Sources/SyntaxSupport/AttributeNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ public let ATTRIBUTE_NODES: [Node] = [
),
Child(
name: "accessorSpecifier",
kind: .token(choices: [.keyword(.get), .keyword(.set)]),
kind: .token(choices: [.keyword(.get), .keyword(.set), .keyword(._modify)]),
documentation: "The accessor name.",
isOptional: true
),
Expand Down
7 changes: 7 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/Child.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ public class Child: NodeChoiceConvertible {
/// Whether this child is optional and can be `nil`.
public let isOptional: Bool

/// Whether this child provides a default value when used as a parameter in a function.
public let providesDefaultInitialization: Bool

public let experimentalFeature: ExperimentalFeature?

/// A name of this child that can be shown in diagnostics.
Expand Down Expand Up @@ -303,6 +306,7 @@ public class Child: NodeChoiceConvertible {
nameForDiagnostics: String? = nil,
documentation: String? = nil,
isOptional: Bool = false,
providesDefaultInitialization: Bool = true,
newerChildPath: [Child] = []
) {
precondition(name.first?.isLowercase ?? true, "The first letter of a child’s name should be lowercase")
Expand All @@ -314,6 +318,7 @@ public class Child: NodeChoiceConvertible {
self.documentationSummary = SwiftSyntax.Trivia.docCommentTrivia(from: documentation)
self.documentationAbstract = String(documentation?.split(whereSeparator: \.isNewline).first ?? "")
self.isOptional = isOptional
self.providesDefaultInitialization = providesDefaultInitialization
}

/// Create a node that is a copy of the last node in `newerChildPath`, but
Expand All @@ -329,6 +334,7 @@ public class Child: NodeChoiceConvertible {
self.documentationSummary = other.documentationSummary
self.documentationAbstract = other.documentationAbstract
self.isOptional = other.isOptional
self.providesDefaultInitialization = other.providesDefaultInitialization
}

/// Create a child for the unexpected nodes between two children (either or
Expand All @@ -353,6 +359,7 @@ public class Child: NodeChoiceConvertible {
nameForDiagnostics: nil,
documentation: nil,
isOptional: true,
providesDefaultInitialization: true,
newerChildPath: newerChildPath
)
}
Expand Down
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
23 changes: 21 additions & 2 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 Expand Up @@ -944,7 +961,8 @@ public let EXPR_NODES: [Node] = [
Child(
name: "leftParen",
kind: .token(choices: [.token(.leftParen)]),
isOptional: true
isOptional: true,
providesDefaultInitialization: false
),
Child(
name: "arguments",
Expand All @@ -954,7 +972,8 @@ public let EXPR_NODES: [Node] = [
Child(
name: "rightParen",
kind: .token(choices: [.token(.rightParen)]),
isOptional: true
isOptional: true,
providesDefaultInitialization: false
),
Child(
name: "trailingClosure",
Expand Down
1 change: 1 addition & 0 deletions CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift
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
2 changes: 1 addition & 1 deletion CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ extension Child {
/// ` = default_value` that can be used as the default value to for a
/// function parameter. Otherwise, return `nil`.
public var defaultInitialization: InitializerClauseSyntax? {
if let defaultValue {
if providesDefaultInitialization, let defaultValue {
return InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: defaultValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ allows Swift tools to parse, inspect, generate, and transform Swift source code.
### Internals

- <doc:SwiftSyntax/SyntaxProtocol>
- <doc:SwiftSyntax/SyntaxArena>
- <doc:SwiftSyntax/SyntaxEnum>
- <doc:SwiftSyntax/SyntaxHashable>
- <doc:SwiftSyntax/SyntaxIdentifier>
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
"""
)

DeclSyntax(
"""
/// 'Syntax' object factory recycling 'Syntax.Info' instances.
private let nodeFactory: SyntaxNodeFactory = SyntaxNodeFactory()
"""
)

DeclSyntax(
"""
public init(viewMode: SyntaxTreeViewMode = .sourceAccurate) {
Expand Down Expand Up @@ -330,11 +323,11 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
// with 'Syntax'
var rewrittens: ContiguousArray<RetainedSyntaxArena> = []

for case let (child?, info) in RawSyntaxChildren(node) where viewMode.shouldTraverse(node: child) {
for case let childDataRef? in node.layoutBuffer where viewMode.shouldTraverse(node: childDataRef.pointee.raw) {

// Build the Syntax node to rewrite
var childNode = visitImpl(nodeFactory.create(parent: node, raw: child, absoluteInfo: info))
if childNode.raw.id != child.id {
let childNode = visitImpl(Syntax(arena: node.arena, dataRef: childDataRef))
if childNode.raw.id != childDataRef.pointee.raw.id {
// The node was rewritten, let's handle it

if newLayout.baseAddress == nil {
Expand All @@ -345,13 +338,10 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}

// Update the rewritten child.
newLayout[Int(info.indexInParent)] = childNode.raw
newLayout[Int(childDataRef.pointee.absoluteInfo.layoutIndexInParent)] = childNode.raw
// Retain the syntax arena of the new node until it's wrapped with Syntax node.
rewrittens.append(childNode.raw.arenaReference.retained)
}

// Recycle 'childNode.info'
nodeFactory.dispose(&childNode)
}

if newLayout.baseAddress != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ let syntaxVisitorFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
try! ClassDeclSyntax("open class SyntaxVisitor") {
DeclSyntax("public let viewMode: SyntaxTreeViewMode")

DeclSyntax(
"""
/// 'Syntax' object factory recycling 'Syntax.Info' instances.
private let nodeFactory: SyntaxNodeFactory = SyntaxNodeFactory()
"""
)

DeclSyntax(
"""
public init(viewMode: SyntaxTreeViewMode) {
Expand Down Expand Up @@ -221,10 +214,8 @@ let syntaxVisitorFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
DeclSyntax(
"""
private func visitChildren(_ node: Syntax) {
for case let (child?, info) in RawSyntaxChildren(node) where viewMode.shouldTraverse(node: child) {
var childNode = nodeFactory.create(parent: node, raw: child, absoluteInfo: info)
dispatchVisit(childNode)
nodeFactory.dispose(&childNode)
for case let childDataRef? in node.layoutBuffer where viewMode.shouldTraverse(node: childDataRef.pointee.raw) {
dispatchVisit(Syntax(arena: node.arena, dataRef: childDataRef))
}
}
"""
Expand Down
33 changes: 33 additions & 0 deletions Contributor Documentation/RFC Process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# RFC Process

We gather community feedback for all changes to swift-syntax’s public API to keep it clean and usable. Everybody is encouraged to share their thoughts on the RFC posts.

Public API changes are:
- New APIs
- Changes to API behavior that are not considered bugfixes
- Deprecations of public API
- API-incompatible changes, like changing the type of a public variable
- Declarations marked with `@_spi` are not considered part of the public API and don’t require an RFC.

## The RFC post

The RFC process should contain the following.
- **Summary**: A short summary of the changes. If it is not obvious, what motivated this change?
- **Link to PR**: Link to the pull request that implements the API change.
- **Swift Interface**: The changed API in a Swift Interface style notation.
- For new API this should contain the new API’s signature and its doc comment.
- If the change affects existing API, the old API’s signature should also be included in the RFC post for reference.
- **For new API**: If this is new API, justify why this is this a worthwhile addition to swift-syntax. A good guideline is to answer the following questions.
- **Commonality**: Do you expect this API to be widely used? Is it applicable in a variety of contexts?
- **Discoverability**: Will users of swift-syntax easily find this new API for the operations they want to achieve?
- **Not trivially composable**: Can the desired behavior be achieved using existing public API? If yes, is this new API superior because one of the following reasons?
- **Readability**: Is the proposed new API easier to understand than the composed alternative?
- **Correctness and performance issues**: Does the naive implementation using existing API have any correctness or performance issues that would be covered correctly by the new API.
- **For existing API**: If this is modifying existing API, do you expect many clients to be affected by the change?
- **Migration**: What are the migration steps needed to migrate to the new API?

Make sure to also include the change in `Release Notes/<version>.md`.

## The RFC process

After posting the RFC in the [swift-syntax category on the Swift forums](https://forums.swift.org/c/development/swift-syntax/112), you can merge the PR. You are expected to incorporate any feedback from the RFC in a timely manner.
12 changes: 12 additions & 0 deletions Release Notes/602.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
- Migration steps: Replace uses of `ExpandEditorPlaceholdersToTrailingClosures` with `ExpandEditorPlaceholdersToLiteralClosures`. The initializer does not need to change: `.init(indentationWidth:)` on the new type provides the same behavior as the old type.
- Notes: This improves code completion in a SourceKitLSP session where the trailing closure form may be undesirable. The nested placeholders offer more flexibility to end users, in editors that support it.

- `SyntaxArena` and `ParsingSyntaxArena` has changed to SPI
- Description: `SyntaxArena` and the subclasses were only meant to be used when dealing with `RawSyntax` which is also SPI.
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2930
- Migration steps: Do not use `SyntaxArena` or `ParsingSyntaxArena` directly.
- Notes: Although the type itself was `public`, most initializers were already SPI and there was no way to retrive them from existing types via public API.

- `SyntaxChildrenIndex` is no longer `ExpressibleByNilLiteral`
- Description: `nil` used to represent the end index. However, due to a change in the internal structure, the end index must now be retrieved from the collection.
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2925
- Migration steps: Use `SyntaxChildren.endIndex` instead.
- Notes: `ExpressibleByNilLiteral` was a mistake. In general, `Collection.Index` should only be created and managed by the collection itself. For example, `Collection.index(after:)` exists, but `Index.advanced(by:)` does not.

## Template

- *Affected API or two word description*
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
7 changes: 6 additions & 1 deletion Sources/SwiftParser/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,12 @@ extension Parser {
let unexpectedBeforeAccessor: RawUnexpectedNodesSyntax?
let accessor: RawTokenSyntax?
if period != nil {
(unexpectedBeforeAccessor, accessor) = self.expect(.keyword(.get), .keyword(.set), default: .keyword(.get))
(unexpectedBeforeAccessor, accessor) = self.expect(
.keyword(.get),
.keyword(.set),
.keyword(._modify),
default: .keyword(.get)
)
} else {
(unexpectedBeforeAccessor, accessor) = (nil, nil)
}
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
7 changes: 1 addition & 6 deletions Sources/SwiftParser/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,23 +303,18 @@ public struct Parser {
/// if this is `nil`.
/// - parseTransition: The previously recorded state for an incremental
/// parse, or `nil`.
/// - arena: Arena the parsing syntax are made into. If it's `nil`, a new
/// arena is created automatically, and `input` copied into the
/// arena. If non-`nil`, `input` must be within its registered
/// source buffer or allocator.
public init(
_ input: UnsafeBufferPointer<UInt8>,
maximumNestingLevel: Int? = nil,
parseTransition: IncrementalParseTransition? = nil,
arena: ParsingSyntaxArena? = nil,
swiftVersion: SwiftVersion? = nil
) {
// Chain to the private buffer initializer.
self.init(
buffer: input,
maximumNestingLevel: maximumNestingLevel,
parseTransition: parseTransition,
arena: arena,
arena: nil,
swiftVersion: swiftVersion,
experimentalFeatures: []
)
Expand Down
Loading
Loading