EXPERIMENT: Int return types as data — and the bug that fell out

PREDICTIONS AND RESULTS
  P1 is_int_call's 35 hardcoded names move to data        TRUE
  P2 is_int_name stays -- it is annotation propagation    TRUE
  P3 the dispatch stays -- it is emission                 TRUE
  P4 codegen shrinks ~40 lines                            TRUE  4507 -> 4469
  P5 the design doc's characterisation is WRONG           TRUE
  P6 the moved data also fixes the bug it exposed         TRUE

P5 CORRECTS THE RECORD. el-language-design.md and geometry-vs-code.md both cite
"== lowering to str_eq unless both operand names are in a hardcoded int-name
set -- a literal list of variable names treated as integers" as the paradigm
defect. It is not one. __int_names is populated from TYPE ANNOTATIONS
(param["type"] == "Int"), which is primitive but legitimate type propagation.
The actual defect was is_int_call: 35 hardcoded builtin return types, the same
shape as the temporal 19.

P6 IS A LIVE CORRECTNESS BUG, PRE-EXISTING, NOW FIXED

    let a = str_len("hello")     // no annotation
    let b = str_len("hi")
    let c = a + b                // -> el_str_concat(a, b) on two integers

Verified identical on the pre-change compiler, so not a regression. It compiled
clean, ran, and printed NOTHING where it should print 7. No error at any layer.

The repair is three lines: an unannotated let takes its type from what the
initialiser returns. The return types were already required for dispatch and
were simply never consulted at the binding site. Moving them into data is what
made the gap visible -- reading the code for eight hours did not.

98/98 native + 2 new, 31/31 integration, fixpoint ok.
This commit is contained in:
bigmerge
2026-08-17 09:32:13 -05:00
parent 50425f375d
commit cbef1c1ebb
3 changed files with 71 additions and 40 deletions
+40
View File
@@ -31,3 +31,43 @@ el_duration_sub returns Duration
el_duration_scale returns Duration
el_duration_div returns Duration
ttl_cache_age returns Duration
# Int-returning builtins. Previously 35 hardcoded names in is_int_call().
# These decide whether `a + b` is arithmetic or concatenation, so the
# compiler reads them at emission time -- dispatch, not adjudication.
str_len returns Int
str_index_of returns Int
str_to_int returns Int
str_char_code returns Int
str_count returns Int
str_count_chars returns Int
str_count_bytes returns Int
str_count_lines returns Int
str_count_words returns Int
str_count_letters returns Int
str_count_digits returns Int
str_last_index_of returns Int
str_find_chars returns Int
native_list_len returns Int
el_list_len returns Int
len returns Int
json_get_int returns Int
json_array_len returns Int
engram_node_count returns Int
engram_edge_count returns Int
time_now returns Int
time_now_utc returns Int
time_diff returns Int
time_add returns Int
time_from_parts returns Int
el_abs returns Int
el_max returns Int
el_min returns Int
float_to_int returns Int
unix_timestamp returns Int
instant_to_unix_seconds returns Int
instant_to_unix_millis returns Int
duration_to_seconds returns Int
duration_to_millis returns Int
duration_to_nanos returns Int