Skip to content

Migrate to new Zig compiler#413

Merged
lukewilliamboswell merged 105 commits into
mainfrom
migrate-zig-compiler
Jul 15, 2026
Merged

Migrate to new Zig compiler#413
lukewilliamboswell merged 105 commits into
mainfrom
migrate-zig-compiler

Conversation

@lukewilliamboswell

@lukewilliamboswell lukewilliamboswell commented Dec 30, 2025

Copy link
Copy Markdown
Collaborator

Summary

  • Migrate basic-cli to the new Zig compiler and flat platform host ABI.
  • Consolidate the host into the Rust roc_host static library and restore the public CLI platform surface for commands, files and directories, environment access, HTTP, SQLite, TCP, terminal I/O, time, and related utilities.
  • Build platform inputs for macOS Apple Silicon and Intel, Linux musl x64 and ARM64, and Windows x64.
  • Replace the legacy shell/Expect suite with a cross-platform, spec-driven runner based on 29 executable examples and 41 runtime cases.
  • Adopt the shared release and versioned-docs actions from roc-lang/release-package.

Public API and migration notes

This is a breaking platform release, not only a compiler implementation change.

  • Application arguments are native OsStr values, preserving Unix bytes and Windows UTF-16. The old Arg module is replaced by OsStr.
  • Paths use the shared roc-lang/path package types, and HTTP requests/responses use the shared roc-lang/http package types.
  • Platform effects use the new Try/open-tag error style and expose structured IOErr values.
  • Environment support includes native variable access, dict!, platform!, working-directory access/update, executable path, and temporary directory.
  • The checked-in examples are executable documentation and the source of truth for cross-target build and runtime coverage.

Automated validation

The last complete GitHub matrix is green, including:

  • formatting, checking, and testing all 29 examples;
  • building every example for x64mac, arm64mac, x64musl, arm64musl, and x64win;
  • running 41 spec cases natively on macOS Intel, macOS Apple Silicon, Linux x64, and Windows x64;
  • assembling the complete .tar.zst platform bundle and consuming the downloaded bundle on those four native runners;
  • generating and validating versioned documentation; and
  • CodeQL analysis.

Runs: CI · release dry run

On the latest head, local validation with Roc debug-a06fe3fc passes formatting and checking for every example, all 66 Roc tests, git diff --check, Rust formatting and a locked all-target Cargo test-profile build, ShellCheck/Bash syntax, Python syntax, and test-spec JSON parsing.

The fresh GitHub run currently stops at roc fmt --check because the published release-fast-252a59ae nightly predates the formatter used for the final cleanup. It reaches the first changed SQLite example without a compile or test failure. Rerun the matrix after debug-a06fe3fc (or its formatter change) is published in the next nightly.

CI and release intentionally follow the current nightly-new-compiler alias. Zig is pinned to 0.16.0 and Rust to 1.82.0.

Release flow

The Release workflow is available through workflow_dispatch with a stable or release-candidate version. It:

  1. validates the request and default branch;
  2. builds and tests the release bundle on the supported native runners;
  3. publishes the release and marks prerelease versions automatically;
  4. publishes validated versioned docs; and
  5. opens a follow-up PR that updates example bundle URLs and commits the generated docs tree.

The shared release actions are pinned to d2560ead9f724bfaabfbc8134b8895e120171064.

bump_check is temporarily warn: stable 0.20.0 uses the old .tar.br format and Roc syntax, while alpha-0 no longer parses with the current compiler. Change this to require after the first stable new-compiler .tar.zst release.

Known limitations and coverage notes

  • The Windows time/sleep runtime currently crashes, so examples/time.roc builds on Windows but its runtime case is skipped. This is accepted for the release candidate.
  • ARM64 Linux is compile-only because no matching runner is available.
  • The command example's runtime case invokes Unix commands.
  • Terminal and TTY runtime cases use POSIX PTYs; the Python harness does not provide Windows ConPTY support.
  • Windows file-permission metadata returns the documented Unsupported result.
  • Nix checks remain temporarily removed.

Final review

The branch is based on the current main and is mergeable. This PR remains a draft while the final maintainer review is completed; it can be marked ready once that review and the fresh GitHub matrix are satisfactory.

Comment thread .github/workflows/ci.yml Fixed
Comment thread .github/workflows/release.yml Fixed
Comment thread .github/workflows/release.yml Fixed
lukewilliamboswell and others added 10 commits January 5, 2026 15:24
Removed Path.type! function which was causing crash: "increfDataPtrC:
ORIGINAL ptr=0x1 is not 8-byte aligned". This appears to be an ABI
issue with opaque types in RocTry with the new compiler.

The function used an opaque type PathType := [IsDir, IsFile, IsSymLink]
which doesn't work correctly in Try results. The three individual
functions (is_file!, is_dir!, is_sym_link!) all work perfectly and
cover the same use cases.

All tests now pass. Path.type! can be investigated as a separate
follow-up issue once the opaque type ABI is better understood.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Restructure Cmd to use opaque type with methods (Cmd := { record }.{ methods })
- Update doc comments to use -> operator syntax instead of deprecated |>
- Delete orphaned examples (dir-test, env-test, file-test, print-test)
- Delete orphaned expect scripts for removed examples
- Delete old tests/ directory with unmigrated tests
- Update all_tests.sh to remove references to deleted examples
- Add test files demonstrating -> operator syntax works

Note: Static dispatch with . syntax crashes compiler (checkDeferredStaticDispatchConstraints)
so we use -> operator syntax instead, which works correctly.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
After compiler fixes for static dispatch, we can now use the idiomatic
. syntax for all methods including effects:

- Update all doc comments to show static dispatch syntax
- Effect methods now work: cmd.exec_exit_code!()
- Builder methods continue to work: Cmd.new("ls").args([])
- Full fluent API: Cmd.new("echo").args(["Hi"]).exec_cmd!()

Previous syntax required:
- . for regular methods
- Qualified calls for effects (Cmd.exec_exit_code!(cmd))

Now all methods use consistent . syntax throughout.

Tests verify:
- Simple method chaining with effects
- Multiline builder patterns
- Output capture via static dispatch
- Complete fluent chains

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Use argc/argv directly instead of std::env::args() because when built
as a static library, the Rust runtime isn't properly initialized and
std::env::args() returns an empty list.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
c_char is u8 on ARM64 Linux but i8 on x86, so use the portable
c_char type from std::ffi for argv handling.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The `git diff | head -50` command can exit with 141 (SIGPIPE) on Linux
when head closes the pipe before git finishes writing. Add `|| true`
to ignore this expected condition.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Limit GITHUB_TOKEN permissions to contents:read by default, as
recommended by GitHub's security scanner. The create-release job
overrides this with contents:write as needed.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@lukewilliamboswell
lukewilliamboswell marked this pull request as ready for review July 13, 2026 05:39
lukewilliamboswell and others added 9 commits July 15, 2026 09:23
- Normalize Windows filesystem errors (ACCESS_DENIED on directories) to
  the portable IsADirectory/NotADirectory IOErr tags; fixes the
  error-handling example on Windows
- Work around the u128 return ABI mismatch on x86_64-windows by
  reshaping Host.utc_now! to Try(U128, [ClockBeforeEpoch]); fixes the
  time example crash (upstream: roc-lang/roc#10163)
- Implement File.is_readable!/is_writable!/is_executable! on Windows
  and re-enable the file-permissions example there
- Un-skip time.roc run scenario on Windows
- Add a validate-windows CI job (fmt/check/test on windows-2025)
- Gate the CStr import behind cfg(unix) to fix the Windows build warning

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lukewilliamboswell
lukewilliamboswell merged commit 85a8132 into main Jul 15, 2026
22 checks passed
@lukewilliamboswell
lukewilliamboswell deleted the migrate-zig-compiler branch July 15, 2026 05:22
@Anton-4 Anton-4 mentioned this pull request Jul 15, 2026
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.

4 participants