Jesse A. Green / notebook

Sway — Administrator & Developer Guide

Generated May 2026 from FuelLabs/sway at e12e611

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Audience: Compiler engineers, toolchain contributors, language designers, blockchain infrastructure operators, and advanced integrators building on the Fuel ecosystem.


Table of Contents

  1. Architecture Overview
  2. System Requirements
  3. Configuration Reference
  4. Deployment & Scaling
  5. Operations
  6. Performance
  7. Security
  8. Developer Internals
  9. Integration Points

1. Architecture Overview

Sway is a domain-specific programming language targeting the FuelVM — the virtual machine powering the Fuel blockchain. It is syntactically and semantically inspired by Rust, providing ownership semantics, type inference, pattern matching, and generics, while being specifically designed for the constraints and capabilities of a UTXO-based blockchain execution environment.

The repository is a large Rust workspace (Cargo.toml at root) containing the complete Sway toolchain: compiler, formatter, language server, package manager, documentation generator, debugger, and migration assistant. Version 0.71.0, source commit e12e611, spanning 8,121 files.

Note

The entire Sway toolchain — compiler, package manager, LSP, formatter, and CLI — is developed as a single Rust workspace. All crates share a unified dependency tree, enabling cross-crate type sharing without serialization overhead. The forc CLI binary is the single user-facing entry point into this ecosystem.

1.1 Workspace Members

Crate Path Role
forc forc/ CLI entry point, subcommand dispatcher
forc-pkg forc-pkg/ Package manager, dependency resolution, build plans
forc-test forc-test/ Test framework runner
forc-util forc-util/ Shared CLI utilities, bytecode parsing
forc-debug forc-plugins/forc-debug/ DAP debug server
forc-doc forc-plugins/forc-doc/ HTML documentation generator (swaydoc)
forc-fmt forc-plugins/forc-fmt/ Formatter CLI frontend
forc-lsp forc-plugins/forc-lsp/ LSP server wrapper
forc-migrate forc-plugins/forc-migrate/ Breaking-change migration assistant
forc-publish forc-plugins/forc-publish/ Package registry publisher
forc-tx forc-plugins/forc-tx/ Transaction builder
sway-ast sway-ast/ AST data structures for all language constructs
sway-core sway-core/ Core compiler: type checking, IR gen, ASM gen
sway-error sway-error/ Error and warning type definitions, handler
sway-features sway-features/ Experimental feature flag management
sway-ir sway-ir/ SSA-form intermediate representation
sway-ir/sway-ir-macros sway-ir/sway-ir-macros/ Proc-macros for IR construction
sway-lsp sway-lsp/ LSP implementation (capabilities + server loop)
sway-parse sway-parse/ Lexer and recursive-descent parser
sway-types sway-types/ Shared types: spans, identifiers, source maps
sway-utils sway-utils/ Utility functions, manifest discovery, constants
swayfmt swayfmt/ Code formatter library
test test/ E2E, snapshot, and in-language test harness
mdbook-forc-documenter scripts/mdbook-forc-documenter/ mdBook plugin for forc docs

1.2 High-Level Data Flow

┌─────────────────────────────────────────────────────────────────────┐
│                          forc build                                 │
│                       (CLI entry point)                             │
└───────────────────────────┬─────────────────────────────────────────┘
                            │
                    ┌───────▼────────┐
                    │   forc-pkg     │
                    │  Manifest parse│
                    │  Dep resolve   │
                    │  Build plan    │
                    └───────┬────────┘
                            │ per-package source files
              ┌─────────────▼──────────────┐
              │        sway-parse          │
              │  Lex → Token stream        │
              │  Parse → sway-ast nodes    │
              └─────────────┬──────────────┘
                            │ parsed AST
              ┌─────────────▼──────────────┐
              │        sway-core           │
              │  Type checking             │
              │  Declaration engine        │
              │  Control flow analysis     │
              └─────────────┬──────────────┘
                            │ typed AST
              ┌─────────────▼──────────────┐
              │        sway-ir             │
              │  IR generation (SSA)       │
              │  Optimization passes       │
              └─────────────┬──────────────┘
                            │ optimized IR
              ┌─────────────▼──────────────┐
              │        sway-core           │
              │  ASM generation            │
              │  Virtual → Allocated → Final│
              └─────────────┬──────────────┘
                            │
              ┌─────────────▼──────────────┐
              │        Output              │
              │  Bytecode (.bin)           │
              │  ABI (.json)               │
              │  Debug info                │
              └────────────────────────────┘

1.3 Program Types

Sway supports four distinct program types, each with different execution semantics and structural requirements:

Program Type Entry Point Return Type Purpose
contract ABI function dispatch () per function Deployed smart contract; has storage, ABI
script main() Any Executed once per transaction; no persistent storage
predicate main() bool Authorization; pure function; no storage
library (module root) N/A Reusable code; no entry point

The program type is declared at the top of every Sway file:

contract;   // or: script; predicate; library;

1.4 Plugin System Architecture

The forc binary implements an extensible plugin system: any binary named forc-<name> found on PATH is automatically discovered and exposed as forc <name>. This allows third-party plugins without modifying forc itself.

forc <cmd>
  ├── Built-in subcommands (new, build, check, clean, deploy, run, ...)
  └── forc-* on PATH (forc-debug, forc-doc, forc-fmt, forc-lsp, ...)

Plugin discovery uses which-style PATH scanning at runtime. Each plugin binary receives forwarded arguments and inherits the calling environment.

1.5 Build Targets

Target Description
fuel Default; targets FuelVM bytecode via fuel-asm / fuel-vm
evm Targets EVM bytecode via the EVM ABI and code generation path

2. System Requirements

2.1 Build Dependencies

Dependency Version Purpose
Rust toolchain Stable (pinned in rust-toolchain.toml) Compile the workspace
just >= 1.0 Task runner (project-wide recipes)
cargo Bundled with Rust Build and test
git >= 2.0 Source control, forc-pkg git dependencies
fuel-core node 0.48.x Required for E2E and node-based tests
forc (bootstrapped) 0.71.0 Building Sway example projects

2.2 Optional Build Dependencies

Dependency Purpose
mdbook Building the Sway book
cargo-nextest Faster parallel test execution
cargo-sort Enforcing sorted Cargo.toml dependencies (CI)
cargo-audit Security advisory scanning
sccache Cross-invocation Rust compilation caching

2.3 Runtime Requirements (forc)

Requirement Notes
git on PATH Required for git-sourced dependencies in Forc.toml
Network access For fetching remote dependencies (disable with --offline)
fuel-core node Required for forc run, forc deploy, forc test E2E
Write access to ~/.forc/ Cache directory for downloaded packages

2.4 Platform Support

Platform Status
Linux x86_64 Primary CI target; fully supported
macOS Apple Silicon Supported; CI tested
macOS Intel Supported
Windows x86_64 Community supported; some path-handling edge cases

2.5 Key Dependency Versions

Crate Version Role
fuel-vm 0.66 FuelVM execution engine
fuel-tx 0.66 Fuel transaction types
fuel-asm 0.66 Fuel assembly instruction set
fuels 0.77 Fuel Rust SDK (SDK harness tests)
fuel-core-client 0.48.0 Fuel node GraphQL client
clap 4.5 CLI argument parsing
tokio latest stable Async runtime
petgraph latest Dependency DAG
dashmap latest Concurrent HashMap for LSP
serde / serde_json / toml latest Serialization
lsp-types 0.94 LSP protocol types
tower-lsp 0.20 LSP server framework
horrorshow latest HTML generation (forc-doc)
tikv-jemallocator latest Memory allocator (performance)

3. Configuration Reference

3.1 Forc.toml — Package Manifest

Forc.toml is the package manifest, analogous to Cargo.toml. It is located at the project root. The constant MANIFEST_FILE_NAME = "Forc.toml" is defined in sway-utils.

[project] Section

[project]
name = "my_contract"
version = "0.1.0"
authors = ["Alice <[email removed]>"]
entry = "main.sw"          # Default: main.sw (scripts/contracts) or lib.sw (libraries)
license = "Apache-2.0"
implicit-std = true        # Whether to implicitly depend on sway-std
Field Type Default Description
name String required Package name
version String required SemVer package version
authors String[] [] Author list
entry String main.sw / lib.sw Entry file relative to src/
license String "" SPDX license identifier
implicit-std bool true Auto-add sway-std dependency

[dependencies] Section

[dependencies]
# Path dependency
my_lib = { path = "../my_lib" }

# Git dependency (tag, branch, or rev)
sway_standards = { git = "https://github.com/FuelLabs/sway-standards", tag = "v0.4.0" }

# IPFS dependency (CID-based)
my_package = { ipfs = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG" }
Source Type Fields Notes
Path path Relative or absolute filesystem path
Git git, tag / branch / rev Fetched via git clone; cached in ~/.forc/
IPFS ipfs CID-based; fetched from IPFS network

[patch] Section

[patch."https://github.com/FuelLabs/sway-standards"]
sway_standards = { path = "../local-standards" }

Overrides remote dependencies with local versions for development. Follows the same semantics as Cargo's [patch].

[build-profile] Section

[build-profile.release]
optimization_level = "1"      # "0" = Opt0 (default), "1" = Opt1
print_dasm = false
print_finalized_asm = false
print_ir = false
Field Values Default Description
optimization_level "0", "1" "0" IR optimization aggressiveness
print_dasm bool false Print desugared ASM to stdout
print_finalized_asm bool false Print final allocated ASM
print_ir bool false Print generated SSA IR

[workspace] Section (Multi-package Projects)

[workspace]
members = [
    "contracts/my_contract",
    "libraries/my_lib",
    "scripts/my_script",
]

3.2 Forc.lock — Lockfile

Forc.lock is auto-generated and must not be edited manually. It records exact resolved versions and content hashes for all transitive dependencies, ensuring reproducible builds across machines and CI environments.

[[package]]
name = "core"
source = "path+from-root-..."
version = "0.0.0"

[[package]]
name = "sway_standards"
source = "git+https://github.com/FuelLabs/sway-standards?tag=v0.4.0#abc123def"
version = "0.4.0"
dependencies = ["core", "std"]

Commit Forc.lock to version control for all non-library packages. Libraries may omit it to avoid conflict with downstream consumers.

3.3 swayfmt.toml — Formatter Configuration

swayfmt.toml is the formatter configuration file. swayfmt searches from the project directory upward to the filesystem root. If absent, all defaults apply.

Important

swayfmt.toml is optional. The built-in defaults produce fully valid, community-standard formatting. Only add this file when your team needs to deviate from the defaults. Commit it to version control and enforce forc fmt --check in CI to prevent formatting drift.

Whitespace Section

[whitespace]
tab_spaces = 4            # Spaces per indent level
newline_style = "Auto"    # "Auto" | "Unix" | "Windows" | "Native"
indent_style = "Block"    # "Block" | "Visual"
Field Default Options Description
tab_spaces 4 integer Spaces per indent
newline_style Auto Auto, Unix, Windows, Native Line ending style
indent_style Block Block, Visual Indentation alignment mode

Imports Section

[imports]
group_imports = "StdlibFirst"    # "Preserve" | "One" | "StdlibFirst"
import_granularity = "Preserve"  # "Preserve" | "Item" | "Crate" | "Module"
Field Default Options Description
group_imports StdlibFirst Preserve, One, StdlibFirst Import group ordering
import_granularity Preserve Preserve, Item, Crate, Module Merge/split use trees

Expressions Section

[expressions]
expr_brace_style = "SameLineWhere"
Field Default Description
expr_brace_style SameLineWhere Brace and where-clause placement style

Literals Section

[literals]
hex_literal_case = "Preserve"   # "Preserve" | "Upper" | "Lower"

Structures Section

[structures]
field_alignment = "Off"   # "Off" | "AlignFields"
Field Default Description
field_alignment Off When AlignFields, aligns struct field type annotations

Heuristics Section

Controls character-width thresholds that determine when the formatter breaks a line vs. keeps it inline. Values are integers representing character counts.

[heuristics]
# (threshold fields — specific names are format-version dependent)

Comments Section

Controls how inline and doc comments are reflowed and positioned relative to the code they annotate.

Ordering Section

Controls ordering of items within modules (e.g., whether use declarations are grouped before fn declarations).

3.4 Environment Variables

Variable Purpose Example
FORC_EXPERIMENTAL Enable experimental features (comma-separated) FORC_EXPERIMENTAL=new_encoding,references
FORC_NO_EXPERIMENTAL Disable experimental features FORC_NO_EXPERIMENTAL=new_hashing
FORC_PUB_TOKEN Auth token for forc publish FORC_PUB_TOKEN=<registry-token>
FORC_IMPLICIT_STD_PATH Override path to sway-std standard library FORC_IMPLICIT_STD_PATH=/path/to/sway-std
FORC_IMPLICIT_STD_GIT Override git URL for implicit std FORC_IMPLICIT_STD_GIT=https://github.com/...
FORC_IMPLICIT_STD_GIT_TAG Pin std to specific git tag FORC_IMPLICIT_STD_GIT_TAG=v0.71.0
FORC_IMPLICIT_STD_GIT_BRANCH Pin std to specific branch FORC_IMPLICIT_STD_GIT_BRANCH=master
CARGO_MANIFEST_DIR Test harness: locates test assets Set automatically by Cargo during cargo test
RUST_BACKTRACE Enable Rust backtraces for ICE debugging RUST_BACKTRACE=full

3.5 Experimental Feature Flags

Managed by the sway-features crate. Features are toggled via environment variables (future: Forc.toml support planned).

Feature Flag Name Description
New encoding new_encoding Revised ABI encoding scheme
References references Reference types (&T, &mut T) in Sway
New hashing new_hashing Updated hash primitive semantics
Str array no padding str_array_no_padding Removes padding from string array encoding
Dynamic storage dynamic_storage Dynamic storage key computation at runtime
# Enable multiple features
FORC_EXPERIMENTAL=new_encoding,references forc build

# Disable a feature that would otherwise be on
FORC_NO_EXPERIMENTAL=dynamic_storage forc build

Important

Experimental features may introduce breaking changes between minor versions. Never enable experimental features in production contracts without thorough testing. The new_encoding feature changes the ABI wire format — enabling it on an already-deployed contract is a breaking change for all callers.


4. Deployment & Scaling

4.1 Building the Toolchain from Source

# Clone the repository
git clone https://github.com/FuelLabs/sway.git
cd sway

# Install Rust toolchain (respects rust-toolchain.toml)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

# Build all workspace members (debug)
cargo build --workspace

# Build release binaries
cargo build --release --workspace

# Install forc and all plugins to ~/.cargo/bin
cargo install --path forc
cargo install --path forc-plugins/forc-fmt
cargo install --path forc-plugins/forc-lsp
cargo install --path forc-plugins/forc-debug
cargo install --path forc-plugins/forc-doc
cargo install --path forc-plugins/forc-migrate
cargo install --path forc-plugins/forc-publish
cargo install --path forc-plugins/forc-tx

fuelup is the Fuel toolchain manager (analogous to rustup). It manages multiple forc versions and the associated fuel-core node binary.

# Install fuelup
curl https://install.fuel.network | sh

# Install the latest stable Fuel toolchain
fuelup toolchain install latest
fuelup default latest

# List installed toolchains
fuelup toolchain list

# Install a specific version
fuelup toolchain install nightly
fuelup toolchain install v0.71.0

# Verify installation
forc --version
fuel-core --version

4.3 CI/CD Pipeline Integration

Full Toolchain CI (Contributing to Sway)

name: Sway Toolchain CI

on: [push, pull_request]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust (pinned via rust-toolchain.toml)
        uses: dtolnay/rust-toolchain@stable

      - name: Install just
        uses: extractions/setup-just@v1

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target/
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Check sorted dependencies
        run: cargo install cargo-sort && cargo sort --check --workspace

      - name: Lint
        run: cargo clippy --all-targets --workspace -- -D warnings

      - name: Format check
        run: cargo fmt --check --all

      - name: Build
        run: cargo build --release --workspace

      - name: Test
        run: cargo test --workspace

Sway Project CI (For Contract Developers)

name: Contract CI

on: [push, pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install fuelup
        run: curl https://install.fuel.network | sh

      - name: Install Fuel toolchain
        run: |
          fuelup toolchain install latest
          fuelup default latest

      - name: Format check
        run: forc fmt --check

      - name: Build (locked — no dependency updates)
        run: forc build --locked

      - name: Run tests
        run: forc test --locked

4.4 Package Dependency Cache

forc-pkg caches downloaded packages under ~/.forc/:

~/.forc/
  cache/
    git/
      <repo-hash>/          # Bare git clones of dependencies
        HEAD
        config
        objects/
    ipfs/
      <cid>/                # IPFS-fetched package contents

Cache invalidation is keyed by content hash, so stale entries are never silently used. In containerized CI, mount ~/.forc/cache as a named volume or use the CI platform's cache action to persist across runs.

Note

Cache entries are never automatically pruned. In long-running CI systems, periodically clear ~/.forc/cache/git/ if disk space becomes a concern. The next build will re-fetch and re-validate all dependencies.

4.5 Cross-Compilation (Compiler Binary)

The Sway compiler is a Rust program and cross-compiles using standard Rust tooling. The generated Sway bytecode always targets FuelVM or EVM regardless of the host architecture.

# Build forc for Linux ARM64 on Linux x86_64
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu -p forc

4.6 Workspace Builds (Multi-package Projects)

# Build all workspace members
forc build --path /workspace/root

# Check all members without codegen (fast)
forc check --path /workspace/root

# Build and test a specific member
forc build --path /workspace/root/contracts/token
forc test --path /workspace/root/contracts/token

# Locked offline build for reproducibility
forc build --path /workspace/root --locked --offline

4.7 Output Artifacts

forc build produces output in the out/ directory by default:

out/
  debug/                    # or release/ when --release is used
    <name>.bin              # FuelVM bytecode
    <name>-abi.json         # JSON ABI
    <name>-storage_slots.json  # Storage slot initializers

Override output directory:

forc build --output-dir ./artifacts/
forc build --output-bin-path ./artifacts/my_contract.bin

5. Operations

5.1 forc CLI Subcommands

The forc CLI (forc/src/main.rs → forc/src/cli/mod.rs) dispatches to 16 built-in subcommands plus any discovered forc-* plugins.

Note

Run forc help <subcommand> or forc <subcommand> --help for complete argument documentation. All subcommands accept --path <dir> to specify the project root (defaults to current working directory).

Subcommand Purpose
forc new Scaffold a new Sway project
forc init Initialize Sway project in existing directory
forc build Compile Sway project to bytecode + ABI
forc check Type-check without codegen
forc clean Remove build artifacts (out/ directory)
forc deploy Deploy contract to a Fuel network
forc run Run a script against a Fuel node
forc test Run in-language unit tests
forc update Update dependencies in Forc.lock
forc add Add a dependency to Forc.toml
forc remove Remove a dependency from Forc.toml
forc contract-id Compute deterministic contract ID
forc parse-bytecode Disassemble and display compiled bytecode
forc completions Generate shell completion scripts
forc plugins List all discovered forc-* plugins
forc addr2line Resolve bytecode addresses to source locations

5.2 forc build — Complete Flag Reference

forc build [OPTIONS]

Core Options:
  --path <PATH>                    Project root [default: .]
  --release                        Enable Opt1 IR optimizations
  --profile <PROFILE>              Use named build profile from Forc.toml
  --target <TARGET>                Build target: fuel (default) or evm
  --locked                         Require Forc.lock to be current; fail if not
  --offline                        No network access; use cache only
  --ipfs-node <URL>                Custom IPFS gateway URL

Output Options:
  --output-dir <DIR>               Override output directory [default: out/]
  --output-bin-path <PATH>         Override output .bin path
  --json-abi                       Emit ABI as JSON to stdout
  --json-abi-with-callpaths        Emit ABI with fully-qualified call paths

Diagnostic Options:
  --print-ast                      Print typed AST to stdout
  --print-dasm                     Print desugared ASM
  --print-finalized-asm            Print final allocated ASM
  --print-ir                       Print generated SSA IR
  --time-phases                    Print wall-clock timing per compiler phase
  --ir-opt <PASSES>                Comma-separated IR optimization pass list
  --error-on-warnings              Treat all warnings as errors

Verbosity Options:
  -v, --verbose                    Verbose output
  -s, --silent                     Suppress all output
  --terse                          Suppress warnings in output

5.3 forc test — Complete Flag Reference

forc test [OPTIONS] [TEST_FILTER]

Options:
  --path <PATH>           Project root
  --release               Optimize before testing (Opt1)
  --logs                  Display VM execution logs during tests
  --raw-log               Display raw log bytes
  --filter-exact          Match test names exactly (substring match by default)
  --count                 Print test count without running
  --node-url <URL>        Fuel node URL for integration tests
  --default-salt          Use deterministic salt for reproducible contract IDs
  --locked                Require lockfile to be current
  --offline               No network; cache only

5.4 forc-debug — DAP Server

forc-debug implements the Debug Adapter Protocol (DAP), enabling IDE-integrated debugging of Sway contracts and scripts running against a live Fuel node.

# Start DAP server connecting to fuel-core at default address
forc debug --serve

# Connect to a remote or non-default node
forc debug --serve --api-url http://192.168.1.100:4000/graphql
Option Default Description
--api-url http://127.0.0.1:4000/graphql Fuel node GraphQL endpoint
--serve off Start DAP server on stdin/stdout

The DAP server translates between the DAP protocol (VS Code, Neovim DAP, etc.) and the Fuel node's debug API, supporting:

  • Breakpoints (by source line and bytecode offset)
  • Step over / step into / step out
  • Register and memory inspection
  • Stack frame navigation
  • Variable watches

5.5 forc-lsp — Language Server

# Start LSP server (editor launches this via stdin/stdout)
forc lsp

# Verbose LSP logging (useful for LSP client debugging)
forc lsp --verbose

LSP capabilities implemented in sway-lsp:

Capability Supported
Text document sync Full (on save)
Publish diagnostics Yes (errors + warnings)
Hover (type info, doc comments) Yes
Go-to-definition Yes
Find all references Yes
Completion (items, keywords) Yes
Code actions Yes
Rename symbol Yes
Semantic tokens Yes
Document symbols Yes
Workspace symbols Yes
Signature help Yes
Formatting (forc fmt integration) Yes

5.6 forc-doc — Documentation Generation

# Generate HTML docs for current package
forc doc

# Open in default browser after generation
forc doc --open

# Generate docs for all workspace members
forc doc --workspace

# Specify output directory
forc doc --out-dir ./docs/

Output is placed in out/doc/ relative to the project root. HTML is generated using the horrorshow templating library following swaydoc conventions (styled similar to rustdoc).

5.7 forc-publish — Package Registry

# Publish current package
FORC_PUB_TOKEN=<token> forc publish

# Dry run — validate without actually publishing
forc publish --dry-run

# Specify registry URL
forc publish --registry https://registry.fuel.network

# Verify your token is set
echo $FORC_PUB_TOKEN

Important

FORC_PUB_TOKEN must be set in the environment. Never hard-code registry tokens in Forc.toml or commit them to version control. Store them in CI secrets (GitHub Actions: Settings → Secrets and variables → Actions).

5.8 forc-migrate — Breaking Change Migration

forc-migrate automates source-level migrations when Sway introduces breaking language changes. The plugin contains 10 migration definitions (~51K chars).

# List available migrations and which apply to current code
forc migrate list

# Apply all applicable migrations to current project
forc migrate

# Preview changes without modifying files
forc migrate --dry-run

# Apply a specific migration
forc migrate <migration-name>

Note

Always run forc migrate --dry-run and review the diff before applying. Commit the un-migrated code first so the migration is a separate, reviewable commit.

5.9 forc-fmt — Code Formatter

# Format all .sw files in project
forc fmt

# Check formatting in CI (exit code 1 if any file needs changes)
forc fmt --check

# Format a specific file
forc fmt --path src/main.sw

# Use a specific config file
forc fmt --config-path /path/to/swayfmt.toml

The formatter is deterministic and idempotent: running it twice on any file produces identical output. All contributions to the Sway repository must pass forc fmt --check in CI.

5.10 forc-tx — Transaction Builder

# Build a transaction (subcommands vary by tx type)
forc tx create [OPTIONS]
forc tx script [OPTIONS]

forc-tx is used for constructing raw Fuel transactions programmatically, particularly useful for testing contract interactions outside of the SDK.

5.11 Operational Runbooks

Diagnosing a Compilation Failure

# Step 1: Full verbose output
RUST_BACKTRACE=1 forc build --verbose 2>&1 | tee build.log

# Step 2: Check which phase failed
forc build --time-phases 2>&1 | tail -20

# Step 3: Inspect IR for type/codegen issues
forc build --print-ir 2>&1 | tee ir_dump.txt

# Step 4: Inspect typed AST for type checker issues
forc build --print-ast 2>&1 | tee ast_dump.txt

# Step 5: Inspect final ASM for code generation issues
forc build --print-finalized-asm 2>&1 | tee asm_dump.txt

Warning

If the compiler panics (ICE — Internal Compiler Error), this is always a bug in the compiler, not your code. File an issue at https://github.com/FuelLabs/sway/issues with the full panic message, RUST_BACKTRACE=full output, and the smallest possible reproducer.

Resolving Dependency Conflicts

# Update all dependencies to latest compatible versions
forc update

# Update a specific dependency
forc update sway_standards

# View the full dependency tree
# (if forc-tree plugin is installed)
forc tree

# Force re-resolve (delete lockfile and rebuild)
rm Forc.lock && forc build

Warning

Deleting Forc.lock in a production project may pull in newer transitive dependency versions that introduce breaking changes. Prefer forc update <specific-dep> for surgical dependency updates.

Clearing the Package Cache

# Clear all cached packages (will re-fetch on next build)
rm -rf ~/.forc/cache/

# Clear only git dependency caches
rm -rf ~/.forc/cache/git/

# Clear only IPFS caches
rm -rf ~/.forc/cache/ipfs/

Verifying a Build is Reproducible

# Build 1
forc build --locked --offline
sha256sum out/debug/my_contract.bin > hash1.txt

# Clean and rebuild
forc clean
forc build --locked --offline
sha256sum out/debug/my_contract.bin > hash2.txt

# Compare (should be identical)
diff hash1.txt hash2.txt

6. Performance

6.1 Compiler Performance Characteristics

The Sway compiler is designed for incremental workloads in LSP contexts. sway-lsp maintains a persistent in-memory typed program state, recompiling only on file save. For batch forc build, performance scales approximately linearly with total source size.

Note

The LSP uses dashmap (lock-free concurrent HashMap) throughout sway-lsp to allow parallel read-heavy IDE operations (hover, completion, references) while serializing write-heavy compilation updates. This provides sub-10ms response times for most IDE interactions on typical contract codebases.

6.2 Optimization Levels

Level forc build flag Forc.toml value Description
Opt0 (default) optimization_level = "0" No IR optimization; fastest compile time
Opt1 --release optimization_level = "1" Full IR optimization suite

Use Opt0 during development for fast iteration. Opt1 for production: the resulting bytecode is meaningfully smaller (fewer instructions) and faster (fewer redundant computations on-chain, lowering gas costs).

6.3 IR Optimization Passes

The sway-ir pass manager applies passes in a configured sequence. Individual passes can be selected with --ir-opt <pass1,pass2,...>.

Pass Kebab Name Description
Constant folding const-folding Evaluate pure constant expressions at compile time
Constant demotion const-demotion Spill large constants from registers to memory
Function inlining fn-inline Inline small or single-call functions
Dead code elimination dce Remove unreachable code and unused values
Scalar replacement of aggregates sroa Decompose struct accesses into scalar operations
Simplify CFG simplify-cfg Merge basic blocks, remove unreachable blocks
Memory to register mem2reg Promote stack allocations to SSA registers
Loop invariant code motion licm Hoist loop-invariant computations out of loops

Custom pass sequence example:

forc build --release --ir-opt "const-folding,fn-inline,dce,simplify-cfg,mem2reg"

6.4 Performance Benchmarking with just

# End-to-end compilation performance benchmark
just perf-e2e

# In-language test execution performance
just perf-in-lang

# Run all benchmarks
just perf-all

# Diff current performance against the previous baseline
just perf-diff

# Diff against the latest published release
just perf-diff-latest

Performance data is collected with the --perf flag on the test harness, measuring wall-clock time per compiler phase.

6.5 Memory Allocator

tikv-jemallocator is configured as the global Rust allocator for forc and other binaries. jemalloc outperforms the system allocator for compiler workload patterns (high rates of small, short-lived allocations during parsing and type checking).

// Applied in forc/src/main.rs
#[cfg(feature = "jemalloc")]
#[global_allocator]
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;

6.6 Build Caching with sccache

For large CI environments building the Sway compiler itself frequently:

# Install sccache
cargo install sccache

# Set sccache as the Rust compiler wrapper
export RUSTC_WRAPPER=sccache

# Build with caching
cargo build --release --workspace

# View cache statistics
sccache --show-stats

6.7 Parallel Package Builds

forc-pkg constructs a dependency DAG using petgraph and builds packages in topological order. Independent packages are built in parallel (thread count defaults to number of logical CPUs, configurable with --jobs/-j):

# Use 8 parallel jobs
forc build --jobs 8

# Use half the available CPUs
forc build --jobs $(nproc --ignore=1)

7. Security

7.1 Open Security Advisories

Caution

Two active RUSTSEC advisories affect the Sway toolchain dependency tree as of source commit e12e611 (version 0.71.0). Review these before deploying build infrastructure that processes untrusted Sway source code.

RUSTSEC-2025-0055 — ANSI Escape Sequence Log Poisoning (Issue #7589)

Affected: A logging/terminal display dependency in the toolchain.

Risk: Maliciously crafted content — such as a package name or compiler error message containing ANSI escape sequences — could manipulate terminal output. In CI systems displaying raw build logs, this could suppress or hide critical warnings from human reviewers.

Mitigation:

# Strip ANSI codes from forc output in automated pipelines
forc build 2>&1 | sed 's/\x1B\[[0-9;]*[mK]//g' > build.log

# Or use --terse to reduce styled output
forc build --terse 2>&1 > build.log
  • Pin the affected transitive dependency to a patched version once available.
  • Use --json-abi for programmatic ABI consumption instead of parsing terminal output.

RUSTSEC-2026-0049 — CRL Matching Logic Flaw (Issue #7576)

Affected: TLS certificate validation in the HTTPS dependency-fetching path.

Risk: Certificate Revocation Lists (CRLs) may not be properly honored during git or IPFS dependency fetching. A revoked TLS certificate for a dependency host could be accepted, enabling potential man-in-the-middle attacks on dependency downloads.

Mitigation:

# Use --locked --offline for all production/CI builds
# This prevents dependency fetching entirely
forc build --locked --offline
  • Fetch dependencies on a separate, network-isolated build step; then pass --offline to the actual compilation step.
  • Apply the patched dependency version once the upstream fix is merged and released.

Warning

Never run forc build against untrusted Forc.toml files without sandboxing. A malicious Forc.toml could cause forc-pkg to fetch and compile arbitrary Sway source from remote git repositories. Use --locked --offline to prevent this, or run in an isolated container with --network none.

7.2 Supply Chain Security

Dependency Pinning

# Audit all Rust dependencies for known advisories
cargo install cargo-audit
cargo audit

# Generate a Software Bill of Materials
cargo install cargo-sbom
cargo sbom > sbom.json

# Ensure Forc.lock is committed and unchanged
git diff --exit-code Forc.lock || (echo "Forc.lock has uncommitted changes" && exit 1)

Reproducible Builds

# Always use --locked in CI to prevent accidental dependency updates
forc build --locked

# Verify output bytecode hash against a known-good value
EXPECTED="sha256:abc123..."
ACTUAL=$(sha256sum out/debug/my_contract.bin | awk '{print "sha256:"$1}')
[ "$EXPECTED" = "$ACTUAL" ] || (echo "Bytecode mismatch!" && exit 1)

7.3 Sandboxing Untrusted Builds

When compiling untrusted Sway source (e.g., third-party contract submissions or security research):

# Minimal Docker sandbox
docker run --rm \
  --network none \
  --read-only \
  --tmpfs /tmp:exec,size=512m \
  -v /path/to/project:/workspace:ro \
  -v /path/to/output:/out:rw \
  ghcr.io/fuellabs/fuel-toolchain:latest \
  forc build \
    --path /workspace \
    --output-dir /out \
    --locked \
    --offline

# Even more restricted: drop all capabilities
docker run --rm \
  --network none \
  --read-only \
  --tmpfs /tmp:exec,size=512m \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  -v /path/to/project:/workspace:ro \
  -v /path/to/output:/out:rw \
  ghcr.io/fuellabs/fuel-toolchain:latest \
  forc build --path /workspace --output-dir /out --locked --offline

Key isolation measures:

  • --network none — Prevents forc-pkg from fetching remote dependencies
  • --read-only — Source is read-only; builds go to a writable volume
  • --locked --offline — Enforces pre-resolved lockfile; no network access
  • --cap-drop ALL — No Linux capabilities (prevents privilege escalation)

7.4 CEI Pattern Analysis — Reentrancy Detection

The Sway compiler performs Checks-Effects-Interactions (CEI) pattern analysis to detect reentrancy vulnerability patterns at compile time. A CEI violation occurs when a storage write ("effect") is performed after an external contract call ("interaction").

contract;

abi VulnerableContract {
    fn withdraw(amount: u64);
}

impl VulnerableContract for Contract {
    fn withdraw(amount: u64) {
        let sender = msg_sender().unwrap();
        
        // INTERACTION: external call before state update
        transfer(amount, AssetId::base(), sender);
        
        // EFFECT: storage update after — CEI violation warning
        storage.balance.write(storage.balance.read() - amount);
    }
}

Correct CEI pattern:

fn withdraw(amount: u64) {
    let sender = msg_sender().unwrap();
    
    // EFFECT first: update state
    storage.balance.write(storage.balance.read() - amount);
    
    // INTERACTION after: now safe
    transfer(amount, AssetId::base(), sender);
}

Warning

CEI warnings are currently nondeterministic (GitHub issue #7606). The same source file may or may not trigger the warning across different compilations. Do not rely solely on the CEI checker. Apply manual code review, test reentrancy scenarios explicitly, and treat any CEI warning as a definitive finding requiring immediate remediation.

To treat CEI violations as hard errors:

forc build --error-on-warnings

7.5 Compiler Security Properties

Property Implementation
No arbitrary OS syscalls FuelVM is a sandboxed virtual machine; no OS access
Memory safety (compiler) Rust ownership system throughout the compiler
Memory safety (contracts) FuelVM has no raw pointer arithmetic
Integer overflow Sway panics on overflow in debug; configurable in release
Reentrancy detection CEI pattern analysis at compile time (with caveats)
Immutable storage keys Storage key layout computed deterministically from ABI
Deterministic contract IDs Contract ID = hash of bytecode + salt; fully deterministic

7.6 ABI Encoding Security

The generated ABI JSON specifies the canonical encoding for all public contract functions. Incorrect encoding causes transaction revert (not silent data corruption). Key points:

  • Function selectors are 4-byte SHA-256 prefixes of the canonical signature
  • Parameter encoding is strict; mismatches revert
  • The new_encoding experimental feature changes the wire format — enabling it on an already-deployed contract breaks all callers using the old format
  • Configurable constants (configurables) are embedded in bytecode at deploy time and cannot be changed post-deployment

8. Developer Internals

8.1 Compiler Pipeline — Phase-by-Phase Analysis

Phase 1: Parsing (sway-parse)

Source size: 17 files, 121K characters

The parser is a hand-written recursive-descent parser operating in two stages:

Lexer tokenizes source text into a typed token stream:

  • Keywords (fn, let, match, if, contract, ...)
  • Identifiers, integer literals, string literals, boolean literals
  • Operators, punctuation, delimiters
  • Doc comments (///) preserved as AST nodes
  • Full byte-offset span tracking per token

Parser consumes tokens and produces sway-ast node trees:

  • Uses ParseToEnd and ParseBracket combinators for delimiter-bounded sequences
  • Recursive descent with direct precedence climbing for expressions
  • Error recovery is minimal; most parse errors are immediately fatal
  • All produced nodes carry Span information for downstream error reporting

Key public entry point:

pub fn parse_file(
    handler: &Handler,
    src: Arc<str>,
    path: Option<Arc<PathBuf>>,
) -> Result<ParsedTree, ErrorEmitted>

Phase 2: AST Representation (sway-ast)

sway-ast defines the concrete syntax tree — a direct structural reflection of the source text. All nodes carry Span. The AST is NOT yet type-annotated at this stage.

Key node families:

Family Node Examples
Items (top-level declarations) ItemFn, ItemImpl, ItemTrait, ItemStruct, ItemEnum, ItemStorage, ItemConst, ItemUse, ItemConfigurable
Expressions ExprIf, ExprMatch, ExprBlock, ExprCall, ExprMethodCall, ExprBinary, ExprUnary, ExprIndex, ExprTuple
Type expressions TyTuple, TyArray, TyPath, TyInfer, TyStr, TyPrimitive, TyPtr, TySlice
Patterns PatLiteral, PatIdent, PatTuple, PatStruct, PatEnum, PatWildcard, PatOr
Statements StatementLet, StatementExpr

Phase 3: Type Checking (sway-core — type_system/)

Source size: 282K characters — the largest single subsystem

The type checker performs six major operations:

  1. Name resolution — Resolves identifiers to declarations in the namespace, traversing module boundaries and handling use imports.

  2. Type inference — Bidirectional type inference with constraint propagation. Types flow both top-down (from context) and bottom-up (from literals and calls).

  3. Monomorphization — Instantiates generic functions and types with concrete type arguments. Memoized in the declaration engine to avoid duplicate work.

  4. Trait resolution — Resolves which impl Trait for T block satisfies each trait constraint, checking that all associated types and methods are provided.

  5. Type unification — Merges type variables with concrete types during inference. Failed unification produces type mismatch errors.

  6. Coercion — Applies implicit coercions where permitted (e.g., b256 to Address).

The type system uses TypeId handles (integer indices) into the TypeEngine to represent all types, avoiding recursive data structures:

// The TypeEngine maps TypeId -> TypeInfo
pub enum TypeInfo {
    Unknown,
    UnknownGeneric { name: Ident, trait_constraints: VecSet<TraitConstraint> },
    Placeholder(TypeParameter),
    TypeParam(usize),
    StringSlice,
    StringArray { length: Length },
    UnsignedInteger(IntegerBits),  // U8, U16, U32, U64, U256
    Boolean,
    Tuple(Vec<TypeArgument>),
    B256,
    Numeric,               // Unresolved numeric literal
    Contract,
    ErrorRecovery(ErrorEmitted),
    Array(TypeArgument, Length),
    RawUntypedPtr,
    RawUntypedSlice,
    Ptr(TypeArgument),
    Slice(TypeArgument),
    Enum(DeclRefEnum),
    Struct(DeclRefStruct),
    ContractCaller { abi_name: AbiName, address: Box<TypedExpression> },
    Custom { qualified_call_path: QualifiedCallPath, type_arguments: Option<Vec<TypeArgument>> },
    SelfType,
    Alias { name: Ident, ty: TypeArgument },
    TraitType { name: Ident, trait_type_id: TraitTypeId },
}

Known active issues:

  • #7603 — ICE from invalid type unification of arrays (type variable scope escape)
  • #7604 — Compiler panic with type aliases + const generic arrays
  • #7602 — ICE when indexing self[i] with const generic index
  • #7605 — Confusing out-of-bounds error for const generic arrays

Phase 4: Declaration Engine (sway-core — decl_engine/)

Source size: 93K characters

The declaration engine manages the lifecycle of all named declarations using opaque integer handles, decoupling declaration identity from type-checking state. This enables incremental recompilation: unchanged declarations retain their handles and cached type information across rebuilds.

Core types:

pub struct DeclEngine {
    // Stores all typed declarations by DeclId
    // Supports: function, struct, enum, trait, impl, ...
}

// Typed handle to a specific declaration
pub struct DeclRef<T> {
    pub name: Ident,
    pub id: DeclId,
    pub decl_span: Span,
    _marker: PhantomData<T>,
}

pub struct DeclId(usize);  // Opaque integer

The declaration engine also caches monomorphized instances, so Vec<u64> and Vec<bool> are each generated once regardless of how many times they appear in the codebase.

Phase 5: Control Flow Analysis

Two analysis passes run on the fully typed AST:

Dead Code Analysis

  • Constructs a reachability graph from all entry points
  • Marks unused functions, variables, struct fields, and use imports
  • Emits Warning::DeadCode variants for each unused item
  • Respects visibility: pub items are considered reachable even if not locally called

CEI Pattern Analysis

  • Scans each function body for the pattern: external contract call followed by storage write
  • Constructs a partial temporal order of side-effecting operations
  • Emits Warning::StorageWriteAfterContractCall on violations
  • Known issue #7606: HashMap iteration order affects which violations are detected in which order; the set of reported violations can vary between invocations

Phase 6: IR Generation (sway-ir)

Source size: 481K characters, 21 files

The compiler lowers the typed AST to SSA-form (Static Single Assignment) intermediate representation. Every variable is assigned exactly once; phi nodes merge values at control flow join points.

IR container hierarchy:

Module
  └── Function (one per Sway function)
        ├── Argument list
        └── Block (basic block: sequential instructions, ends with branch/ret)
              └── Instruction (SSA value-producing or effect-producing)

All IR instruction variants:

Instruction Description
AsmBlock Inline assembly block (raw FuelASM)
BitCast Bitwise reinterpretation between types of equal size
BinaryOp Arithmetic (+, -, *, /, %) and bitwise (&,
Branch Unconditional jump to a basic block
Call Internal function call
CastPtr Pointer type cast (changes pointee type, not bits)
Cmp Comparison: eq, ne, lt, le, gt, ge
ConditionalBranch Conditional jump: if cond goto true_bb else false_bb
ContractCall External contract invocation via ABI
ExtractElement Extract element from array or slice
ExtractValue Extract field from struct/tuple by index path
FuelVm(FuelVmInstruction) FuelVM-specific: Log, Revert, Smo, StateClear, StateLoadQuadWord, StateLoadWord, StateStoreQuadWord, StateStoreWord, WideUnaryOp, WideBinaryOp, WideCmpOp, WideModularOp
GetElemPtr GEP-style: compute pointer to sub-element of aggregate
GetLocal Get pointer to a local (stack) variable
GetGlobal Get pointer to a module-level global
InsertElement Insert element into array/slice (returns new value)
InsertValue Insert field into struct/tuple (returns new value)
IntToPtr Cast integer to raw pointer
Load Dereference pointer
MemCopyBytes Copy N bytes between two pointers
MemCopyVal Typed copy between two pointers
Nop No-operation (placeholder)
PtrToInt Cast pointer to integer
Ret Return from function
Revert Revert the transaction with a code
Store Write value through pointer

IR text format for debugging:

// Example IR snippet (schematic)
fn my_function(a: u64, b: u64) -> u64 {
entry(a: u64, b: u64):
  v0 = add a, b
  ret u64 v0
}
# Dump IR to stdout during build
forc build --print-ir

# Parse IR text back to IR data structure (for testing)
# (internal tool; no direct forc command)

Phase 7: IR Optimization

The PassManager orchestrates optimization passes. Each pass implements:

pub trait Pass {
    fn name(&self) -> &str;
    fn descr(&self) -> &str;
    fn run(
        &self,
        module: &mut Module,
        analysis_results: &AnalysisResults,
    ) -> Result<bool, IrError>;   // bool = whether the IR was modified
    fn analyses_required(&self) -> Vec<AnalysisName>;
}

The pass manager tracks which analyses are valid after each pass and re-runs invalidated analyses before dependent passes execute. The default Opt1 pass sequence is configured internally in sway-core.

Phase 8: ASM Generation (sway-core — asm_generation/)

Source size: 196K characters

Three-stage lowering from IR to bytecode:

Stage 1 — Virtual ASM

  • Architecture-agnostic assembly
  • Unlimited virtual registers (VRs)
  • IR instructions mapped to FuelASM instruction sequences
  • Memory layout computed for all locals and aggregates

Stage 2 — Allocated ASM

  • Virtual registers mapped to physical FuelVM registers (r0–r63) via linear scan
  • Spill code inserted for registers that exceed the physical count
  • Calling convention enforced (argument passing, return values)

Stage 3 — Final ASM

  • Labels resolved to byte offsets
  • Jump targets patched
  • Inline assembly blocks integrated
  • Final instruction stream ready for bytecode emission

Phase 9: ABI Generation

Fuel ABI generator (fuel_abi.rs): produces the standard Fuel JSON ABI format, including:

  • All public contract functions with canonical type encoding
  • Function selector (4-byte SHA-256 prefix of canonical signature)
  • Storage read/write attributes
  • payable attribute
  • Log types
  • Configurable constants

EVM ABI generator (evm_abi.rs): produces EVM-compatible Solidity ABI JSON for contracts targeting the EVM build target.

8.2 The Engines Architecture

sway-core uses a central Engines struct to thread shared mutable state through the compiler without passing arguments everywhere:

pub struct Engines {
    pub type_engine: TypeEngine,
    pub decl_engine: DeclEngine,
    pub parsed_decl_engine: ParsedDeclEngine,
    pub query_engine: QueryEngine,
    pub source_engine: SourceEngine,
}

impl Engines {
    pub fn te(&self) -> &TypeEngine { &self.type_engine }
    pub fn de(&self) -> &DeclEngine { &self.decl_engine }
    pub fn se(&self) -> &SourceEngine { &self.source_engine }
}

This pattern:

  • Makes engine access explicit and auditable (not global state)
  • Enables testing with isolated engine instances
  • Allows the query engine to track dependencies between engine accesses for incremental compilation invalidation

8.3 Module Reference — All Workspace Crates

sway-parse

Component Location Description
Lexer src/lexer/ Tokenizes source text; produces TokenStream
Parser entry src/lib.rs parse_file() public API
Expression parser src/expr/ All expression parsing rules
Item parser src/item/ Top-level declaration parsing
Type parser src/ty/ Type expression parsing
Pattern parser src/pattern/ Pattern matching construct parsing
Combinators src/priv_prelude.rs ParseToEnd, ParseBracket, Peek

sway-ast

Component Location Description
Expressions src/expr/ All expression AST variants
Items src/item/ All declaration AST variants
Types src/ty.rs Type expression variants
Patterns src/pattern.rs Pattern variants
Literals src/literal.rs Literal value types

sway-core

Sub-module Approx Size Description
type_system/ 282K chars Type inference, unification, monomorphization, trait resolution
decl_engine/ 93K chars Declaration lifecycle, handle-based storage
asm_generation/ 196K chars Virtual → Allocated → Final assembly
ir_generation/ significant Typed AST → sway-ir lowering
control_flow_analysis/ moderate Dead code, CEI analysis
language/ significant Typed AST node definitions (parallel to sway-ast)
semantic_analysis/ significant Name resolution, namespace management
transform/ moderate AST desugaring and normalization passes
query_engine/ moderate Query-based incremental compilation interface

sway-ir

Component File Description
Module src/module.rs Top-level IR container
Function src/function.rs IR function (args, return type, blocks)
Basic Block src/block.rs Sequence of instructions + terminator
Instruction src/instruction.rs All IR instruction variants
IR Types src/irtype.rs IR type system (flat, no generics)
Values src/value.rs SSA values: instructions + constants
Constants src/constant.rs Compile-time constants
Pass Manager src/pass_manager.rs Pass ordering and execution
Analyses src/analysis/ Dominators, use-def chains, call graph
Passes src/passes/ One file per optimization pass
Printer src/printer.rs IR to text format
Parser src/parser.rs Text format to IR (for tests)
IR Macros sway-ir-macros/ Proc-macros for IR construction in tests

sway-error

// Core types in sway-error
pub struct Handler {
    inner: RefCell<HandlerInner>,
}

pub struct HandlerInner {
    pub errors: Vec<(Span, CompileError)>,
    pub warnings: Vec<CompileWarning>,
}

pub struct ErrorEmitted;  // Zero-size type; returned from functions that emit errors

The Handler is passed through every compilation phase. Errors are collected (not immediately fatal) allowing multiple errors to be reported per build. An Err(ErrorEmitted) return means at least one error was emitted to the handler; the caller can continue or propagate.

sway-features

pub struct ExperimentalFeatures {
    pub new_encoding: bool,
    pub references: bool,
    pub new_hashing: bool,
    pub str_array_no_padding: bool,
    pub dynamic_storage: bool,
}

impl ExperimentalFeatures {
    // Reads FORC_EXPERIMENTAL and FORC_NO_EXPERIMENTAL env vars
    pub fn from_env() -> Self { ... }
    
    // Construct with all features disabled
    pub fn none() -> Self { ... }
}

sway-types

Type Description
Span Source location: SourceId + byte start + byte end
Ident Identifier string + Span
SourceId Opaque file identifier (integer)
SourceEngine Maps SourceId ↔ file path and full source content
Spanned Trait: fn span(&self) -> Span
Named Trait: fn name(&self) -> &Ident

sway-utils

Key constants:

pub const MANIFEST_FILE_NAME: &str = "Forc.toml";
pub const MAIN_ENTRY: &str = "main.sw";
pub const LIB_ENTRY: &str = "lib.sw";
pub const DEFAULT_OUTPUT_DIRECTORY: &str = "out";
pub const LOCK_FILE_NAME: &str = "Forc.lock";
pub const SWAYFMT_CONFIG_FILE_NAME: &str = "swayfmt.toml";

Key functions:

// Search upward from starting_directory for Forc.toml
pub fn find_manifest_dir(starting_directory: &Path) -> Option<PathBuf>

// Search upward for workspace root (Forc.toml with [workspace])
pub fn find_workspace_dir(starting_directory: &Path) -> Option<PathBuf>

swayfmt

Module Description
src/config/ All configuration type definitions and defaults
src/formatter/ Core formatting state machine and entry points
src/utils/comments/ Comment preservation and correct placement
src/utils/expressions/ Expression formatting rules
src/utils/heuristics/ Width-based line-break decisions
src/utils/imports/ use statement formatting and grouping
src/utils/items/ Item (declaration) formatting
src/utils/literals/ Literal value formatting
src/utils/ordering/ Item ordering within module scope
src/utils/structures/ Struct and enum formatting
src/utils/whitespace/ Indentation and newline normalization

Public API:

pub fn format_text(src: &Arc<str>) -> Result<String, FormatterError>

pub fn format_text_with_config(
    src: &Arc<str>,
    config: &FormatterConfig,
) -> Result<String, FormatterError>

sway-lsp

Component Description
src/server.rs tower-lsp LanguageServer trait implementation
src/capabilities.rs LSP ServerCapabilities construction
src/core/session.rs Per-workspace compilation session (holds typed program)
src/core/document.rs Per-file text document state and version tracking
src/handlers/ Individual LSP request handlers
src/traverse/ Post-compilation AST traversal for IDE feature queries

Concurrency model: dashmap::DashMap provides lock-free concurrent access to the document store and session state. Read-heavy operations (hover, completion, diagnostics) proceed without blocking; the compilation lock serializes write access to the typed program state.

forc

forc/src/
  main.rs              Jemalloc setup, async runtime, CLI dispatch
  cli/
    mod.rs             Subcommand enum and dispatch table
    build.rs           forc build
    check.rs           forc check
    clean.rs           forc clean
    new.rs             forc new / forc init
    deploy.rs          forc deploy
    run.rs             forc run
    test.rs            forc test
    update.rs          forc update
    add.rs             forc add
    remove.rs          forc remove
    contract_id.rs     forc contract-id
    parse_bytecode.rs  forc parse-bytecode
    completions.rs     forc completions
    plugins.rs         forc plugins
    addr2line.rs       forc addr2line

forc-pkg

Component Description
src/manifest/ Forc.toml parsing, validation, workspace detection
src/lock.rs Forc.lock reading and writing
src/source/ Dependency fetching: path/, git/, ipfs/
src/pkg.rs Package compilation orchestration
src/build_plan.rs Dependency DAG construction, topological sort
src/compiled_package.rs Compiled package artifact type
src/lib.rs Public API

The dependency graph is a petgraph::Graph<Node, Edge>. Topological ordering via petgraph::algo::toposort determines build order. Cycle detection uses petgraph::algo::is_cyclic_directed.

forc-test

Implements the Sway unit test runner:

  1. Compiles the package with test functions enabled
  2. Deploys the contract to an in-process FuelVM instance
  3. Calls each #[test] function as an ABI method
  4. Reports pass/fail based on whether the call reverts

forc-util

Component Description
Bytecode parsing Disassembly of FuelVM .bin bytecode
CLI utilities Shared clap arg types, error formatting
Node connection Shared fuel-core-client setup

forc-debug

Implements the DAP server. Main loop:

  1. Start tokio async runtime
  2. Connect to Fuel node GraphQL endpoint (--api-url)
  3. Listen on stdin for DAP protocol messages (JSON-RPC)
  4. Translate DAP requests (set-breakpoint, step, continue) to Fuel node debug API calls
  5. Send DAP events (stopped, output) back on stdout

forc-doc

  1. Compiles the package with forc-pkg
  2. Walks the typed AST for all public items (functions, structs, enums, traits)
  3. Extracts doc comments (/// and //!)
  4. Generates HTML pages using horrorshow macros
  5. Writes output to out/doc/

forc-migrate

For each defined migration:

  1. Scan source files for patterns matching the deprecated form
  2. Apply AST-aware or regex-based transforms
  3. Write modified files (or preview in --dry-run)
  4. Report what was changed

forc-publish

  1. Validate Forc.toml (required fields)
  2. Run forc check to ensure the package type-checks
  3. Create a source tarball (excluding build artifacts and .forc/)
  4. Upload to the registry via HTTP using FORC_PUB_TOKEN

8.4 Error Message Taxonomy

The compiler emits 295 distinct diagnostic types across all phases, split between hard errors (CompileError) and warnings (CompileWarning).

Parse Error Categories

Category Approx Count Representative Messages
Unexpected token ~15 UnexpectedToken, ExpectedToken, UnexpectedEndOfInput
Invalid literal ~8 InvalidIntegerLiteral, InvalidHexLiteral, InvalidStrEscape
Invalid syntax ~20 Misplaced keywords, invalid attribute syntax, bad annotation
Delimiter mismatch ~5 Unclosed braces, mismatched parentheses, extra closing delimiter

Type Error Categories

Category Approx Count Representative Messages
Type mismatch ~25 TypeError, MismatchedType, ArgumentParameterTypeMismatch
Unresolved type ~15 UnresolvedType, UnknownType, UnableToInferGeneric
Generic constraint violation ~12 TraitConstraintNotSatisfied, TraitNotImplemented
Array/slice errors ~8 InvalidArrayLength, ArrayOutOfBounds, ConstantEvaluationError
Integer range/cast ~6 IntegerTooLarge, IntegerOverflow, TypeCastNotAllowed
Self type errors ~5 InvalidSelfParam, SelfParameterNotAllowedForContract
Numeric type errors ~6 MultipleDefinitionsOfName, UnreachablePattern

Declaration Error Categories

Category Approx Count Representative Messages
Duplicate declaration ~12 DuplicateDeclaration, MultipleDefinitionsOfName
Missing declaration ~10 SymbolNotFound, FunctionNotFound, MethodNotFound
Visibility errors ~8 ModuleNotFound, PrivateField, ImportPrivateModule
Trait/impl errors ~15 MissingInterfaceSurfaceMethods, ImplSelfWithoutSelf, TraitImplNotAllowed
Storage errors ~12 InvalidStorageField, StorageAccessMismatch, StorageNotDeclared

Control Flow Error Categories

Category Approx Count Representative Messages
Unreachable code ~5 UnreachableCode, MatchPatternAlreadyCovered
Missing return ~3 MissingReturnStatement, ReturnStatementNotAllowed
CEI violation ~4 StorageWriteAfterContractCall
Loop issues ~2 BreakOutsideLoop, ContinueOutsideLoop

ABI Error Categories

Category Approx Count Representative Messages
Invalid ABI type ~8 InvalidABIType, ABIMethodNotFound, ABISupertraitNotABI
ABI encoding ~6 InvalidEncodingType, ABIHashTemplateError

Code Generation Error Categories

Category Approx Count Representative Messages
Register allocation ~5 TooManyRegisters
Unsupported operation ~10 OperationNotSupported, TargetNotSupported
IR errors ~8 IrGenError, IsizeTooBig

Warning Categories

Category Approx Count Representative Messages
Dead code ~8 DeadCode, UnusedVariable, UnusedImport, UnusedReturnValue
Deprecated usage ~5 Deprecated
Style ~3 NonSnakeCaseStructFieldName, NonCamelCaseTypeName
CEI pattern ~4 StorageWriteAfterContractCall
Shadow warning ~3 ShadowsOtherSymbol

8.5 Storage Layout Reference

storage {
    // Simple field: key = sha256("storage_domain:owner")
    owner: Address = Address::zero(),

    // Map: key for entry k = sha256(sha256("storage_domain:balances") ++ k)
    balances: StorageMap<Address, u64> = StorageMap::<Address, u64> {},

    // Vec: element i key = sha256(sha256("storage_domain:items") ++ i)
    items: StorageVec<u64> = StorageVec {},

    // Nested: StorageVec<StorageMap<...>> — see issue #6040 for limitations
}

Storage keys are deterministic and collision-resistant by construction:

  • Each storage field has a unique domain derived from its name
  • Map keys are hashed with the field domain, preventing aliasing
  • Vec indices are hashed with the field domain

Active storage bugs:

  • #6040 — StorageVec::insert() with deeply nested generic types
  • #7559 — Complex generic StorageKey<T> fails to resolve in certain patterns

8.6 Testing Infrastructure

Test Infrastructure Overview (test/ crate)

The test workspace member is the E2E test harness. Each test case is a Sway project in tests/ with a test.toml controlling behavior.

test.toml Format

# Category controls what the harness does with this test
category = "run"           # run | run_on_node | compile | unit_tests_pass | fail | disabled

# For "run" and "run_on_node" categories:
expected_output = "42\n"   # Expected stdout from script execution

# For "fail" category:
# (errors are checked against .stderr expected files)
Category Description
run Compile and execute; assert stdout matches expected_output
run_on_node Compile and run against a live fuel-core node
compile Compile only; assert success (or failure for expected_failure)
unit_tests_pass Compile and run all #[test] functions; assert all pass
fail Assert compilation fails with specific errors
disabled Skip; comment in test.toml explains why

Snapshot Tests

snapshot.toml drives compilation commands. Expected output is stored in .expected files adjacent to each test project.

# Run snapshot tests
cargo test --package test -- snapshot

# Update snapshots (when output intentionally changes)
UPDATE_EXPECT=1 cargo test --package test -- snapshot

In-Language Unit Tests

contract;

#[test]
fn addition_works() {
    assert_eq(1u64 + 1u64, 2u64);
}

#[test]
fn zero_division_reverts() {
    let _ = 1u64 / 0u64;  // should revert
}

#[test(should_revert)]
fn expected_revert() {
    revert(42);
}

Run with forc test. Harness compiles the package with tests enabled, deploys to an in-process VM, and calls each test function.

SDK Harness Tests (Rust)

use fuels::prelude::*;

// abigen! generates Rust bindings from the ABI JSON
abigen!(Contract(
    name = "MyToken",
    abi = "out/debug/my_token-abi.json"
));

#[tokio::test]
async fn test_mint() {
    let config = WalletsConfig::new(Some(1), None, None);
    let wallets = launch_custom_provider_and_get_wallets(config, None, None)
        .await
        .unwrap();
    let wallet = wallets.into_iter().next().unwrap();

    let id = Contract::load_from(
        "out/debug/my_token.bin",
        LoadConfiguration::default(),
    )
    .unwrap()
    .deploy(&wallet, TxPolicies::default())
    .await
    .unwrap();

    let contract = MyToken::new(id, wallet);
    let result = contract
        .methods()
        .mint(100u64)
        .call()
        .await
        .unwrap();
    assert_eq!(result.value, 100u64);
}

Performance Test Recipes

just perf-e2e          # Compile ~20 representative contracts; measure wall time
just perf-in-lang      # Run in-language tests; measure execution time
just perf-all          # Both of the above
just perf-diff         # Compare vs saved baseline (stored in perf_baseline/)
just perf-diff-latest  # Compare vs forc downloaded from latest GitHub release

8.7 Contributing — Development Workflow

First-Time Setup

git clone https://github.com/FuelLabs/sway.git && cd sway
rustup show                    # Installs pinned toolchain from rust-toolchain.toml
cargo install cargo-sort just  # Required by CI
cargo build --workspace        # Initial build
cargo test --workspace         # Run full test suite

CI Requirements (All Must Pass)

cargo sort --check --workspace      # Sorted [dependencies] in all Cargo.toml
cargo fmt --check --all             # Rust formatting
cargo clippy --all-targets \
  --workspace -- -D warnings        # No clippy warnings
forc fmt --check                    # Sway example formatting
cargo build --workspace             # Full build
cargo test --workspace              # Full test suite

Adding a Language Feature (Step-by-Step)

  1. AST nodes (sway-ast): Add new Item*, Expr*, or Ty* variants with Span fields
  2. Parser (sway-parse): Extend the relevant recursive descent rule to produce the new node; add ParseToEnd/ParseBracket combinators as needed
  3. Typed AST (sway-core/language/): Add corresponding typed variants; these hold TypeId instead of raw syntax types
  4. Type checker (sway-core/type_system/): Implement type-checking logic for the new node; use the Engines struct to access TypeEngine and DeclEngine
  5. IR lowering (sway-core/ir_generation/): Emit appropriate sway-ir instructions for the new construct
  6. Tests: Add test cases in tests/ covering both success and expected-failure scenarios; add a test.toml for each
  7. Book: Update docs/book/ with user-facing documentation
  8. Errors: If the feature introduces new error conditions, add variants to sway-error

Adding an IR Optimization Pass

  1. Create sway-ir/src/passes/my_pass.rs
  2. Implement Pass:
    pub struct MyPass;
    impl Pass for MyPass {
        fn name(&self) -> &str { "my-pass" }
        fn descr(&self) -> &str { "Describe what this pass does" }
        fn run(&self, module: &mut Module, _: &AnalysisResults) -> Result<bool, IrError> {
            // Modify IR; return Ok(true) if any change was made
            Ok(false)
        }
        fn analyses_required(&self) -> Vec<AnalysisName> { vec![] }
    }
    
  3. Register in sway-ir/src/pass_manager.rs
  4. Add tests in sway-ir/tests/ using the text IR parser

Filing a High-Quality Bug Report

# Capture the panic with full backtrace
RUST_BACKTRACE=full forc build --path /path/to/reproducer 2>&1 > bug_report.txt

# Note exact versions
forc --version >> bug_report.txt
rustc --version >> bug_report.txt

# Minimize the reproducer
# Remove code until the panic stops, then restore the last line removed

Include in the GitHub issue:

  • forc --version output
  • RUST_BACKTRACE=full output
  • Minimal self-contained Sway project that reproduces the issue
  • Operating system and architecture

Active High-Priority Issues for Contributors

Issue Title Severity
#7551 Compiler infinite loop Critical
#7603 ICE from invalid type unification of arrays High
#7604 Compiler panic with type aliases + const generic arrays High
#7602 ICE when accessing self[i] with const generics High
#7606 CEI warnings nondeterministic Medium
#7605 Confusing OOB error for const generic arrays Medium
#6040 StorageVec::insert() with nested types Medium
#7559 Generic StorageKey resolution failure Medium
#7589 RUSTSEC-2025-0055 ANSI escape log poisoning Low
#7576 RUSTSEC-2026-0049 CRL matching logic flaw Low

8.8 LSP Architecture Deep Dive

The sway-lsp server follows a session-based architecture to maintain workspace state across editor interactions:

Editor (VS Code, Neovim, Emacs, ...)
  ↕ JSON-RPC 2.0 (stdin/stdout, per LSP spec)
  ↕ Managed by tower-lsp framework
LSP Server Process (forc lsp → sway-lsp)
  ├── Compilation loop (triggered by textDocument/didSave)
  │     ├── forc-pkg: resolve dependencies
  │     ├── sway-parse: parse changed files
  │     ├── sway-core: type check, build typed program
  │     └── Update session state
  └── Request handlers (hover, completion, definition, references, ...)
        └── Query session state (read-only, concurrent via DashMap)

Performance design:

  • Compilation is triggered only on textDocument/didSave, not on every keystroke. This keeps compile overhead from blocking typing.
  • Between saves, all IDE requests (hover, completion, go-to-definition) use cached session state. These complete in O(1) to O(log n) with no compilation.
  • DashMap allows multiple concurrent readers, so parallel LSP requests (e.g., hover + diagnostics publication) do not block each other.

Span-based query architecture: All IDE features are implemented by:

  1. Converting the cursor position (line, column) to a byte offset
  2. Finding the Span in the typed AST that covers the cursor offset
  3. Querying the declaration engine for what that span refers to
  4. Returning the relevant information (type, documentation, location)

8.9 ABI Format Reference

Fuel JSON ABI (Full Structure)

{
  "specVersion": "1",
  "encodingVersion": "1",
  "programType": "contract",
  "concreteTypes": [
    {
      "type": "u64",
      "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0",
      "metadataTypeId": 0,
      "components": null,
      "typeParameters": null
    }
  ],
  "metadataTypes": [
    {
      "type": "u64",
      "metadataTypeId": 0,
      "components": null,
      "typeParameters": null
    }
  ],
  "functions": [
    {
      "name": "transfer",
      "inputs": [
        { "name": "amount", "concreteTypeId": "..." },
        { "name": "recipient", "concreteTypeId": "..." }
      ],
      "output": "...",
      "attributes": ["storage(read, write)", "payable"]
    }
  ],
  "loggedTypes": [
    { "logId": "0", "concreteTypeId": "..." }
  ],
  "messagesTypes": [...],
  "configurables": [
    {
      "name": "OWNER",
      "concreteTypeId": "...",
      "offset": 2048
    }
  ]
}

Function Selector Computation

selector = SHA-256( canonical_signature )[0..4]

Where canonical_signature follows the pattern:

function_name(param1_type,param2_type,...)

Example:

transfer(u64,b256) → SHA-256("transfer(u64,b256)")[0..4]

9. Integration Points

9.1 Fuel Node Integration

forc communicates with fuel-core nodes via the GraphQL API, using the fuel-core-client (v0.48.0) crate:

Operation How
forc deploy Submits a Create transaction containing bytecode + storage slots
forc run Submits a Script transaction; prints output
forc test (E2E) Launches ephemeral in-process node; submits transactions; asserts results
forc debug Streams debug events via DAP over the node's debug interface

Default node URL: http://127.0.0.1:4000/graphql

Override in any command:

forc deploy --node-url http://beta-5.fuel.network/graphql
forc run --node-url http://testnet.fuel.network/graphql
forc test --node-url http://127.0.0.1:4000/graphql

9.2 Fuel Rust SDK Integration (fuels 0.77)

The fuels crate is the primary SDK for writing Rust integration tests against compiled Sway contracts. The workflow:

  1. abigen! macro reads the ABI JSON and generates type-safe Rust bindings
  2. Contract::load_from() loads the compiled .bin bytecode
  3. .deploy() submits a Create transaction to the node
  4. Generated methods call contract functions via ABI-encoded Script transactions
  5. Return values are ABI-decoded back to Rust types
use fuels::prelude::*;

abigen!(Contract(
    name = "MyContract",
    abi = "out/debug/my_contract-abi.json"
));

#[tokio::test]
async fn integration_test() {
    // Launch an in-process fuel-core node with a funded wallet
    let config = WalletsConfig::new(Some(1), Some(1), Some(Amount::from(1_000_000)));
    let wallets = launch_custom_provider_and_get_wallets(config, None, None)
        .await
        .unwrap();
    let wallet = wallets.into_iter().next().unwrap();

    // Deploy
    let id = Contract::load_from(
        "out/debug/my_contract.bin",
        LoadConfiguration::default(),
    )
    .unwrap()
    .deploy(&wallet, TxPolicies::default())
    .await
    .unwrap();

    // Call
    let contract_instance = MyContract::new(id, wallet);
    let result = contract_instance
        .methods()
        .my_function(42u64)
        .call()
        .await
        .unwrap();
    assert_eq!(result.value, 42u64);
}

9.3 mdBook Integration

The Sway book is built with mdbook plus the custom mdbook-forc-documenter preprocessor (in scripts/mdbook-forc-documenter/). This preprocessor generates forc subcommand documentation pages directly from the clap argument definitions, keeping the book in sync with the tool automatically.

# Install dependencies
cargo install mdbook
cargo install --path scripts/mdbook-forc-documenter

# Build the book
mdbook build docs/book
# Output: docs/book/book/

# Serve locally with hot-reload
mdbook serve docs/book --open

The book is also published to the Fuel documentation site on each release.

9.4 Editor Integration

Visual Studio Code

Install the official Sway extension (by FuelLabs) from the VS Code marketplace. Configuration in settings.json:

{
  "sway.server.path": "forc",      // Uses forc lsp subcommand
  "sway.trace.server": "off",      // "off" | "messages" | "verbose"
  "editor.formatOnSave": true,
  "[sway]": {
    "editor.defaultFormatter": "FuelLabs.sway-vscode-plugin"
  }
}

Neovim (nvim-lspconfig)

require('lspconfig').sway_lsp.setup({
  cmd = { 'forc', 'lsp' },
  filetypes = { 'sway' },
  root_dir = require('lspconfig').util.root_pattern('Forc.toml'),
  settings = {},
  on_attach = function(client, bufnr)
    -- Standard LSP keybindings
    local opts = { buffer = bufnr }
    vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
    vim.keymap.set('n', 'K',  vim.lsp.buf.hover, opts)
    vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
  end,
})

Emacs (eglot or lsp-mode)

;; eglot
(add-to-list 'eglot-server-programs
             '(sway-mode . ("forc" "lsp")))

;; lsp-mode
(lsp-register-client
  (make-lsp-client
    :new-connection (lsp-stdio-connection '("forc" "lsp"))
    :major-modes '(sway-mode)
    :server-id 'sway-lsp))

9.5 DAP Debugging Integration

forc-debug --serve implements the Debug Adapter Protocol over stdin/stdout. The IDE launches forc debug --serve as a child process and communicates via DAP JSON-RPC.

VS Code launch.json example:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "fuel",
      "request": "launch",
      "name": "Debug Sway Script",
      "program": "${workspaceFolder}/out/debug/my_script.bin",
      "nodeUrl": "http://127.0.0.1:4000/graphql",
      "stopAtEntry": true
    }
  ]
}

Neovim (nvim-dap):

local dap = require('dap')
dap.adapters.fuel = {
  type = 'executable',
  command = 'forc',
  args = { 'debug', '--serve' },
}
dap.configurations.sway = {
  {
    type = 'fuel',
    request = 'launch',
    name = 'Debug contract',
    program = '${workspaceFolder}/out/debug/my_contract.bin',
    nodeUrl = 'http://127.0.0.1:4000/graphql',
  },
}

9.6 IPFS Dependency Integration

# Forc.toml
[dependencies]
my_library = { ipfs = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG" }
# Override IPFS gateway
forc build --ipfs-node https://ipfs.infura.io

# Use Cloudflare IPFS gateway
forc build --ipfs-node https://cloudflare-ipfs.com

IPFS packages are cached in ~/.forc/cache/ipfs/<cid>/ after first fetch. Content is verified by CID (content-addressed, so integrity is implicit).

9.7 Downstream Tooling Compatibility

Tool Input Description
fuel-core .bin bytecode, ABI JSON Executes contracts and scripts
fuels-rs ABI JSON abigen! generates Rust bindings
fuels-ts ABI JSON Generates TypeScript/JavaScript bindings
fuel-explorer ABI JSON, debug info Block explorer contract verification
Sway Playground Source code Web-based Sway IDE (online)

9.8 Troubleshooting Reference

Warning

The following ICE (Internal Compiler Error) patterns correspond to active bugs in version 0.71.0 (commit e12e611). Track the linked issues for fix status.

Symptom Likely Cause Issue Workaround
Panic / ICE during type checking with type aliases Type alias + const generic array #7604 Avoid const generics on type-aliased types
ICE on self[i] access Const generic indexing edge case #7602 Use explicit index variable with known type
ICE "invalid type unification" message Array type unification scope escape #7603 Simplify array type expressions
forc build hangs indefinitely Infinite loop in type inference #7551 Kill process; file issue with minimal reproducer
CEI warning appears or disappears non-deterministically Nondeterministic CEI analysis #7606 Treat any CEI occurrence as real; apply manual review
Confusing "out of bounds" error on const generic array Incorrect error reporting path #7605 Check array size bounds carefully; compare type signatures
StorageVec behaves incorrectly with nested types Nested type storage layout bug #6040 Avoid StorageVec<StorageMap<...>> and similar patterns
Generic StorageKey<T> fails to compile in complex patterns Generic storage key resolution #7559 Simplify storage generic parameters
Terminal shows garbled output in CI ANSI escape log poisoning #7589 Strip ANSI codes from output; see §7.1
forc build fetches dependencies despite --offline CRL validation dependency #7576 Use --locked --offline; verify Forc.lock is committed

Note

For issues not in the table above, search https://github.com/FuelLabs/sway/issues before filing a new report. Always include forc --version, RUST_BACKTRACE=full output, and a minimal self-contained reproducer.