test: group examples into per-category folders
Move examples/*.sx and their expected/ snapshots into per-category subfolders (examples/<category>/...). Folder = leading filename token, with ffi-objc/ffi-jni kept whole; filenames are unchanged. The corpus runner and LSP sweep now discover each category's expected/ dir, while issues/ stays flat. Example 1058's repo-root-relative companion import is made file-relative. Path strings embedded in 164 snapshots were regenerated (path-only changes). Test-layout docs in CLAUDE.md updated.
This commit is contained in:
35
examples/packs/0500-packs-varargs.sx
Normal file
35
examples/packs/0500-packs-varargs.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
sum :: (..args: []i32) -> i32 {
|
||||
result := 0;
|
||||
for args (it) {
|
||||
result = result + it;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
print_all :: (..args: []i32) {
|
||||
for args (it) {
|
||||
out(int_to_string(it));
|
||||
out(" ");
|
||||
}
|
||||
out("\n");
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
out(int_to_string(sum(10, 20, 30)));
|
||||
out("\n");
|
||||
|
||||
print_all(1, 2, 3, 4, 5);
|
||||
|
||||
arr : [3]i32 = .[10, 20, 30];
|
||||
out(int_to_string(sum(..arr)));
|
||||
out("\n");
|
||||
|
||||
for arr (it) {
|
||||
out(int_to_string(it));
|
||||
out(" ");
|
||||
}
|
||||
out("\n");
|
||||
0
|
||||
}
|
||||
47
examples/packs/0501-packs-any-varargs.sx
Normal file
47
examples/packs/0501-packs-any-varargs.sx
Normal file
@@ -0,0 +1,47 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
Point :: struct {
|
||||
x: i32;
|
||||
y: i32;
|
||||
}
|
||||
|
||||
// Print all arguments — accepts any type, dispatches via type-switch
|
||||
print_any :: (..args: []Any) {
|
||||
for args (it) {
|
||||
type := type_of(it);
|
||||
if type == {
|
||||
case int: out(int_to_string(cast(i32) it));
|
||||
case string: out(cast(string) it);
|
||||
case bool: out(bool_to_string(cast(bool) it));
|
||||
case float: out(float_to_string(cast(f64) it));
|
||||
case Point: {
|
||||
p := cast(Point) it;
|
||||
out("(");
|
||||
out(int_to_string(p.x));
|
||||
out(",");
|
||||
out(int_to_string(p.y));
|
||||
out(")");
|
||||
}
|
||||
}
|
||||
out(" ");
|
||||
}
|
||||
out("\n");
|
||||
}
|
||||
|
||||
count :: (..args: []Any) -> i32 {
|
||||
args.len
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print_any(42, "hello", true, 3.14);
|
||||
|
||||
// Test with struct
|
||||
p := Point.{ x=10, y=20 };
|
||||
print_any("point:", p, 99);
|
||||
|
||||
// Test count
|
||||
out(int_to_string(count(1, 2, 3)));
|
||||
out("\n");
|
||||
|
||||
0
|
||||
}
|
||||
22
examples/packs/0502-packs-pack-parse.sx
Normal file
22
examples/packs/0502-packs-pack-parse.sx
Normal file
@@ -0,0 +1,22 @@
|
||||
// Variadic heterogeneous type packs — `..$args` — parse smoke.
|
||||
//
|
||||
// First positive slice of the pack feature: the parser accepts
|
||||
// `..$args` (variadic marker + comptime sigil + name) as a
|
||||
// parameter declaration. No semantic effect yet — the function
|
||||
// is declared but never instantiated; main exists so the example
|
||||
// has runnable output.
|
||||
//
|
||||
// Next slices: type-system representation of the pack, impl
|
||||
// matching for `Closure(..$args) -> $R`, runtime indexing
|
||||
// (`args[$i]`), and the `#insert build_x($args, ...)` pattern.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
foo :: (..$args) -> i64 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("pack parse ok\n");
|
||||
return 0;
|
||||
}
|
||||
23
examples/packs/0503-packs-pack-type-rep.sx
Normal file
23
examples/packs/0503-packs-pack-type-rep.sx
Normal file
@@ -0,0 +1,23 @@
|
||||
// Variadic heterogeneous type packs — `..$args` — type-system
|
||||
// representation lock-in.
|
||||
//
|
||||
// Step 1c slice for the pack feature (see
|
||||
// ~/.claude/plans/lets-see-options-for-merry-dijkstra.md). Exercises
|
||||
// the parser's acceptance of `..$args` inside a `Closure(...)` type
|
||||
// expression — the pack-shape spelling used by impl headers like
|
||||
// `impl Into(Block) for Closure(..$args) -> $R`.
|
||||
//
|
||||
// Today's parser only accepts `..$args` in fn parameter lists (1b);
|
||||
// the same syntax inside a `Closure(...)` type expression hits
|
||||
// `expected type name` at the `..` token. This file pins that
|
||||
// rejection. The next commit teaches `parseTypeExpr`'s `Closure(...)`
|
||||
// arm + the type-table representation to carry the pack.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
takes_cb :: (cb: Closure(..$args) -> $R) -> void { }
|
||||
|
||||
main :: () -> i32 {
|
||||
print("pack type rep ok\n");
|
||||
return 0;
|
||||
}
|
||||
46
examples/packs/0504-packs-pack-impl-match.sx
Normal file
46
examples/packs/0504-packs-pack-impl-match.sx
Normal file
@@ -0,0 +1,46 @@
|
||||
// Variadic heterogeneous type packs — `..$args` — impl matching
|
||||
// lock-in.
|
||||
//
|
||||
// Step 1d slice for the pack feature (see
|
||||
// ~/.claude/plans/lets-see-options-for-merry-dijkstra.md). Pins
|
||||
// today's concrete-only impl-matching behaviour: a user-declared
|
||||
// `impl Into(Block) for Closure(..$args) -> $R` does NOT match
|
||||
// any concrete closure source type. The xx cast site hits the
|
||||
// existing "no `Into(Block) for <src>` impl" diagnostic even
|
||||
// though the pack impl is reachable.
|
||||
//
|
||||
// Next commit (1d.B) teaches `tryUserConversion` /
|
||||
// `registerParamImpl` to walk a second `param_impl_pack_map`
|
||||
// when the concrete-key miss happens. Pack impls bind their
|
||||
// `$args` and `$R` to the concrete source closure's tail types
|
||||
// and return; monomorphisation proceeds against those bindings.
|
||||
//
|
||||
// The `Closure(i32, bool) -> bool` shape is not covered by
|
||||
// stdlib's hand-rolled impls (only `Closure() -> void` and
|
||||
// `Closure(bool) -> void`) and not covered by 96-block-multi-arg's
|
||||
// `Closure(i32, *void) -> void` impl, so the pack impl is the
|
||||
// only candidate.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/ffi/objc_block.sx";
|
||||
|
||||
impl Into(Block) for Closure(..$args) -> $R {
|
||||
convert :: (self: Closure(..$args) -> $R) -> Block {
|
||||
.{
|
||||
isa = @_NSConcreteStackBlock,
|
||||
flags = 0,
|
||||
reserved = 0,
|
||||
invoke = null,
|
||||
descriptor = xx @__sx_block_descriptor,
|
||||
sx_env = self.env,
|
||||
sx_fn = self.fn_ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
cl := (a: i32, b: bool) => true;
|
||||
b : *Block = xx cl;
|
||||
print("pack impl match ok\n");
|
||||
return 0;
|
||||
}
|
||||
32
examples/packs/0505-packs-pack-typed-index.sx
Normal file
32
examples/packs/0505-packs-pack-typed-index.sx
Normal file
@@ -0,0 +1,32 @@
|
||||
// Variadic heterogeneous type packs — step 2: typed pack indexing.
|
||||
//
|
||||
// `args[$i]` (with `$i` a comptime-known integer) inside a pack-fn
|
||||
// body should resolve to the i-th call-site argument with its
|
||||
// CONCRETE type, not the boxed `Any` that today's `[]Any` slice
|
||||
// path yields. Without typed access, downstream operations on the
|
||||
// element (field access, typed coercion, passing to a typed slot)
|
||||
// either fail with "field 'X' not found on type 'Any'" or silently
|
||||
// box/unbox through Any.
|
||||
//
|
||||
// This file pins today's failure: `args[0].x` on a struct-typed
|
||||
// call arg trips "field 'x' not found on type 'Any'" because the
|
||||
// AST-level type inference for `args[0]` returns Any.
|
||||
//
|
||||
// Next commit teaches `lowerIndexExpr` to detect a pack-name base
|
||||
// with a comptime-int-literal index and substitute the i-th
|
||||
// call-site arg's lowered value directly — propagating the call
|
||||
// arg's real type through field access, typed assignments, and
|
||||
// further indexing.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Point :: struct { x: i64; y: i64; }
|
||||
|
||||
get_x :: (..$args) -> i64 => args[0].x;
|
||||
|
||||
main :: () -> i32 {
|
||||
p := Point.{ x = 7, y = 9 };
|
||||
n := get_x(p);
|
||||
print("{}\n", n);
|
||||
return 0;
|
||||
}
|
||||
39
examples/packs/0506-packs-pack-if-return.sx
Normal file
39
examples/packs/0506-packs-pack-if-return.sx
Normal file
@@ -0,0 +1,39 @@
|
||||
// Variadic heterogeneous type packs — control-flow follow-up to
|
||||
// issue-0045 fix (commit 9e78790).
|
||||
//
|
||||
// issue-0045's fix routes inline-comptime-body `return X;` into a
|
||||
// result slot so the caller's basic block isn't terminated
|
||||
// mid-flight. But the fix sets `block_terminated = true` after
|
||||
// the inline return — which leaks PAST the enclosing `if`'s
|
||||
// merge block. When the body shape is
|
||||
// if cond { return X; }
|
||||
// return Y;
|
||||
// only the then-branch's `return X;` runs; `block_terminated`
|
||||
// stays true in the merge block, so `lowerBlockValue`'s loop
|
||||
// exits before the trailing `return Y;` lowers. The trailing
|
||||
// return never stores into the slot — for the false-condition
|
||||
// path the load reads uninitialised stack memory.
|
||||
//
|
||||
// Pack-fn `..$args` is the shortest repro because `args.len`
|
||||
// gives a comptime-feeling test for the condition. The bug is
|
||||
// actually shape-agnostic — any comptime body with `if cond
|
||||
// { return X; }; return Y;` regresses the same way.
|
||||
//
|
||||
// `maybe()` with zero call-args takes the false branch and
|
||||
// should fall through to `return -1;`. Today it loads garbage
|
||||
// from the uninitialised slot.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
maybe :: (..$args) -> i64 {
|
||||
if args.len > 0 {
|
||||
return 42;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", maybe()); // expect -1
|
||||
print("{}\n", maybe(99)); // expect 42
|
||||
return 0;
|
||||
}
|
||||
30
examples/packs/0507-packs-pack-mono-dedup.sx
Normal file
30
examples/packs/0507-packs-pack-mono-dedup.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Variadic heterogeneous type packs — step 2b: per-call-shape
|
||||
// monomorphisation. Each unique call signature gets ONE mono fn;
|
||||
// repeat calls with the same signature share it. The runtime output
|
||||
// confirms correct semantics; the IR (visible via `sx ir`) shows
|
||||
// the distinct mono symbols:
|
||||
//
|
||||
// call @count__pack(ctx)
|
||||
// call @count__pack_i64(ctx, 1)
|
||||
// call @count__pack_i64(ctx, 2) ← shares with the 1-arg i64 call
|
||||
// call @count__pack_i64_i64_i64(ctx, 1, 2, 3)
|
||||
// call @count__pack_string_bool(ctx, ..)
|
||||
//
|
||||
// Before step 2b, each call inlined a fresh copy of the body into
|
||||
// main's basic block — no shared symbols, IR size grew linearly in
|
||||
// call sites. After 2b, distinct shapes get distinct functions,
|
||||
// repeats share, IR scales with unique shapes.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
count :: (..$args) -> i64 => args.len;
|
||||
|
||||
main :: () -> i32 {
|
||||
a := count();
|
||||
b := count(1);
|
||||
c := count(2);
|
||||
d := count(1, 2, 3);
|
||||
e := count("x", true);
|
||||
print("{} {} {} {} {}\n", a, b, c, d, e);
|
||||
return 0;
|
||||
}
|
||||
23
examples/packs/0508-packs-pack-generic-ret.sx
Normal file
23
examples/packs/0508-packs-pack-generic-ret.sx
Normal file
@@ -0,0 +1,23 @@
|
||||
// Variadic heterogeneous type packs — follow-up #2 (generic $R
|
||||
// return type).
|
||||
//
|
||||
// A pack-fn's return type can be a generic name (`$R`) — bound at
|
||||
// the call site to match the body's natural type or the caller's
|
||||
// target. Today's `monomorphizePackFn` calls `resolveReturnType`
|
||||
// which treats `$R` as an opaque struct, so the mono's signature
|
||||
// gets a wrong ret_ty and the value is silently zero / garbage.
|
||||
//
|
||||
// `first(42)` should return 42; the lock-in pins today's `0`.
|
||||
// Next commit infers the ret type from the body's tail expression
|
||||
// (or first `return X;`) and rebuilds the mono signature.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
first :: (..$args) -> $R => args[0];
|
||||
|
||||
main :: () -> i32 {
|
||||
a : i64 = first(42);
|
||||
b : i64 = first(99);
|
||||
print("{} {}\n", a, b);
|
||||
return 0;
|
||||
}
|
||||
25
examples/packs/0509-packs-pack-hetero-ret.sx
Normal file
25
examples/packs/0509-packs-pack-hetero-ret.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// Variadic heterogeneous type packs — generic `$R` with
|
||||
// heterogeneous element pick. `foo(..$args) -> $R => args[2]`
|
||||
// returns the THIRD arg's value; the ret type is inferred from
|
||||
// the third arg's concrete type per call shape.
|
||||
//
|
||||
// foo(42, 3.2, "hello") → returns "hello" (string).
|
||||
//
|
||||
// Exercises:
|
||||
// - generic `$R` inference for non-zeroth pack indices.
|
||||
// - heterogeneous mixed-type call args binding into distinct
|
||||
// types per position (i64, f64, string).
|
||||
// - `pack_arg_types` type-only binding for `inferExprType`
|
||||
// pre-mono-scope: without it, the synthesized-ident detour
|
||||
// loses the type because the scope isn't set up yet during
|
||||
// return-type inference.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
foo :: (..$args) -> $R => args[2];
|
||||
|
||||
main :: () -> i32 {
|
||||
a := foo(42, 3.2, "hello");
|
||||
print("{}\n", a);
|
||||
return 0;
|
||||
}
|
||||
20
examples/packs/0510-packs-pack-index-oob.sx
Normal file
20
examples/packs/0510-packs-pack-index-oob.sx
Normal file
@@ -0,0 +1,20 @@
|
||||
// Variadic heterogeneous type packs — out-of-bounds pack index
|
||||
// is a compile-time error.
|
||||
//
|
||||
// `foo(..$args) -> $R => args[2]` accesses the third pack
|
||||
// element. When called with fewer than 3 args, the literal index
|
||||
// 2 is out of bounds for the pack's actual arity. The compiler
|
||||
// detects this in `diagPackIndexOOB` and emits a focused
|
||||
// diagnostic at the index span — pre-fix, the fall-through hit
|
||||
// the standard slice-indexing path and produced "unresolved
|
||||
// 'args'" which buried the real cause.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
foo :: (..$args) -> $R => args[2];
|
||||
|
||||
main :: () -> i32 {
|
||||
n : i64 = foo(99);
|
||||
print("{}\n", n);
|
||||
return 0;
|
||||
}
|
||||
23
examples/packs/0511-packs-pack-bare-args.sx
Normal file
23
examples/packs/0511-packs-pack-bare-args.sx
Normal file
@@ -0,0 +1,23 @@
|
||||
// Step 2.7 — forwarding a variadic to a `[]Any` helper.
|
||||
//
|
||||
// A comptime pack `..$args` is comptime-only (Decision 1): `args` bare is NOT a
|
||||
// runtime value, so `log_count(args)` on a pack is an error (see the
|
||||
// pack-as-value tests). To forward a variadic to a runtime `[]Any` helper,
|
||||
// declare it as the *slice* variadic `..args: []Any` — then `args` is a real
|
||||
// `[]Any` slice that passes straight through.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
log_count :: (items: []Any) -> i64 {
|
||||
return items.len;
|
||||
}
|
||||
|
||||
// Slice variadic: `args` is a runtime []Any, forwarded directly.
|
||||
forward :: (..args: []Any) -> i64 {
|
||||
return log_count(args);
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", forward(1, "hi", 2.5));
|
||||
return 0;
|
||||
}
|
||||
29
examples/packs/0512-packs-pack-runtime-index.sx
Normal file
29
examples/packs/0512-packs-pack-runtime-index.sx
Normal file
@@ -0,0 +1,29 @@
|
||||
// Variadic heterogeneous type packs — Step 2.6: indexing a pack with a
|
||||
// RUNTIME index is a compile error.
|
||||
//
|
||||
// Per locked Decision 1, a pack is comptime-only and has NO runtime
|
||||
// representation — so `args[i]` is valid only when `i` is a compile-time
|
||||
// constant (a literal, or an `inline for` cursor). A runtime index (here a
|
||||
// `while`-loop counter) must produce a clear diagnostic, not the confusing
|
||||
// "unresolved 'args'" the slice-index fall-through used to give. To walk a
|
||||
// pack, use `inline for 0..args.len (i) { ... }`, which unrolls so each
|
||||
// `args[i]` is a comptime index.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
count_anys :: (..$args) -> i64 {
|
||||
total : i64 = 0;
|
||||
i : i64 = 0;
|
||||
while i < args.len {
|
||||
x : Any = args[i]; // ERROR: runtime index into a comptime-only pack
|
||||
_ = x;
|
||||
total = total + 1;
|
||||
i = i + 1;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", count_anys(10, "hi", 2.5, true));
|
||||
return 0;
|
||||
}
|
||||
29
examples/packs/0513-packs-pack-mixed-comptime.sx
Normal file
29
examples/packs/0513-packs-pack-mixed-comptime.sx
Normal file
@@ -0,0 +1,29 @@
|
||||
// Variadic heterogeneous type packs — follow-up #1 (mixed
|
||||
// `$comptime + ..$args` pack-fn signatures).
|
||||
//
|
||||
// Today's `isPackFn` rejects pack-fns that mix any other
|
||||
// comptime param with the trailing pack — they fall through
|
||||
// to the inline `lowerComptimeCall` path. The inline path
|
||||
// doesn't bind non-string comptime params as runtime locals,
|
||||
// so a body that uses both `$tag` (i32) AND `..$args` fails
|
||||
// at the bare-name lookup of `tag`.
|
||||
//
|
||||
// Next commit relaxes `isPackFn` to accept "exactly one
|
||||
// trailing pack + any number of non-pack comptime params" and
|
||||
// `monomorphizePackFn` folds the comptime VALUES into the
|
||||
// mangled name (so distinct calls of `tagged(7, ...)` vs
|
||||
// `tagged(9, ...)` get distinct monos), then binds the
|
||||
// comptime values as both comptime substitutions and runtime
|
||||
// locals (for body code that references them by name).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
tagged :: ($tag: i32, ..$args) -> i64 {
|
||||
return tag * 100 + args.len;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", tagged(7, 1, 2, 3)); // 7*100 + 3 = 703
|
||||
print("{}\n", tagged(9)); // 9*100 + 0 = 900
|
||||
return 0;
|
||||
}
|
||||
39
examples/packs/0514-packs-pack-type-position.sx
Normal file
39
examples/packs/0514-packs-pack-type-position.sx
Normal file
@@ -0,0 +1,39 @@
|
||||
// Variadic heterogeneous type packs — step 3: `$args[$i]` in
|
||||
// type positions.
|
||||
//
|
||||
// `$args[$i]` resolves to the i-th element type of the active
|
||||
// pack binding wherever a type expression is expected:
|
||||
// - return type: `-> $args[0]`
|
||||
// - local var annotation: `x : $args[1] = ...`
|
||||
// - (later: param types, fn-pointer types, struct field types)
|
||||
//
|
||||
// Today's parser hits "expected '{'" at the `$args[0]` token in
|
||||
// the return type position because the `$<ident>` arm only
|
||||
// accepts plain generic names; `[<int>]` after the name isn't
|
||||
// recognised. This file pins that rejection. Next commit teaches
|
||||
// the parser to accept `$<pack>[<int>]` and adds a new
|
||||
// `PackIndexTypeExpr` AST node; `resolveTypeWithBindings`
|
||||
// consults the active `pack_arg_types` map.
|
||||
//
|
||||
// The body intentionally exercises TWO positions per mono — the
|
||||
// return type AND a local annotation — so the parser change has
|
||||
// to cover more than just the trailing return arrow.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
swap_take :: (..$args) -> $args[0] {
|
||||
second : $args[1] = args[1];
|
||||
// `second` is bound and typed — confirms the local-annotation
|
||||
// path also resolves. The body returns args[0] (statically
|
||||
// typed as $args[0]).
|
||||
return args[0];
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// Heterogeneous call shapes — each picks a different concrete
|
||||
// pair, gets its own mono.
|
||||
a : i64 = swap_take(42, "ignored"); // $args[0] = i64, $args[1] = string
|
||||
b : string = swap_take("first", 99); // $args[0] = string, $args[1] = i64
|
||||
print("{} {}\n", a, b);
|
||||
return 0;
|
||||
}
|
||||
21
examples/packs/0515-packs-pack-type-position-three.sx
Normal file
21
examples/packs/0515-packs-pack-type-position-three.sx
Normal file
@@ -0,0 +1,21 @@
|
||||
// Variadic heterogeneous type packs — step 3 complex smoke.
|
||||
//
|
||||
// Three-element pack with `$args[2]` (the third element) used in
|
||||
// the return-type position. Confirms:
|
||||
// - Multi-arg packs index past the zeroth element correctly.
|
||||
// - Three distinct call shapes get three distinct monos.
|
||||
// - The return-type slot is correctly substituted per-mono so
|
||||
// the inferred caller type matches what the body actually
|
||||
// returns (string / i64 / bool here).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
third :: (..$args) -> $args[2] => args[2];
|
||||
|
||||
main :: () -> i32 {
|
||||
a := third(1, 2, "third"); // (i64, i64, string) → "third"
|
||||
b := third(true, 3.14, 99); // (bool, f64, i64) → 99
|
||||
c := third("a", "b", false); // (string, string, bool) → false
|
||||
print("{} {} {}\n", a, b, c);
|
||||
return 0;
|
||||
}
|
||||
30
examples/packs/0516-packs-pack-type-fnptr.sx
Normal file
30
examples/packs/0516-packs-pack-type-fnptr.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Variadic heterogeneous type packs — step 3: `$args[$i]` in
|
||||
// fn-pointer type literals.
|
||||
//
|
||||
// `(*void, $args[0]) -> $args[1]` is the shape step 5's generic
|
||||
// `Into(Block) for Closure(..$args) -> $R` body needs for its
|
||||
// trampoline:
|
||||
// typed_fn : (*void, $args[0], $args[1], ...) -> $R =
|
||||
// xx block_self.sx_fn;
|
||||
// — the trampoline's invoke slot is typed against the pack
|
||||
// positions to bridge the Block ABI to the sx closure.
|
||||
//
|
||||
// This test exercises the same plumbing on a smaller scale: a
|
||||
// local var with a fn-pointer type whose param + return types
|
||||
// both interpolate through `$args[$i]`.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
// Two concrete handlers that match the per-mono fn-pointer shape.
|
||||
double_i64 :: (env: *void, x: i64) -> i64 => x * 2;
|
||||
|
||||
via_fnptr :: (..$args) -> $args[1] {
|
||||
fp : (*void, $args[0]) -> $args[1] = double_i64;
|
||||
return fp(null, args[0]);
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
n := via_fnptr(7, 0); // (i64, i64) → fp : (*void, i64) -> i64
|
||||
print("{}\n", n);
|
||||
return 0;
|
||||
}
|
||||
62
examples/packs/0517-packs-pack-reflection-intrinsics.sx
Normal file
62
examples/packs/0517-packs-pack-reflection-intrinsics.sx
Normal file
@@ -0,0 +1,62 @@
|
||||
// Variadic heterogeneous type packs — step 3: type-reflection
|
||||
// intrinsics.
|
||||
//
|
||||
// Three comptime helpers used by pack-fn bodies to branch on
|
||||
// type identity / protocol membership:
|
||||
//
|
||||
// type_name(T) -> string // display name of T
|
||||
// type_eq(T1, T2) -> bool // structural TypeId equality
|
||||
// has_impl(P, T) -> bool // T has a reachable impl for P
|
||||
//
|
||||
// All three fold to compile-time constants and are accepted by
|
||||
// `tryConstBoolCondition`, so `inline if type_eq(...)` /
|
||||
// `inline if has_impl(...)` collapse to a single branch at lower
|
||||
// time — no runtime cost.
|
||||
//
|
||||
// `has_impl`'s protocol arg accepts both shapes:
|
||||
// - plain protocol name: `has_impl(Allocator, CAllocator)`.
|
||||
// - parameterised call: `has_impl(Wrap(i64), i32)` — the args
|
||||
// match the impl's protocol type-args exactly.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/mem.sx";
|
||||
|
||||
// User-defined parameterised protocol + an impl, so has_impl can
|
||||
// confirm parameterised matching works with a known-true case.
|
||||
Wrap :: protocol(Target: Type) {
|
||||
wrap :: (self: *Self) -> Target;
|
||||
}
|
||||
|
||||
impl Wrap(i64) for i32 {
|
||||
wrap :: (self: i32) -> i64 => xx self;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// type_name — display names.
|
||||
print("{} {} {}\n", type_name(i64), type_name(string), type_name(bool));
|
||||
|
||||
// type_eq — structural equality on TypeIds.
|
||||
print("{} {} {} {}\n",
|
||||
type_eq(i64, i64),
|
||||
type_eq(i64, string),
|
||||
type_eq(*i64, *i64),
|
||||
type_eq(*i64, *i32));
|
||||
|
||||
// inline-if folds type_eq at lower time.
|
||||
inline if type_eq(i64, i64) {
|
||||
print("inline-if folded: same\n");
|
||||
} else {
|
||||
print("inline-if folded: different\n");
|
||||
}
|
||||
|
||||
// has_impl — plain protocol (Allocator is unary).
|
||||
print("Allocator/CAllocator: {}\n", has_impl(Allocator, CAllocator));
|
||||
print("Allocator/i64: {}\n", has_impl(Allocator, i64));
|
||||
|
||||
// has_impl — parameterised protocol (Wrap takes a Target type arg).
|
||||
print("Wrap(i64)/i32: {}\n", has_impl(Wrap(i64), i32));
|
||||
print("Wrap(i64)/bool: {}\n", has_impl(Wrap(i64), bool));
|
||||
print("Wrap(bool)/i32: {}\n", has_impl(Wrap(bool), i32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
44
examples/packs/0518-packs-pack-value-dispatch.sx
Normal file
44
examples/packs/0518-packs-pack-value-dispatch.sx
Normal file
@@ -0,0 +1,44 @@
|
||||
// Variadic heterogeneous type packs — step 4 source-construction
|
||||
// path: `$args[$i]` in expression position yields a comptime Type
|
||||
// VALUE (`Value.type_tag(TypeId)` in the interp). Lets builders +
|
||||
// pack-fn bodies dispatch on the i-th pack type at compile time.
|
||||
//
|
||||
// Two usage shapes covered here:
|
||||
//
|
||||
// 1. `type_name($args[0])` — the value-form Type goes through the
|
||||
// reflection intrinsic, picking up the per-mono concrete type.
|
||||
//
|
||||
// 2. `inline if type_eq($args[0], i64) { ... }` — compile-time
|
||||
// branch over the pack element's type. The fold via
|
||||
// `tryConstBoolCondition` reads $args[0] via `resolveTypeArg`,
|
||||
// which the step-4 work taught to walk `pack_arg_types`.
|
||||
//
|
||||
// Lowering: `$args[$i]` in expression position emits a
|
||||
// `const_type(arg_types[i])` IR op. The interp materialises a
|
||||
// `Value.type_tag(TypeId)`. LLVM emit bails (Type is comptime-only).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
show :: (..$args) -> string => type_name($args[0]);
|
||||
|
||||
describe :: (..$args) -> string {
|
||||
inline if type_eq($args[0], i64) { return "got i64"; }
|
||||
inline if type_eq($args[0], string) { return "got string"; }
|
||||
inline if type_eq($args[0], bool) { return "got bool"; }
|
||||
return "got other";
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// type_name picks up the per-mono first-arg type.
|
||||
print("{}\n", show(42)); // i64
|
||||
print("{}\n", show("hi")); // string
|
||||
print("{}\n", show(3.14)); // f64
|
||||
|
||||
// inline-if + type_eq picks the right branch per mono.
|
||||
print("{}\n", describe(42)); // got i64
|
||||
print("{}\n", describe("hello")); // got string
|
||||
print("{}\n", describe(true)); // got bool
|
||||
print("{}\n", describe(3.14)); // got other
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
examples/packs/0519-packs-pack-bare-value.sx
Normal file
35
examples/packs/0519-packs-pack-bare-value.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
// Variadic heterogeneous type packs — step 4 final slice (4A
|
||||
// bare): `$args` referenced bare (without `[...]` indexing) in
|
||||
// expression position should evaluate to a comptime `[]Type`
|
||||
// slice value — the whole pack passed through as data so
|
||||
// builder fns can walk it.
|
||||
//
|
||||
// Use case (eventual): step 5's generic Into(Block) impl body
|
||||
// convert :: (self: Closure(..$args) -> $R) -> Block {
|
||||
// #insert build_block_convert($args, $R);
|
||||
// }
|
||||
// where `build_block_convert(args: []Type, ret: Type) -> string`
|
||||
// is a regular sx fn the interp executes — it walks `args` to
|
||||
// emit a trampoline fn matching the per-mono signature.
|
||||
//
|
||||
// Today the parser-arm I wrote for `$<ident>[<int>]` (commit
|
||||
// fd03b58, M5.A.next.4.3) REQUIRES the `[` after the pack
|
||||
// name; bare `$args` hits a focused diagnostic. This file
|
||||
// pins that rejection. Next commit makes the `[` optional —
|
||||
// no `[` yields a `comptime_pack_ref` AST node which lowering
|
||||
// converts to a `[N x Type]` aggregate of `const_type` values.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
len_of :: (..$args) -> i64 {
|
||||
list := $args;
|
||||
return list.len;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", len_of());
|
||||
print("{}\n", len_of(42));
|
||||
print("{}\n", len_of(1, 2, 3));
|
||||
print("{}\n", len_of("a", true, 3.14, "b"));
|
||||
return 0;
|
||||
}
|
||||
38
examples/packs/0520-packs-pack-dynamic-type-name.sx
Normal file
38
examples/packs/0520-packs-pack-dynamic-type-name.sx
Normal file
@@ -0,0 +1,38 @@
|
||||
// Variadic heterogeneous type packs — step 4A final-slice
|
||||
// follow-up. `type_name(<dynamic-arg>)` where the argument is
|
||||
// NOT a static type expression (e.g. `list[i]` indexing into
|
||||
// a `$args`-derived `[]Type` slice) silently folded to "i64"
|
||||
// because `resolveTypeArg`'s catch-all `else => .i64` lied —
|
||||
// the kind of silent unimplemented arm the project's REJECTED
|
||||
// PATTERNS forbid.
|
||||
//
|
||||
// The fix: `tryLowerReflectionCall` now splits static vs
|
||||
// dynamic args via `isStaticTypeArg(node)`. Static → fold to
|
||||
// const_string at lower time (today's fast path). Dynamic →
|
||||
// emit `callBuiltin(.type_name, [arg_ref])` for the interp's
|
||||
// runtime arm to handle.
|
||||
//
|
||||
// Type values are comptime-only — the dynamic path only works
|
||||
// inside a comptime context (`#run` / `#insert`). The test
|
||||
// runs `walk(42, "hi")` at `#run` time and prints the result.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/build.sx";
|
||||
|
||||
walk :: (..$args) -> string {
|
||||
list := $args;
|
||||
s := "";
|
||||
i : i64 = 0;
|
||||
while i < list.len {
|
||||
s = concat(s, type_name(list[i]));
|
||||
i = i + 1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
show :: () {
|
||||
print("{}\n", walk(42, "hi"));
|
||||
}
|
||||
#run show();
|
||||
|
||||
main :: () { print("rt\n"); }
|
||||
48
examples/packs/0521-packs-pack-builder-smoke.sx
Normal file
48
examples/packs/0521-packs-pack-builder-smoke.sx
Normal file
@@ -0,0 +1,48 @@
|
||||
// Variadic heterogeneous type packs — step 4A end-to-end
|
||||
// smoke. Exercises the FULL chain step 5's generic
|
||||
// `Into(Block)` impl needs:
|
||||
//
|
||||
// 1. A pack-fn that passes its bound `$args` to a builder
|
||||
// via `#run` / `#insert` (here `#run` for simplicity).
|
||||
// 2. The builder receives a `[]Type` slice and walks it,
|
||||
// calling `type_name(list[i])` per position.
|
||||
// 3. `type_name(list[i])` is the DYNAMIC form — the index_expr
|
||||
// argument can't be statically resolved at lower time, so
|
||||
// the lowering emits a `callBuiltin(.type_name, ...)` that
|
||||
// the interp's arm handles by reading the runtime
|
||||
// `Value.type_tag(TypeId)` and returning the per-position
|
||||
// name.
|
||||
//
|
||||
// The smoke demonstrates that step 4's full surface — bare
|
||||
// `$args` (whole pack as []Type) + dynamic reflection
|
||||
// intrinsics + per-position type discovery at interp time —
|
||||
// hangs together end-to-end. This is the foundation step 5's
|
||||
// builder-driven generic Into(Block) impl rests on.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/build.sx";
|
||||
|
||||
// Generic "describe pack" builder. Receives the pack as
|
||||
// []Type, returns a joined string with each type's name.
|
||||
describe :: (..$args) -> string {
|
||||
list := $args;
|
||||
s := "[";
|
||||
i : i64 = 0;
|
||||
while i < list.len {
|
||||
if i > 0 { s = concat(s, ", "); }
|
||||
s = concat(s, type_name(list[i]));
|
||||
i = i + 1;
|
||||
}
|
||||
s = concat(s, "]");
|
||||
return s;
|
||||
}
|
||||
|
||||
run_all :: () {
|
||||
print("{}\n", describe()); // []
|
||||
print("{}\n", describe(42)); // [i64]
|
||||
print("{}\n", describe(42, "hi")); // [i64, string]
|
||||
print("{}\n", describe(true, 3.14, "x", 99)); // [bool, f64, string, i64]
|
||||
}
|
||||
#run run_all();
|
||||
|
||||
main :: () { print("rt\n"); }
|
||||
55
examples/packs/0522-packs-pack-bare-args-cross-call.sx
Normal file
55
examples/packs/0522-packs-pack-bare-args-cross-call.sx
Normal file
@@ -0,0 +1,55 @@
|
||||
// Regression: bare `$args` slice survives crossing a function-call
|
||||
// boundary — both `.len` AND per-element values come through.
|
||||
//
|
||||
// Before the fix landed in `lazyLowerFunction`, the callee's
|
||||
// `args.len` got constant-folded to the outer pack-fn mono's
|
||||
// arity. `walk(args: []Any) { return args.len; }` lazily lowered
|
||||
// inside `probe(..$args)`'s first mono inherited
|
||||
// `pack_param_count["args"] = N` from the pack — the
|
||||
// `<pack_name>.len` intercept in `lowerFieldAccess` then baked
|
||||
// `ret i64 N` into walk's IR. Every subsequent shape's call to
|
||||
// walk returned the same constant, regardless of the actual slice
|
||||
// it received.
|
||||
//
|
||||
// `describe(args)` walks element-by-element so a silent
|
||||
// truncation surfaces as a missing tail (or a different type at
|
||||
// some position) — not just the wrong length.
|
||||
//
|
||||
// Walking under `#run` is intentional: the bare-`$args` slice
|
||||
// carries `const_type` elements that only the interp materialises;
|
||||
// LLVM emission leaves the per-element slots as undef (4A.bare
|
||||
// semantics — bare-pack is comptime-only).
|
||||
//
|
||||
// The element type is `[]Type` (a bare `$args` is the list of the
|
||||
// pack args' TYPES, each an 8-byte `.type_value`). Declaring it
|
||||
// `[]Any` (16-byte boxes) read every element past the first at the
|
||||
// wrong stride — the legacy interp's loose Value model tolerated it,
|
||||
// the byte-accurate comptime VM does not.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
describe :: (args: []Type) -> string {
|
||||
s := "[";
|
||||
i : i64 = 0;
|
||||
while i < args.len {
|
||||
if i > 0 { s = concat(s, ", "); }
|
||||
s = concat(s, type_name(args[i]));
|
||||
i = i + 1;
|
||||
}
|
||||
return concat(s, "]");
|
||||
}
|
||||
|
||||
probe :: (..$args) -> string {
|
||||
list := $args;
|
||||
return describe(list);
|
||||
}
|
||||
|
||||
run_all :: () {
|
||||
print("0: {}\n", probe());
|
||||
print("1: {}\n", probe(1));
|
||||
print("3: {}\n", probe(1, "x", true));
|
||||
print("5: {}\n", probe(1, 2.0, "x", true, 99));
|
||||
}
|
||||
#run run_all();
|
||||
|
||||
main :: () { print("rt\n"); }
|
||||
28
examples/packs/0523-packs-new-form-variadic-cross-module.sx
Normal file
28
examples/packs/0523-packs-new-form-variadic-cross-module.sx
Normal file
@@ -0,0 +1,28 @@
|
||||
// Regression: new-form variadic `..name: []T` defined in an imported
|
||||
// module is callable from another module without crashing LLVM emit.
|
||||
//
|
||||
// Before the fix in `resolveParamType` + `packVariadicCallArgs`,
|
||||
// the new-form variadic's element type went through one extra
|
||||
// `sliceOf` wrap (the helpers treated `..parts: []string` the same
|
||||
// as the legacy `parts: ..string` and added a slice level on top
|
||||
// of the already-declared slice). The double-wrapped `[][]T`
|
||||
// signature mismatched what the call-site marshalling emitted as
|
||||
// `[N x T]`, producing null/undef Refs that crashed
|
||||
// `LLVMBuildExtractValue` inside `emitStrCmp` during emission.
|
||||
//
|
||||
// Today's stdlib `path_join` uses the new form
|
||||
// (`(..parts: []string) -> string`); it lives in `modules/std.sx`
|
||||
// and is called here from the test module. Two- and three-arg
|
||||
// shapes must round-trip the slice through the function-call
|
||||
// boundary and concatenate the parts with '/'. Empty join (no
|
||||
// args) returns "".
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", path_join());
|
||||
print("{}\n", path_join("a"));
|
||||
print("{}\n", path_join("a", "b"));
|
||||
print("{}\n", path_join("a", "b", "c", "d"));
|
||||
return 0;
|
||||
}
|
||||
30
examples/packs/0524-packs-generic-fn-pack-state-leak.sx
Normal file
30
examples/packs/0524-packs-generic-fn-pack-state-leak.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Regression: a generic function (with `$T: Type` type params)
|
||||
// called from inside a pack-fn mono must NOT inherit the outer
|
||||
// pack maps during its own body lowering. Before the fix landed
|
||||
// in `monomorphizeFunction`, the cached mono of a generic with
|
||||
// an `args`-named param had its `args.len` constant-folded to
|
||||
// the arity of whichever pack shape triggered the first mono;
|
||||
// every subsequent shape read the same baked-in constant.
|
||||
//
|
||||
// Same root cause as issue-0048 (`lazyLowerFunction`), in a
|
||||
// different lowering path (`monomorphizeFunction`).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
build :: (args: []Type, $ret: Type) -> string {
|
||||
return concat("len=", int_to_string(args.len));
|
||||
}
|
||||
|
||||
probe :: (..$args) -> string {
|
||||
return build($args, void);
|
||||
}
|
||||
|
||||
run_all :: () {
|
||||
print("0: {}\n", probe());
|
||||
print("1: {}\n", probe(true));
|
||||
print("2: {}\n", probe(42, "hi"));
|
||||
print("4: {}\n", probe(1, 2.0, "x", true));
|
||||
}
|
||||
#run run_all();
|
||||
|
||||
main :: () { print("rt\n"); }
|
||||
26
examples/packs/0525-packs-pack-as-type-slice-arg.sx
Normal file
26
examples/packs/0525-packs-pack-as-type-slice-arg.sx
Normal file
@@ -0,0 +1,26 @@
|
||||
// Regression (issue 0143): a variadic `..$args` pack forwarded as a `[]Type`
|
||||
// ARGUMENT across a call must read the right element types. The pack-slice
|
||||
// materialization (`buildPackSliceValue`) built a `[]Any` (16-byte) array while
|
||||
// `Type` is now `.type_value` (8 bytes) — so a `[]Type` reader (8-byte stride)
|
||||
// read `[t0, pad, t1, …]` instead of `[t0, t1, …]`. The legacy interp's
|
||||
// tagged-Value model hid it; the byte-accurate comptime VM exposed it.
|
||||
#import "modules/std.sx";
|
||||
|
||||
inner :: (args: []Type) -> string {
|
||||
s := "";
|
||||
i : i64 = 0;
|
||||
while i < args.len {
|
||||
s = concat(s, type_name(args[i]));
|
||||
s = concat(s, " ");
|
||||
i = i + 1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
outer :: (..$args) -> string { return inner($args); }
|
||||
|
||||
R :: #run outer(42, "hi", true);
|
||||
|
||||
main :: () {
|
||||
print("[{}]\n", R);
|
||||
}
|
||||
28
examples/packs/0525-packs-pack-fn-comptime-return.sx
Normal file
28
examples/packs/0525-packs-pack-fn-comptime-return.sx
Normal file
@@ -0,0 +1,28 @@
|
||||
// Pack-fn (or any comptime-param fn) with a block body containing
|
||||
// an explicit `return X;` lowers to clean IR — the inline-return
|
||||
// path stores into a dedicated result slot and branches to the
|
||||
// shared `ret_done` block instead of emitting a `ret` inside the
|
||||
// caller's basic block. Without that, LLVM's verifier rejected the
|
||||
// IR with "Terminator found in the middle of a basic block".
|
||||
//
|
||||
// Surfaced by the variadic heterogeneous type packs feature (step
|
||||
// 1 made `..$args` parseable, so the simplest pack-fn smoke test
|
||||
// exercised the bug). The root cause is broader than packs: ANY
|
||||
// comptime fn with `is_comptime` params, a non-void return, and a
|
||||
// block body with `return X;` had the same crash. `format`/`print`
|
||||
// use arrow form (`=> expr`) or `#insert`-only bodies, so the bug
|
||||
// was invisible until pack-fn bodies surfaced it.
|
||||
//
|
||||
// Once fixed, calling foo() reaches the body's `return 42;`, the
|
||||
// inliner stores 42 into a result slot, the caller loads it as the
|
||||
// inline value, and main prints "42".
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
foo :: (..$args) -> i64 { return 42; }
|
||||
|
||||
main :: () -> i32 {
|
||||
n : i64 = foo(1, "hello");
|
||||
print("{}\n", n);
|
||||
return 0;
|
||||
}
|
||||
39
examples/packs/0526-packs-protocol-pack.sx
Normal file
39
examples/packs/0526-packs-protocol-pack.sx
Normal file
@@ -0,0 +1,39 @@
|
||||
// Feature 1 — heterogeneous protocol-constrained variadic pack (binding).
|
||||
//
|
||||
// `..xs: Show` (no `[]`, no `$`) is a pack, not a slice: each call site
|
||||
// monomorphizes with the concrete per-position arg types (Decision 1 — a pack
|
||||
// is a comptime mechanism, no runtime pack value), and `xs.len` is a comptime
|
||||
// constant. Arity and element types vary per call; each call is a distinct
|
||||
// specialization.
|
||||
//
|
||||
// DESIGN (locked): a pack element is viewed THROUGH the protocol — only the
|
||||
// protocol's own interface (its methods, and the projections `xs.T` / `xs.value`)
|
||||
// is accessible, NOT arbitrary concrete members. So `xs[i].get()` / `xs.T` are
|
||||
// the intended interface; `xs[i].v` (a field on the concrete IntBox, not part
|
||||
// of `Show`) is an error. Those are still being implemented — this example
|
||||
// locks in only the binding + comptime `xs.len`, the protocol-agnostic part.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
|
||||
IntBox :: struct { v: i64; }
|
||||
StrBox :: struct { s: string; }
|
||||
impl Show(i64) for IntBox { get :: (self: *IntBox) -> i64 => self.v; }
|
||||
impl Show(string) for StrBox { get :: (self: *StrBox) -> string => self.s; }
|
||||
|
||||
howmany :: (..xs: Show) -> i64 {
|
||||
return xs.len;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
a := IntBox.{ v = 42 };
|
||||
b := IntBox.{ v = 7 };
|
||||
c := StrBox.{ s = "cool" };
|
||||
print("n0={}\n", howmany()); // empty pack
|
||||
print("n2={}\n", howmany(a, b)); // two elements
|
||||
print("n3={}\n", howmany(a, b, c)); // heterogeneous: IntBox, IntBox, StrBox
|
||||
0
|
||||
}
|
||||
24
examples/packs/0527-packs-pack-non-conform.sx
Normal file
24
examples/packs/0527-packs-pack-non-conform.sx
Normal file
@@ -0,0 +1,24 @@
|
||||
// Feature 1 — a pack argument that doesn't conform to the constraint protocol
|
||||
// is a per-position error. `Naked` has no `impl Show`, so passing it to a
|
||||
// `..xs: Show` pack is rejected (pointing at the offending argument).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
IntBox :: struct { v: i64; }
|
||||
impl Show(i64) for IntBox { get :: (self: *IntBox) -> i64 => self.v; }
|
||||
|
||||
Naked :: struct { x: i64; } // intentionally NOT `impl Show`
|
||||
|
||||
howmany :: (..xs: Show) -> i64 {
|
||||
return xs.len;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
a := IntBox.{ v = 1 };
|
||||
n := Naked.{ x = 2 };
|
||||
print("{}\n", howmany(a, n)); // `n` does not conform to Show
|
||||
0
|
||||
}
|
||||
31
examples/packs/0528-packs-protocol-pack-methods.sx
Normal file
31
examples/packs/0528-packs-protocol-pack-methods.sx
Normal file
@@ -0,0 +1,31 @@
|
||||
// Feature 1 — protocol-interface method calls on heterogeneous pack elements.
|
||||
//
|
||||
// `..xs: Greeter` binds per call shape; each `xs[i]` is the concrete element,
|
||||
// and calling the protocol's own method `greet()` on it dispatches to that
|
||||
// element's impl. Elements may be DIFFERENT concrete types (Dog, Cat) as long
|
||||
// as each conforms to Greeter — this is the protocol-interface access the
|
||||
// pack is for. (Protocol method decls omit the implicit `self`; impls list it.)
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Greeter :: protocol {
|
||||
greet :: (self: *Self) -> i64;
|
||||
}
|
||||
|
||||
Dog :: struct { age: i64; }
|
||||
Cat :: struct { lives: i64; }
|
||||
impl Greeter for Dog { greet :: (self: *Dog) -> i64 => self.age; }
|
||||
impl Greeter for Cat { greet :: (self: *Cat) -> i64 => self.lives * 100; }
|
||||
|
||||
pair_sum :: (..xs: Greeter) -> i64 {
|
||||
return xs[0].greet() + xs[1].greet();
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
d := Dog.{ age = 3 };
|
||||
c := Cat.{ lives = 9 };
|
||||
print("dog+cat={}\n", pair_sum(d, c)); // 3 + 900 = 903 (heterogeneous)
|
||||
print("cat+dog={}\n", pair_sum(c, d)); // 900 + 3 = 903 (order swapped)
|
||||
print("dog+dog={}\n", pair_sum(d, Dog.{ age = 4 })); // 3 + 4 = 7
|
||||
0
|
||||
}
|
||||
30
examples/packs/0529-packs-protocol-pack-parameterized.sx
Normal file
30
examples/packs/0529-packs-protocol-pack-parameterized.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Feature 1 — method calls on a PARAMETERIZED protocol pack (the canonical
|
||||
// shape: `..xs: ValueListenable` where each element conforms with its own
|
||||
// type-arg). Calling the protocol method `get()` on `xs[i]` resolves to the
|
||||
// concrete element's impl, even though each element binds a different `T`.
|
||||
//
|
||||
// (Parameterised-protocol impl methods with a concrete source type are now
|
||||
// registered as `<Source>.<method>`, so UFCS — and thus `xs[i].get()` —
|
||||
// resolves them.)
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
|
||||
IntCell :: struct { v: i64; }
|
||||
StrCell :: struct { s: string; }
|
||||
impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl Box(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
|
||||
describe :: (..xs: Box) -> void {
|
||||
// xs[0] : Box(i64), xs[1] : Box(string) — different type-args per position.
|
||||
print("first={} second={}\n", xs[0].get(), xs[1].get());
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
describe(IntCell.{ v = 11 }, StrCell.{ s = "hi" });
|
||||
describe(StrCell.{ s = "x" }, IntCell.{ v = 99 });
|
||||
0
|
||||
}
|
||||
22
examples/packs/0530-packs-pack-interface-only.sx
Normal file
22
examples/packs/0530-packs-pack-interface-only.sx
Normal file
@@ -0,0 +1,22 @@
|
||||
// Feature 1 — a pack element exposes ONLY the constraint protocol's interface.
|
||||
// `xs[i].v` reaches a concrete field of IntCell that is not part of `Box`, so
|
||||
// it's rejected even though IntCell does have `v` — a pack element is viewed
|
||||
// through the protocol, like a constrained generic. (Protocol methods like
|
||||
// `get()` ARE callable; see examples 193/194.)
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
IntCell :: struct { v: i64; }
|
||||
impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
|
||||
leak :: (..xs: Box) -> i64 {
|
||||
return xs[0].v; // `v` is not part of Box — error
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", leak(IntCell.{ v = 5 }));
|
||||
0
|
||||
}
|
||||
28
examples/packs/0531-packs-pack-value-projection.sx
Normal file
28
examples/packs/0531-packs-pack-value-projection.sx
Normal file
@@ -0,0 +1,28 @@
|
||||
// Feature 1 — value-position pack projection: `xs.<method>` projects a
|
||||
// (zero-arg) protocol method over every element into a TUPLE of the per-element
|
||||
// results. For a parameterised `Box(T)`, each element's method returns its own
|
||||
// `T`, so the projected tuple is heterogeneous.
|
||||
//
|
||||
// xs.get ≈ (xs[0].get(), xs[1].get())
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
|
||||
IntCell :: struct { v: i64; }
|
||||
StrCell :: struct { s: string; }
|
||||
impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl Box(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
|
||||
show :: (..xs: Box) -> void {
|
||||
vals := xs.get; // tuple (i64, string)
|
||||
print("0={} 1={}\n", vals.0, vals.1);
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
show(IntCell.{ v = 42 }, StrCell.{ s = "hi" });
|
||||
show(StrCell.{ s = "x" }, IntCell.{ v = 7 }); // order swapped → (string, i64)
|
||||
0
|
||||
}
|
||||
26
examples/packs/0532-packs-pack-spread-call.sx
Normal file
26
examples/packs/0532-packs-pack-spread-call.sx
Normal file
@@ -0,0 +1,26 @@
|
||||
// Feature 1 — pack spread into a call's positional arguments. `f(..xs.get)`
|
||||
// projects `get` over the pack and spreads the resulting tuple into f's params:
|
||||
// add2(..xs.get) ≈ add2(xs[0].get(), xs[1].get())
|
||||
// The canonical's `mapper(..sources.value)` is this shape.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> i64;
|
||||
}
|
||||
IntCell :: struct { v: i64; }
|
||||
Dbl :: struct { n: i64; }
|
||||
impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl Box(i64) for Dbl { get :: (self: *Dbl) -> i64 => self.n * 2; }
|
||||
|
||||
add2 :: (a: i64, b: i64) -> i64 { return a + b; }
|
||||
add3 :: (a: i64, b: i64, c: i64) -> i64 { return a + b + c; }
|
||||
|
||||
via2 :: (..xs: Box) -> i64 { return add2(..xs.get); }
|
||||
via3 :: (..xs: Box) -> i64 { return add3(..xs.get); }
|
||||
|
||||
main :: () -> i32 {
|
||||
print("two={}\n", via2(IntCell.{ v = 10 }, Dbl.{ n = 5 })); // 10 + 10 = 20
|
||||
print("three={}\n", via3(Dbl.{ n = 1 }, IntCell.{ v = 2 }, Dbl.{ n = 3 })); // 2 + 2 + 6 = 10
|
||||
0
|
||||
}
|
||||
25
examples/packs/0533-packs-pack-tuple-materialize.sx
Normal file
25
examples/packs/0533-packs-pack-tuple-materialize.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// Feature 1 — materialize a tuple from a pack via `(..xs.method)` (Decision 2:
|
||||
// a pack is stored by materializing a tuple). `(..xs.get)` projects `get` over
|
||||
// the pack and collects the results into a real tuple value, which can then be
|
||||
// stored, indexed, and (for `Box(T)`) is heterogeneous per position.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
IntCell :: struct { v: i64; }
|
||||
StrCell :: struct { s: string; }
|
||||
impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl Box(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
|
||||
snapshot :: (..xs: Box) -> void {
|
||||
t := (..xs.get); // tuple (i64, string) materialized from the pack
|
||||
print("0={} 1={}\n", t.0, t.1);
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
snapshot(IntCell.{ v = 42 }, StrCell.{ s = "hi" });
|
||||
snapshot(StrCell.{ s = "x" }, IntCell.{ v = 7 }); // order swapped → (string, i64)
|
||||
0
|
||||
}
|
||||
38
examples/packs/0534-packs-pack-type-projection.sx
Normal file
38
examples/packs/0534-packs-pack-type-projection.sx
Normal file
@@ -0,0 +1,38 @@
|
||||
// Feature 1 — TYPE-position pack projection `xs.T`. The per-element protocol
|
||||
// type-arg `T` projects into a Pack of types, usable in type/signature
|
||||
// positions: a tuple type `(..xs.T)` and a closure signature
|
||||
// `Closure(..xs.T) -> R`. (`T` of each element comes from its
|
||||
// `impl Box(T) for <elem>`.)
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: protocol(T: Type) {
|
||||
get :: (self: *Self) -> T;
|
||||
}
|
||||
|
||||
IntCell :: struct { v: i64; }
|
||||
StrCell :: struct { s: string; }
|
||||
Dbl :: struct { n: i64; }
|
||||
impl Box(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl Box(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
impl Box(i64) for Dbl { get :: (self: *Dbl) -> i64 => self.n * 2; }
|
||||
|
||||
// Tuple type `(..xs.T)` — heterogeneous (i64, string), matched by the
|
||||
// value-projection `(..xs.get)`.
|
||||
snap :: (..xs: Box) -> void {
|
||||
t : (..xs.T) = (..xs.get);
|
||||
print("0={} 1={}\n", t.0, t.1);
|
||||
}
|
||||
|
||||
// Closure signature `Closure(..xs.T) -> i64` — here `Closure(i64, i64) -> i64`.
|
||||
// The closure literal's params are contextually typed from the projection.
|
||||
fold :: (..xs: Box) -> i64 {
|
||||
cb : Closure(..xs.T) -> i64 = (a, b) => a + b;
|
||||
return cb(xs[0].get(), xs[1].get());
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
snap(IntCell.{ v = 42 }, StrCell.{ s = "hi" }); // (i64, string)
|
||||
print("fold={}\n", fold(IntCell.{ v = 10 }, Dbl.{ n = 5 })); // 10 + 10 = 20
|
||||
0
|
||||
}
|
||||
31
examples/packs/0535-packs-slice-of-protocol-variadic.sx
Normal file
31
examples/packs/0535-packs-slice-of-protocol-variadic.sx
Normal file
@@ -0,0 +1,31 @@
|
||||
// Slice-of-protocol variadic `..xs: []P` — the RUNTIME counterpart to the
|
||||
// comptime pack `..xs: P`. Each trailing arg is `xx`-erased to a `P` protocol
|
||||
// value {ctx, vtable} and packed into a runtime `[]P`, so the elements can be
|
||||
// indexed by a RUNTIME index and dispatched through the protocol interface
|
||||
// (unlike a pack, which is comptime-only — see examples/163).
|
||||
//
|
||||
// This is the type-safe way to iterate a heterogeneous arg list at runtime:
|
||||
// concrete per-position types are erased to the constraint protocol.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol { show :: (self: *Self) -> string; }
|
||||
A :: struct { x: i64; }
|
||||
B :: struct { s: string; }
|
||||
impl Show for A { show :: (self: *A) -> string => "A"; }
|
||||
impl Show for B { show :: (self: *B) -> string => "B"; }
|
||||
|
||||
// Runtime loop over a []Show: runtime index + protocol-method dispatch.
|
||||
each :: (..xs: []Show) -> void {
|
||||
i := 0;
|
||||
while i < xs.len {
|
||||
print("[{}]={}\n", i, xs[i].show());
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
each(A.{ x = 1 }, B.{ s = "hi" }, A.{ x = 3 }); // heterogeneous, erased to Show
|
||||
each(); // empty is fine (len 0)
|
||||
0
|
||||
}
|
||||
25
examples/packs/0536-packs-pack-as-value.sx
Normal file
25
examples/packs/0536-packs-pack-as-value.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// Step 2.7 — pack-as-value diagnostics. A pack is comptime-only (Decision 1),
|
||||
// so using the bare pack name where a runtime value is required is an error,
|
||||
// with a context-tailored suggestion. All four categories below fire (the
|
||||
// functions are monomorphized when called from main).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol { show :: (self: *Self) -> string; }
|
||||
A :: struct {}
|
||||
impl Show for A { show :: (self: *A) -> string => "A"; }
|
||||
|
||||
sink :: (v: i64) -> void { _ = v; }
|
||||
|
||||
storage :: (..xs: Show) -> void { y := xs; _ = y; } // A: store
|
||||
call :: (..xs: Show) -> void { sink(xs); } // B: pass to a call
|
||||
ret :: (..xs: Show) -> i64 { return xs; } // C: return
|
||||
iter :: (..xs: Show) -> void { for xs (x) { _ = x; } } // D: runtime iterate
|
||||
|
||||
main :: () -> i32 {
|
||||
storage(A.{});
|
||||
call(A.{});
|
||||
_ = ret(A.{});
|
||||
iter(A.{});
|
||||
0
|
||||
}
|
||||
32
examples/packs/0537-packs-pack-xx-to-slice.sx
Normal file
32
examples/packs/0537-packs-pack-xx-to-slice.sx
Normal file
@@ -0,0 +1,32 @@
|
||||
// `xx <pack>` materializes a comptime pack into a runtime slice (issue 0053):
|
||||
// the explicit pack→slice bridge. With a `[]Any` target each element is boxed
|
||||
// to `Any`; with a `[]P` target each is `xx`-erased to the protocol `P`. This is
|
||||
// how you forward a pack to a runtime (`[]Any` / `[]P`) helper.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol { show :: (self: *Self) -> string; }
|
||||
A :: struct {}
|
||||
B :: struct { s: string; }
|
||||
impl Show for A { show :: (self: *A) -> string => "A"; }
|
||||
impl Show for B { show :: (self: *B) -> string => "B"; }
|
||||
|
||||
count_any :: (items: []Any) -> i64 { return items.len; }
|
||||
|
||||
show_all :: (items: []Show) -> i64 {
|
||||
i := 0;
|
||||
while i < items.len { print("{}\n", items[i].show()); i = i + 1; }
|
||||
return items.len;
|
||||
}
|
||||
|
||||
// `..$args` pack → []Any via `xx`.
|
||||
fwd_any :: (..$args) -> i64 { return count_any(xx args); }
|
||||
|
||||
// `..xs: Show` pack → []Show via `xx`.
|
||||
fwd_show :: (..xs: Show) -> i64 { return show_all(xx xs); }
|
||||
|
||||
main :: () -> i32 {
|
||||
print("any={}\n", fwd_any(1, "hi", 2.5)); // 3
|
||||
print("show={}\n", fwd_show(A.{}, B.{ s = "x" }, A.{})); // A B A, 3
|
||||
0
|
||||
}
|
||||
25
examples/packs/0538-packs-generic-struct-pack-field.sx
Normal file
25
examples/packs/0538-packs-generic-struct-pack-field.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// Phase 4.2 (core) — a generic struct with a pack type-param `..$Ts: []Type`
|
||||
// and a pack-shaped tuple field `(..$Ts)`. Each instantiation binds the
|
||||
// remaining type args as the pack, so the field is a tuple of those per-position
|
||||
// types. Storing the whole tuple field and reading its elements both work.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: struct($R: Type, ..$Ts: []Type) {
|
||||
r: $R;
|
||||
pair: (..$Ts); // tuple of the pack's element types
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// Box(i64, i32, string): R=i64, Ts=[i32, string], pair: (i32, string).
|
||||
a : Box(i64, i32, string) = ---;
|
||||
a.r = 7;
|
||||
a.pair = (42, "hi"); // whole-tuple field store
|
||||
print("a: r={} 0={} 1={}\n", a.r, a.pair.0, a.pair.1);
|
||||
|
||||
// A different shape → a different per-position tuple field.
|
||||
b : Box(bool, string, bool) = ---; // Ts=[string, bool], pair: (string, bool)
|
||||
b.pair = ("x", true);
|
||||
print("b: 0={} 1={}\n", b.pair.0, b.pair.1);
|
||||
0
|
||||
}
|
||||
29
examples/packs/0539-packs-combined-pack-field.sx
Normal file
29
examples/packs/0539-packs-combined-pack-field.sx
Normal file
@@ -0,0 +1,29 @@
|
||||
// Phase 4.2 — the canonical `Combined` struct's storage layer: a generic
|
||||
// struct whose field is a pack of PARAMETERIZED-protocol values,
|
||||
// `sources: (..VL(Ts))` → `(VL(T0), VL(T1), …)`. Each `VL(Ti)` is a real
|
||||
// 16-byte protocol value (issue: parameterized-protocol value types), and
|
||||
// `(..VL(Ts))` applies `VL` per pack element. Instantiate + whole-tuple store
|
||||
// of `xx`-erased values + per-element method dispatch all work.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
StrCell :: struct { s: string; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl VL(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
|
||||
Combined :: struct($R: Type, ..$Ts: []Type) {
|
||||
sources: (..VL(Ts)); // (VL(T0), VL(T1), …) — tuple of protocol values
|
||||
value: $R;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// Combined(i64, i64, string): R=i64, Ts=[i64, string],
|
||||
// sources: (VL(i64), VL(string)).
|
||||
c : Combined(i64, i64, string) = ---;
|
||||
c.sources = (xx IntCell.{ v = 10 }, xx StrCell.{ s = "hi" });
|
||||
c.value = 99;
|
||||
print("{} {} {}\n", c.sources.0.get(), c.sources.1.get(), c.value); // 10 hi 99
|
||||
0
|
||||
}
|
||||
27
examples/packs/0540-packs-pack-type-arg-spread.sx
Normal file
27
examples/packs/0540-packs-pack-type-arg-spread.sx
Normal file
@@ -0,0 +1,27 @@
|
||||
// Phase 6 — pack-spread in a parameterized-type's arg list:
|
||||
// `Combined($R, ..sources.T)`. Inside a pack-fn, `..sources.T` projects each
|
||||
// source's protocol type-arg and spreads them into the generic struct's pack
|
||||
// type-param `..$Ts`, so `Combined(i64, ..sources.T)` for a single `VL(i64)`
|
||||
// source instantiates `Combined(i64, i64)` (field `sources: (VL(i64))`).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
|
||||
Combined :: struct($R: Type, ..$Ts: []Type) {
|
||||
sources: (..VL(Ts));
|
||||
value: $R;
|
||||
}
|
||||
|
||||
make :: (..sources: VL) -> i64 {
|
||||
c : Combined(i64, ..sources.T) = ---; // instantiate with the spread type-arg
|
||||
c.sources.0 = xx sources[0]; // erase the concrete source to VL(i64)
|
||||
return c.sources.0.get();
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", make(IntCell.{ v = 7 })); // 7
|
||||
0
|
||||
}
|
||||
28
examples/packs/0541-packs-pack-to-protocol-tuple.sx
Normal file
28
examples/packs/0541-packs-pack-to-protocol-tuple.sx
Normal file
@@ -0,0 +1,28 @@
|
||||
// Phase 6 — `c.sources = (..sources)`: materialize a pack into a
|
||||
// protocol-typed tuple field, erasing each concrete pack element to the field's
|
||||
// protocol slot. The pack `..sources: VL` holds concrete cells; `(..sources)`
|
||||
// into a `(..VL(Ts))` field `xx`-erases each to its `VL(Ti)` value.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
StrCell :: struct { s: string; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
impl VL(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }
|
||||
|
||||
Combined :: struct($R: Type, ..$Ts: []Type) {
|
||||
sources: (..VL(Ts));
|
||||
value: $R;
|
||||
}
|
||||
|
||||
build :: (..sources: VL) -> void {
|
||||
c : Combined(i64, ..sources.T) = ---;
|
||||
c.sources = (..sources); // pack → tuple, per-element erase
|
||||
print("{} {}\n", c.sources.0.get(), c.sources.1.get());
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
build(IntCell.{ v = 10 }, StrCell.{ s = "hi" }); // 10 hi
|
||||
0
|
||||
}
|
||||
18
examples/packs/0542-packs-mapper-projection-spread.sx
Normal file
18
examples/packs/0542-packs-mapper-projection-spread.sx
Normal file
@@ -0,0 +1,18 @@
|
||||
// Phase 6 — `mapper(..sources.value)`: project a method over a pack and spread
|
||||
// the results into a closure call. The mapper lambda's params are contextually
|
||||
// typed from the `Closure(...)` parameter even though `apply` is a pack-fn.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
|
||||
apply :: (mapper: Closure(i64, i64) -> i64, ..sources: VL) -> i64 {
|
||||
return mapper(..sources.get); // (a, b) => a + b applied to (i0.get(), i1.get())
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", apply((a, b) => a + b, IntCell.{ v = 40 }, IntCell.{ v = 2 })); // 42
|
||||
0
|
||||
}
|
||||
36
examples/packs/0543-packs-canonical-map.sx
Normal file
36
examples/packs/0543-packs-canonical-map.sx
Normal file
@@ -0,0 +1,36 @@
|
||||
// Phase 6 — the canonical heterogeneous `map`, end to end. A pack-fn whose
|
||||
// return type `$R` is inferred from the mapper's closure return:
|
||||
// - `mapper: Closure(..sources.T) -> $R` types the lambda's params from the
|
||||
// projected pack element types, and its body (`a + b`) drives `$R`.
|
||||
// - `$R` is inferred at the call site from the lowered mapper's closure ret,
|
||||
// bound into the mono (`-> VL($R)` ⇒ `VL(i64)`, `Combined($R, ..)` ⇒
|
||||
// `Combined(i64, ..)`), and folded into the mangle.
|
||||
// - `(..sources)` materializes the pack into the `(..VL(Ts))` field (per-element
|
||||
// erase) and `mapper(..sources.get)` projects+spreads; `xx c` erases the
|
||||
// generic-struct instance to `VL(i64)` via the generic impl's monomorphized
|
||||
// thunk.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
|
||||
Combined :: struct($R: Type, ..$Ts: []Type) {
|
||||
sources: (..VL(Ts));
|
||||
value: $R;
|
||||
}
|
||||
impl VL($R) for Combined($R, ..$Ts) { get :: (self: *Combined) -> $R => self.value; }
|
||||
|
||||
map :: (mapper: Closure(..sources.T) -> $R, ..sources: VL) -> VL($R) {
|
||||
c : Combined($R, ..sources.T) = ---;
|
||||
c.sources = (..sources);
|
||||
c.value = mapper(..sources.get);
|
||||
return xx c;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
r := map((a, b) => a + b, IntCell.{ v = 40 }, IntCell.{ v = 2 });
|
||||
print("{}\n", r.get()); // 42
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Regression (stdlib E4): an imported pack function whose fixed-prefix param
|
||||
// type is visible only in its defining module must resolve during pack
|
||||
// monomorphization. `lib.sx` imports `dep.sx` (which defines `Needs`) and
|
||||
// exposes `make() -> Needs` plus `use_pack(n: Needs, ..$args)`. `main` imports
|
||||
// ONLY `lib.sx`, so `Needs` is two flat hops away and not bare-visible here —
|
||||
// main never names it.
|
||||
//
|
||||
// Before the fix, `monomorphizePackFn` restored the caller's source before
|
||||
// re-binding the fixed-prefix params, so `n: Needs` was resolved in main's
|
||||
// context and rejected with "type 'Needs' is not visible" — even though the
|
||||
// control plain fn `use_plain(n: Needs)` (typed via the source-pinned call-arg
|
||||
// path) ran fine. The fixed-prefix param is now resolved under the pack fn's own
|
||||
// source (`fd.body.source_file`), matching the rest of the pack signature/body.
|
||||
#import "modules/std.sx";
|
||||
#import "0544-packs-imported-pack-fn-fixed-param-source-pin/lib.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
x := make();
|
||||
print("plain {}\n", use_plain(x));
|
||||
print("pack {}\n", use_pack(x, 1, 2));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// `Needs` lives two flat-import hops away from `main` (main -> lib -> dep), so
|
||||
// it is NOT bare-visible at the call site under non-transitive visibility.
|
||||
Needs :: struct { v: i64; }
|
||||
@@ -0,0 +1,16 @@
|
||||
// `lib.sx` imports `dep.sx`, so `Needs` is bare-visible HERE. A module that
|
||||
// imports only `lib.sx` cannot see `Needs` (non-transitive). The pack fn's
|
||||
// fixed-prefix param `n: Needs` must therefore resolve in this module's
|
||||
// context, not the caller's.
|
||||
#import "modules/std.sx";
|
||||
#import "dep.sx";
|
||||
|
||||
make :: () -> Needs => Needs.{ v = 7 };
|
||||
|
||||
// Control: a plain (non-pack) fn with the same fixed param already resolves in
|
||||
// its defining module — the cross-module call-arg typing path is source-pinned.
|
||||
use_plain :: (n: Needs) -> i64 => n.v;
|
||||
|
||||
// Pack fn: the fixed-prefix param `n: Needs` is bound during pack
|
||||
// monomorphization. Its type must resolve under this module's source.
|
||||
use_pack :: (n: Needs, ..$args) -> i64 => n.v + args[0];
|
||||
63
examples/packs/0545-packs-inline-for-element.sx
Normal file
63
examples/packs/0545-packs-inline-for-element.sx
Normal file
@@ -0,0 +1,63 @@
|
||||
// `inline for` element form over a pack — multi-iterable parity with the
|
||||
// runtime for-loop. Position 0 drives the unroll count (a pack's arity or a
|
||||
// bounded range's span); trailing iterables pair with it. A pack capture is
|
||||
// the concrete per-position element viewed through the constraint protocol
|
||||
// (same semantics as `xs[i]`); a range capture is a comptime cursor.
|
||||
//
|
||||
// inline for xs (x) — element form
|
||||
// inline for xs, 0.. (x, i) — element + paired index
|
||||
// inline for 0..xs.len, xs (i, x) — range driver, trailing pack
|
||||
// inline for xs { } — captureless; N=0 unrolls nothing
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol { show :: (self: *Self) -> string; }
|
||||
IntBox :: struct { v: i64; }
|
||||
StrBox :: struct { s: string; }
|
||||
impl Show for IntBox { show :: (self: *IntBox) -> string { int_to_string(self.v) } }
|
||||
impl Show for StrBox { show :: (self: *StrBox) -> string { self.s } }
|
||||
|
||||
bare :: (..xs: Show) {
|
||||
inline for xs (x) {
|
||||
print("bare: {}\n", x.show());
|
||||
}
|
||||
}
|
||||
elem_and_index :: (..xs: Show) {
|
||||
inline for xs, 0.. (x, i) {
|
||||
print("{}: {}\n", i, x.show());
|
||||
}
|
||||
}
|
||||
range_driver :: (..xs: Show) {
|
||||
inline for 0..xs.len, xs (i, x) {
|
||||
print("r{}: {}\n", i, x.show());
|
||||
}
|
||||
}
|
||||
offset_index :: (..xs: Show) {
|
||||
inline for xs, 10.. (x, i) {
|
||||
print("{} -> {}\n", i, x.show());
|
||||
}
|
||||
}
|
||||
captureless :: (..xs: Show) {
|
||||
n := 0;
|
||||
inline for xs { n += 1; }
|
||||
print("ran {}\n", n);
|
||||
}
|
||||
value_pos :: (..xs: Show) {
|
||||
inline for xs (x) {
|
||||
print("val: {}\n", x);
|
||||
}
|
||||
}
|
||||
empty :: (..xs: Show) {
|
||||
inline for xs (x) { print("never\n"); }
|
||||
print("empty ok\n");
|
||||
}
|
||||
|
||||
main :: () {
|
||||
bare(IntBox.{ v = 7 }, StrBox.{ s = "hi" });
|
||||
elem_and_index(IntBox.{ v = 7 }, StrBox.{ s = "hi" });
|
||||
range_driver(IntBox.{ v = 1 }, StrBox.{ s = "two" });
|
||||
offset_index(StrBox.{ s = "x" }, StrBox.{ s = "y" });
|
||||
captureless(IntBox.{ v = 0 }, IntBox.{ v = 0 }, IntBox.{ v = 0 });
|
||||
value_pos(IntBox.{ v = 42 });
|
||||
empty();
|
||||
}
|
||||
6
examples/packs/0546-packs-fn-alias-rich.sx
Normal file
6
examples/packs/0546-packs-fn-alias-rich.sx
Normal file
@@ -0,0 +1,6 @@
|
||||
// Companion of 0546: the authoring module for the fn-alias re-exports.
|
||||
#import "modules/std.sx";
|
||||
|
||||
helper :: () -> i64 { 7 }
|
||||
first_of :: (xs: []$T) -> T { xs[0] }
|
||||
my_pack :: (..$args) -> i64 { args[0] + args[1] }
|
||||
35
examples/packs/0546-packs-fn-alias.sx
Normal file
35
examples/packs/0546-packs-fn-alias.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
// Function aliases dispatch exactly like their target, across every fn
|
||||
// kind: plain, runtime-generic ([]$T), and comptime-pack (..$args) — with
|
||||
// bare, renamed, and namespace-member RHS. The alias is an ordinary own
|
||||
// declaration, so it re-exports one flat-import level (companion file
|
||||
// -rich.sx authors the fns aliased here and via the namespace).
|
||||
// Regression (issue 0121): comptime-pack fn aliases (and ALL renamed fn
|
||||
// aliases) used to fail "unresolved '<alias>'" — only same-name re-exports
|
||||
// worked, through the name-keyed global registry.
|
||||
#import "modules/std.sx";
|
||||
s :: #import "modules/std.sx";
|
||||
r :: #import "0546-packs-fn-alias-rich.sx";
|
||||
|
||||
pack_sum :: (..$args) -> i64 {
|
||||
args[0] + args[1]
|
||||
}
|
||||
sum_alias :: pack_sum; // same-file pack alias (the 0121 repro)
|
||||
|
||||
helper2 :: r.helper; // renamed plain, namespace RHS
|
||||
head_of :: r.first_of; // renamed runtime-generic, namespace RHS
|
||||
sum2 :: r.my_pack; // renamed pack, namespace RHS
|
||||
|
||||
my_print :: s.print; // std's print — comptime pack + $fmt
|
||||
my_format :: s.format; // value-returning sibling
|
||||
|
||||
main :: () {
|
||||
print("pack: {}\n", sum_alias(3, 4));
|
||||
print("plain: {}\n", helper2());
|
||||
arr := .[10, 20, 30];
|
||||
xs : []i64 = arr;
|
||||
print("generic: {}\n", head_of(xs));
|
||||
print("ns-pack: {}\n", sum2(20, 22));
|
||||
my_print("std-print: {} {}\n", 1, "two");
|
||||
t := my_format("std-format {}", 42);
|
||||
my_print("{}\n", t);
|
||||
}
|
||||
27
examples/packs/0547-packs-xx-pack-index-to-protocol.sx
Normal file
27
examples/packs/0547-packs-xx-pack-index-to-protocol.sx
Normal file
@@ -0,0 +1,27 @@
|
||||
// `xx <pack>[i]` erased to a protocol-typed local.
|
||||
//
|
||||
// Erasing a single comptime-pack element to a protocol scalar routes through
|
||||
// buildProtocolErasure. A pack index is a comptime rvalue (a pack has no
|
||||
// runtime storage — `sources[i]` resolves to the call-site arg, which only
|
||||
// gets storage when lowered as a value), so the erasure must heap-copy the
|
||||
// materialized element rather than take its address.
|
||||
//
|
||||
// Regression (issue 0135): `xx sources[0]` used to lower the bare pack as a
|
||||
// value and error with "pack 'sources' has no runtime value".
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
|
||||
first :: (..sources: VL) -> i64 {
|
||||
x : VL(i64) = xx sources[0]; // erase element 0 to VL(i64)
|
||||
return x.get();
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", first(IntCell.{ v = 7 })); // 7
|
||||
print("{}\n", first(IntCell.{ v = 42 }, IntCell.{ v = 99 })); // 42 (element 0)
|
||||
0
|
||||
}
|
||||
25
examples/packs/0548-packs-xx-pack-index-two-elements.sx
Normal file
25
examples/packs/0548-packs-xx-pack-index-two-elements.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// Erase two DISTINCT comptime-pack elements to protocol locals — each gets
|
||||
// its own heap copy and resolves to its OWN concrete type's method (IntCell.get
|
||||
// vs Doubler.get), proving the per-element erasure picks the right vtable.
|
||||
//
|
||||
// Regression (issue 0135): single-element `xx pack[i]` erasure to a protocol
|
||||
// scalar was unsupported (the bare pack lowered as a value and errored).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: (self: *Self) -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
Doubler :: struct { n: i64; }
|
||||
impl VL(i64) for Doubler { get :: (self: *Doubler) -> i64 => self.n * 2; }
|
||||
|
||||
sum_two :: (..sources: VL) -> i64 {
|
||||
a : VL(i64) = xx sources[0]; // erase element 0
|
||||
b : VL(i64) = xx sources[1]; // erase element 1
|
||||
return a.get() + b.get();
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", sum_two(IntCell.{ v = 10 }, Doubler.{ n = 16 })); // 10 + (16*2) = 42
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// E6BR-4 (MIXED pack source — the trap cell) — a pack-closure param-impl source
|
||||
// `Closure(*Box, ..$args) -> $R` mixes a CONCRETE fixed prefix (`*Box`) with pack
|
||||
// metadata (`..$args`, `$R`). The reconciled choke-point decides template-vs-author
|
||||
// AT THE LEAF: `*Box` is resolved SOURCE-AWARE through `resolveCompound` while
|
||||
// `..$args`/`$R` stay pack metadata via `PackResolver` — NOT a top-level
|
||||
// "contains-unbound → no-author wrapper" router, which would send `*Box` down the
|
||||
// global last-wins path (the trap both engines flagged). With two flat `Box`
|
||||
// authors and none own, the concrete `*Box` prefix is a genuine collision and the
|
||||
// build exits 1 — proving the prefix IS routed source-aware (it caught the
|
||||
// ambiguity) while the pack parts did not spuriously error.
|
||||
//
|
||||
// Fail-before (pre-E6BR-4): the wrapped/pack source fell to the no-author
|
||||
// `type_bridge.resolveTemplateSignatureType` wrapper (global last-wins, no
|
||||
// diagnostic), so the `*Box` collision registered silently. Protects the pure-pack
|
||||
// `Closure(..$args) -> $R` bridge in `library/modules/ffi/objc_block.sx` (0504 /
|
||||
// 1302 / 1304 stay byte-identical), whose single author keeps the prefix-free path.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "0829-packs-param-impl-mixed-pack-source-ambiguous/a.sx";
|
||||
#import "0829-packs-param-impl-mixed-pack-source-ambiguous/b.sx";
|
||||
|
||||
Block :: struct { tag: i32; }
|
||||
|
||||
Sink :: protocol(T: Type) {
|
||||
convert :: (self: *Self) -> T;
|
||||
}
|
||||
|
||||
impl Sink(Block) for Closure(*Box, ..$args) -> $R {
|
||||
convert :: (self: Closure(*Box, ..$args) -> $R) -> Block {
|
||||
.{ tag = 0 }
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// One of two flat-imported `Box` authors; with no own author the FIXED PREFIX
|
||||
// `*Box` of the pack-closure source is a genuine collision.
|
||||
Box :: struct { a: i32; }
|
||||
|
||||
a_box :: () -> i32 {
|
||||
b : Box = ---;
|
||||
b.a = 1;
|
||||
return b.a;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// The second flat-imported `Box` author — a DISTINCT nominal from a.sx's `Box`.
|
||||
Box :: struct { b: i32; }
|
||||
|
||||
b_box :: () -> i32 {
|
||||
x : Box = ---;
|
||||
x.b = 2;
|
||||
return x.b;
|
||||
}
|
||||
1
examples/packs/expected/0500-packs-varargs.exit
Normal file
1
examples/packs/expected/0500-packs-varargs.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/packs/expected/0500-packs-varargs.stderr
Normal file
1
examples/packs/expected/0500-packs-varargs.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
4
examples/packs/expected/0500-packs-varargs.stdout
Normal file
4
examples/packs/expected/0500-packs-varargs.stdout
Normal file
@@ -0,0 +1,4 @@
|
||||
60
|
||||
1 2 3 4 5
|
||||
60
|
||||
10 20 30
|
||||
1
examples/packs/expected/0501-packs-any-varargs.exit
Normal file
1
examples/packs/expected/0501-packs-any-varargs.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/packs/expected/0501-packs-any-varargs.stderr
Normal file
1
examples/packs/expected/0501-packs-any-varargs.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
3
examples/packs/expected/0501-packs-any-varargs.stdout
Normal file
3
examples/packs/expected/0501-packs-any-varargs.stdout
Normal file
@@ -0,0 +1,3 @@
|
||||
42 hello true 3.140000
|
||||
point: (10,20) 99
|
||||
3
|
||||
1
examples/packs/expected/0502-packs-pack-parse.exit
Normal file
1
examples/packs/expected/0502-packs-pack-parse.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/packs/expected/0502-packs-pack-parse.stderr
Normal file
1
examples/packs/expected/0502-packs-pack-parse.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/packs/expected/0502-packs-pack-parse.stdout
Normal file
1
examples/packs/expected/0502-packs-pack-parse.stdout
Normal file
@@ -0,0 +1 @@
|
||||
pack parse ok
|
||||
1
examples/packs/expected/0503-packs-pack-type-rep.exit
Normal file
1
examples/packs/expected/0503-packs-pack-type-rep.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/packs/expected/0503-packs-pack-type-rep.stderr
Normal file
1
examples/packs/expected/0503-packs-pack-type-rep.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/packs/expected/0503-packs-pack-type-rep.stdout
Normal file
1
examples/packs/expected/0503-packs-pack-type-rep.stdout
Normal file
@@ -0,0 +1 @@
|
||||
pack type rep ok
|
||||
1
examples/packs/expected/0504-packs-pack-impl-match.exit
Normal file
1
examples/packs/expected/0504-packs-pack-impl-match.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pack impl match ok
|
||||
1
examples/packs/expected/0505-packs-pack-typed-index.exit
Normal file
1
examples/packs/expected/0505-packs-pack-typed-index.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
7
|
||||
1
examples/packs/expected/0506-packs-pack-if-return.exit
Normal file
1
examples/packs/expected/0506-packs-pack-if-return.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/packs/expected/0506-packs-pack-if-return.stderr
Normal file
1
examples/packs/expected/0506-packs-pack-if-return.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
examples/packs/expected/0506-packs-pack-if-return.stdout
Normal file
2
examples/packs/expected/0506-packs-pack-if-return.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
-1
|
||||
42
|
||||
1
examples/packs/expected/0507-packs-pack-mono-dedup.exit
Normal file
1
examples/packs/expected/0507-packs-pack-mono-dedup.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
16133
examples/packs/expected/0507-packs-pack-mono-dedup.ir
Normal file
16133
examples/packs/expected/0507-packs-pack-mono-dedup.ir
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0 1 1 3 2
|
||||
1
examples/packs/expected/0508-packs-pack-generic-ret.exit
Normal file
1
examples/packs/expected/0508-packs-pack-generic-ret.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
42 99
|
||||
1
examples/packs/expected/0509-packs-pack-hetero-ret.exit
Normal file
1
examples/packs/expected/0509-packs-pack-hetero-ret.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
hello
|
||||
1
examples/packs/expected/0510-packs-pack-index-oob.exit
Normal file
1
examples/packs/expected/0510-packs-pack-index-oob.exit
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
5
examples/packs/expected/0510-packs-pack-index-oob.stderr
Normal file
5
examples/packs/expected/0510-packs-pack-index-oob.stderr
Normal file
@@ -0,0 +1,5 @@
|
||||
error: pack index 2 out of bounds: 'args' has 1 element
|
||||
--> examples/packs/0510-packs-pack-index-oob.sx:14:32
|
||||
|
|
||||
14 | foo :: (..$args) -> $R => args[2];
|
||||
| ^
|
||||
1
examples/packs/expected/0510-packs-pack-index-oob.stdout
Normal file
1
examples/packs/expected/0510-packs-pack-index-oob.stdout
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/packs/expected/0511-packs-pack-bare-args.exit
Normal file
1
examples/packs/expected/0511-packs-pack-bare-args.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/packs/expected/0511-packs-pack-bare-args.stderr
Normal file
1
examples/packs/expected/0511-packs-pack-bare-args.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/packs/expected/0511-packs-pack-bare-args.stdout
Normal file
1
examples/packs/expected/0511-packs-pack-bare-args.stdout
Normal file
@@ -0,0 +1 @@
|
||||
3
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: pack 'args' must be indexed by a compile-time constant — a pack is comptime-only and has no runtime value
|
||||
--> examples/packs/0512-packs-pack-runtime-index.sx:18:24
|
||||
|
|
||||
18 | x : Any = args[i]; // ERROR: runtime index into a comptime-only pack
|
||||
| ^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
15955
examples/packs/expected/0513-packs-pack-mixed-comptime.ir
Normal file
15955
examples/packs/expected/0513-packs-pack-mixed-comptime.ir
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
703
|
||||
900
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user