Skip to content

Commit d792672

Browse files
Fix float truncation in arr_get/dict_get arithmetic
The compiler's static type table claimed arr_get / dict_get / arr_min / arr_max / arr_sum always return int. They don't — they're polymorphic over the element type. The lie made h sum = arr_get(cur, 1) + rating; # rating is float compile to Op::AddInt (the typed fast-path), which calls .to_int() on both operands and silently truncates the float. Caught by a real ratings aggregator: summing 4.5 + 3.5 + 5.0 returned 12 instead of 13.0 under VM (tree-walk was fine — its eval_expr inspects values at runtime, not types at compile time). Tree-walk and VM both wrong-but- in-different-ways for some shapes. Removed the polymorphic builtins from the int-return list. They now have no static return type, so any arithmetic that uses them goes through Op::Add (the polymorphic dispatch) and respects runtime types. The four other names that legitimately return int regardless of input (arr_len, len, arr_index_of, arr_contains) stay in the table. Found while building examples/recommend/recommend.omc — a real movie recommendation engine over MovieLens ratings (10k → 100k). VM and tree-walk now agree on hit counts. 92/92 unit tests pass. 43/43 functional examples produce identical output under tree-walk and VM. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent e434626 commit d792672

1 file changed

Lines changed: 10 additions & 2 deletions

File tree

omnimcode-core/src/compiler.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,19 @@ impl Compiler {
134134
self.fn_return_types.get(name.as_str()).copied().or_else(|| {
135135
// Built-ins whose return type is fixed.
136136
match name.as_str() {
137+
// Truly int-returning builtins. Polymorphic ones
138+
// (arr_get, dict_get, arr_min/max/sum — return value
139+
// depends on the element type) are deliberately
140+
// EXCLUDED. Listing them here causes the compiler
141+
// to emit Op::AddInt for `arr_get(...) + x`, which
142+
// calls .to_int() on both operands and silently
143+
// truncates floats. Caught by a real-world float-
144+
// accumulator pattern in examples/recommend.
137145
"fibonacci" | "fib" | "is_fibonacci" | "factorial"
138146
| "abs" | "floor" | "ceil" | "round" | "is_prime"
139147
| "even" | "odd" | "is_even" | "is_odd"
140-
| "len" | "arr_len" | "arr_min" | "arr_max"
141-
| "arr_sum" | "arr_get" | "arr_index_of" | "arr_contains"
148+
| "len" | "arr_len"
149+
| "arr_index_of" | "arr_contains"
142150
| "is_singularity" | "resolve_singularity"
143151
| "pow_int" | "square" | "cube" | "sign" | "to_int"
144152
| "int" | "classify_resonance" | "safe_add" | "safe_sub"

0 commit comments

Comments
 (0)