You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
index (U007) and concat (U004): see a List.get / append that the loop reaches through a helper or a continuation #198
Found while profiling bolt lint (branch autoresearch/bolt-lint-perf). Both rules only look at the recursive def's own body, so the same quadratic hides one call away.
That's one List.get from line 0 per binder: 22k binders over 30k lines took ~20 s on bolt/rules/PROOF.bend. A cursor in source order fixed it (binder 35 s to 15.6 s). U007 didn't fire. It did fire on my first version of the fix, where the fallback List.get sat inline in the recursive def. Moving that fallback into a helper silences U007 the same way the original code did.
concat: append onto an accumulator through a continuation
bolt/lsp/files/disk.bend:
def slurp.cut(bytes, file, acc, rest: File -> List<&2, U32> -> IO(..)) -> IO(..):
match bytes:
case Con{b, t}:
rest(file, List.append(&2, U32, acc, b <> t)) # rest is `fl => a => slurp(f, fl, a)`
Each 64 KB chunk appends onto everything read so far, which is quadratic in chunks. It's small in bolt (~0.2 s over the tree), but it's the textbook concat shape, and it's invisible because the loop goes slurp -> slurp.next -> slurp.cut -> rest(..).
Proposal
index: also report a List.get/String.get with a non-literal index in a non-recursive def of the file that a recursive def calls on its recursive path. Name the helper and the loop in the message.
concat: treat a call to a parameter that the loop passes as x => .. => self(..) like a self-call. Or more simply: an argument List.append(.., acc, ..) where acc is a parameter, passed to a function-typed parameter.
Activity