@yabgu_gm/tensionscript 0.11.4 → 0.13.0
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.
- package/README.md +3 -1
- package/dist/asc.generated.d.ts +856 -21
- package/dist/asc.js +40 -1
- package/dist/asc.js.map +2 -2
- package/dist/assemblyscript.generated.d.ts +856 -21
- package/dist/assemblyscript.js +179 -179
- package/dist/assemblyscript.js.map +3 -3
- package/dist/importmap.json +2 -2
- package/dist/web.js +3 -3
- package/package.json +3 -1
- package/std/assembly/dynamicarray.ts +39 -0
|
@@ -338,6 +338,8 @@ declare module "types:tensionscript/src/common" {
|
|
|
338
338
|
const Object = "Object";
|
|
339
339
|
const Array = "Array";
|
|
340
340
|
const StaticArray = "StaticArray";
|
|
341
|
+
/** The descriptor behind `@managed @dynamic [T * n]` (Landing 4d.1). */
|
|
342
|
+
const DynamicArray = "DynamicArray";
|
|
341
343
|
const Set = "Set";
|
|
342
344
|
const Map = "Map";
|
|
343
345
|
const Function = "Function";
|
|
@@ -2332,7 +2334,37 @@ declare module "types:tensionscript/src/types" {
|
|
|
2332
2334
|
/** String iterator. */
|
|
2333
2335
|
StringviewIter = 25,
|
|
2334
2336
|
/** No return type. */
|
|
2335
|
-
Void = 26
|
|
2337
|
+
Void = 26,
|
|
2338
|
+
/**
|
|
2339
|
+
* A pointer to `T` with unknown length, `[T *]`.
|
|
2340
|
+
*
|
|
2341
|
+
* **Appended at the end**, not beside {@link FixedArray}, on purpose. This is
|
|
2342
|
+
* a `const enum` with implicit numbering, so an insert would renumber the
|
|
2343
|
+
* twelve kinds between `FixedArray` and `Void`; the compiler is self-hosted, so
|
|
2344
|
+
* a partial rebuild could then disagree with `dist/` about what
|
|
2345
|
+
* `TypeKind.Extern` means -- silently. The order here carries no meaning.
|
|
2346
|
+
*
|
|
2347
|
+
* One slot holding an address: not a value (no extent to inline), not a
|
|
2348
|
+
* reference (the collector owns nothing). `toRef` answers the pointer type,
|
|
2349
|
+
* which is what lets a `[T *]` parameter, local, global and return bind as one
|
|
2350
|
+
* slot where `T[N]` reaches `Type#toRef`'s `assert(false)`.
|
|
2351
|
+
*/
|
|
2352
|
+
UnmanagedArray = 27,
|
|
2353
|
+
/**
|
|
2354
|
+
* `@unmanaged @dynamic [T * n]` — a header-prefixed array whose length is a
|
|
2355
|
+
* runtime value.
|
|
2356
|
+
*
|
|
2357
|
+
* Appended for the same reason {@link UnmanagedArray} was: an insert would
|
|
2358
|
+
* renumber every kind after it, and the compiler is self-hosted.
|
|
2359
|
+
*
|
|
2360
|
+
* A separate kind rather than a flag on `UnmanagedArray` because the two have
|
|
2361
|
+
* different layouts — one addresses bare elements, the other a
|
|
2362
|
+
* `[u32 length][pad][data]` header — and every element access has to know
|
|
2363
|
+
* which it is looking at. The storage *model* is a field
|
|
2364
|
+
* ({@link dynamicMemoryModel}), not a kind, so `@managed @dynamic` (Landing 4d)
|
|
2365
|
+
* is the same kind under a different owner.
|
|
2366
|
+
*/
|
|
2367
|
+
DynamicArray = 28
|
|
2336
2368
|
}
|
|
2337
2369
|
/** Indicates capabilities of a type. */
|
|
2338
2370
|
export const enum TypeFlags {
|
|
@@ -2383,12 +2415,55 @@ declare module "types:tensionscript/src/types" {
|
|
|
2383
2415
|
/** Element count of a {@link TypeKind.FixedArray}, else `0`. */
|
|
2384
2416
|
fixedLength: number;
|
|
2385
2417
|
/**
|
|
2386
|
-
*
|
|
2418
|
+
* Who owns a {@link TypeKind.FixedArray}'s storage — the second axis of the
|
|
2419
|
+
* kind, alongside the element and the length.
|
|
2420
|
+
*
|
|
2421
|
+
* The memory model was already on the AST (`TypeNode.memoryModel`) and was
|
|
2422
|
+
* simply dropped before Landing 5a.5: `Type.fixedArray` interned one object
|
|
2423
|
+
* per `(element, length)`, so `[u32 * 4]`, `@unmanaged [u32 * 4]`,
|
|
2424
|
+
* `@managed [u32 * 4]` and `@inline [u32 * 4]` were **the same Type**, and
|
|
2425
|
+
* the prefix was decorative — measured, all four emitted identical code.
|
|
2426
|
+
*
|
|
2427
|
+
* The two forms are not the same thing. `[u32 * 4]` is 16 bytes of inline
|
|
2428
|
+
* elements with no address of its own; `@unmanaged [u32 * 4]` is a pointer to
|
|
2429
|
+
* four elements, i.e. 4 bytes. Part of {@link equals} for the same reason
|
|
2430
|
+
* {@link dynamicMemoryModel} is: interning them together would make the two
|
|
2431
|
+
* spellings the same object, and no downstream test could tell them apart.
|
|
2432
|
+
*/
|
|
2433
|
+
fixedMemoryModel: MemoryModelCode;
|
|
2434
|
+
/**
|
|
2435
|
+
* Element type of a {@link TypeKind.UnmanagedArray}, else `null`.
|
|
2436
|
+
*
|
|
2437
|
+
* Kept apart from {@link fixedElementType} rather than shared. The two kinds
|
|
2438
|
+
* say different things -- an extent versus an address -- and a shared field
|
|
2439
|
+
* would force every `kind == FixedArray` test in the compiler to become a
|
|
2440
|
+
* three-way test, with the risk that one of them silently starts treating an
|
|
2441
|
+
* address as an extent. `size` differs for the same reason: this kind's size is
|
|
2442
|
+
* the pointer's, not the element's replicated.
|
|
2443
|
+
*/
|
|
2444
|
+
unmanagedElementType: Type | null;
|
|
2445
|
+
/** Element type of a {@link TypeKind.DynamicArray}, else `null`. */
|
|
2446
|
+
dynamicArrayElementType: Type | null;
|
|
2447
|
+
/**
|
|
2448
|
+
* Who owns a {@link TypeKind.DynamicArray}'s buffer.
|
|
2387
2449
|
*
|
|
2388
|
-
*
|
|
2389
|
-
*
|
|
2390
|
-
*
|
|
2391
|
-
*
|
|
2450
|
+
* {@link MemoryModelCode.Unmanaged} for a C-compatible header-prefixed buffer;
|
|
2451
|
+
* {@link MemoryModelCode.Managed} is Landing 4d. Part of {@link equals}, so the
|
|
2452
|
+
* two cannot be confused for one another even though they share a kind and a
|
|
2453
|
+
* layout.
|
|
2454
|
+
*/
|
|
2455
|
+
dynamicMemoryModel: MemoryModelCode;
|
|
2456
|
+
/**
|
|
2457
|
+
* Alignment (log2) of a {@link TypeKind.FixedArray}.
|
|
2458
|
+
*
|
|
2459
|
+
* For the **value** form this is the element's. `alignLog2` cannot derive
|
|
2460
|
+
* that from `byteSize` -- a 24-byte `f32[6]` would report 16-byte alignment
|
|
2461
|
+
* (`31 - clz(24)` = 4), and a 96-byte `f32[24]` would report 64. An array is
|
|
2462
|
+
* aligned as its element is, no matter how long it is, so the value is carried
|
|
2463
|
+
* rather than computed.
|
|
2464
|
+
*
|
|
2465
|
+
* For the **view** form it is the *pointer's*, because that is what the value
|
|
2466
|
+
* is: the extent says nothing about how the address is aligned.
|
|
2392
2467
|
*/
|
|
2393
2468
|
private fixedAlignLog2;
|
|
2394
2469
|
/** Respective non-nullable type, if nullable. */
|
|
@@ -2405,7 +2480,15 @@ declare module "types:tensionscript/src/types" {
|
|
|
2405
2480
|
get exceptVoid(): Type;
|
|
2406
2481
|
/** Size in bytes. */
|
|
2407
2482
|
get byteSize(): number;
|
|
2408
|
-
/**
|
|
2483
|
+
/**
|
|
2484
|
+
* Gets this type's logarithmic alignment in memory.
|
|
2485
|
+
*
|
|
2486
|
+
* An `UnmanagedArray` deliberately does **not** take the {@link fixedAlignLog2}
|
|
2487
|
+
* branch. It is one pointer, so its alignment is the pointer's -- which is what
|
|
2488
|
+
* the `byteSize` fallback already yields, since this kind's `size` is the
|
|
2489
|
+
* pointer's and not the element's replicated. There is no element alignment to
|
|
2490
|
+
* borrow here; the element is not stored in this type.
|
|
2491
|
+
*/
|
|
2409
2492
|
get alignLog2(): number;
|
|
2410
2493
|
/** Tests if this type represents a basic value. */
|
|
2411
2494
|
get isValue(): boolean;
|
|
@@ -2456,6 +2539,34 @@ declare module "types:tensionscript/src/types" {
|
|
|
2456
2539
|
get isManaged(): boolean;
|
|
2457
2540
|
/** Tests if this is a class type explicitly annotated as unmanaged. */
|
|
2458
2541
|
get isUnmanaged(): boolean;
|
|
2542
|
+
/**
|
|
2543
|
+
* This type's extent in bytes when it is stored **inline**, rather than by
|
|
2544
|
+
* reference.
|
|
2545
|
+
*
|
|
2546
|
+
* For a scalar the two are the same number, and for an ordinary class neither
|
|
2547
|
+
* is what an inline array wants -- a class element is stored as its 4-byte
|
|
2548
|
+
* reference, so `byteSize` is right there. The one case where `byteSize` is
|
|
2549
|
+
* **wrong** is a C-layout record (`@unmanaged` / `@managed struct`, and
|
|
2550
|
+
* `@inline struct`, which the parser also flags `@unmanaged`): there
|
|
2551
|
+
* `byteSize` is the reference width (4) while the bytes an inline element
|
|
2552
|
+
* actually occupies are the record's layout size, `Class#nextMemoryOffset`.
|
|
2553
|
+
*
|
|
2554
|
+
* That is the same pair `builtin_sizeof` distinguishes
|
|
2555
|
+
* (`builtins.ts`, the `Unmanaged | ManagedStruct` branch), and it is why
|
|
2556
|
+
* `sizeof<Props>()` answered 16 while `sizeof<[Props * 4]>()` answered 16
|
|
2557
|
+
* instead of 64: the array's size was built from the reference width.
|
|
2558
|
+
*/
|
|
2559
|
+
get inlineExtentBytes(): number;
|
|
2560
|
+
/**
|
|
2561
|
+
* This type's alignment as a log2 when it is stored inline.
|
|
2562
|
+
*
|
|
2563
|
+
* A record's alignment is the strongest of its fields', accumulated while the
|
|
2564
|
+
* resolver lays it out (`Class#alignLog2`), and **not** `Type#alignLog2` —
|
|
2565
|
+
* which reads the class's 4-byte reference size and would report 2 for every
|
|
2566
|
+
* record, including one aligned to 8. The same distinction `builtin_alignof`
|
|
2567
|
+
* makes, for the same reason.
|
|
2568
|
+
*/
|
|
2569
|
+
get inlineAlignLog2(): number;
|
|
2459
2570
|
get isMemory(): boolean;
|
|
2460
2571
|
/** Gets the corresponding non-nullable type. */
|
|
2461
2572
|
get nonNullableType(): Type;
|
|
@@ -2530,21 +2641,90 @@ declare module "types:tensionscript/src/types" {
|
|
|
2530
2641
|
/** A 32-bit float. */
|
|
2531
2642
|
static readonly f32: Type;
|
|
2532
2643
|
/** A 64-bit float. */
|
|
2533
|
-
/** Interned fixed-array types, keyed by element type and length. */
|
|
2644
|
+
/** Interned fixed-array types, keyed by model, element type and length. */
|
|
2534
2645
|
private static _fixedArrays;
|
|
2535
2646
|
/**
|
|
2536
|
-
* Gets the {@link TypeKind.FixedArray} of `elementType` repeated `length`
|
|
2537
|
-
*
|
|
2538
|
-
*
|
|
2539
|
-
*
|
|
2540
|
-
*
|
|
2541
|
-
*
|
|
2542
|
-
*
|
|
2543
|
-
*
|
|
2647
|
+
* Gets the {@link TypeKind.FixedArray} of `elementType` repeated `length`
|
|
2648
|
+
* times, in the storage named by `memoryModel`.
|
|
2649
|
+
*
|
|
2650
|
+
* Interned: the same `(model, element, length)` always yields the same `Type`,
|
|
2651
|
+
* so `offsetof`, `alignof`, `sizeof` and field lookup can compare by identity
|
|
2652
|
+
* the way they do for every other type.
|
|
2653
|
+
*
|
|
2654
|
+
* **The model is part of the identity**, and that is the point of Landing
|
|
2655
|
+
* 5a.5. Before it, this function had one axis (element, length) and the memory
|
|
2656
|
+
* model was dropped, so `[u32 * 4]` and `@unmanaged [u32 * 4]` were the same
|
|
2657
|
+
* Type object — measured: both compiled, both `sizeof` 16, and all four
|
|
2658
|
+
* spellings (`[T * N]`, `@unmanaged [T * N]`, `@managed [T * N]`,
|
|
2659
|
+
* `@inline [T * N]`) emitted byte-identical code. A prefix that changes
|
|
2660
|
+
* nothing is worse than one that is refused, because it reads as if it means
|
|
2661
|
+
* something.
|
|
2662
|
+
*
|
|
2663
|
+
* The two honourable forms differ in both size and alignment:
|
|
2664
|
+
*
|
|
2665
|
+
* value (`Any` / `Inline`) — inline elements: `elementSize * length` bytes,
|
|
2666
|
+
* aligned as the element is
|
|
2667
|
+
* view (`Unmanaged`) — one address: `pointerSize` bits, aligned as a
|
|
2668
|
+
* pointer is
|
|
2669
|
+
* heap (`Managed`) — one GC reference, same shape as the view; the
|
|
2670
|
+
* form itself is refused until Landing 5c, but
|
|
2671
|
+
* the Type can be built so that `sizeof` answers
|
|
2672
|
+
* the truth before the refusal fires
|
|
2673
|
+
*
|
|
2674
|
+
* `pointerSize` is in **bits**, matching `Type.size`.
|
|
2544
2675
|
*/
|
|
2545
|
-
static fixedArray(elementType: Type, length: number): Type;
|
|
2676
|
+
static fixedArray(elementType: Type, length: number, memoryModel: MemoryModelCode, pointerSize: number): Type;
|
|
2546
2677
|
/** Gets the element type of a {@link TypeKind.FixedArray}. */
|
|
2547
2678
|
get fixedArrayElementType(): Type;
|
|
2679
|
+
/** Interned unmanaged-array types, keyed by element type and pointer width. */
|
|
2680
|
+
private static _unmanagedArrays;
|
|
2681
|
+
/**
|
|
2682
|
+
* Gets the {@link TypeKind.UnmanagedArray} of `elementType`: a pointer to a run
|
|
2683
|
+
* of `elementType`, with no length.
|
|
2684
|
+
*
|
|
2685
|
+
* `pointerSize` is `options.usizeType.size` -- 32 or 64 bits. It is a
|
|
2686
|
+
* parameter rather than a constant because a `Type` carries its own size, and
|
|
2687
|
+
* `size` here must be the **pointer's**, not the element's: there is no extent
|
|
2688
|
+
* to measure. It is part of the cache key for the same reason -- `equals`
|
|
2689
|
+
* compares element types only, so two types differing solely in pointer width
|
|
2690
|
+
* must not be the same object.
|
|
2691
|
+
*
|
|
2692
|
+
* Unlike {@link Type.fixedArray} this consults nothing about the element but
|
|
2693
|
+
* its identity: the count is unknown, which is the entire point of the kind.
|
|
2694
|
+
*
|
|
2695
|
+
* The cache is validated by **identity** of the element, not just by the key.
|
|
2696
|
+
* This is what keeps interning a per-program property rather than a
|
|
2697
|
+
* per-process one: the map is a static that outlives a `Program`, so a second
|
|
2698
|
+
* `asc.main` in the same process (which is exactly what the compiler test
|
|
2699
|
+
* harness does -- debug then release) would otherwise be handed the first
|
|
2700
|
+
* program's `Type`, whose `unmanagedElementType` carries the first program's
|
|
2701
|
+
* `Class`. A property read through that class then emitted a call to a getter
|
|
2702
|
+
* the new module never compiled, and the module failed to validate:
|
|
2703
|
+
* `wasm-validator error ... call target must exist`.
|
|
2704
|
+
*
|
|
2705
|
+
* So a cached entry is returned only when its element is the *same object* the
|
|
2706
|
+
* current program just resolved. Within one program that is always true --
|
|
2707
|
+
* `resolveType` interns a record's `Type` -- so interning still holds there.
|
|
2708
|
+
*/
|
|
2709
|
+
static unmanagedArray(elementType: Type, pointerSize: number): Type;
|
|
2710
|
+
/** Gets the element type of a {@link TypeKind.UnmanagedArray}. */
|
|
2711
|
+
get unmanagedArrayElementType(): Type;
|
|
2712
|
+
/** Interned dynamic-array types, keyed by model, element and pointer width. */
|
|
2713
|
+
private static _dynamicArrays;
|
|
2714
|
+
/**
|
|
2715
|
+
* Gets the {@link TypeKind.DynamicArray} of `elementType`.
|
|
2716
|
+
*
|
|
2717
|
+
* The key carries the **model** as well as the element, because `equals`
|
|
2718
|
+
* compares both: two models over one element are different types, and
|
|
2719
|
+
* interning them together would make them the same object.
|
|
2720
|
+
*
|
|
2721
|
+
* Like {@link Type.unmanagedArray} the entry is validated by element identity
|
|
2722
|
+
* on the way out — the map outlives a `Program`, so a second compile in one
|
|
2723
|
+
* process must not be handed the first one's element `Class`.
|
|
2724
|
+
*/
|
|
2725
|
+
static dynamicArray(elementType: Type, memoryModel: MemoryModelCode, pointerSize: number): Type;
|
|
2726
|
+
/** Gets the element type of a {@link TypeKind.DynamicArray}. */
|
|
2727
|
+
get dynamicElementType(): Type;
|
|
2548
2728
|
static readonly f64: Type;
|
|
2549
2729
|
/** A 128-bit vector. */
|
|
2550
2730
|
static readonly v128: Type;
|
|
@@ -3259,7 +3439,83 @@ declare module "types:tensionscript/src/resolver" {
|
|
|
3259
3439
|
* collection wants `Array<T>`, and letting `T[N]` hold references would make
|
|
3260
3440
|
* `@unmanaged` records carry GC edges they cannot describe. Refused by name.
|
|
3261
3441
|
*/
|
|
3442
|
+
/**
|
|
3443
|
+
* Turns on `Feature.MultiValue` the first time a value-form `[T * N]` return
|
|
3444
|
+
* type is resolved.
|
|
3445
|
+
*
|
|
3446
|
+
* **At resolution, not at emission.** The module's feature flags are computed
|
|
3447
|
+
* once, in `Compiler`'s constructor (`module.setFeatures`), and a return is
|
|
3448
|
+
* emitted long after that — so this sets the option *and* re-sets the module's
|
|
3449
|
+
* flags, which `setFeatures` supports (`module.ts`). Measuring that
|
|
3450
|
+
* re-settability is what this hook rests on: with a write-once flags word this
|
|
3451
|
+
* would have needed a deferred second pass.
|
|
3452
|
+
*
|
|
3453
|
+
* Policy is **auto-enable** rather than a required flag: a consumer who writes
|
|
3454
|
+
* `function make(): [T * N]` should not have to know that the emitter lowers it
|
|
3455
|
+
* to multivalue results. The trade is that the module's declared feature set
|
|
3456
|
+
* depends on its source, which is exactly the contract `--exportRuntime`
|
|
3457
|
+
* already sets. A module that never returns one never gets the flag.
|
|
3458
|
+
*
|
|
3459
|
+
* Idempotent: `features` is a bitmask, and re-setting the same flags is a
|
|
3460
|
+
* no-op for binaryen.
|
|
3461
|
+
*/
|
|
3462
|
+
private enableMultiValueForArrayReturn;
|
|
3463
|
+
/** Whether `type` is a fixed array in its **value** form — N inline elements
|
|
3464
|
+
* with no address of their own — as opposed to the `@unmanaged` view (a
|
|
3465
|
+
* pointer) or the `@managed` heap form (Landing 5c). */
|
|
3466
|
+
private isValueFormFixedArray;
|
|
3262
3467
|
private resolveFixedArrayType;
|
|
3468
|
+
/**
|
|
3469
|
+
* Resolves an {@link UnmanagedArrayTypeNode} to a
|
|
3470
|
+
* {@link TypeKind.UnmanagedArray}.
|
|
3471
|
+
*
|
|
3472
|
+
* Deliberately **not** a copy of {@link resolveFixedArrayType}: none of that
|
|
3473
|
+
* function's refusals belong here, and copying them would refuse the form's
|
|
3474
|
+
* whole purpose.
|
|
3475
|
+
*
|
|
3476
|
+
* A fixed array *contains* its elements, so a record element would claim `N`
|
|
3477
|
+
* records sit inline -- refused by name (`resolver.ts`, the `AS100` record
|
|
3478
|
+
* arm). An unmanaged array contains one address, so a record element is the
|
|
3479
|
+
* ordinary case: `[BodyState *]` is a pointer to a run of records, which is
|
|
3480
|
+
* exactly what the collision solver needs and what `BodyState[N]` cannot say.
|
|
3481
|
+
*
|
|
3482
|
+
* What *is* refused is an element with no bytes to point at, which is the same
|
|
3483
|
+
* `byteSize` question `sizeof` asks. An `@inline` element is admitted here on
|
|
3484
|
+
* purpose: it is a value type with a layout, and a pointer to it is a pointer
|
|
3485
|
+
* to those bytes -- the refusal that applies to it is the *field* form's, not
|
|
3486
|
+
* the pointer's.
|
|
3487
|
+
*
|
|
3488
|
+
* A **GC-managed** element is refused (see the arm below). Measured before it
|
|
3489
|
+
* existed: `[Foo *]` over a `class Foo` compiled and emitted
|
|
3490
|
+
* `base + i*4`, `i32.load`, `call Foo#get:x` -- the buffer holds bare
|
|
3491
|
+
* references that nothing scans.
|
|
3492
|
+
*/
|
|
3493
|
+
private resolveUnmanagedArrayType;
|
|
3494
|
+
/**
|
|
3495
|
+
* Resolves a {@link DynamicArrayTypeNode} to a {@link TypeKind.DynamicArray}.
|
|
3496
|
+
*
|
|
3497
|
+
* The type is **one pointer** to a `[u32 length][pad][data]` header; the length
|
|
3498
|
+
* is not in the type, which is the whole point — it is a runtime value, read
|
|
3499
|
+
* from the buffer. `n` is spelling here and a binding where a function scope
|
|
3500
|
+
* exists (see `Program#bindDynamicLengthLocals`).
|
|
3501
|
+
*
|
|
3502
|
+
* Three refusals, each for a different reason:
|
|
3503
|
+
*
|
|
3504
|
+
* - **`@managed`** is Landing 4d. The buffer would need a collector-visible
|
|
3505
|
+
* header, which this landing does not produce.
|
|
3506
|
+
*
|
|
3507
|
+
* - **No model at all** cannot be honoured by any emitter: an inline
|
|
3508
|
+
* runtime-length array would need variable stack allocation, which WASM does
|
|
3509
|
+
* not have. Naming a model is the source saying where the bytes live.
|
|
3510
|
+
*
|
|
3511
|
+
* - **A GC-managed element** is the same hazard Landing 3's CX1 closed for
|
|
3512
|
+
* `[T *]`: the buffer is not scanned, so a reference stored in it is not a
|
|
3513
|
+
* root.
|
|
3514
|
+
*
|
|
3515
|
+
* An `@inline` element is accepted: it is a value type, so its extent is
|
|
3516
|
+
* `byteSize` and Landing 3 measured that stride works.
|
|
3517
|
+
*/
|
|
3518
|
+
private resolveDynamicArrayType;
|
|
3263
3519
|
private resolveTupleType;
|
|
3264
3520
|
private resolveBuiltinNotNullableType;
|
|
3265
3521
|
/** Resolves a type name to the program element it refers to. */
|
|
@@ -3372,6 +3628,28 @@ declare module "types:tensionscript/src/resolver" {
|
|
|
3372
3628
|
private lookupPropertyAccessExpression;
|
|
3373
3629
|
/** Resolves a property access expression to its static type. */
|
|
3374
3630
|
private resolvePropertyAccessExpression;
|
|
3631
|
+
/**
|
|
3632
|
+
* The element type of an array-kind receiver, or `null` when `type` is not one.
|
|
3633
|
+
*
|
|
3634
|
+
* Three kinds answer here, and they are one family even though only two are a
|
|
3635
|
+
* `TypeKind`:
|
|
3636
|
+
*
|
|
3637
|
+
* - `[T *]` — `TypeKind.UnmanagedArray`, element on the type;
|
|
3638
|
+
* - `@unmanaged @dynamic [T * n]` — `TypeKind.DynamicArray`, element on the type;
|
|
3639
|
+
* - `@managed @dynamic [T * n]` — a **class reference** to the std
|
|
3640
|
+
* `DynamicArray<T>` descriptor (Landing 4d.1), so the element is the class's
|
|
3641
|
+
* type argument.
|
|
3642
|
+
*
|
|
3643
|
+
* The third case is why this is a helper. Landing 2 added the first arm by
|
|
3644
|
+
* hand, Landing 4b added the second by hand, and the managed form would be the
|
|
3645
|
+
* third copy of the same two-line idea — in two places, since the element is
|
|
3646
|
+
* wanted both as a *type* (`resolveElementAccessExpression`) and as an
|
|
3647
|
+
* *element* (`lookupElementAccessExpression`, which peels `y[i].field` through
|
|
3648
|
+
* the element's class). One definition, three kinds, two consumers.
|
|
3649
|
+
*/
|
|
3650
|
+
private arrayKindElementType;
|
|
3651
|
+
/** Whether `classReference` is the std `DynamicArray<T>` descriptor class. */
|
|
3652
|
+
private isManagedDynamicArrayClass;
|
|
3375
3653
|
/** Looks up the program element the specified element access expression refers to. */
|
|
3376
3654
|
private lookupElementAccessExpression;
|
|
3377
3655
|
/** Resolves an element access expression to its static type. */
|
|
@@ -3642,6 +3920,25 @@ declare module "types:tensionscript/src/parser" {
|
|
|
3642
3920
|
finish(): void;
|
|
3643
3921
|
/** Parses a type name. */
|
|
3644
3922
|
parseTypeName(tn: Tokenizer): TypeName | null;
|
|
3923
|
+
/**
|
|
3924
|
+
* Whether a `[` at the start of a type begins the unmanaged-array family
|
|
3925
|
+
* (`[T *]`, `[T * N]`) rather than a tuple.
|
|
3926
|
+
*
|
|
3927
|
+
* The discriminator is one token after the element type: `*` commits, and
|
|
3928
|
+
* anything else (`]`, `,`, `:`, `|`) belongs to the tuple arm. The lookahead
|
|
3929
|
+
* speculates with errors suppressed and rewinds either way -- the same shape
|
|
3930
|
+
* as `tryParseFunctionType` / `tryParseSignatureIsSignature`, and the reason
|
|
3931
|
+
* the tuple arm's body needs no change: it is entered with the tokenizer
|
|
3932
|
+
* exactly where its own `tn.skip(Token.CloseBracket)` expects it.
|
|
3933
|
+
*
|
|
3934
|
+
* A pre-type decorator is excluded before speculating. `parseType`'s decorator
|
|
3935
|
+
* arm reports `AS212` ("Decorator '@x' is not valid here") *before*
|
|
3936
|
+
* `suppressErrors` is consulted, so speculating into `[@unmanaged T *]` would
|
|
3937
|
+
* emit a diagnostic for a form this family does not accept anyway -- and then
|
|
3938
|
+
* emit the tuple/`Type expected` error on the rewind, giving two errors for
|
|
3939
|
+
* one mistake.
|
|
3940
|
+
*/
|
|
3941
|
+
startsUnmanagedArrayType(tn: Tokenizer): boolean;
|
|
3645
3942
|
/** Parses a type. */
|
|
3646
3943
|
parseType(tn: Tokenizer, acceptParenthesized?: boolean, suppressErrors?: boolean): TypeNode | null;
|
|
3647
3944
|
private tryParseSignatureIsSignature;
|
|
@@ -3813,7 +4110,7 @@ declare module "types:tensionscript/src/program" {
|
|
|
3813
4110
|
import { Type, Signature } from "types:tensionscript/src/types";
|
|
3814
4111
|
import { Token } from "types:tensionscript/src/tokenizer";
|
|
3815
4112
|
import { Node, Source, DecoratorNode, DecoratorKind, TypeParameterNode, TypeNode, NamedTypeNode, FunctionTypeNode, ArrowKind, Expression, IdentifierExpression, Statement, ClassDeclaration, DeclarationStatement, EnumDeclaration, EnumValueDeclaration, FieldDeclaration, FunctionDeclaration, InterfaceDeclaration, NamespaceDeclaration, TypeDeclaration, VariableDeclaration, VariableLikeDeclarationStatement } from "types:tensionscript/src/ast";
|
|
3816
|
-
import { Module, ExpressionRef, FunctionRef, MemorySegment } from "types:tensionscript/src/module";
|
|
4113
|
+
import { Module, ExpressionRef, FunctionRef, MemorySegment, TypeRef } from "types:tensionscript/src/module";
|
|
3817
4114
|
import { Resolver } from "types:tensionscript/src/resolver";
|
|
3818
4115
|
import { Flow } from "types:tensionscript/src/flow";
|
|
3819
4116
|
import { Parser } from "types:tensionscript/src/parser";
|
|
@@ -3941,6 +4238,17 @@ declare module "types:tensionscript/src/program" {
|
|
|
3941
4238
|
/** Gets the standard `StaticArray` prototype. */
|
|
3942
4239
|
get staticArrayPrototype(): ClassPrototype;
|
|
3943
4240
|
private _staticArrayPrototype;
|
|
4241
|
+
/**
|
|
4242
|
+
* Gets the `DynamicArray` prototype — the descriptor class behind
|
|
4243
|
+
* `@managed @dynamic [T * n]`.
|
|
4244
|
+
*
|
|
4245
|
+
* Follows `staticArrayPrototype` exactly: a lazily-cached `require` of the
|
|
4246
|
+
* std prototype, so `@managed @dynamic [T * n]` can resolve through
|
|
4247
|
+
* `resolveClass(program.dynamicArrayPrototype, [elementType])` and come back
|
|
4248
|
+
* as an ordinary generic class instance.
|
|
4249
|
+
*/
|
|
4250
|
+
get dynamicArrayPrototype(): ClassPrototype;
|
|
4251
|
+
private _dynamicArrayPrototype;
|
|
3944
4252
|
/** Gets the standard `Set` prototype. */
|
|
3945
4253
|
get setPrototype(): ClassPrototype;
|
|
3946
4254
|
private _setPrototype;
|
|
@@ -4586,6 +4894,29 @@ declare module "types:tensionscript/src/program" {
|
|
|
4586
4894
|
* therefore cannot alias.
|
|
4587
4895
|
*/
|
|
4588
4896
|
fieldLocals: Map<string, Local> | null;
|
|
4897
|
+
/**
|
|
4898
|
+
* The WASM slot type for this local, when it is **not** what {@link type}
|
|
4899
|
+
* says it is.
|
|
4900
|
+
*
|
|
4901
|
+
* `type` answers "what does the source see" — a record, so `p.field` resolves;
|
|
4902
|
+
* an array, so `arr[i]` resolves. The slot is a different question, and for
|
|
4903
|
+
* most locals the two agree. Three cases where they do not:
|
|
4904
|
+
*
|
|
4905
|
+
* - **view local** (`isViewLocal`) — the slot is the pointer; handled below by
|
|
4906
|
+
* substituting `usizeType`, because a pointer *is* a type.
|
|
4907
|
+
* - **multivalue tuple** — the slot is the `TypeRef` binaryen makes for a
|
|
4908
|
+
* multi-result signature. That has **no `Type` at all**: `createType(refs)`
|
|
4909
|
+
* answers a `TypeRef` the type system cannot describe. Hence an override
|
|
4910
|
+
* rather than a substitution — this is the one local whose slot cannot be
|
|
4911
|
+
* named by a `Type`.
|
|
4912
|
+
*
|
|
4913
|
+
* {@link TypeRef.None} for every other local, so the ordinary case costs
|
|
4914
|
+
* nothing — the same reasoning as {@link fieldLocals}. A sentinel rather than
|
|
4915
|
+
* `| null` because `TypeRef` is an integer type and cannot be nullable here
|
|
4916
|
+
* (measured: `AS204: Type 'TypeRef' cannot be nullable` when the self-hosted
|
|
4917
|
+
* compiler parsed this declaration).
|
|
4918
|
+
*/
|
|
4919
|
+
typeRefOverride: TypeRef;
|
|
4589
4920
|
/**
|
|
4590
4921
|
* Whether this local is a **view parameter**: `a: @unmanaged T` where `T` is
|
|
4591
4922
|
* an inline type.
|
|
@@ -4607,6 +4938,15 @@ declare module "types:tensionscript/src/program" {
|
|
|
4607
4938
|
* is what gives it one `i32` slot instead of the record's reference type.
|
|
4608
4939
|
*/
|
|
4609
4940
|
isViewLocal: boolean;
|
|
4941
|
+
/**
|
|
4942
|
+
* Whether this local is a **dynamic-array length binding** — the `n` in
|
|
4943
|
+
* `[T * n]`, introduced by the signature rather than written as a declaration.
|
|
4944
|
+
*
|
|
4945
|
+
* It is read-only by construction: its value comes from the buffer header at
|
|
4946
|
+
* function entry, so assigning it would make the compiler's idea of the length
|
|
4947
|
+
* disagree with the buffer's. The assignment and shadowing rules key on this.
|
|
4948
|
+
*/
|
|
4949
|
+
isDynamicLength: boolean;
|
|
4610
4950
|
/** Constructs a new local variable. */
|
|
4611
4951
|
constructor(
|
|
4612
4952
|
/** Simple name. */
|
|
@@ -4732,6 +5072,23 @@ declare module "types:tensionscript/src/program" {
|
|
|
4732
5072
|
* one structure regardless of where the leaves' storage came from.
|
|
4733
5073
|
*/
|
|
4734
5074
|
bindSroaParameterLeaves(type: Type, path: string, into: Map<string, Local>, localIndex: number, flow: Flow): BindResult;
|
|
5075
|
+
/**
|
|
5076
|
+
* Binds a value-form `[T * N]` parameter's **leaves** to the WASM parameters
|
|
5077
|
+
* that carry them.
|
|
5078
|
+
*
|
|
5079
|
+
* The array sibling of {@link bindSroaParameterLeaves}, and the same tree
|
|
5080
|
+
* shape `fillSroaArrayLocals` builds for a local: the map is keyed `"0"`,
|
|
5081
|
+
* `"1"`, ... and a record element is a placeholder carrying its field leaves.
|
|
5082
|
+
* What differs is where the leaves' storage comes from — incoming parameters
|
|
5083
|
+
* here, fresh locals there.
|
|
5084
|
+
*
|
|
5085
|
+
* Element-major, matching `Signature.leafTypesOf` and the caller's operand
|
|
5086
|
+
* order. A parameter is a **value** for the callee's whole body: nothing is
|
|
5087
|
+
* written back, so a store to `arr[0].x` is invisible to the caller. That is
|
|
5088
|
+
* the copy semantics the representation is for, and it costs nothing extra —
|
|
5089
|
+
* the leaves are separate slots precisely because the value has no address.
|
|
5090
|
+
*/
|
|
5091
|
+
bindSroaArrayParameterLeaves(type: Type, path: string, into: Map<string, Local>, localIndex: number, flow: Flow): BindResult;
|
|
4735
5092
|
/** Constructs a new concrete function. */
|
|
4736
5093
|
constructor(
|
|
4737
5094
|
/** Name incl. type parameters, i.e. `foo<i32>`. */
|
|
@@ -4744,8 +5101,23 @@ declare module "types:tensionscript/src/program" {
|
|
|
4744
5101
|
signature: Signature, // pre-resolved
|
|
4745
5102
|
/** Contextual type arguments inherited from its parent class, if any. */
|
|
4746
5103
|
contextualTypeArguments?: Map<string, Type> | null);
|
|
4747
|
-
/**
|
|
4748
|
-
|
|
5104
|
+
/**
|
|
5105
|
+
* The **WASM slot types** of the additional locals that are not parameters.
|
|
5106
|
+
*
|
|
5107
|
+
* Named for the refs rather than the types because that is what it now
|
|
5108
|
+
* answers: most slots are `local.type.toRef()`, but a multivalue tuple's slot
|
|
5109
|
+
* is a `TypeRef` with no `Type` behind it ({@link Local.typeRefOverride}), and
|
|
5110
|
+
* a view local's slot is the pointer rather than the record it names. Callers
|
|
5111
|
+
* feed this straight to `Module#addFunction`'s `varTypes`, which is a
|
|
5112
|
+
* `TypeRef[]` — so the conversion belongs here, where the slot is decided,
|
|
5113
|
+
* rather than at each of them.
|
|
5114
|
+
*
|
|
5115
|
+
* Renamed from `getNonParameterLocalTypes` when the tuple override landed:
|
|
5116
|
+
* four call sites all wrapped the old answer in `typesToRefs`, and renaming
|
|
5117
|
+
* means a caller that was missed fails to compile instead of silently
|
|
5118
|
+
* declaring a slot of the wrong type.
|
|
5119
|
+
*/
|
|
5120
|
+
getNonParameterLocalTypeRefs(): TypeRef[];
|
|
4749
5121
|
/** Gets the name of the parameter at the specified index. */
|
|
4750
5122
|
getParameterName(index: number): string;
|
|
4751
5123
|
/** Creates a stub for use with this function, i.e. for varargs or override calls. */
|
|
@@ -5859,6 +6231,15 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
5859
6231
|
indexExpression: Expression | null,
|
|
5860
6232
|
/** Whether to tee the value. */
|
|
5861
6233
|
tee: boolean): ExpressionRef;
|
|
6234
|
+
/**
|
|
6235
|
+
* The {@link DynamicArrayTypeNode} a declaration names, if it names one.
|
|
6236
|
+
*
|
|
6237
|
+
* Two spellings carry the length's name: the annotation (`const y: [T * n]`)
|
|
6238
|
+
* and `changetype`'s type argument (`const y = changetype<[T * n]>(p)`). Both
|
|
6239
|
+
* are read here so the local-position binding does not depend on which one the
|
|
6240
|
+
* source chose.
|
|
6241
|
+
*/
|
|
6242
|
+
private dynamicArrayTypeNodeOf;
|
|
5862
6243
|
/** Makes an assignment to a local, keeping track of wrap and null states. */
|
|
5863
6244
|
private makeLocalAssignment;
|
|
5864
6245
|
/** Makes an assignment to a global. */
|
|
@@ -5931,6 +6312,177 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
5931
6312
|
/** Creates an indirect call to a first-class function. */
|
|
5932
6313
|
makeCallIndirect(signature: Signature, functionArg: ExpressionRef, reportNode: Node, operands?: ExpressionRef[] | null, immediatelyDropped?: boolean): ExpressionRef;
|
|
5933
6314
|
private compileCommaExpression;
|
|
6315
|
+
/**
|
|
6316
|
+
* The byte extent of one element of a `[T *]` — the stride `y[i]` walks by.
|
|
6317
|
+
*
|
|
6318
|
+
* For a scalar this is `Type.byteSize`. For a record it is **not**: an
|
|
6319
|
+
* `@unmanaged`/`@managed` record's `Type` is reference-like, so its `byteSize`
|
|
6320
|
+
* is the 4-byte address, and the extent lives on the `Class` that laid the
|
|
6321
|
+
* fields out. `builtin_sizeof` already answers this way for the same reason
|
|
6322
|
+
* (`builtins.ts`, the `Unmanaged | ManagedStruct` branch answers
|
|
6323
|
+
* `nextMemoryOffset`), so the two cannot disagree about how big a record is.
|
|
6324
|
+
*
|
|
6325
|
+
* An `@inline struct` needs no arm: it *is* a value type, so its
|
|
6326
|
+
* `byteSize` is already the extent. Measured — `[Inl *]` over
|
|
6327
|
+
* `@inline struct Inl { x: f64; y: f64 }` strides 16, which is
|
|
6328
|
+
* `sizeof<Inl>()`.
|
|
6329
|
+
*
|
|
6330
|
+
* Measured, and the reason this helper exists: using `byteSize` directly gave
|
|
6331
|
+
* a stride of 4 for a two-`f64` record of 16 bytes — the same "alignment or
|
|
6332
|
+
* reference size instead of the extent" mistake the fixed-array arm avoids
|
|
6333
|
+
* only because it refuses records outright.
|
|
6334
|
+
*/
|
|
6335
|
+
private unmanagedArrayElementSize;
|
|
6336
|
+
/**
|
|
6337
|
+
* Whether `type` is a record whose elements live **at** the address rather
|
|
6338
|
+
* than being a value loaded from it: `@unmanaged`, `@managed` or `@inline`.
|
|
6339
|
+
*
|
|
6340
|
+
* This is the discriminator between "the address is the element" and "load the
|
|
6341
|
+
* element from the address", and it is deliberately about the *element kind*
|
|
6342
|
+
* rather than about type equality — see {@link compileUnmanagedArrayElementAccess}.
|
|
6343
|
+
*/
|
|
6344
|
+
private isRecordValueType;
|
|
6345
|
+
/**
|
|
6346
|
+
* The header an `@unmanaged @dynamic [T * n]` buffer carries in front of its
|
|
6347
|
+
* elements: `align_up(4, alignof(T))`.
|
|
6348
|
+
*
|
|
6349
|
+
* Four bytes hold the `u32` length; anything needing stronger alignment than
|
|
6350
|
+
* that gets padding after it. So `u32` elements sit at `ptr + 4`, and a
|
|
6351
|
+
* two-`f64` record sits at `ptr + 8`.
|
|
6352
|
+
*
|
|
6353
|
+
* Reported in Landing 4a: **no header-size helper existed**, because nothing
|
|
6354
|
+
* in 4a needed one — `.length` reads offset 0, and 4a's own V5 recorded that
|
|
6355
|
+
* the constant could not be observed from outside. This is its first
|
|
6356
|
+
* definition; `.length` and the element address both go through it so they
|
|
6357
|
+
* cannot drift.
|
|
6358
|
+
*
|
|
6359
|
+
* A record's alignment is `Class#alignLog2` rather than `Type#alignLog2` for
|
|
6360
|
+
* the same reason its size is `nextMemoryOffset`: a record's `Type` is
|
|
6361
|
+
* reference-like and would report the 4-byte pointer's alignment for every
|
|
6362
|
+
* record, including the `f64`-only ones that are aligned 8.
|
|
6363
|
+
*/
|
|
6364
|
+
/**
|
|
6365
|
+
* Whether `type` is the **managed** dynamic-array descriptor — the std
|
|
6366
|
+
* `DynamicArray<T>` class that `@managed @dynamic [T * n]` resolves to
|
|
6367
|
+
* (Landing 4d.1).
|
|
6368
|
+
*
|
|
6369
|
+
* Answered by class identity rather than by a memory-model field, because the
|
|
6370
|
+
* managed form is a class reference now: its `Type` is the class instance's
|
|
6371
|
+
* type, and the "model" is implicit in `isManaged`. That is the whole point of
|
|
6372
|
+
* the redesign — `TypeKind.DynamicArray` carries `TypeFlags.None` and is not
|
|
6373
|
+
* traced, so a descriptor stored as one would not be rooted.
|
|
6374
|
+
*/
|
|
6375
|
+
/**
|
|
6376
|
+
* The element type of either dynamic-array form.
|
|
6377
|
+
*
|
|
6378
|
+
* `@unmanaged @dynamic [T * n]` carries the element on its type;
|
|
6379
|
+
* `@managed @dynamic [T * n]` is a `DynamicArray<T>` class reference, so the
|
|
6380
|
+
* element is the class's type argument. One accessor for both, because every
|
|
6381
|
+
* consumer below — access, compound, increment — would otherwise branch.
|
|
6382
|
+
*/
|
|
6383
|
+
private dynamicArrayElementOf;
|
|
6384
|
+
private isManagedDynamicArrayType;
|
|
6385
|
+
private dynamicArrayHeaderSize;
|
|
6386
|
+
/**
|
|
6387
|
+
* Compiles the byte address of `y[i]` for a dynamic array:
|
|
6388
|
+
* `ptr + headerSize + i*sizeof(T)`.
|
|
6389
|
+
*
|
|
6390
|
+
* Shared by the read and the write arm, so the two cannot disagree about which
|
|
6391
|
+
* bytes they address — the same split the fixed and unmanaged arms use.
|
|
6392
|
+
*
|
|
6393
|
+
* Two constants, each of which was a bug somewhere else in this family:
|
|
6394
|
+
*
|
|
6395
|
+
* - **`headerSize` is present.** It is what separates a dynamic array from a
|
|
6396
|
+
* `[T *]`: the data starts after the length word and its padding.
|
|
6397
|
+
* - **The stride is a multiply by the element's extent**, not a shift by its
|
|
6398
|
+
* alignment. For a two-`f64` record those differ (16 vs 8), which is Landing
|
|
6399
|
+
* 2's lesson and the reason `unmanagedArrayElementSize` exists.
|
|
6400
|
+
*/
|
|
6401
|
+
private compileDynamicArrayElementAddress;
|
|
6402
|
+
/**
|
|
6403
|
+
* The bounds check an `@unmanaged @dynamic [T * n]` access performs before it
|
|
6404
|
+
* touches memory: `if ((u32)index >= (u32)length) trap`.
|
|
6405
|
+
*
|
|
6406
|
+
* **Unsigned** on purpose. A negative index is a huge `u32`, so it fails the
|
|
6407
|
+
* same comparison as any other out-of-range value — one check covers both ends
|
|
6408
|
+
* without a second comparison, and `y[-1]` cannot walk backwards out of the
|
|
6409
|
+
* buffer.
|
|
6410
|
+
*
|
|
6411
|
+
* The length comes from the header directly rather than from the `n` binding.
|
|
6412
|
+
* `n` is a snapshot taken at entry (D5 of 4a); the header is what the buffer
|
|
6413
|
+
* currently says, and a bounds check is about the memory that exists now.
|
|
6414
|
+
*
|
|
6415
|
+
* The message is a literal: `makeAbort` takes a string expression, and nothing
|
|
6416
|
+
* in this compiler formats an index and a length into one (measured — 4a's
|
|
6417
|
+
* `changetype` trap is the same shape). Naming the two causes would mean
|
|
6418
|
+
* building a string at every check.
|
|
6419
|
+
*/
|
|
6420
|
+
private compileDynamicArrayBoundsCheck;
|
|
6421
|
+
/**
|
|
6422
|
+
* Compiles the byte address of `y[i]` for an unmanaged array: `base + i*sizeof(T)`.
|
|
6423
|
+
*
|
|
6424
|
+
* Shared by the read and the write arm, so the two cannot disagree about which
|
|
6425
|
+
* bytes they address — the same reason `compileFixedArrayElementAccess` and
|
|
6426
|
+
* `compileFixedArrayElementAddress` are split.
|
|
6427
|
+
*
|
|
6428
|
+
* The stride is a **multiply**, not the fixed-array arm's `1 << alignof(T)`.
|
|
6429
|
+
* That shift is right only for the elements the fixed arm admits (records are
|
|
6430
|
+
* refused there, so every element is a scalar, where size and alignment
|
|
6431
|
+
* coincide). A record element is the ordinary case here, and for a record the
|
|
6432
|
+
* two disagree: two `f64`s give `sizeof` 16 and `alignof` 8.
|
|
6433
|
+
*/
|
|
6434
|
+
private compileUnmanagedArrayElementAddress;
|
|
6435
|
+
/**
|
|
6436
|
+
* Compiles `y[i]` for an unmanaged array, `[T *]` — both directions.
|
|
6437
|
+
*
|
|
6438
|
+
* Two things separate this from {@link compileFixedArrayElementAccess}:
|
|
6439
|
+
*
|
|
6440
|
+
* - **The stride is a multiply** (see the address helper).
|
|
6441
|
+
*
|
|
6442
|
+
* - **A record element compiles to an address, not a load.** A record's
|
|
6443
|
+
* `toRef` is the 4-byte reference, so loading there would read the record's
|
|
6444
|
+
* first four bytes and call them a pointer. So the address is yielded typed
|
|
6445
|
+
* as the element, and `.field` on it resolves through the record's own
|
|
6446
|
+
* accessor — a load or a store at `addr + offsetof`. **That is also how a
|
|
6447
|
+
* field write works**: `y[i].x = v` reaches the property setter, whose
|
|
6448
|
+
* `this` is this address. No separate arm.
|
|
6449
|
+
*
|
|
6450
|
+
* Reads are unchecked. `*` says the length is unknown, so there is nothing to
|
|
6451
|
+
* check against; `@dynamic` is where a checked form lives.
|
|
6452
|
+
*
|
|
6453
|
+
* A whole-record **write** is refused, keyed on the element being a record.
|
|
6454
|
+
* The key is the element kind, not "both sides have the same type": a scalar
|
|
6455
|
+
* element assignment (`a[i] = 5` over `[u32 *]`) is an ordinary store and must
|
|
6456
|
+
* keep compiling. Refusing by type equality would have caught that case too,
|
|
6457
|
+
* which is the trap this comment exists to keep shut.
|
|
6458
|
+
*/
|
|
6459
|
+
private compileUnmanagedArrayElementAccess;
|
|
6460
|
+
/**
|
|
6461
|
+
* Compiles `y[i]` for an `@unmanaged @dynamic [T * n]` — both directions.
|
|
6462
|
+
*
|
|
6463
|
+
* Differs from {@link compileUnmanagedArrayElementAccess} in exactly one place,
|
|
6464
|
+
* and it is the whole point of the kind: **the bounds check**. A `[T *]` has no
|
|
6465
|
+
* length to check against, so its access is unchecked by contract; a dynamic
|
|
6466
|
+
* array carries one in its header, and an index outside it is a diagnostic
|
|
6467
|
+
* rather than whatever memory happens to follow.
|
|
6468
|
+
*
|
|
6469
|
+
* Everything else is the unmanaged arm's shape, deliberately:
|
|
6470
|
+
*
|
|
6471
|
+
* - a **record element** compiles to the address, typed as the element, so
|
|
6472
|
+
* `.field` reads and writes go through the record's own accessor — which is
|
|
6473
|
+
* also how `y[i].field = v` works, with no arm of its own;
|
|
6474
|
+
* - a **scalar element** is loaded or stored at its own width;
|
|
6475
|
+
* - a whole-record **write** is refused, keyed on the element being a record
|
|
6476
|
+
* rather than on type equality, so `a[i] = 5` over `[u32 * n]` still
|
|
6477
|
+
* compiles.
|
|
6478
|
+
*
|
|
6479
|
+
* Compound assignment and increment call this **twice** — once by way of the
|
|
6480
|
+
* read the operator performs, once for the store — so the check is emitted
|
|
6481
|
+
* twice. That is the smaller of the two correct shapes: sharing one check
|
|
6482
|
+
* would mean threading the checked address through the operator's own codegen,
|
|
6483
|
+
* which does not know this arm exists.
|
|
6484
|
+
*/
|
|
6485
|
+
private compileDynamicArrayElementAccess;
|
|
5934
6486
|
/**
|
|
5935
6487
|
* Compiles `array[index]` for a `T[N]` inline array: read and write.
|
|
5936
6488
|
*
|
|
@@ -6071,6 +6623,42 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
6071
6623
|
addDebugLocation(expr: ExpressionRef, range: Range): void;
|
|
6072
6624
|
/** Checks whether a particular function signature is supported. */
|
|
6073
6625
|
checkSignatureSupported(signature: Signature, reportNode: FunctionTypeNode): boolean;
|
|
6626
|
+
/**
|
|
6627
|
+
* The `[T * N]` half of signature support, kept separate so that a refusal
|
|
6628
|
+
* can **stop** the function rather than merely be reported.
|
|
6629
|
+
*
|
|
6630
|
+
* `checkSignatureSupported` reports and compilation carries on — the right
|
|
6631
|
+
* shape for a feature gate, whose codegen path can still produce a module.
|
|
6632
|
+
* Not for this one: a value-form `[T * N]` parameter or return has no slot, so
|
|
6633
|
+
* continuing reaches `Signature#paramRefs` / `#resultRefs`, which call
|
|
6634
|
+
* `toRef`, which asserts for the value form by design. Measured before this
|
|
6635
|
+
* split: `export function f(a: [u32 * 4]): u32` and
|
|
6636
|
+
* `export function f(p: usize): [u32 * 4]` both crashed the compiler inside
|
|
6637
|
+
* `toRef` instead of reporting.
|
|
6638
|
+
*/
|
|
6639
|
+
private checkFixedArrayStorageInSignature;
|
|
6640
|
+
/**
|
|
6641
|
+
* Refuses a `[T * N]` that has no storage in the position it was written in.
|
|
6642
|
+
*
|
|
6643
|
+
* Landing 5a.5 made the memory model part of the Type, which splits the kind
|
|
6644
|
+
* into three: the **view** (`@unmanaged [T * N]`, one address — works
|
|
6645
|
+
* everywhere `@unmanaged T` works), the **heap** form (`@managed [T * N]`,
|
|
6646
|
+
* Landing 5c) and the **value** form (`[T * N]`, `u32[N]`, `@inline [T * N]`
|
|
6647
|
+
* — N inline elements, no address of its own).
|
|
6648
|
+
*
|
|
6649
|
+
* The value form exists and is laid out correctly: it is a record field's
|
|
6650
|
+
* type, `sizeof` counts N × sizeof(T), and Landing 1's fixtures assert all of
|
|
6651
|
+
* that. What it does not have is a **slot**. `toRef` asserts for it by design,
|
|
6652
|
+
* so every position that needs a WASM local, parameter or result must be
|
|
6653
|
+
* refused *before* that assert is reached — otherwise the compiler crashes
|
|
6654
|
+
* where the answer is a diagnostic. Landing 5b gives the form inline storage
|
|
6655
|
+
* (stack slot, copy at the ABI, sret) and these refusals come out.
|
|
6656
|
+
*
|
|
6657
|
+
* This mirrors `Program.checkInlineStructValue`, which refuses the same class
|
|
6658
|
+
* of position for the same reason (a value with no address where one is
|
|
6659
|
+
* needed). `position` names the site so the message says which case was hit.
|
|
6660
|
+
*/
|
|
6661
|
+
private checkFixedArrayStoragePosition;
|
|
6074
6662
|
/** Is `type` an `@inline struct`: a value carried as its fields, never as a
|
|
6075
6663
|
* pointer? */
|
|
6076
6664
|
/**
|
|
@@ -6125,6 +6713,23 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
6125
6713
|
* there is no address to pass. Anything else refuses by name rather than
|
|
6126
6714
|
* compiling a pointer.
|
|
6127
6715
|
*/
|
|
6716
|
+
/**
|
|
6717
|
+
* Expands a value-form `[T * N]` argument into one operand per element leaf.
|
|
6718
|
+
*
|
|
6719
|
+
* Two shapes reach here, and they differ in where the leaves come from:
|
|
6720
|
+
*
|
|
6721
|
+
* - **A value-form local** — push its SROA leaves. `pushSroaLeafOperands`
|
|
6722
|
+
* walks the map depth first through placeholders, which is exactly the
|
|
6723
|
+
* element-major order `paramRefs` declares.
|
|
6724
|
+
* - **An array literal** — compile each element into its own operand. A record
|
|
6725
|
+
* element is several leaves and no literal names them (`{x, y}` goes through
|
|
6726
|
+
* the class path and *allocates*), so it is refused by name, matching
|
|
6727
|
+
* `fillSroaArrayFromLiteral`.
|
|
6728
|
+
*
|
|
6729
|
+
* Anything else — a call returning an array, a conditional — would need the
|
|
6730
|
+
* value materialised somewhere, which is the return path, not this one.
|
|
6731
|
+
*/
|
|
6732
|
+
private expandSroaArrayArgument;
|
|
6128
6733
|
private expandSroaArgument;
|
|
6129
6734
|
/**
|
|
6130
6735
|
* The SROA local an expression names, or `null`.
|
|
@@ -6411,6 +7016,165 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
6411
7016
|
* has already reported why), and the caller has been told.
|
|
6412
7017
|
*/
|
|
6413
7018
|
emitSroaStores(type: Type, fieldLocals: Map<string, Local>, dest: ExpressionRef, baseOffset: number, stmts: ExpressionRef[]): void;
|
|
7019
|
+
/**
|
|
7020
|
+
* Whether `type` is a fixed array in its **value** form — N inline elements,
|
|
7021
|
+
* no address of its own — as opposed to the `@unmanaged` view (a pointer,
|
|
7022
|
+
* Landing 5a.5) or the `@managed` heap form (Landing 5c).
|
|
7023
|
+
*/
|
|
7024
|
+
isValueFormFixedArray(type: Type): boolean;
|
|
7025
|
+
/**
|
|
7026
|
+
* The largest `N` whose value-form array can be indexed with a **runtime**
|
|
7027
|
+
* index.
|
|
7028
|
+
*
|
|
7029
|
+
* A runtime index on SROA leaves has no address to scale, so the element is
|
|
7030
|
+
* selected with a `br_table` over one block per element. Past a handful of
|
|
7031
|
+
* blocks that dispatch costs more than the thing it replaces: the caller who
|
|
7032
|
+
* wants an arbitrary index over many elements wants a pointer, and
|
|
7033
|
+
* `@unmanaged [T * N]` gives them one with no block at all. Eight is the
|
|
7034
|
+
* boundary between the two. Landing 5d's spill strategy is what would lift it.
|
|
7035
|
+
*/
|
|
7036
|
+
private static readonly VALUE_ARRAY_MAX_RUNTIME_INDEX;
|
|
7037
|
+
/** Per-emission counter for the runtime-index block labels, so two accesses in
|
|
7038
|
+
* one function cannot collide (Binaryen requires unique block names). */
|
|
7039
|
+
private sroaSelectId;
|
|
7040
|
+
/**
|
|
7041
|
+
* Fills `into` with one entry per **element** of a value-form `[T * N]`.
|
|
7042
|
+
*
|
|
7043
|
+
* The same shape `fillSroaFieldLocals` gives a record, with the index where
|
|
7044
|
+
* the field name would be: the map is string-keyed and `"0"`, `"1"` are
|
|
7045
|
+
* ordinary keys, so no new container is needed — only a new way to enumerate
|
|
7046
|
+
* the entries.
|
|
7047
|
+
*
|
|
7048
|
+
* - A **scalar** element gets one WASM local, named `<path>$<index>`.
|
|
7049
|
+
* - A **record** element is several leaves, so it gets the placeholder local
|
|
7050
|
+
* (`index -1`) carrying a nested map — exactly what a nested `@inline`
|
|
7051
|
+
* field gets, and for the same reason: `arr[i]` on a record names a whole
|
|
7052
|
+
* sub-value that no single local can hold, while `arr[i].x` descends one
|
|
7053
|
+
* hop to a leaf.
|
|
7054
|
+
*
|
|
7055
|
+
* Returns `false` when an element was refused, having reported why.
|
|
7056
|
+
*/
|
|
7057
|
+
private fillSroaArrayLocals;
|
|
7058
|
+
/**
|
|
7059
|
+
* Compiles a value-form `[T * N]` local as SROA: one WASM local per element
|
|
7060
|
+
* leaf, no local for the array itself, no store for the zero case.
|
|
7061
|
+
*
|
|
7062
|
+
* Returns `true` when the declaration was handled here (the caller must not
|
|
7063
|
+
* fall through to the ordinary local path).
|
|
7064
|
+
*/
|
|
7065
|
+
private compileSroaValueArrayLocal;
|
|
7066
|
+
/**
|
|
7067
|
+
* Stores an array literal's elements into a value-form array's leaves.
|
|
7068
|
+
*
|
|
7069
|
+
* A scalar element is compiled straight into its leaf. A **record** element is
|
|
7070
|
+
* several leaves and a literal cannot name them one at a time, so it is
|
|
7071
|
+
* refused by name here rather than compiled: the object-literal spelling
|
|
7072
|
+
* (`{ x: 1.5, y: 2.5 }`) goes through the class path and *allocates* — measured,
|
|
7073
|
+
* `const p: P = { x: 1.5 }` emitted `P#constructor` plus setters and needed
|
|
7074
|
+
* `env.abort`, i.e. a heap record behind a pointer, which is not a value.
|
|
7075
|
+
* Initialising the elements field by field (`arr[0].x = 10.5`) is the working
|
|
7076
|
+
* route, and it is what the diagnostic says.
|
|
7077
|
+
*/
|
|
7078
|
+
private fillSroaArrayFromLiteral;
|
|
7079
|
+
/**
|
|
7080
|
+
* The local behind `name`, when that local is a value-form `[T * N]` — i.e. a
|
|
7081
|
+
* value stored as one WASM local per element leaf, with no slot of its own.
|
|
7082
|
+
*
|
|
7083
|
+
* Returns `null` for everything else, including the view form (which *is* an
|
|
7084
|
+
* address and goes through the ordinary path).
|
|
7085
|
+
*/
|
|
7086
|
+
private resolveSroaValueArray;
|
|
7087
|
+
/**
|
|
7088
|
+
* The compile-time value of an index expression, or `-1` when it is not a
|
|
7089
|
+
* non-negative integer literal.
|
|
7090
|
+
*
|
|
7091
|
+
* `-1` is the "not constant" answer rather than an error: a runtime index is a
|
|
7092
|
+
* legitimate access, it just takes the `br_table` path.
|
|
7093
|
+
*/
|
|
7094
|
+
private constantIndexValue;
|
|
7095
|
+
/**
|
|
7096
|
+
* Indexes a value-form `[T * N]` local, whose elements are separate WASM
|
|
7097
|
+
* locals.
|
|
7098
|
+
*
|
|
7099
|
+
* A **constant** index needs no dispatch at all: it names one leaf, and the
|
|
7100
|
+
* access is `local.get` / `local.set` on it. A **runtime** index has no address
|
|
7101
|
+
* to scale, so it is selected with a `br_table` over one block per element —
|
|
7102
|
+
* bounded by {@link VALUE_ARRAY_MAX_RUNTIME_INDEX}, past which the caller wants
|
|
7103
|
+
* a pointer view instead.
|
|
7104
|
+
*/
|
|
7105
|
+
private compileSroaValueArrayElementAccess;
|
|
7106
|
+
/**
|
|
7107
|
+
* Selects one element leaf of a value-form array by a runtime index.
|
|
7108
|
+
*
|
|
7109
|
+
* The shape is one `br_table` with a block per element, each block yielding
|
|
7110
|
+
* that element's leaf — the only way to choose between WASM locals at runtime,
|
|
7111
|
+
* since they are not addressable. An index outside `[0, N)` is the caller's
|
|
7112
|
+
* error, exactly as it is for `[T *]`: the extent is compile-time and there is
|
|
7113
|
+
* no length on the value stack to check against.
|
|
7114
|
+
*/
|
|
7115
|
+
private compileSroaValueArrayRuntimeIndex;
|
|
7116
|
+
/**
|
|
7117
|
+
* Reads `arr[i].field` where `arr` is a value-form array **of records** and `i`
|
|
7118
|
+
* is a runtime index. Returns `0` when the shape does not apply.
|
|
7119
|
+
*
|
|
7120
|
+
* A record element is several leaves per candidate, so a single-value
|
|
7121
|
+
* `br_table` cannot select one — but a *field* is one leaf per candidate, so
|
|
7122
|
+
* the selection is per leaf: one block per element, each yielding that
|
|
7123
|
+
* element's `<field>` leaf. Same block nesting as the scalar runtime index
|
|
7124
|
+
* (`compileSroaValueArrayRuntimeIndex`), one hop lower.
|
|
7125
|
+
*
|
|
7126
|
+
* This is the shape the collision solver writes by hand today —
|
|
7127
|
+
* `arr[i].x` with a runtime `i` over a run of records — which is why it is
|
|
7128
|
+
* worth the dispatch rather than only supporting a constant index.
|
|
7129
|
+
*/
|
|
7130
|
+
private compileSroaArrayLeafByRuntimeIndex;
|
|
7131
|
+
/**
|
|
7132
|
+
* Writes `arr[i].field = value` where `arr` is a value-form array of records
|
|
7133
|
+
* and `i` is a runtime index. Returns `0` when the shape does not apply.
|
|
7134
|
+
*
|
|
7135
|
+
* The mirror of {@link compileSroaArrayLeafByRuntimeIndex}: one block per
|
|
7136
|
+
* element, each storing into that element's `<field>` leaf. The value is
|
|
7137
|
+
* materialised into a temp first — one WASM node cannot be the parent of N
|
|
7138
|
+
* stores — which is the same reason the scalar runtime-index write does it.
|
|
7139
|
+
*/
|
|
7140
|
+
private compileSroaArrayLeafStoreByRuntimeIndex;
|
|
7141
|
+
/**
|
|
7142
|
+
* Emits the `br_table` that selects one of `leafIndices` by a runtime index.
|
|
7143
|
+
*
|
|
7144
|
+
* The only way to choose between WASM locals at runtime, since locals are not
|
|
7145
|
+
* addressable: one block per candidate, the body sitting **after** its block's
|
|
7146
|
+
* `end` (where a branch target lands), element 0 as the fall-through.
|
|
7147
|
+
*
|
|
7148
|
+
* One helper rather than four. After Landing 5b.1 four call sites emitted this
|
|
7149
|
+
* same nesting — scalar read, scalar write, record-field read, record-field
|
|
7150
|
+
* write — differing only in which leaf each block touched. Params and returns
|
|
7151
|
+
* would have added more, and a structural bug in one of them would have been
|
|
7152
|
+
* invisible in the other three.
|
|
7153
|
+
*
|
|
7154
|
+
* **A method, not a closure.** The self-hosted compiler refuses an arrow
|
|
7155
|
+
* function that captures a local without a declared type — `AS100: a captured
|
|
7156
|
+
* local without a declared type (closures lowering)` — so the four sites
|
|
7157
|
+
* cannot share a callback.
|
|
7158
|
+
*
|
|
7159
|
+
* `storeValueLocal` is `-1` for a read; for a store it names the temp holding
|
|
7160
|
+
* the value. A store's body cannot reuse the caller's expression tree: a WASM
|
|
7161
|
+
* node has one parent, so N stores cannot share one subtree. `resultType` is
|
|
7162
|
+
* `TypeRef.None` for a store, in which case the dispatch yields nothing.
|
|
7163
|
+
*/
|
|
7164
|
+
private compileLeafIndexSelect;
|
|
7165
|
+
/**
|
|
7166
|
+
* Returns a value-form `[T * N]` value as WASM multivalue results.
|
|
7167
|
+
*
|
|
7168
|
+
* One result per element leaf, element-major — the order `resultRefs` declares
|
|
7169
|
+
* and the caller's unpack indexes into. The leaves are read out of the value's
|
|
7170
|
+
* SROA locals; a fresh array literal goes through the same path, because the
|
|
7171
|
+
* literal binds to leaves before the return is compiled.
|
|
7172
|
+
*
|
|
7173
|
+
* Requires `Feature.MultiValue`, which `Resolver` turns on when it resolves
|
|
7174
|
+
* this return type (`enableMultiValueOnce`), so a module that returns one of
|
|
7175
|
+
* these always has the feature and a module that does not never does.
|
|
7176
|
+
*/
|
|
7177
|
+
private compileMultivalueReturnStatement;
|
|
6414
7178
|
private compileSroaLocal;
|
|
6415
7179
|
/**
|
|
6416
7180
|
* The instance fields of an `@inline struct`, in declaration order, or `null`
|
|
@@ -8855,7 +9619,26 @@ declare module "types:tensionscript/src/ast" {
|
|
|
8855
9619
|
ExportMember = 67,
|
|
8856
9620
|
SwitchCase = 68,
|
|
8857
9621
|
IndexSignature = 69,
|
|
8858
|
-
Comment = 70
|
|
9622
|
+
Comment = 70,
|
|
9623
|
+
/**
|
|
9624
|
+
* `[T *]` — a pointer to T with unknown length.
|
|
9625
|
+
*
|
|
9626
|
+
* Appended at the end rather than beside {@link FixedArrayType}. `NodeKind`
|
|
9627
|
+
* is a `const enum` with implicit numbering, so an insert would renumber every
|
|
9628
|
+
* node kind after it; the compiler is self-hosted, so a partial rebuild could
|
|
9629
|
+
* then disagree with `dist/` about what `NodeKind.Comment` means -- silently.
|
|
9630
|
+
* The position carries no meaning.
|
|
9631
|
+
*/
|
|
9632
|
+
UnmanagedArrayType = 71,
|
|
9633
|
+
/**
|
|
9634
|
+
* `@unmanaged @dynamic [T * n]` — a header-prefixed array whose length is a
|
|
9635
|
+
* runtime value read from the buffer.
|
|
9636
|
+
*
|
|
9637
|
+
* Appended for the same reason {@link UnmanagedArrayType} was: this is an
|
|
9638
|
+
* implicit-numbering `const enum`, so an insert would renumber every node kind
|
|
9639
|
+
* after it.
|
|
9640
|
+
*/
|
|
9641
|
+
DynamicArrayType = 72
|
|
8859
9642
|
}
|
|
8860
9643
|
/** Base class of all nodes. */
|
|
8861
9644
|
export abstract class Node {
|
|
@@ -8873,6 +9656,8 @@ declare module "types:tensionscript/src/ast" {
|
|
|
8873
9656
|
static createFunctionType(parameters: ParameterNode[], returnType: TypeNode, explicitThisType: NamedTypeNode | null, isNullable: boolean, range: Range): FunctionTypeNode;
|
|
8874
9657
|
static createTupleType(elements: TypeNode[], elementNames: (IdentifierExpression | null)[] | null, isNullable: boolean, range: Range): TupleTypeNode;
|
|
8875
9658
|
static createFixedArrayType(elementType: TypeNode, length: number, range: Range): FixedArrayTypeNode;
|
|
9659
|
+
static createUnmanagedArrayType(elementType: TypeNode, range: Range): UnmanagedArrayTypeNode;
|
|
9660
|
+
static createDynamicArrayType(elementType: TypeNode, lengthName: IdentifierExpression, memoryModel: MemoryModel, range: Range): DynamicArrayTypeNode;
|
|
8876
9661
|
static createOmittedType(range: Range): NamedTypeNode;
|
|
8877
9662
|
static createTypeParameter(name: IdentifierExpression, extendsType: NamedTypeNode | null, defaultType: NamedTypeNode | null, range: Range): TypeParameterNode;
|
|
8878
9663
|
static createParameter(parameterKind: ParameterKind, name: IdentifierExpression, type: TypeNode, initializer: Expression | null, range: Range): ParameterNode;
|
|
@@ -9112,6 +9897,56 @@ declare module "types:tensionscript/src/ast" {
|
|
|
9112
9897
|
/** Source range. */
|
|
9113
9898
|
range: Range);
|
|
9114
9899
|
}
|
|
9900
|
+
/**
|
|
9901
|
+
* Represents an unmanaged array type, `[T *]` — a pointer to `T` with no length.
|
|
9902
|
+
*
|
|
9903
|
+
* The difference from {@link FixedArrayTypeNode} is the missing `length`, and it
|
|
9904
|
+
* is the whole difference: a fixed array *contains* its elements, so it has an
|
|
9905
|
+
* extent the layout can size; this one *addresses* them, so its own size is the
|
|
9906
|
+
* pointer's. That is why `[T *]` binds as one `i32` slot where `T[N]` has no
|
|
9907
|
+
* reference representation at all (`Type#toRef` asserts on a fixed array).
|
|
9908
|
+
*
|
|
9909
|
+
* Not a reference: the collector owns nothing here, the address is the caller's.
|
|
9910
|
+
* Not a value either: there is nothing to inline. `changetype` and a parameter
|
|
9911
|
+
* are the two ways one comes into being.
|
|
9912
|
+
*/
|
|
9913
|
+
export class UnmanagedArrayTypeNode extends TypeNode {
|
|
9914
|
+
/** Element type. */
|
|
9915
|
+
elementType: TypeNode;
|
|
9916
|
+
constructor(
|
|
9917
|
+
/** Element type. */
|
|
9918
|
+
elementType: TypeNode,
|
|
9919
|
+
/** Source range. */
|
|
9920
|
+
range: Range);
|
|
9921
|
+
}
|
|
9922
|
+
/**
|
|
9923
|
+
* Represents a dynamic array type, `@unmanaged @dynamic [T * n]`.
|
|
9924
|
+
*
|
|
9925
|
+
* The `n` is **spelling, not an expression**: the parser cannot evaluate it (it
|
|
9926
|
+
* has no symbol table), so it is carried as a name and the length is read at
|
|
9927
|
+
* runtime from the buffer header. That is why the form is admissible at parse
|
|
9928
|
+
* time without knowing whether `n` is a constant — resolution decides that, and
|
|
9929
|
+
* `resolveDynamicArrayType` refuses a name that turns out to be compile-time.
|
|
9930
|
+
*
|
|
9931
|
+
* One i32 slot at the ABI, holding a pointer to `[u32 length][pad][T data[n]]`.
|
|
9932
|
+
*/
|
|
9933
|
+
export class DynamicArrayTypeNode extends TypeNode {
|
|
9934
|
+
/** Element type. */
|
|
9935
|
+
elementType: TypeNode;
|
|
9936
|
+
/** The length's name. Bound as a read-only local where a function scope exists. */
|
|
9937
|
+
lengthName: IdentifierExpression;
|
|
9938
|
+
/** Storage model of the buffer. `Unmanaged` for now; `Managed` is Landing 4d. */
|
|
9939
|
+
dynamicMemoryModel: MemoryModel;
|
|
9940
|
+
constructor(
|
|
9941
|
+
/** Element type. */
|
|
9942
|
+
elementType: TypeNode,
|
|
9943
|
+
/** The length's name. Bound as a read-only local where a function scope exists. */
|
|
9944
|
+
lengthName: IdentifierExpression,
|
|
9945
|
+
/** Storage model of the buffer. `Unmanaged` for now; `Managed` is Landing 4d. */
|
|
9946
|
+
dynamicMemoryModel: MemoryModel,
|
|
9947
|
+
/** Source range. */
|
|
9948
|
+
range: Range);
|
|
9949
|
+
}
|
|
9115
9950
|
/** Represents a type parameter. */
|
|
9116
9951
|
export class TypeParameterNode extends Node {
|
|
9117
9952
|
/** Identifier reference. */
|