Native Backend

Choose between the Rust and Cranelift backends when compiling to native.

When compiling Tish to a native binary (tish build --target native), you can select the native backend with --native-backend.

Backends

BackendFlagNative importsWhat it actually produces
rust--native-backend rust (default)✅ SupportedRust source (via tish_compile) linked against tishlang_runtime — cargo builds the final binary
cranelift--native-backend cranelift❌ Not supportedSerialized bytecode embedded in the binary; executable runs tishlang_vm at startup (not CLIF lowering of opcodes)
llvm--native-backend llvm❌ Not supportedSame embedded-bytecode + tishlang_vm pattern as cranelift, linked via clang instead of the Cranelift object builder

When to use each

Rust backend (default)

The Rust backend transpiles your Tish program to Rust source calling tishlang_runtime — dynamic operations on Value — then invokes cargo build --release. This gives:

  • Full native-module support (import { Egui } from 'tish:egui', import { x } from 'cargo:my_crate' with tish.rustDependencies, @scope/pkg)
  • Access to the full Rust ecosystem
  • Destructuring in function parameters
tish build main.tish -o app
# or explicitly:
tish build main.tish -o app --native-backend rust

Primitive lowering (in progress): Where types are annotated or can be inferred, the Rust backend emits native Rust primitives (f64, Vec<f64>, direct arithmetic) instead of Value. See Type Annotations for the current status.

Native typing flags (opt-in)

The deeper typed-native optimizations are dark-shipped behind environment variables — they are off by default, so the default build stays byte-identical, and you opt in per build. They apply only to --native-backend rust.

FlagWhat it does
TISH_PARAM_NATIVE=1Annotated scalar params (a: number/boolean/string) get a native shadow (f64/bool/String) so the body lowers without boxing.
TISH_PARAM_INFER=1Unannotated params used purely numerically are inferred number (conservative, sound).
TISH_NATIVE_FN=1Numeric-only top-level functions are emitted as native fn(f64, …) -> f64; direct calls bypass the boxed call ABI.
TISH_STRUCT_INFER=1Block-local let o = {…} / let xs = […] are inferred to a native struct / T[] when every later use is safe.
TISH_NATIVE_HOF=1reduce/map/filter/some/every over a native number[] lower to a direct Rust iterator chain.
TISH_AGGREGATE_INFER=1Interprocedural monomorphic struct inference: when a whole-program candidacy predicate holds (a monomorphic all-f64 object shape that never hits ===/escape/reshape), an array-of-objects is unboxed into a native Vec<Struct> threaded by reference and its factory/operator functions are de-virtualized into typed Rust free functions — removing the boxed Value + RefCell + property-map hot path. All-or-nothing per group: any unlowerable use disables it and falls back to the byte-identical boxed path.
# Example: build with the full typed-native flag set
TISH_PARAM_NATIVE=1 TISH_PARAM_INFER=1 TISH_NATIVE_FN=1 \
TISH_STRUCT_INFER=1 TISH_NATIVE_HOF=1 TISH_AGGREGATE_INFER=1 \
  tish build main.tish -o app --native-backend rust

These flags are correctness-preserving (each bails to the boxed path rather than miscompile), but they are still being hardened — treat them as opt-in performance experiments.

Cranelift backend

The Cranelift backend produces a standalone binary without a cargo invocation — build is fast. However, the binary runs the same tishlang_vm on embedded bytecode; it is not AOT machine-code compilation of Tish opcodes. Throughput is VM-class, similar to tish run --backend vm.

Use when your program:

  • Has no external native imports (cargo:…, packaged tish:* modules such as tish:egui, or @scope/pkg). Built-in tish:fs, tish:http, and tish:process (when enabled) are still allowed on this path.
  • Benefits from a fast build (no cargo + rustc overhead)
tish build main.tish -o app --native-backend cranelift

If your program uses external native imports (including cargo:… crates), the Cranelift backend will error with a message like:

Cranelift backend does not support external native imports (tish:…, cargo:…, @scope/pkg). Built-in tish:fs, tish:http, tish:process are supported. Use --native-backend rust for external modules.

Known limitations (Cranelift / LLVM)

Because the binary runs tishlang_vm, any construct the VM supports is supported; constructs not yet implemented in the VM (e.g. certain destructuring patterns) are equally unsupported here. Destructuring parameters are not supported in bytecode — use the Rust backend or destructure inside the function body.

Target and feature flags

--native-backend applies only when --target native (the default). Other targets (js, wasm, wasi, bytecode) ignore it.

For WebAssembly targets, see WASM Targets.

Feature flags (--feature http, etc.) apply to the Rust backend when compiling to native; the Cranelift/LLVM paths support only pure Tish.

Improve this documentation