Files
AILang/crates/ail/tests/snapshots/max3.ll
T
Brummel 9339279181 iter prep.3-kernel-tier-modules (DONE 9/9): kernel-tier modules + param-in + stub crate — closes #33
Terminal iteration of the kernel-extension-mechanics milestone. Ships
the four language-level mechanisms named in the spec's § Goal:
Module.kernel + TypeDef.param-in schema, their Form-A surface,
flag-driven kernel-tier auto-injection, and generic param-in checker
enforcement with a new diagnostic.

Schema (Tasks 1+2). Module gains a `kernel: bool` field
(skip_serializing_if = is_false), TypeDef gains a
`param_in: BTreeMap<String, BTreeSet<String>>` field
(skip-if-empty, kebab-renamed to "param-in"). Both fields are
strictly additive — every pre-existing fixture's canonical-JSON hash
is bit-stable except `prelude.ail`, which intentionally gains
`(kernel)`. The struct-literal sweep covered ~104 Module sites and
~35 TypeDef sites across the workspace; the additive serde-default
covers JSON deserialise paths, only Rust struct literals broke.

Form-A surface (Tasks 3+4). `(kernel)` is a bare module-header
attribute; `(param-in (a Int Float) (b Str))` is one outer
TypeDef-body clause carrying one or more inner var-lists (OQ1
decision — mirrors `(ctors …)`, one parser arm, deterministic
BTreeMap iteration). Both round-trip Form-A → JSON → Form-A
bit-identical.

Workspace-load migration (Task 5). The hardcoded `&["prelude"]`
literal at loader.rs:108 became a `modules.values().filter(|m|
m.kernel)` derivation; `parse_prelude()` injection stays because
the prelude has no on-disk manifest in user workspaces. Prelude
now carries `(kernel)` in its source, so the new filter picks it
up automatically. Code-path migration only — observable behaviour
is identical (prelude_free_fns.rs stays green). prelude hash
re-pinned (af372f28c726f29f) with Honesty-Rule provenance comment.
WorkspaceLoadError::ReservedModuleName diagnostic prose
repurposed: any built-in kernel module name is reserved
(currently prelude + kernel_stub), not specifically prelude. CLI
mapping at main.rs updated in lockstep.

Stub crate (Task 6). New `crates/ailang-kernel-stub/` is a
zero-dependency leaf crate carrying only `pub const STUB_AIL:
&str` with the Form-A source of the kernel_stub module (one
parametric TypeDef with param-in, one ctor). The parse hop —
`parse_kernel_stub()` — lives in ailang-surface next to
parse_prelude, keeping the crate-dependency graph acyclic
(`ailang-surface → ailang-kernel-stub → ailang-core`, no
back-edge). The stub is injected unconditionally in all builds as
the ratifying fixture for the kernel-extension mechanism; future
base extensions may add more or retire the stub. Drift-pinned by
`kernel_stub_module_round_trips`.

Checker (Task 7). New `CheckError::ParamNotInRestrictedSet`
variant + code() + ctx() arms + enforcement in
`check_type_well_formed`'s Type::Con arm — generic, data-driven
from the TypeDef, mentions no specific extension type. Two
in-source tests pin both the rejection (`Str` outside `{Int,
Float}`) and the acceptance (`Int` inside) paths.

Workspace-load integration tests (Task 8). New
`workspace_kernel.rs` integration-test crate with three tests:
auto-import without explicit `(import …)` declaration, two
kernel-tier modules co-load, explicit-import-overrides-auto-
import precedence preserved. Loader is import-tree-only so the
auto-import tests use a bridge module that brings the kernel
module into the workspace via the import graph — docstring
captures the reachability nuance for future readers.

Doc-state transitions (Task 9). INDEX.md kernel-extensions row
annotation transitions from "design accepted 2026-05-28; impl in
progress" to "mechanisms milestone closed 2026-05-28; raw-buf and
series milestones pending". Whitepaper STATUS + auto-import +
param-in sections transitioned forward→present for shipped
mechanisms; forward-tense survives only in sections describing
the still-pending raw-buf/series milestones (per Honesty-Rule).
data-model contract gains anchor blocks for both new schema
fields.

Side-effect: every binary's IR snapshot now contains ~52 lines
for `drop_kernel_stub_StubT` because the stub is auto-injected
into every workspace load. Snapshots refreshed; e2e expects 4
modules per workspace (prelude + kernel_stub + entry + zero or
more user modules) instead of the previous 3.

Plan defects scrubbed in the implementation (folded back into
the planner template via the planner's self-review checklist
next time): Task 4 sample test src used fictional
`(ctors (MkT a))` list form (project grammar is per-`(ctor MkT
a)`); Task 6 original wiring would have created a cycle
ailang-surface → ailang-kernel-stub → ailang-surface (inverted —
stub crate is zero-dep, parse hop lives in surface); Task 7 in-
source tests referenced a fictional `check_type_in_module`
helper (used the existing Workspace + check_workspace
convention); Task 8 first integration test expected loader to
auto-load kernel modules from disk (loader is import-tree-only;
tests use a bridge module).

Concern-5 fix folded in pre-commit: workspace.rs ReservedModuleName
doc-prose initially said "in test/dev builds" for kernel_stub —
but stub is unconditionally injected in all builds. Doc copy
tightened to present-state per Honesty-Rule.

Stats: 0 spec-review-loops, 0 quality-review-loops, 2 sweep-script
retries on Task 2 (brace-depth bug on nested vec![Ctor{…}],
recovered via per-file checkout + rewritten anchor-on-existing-
field sweep), 1 e2e-snapshot refresh on Task 6.
2026-05-28 18:43:42 +02:00

353 lines
9.2 KiB
LLVM

; AILang generated workspace; entry: max3
source_filename = "max3.ail"
target triple = "<NORMALIZED>"
declare i32 @printf(ptr, ...)
declare i32 @fputs(ptr, ptr)
@stdout = external global ptr
declare ptr @ailang_rc_alloc(i64)
declare void @ailang_rc_inc(ptr)
declare void @ailang_rc_dec(ptr)
declare ptr @ailang_drop_worklist_new()
declare void @ailang_drop_worklist_push(ptr, ptr)
declare ptr @ailang_drop_worklist_pop(ptr)
declare void @ailang_drop_worklist_free(ptr)
declare i32 @strcmp(ptr, ptr)
declare zeroext i1 @ail_str_eq(ptr, ptr)
declare i32 @ail_str_compare(ptr, ptr)
declare ptr @ailang_int_to_str(i64)
declare ptr @ailang_float_to_str(double)
declare ptr @ailang_bool_to_str(i1)
declare ptr @ailang_str_clone(ptr)
declare ptr @ailang_str_concat(ptr, ptr)
declare i64 @llvm.fptosi.sat.i64.f64(double)
@ail_max3_max_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_max_adapter, ptr null }
@ail_max3_max3_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_max3_adapter, ptr null }
@ail_max3_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_main_adapter, ptr null }
@ail_prelude_float_eq_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_eq_adapter, ptr null }
@ail_prelude_float_ne_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ne_adapter, ptr null }
@ail_prelude_float_lt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_lt_adapter, ptr null }
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
@ail_prelude_compare__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_compare__Int_adapter, ptr null }
@ail_prelude_gt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_gt__Int_adapter, ptr null }
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
define void @drop_kernel_stub_StubT(ptr %p) {
entry:
%is_null = icmp eq ptr %p, null
br i1 %is_null, label %ret, label %live
live:
%tag = load i64, ptr %p, align 8
switch i64 %tag, label %dflt [
i64 0, label %arm_0
]
arm_0:
%a0 = getelementptr inbounds i8, ptr %p, i64 8
%v1 = load ptr, ptr %a0, align 8
call void @ailang_rc_dec(ptr %v1)
br label %join
dflt:
unreachable
join:
call void @ailang_rc_dec(ptr %p)
br label %ret
ret:
ret void
}
define void @partial_drop_kernel_stub_StubT(ptr %p, i64 %mask) {
entry:
%is_null = icmp eq ptr %p, null
br i1 %is_null, label %ret, label %live
live:
%tag = load i64, ptr %p, align 8
switch i64 %tag, label %dflt [
i64 0, label %arm_0
]
arm_0:
%b0 = and i64 %mask, 1
%s1 = icmp ne i64 %b0, 0
br i1 %s1, label %after_0_0, label %do_0_0
do_0_0:
%a2 = getelementptr inbounds i8, ptr %p, i64 8
%v3 = load ptr, ptr %a2, align 8
call void @ailang_rc_dec(ptr %v3)
br label %after_0_0
after_0_0:
br label %join
dflt:
unreachable
join:
call void @ailang_rc_dec(ptr %p)
br label %ret
ret:
ret void
}
define i64 @ail_max3_max(i64 %arg_a, i64 %arg_b) {
entry:
%v1 = call i1 @ail_prelude_gt__Int(i64 %arg_a, i64 %arg_b)
br i1 %v1, label %then.2, label %else.2
then.2:
br label %join.2
else.2:
br label %join.2
join.2:
%v3 = phi i64 [ %arg_a, %then.2 ], [ %arg_b, %else.2 ]
ret i64 %v3
}
define i64 @ail_max3_max_adapter(ptr %_env, i64 %a0, i64 %a1) {
entry:
%r = call i64 @ail_max3_max(i64 %a0, i64 %a1)
ret i64 %r
}
define i64 @ail_max3_max3(i64 %arg_a, i64 %arg_b, i64 %arg_c) {
entry:
%v1 = call i1 @ail_prelude_gt__Int(i64 %arg_a, i64 %arg_b)
br i1 %v1, label %then.2, label %else.2
then.2:
%v3 = call i1 @ail_prelude_gt__Int(i64 %arg_a, i64 %arg_c)
br i1 %v3, label %then.4, label %else.4
then.4:
br label %join.4
else.4:
br label %join.4
join.4:
%v5 = phi i64 [ %arg_a, %then.4 ], [ %arg_c, %else.4 ]
br label %join.2
else.2:
%v6 = call i1 @ail_prelude_gt__Int(i64 %arg_b, i64 %arg_c)
br i1 %v6, label %then.7, label %else.7
then.7:
br label %join.7
else.7:
br label %join.7
join.7:
%v8 = phi i64 [ %arg_b, %then.7 ], [ %arg_c, %else.7 ]
br label %join.2
join.2:
%v9 = phi i64 [ %v5, %join.4 ], [ %v8, %join.7 ]
ret i64 %v9
}
define i64 @ail_max3_max3_adapter(ptr %_env, i64 %a0, i64 %a1, i64 %a2) {
entry:
%r = call i64 @ail_max3_max3(i64 %a0, i64 %a1, i64 %a2)
ret i64 %r
}
define i8 @ail_max3_main() {
entry:
%v1 = call i64 @ail_max3_max3(i64 3, i64 17, i64 9)
%v2 = call i8 @ail_prelude_print__Int(i64 %v1)
ret i8 %v2
}
define i8 @ail_max3_main_adapter(ptr %_env) {
entry:
%r = call i8 @ail_max3_main()
ret i8 %r
}
define i1 @ail_prelude_float_eq(double %arg_x, double %arg_y) alwaysinline {
entry:
%v1 = fcmp oeq double %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_float_eq_adapter(ptr %_env, double %a0, double %a1) {
entry:
%r = call i1 @ail_prelude_float_eq(double %a0, double %a1)
ret i1 %r
}
define i1 @ail_prelude_float_ne(double %arg_x, double %arg_y) alwaysinline {
entry:
%v1 = fcmp une double %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_float_ne_adapter(ptr %_env, double %a0, double %a1) {
entry:
%r = call i1 @ail_prelude_float_ne(double %a0, double %a1)
ret i1 %r
}
define i1 @ail_prelude_float_lt(double %arg_x, double %arg_y) alwaysinline {
entry:
%v1 = fcmp olt double %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_float_lt_adapter(ptr %_env, double %a0, double %a1) {
entry:
%r = call i1 @ail_prelude_float_lt(double %a0, double %a1)
ret i1 %r
}
define i1 @ail_prelude_float_le(double %arg_x, double %arg_y) alwaysinline {
entry:
%v1 = fcmp ole double %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_float_le_adapter(ptr %_env, double %a0, double %a1) {
entry:
%r = call i1 @ail_prelude_float_le(double %a0, double %a1)
ret i1 %r
}
define i1 @ail_prelude_float_gt(double %arg_x, double %arg_y) alwaysinline {
entry:
%v1 = fcmp ogt double %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_float_gt_adapter(ptr %_env, double %a0, double %a1) {
entry:
%r = call i1 @ail_prelude_float_gt(double %a0, double %a1)
ret i1 %r
}
define i1 @ail_prelude_float_ge(double %arg_x, double %arg_y) alwaysinline {
entry:
%v1 = fcmp oge double %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_float_ge_adapter(ptr %_env, double %a0, double %a1) {
entry:
%r = call i1 @ail_prelude_float_ge(double %a0, double %a1)
ret i1 %r
}
define ptr @ail_prelude_compare__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
entry:
%v1 = icmp slt i64 %arg_x, %arg_y
br i1 %v1, label %cmp_lt_2, label %cmp_after_lt_2
cmp_lt_2:
%v3 = call ptr @ailang_rc_alloc(i64 8)
store i64 0, ptr %v3, align 8
ret ptr %v3
cmp_after_lt_2:
%v4 = icmp eq i64 %arg_x, %arg_y
br i1 %v4, label %cmp_eq_2, label %cmp_gt_2
cmp_eq_2:
%v5 = call ptr @ailang_rc_alloc(i64 8)
store i64 1, ptr %v5, align 8
ret ptr %v5
cmp_gt_2:
%v6 = call ptr @ailang_rc_alloc(i64 8)
store i64 2, ptr %v6, align 8
ret ptr %v6
}
define ptr @ail_prelude_compare__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
entry:
%r = call ptr @ail_prelude_compare__Int(i64 %a0, i64 %a1)
ret ptr %r
}
define i1 @ail_prelude_gt__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
entry:
%v1 = icmp sgt i64 %arg_x, %arg_y
ret i1 %v1
}
define i1 @ail_prelude_gt__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
entry:
%r = call i1 @ail_prelude_gt__Int(i64 %a0, i64 %a1)
ret i1 %r
}
define ptr @ail_prelude_show__Int(i64 %arg_x) {
entry:
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
ret ptr %v1
}
define ptr @ail_prelude_show__Int_adapter(ptr %_env, i64 %a0) {
entry:
%r = call ptr @ail_prelude_show__Int(i64 %a0)
ret ptr %r
}
define i8 @ail_prelude_print__Int(i64 %arg_x) {
entry:
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
%v3 = load ptr, ptr @stdout, align 8
call i32 @fputs(ptr %v2, ptr %v3)
call void @ailang_rc_dec(ptr %v1)
ret i8 0
}
define i8 @ail_prelude_print__Int_adapter(ptr %_env, i64 %a0) {
entry:
%r = call i8 @ail_prelude_print__Int(i64 %a0)
ret i8 %r
}
define void @drop_prelude_Ordering(ptr %p) {
entry:
%is_null = icmp eq ptr %p, null
br i1 %is_null, label %ret, label %live
live:
%tag = load i64, ptr %p, align 8
switch i64 %tag, label %dflt [
i64 0, label %arm_0
i64 1, label %arm_1
i64 2, label %arm_2
]
arm_0:
br label %join
arm_1:
br label %join
arm_2:
br label %join
dflt:
unreachable
join:
call void @ailang_rc_dec(ptr %p)
br label %ret
ret:
ret void
}
define void @partial_drop_prelude_Ordering(ptr %p, i64 %mask) {
entry:
%is_null = icmp eq ptr %p, null
br i1 %is_null, label %ret, label %live
live:
%tag = load i64, ptr %p, align 8
switch i64 %tag, label %dflt [
i64 0, label %arm_0
i64 1, label %arm_1
i64 2, label %arm_2
]
arm_0:
br label %join
arm_1:
br label %join
arm_2:
br label %join
dflt:
unreachable
join:
call void @ailang_rc_dec(ptr %p)
br label %ret
ret:
ret void
}
define i32 @main() {
call i8 @ail_max3_main()
ret i32 0
}