Continuing the falcon dispatch story (index #650 ✓, null-slot #664 ✓ — thank you, both confirmed fixed against the real build). v0.36.0's note said "falcon's dispatch story complete", but verifying synth v0.37.0 on the actual fused falcon core shows the same 20 functions decline one layer deeper — the closed-world check now finds a type-signature mismatch:
call_indirect (expected type 3, table 1): closed-world type check failed — table 1 entry
(function 93, type 7) has a different signature than expected type 3 — a runtime type check
is not implementable on the raw code-pointer table; refusing to emit an unchecked indirect branch
Root cause: heterogeneous funcref table
falcon's fused (table 1 41) is a single heterogeneous elem segment of 40 functions spanning multiple signatures (type 3 = (i32 i32)→i32, type 7 = (i32 i32 i32 i32)→i32, …). Each call_indirect site expects one specific type; at runtime the index always selects a correctly-typed entry (falcon passes wasmtime SIL), but statically the table also holds other-typed entries, so the closed-world verifier can't prove type-safety and — lacking a runtime type check — declines all 20.
This is valid wasm: heterogeneous tables are legal, and a call_indirect type mismatch is a runtime trap (WASM 4.4.8), not a validation error. So the sound lowering is the runtime type check itself.
Minimal repro
(module
(type $t2 (func (param i32 i32) (result i32)))
(type $t4 (func (param i32 i32 i32 i32) (result i32)))
(table $tab 2 2 funcref)
(func $add2 (type $t2) (i32.add (local.get 0) (local.get 1)))
(func $sum4 (type $t4) (i32.const 4))
(elem (table $tab) (i32.const 0) func $add2 $sum4) ;; slot0=t2, slot1=t4 — heterogeneous
(func (export "dispatch") (param $sel i32) (result i32)
(call_indirect $tab (type $t2) (i32.const 7) (i32.const 8) (local.get $sel))))
synth compile -t cortex-m7dp → skips 'dispatch': table 0 entry (function 1, type 1)
has a different signature than expected type 0
Suggested fix (subsumes the null-slot case)
A per-slot type-id sidecar: alongside the code-pointer table, emit a parallel u32 type_id[] (structural-type hash / dense type index). At each call_indirect: bounds-check; load type_id[idx]; CMP expected_type_id; BNE → UDF (trap); BLX. This is exactly the WASM-mandated runtime check, and a reserved type_id = 0 for null slots generalizes #664's null-trap in the same mechanism.
jess impact
The same 20 falcon funcs (the whole table-1 dispatch cluster). Inventory on v0.37.0 unchanged at 46/146 = 24 #369 float + 20 heterogeneous-table CI (this) + 1 #518 + 1 #503. All still behind #369, so no urgency — flagging with the repro so the "dispatch complete" milestone is accurate. (Minor aside: meld emits 31 type decls for 25 distinct signatures — 6 structural dups — harmless here since your check is structural, noting in case it matters for the type-id densification.)
Thanks again for the sustained turnaround on this cluster.
Continuing the falcon dispatch story (index #650 ✓, null-slot #664 ✓ — thank you, both confirmed fixed against the real build). v0.36.0's note said "falcon's dispatch story complete", but verifying synth v0.37.0 on the actual fused falcon core shows the same 20 functions decline one layer deeper — the closed-world check now finds a type-signature mismatch:
Root cause: heterogeneous funcref table
falcon's fused
(table 1 41)is a single heterogeneous elem segment of 40 functions spanning multiple signatures (type 3 =(i32 i32)→i32, type 7 =(i32 i32 i32 i32)→i32, …). Eachcall_indirectsite expects one specific type; at runtime the index always selects a correctly-typed entry (falcon passes wasmtime SIL), but statically the table also holds other-typed entries, so the closed-world verifier can't prove type-safety and — lacking a runtime type check — declines all 20.This is valid wasm: heterogeneous tables are legal, and a
call_indirecttype mismatch is a runtime trap (WASM 4.4.8), not a validation error. So the sound lowering is the runtime type check itself.Minimal repro
Suggested fix (subsumes the null-slot case)
A per-slot type-id sidecar: alongside the code-pointer table, emit a parallel
u32 type_id[](structural-type hash / dense type index). At eachcall_indirect:bounds-check; load type_id[idx]; CMP expected_type_id; BNE → UDF (trap); BLX. This is exactly the WASM-mandated runtime check, and a reservedtype_id = 0for null slots generalizes #664's null-trap in the same mechanism.jess impact
The same 20 falcon funcs (the whole table-1 dispatch cluster). Inventory on v0.37.0 unchanged at 46/146 = 24 #369 float + 20 heterogeneous-table CI (this) + 1 #518 + 1 #503. All still behind #369, so no urgency — flagging with the repro so the "dispatch complete" milestone is accurate. (Minor aside: meld emits 31 type decls for 25 distinct signatures — 6 structural dups — harmless here since your check is structural, noting in case it matters for the type-id densification.)
Thanks again for the sustained turnaround on this cluster.