Compiler Limits
This document enumerates the current hard limits in the Silk compiler and its
tooling. These limits are implementation guardrails (primarily to keep
memory usage bounded when compiling untrusted inputs); they are not intended to
be permanent language constraints unless explicitly called out in the language
spec (docs/language/).
Where a language feature has an implementation cap that affects user code, the cap is also documented in the relevant language document (for example varargs).
Source and Manifest Size Limits#
- Silk source file max size (per file): 64 MiB
- Applies to:
- the
silkCLI (src/driver.zig), - the Zig wrapper API that loads sources from disk (
src/silk.zig), - the C ABI entrypoints that load sources from disk (
src/abi.zig), - the LSP server file loader (
src/lsp_main.zig). - Rationale: avoid unbounded allocations while still allowing large modules.
- Package manifest max size: 1 MiB
- Applies to reading
silk.toml(src/package_manifest.zig).
Front-End (Type Checker) Structural Limits#
The current checker uses fixed-capacity buffers for a number of intermediate tables. Module-/package-scoped tables are heap-backed to avoid stack overflows when compiling large module sets, while some per-function scratch state is still stack-backed.
When these limits are exceeded, the compiler typically reports
E2002 (“unsupported expression in the Supported forms”) because the checker
uses CheckError.UnsupportedExpression as a shared “not supported yet” / “hit
an internal cap” path. This will be refined into dedicated “limit exceeded”
diagnostics as the compiler matures.
Current caps (src/checker.zig):
- Top-level bindings per module: 16384
- Local bindings per function: 1024
- Function-like bindings tracked in a module set (functions, externs, imported callables, etc.): 16384
- Struct declarations tracked in a module set: 16384
- Enum declarations tracked in a module set: 16384
- Interface declarations tracked in a module set: 16384
- Type aliases tracked in a module set: 16384
- Methods tracked in a module set (impl methods, coercions, etc.): 16384
- Fixed array type length cap (
T[N]): 4096
Varargs Pack Capacity#
Varargs are implemented using an internal, fixed-size “pack struct” lowered as a flattened scalar-slot struct value.
- Varargs pack capacity (
N): 128
See varargs for the surface rules and current representation.
Lowering / IR Limits#
Current caps (src/lower_ir.zig):
- Lowering binding environment size (per function): 1024
- This is the maximum number of simultaneously in-scope bindings that the IR lowerer can track.
- Type-alias resolution depth: 256
- This bounds recursive/chain alias resolution during lowering to avoid runaway recursion in pathological cases.
- Varargs pack capacity (
N): 128
Const Evaluator Limits#
The current const-evaluator used for the fn main() -> int constant
program path builds a small environment of constant top-level let bindings
that main may reference.
- Const-eval environment bindings: 4096 (
src/backend_const.zig)
If a module exceeds this, additional candidate bindings are ignored for the
purposes of const-evaluating main in that path.
Bundled Regex Runtime Limits#
The bundled regexp engine is intentionally wrapped with conservative resource
limits so the compiler/runtime does not hand unbounded recursion or pathological
backtracking to the engine when compiling or executing untrusted patterns.
Before runtime execution, Silk also performs conservative structural validation
of foreign (ptr, len) regexp bytecode so malformed ABI-supplied buffers are
rejected as invalid input instead of being handed directly to the engine.
The runtime also tracks which regex bytecode buffers it allocated itself, so
the regex free/drop path ignores borrowed/literal/foreign regexp views
instead of releasing arbitrary pointers.
- Regexp compile stack budget: 128 KiB
- Applies to:
- compile-time regexp literals during type checking (
src/checker.zig), - runtime
std::regex::RegExp.compile(...)viasilk_rt_regexp_compile(src/silk_rt_api.c). - Effect:
- overly deep regexp nesting is rejected as an invalid regexp rather than recursing without a bound in the embedder.
- Regexp execution timeout poll budget: 256 polls
- Applies to runtime
std::regex::exec(...)/search(...)/ iterator-based matching viasilk_rt_regexp_exec(src/silk_rt_api.c). - Boundary guard:
silk_rt_regexp_exec(...)first validates the regex header, declared bytecode extent, reachable control-flow targets, and stack discipline of the supplied bytecode view,- malformed foreign
regexpbuffers are rejected withstd::regex::EXEC_ERR_INVALID_INPUT(-3) before the bundled engine is entered. - Engine behavior:
- the bundled QuickJS regexp engine consults the timeout hook once every 10000 internal execution steps,
- so the current shipped execution budget is approximately 2.56 million
hook-accounted steps before the runtime returns
EXEC_ERR_TIMEOUT. - Effect:
- pathological backtracking is bounded and reported as a timeout instead of running indefinitely.
Source repository · Edit this page · View Markdown