Skip to content

Commit 38f9b2b

Browse files
committed
Add a version indicator macro to indicate the swift-syntax version a client is building against
All swift-syntax versions ≥ 509 will include a module `SwiftSyntax509` and all swift-syntax versions ≥ 510 will include both `SwiftSyntax509` and `SwiftSyntax510`. This way clients can check which version of swift-syntax they are building against using e.g. ```swift #if canImport(SwiftSyntax510) // code specific to swift-syntax version >= 510 #else // code for swift-syntax < 510 #endif ```
1 parent 4294feb commit 38f9b2b

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

Package.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ let package = Package(
146146

147147
.target(
148148
name: "SwiftSyntax",
149-
dependencies: [],
149+
dependencies: ["SwiftSyntax509"],
150150
exclude: ["CMakeLists.txt"],
151151
swiftSettings: swiftSyntaxSwiftSettings
152152
),
@@ -156,6 +156,13 @@ let package = Package(
156156
dependencies: ["_SwiftSyntaxTestSupport", "SwiftSyntax", "SwiftSyntaxBuilder"]
157157
),
158158

159+
// MARK: Verison marker modules
160+
161+
.target(
162+
name: "SwiftSyntax509",
163+
dependencies: []
164+
),
165+
159166
// MARK: SwiftSyntaxBuilder
160167

161168
.target(

Sources/SwiftSyntax/Documentation.docc/Macro Versioning.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,36 @@ Guidance of how to version macros when a new major swift-syntax version is relea
44

55
## Summary
66

7-
Update the minor version of a macro when updating its swift-syntax version dependency.
7+
A macro can depend on multiple versions of swift-syntax. If it is affected by source-breaking changes in swift-syntax, it can check the version of swift-syntax it is compiling against using e.g. `#if canImport(SwiftSyntax510)`.
88

99
## Detailed Explanation
1010

1111
All the ideas described in the following apply to all packages that depend on swift-syntax, not only macros.
1212

13-
For simplicity, this article assumes that `509` is the current swift-syntax version and `510` the next, but everything applies to any other major swift-syntax version update, including version jumps to `600`.
13+
For simplicity, this article assumes that 509 is the current swift-syntax version and 510 the next, but everything applies to any other major swift-syntax version update, including version jumps to e.g. 600.
1414

15-
When starting to write a macro, no special considerations need to be made with regard to versioning. Depending on swift-syntax as with `from: "509.0.0"` will make sure that the macro receives any bug fix updates to swift-syntax 509. For example, a macro depending on swift-syntax 509 might be released as version 1.0, 1.2, 2.0, …
15+
Any given version macro can depend on multiple major swift-syntax versions at once. For example, if a macro supports both swift-syntax 509 and swift-syntax 510 may declare its dependency on swift-syntax as
1616

17-
When swift-syntax releases version 510, the macro should release a new minor release in which it updates the swift-syntax dependency to `from: "510.0.0"`. For the sake of this example, let’s assume that the macro raises its version from 1.2 to 1.3 during this step.
17+
```
18+
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"..<"511.0.0"),
19+
```
1820

19-
Any client package that depends on the macro using an `from: "1.0"` and doesn’t have any other transitive dependencies on swift-syntax will automatically receive version `1.3` of the macro when updating the package dependencies using `swift package update` or Xcode’s *Update to Latest Package Versions* command.
21+
In order to handle breaking API changes, clients can wrap uses of such APIs in conditional compilation clauses that check the version of swift-syntax it is building against. All versions of swift-syntax ≥ 509 will include an empty `SwiftSyntaxVersion509` module, swift-syntax ≥ 510 will include both a `SwiftSyntaxVersion510` and `SwiftSyntaxVersion509` module, and so on for any new releases. This allows clients to write
2022

21-
Should a client depend on another macro, which hasn’t released a new version that depends on swift-syntax 510 yet, then SwiftPM will continue to select version 1.2 for the macro. In order for the client to update to version 1.3 of the macro, all macros need to release a version that is compatible with swift-syntax 510. The macro can continue to deliver updates for those clients by creating patch releases such as 1.2.1.
23+
```swift
24+
#if canImport(SwiftSyntax510)
25+
// code specific to swift-syntax version >= 510
26+
#elseif canImport(SwiftSyntax509)
27+
// code to support swift-syntax version 509
28+
#else
29+
// code for swift-syntax < 509. Not needed for macros since macros require swift-syntax >= 509.
30+
#endif
31+
```
2232

23-
It is possible to mix-and-match swift-syntax and Swift compiler versions, i.e. swift-syntax 509 will also work with a Swift 5.10 compiler and a Swift 5.9 compiler works with swift-syntax 510 because swift-syntax is just an ordinary package dependency.
33+
The `SwiftSyntax<version>` modules are empty and don’t contain any code. Their only purpose is to serve as targets for the `canImport` checks.
2434

2535
## Representation of New Syntax with Old swift-syntax Versions
2636

27-
If a swift-syntax verison is used that is older than the compiler’s version, then swift-syntax will not be able to represent the new syntactic structures (like new statements) in the source file because it doesn’t know about them.
37+
If a swift-syntax version is used that is older than the compiler’s version, then swift-syntax will not be able to represent the new syntactic structures (like new statements) in the source file because it doesn’t know about them.
2838

2939
In this case, swift-syntax will represent the unknown syntactic constructs as a mixture of unexpected syntax nodes in the `unexpected*` children of the syntax nodes. Depending on the macro’s behavior this might not pose any issues. For example, if the macro adds an completion-handler alternative to an async function, it most likely doesn’t care if some statement in the body couldn’t be parsed, since it is only interested in the signature.

Sources/SwiftSyntax509/Empty.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// The SwiftSyntax509 module is intentionally empty.
2+
// It serves as an indicator which version of swift-syntax a package is building against.
3+
// See the 'Macro Versioning.md' document for more details.

0 commit comments

Comments
 (0)