@yabgu_gm/tensionscript 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -620,7 +620,9 @@ declare module "types:tensionscript/src/diagnosticMessages.generated" {
620
620
  _abi_align_0_the_alignment_must_be_a_power_of_two = 6407,
621
621
  _abi_align_0_is_less_than_the_field_type_s_natural_alignment_1_asking_for_less_is_a_lie_so_it_is_refused_rather_than_silently_ignored = 6408,
622
622
  _abi_align_0_is_too_large_the_maximum_is_1 = 6409,
623
- Alignment_is_a_property_of_the_field_not_its_type_Place_abi_align_N_on_the_field_declaration = 6410
623
+ Alignment_is_a_property_of_the_field_not_its_type_Place_abi_align_N_on_the_field_declaration = 6410,
624
+ A_view_parameter_unmanaged_0_over_an_inline_type_cannot_appear_in_a_host_visible_signature_an_external_or_exported_parameter_is_supplied_by_the_host_and_a_view_is_an_address_this_compiler_did_not_materialise = 6411,
625
+ Call_to_0_emits_1_operands_but_its_signature_declares_2 = 6412
624
626
  }
625
627
  /** Translates a diagnostic code to its respective string. */
626
628
  export function diagnosticCodeToString(code: DiagnosticCode): string;
@@ -2706,6 +2708,21 @@ declare module "types:tensionscript/src/types" {
2706
2708
  * all of them.
2707
2709
  */
2708
2710
  static wasmParamCountOf(type: Type): number;
2711
+ /**
2712
+ * Appends the **leaf** types of an `@inline struct`, in declaration order,
2713
+ * depth first.
2714
+ *
2715
+ * A leaf is a field that occupies one WASM local: a scalar or a reference. A
2716
+ * field whose type is itself an `@inline struct` is not a leaf — it is several
2717
+ * locals behind a map — so the walk recurses into it. This is the type-level
2718
+ * twin of the `fieldLocals` tree the compiler builds
2719
+ * (`Compiler#fillSroaFieldLocals`), and the two must agree in **order** as
2720
+ * well as count: the callee binds WASM parameter *k* to the *k*th leaf, and
2721
+ * the caller pushes operands in the same walk.
2722
+ */
2723
+ static leafTypesOf(type: Type, out: Type[]): void;
2724
+ /** The number of leaf locals an `@inline struct` occupies. */
2725
+ static leafCountOf(type: Type): number;
2709
2726
  /**
2710
2727
  * How many WASM operands **this signature** spends on source parameter
2711
2728
  * `sourceIndex`.
@@ -2722,6 +2739,18 @@ declare module "types:tensionscript/src/types" {
2722
2739
  * the same source parameter.
2723
2740
  */
2724
2741
  wasmParamSlotCountOf(sourceIndex: number): number;
2742
+ /**
2743
+ * Whether source parameter `sourceIndex` is a **view**: `@unmanaged` at the
2744
+ * declaration over a type that is an `@inline struct`.
2745
+ *
2746
+ * The type still says *value* — every use of `MyStruct` shares one `Type`, and
2747
+ * that is what makes a member lookup work on the parameter — while the model
2748
+ * says this use is an address. One `i32` slot, no field locals, a load at the
2749
+ * field's offset: the same crossing an `@unmanaged struct` parameter already
2750
+ * takes, with the model recorded at the declaration instead of on a pointer
2751
+ * type.
2752
+ */
2753
+ isViewParam(sourceIndex: number): boolean;
2725
2754
  /**
2726
2755
  * Whether source parameter `sourceIndex` **crosses by value** — one `i32`
2727
2756
  * address instead of one WASM operand per field.
@@ -2735,8 +2764,12 @@ declare module "types:tensionscript/src/types" {
2735
2764
  * address, and the override asks for a copy of what is there — the same
2736
2765
  * copy, read from memory instead of from SROA locals.
2737
2766
  *
2738
- * The reverse is not a thing: `@unmanaged`/`@managed` over an `@inline`
2739
- * declaration is refused (`TS6395`), because a value has no address to lend.
2767
+ * The reverse is partly a thing now. `@unmanaged` over an `@inline`
2768
+ * declaration is legal where the use supplies an address — a parameter (a
2769
+ * view parameter, `isViewParam`) or `changetype`'s type argument — and a view
2770
+ * parameter crosses as a pointer, so it is asked before this predicate. Every
2771
+ * other cell still refuses (`TS6395`), and `@managed` over `@inline` refuses
2772
+ * at every position: a value has no GC header and no address to lend.
2740
2773
  */
2741
2774
  crossesByValueParam(sourceIndex: number): boolean;
2742
2775
  /**
@@ -2759,9 +2792,17 @@ declare module "types:tensionscript/src/types" {
2759
2792
  get byValPointerParams(): boolean;
2760
2793
  /** Whether `type` is an `@inline struct`. */
2761
2794
  static isInlineStructRef(type: Type): boolean;
2762
- /** The number of fields an `@inline struct` has (0 for a record with none).
2763
- * Distinct from `wasmParamCountOf`, which cannot express "one field" and
2764
- * "one operand" differently. */
2795
+ /**
2796
+ * How many **WASM slots** an `@inline struct` spends — its leaf count.
2797
+ *
2798
+ * Leaf count, not direct-field count: a nested inline field is several locals,
2799
+ * so `Outer1 { a: u32; inner: Inner{x,y} }` is 3, not 2. A record with no
2800
+ * members is 0.
2801
+ *
2802
+ * Callers that made sense of "direct fields" are listed in the Phase C audit
2803
+ * (`docs`); the one place that genuinely needs the direct count is layout, and
2804
+ * layout reads `members` itself rather than asking this.
2805
+ */
2765
2806
  static fieldCountOf(type: Type): number;
2766
2807
  /**
2767
2808
  * Whether a call to this signature passes a hidden destination pointer.
@@ -3095,6 +3136,60 @@ declare module "types:tensionscript/src/resolver" {
3095
3136
  currentElementExpression: Expression | null;
3096
3137
  /** Whether a new override has been discovered. */
3097
3138
  discoveredOverride: boolean;
3139
+ /**
3140
+ * Whether a use-site `@unmanaged` over an `@inline` declaration is being
3141
+ * resolved as the **type argument of `changetype`**.
3142
+ *
3143
+ * That position is the one where the operand can supply the address the value
3144
+ * itself does not have, so the refusal's premise does not hold there (see
3145
+ * `checkMemoryModelOverride`). Every other position — a parameter, a local, a
3146
+ * field, a return type — still refuses with `TS6395`, which is what keeps the
3147
+ * function-parameter form (`Phase 2`) out of this change.
3148
+ *
3149
+ * The compiler sets this around the one `resolveTypeArguments` call it makes
3150
+ * for a `changetype` builtin (`Compiler#compileCallExpressionBuiltin`), and
3151
+ * resets it immediately: the flag is a scope, not a mode.
3152
+ */
3153
+ allowInlineView: boolean;
3154
+ /**
3155
+ * Whether a use-site `@unmanaged` over an `@inline` declaration is being
3156
+ * resolved in a **parameter position** — the cell where the caller supplies
3157
+ * the address, so `f(a: @unmanaged T)` with an inline `T` is a view parameter.
3158
+ *
3159
+ * Distinct from {@link allowInlineView} (Phase 1, `changetype`'s type
3160
+ * argument, where the operand supplies the address at the point of use).
3161
+ *
3162
+ * **Saved and restored, never blindly cleared.** Resolving one parameter's
3163
+ * type can resolve another function (a default value's call, a nested
3164
+ * signature), and a nested window that reset the flag to `false` on the way
3165
+ * out closed the outer window — measured: the owner's pattern reported TS6395
3166
+ * with both flags reading `false` while inside `resolveFunction`'s own loop.
3167
+ */
3168
+ allowInlineViewParam: boolean;
3169
+ /**
3170
+ * Call expressions that are **views of caller bytes**: an inline-typed
3171
+ * `changetype<@unmanaged T>(ptr)`.
3172
+ *
3173
+ * Marked here, at resolution, because the compiler asks this question while
3174
+ * compiling the *field access* — which happens before the `changetype` it
3175
+ * wraps is ever compiled. Recording it at codegen time (the first attempt)
3176
+ * produced a field read that never saw the mark and compiled to
3177
+ * `unreachable`.
3178
+ *
3179
+ * Keyed on the AST node rather than on the type, because the type is the
3180
+ * declaration's (`T` is still an `@inline struct`) and the model is the
3181
+ * *use's*: there is one `Type` per class, shared by every use.
3182
+ */
3183
+ private viewCalls;
3184
+ /**
3185
+ * Records `node` as a view call. The resolver marks the ones it resolves;
3186
+ * `Compiler#compileCallExpressionBuiltin` marks the ones it resolves itself,
3187
+ * because a builtin's type arguments are resolved on the *codegen* path and
3188
+ * never pass through `maybeInferCall`.
3189
+ */
3190
+ markViewCall(node: Expression): void;
3191
+ /** Whether `node` is an inline-typed `changetype<@unmanaged T>(...)`. */
3192
+ isViewCall(node: Expression): boolean;
3098
3193
  /** Constructs the resolver for the specified program. */
3099
3194
  constructor(
3100
3195
  /** The program to construct a resolver for. */
@@ -3122,10 +3217,14 @@ declare module "types:tensionscript/src/resolver" {
3122
3217
  * - **`@managed` over an `@unmanaged` declaration** — the collector traces a
3123
3218
  * reference through a header the record does not have. No emitter can
3124
3219
  * invent the header, so a use cannot confer provenance. (`TS6394`.)
3125
- * - **`@unmanaged`/`@managed` over an `@inline` declaration** — a value is
3126
- * stored as one local per field and has **no address** at all, so there is
3127
- * nothing to lend as a pointer and nothing a header could sit in front of.
3128
- * (`TS6395`.)
3220
+ * - **`@managed` over an `@inline` declaration** — a value has neither a
3221
+ * header nor an address, at any position. (`TS6395`.)
3222
+ * - **`@unmanaged` over an `@inline` declaration**, *except* where the use
3223
+ * supplies an address: `changetype`'s type argument (the operand supplies
3224
+ * it) and a parameter (the caller supplies it). Those two windows are
3225
+ * `allowInlineView` and `allowInlineViewParam`, and they are the whole
3226
+ * difference between a view and a claim. Every other position — a return
3227
+ * type, a local, a field — still has nothing to lend. (`TS6395`.)
3129
3228
  *
3130
3229
  * Everything else is left to the emitters: `@unmanaged` over `@managed` is
3131
3230
  * the identity cell (10.0a), `@inline` over a pointer declaration is the
@@ -3763,6 +3862,14 @@ declare module "types:tensionscript/src/program" {
3763
3862
  function fromUnaryPostfixToken(token: Token): OperatorKind;
3764
3863
  }
3765
3864
  /** Represents an AssemblyScript program. */
3865
+ /** How many WASM slots a parameter binding consumed — see
3866
+ * `Program#bindSroaParameterLeaves`. A one-field wrapper because this compiler
3867
+ * reports the count and the caller advances past it; a bare `i32` return would
3868
+ * be the same information with no name at the call site. */
3869
+ export class BindResult {
3870
+ leafCount: number;
3871
+ constructor(leafCount: number);
3872
+ }
3766
3873
  export class Program extends DiagnosticEmitter {
3767
3874
  /** Compiler options. */
3768
3875
  options: Options;
@@ -4479,6 +4586,17 @@ declare module "types:tensionscript/src/program" {
4479
4586
  * therefore cannot alias.
4480
4587
  */
4481
4588
  fieldLocals: Map<string, Local> | null;
4589
+ /**
4590
+ * Whether this local is a **view parameter**: `a: @unmanaged T` where `T` is
4591
+ * an inline type.
4592
+ *
4593
+ * Its `type` is still the inline record, because that is what makes `a.field`
4594
+ * resolve — every use of `T` shares one `Type`. Its *storage* is the one `i32`
4595
+ * WASM parameter holding the caller's address, which is why a field read goes
4596
+ * through `load` at the field's offset rather than through `fieldLocals`
4597
+ * (there are none: a view has no per-field locals to copy into).
4598
+ */
4599
+ isViewParam: boolean;
4482
4600
  /** Constructs a new local variable. */
4483
4601
  constructor(
4484
4602
  /** Simple name. */
@@ -4590,6 +4708,20 @@ declare module "types:tensionscript/src/program" {
4590
4708
  nextInlineId: number;
4591
4709
  /** Counting id of anonymous inner functions. */
4592
4710
  nextAnonymousId: number;
4711
+ /**
4712
+ * Binds an `@inline struct` parameter's **leaves** to the WASM parameters that
4713
+ * carry them, building the `fieldLocals` tree a read path walks.
4714
+ *
4715
+ * `localIndex` is the index of the parameter's first WASM slot; the walk
4716
+ * consumes one slot per leaf in the same depth-first order
4717
+ * `Signature.leafTypesOf` declares and the caller pushes operands in. Returns
4718
+ * how many slots were consumed, so the caller advances past them.
4719
+ *
4720
+ * A nested field gets a placeholder `Local` (index `-1`) carrying its own map,
4721
+ * exactly as `fillSroaFieldLocals` builds one for a local — the tree shape is
4722
+ * one structure regardless of where the leaves' storage came from.
4723
+ */
4724
+ bindSroaParameterLeaves(type: Type, path: string, into: Map<string, Local>, localIndex: number, flow: Flow): BindResult;
4593
4725
  /** Constructs a new concrete function. */
4594
4726
  constructor(
4595
4727
  /** Name incl. type parameters, i.e. `foo<i32>`. */
@@ -5284,7 +5416,7 @@ declare module "types:tensionscript/src/compiler" {
5284
5416
  import { Range, DiagnosticEmitter } from "types:tensionscript/src/diagnostics";
5285
5417
  import { Module, MemorySegment, ExpressionRef, TypeRef, GlobalRef } from "types:tensionscript/src/module";
5286
5418
  import { Feature, Target, Runtime } from "types:tensionscript/src/common";
5287
- import { Program, Class, Element, DeclaredElement, Enum, Function, Global, Property, VariableLikeElement, File } from "types:tensionscript/src/program";
5419
+ import { Program, Class, Element, DeclaredElement, Enum, Function, Global, Local, Property, VariableLikeElement, File } from "types:tensionscript/src/program";
5288
5420
  import { Flow, ConditionKind } from "types:tensionscript/src/flow";
5289
5421
  import { Resolver } from "types:tensionscript/src/resolver";
5290
5422
  import { Node, FunctionTypeNode, Statement, Expression } from "types:tensionscript/src/ast";
@@ -5770,6 +5902,18 @@ declare module "types:tensionscript/src/compiler" {
5770
5902
  private needToStack;
5771
5903
  /** Marks managed call operands for the shadow stack. */
5772
5904
  private operandsTostack;
5905
+ /**
5906
+ * Checks that the operands about to be passed match the WASM arity the callee
5907
+ * declares, and reports a clean diagnostic when they do not.
5908
+ *
5909
+ * The invariant is maintained by the default-argument filling in
5910
+ * `makeCallDirect`; this guard exists because when that filling misses — as it
5911
+ * did for an sret callee with an omitted optional argument — the mismatch
5912
+ * reached the WASM validator as `call* param number must match`, which names a
5913
+ * binaryen rule and never mentions the call that broke it. A wrong arity is a
5914
+ * compiler bug, so it should say so at the call site.
5915
+ */
5916
+ private checkCallArity;
5773
5917
  /** Creates a direct call to the specified function. */
5774
5918
  makeCallDirect(instance: Function, operands: ExpressionRef[] | null, reportNode: Node, immediatelyDropped?: boolean): ExpressionRef;
5775
5919
  /** Compiles an indirect call to a first-class function. */
@@ -5947,11 +6091,27 @@ declare module "types:tensionscript/src/compiler" {
5947
6091
  /**
5948
6092
  * The SROA local an expression names, or `null`.
5949
6093
  *
5950
- * Only a bare identifier can be one: `p.x.y` where `x` is itself an inline
5951
- * struct cannot happen this phase (a nested field is refused at declaration),
5952
- * so the receiver of a field access is either an SROA local or an ordinary
5953
- * expression that has an address.
6094
+ * The receiver is either an SROA local (base identifier) or a chain of field
6095
+ * accesses into one (`o.inner` in `o.inner.x`). The chain is walked from the
6096
+ * base outward, one hop per `fieldLocals` lookup: a nested inline field is
6097
+ * entered through the placeholder `Local` its creation installed
6098
+ * (`fillSroaFieldLocals`), so the walk and the tree are one structure rather
6099
+ * than two that could disagree.
6100
+ *
6101
+ * Returns the `Local` the final hop resolved to, or `null` when any step does
6102
+ * not hold — a non-local base, a field with no entry, or a leaf reached before
6103
+ * the chain ends. `null` is not an error here: the caller falls through to the
6104
+ * ordinary address paths, which refuse a value with no address.
5954
6105
  */
6106
+ /**
6107
+ * Pushes one operand per **leaf** of a `fieldLocals` tree, depth first.
6108
+ *
6109
+ * Shared by the call site (`expandSroaArgument`) so the operand order is the
6110
+ * one `Signature.leafTypesOf` declares and the binder indexes into — three
6111
+ * walks, one order. A nested field's entry is a placeholder (index `-1`)
6112
+ * carrying its own map, so the walk descends through it.
6113
+ */
6114
+ private pushSroaLeafOperands;
5955
6115
  private resolveSroaReceiver;
5956
6116
  /** Size of the static call-temp region, in bytes. 4 KB is 256 slots at the
5957
6117
  * 16-byte fixture record size. Overflow aborts (see `makeSretCallBlock`);
@@ -6041,6 +6201,15 @@ declare module "types:tensionscript/src/compiler" {
6041
6201
  /** `base + mark + extra`, freshly built. Callers must not share the node:
6042
6202
  * Binaryen's passes assume a single parent per expression. */
6043
6203
  private makeSretAddressPlus;
6204
+ /**
6205
+ * Stores a by-value argument's leaves into the static call-temp region.
6206
+ *
6207
+ * The same tree walk as `copyInto` (`emitSroaStores`) and `copySroaValue`:
6208
+ * leaves become stores at `tempAddress + field offset`, a nested field is
6209
+ * descended into. Keeping one recursion is what makes a nested value cross a
6210
+ * host boundary at the layout the C side expects.
6211
+ */
6212
+ emitTempArgumentLeaves(type: Type, fieldLocals: Map<string, Local>, base: number, markLocal: Local, baseOffset: number, stmts: ExpressionRef[]): void;
6044
6213
  /**
6045
6214
  * Materialises one `@inline struct` argument of an `@external` call on the
6046
6215
  * static call-temp stack and returns the address to pass.
@@ -6111,6 +6280,93 @@ declare module "types:tensionscript/src/compiler" {
6111
6280
  * Returns true when the declaration was handled here (the caller must not fall
6112
6281
  * through to the ordinary local path).
6113
6282
  */
6283
+ /**
6284
+ * Fills `into` with one entry per field of an `@inline struct` value.
6285
+ *
6286
+ * A **leaf** field (scalar, or a reference) gets one WASM local, named
6287
+ * `<path>$<field>` — a synthetic name keeps it out of user scope, so nothing
6288
+ * can look one up by accident.
6289
+ *
6290
+ * A field whose type is itself an `@inline struct` is **not a leaf**: it is
6291
+ * recursed into, and its entry is a placeholder `Local` (index `-1`) carrying
6292
+ * its own map. That makes `fieldLocals` a **tree** whose shape is the value's
6293
+ * nesting, which is what lets a read path walk `o.inner.x` a hop at a time
6294
+ * without a second representation. The placeholder is never `local.get`-ed:
6295
+ * the bare-read guard refuses a value read and the receiver walk descends to
6296
+ * a leaf before emitting anything.
6297
+ *
6298
+ * Returns `false` when a field was refused, having reported why. The refusal
6299
+ * is per **leaf**, so a nested value inherits exactly the rules the flat one
6300
+ * has — a `T[N]` field or a GC-reference field is refused at any depth.
6301
+ */
6302
+ private fillSroaFieldLocals;
6303
+ /**
6304
+ * Copies one SROA value's leaves into another's, following the tree.
6305
+ *
6306
+ * `from` and `to` are the two `fieldLocals` maps — the same shape
6307
+ * `fillSroaFieldLocals` builds, so a nested field is a placeholder on both
6308
+ * sides and the recursion descends through it rather than trying to move a
6309
+ * value that has no single representation.
6310
+ *
6311
+ * This is what makes `let q = p` and `q = p` **copies** rather than aliases:
6312
+ * one `local.set` per leaf, so a later write to `q` cannot be seen through
6313
+ * `p`. Both sides come from this compiler's own maps, so there is no aliasing
6314
+ * question to answer — the leaves are distinct locals by construction.
6315
+ */
6316
+ private copySroaValue;
6317
+ /**
6318
+ * Stores a `fieldLocals` tree's leaves into the hidden destination slot at
6319
+ * `destIndex`, one store per leaf.
6320
+ *
6321
+ * The third destination shape for the same recursion: `emitSroaStores` writes
6322
+ * to a compiled `usize`, `emitTempArgumentLeaves` to a call-temp address, and
6323
+ * this one to a **parameter** — the sret slot a `return p` fills. The address
6324
+ * is a fresh `local.get` per store, because Binaryen's passes assume one
6325
+ * parent per node.
6326
+ */
6327
+ emitSroaStoresToLocal(type: Type, fieldLocals: Map<string, Local>, destIndex: number, baseOffset: number, stmts: ExpressionRef[]): void;
6328
+ /**
6329
+ * Zeroes every **leaf** of an `@inline struct` in the destination slot.
6330
+ *
6331
+ * `return new P()` has no local to copy from — the value is all zeroes — but
6332
+ * the slot is stack space that a previous sret call may have filled, so the
6333
+ * bytes still have to be written. Walking the type rather than the direct
6334
+ * fields is what zeroes a nested field's leaves: measured before this,
6335
+ * `return new Outer1()` with `Inner{x,y}` stored only offset 0 and left
6336
+ * offsets 4 and 8 holding whatever was there.
6337
+ */
6338
+ emitSroaZerosToLocal(type: Type, destIndex: number, baseOffset: number, stmts: ExpressionRef[]): void;
6339
+ /**
6340
+ * Loads an `@inline struct`'s leaves out of the sret slot into a target's
6341
+ * field locals, one load per leaf.
6342
+ *
6343
+ * The mirror of {@link emitSroaStoresToLocal}: `let q = make()` reads the slot
6344
+ * back into the leaf locals a read path walks. A fresh slot address per load,
6345
+ * for the same one-parent-per-node reason.
6346
+ */
6347
+ emitSretLoadsInto(type: Type, fieldLocals: Map<string, Local>, base: number, markLocal: Local, baseOffset: number, stmts: ExpressionRef[]): void;
6348
+ /**
6349
+ * The `fieldLocals` tree behind an SROA-tracked expression, or `null`.
6350
+ *
6351
+ * The public face of {@link resolveSroaReceiver} for code outside this class —
6352
+ * today only the `copyInto` builtin, which needs the *tree* (to store its
6353
+ * leaves) rather than a single receiver.
6354
+ */
6355
+ sroaTreeOf(expression: Expression): Map<string, Local> | null;
6356
+ /**
6357
+ * Stores an inline value's leaves at `dest + offset`.
6358
+ *
6359
+ * The third leaf consumer, beside `copySroaValue` (local-to-local) and the
6360
+ * read path (local-to-stack): same tree, same recursion, an expression
6361
+ * reference instead of a destination map. The offsets come from the **type**
6362
+ * (`property.memoryOffset`, the layout the C side sees), so what lands in
6363
+ * memory is the wire layout, not a packing of the locals.
6364
+ *
6365
+ * Leaves whose local is missing are skipped rather than stored as `-1`: a
6366
+ * field refused at declaration was never part of the value (`isSroaFieldType`
6367
+ * has already reported why), and the caller has been told.
6368
+ */
6369
+ emitSroaStores(type: Type, fieldLocals: Map<string, Local>, dest: ExpressionRef, baseOffset: number, stmts: ExpressionRef[]): void;
6114
6370
  private compileSroaLocal;
6115
6371
  /**
6116
6372
  * The instance fields of an `@inline struct`, in declaration order, or `null`
@@ -6296,6 +6552,7 @@ declare module "types:tensionscript/src/builtins" {
6296
6552
  const select = "~lib/builtins/select";
6297
6553
  const unreachable = "~lib/builtins/unreachable";
6298
6554
  const changetype = "~lib/builtins/changetype";
6555
+ const copyInto = "~lib/builtins/copyInto";
6299
6556
  const assert = "~lib/builtins/assert";
6300
6557
  const call_indirect = "~lib/builtins/call_indirect";
6301
6558
  const unchecked = "~lib/builtins/unchecked";