Skip to content

fix: at xs i auto-floors fractional indices#304

Merged
danieljohnmorris merged 5 commits into
mainfrom
fix/at-auto-floor-float-index
May 16, 2026
Merged

fix: at xs i auto-floors fractional indices#304
danieljohnmorris merged 5 commits into
mainfrom
fix/at-auto-floor-float-index

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

at xs i used to error with ILO-R009 at: index must be an integer whenever i came from arithmetic like / k 2 or any other division. Every persona writing the median-bucket idiom (at xs (len/2)) had to wrap the index in flr (originating entry: html-scraper rerun3 friction #3, ilo_assessment_feedback.md:2542).

Auto-flooring at the at builtin boundary kills the ceremony. The fract!=0 guard is dropped across tree, VM, and Cranelift, and the index is .floor() as i64-ed before the existing negative-index resolution and bounds check. Non-numeric still errors.

Repro

Before:

$ ilo 'f>n;xs=[10,20,30,40,50];k=len xs;i=/ k 2;at xs i' --run-tree f
{"code":"ILO-R009","message":"at: index must be an integer",...}

After:

$ ilo 'f>n;xs=[10,20,30,40,50];k=len xs;i=/ k 2;at xs i' --run-tree f
30

What's in the diff

  • interp: drop fract!=0 guard, floor the numeric index, unit tests for positive frac / negative frac / non-numeric error guard.
  • vm: same change in OP_AT and jit_at. Replaces the jit_at_fractional_index_returns_nil unit test with three positive-coverage tests (1.7 → 1, -0.5 → -1, -1.5 → -2).
  • test: cross-engine regression (tests/regression_at_builtin.rs) covering at xs 1.0, at xs 1.7, at xs -1.5, at xs -0.5, the computed-float len/2 idiom, and a preserved non-numeric error case. Removes the obsolete at_fractional_index_span_matches_vm (jit_at span parity stays covered by the existing OOB tests).
  • example: examples/at-float-index.ilo pins the new contract with -- run: / -- out: assertions so examples_engines exercises it across every engine.
  • docs: one-line note in SPEC.md, ai.txt, skills/ilo/SKILL.md. Site builtins.md gets a separate PR in ilo-lang/site.

Floor semantics: negative fractions go toward negative infinity, so at xs -0.5 == at xs -1 (last element) and at xs -1.5 == at xs -2 (second-from-last on a len-3 list). Consistent with how flr is documented elsewhere.

Test plan

  • cargo test --release --features cranelift clean (all suites)
  • regression_at_builtin covers tree / vm / cranelift for: integer index, integral float, positive frac, negative frac, negative half (was the prior error case), computed-float idiom, and non-numeric error preservation
  • interp_at_fractional_index_floors + negative-frac + non-numeric variants in the tree-walker
  • jit_at_fractional_*_floors x3 in the JIT helper
  • examples_engines runs examples/at-float-index.ilo across every engine
  • cargo fmt --check clean
  • cargo clippy --release --features cranelift --tests -- -D warnings clean

Follow-ups

  • Site docs/reference/builtins.md was missing at entirely; row added in a parallel commit to the site repo.

Previously `at xs 1.5` errored with "index must be an integer", forcing
every `at xs (/ k 2)` idiom (median bucket and similar) to be wrapped in
`flr`. Drop the fract!=0 guard and `.floor() as i64` the numeric value
before the existing negative-index resolution + bounds check.

Negative fractions floor toward negative infinity, so `at xs -0.5` lands
on `-1` (the last element after Python-style resolution). Non-numeric
indices still error.

Replaces interp_at_fractional_index_errors with three coverage tests for
the new contract: positive fractional, negative fractional, and the
non-numeric error guard.
Mirrors the interpreter change for the register VM (OP_AT) and the
Cranelift JIT helper (jit_at). Both drop the fract!=0 guard and floor
the numeric index before the existing negative-index resolution.

Replaces the jit_at_fractional_index_returns_nil unit test with three
positive-coverage tests pinning the auto-floor contract: 1.7 floors to
1, -0.5 floors to -1, -1.5 floors to -2.
Adds positive-coverage tests across tree / VM / cranelift for the new
auto-floor contract: `at xs 1.0`, `at xs 1.7`, `at xs -1.5`, `at xs -0.5`,
and the originating `at xs (len/2)` computed-float idiom. Also keeps a
non-numeric-index error test to pin the preserved type guard.

Replaces the prior `at xs -0.5 must error` cases (now positive coverage
for the same input). Removes the fractional-index span-parity test in
regression_cranelift_error_span.rs since that error path no longer
exists; jit_at's runtime error path stays covered by the OOB span tests.
Four functions covering the canonical shapes (frac / neghalf / neg32 /
mid), with `-- run:` / `-- out:` assertions so the examples_engines
harness exercises every engine. `mid` is the originating idiom from the
html-scraper rerun (median bucket via `len xs / 2`).
@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

One-line note in the SPEC builtins table and ai.txt entry; explicit
SKILL.md note under the List builtins line so agents pick up the new
contract without re-reading the full spec.
@danieljohnmorris danieljohnmorris force-pushed the fix/at-auto-floor-float-index branch from 6e232d6 to 8b53f61 Compare May 16, 2026 12:58
@danieljohnmorris danieljohnmorris merged commit d60c8d2 into main May 16, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the fix/at-auto-floor-float-index branch May 16, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant