Design Priorities for the Swift 6 Language Mode

Would those be breaking changes? If not, they could be in Swift 6 but would not be relevant to this thread about the Swift 6 language mode.

1 Like

It looks like #3 that you linked is related to SE-0384 that's currently in review, so please make sure to offer any input you have there as well.

3 Likes

I don't have enough swift compiler knowledge to estimate if those would be a breaking changes or not, but to my judging, if according to this comment the proper way of supporting ObjC forward declarations is to have an index of ObjC type names in Swift, it may affect the swift module format. Deterministic builds support, if it involves changing the way how and/or where the include paths are stored, might affect the swift module format as well. Parallelization of module loading by lldb might require the change of the module format, too. So it would be great if these issues can be carefully considered and taken into account in terms of

  1. what is the vision for the solution to them, and
  2. should the solution be prioritized and implemented as a part of the Swift 6 scope.

Hi @edudnyk,

This discussion is specifically focused on the Swift 6 language mode.

I suspect I'm not alone in that I'm not entirely sure what a "language mode" is.

7 Likes

This is explained in the post itself at length. Indeed, that’s kind of the central point of the post.

I was going to quote some relevant parts of it here but it would end up being just cutting and pasting entire paragraphs, so instead please refer to them above.

The briefest relevant snippet, I suppose, would be that the Swift 6 language mode is:

a targeted set of source-incompatible changes to the language. . . . Most features do not fall in this category, [including] major efforts that are underway . . . such as the ownership model or constant evaluation

2 Likes

It’s unclear whether or not the features @edudnyk has described, which seem to have an underlying theme of “build system extensibility”, would need to be confined to a new language mode. Doesn’t that make it in-bounds for this thread?

The original post certainly has lots of details. I just feel like the concept of what a language mode actually is gets lost. Is it a compiler setting? Or a more abstract concept?

It’s a compiler setting. It already exists today; that’s how the compiler decides whether to make sendability issues warnings (Swift 5.6 language mode) or errors (5.7 language mode).

2 Likes

That's what I suspected, but I wasn't totally sure. Thanks.

One thing I'd love to see addressed in Swift 6 is C-interop, particularly concerning pointers to forward-declared structs, known in Swift only as OpaquePointer.

Losing all the type info for C APIs that use this pattern (which are, in my limited experience, rather common) makes working with them rather annoying.

This blog post describes the situation in more detail.

The blog post also says changing this would be both API- and ABI-breaking, so I'm not sure this is actually addressable even in a new language mode, but I thought I'd bring it up in case folks agree this is worth the API break and we can find some way to avoid breaking ABI.

9 Likes

Might the ongoing C++ integration work benefit this?

That's certainly something that would require a new language mode, and as you note we'd have to navigate the ABI challenges as well as the source incompatibility. That said, I think this is something that could be considered for Swift 6.

Doug

11 Likes

This isn't quite accurate. The compiler setting (SWIFT_VERSION or Swift Language Version in Xcode, -swift-version to the compiler) only supports 4, 4.2, and 5 at this time. Things like the changes you mention (sendability warnings) are gated by compiler version (you get the new warnings using the new compiler), not the compiler's Swift version setting. IIRC, the Swift 6 compiler will move to supporting 5 (or perhaps a later version like 5.8) and 6 as language "modes", with all of the new behavior enabled under the 6 mode.

For sendability errors, the level of checking is controlled by the SWIFT_STRICT_CONCURRENCY setting (or whatever the command line equivalent is) as well as other compiler flags. And like I said, it also changes between compiler versions as the rules are refined.

@Jon_Shier, there is no need to speculate or recall from memory: the original post spells out the correct answer about Sendable checking and future language mode support explicitly—

1 Like

I’m the one who incorrectly recalled from memory.

Looking at what you quoted, I'm not sure it's clear. It would be good to clarify how language versions work and exactly what the implications for sendability checking really are. I'll try to clarify here.

Language Version Support

The Swift compiler supports building using a specific language version (aka language mode), which facilitates compatibility with older language releases. Currently (Swift 5.7), the supported language versions are 4, 4.2, and 5. These versions are not equivalent to building using an older version of the compiler but should be backward compatible (they are not forward compatible as the newer compiler allows things, even when building for an older version, that the older version does not support).

You can pass a version to the compiler using the -swift-version flag (-swift-version 5) or by setting the "Swift Language Version" (SWIFT_VERSION) setting in Xcode.

When Swift 6 is released, the available versions will be 4, 5, and 6.

Open question: what will be the difference between the current 4 and 4.2 versions and the Swift 6 version 4 support? Is that support even necessary anymore?

Sendability Checking and Language Versions

This is a little more unclear. Currently, there are various flags in the Swift 5.5 and later compilers to allow control over various aspects of the compiler's concurrency safety checking. In 5.6 and later compiler versions, the -strict-concurrency option ("Strict Concurrency Checking" or SWIFT_STRICT_CONCURRENCY in Xcode) can be used to enable more compiler checking of concurrency safety with minimal, targeted, and complete settings (-strict-concurrency=minimal), with minimal the default. In Swift 6, the equivalent of complete will become the default. There are also other compiler settings which control concurrency features but it's unclear how those settings will be affected in Swift 6.

Confusingly, the OP states:

Presumably this doesn't actually mean "disabled" as in "turned off", as that would be a regression from the current compiler. Instead, it seems like it should mean the default falls back to minimal rather than complete, with the option to reenable complete checking even when building in version 5. But this definitely needs to be clarified.

2 Likes

I've gone back and added "4.2" to the list in the original post, because it is a supported language version. The differences between 4 and 4.2 are quite minor.

Whether Swift 4 and 4.2 will be supported in future compiler versions is up to the maintainers of the Swift compiler, and should be decided based on data about how prevalent Swift 4/4.2 code are in the ecosystem and weighed against the benefits of having fewer language modes to support. From a technical standpoint, very little changed from Swift 4 -> 4.2 -> 5, and 6 would be the first real jump since the tumultuous days before Swift 4.

It means that'll be downgraded to warnings or suppressed entirely; I've updated the post to try to clarify that.

Doug

3 Likes

I've noticed previously that -enable-actor-data-race-checks is very blunt - it appears to add a preamble to literally every actor-isolated partial function, even when actor isolation should be able to be proven statically.

Will the implementation be improved to limit runtime checks, or is the plan to enable it as it currently is?

Example. Calling one @MainActor function from another @MainActor function:

Godbolt

@MainActor
func funcOne() async -> Int {
  funcTwo()
}

@MainActor
func funcTwo() -> Int {
  return 42
}

// Compiling with -O (no data race checks)

(1) suspend resume partial function for output.funcOne() async -> Swift.Int:
        push    rax
        mov     rdi, qword ptr [r14 + 16]
        call    swift_release@PLT
        mov     rax, qword ptr [r14 + 8]
        mov     edi, 42                     ; <-- The result
        pop     rcx
        jmp     rax

// Compiling with -O -enable-actor-data-race-checks

(1) suspend resume partial function for output.funcOne() async -> Swift.Int:
        push    r15
        push    rbx
        push    rax
        mov     rbx, qword ptr [r14 + 16]
        mov     r15, qword ptr [r14 + 32]
        mov     r13, rbx
        call    ($sScM6sharedScMvgZ)@PLT               ; static Swift.MainActor.shared.getter
        mov     r13, rax
        mov     rdi, rbx
        mov     rsi, r15
        call    ($sScA15unownedExecutorScevgTj)@PLT    ; dispatch thunk of Swift.Actor.unownedExecutor.getter
        mov     rbx, rax
        mov     r15, rdx
        mov     rdi, rax
        mov     rsi, rdx
        call    swift_task_isCurrentExecutor@PLT       ; runtime call
        test    al, 1
        jne     .LBB2_2
        lea     rdi, [rip + ".L.str.20.output/example.swift"]
        mov     esi, 20
        mov     ecx, 7
        mov     edx, 1
        mov     r8, rbx
        mov     r9, r15
        call    swift_task_reportUnexpectedExecutor@PLT
.LBB2_2:
        mov     rbx, qword ptr [r14 + 24]
        mov     rdi, r13
        call    swift_release@PLT
        mov     rdi, rbx
        call    swift_release@PLT
        mov     rax, qword ptr [r14 + 8]
        mov     edi, 42                     ; <-- The result
        add     rsp, 8
        pop     rbx
        pop     r15
        jmp     rax

I'd like to mention one thing that would help us develop a package ecosystem that is more robust: non-exhaustive enums. Even if just an option.

We also have a problem with packages that use non-standard language features (e.g. @_exported import, _modify, @inline(__always)). I hope that is also on the list of things to address when it comes to the long-term health of the package ecosystem.

7 Likes

Oh and one more thing: the Unicode organisation is preparing a new technical standard, describing best practices for handling Unicode in source code. If we're going to be making breaking changes with Swift 6, it may also be worth considering whether we should make any changes in light of these recommendations.

Some of the changes may have an impact on parsing (which may be different to how Swift currently parses source code and hence be a breaking change), allowed identifiers, etc.

The current draft is here:

https://www.unicode.org/reports/tr55/proposed.html

10 Likes