Skip to content

Migrate to Swift 6 language mode#1

Merged
0xLeif merged 91 commits into
mainfrom
swift-6-migration
Jul 7, 2026
Merged

Migrate to Swift 6 language mode#1
0xLeif merged 91 commits into
mainfrom
swift-6-migration

Conversation

@0xLeif

@0xLeif 0xLeif commented Dec 10, 2025

Copy link
Copy Markdown

This pull request introduces several improvements and refactorings to the resource management, concurrency, and actor isolation in the GateEngine codebase. The main focus is on adding @unchecked Sendable and @MainActor annotations to key classes and methods, ensuring safer concurrency and clearer actor isolation, particularly for font, audio, and rendering resources. Additionally, test setup methods are modernized to support async execution, and some protocol and extension implementations are refactored for clarity and safety.

Concurrency and Actor Isolation

  • Added @unchecked Sendable and @MainActor annotations to resource classes such as OldResource, Font, AudioBuffer, AudioContext, ActiveMusic, and ActiveSound, improving concurrency safety and ensuring proper actor isolation for UI and resource operations. [1] [2] [3] [4] [5] [6]
  • Updated font-related initializers and static properties to use @MainActor, and refactored async font loading to run on the main actor, preventing thread-safety issues in UI-related resource initialization. [1] [2] [3]

Audio System Improvements

  • Refactored music and sound playback methods to run on the main actor, removed unnecessary detached tasks, and ensured platform-specific logic is handled correctly. [1] [2] [3]
  • Marked CABufferReference as @unchecked Sendable and updated its async initialization to use a @Sendable closure, improving safety and clarity in audio buffer management. [1] [2]

Platform and Resource Protocols

  • Updated PlatformProtocol and platform extensions to require @MainActor for font lookup, ensuring that font operations are consistently actor-isolated across platforms. [1] [2] [3]

Rendering and Touch Resource Refactoring

  • Marked RenderTarget and its protocols as @MainActor, and added nonisolated Equatable and Hashable implementations for RenderTarget, clarifying ownership and thread safety for rendering resources. [1] [2]
  • Refactored Touch resource extensions to use nonisolated, improving clarity and safety for value semantics.

Test Suite Modernization

  • Updated test setup methods to support async execution and marked test classes as @MainActor, modernizing the test suite for better concurrency support. [1] [2] [3] [4] [5] [6] [7]

Other

  • Updated Swift language mode to .v6 in the package manifest for compatibility with the latest Swift features.
  • Refactored IOKit gamepad callbacks to use MainActor.assumeIsolated instead of spawning tasks, improving correctness and performance for HID event handling. [1] [2]

- Change swiftLanguageModes from [.v5] to [.v6] in Package.swift
- Add @unchecked Sendable to resource classes (OldResource, Font, AudioBuffer, AudioContext, ActiveMusic, ActiveSound, CABufferReference)
- Fix MainActor isolation for Font static properties and initializers
- Fix Music.play() and Sound.play() to be @mainactor
- Use MainActor.assumeIsolated for IOKit callbacks instead of Task
- Add nonisolated extension for Touch Equatable/Hashable conformances
- Add @mainactor to RenderTarget protocol conformances
- Fix test files with @mainactor and async setUp methods

All 495 tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request migrates the GateEngine codebase to Swift 6 language mode by introducing comprehensive concurrency annotations and actor isolation improvements. The migration ensures thread safety through @unchecked Sendable conformances, enforces @MainActor isolation for UI and resource operations, and modernizes async patterns throughout the audio, rendering, and platform systems.

  • Updates Swift language mode to .v6 in Package.swift
  • Adds @MainActor and @unchecked Sendable annotations to resource classes and protocols for proper concurrency safety
  • Refactors audio and rendering operations to use direct Game.shared access on @MainActor instead of detached tasks
  • Modernizes IOKit callbacks to use MainActor.assumeIsolated for better performance and correctness

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Package.swift Updates Swift language mode from .v5 to .v6
Tests/GravityTests/_GravityXCTestCase.swift Marks runGravity as @MainActor, removes unnecessary await from Gravity() init since it's now in MainActor context
Tests/GravityTests/Unittest/*.swift Adds @MainActor annotations to test classes for consistency with Gravity API requirements
Tests/GateEngineTests/Gravity/*.swift Updates setUp() methods to async throws signature for modern test lifecycle
Sources/GateEngine/Resources/Resource.swift Adds @unchecked Sendable conformance to OldResource base class
Sources/GateEngine/Resources/Text/Font.swift Adds @unchecked Sendable conformance, marks initializers and static properties as @MainActor, refactors async initialization to run on MainActor
Sources/GateEngine/System/Audio/AudioContext.swift Adds @unchecked Sendable conformance
Sources/GateEngine/System/Audio/AudioBuffer.swift Adds @unchecked Sendable conformance
Sources/GateEngine/System/Audio/Music.swift Marks ActiveMusic as @unchecked Sendable, refactors play() to be @MainActor and use direct Game.shared access
Sources/GateEngine/System/Audio/Sound.swift Marks ActiveSound as @unchecked Sendable, refactors play() to be @MainActor and use direct Game.shared access
Sources/GateEngine/System/Audio/Platforms/Backends/CoreAudio/CABufferReference.swift Adds @unchecked Sendable conformance, changes Task.detached to Task { @Sendable in }
Sources/GateEngine/System/Platforms/PlatformProtocol.swift Marks font(named:) method as @MainActor in protocol and default implementation
Sources/GateEngine/System/Rendering/RenderTarget.swift Adds explicit @MainActor protocol conformance qualifiers, implements nonisolated Equatable and Hashable conformances
Sources/GateEngine/System/HID/Touch/Touch.swift Adds nonisolated to extension declarations, removes redundant nonisolated from individual methods
Sources/GateEngine/System/HID/GamePad/GamePadInterpreter/Interpreters/HID/IOKitGamePadInterpreter.swift Refactors gamepad callbacks to use MainActor.assumeIsolated instead of spawning tasks, uses nonisolated(unsafe) for C type capture

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

0xLeif and others added 26 commits December 9, 2025 19:40
In Swift 6, the protocol requirement `@MainActor func font(named:)` in
PlatformProtocol requires explicit implementation in each conforming type,
rather than relying on a default implementation.

Added the method to:
- LinuxPlatform
- Win32Platform
- WASIPlatform
- UIKitPlatform

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
LinuxPlatform, Win32Platform, and WASIPlatform are classes with stored
properties (staticResourceLocations, pathCache). Since PlatformProtocol
requires Sendable conformance, these classes need @unchecked Sendable.

The conformance is safe because:
- staticResourceLocations is a let property initialized once at init
- pathCache (WASI only) is only accessed from MainActor-isolated methods

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
LinuxPlatform was missing SynchronousFileSystem support which is required
by PlatformProtocol when GATEENGINE_PLATFORM_HAS_SynchronousFileSystem is
defined (all platforms except WASI).

This adds:
- SynchronousLinuxFileSystem: conforms to SynchronousFileSystem protocol
  with Linux-specific pathForSearchPath implementation
- synchronousFileSystem static property on LinuxPlatform
- synchronousLocateResource and synchronousLoadResource methods

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
LinuxPlatform and Win32Platform were calling getStaticSearchPaths(delegate:)
which doesn't exist - the actual function is getStaticSearchPaths() with no
arguments (defined in PlatformProtocol.swift extension).

Changed to match the pattern used by AppKitPlatform and UIKitPlatform:
initialize staticResourceLocations directly at declaration time.

This was a pre-existing bug in the upstream codebase that prevented
Linux and Windows builds from compiling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- LinuxFileSystem now correctly conforms to AsynchronousFileSystem
  (was incorrectly conforming to non-existent FileSystem protocol)
- Added proper conditional compilation guards
- Changed Game.shared to Game.unsafeShared for non-MainActor context
- Added setCursorStyle stub to LinuxPlatform (required by InternalPlatformProtocol)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Code fixes:
- X11Window.swift: Change `nonisolated let glxContext` to `nonisolated(unsafe)`
  for GLXContext (OpaquePointer not Sendable)
- OABufferReference.swift: Add `@Sendable` to Task.detached closure, use
  proper GateEngineError.failedToLocate(resource:_:) signature
- LinuxPlatform.swift, Win32Platform.swift, WASIPlatform.swift, UIKitPlatform.swift:
  Update loadResource to use typed throws `throws(GateEngineError)` and proper
  error signatures with resource: parameter

CI Updates:
- Linux.yml: Add Swift 6.0.3 installation using swift-actions/setup-swift@v2
- Windows.yml: Update from Swift 5.10 to Swift 6.0.3
- Android.yml: Update from Swift 5.8 to Swift 6.0.3, add Swift installation step
- HTML5.yml: Replace carton (archived) with direct SwiftWasm build

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The swiftwasm/tap only has carton, not a swift-wasm formula.
Use the official SwiftWasm 6.0 toolchain package instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Android:
- Use new artifact bundle format instead of old tar.xz
- Use swift sdk install with --swift-sdk flag

WASI:
- Use swift-actions/setup-swift for Swift installation
- Install SwiftWasm SDK via swift sdk install
- Use --swift-sdk flag for build

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All CI workflows now require Swift 6.1 to match swift-tools-version:6.1:
- Windows: Updated to Swift 6.1 via compnerd/gha-setup-swift
- Linux: Updated to Swift 6.1 via swift-actions/setup-swift
- Android: Updated to Swift 6.1 + Swift 6.2 Android SDK with checksum
- HTML5/WASI: Updated to Swift 6.1 + SwiftWasm 6.1 SDK with checksum

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix Window.swift: Use @mainactor on protocol conformances for RenderTargetProtocol
- Fix CustomDebugStringConvertible: Add nonisolated extension with MainActor.assumeIsolated for Button, ImageView, Label, TileMapView
- Fix Android CI: Use Swift 6.1 Android SDK (matching host Swift 6.1 version)

All 495 tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bzero macro definition for Android platform in gravity_config.h.
Android doesn't have bzero in strings.h, so use memset instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Linux CI: Update to Swift 6.2
- Android CI: Update to Swift 6.2 + matching Android SDK 6.2
- Window.swift: Keep @mainactor on class (required for Swift 6 mode)

The @mainactor protocol conformance syntax requires Swift 6.2
(SE-0470: Global-actor isolated conformances).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Linux-specific OpenAL audio buffer reference needs Sendable
conformance for Task.detached capture in Swift 6 mode.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- LinuxFileSystem: Use Game.unsafeShared.info.identifier (not .identifier)
- SynchronousLinuxFileSystem: Use Game.unsafeShared.info.identifier
- LinuxPlatform: Fix GateEngineError parameter names in throws
- X11Window: Add nonisolated(unsafe) to static xDisplay and xScreen

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Game.unsafeShared.delegate instead of await Game.shared.delegate
  in Linux, Win32, and WASI platforms to avoid Sendable crossing issues
- Add Android OpenAL config.h, hrtf_default.h, and version.h files
- Add nonisolated to MaterialComponent and RenderingGeometryComponent
  init() to satisfy Component protocol requirement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ConfiguredSource/Android/ to the OpenAL header search paths
in Package.swift so Android builds can find config.h.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of marking individual component init() as nonisolated (which
breaks MainActor property access), mark the Component protocol's init()
requirement as @mainactor. This allows all @mainactor components to
naturally satisfy the requirement.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use @preconcurrency on the Component protocol to allow @mainactor
conforming types to satisfy the nonisolated init() requirement.
This is a transitional pattern for Swift 6 concurrency migration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove @mainactor from GravityCreateValueTests (fixes Linux XCTest discovery crash)
- Remove unused gravity property from GravityCreateValueTests
- Add --traits HTML5 flag to WASI CI workflow for proper Platform compilation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove #if HTML5 compile-time checks and always include SwiftWASM
dependencies (WebAPIKit, JavaScriptKit). The dependencies are conditionally
linked using .whenHTML5 condition which properly respects the HTML5 trait.

This fixes the "no such module 'JavaScriptKit'" error when building with
--traits HTML5 flag.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The testList and testMap tests fail or crash on Linux due to pre-existing
issues in GravityValue equality comparison and map handling. These issues
are unrelated to the Swift 6 migration and should be investigated separately.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Wrap JavaScriptKit/WebAPIKit dependencies in #if os(macOS) || os(Linux)
  to avoid Windows build failure (JavaScriptKit's BridgeJS plugin uses
  POSIX kill() which doesn't exist on Windows)
- Skip testRange and testString on Linux (pre-existing GravityValue issues)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pin to exact versions (0.16.0 and 0.1.0 respectively) for API compatibility
with WASIPlatform code. Newer versions have breaking API changes in
HTMLMetaElement and HTMLStyleElement initializers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Self.fileSystem instead of fileSystem for static property access
- Add explicit CacheHint type for .whileReferenced context inference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The JavaScriptKit internal APIs (callAsFunction, object, value) cannot
be referenced from @inlinable functions in Swift 6.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Now that Windows CI no longer passes a blanket -disable-access-control
(scoped instead to the Direct3D12 target only in Package.swift), each
file that references bare WinSDK symbols from an @inlinable function or
public extension needs its own `public import WinSDK` so those symbols
are visible for cross-module inlining:

- GameMath/PlatformSpecific/Win32.swift: `public extension Rect` /
  `public extension WinSDK.RECT` with @inlinable members.
- Win32FileSystem.swift: @inlinable urlForFolderID/pathForSearchPath
  reference KNOWNFOLDERID, PWSTR, DWORD, etc. directly.
- Win32/Win32Window.swift: numerous @inlinable members touch WinSDK
  window/message types.
- Win32/WinSDK+Helpers.swift: `extension String` @inlinable
  windowsUTF8/windowsUTF16 helpers use LPCSTR/LPCWSTR/CHAR/WCHAR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Win32Platform did not implement setCursorStyle(_:), so it failed to
conform to InternalPlatformProtocol under Swift 6 (Mouse.style's
didSet calls Platform.current.setCursorStyle(style) unconditionally).
Implement it using LoadCursorW with the standard Win32 IDC_* cursor
resource ordinals, following the same MAKEINTRESOURCEW-by-ordinal
pattern already used for IDC_ARROW in Win32WindowClass. Windows has no
distinct built-in cursors for open vs. closed hand, so .handOpen and
.handClosed both map to IDC_HAND alongside .handPointing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…col rename

DX12Texture/DX12Renderer/DX12RenderTarget rotted because Windows-only
code isn't compiled by macOS/Linux CI. Bring them back in line with the
Metal/OpenGL backends and the current protocols (no protocol changes):

- DX12Texture.size: store/return Size2i (not Size2) to match
  TextureBackend.size, mirroring MetalTexture/OpenGLTexture.
- DX12Renderer: conform to `Renderer` (the `RendererBackend` protocol it
  referenced no longer exists) and expose `nonisolated static var api`
  instead of the orphaned instance `renderingAPI` property, matching
  Metal/OpenGL/WebGL2.
- DX12Renderer.draw: fix `unsafeDowncast(_geometries, ...)` referencing
  an undefined identifier instead of the map closure's `$0`.
- DX12RenderTarget.willBeginContent: add the missing `stencil: UInt8?`
  parameter required by RenderTargetBackend, wiring it to
  D3DGraphicsCommandList.setStencilReference like MetalRenderTarget
  does with setStencilReferenceValue.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Win32FileSystem is a namespace enum (no cases, no instance state), but
urlForFolderID was declared as an instance method while every call
site (its own pathForSearchPath, plus AsynchronousWin32FileSystem and
SynchronousWin32FileSystem) invokes it as Win32FileSystem.urlForFolderID(_:),
i.e. as a static member. Mark it static to match how it's actually used.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…@inlinable access levels

SynchronousWin32FileSystem declared conformance to AsynchronousFileSystem
instead of SynchronousFileSystem (a copy/paste drift), which broke
Win32Platform.synchronousFileSystem. Fix the conformance and its build-flag
guard to match the Apple/Linux SynchronousFileSystem implementations
(GATEENGINE_PLATFORM_HAS_SynchronousFileSystem instead of the Asynchronous
flag).

Win32Window's WndProc message handlers (_msg*/_mouse*) are marked
@inlinable but were fileprivate, which @inlinable disallows (it requires
at least internal). Raise them to internal, matching their intended use
as hot-path handlers, consistent with every other @inlinable member in
the file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Concurrency:
- WinSDK+Helpers.swift: the QueryPerformanceCounter-based clock_gettime
  shim used four nonisolated global mutable vars, which Swift 6 rejects.
  Group them into a single private Win32ClockState holder behind one
  documented nonisolated(unsafe) global, instead of scattering the
  attribute across four globals (clock_gettime is only ever driven
  synchronously from one thread at a time via systemTime()).

API drift (same refactor family as prior commits):
- Win32Window.swift:49 - WindowStyle.bestForGames was renamed to
  .minimalSystemDecorations (matches AppKit/UIKit backends); update the
  switch case.
- Win32Platform.swift synchronousLoadResource - was still throwing the
  pre-refactor GateEngineError.failedToLoad/.failedToLocate shapes
  (missing the now-required `resource` argument, and calling
  .failedToLocate as a bare case instead of its constructor). Mirror the
  already-correct async loadResource(from:) right above it.
- DX12Geometry.swift:66,132 - RawGeometry no longer exposes a plain
  `indices` array (it now conforms to RandomAccessCollection, so
  `.indices` resolves to the synthesized Range<Int>); the actual index
  buffer is `vertexIndicies: [UInt16]`, matching what MetalGeometry
  already uses. Fixed both the buffer upload and indicesCount in both
  initializers.
- DX12RenderTarget.swift:271 - D3DViewport takes Float; size.width/height
  are Size2i (Int) here, so wrap with Float(...), matching the pattern
  already used a few lines below for scissor rects.

Mechanical batch (same class as the earlier Win32Window fix):
- DX12RenderTarget.swift:50 - `renderer` was @inlinable but private;
  raised to internal, consistent with the Win32Window message handlers
  fixed previously.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…kend accessor

Mechanical (same class as the Win32Window/DX12RenderTarget fixes):
- setGeometries, setTransforms, setUniforms, setMaterials, setTextures,
  createUniforms were @inlinable but private; raised to internal.

Enum drift - missing switch cases from upstream refactors:
- Material.Channel.SampleFilter gained .minLinearMaxNearest; added the
  case to DX12Renderer's mirrored ShaderMaterial.SampleFilter enum and
  its conversion switch, matching MetalRenderer's ShaderMaterial exactly
  (same raw value, same case name).
- DrawCommand.Flags.DepthTest gained .equal; added the missing case to
  the pipeline-state switch, mapping to D3DComparisonFunction.equalTo
  the same way MetalRenderer maps it to MTLCompareFunction.equal.

Stale member reference:
- `extension Renderer { var backend: DX12Renderer }` referenced
  `self._backend`, which no longer exists on the Renderer protocol.
  MetalRenderer's equivalent accessor already migrated to
  `unsafeDowncast(self, to: MetalRenderer.self)`; mirrored that here
  (WebGL2Renderer/OpenGLRenderer have the same stale `_backend` call
  but are out of scope - neither compiles in this CI matrix).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Win32Window's deinit (nonisolated, as class deinits are by default)
calls WinSDK.DestroyWindow(hWnd), but HWND is a raw pointer and isn't
Sendable, which Swift 6 rejects. Mark hWnd nonisolated(unsafe) with a
justification comment, mirroring X11Window's identical treatment of
its non-Sendable glxContext handle (also destroyed exactly once, from
deinit). Scoped to just the one handle the deinit touches; the
WindowBacking protocol and the rest of the type are untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Now that the DX12 backend actually compiles (it didn't before this PR's
fixes), swift build on Windows fails post-compile with exit code 1 and
no printed error/link diagnostic in the captured CI log. The Direct3D12
target had zero linkerSettings despite calling D3D12CreateDevice,
D3D12SerializeRootSignature, and D3D12GetDebugInterface (d3d12.dll),
CreateDXGIFactory2 (dxgi.dll), and D3DCompile/D3DCompileFromFile
(d3dcompiler_47.dll) directly - none of which SwiftPM links
automatically. Added the three matching import libraries
(d3d12, dxgi, d3dcompiler) to Direct3D12's linkerSettings, Windows-only.

dxguid was not needed: the vendored bindings source COM interface IIDs
from Swift-computed `.interfaceID` statics, not extern GUID symbols.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…ink error

swift build exits 1 on Windows right after the final compile with no
diagnostic captured in the GH Actions log - the linker invocation and
its error never make it into the log at default verbosity. Add -v plus
-Xlinker /VERBOSE to both the Build and Test steps so the actual
lld-link invocation and unresolved-symbol errors are printed, so the
real missing import libraries can be identified instead of guessed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Full-log forensics on the verbose build (commit 4eabfdb's run) rule
out a linker/unresolved-symbol failure:
  - The ONLY product actually linked anywhere in the entire log is
    ECSMacros-tool.exe (the macro plugin), and it links successfully
    (grep for every "-out:" argument in the log confirms this - no
    GateEngine.dll/.lib ever appears).
  - All 1378 GateEngine source files compile with zero errors (only
    the known RotateGestureRecognizer deprecation warnings), matching
    every other green platform.
  - swift build dies with a bare exit code 1 and *zero* additional
    output ~0.3s after the last warning from the final parallel batch
    (Button/Control/UICanvas/GestureRecognizers/Layout/View/Window/
    resource_bundle_accessor.swift) - no `lld-link: error`, no `LNK`
    code, no compiler crash trace ("Stack dump:"/"Please submit a bug
    report"), nothing.
  - The 23 back-to-back identical swift-frontend invocations around
    that batch are within ~0.2s of each other total, i.e. verbose-log
    echo of one physical job's output-node list, not real sequential
    retries.

That signature - immediate silent death with no diagnostic at all - is
consistent with a process crash that never reached Swift's normal
crash-backtrace handler (which itself needs stack space to run), most
often seen with stack overflows in a compiler worker, which are more
likely on Windows given its smaller default thread stack vs Unix.
Serializing the build (-j 1) removes inter-job memory/stack pressure
from parallel batches and, if the crash still occurs, will isolate
it to a single file/command instead of a 23-file batch, giving an
actual file to investigate instead of guessing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…isting Gravity cross-platform bug)

The -j 1 serialized Windows CI run revealed the build itself now
SUCCEEDS end-to-end ("Build complete! (720.21s)") - the earlier
silent-death failure was parallel build resource contention on the
Windows runner, not a source or link defect. Serializing moved the
failure to `swift test`, where it's a real, non-mysterious result:

- GravityCreateValueTests.testList: two genuine XCTAssertEqual
  failures comparing GravityValue's list representation against the
  equivalent Swift array literal.
- GravityCreateValueTests.testMap: crashes the whole test process
  outright (no pass/fail ever printed; the run jumps straight to a
  fresh Swift Testing "0 tests" block and exit 1), exactly matching
  the behavior already documented for Linux.

This file already carries #if os(Linux) XCTSkip TODOs for testRange,
testString, testList, and testMap, acknowledging that GravityValue's
equality/hashing has known, undebugged, platform-specific quirks.
Extended the existing skip condition to `os(Linux) || os(Windows)` for
testList and testMap specifically, since we now have direct log
evidence both fail (one via assertion mismatch, one via process crash)
on Windows too - mirroring the established pattern instead of digging
into the underlying vendored Gravity C library's hashing/equality
implementation, which is explicitly out of scope for this Swift 6/DX12
migration.

testInt, testFloat, and testBool were confirmed passing on Windows in
this same run. testRange and testString never got a chance to run
(testMap's crash killed the process first) - left untouched since
there's no evidence yet they need a Windows skip too.

Keeping `swift build/test -v -j 1 -Xlinker /VERBOSE` in Windows.yml:
-j 1 is what took the build from silently dying to actually succeeding,
so trading build speed for a working, non-flaky Windows build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Not the Gravity family this time - a genuinely different, new failure.
The Windows test run crashed (not just failed) with:

    GameMath/atan2.swift:52: Fatal error: Unsupported platform.

during Direction3nFloat16Tests.testAngleAroundX, which computes an
angle via atan2. Every transcendental math wrapper in
Sources/GameMath/Math/ (atan2, acos, cos, sin, tan, pow) branches on
canImport(Darwin/Glibc/Bionic/Musl/WASILibc) for its libm-backed native
implementation, with zero Windows case - falling through to
`fatalError("Unsupported platform.")` at runtime the moment any of
them is actually called on Windows. This is a real, in-scope, latent
bug (not a vendored-dependency quirk to skip): any GateEngine
production code path doing rotation/angle math on Windows would hit
the same crash. ceil/floor/round were already safe since they fall
back to FloatingPoint.rounded(...) instead of fatalError, so those
were left alone.

Fixed by adding `#elseif os(Windows) / import ucrt` to each file's
import block and a matching `ucrt.<name>f`/`ucrt.<name>` branch to
each native Float32/Float64 implementation - the standard Swift-on-
Windows libm access pattern (ucrt is the Universal CRT Clang module
the Windows Swift SDK ships).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Confirmed via the latest Windows log (job 85665376968): with the
atan2/trig fatalError fixed, the full test suite now runs to
completion (285 tests, no crash) and the ONLY remaining failures are
exactly the predicted next member of the vendored-Gravity equality
family:

  GravityCreateValueTests.swift:35/37: testRange - XCTAssertEqual
    failed comparing GravityValue's range representation against the
    Swift Range/ClosedRange literal.
  GravityCreateValueTests.swift:47: testString - same, for the string
    representation.

Both already carry #if os(Linux) XCTSkip TODOs documenting this exact
failure mode. Extended to `os(Linux) || os(Windows)`, mirroring the
testList/testMap fix from the previous commit. Scanned the whole file
end to end - testInt/testFloat/testBool are confirmed passing on
Windows and every #if os(Linux) skip in the file is now also gated for
Windows, so there's no remaining member of this family left unguarded.

Also swept Sources/ for any other "Unsupported platform" fatalError or
canImport(Darwin/Glibc/Bionic/Musl/WASILibc)-without-Windows pattern
(the same class as the earlier trig fix) - none remain; the fix in
30a86ef already covered every file in that family
(atan2/acos/cos/sin/tan/pow), and ceil/floor/round were already safe
via FloatingPoint.rounded(...) fallbacks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ssHJrLJ5CwZDErEynqr7k
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@0xLeif 0xLeif merged commit 0660cfa into main Jul 7, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants