fix: propagate contextual compile-time execution

This commit is contained in:
2026-11-01 18:31:50 +01:00
parent 1f457d6b41
commit 22b40d3718
6 changed files with 836 additions and 46 deletions
+4 -2
View File
@@ -158,7 +158,7 @@ untagged union constants snapshot every byte of their native-layout storage, inc
`$(expression)` explicitly evaluates a constant expression, including an ordinary procedure call, even in a package without templates. use a typed expression when its shape cannot be inferred independently, such as `$(Point { x = 40 })`; integer literals retain contextual typing. the resulting value works in runtime expressions, bindings, expression statements and array lengths, while the erased expression still receives ordinary checking. each interpreter evaluation is isolated and limited to 100,000 IR instructions/terminators and 128 active frames; failures retain their originating source locations. runtime parameters and mutable local/global dependencies cannot supply compile-time inputs. nonnull data pointers, unsupported slice types and address-bearing untagged union layouts cannot escape temporary evaluation as generated constants; active payloads or aggregate fields containing unsupported values are diagnosed rather than retaining interpreter handles. executed foreign calls remain interpreter traps. general type-valued execution, broader storage-bearing materialization and broader `meta` operations remain open.
`if $(condition) { ... } else { ... }` evaluates a boolean guard before expanding or checking either body, including calls to ordinary constant-input procedures. concrete generic specializations also select branches whose guards use constants, immutable constant bindings, type comparisons or substituted compile-time parameters. only the selected body is specialized and checked; both bodies are still parsed and name-resolved. selected bodies retain their scope, cleanup and return behavior, and erased guards retain ordinary type checking and source diagnostics. ordinary calls in an implicit guard stay runtime; use `$()` to request their evaluation. optional captures remain runtime, and ordinary nongeneric `if (true)` still checks both bodies.
`if $(condition) { ... } else { ... }` evaluates a boolean guard before expanding or checking either body, including calls to ordinary constant-input procedures. concrete generic specializations also select branches whose guards use constants, immutable constant bindings, type comparisons or substituted compile-time parameters. fully bound type-specialized helper predicates also select guards implicitly when their expanded bodies are constant and effect-free; runtime inputs, mutation, mutable globals, foreign calls and explicit traps prevent implicit probing. only the selected body is specialized and checked; both bodies remain parsed and name-resolved. selected bodies retain scope, cleanup and return behavior, and erased guards retain ordinary type checking and source diagnostics. other ordinary calls stay runtime unless `$()` requests evaluation. optional captures remain runtime, and ordinary nongeneric `if (true)` still checks both bodies.
generic guards also specialize side-effect-free `minval!`, `maxval!`, `sizeof!` and `alignof!` expressions with constant type operands.
@@ -224,7 +224,9 @@ the existing `std/arraylist` and `std/mem` work without replacement bindings or
existing `std/hashmap.HashMap`, `AutoHashMap` and `StringHashMap` execute without replacement library code. checks cover collision chains, zero-hash normalization, growth/rehashing, duplicate-key errors, absent lookups, aggregate copy isolation, allocation failure preserving the map and deferred cleanup. native checks use the real C allocator for integer boundaries, booleans, sparse/aliased enums, nested distinct/array/record keys (ignoring record padding), content-based strings and custom callbacks; interpreter checks use separate fixed-capacity typed buffers. a declared result supplies the initializer parameters: `map hashmap.AutoHashMap(i16, i16) := hashmap.init(allocator)`; `StringHashMap` and custom `HashMap` results also infer their exact private/custom callbacks. explicit calls such as `hashmap.init(i16, i16, null, null, allocator)` remain supported.
existing `std/io.print(format, writer, args)` parses constant formats and expands tuple fields before runtime. escaped braces, default bool/integer/string/enum formatting, nested scalar distinct values, `{s}`, `{d}`, `{b}`, `{o}`, `{x}`, `{X}` and `{c}` work through interpreter/native execution; malformed formats, wrong argument counts and unsupported types diagnose. native `f64` default/decimal/scientific (`{e}`) formatting uses the real imported variadic `snprintf`; that path retains its interpreter foreign-call trap. checks compare exact bytes with short-writing callbacks and cover write failures, zero progress and invalid callback counts. the private parser uses owned token initialization and a retained metadata local to select constant-input execution; field-name lookup uses inline metadata iteration, and helper predicates explicitly request compile-time branch selection.
existing `std/io.print(format, writer, args)` parses constant formats and expands tuple fields before runtime without adapting its implementation to the compiler. escaped braces, default bool/integer/string/enum formatting, nested scalar distinct values, `{s}`, `{d}`, `{b}`, `{o}`, `{x}`, `{X}` and `{c}` work through interpreter/native execution; malformed formats, wrong argument counts and unsupported types diagnose. native `f64` default/decimal/scientific (`{e}`) formatting uses the real imported variadic `snprintf`; that path retains its interpreter foreign-call trap. checks compare exact bytes with short-writing callbacks and cover write failures, zero progress and invalid callback counts.
constant-required contexts such as `inline for` iterables propagate evaluation demand through calls before eager body expansion. demanded execution follows reached control flow, including guarded `compile_error!`, and uses checked IR for borrowed local mutation such as `mem.set` and helper slice writes. snapshots preserve partially initialized caller storage and commit owned updated values; addresses cannot escape evaluation. runtime inline bodies suspend demand, and demanded/runtime instances have distinct cache identities. inferred literal-origin numeric locals retain contextual compile-time values until a rigid numeric source establishes their type; explicit annotations, casts and call results remain rigid.
single pointers to fixed arrays implicitly borrow matching slice storage without copying, respecting pointer/element mutability, exact nominal elements and sentinel weakening. optional coercions preserve absence and borrow only present payloads.