Elm Stack Saver

This might come in handy if you are having issues with stack overflows. It tries to detect all recursion which is not tail optimized. It will detect individual recursive functions as well as mutually recursive cycles of functions, and also functions defined inside let..in blocks.

There are some more ‘dynamic’ situations it can miss, such as if recursion happens within runtime created closures.

It works by scanning an elm.js compiler output and building the call graph from that, then applying Tarjan’s algorithm to detect cycles. The JS function names are converted back into Elm formatted names, unless you specified the --jsnames CLI option.

13 Likes

And after that… it turns out that my stack overflow bug is actually the same as this one, which is an elm compiler error, and does not show up as a loop in my stack saver scan!

Now I wonder if I could pick this up from scanning the javascript and looking for the mutated variable that causes :thinking:

Great contribution! I am going scan my scripta compiler with this. Haven’t experienced any stack overflows but that doesn’t prove anything.

I have no real idea about the best way to distribute python programs. This one has a few dependencies:

import argparse
import re
import sys
from collections import defaultdict

Which must exist on my system already, since I can run it with python3 ess without explicitly setting up the dependencies. But it maybe needs a proper way of installing/sharing it in the world of python - or rewrite it in something else.

I just pushed an update that adds TCO closure capture bug detection.

1 Like

When hitting these stack overflow errors (or before hitting them), the elm-review rule NoUnoptimizedRecursion might also be helpful/relevant.

But being able to catch these across multiple declarations AND in packages can be really useful. I’ll keep this in my toolbox, thanks!

I’m thinking it could be nice to present these cycles not by cycle count (not sure that’s very interesting) but rather by origin. Is this a recursion loop that comes from a package (and if so which one), or one from the project’s code?
I’m thinking there could be a section for each package, starting (or ending, depending what you think is going to look most relevant to the user) with the local code.

argparse, re and sys are in the standard library, which ships with Python itself.

The hyped uv tool allows declaring external script dependencies in a comment at the top of the file. That seems like a good fit for a little script like yours.

(I used to be a bit into Python 5+ years ago and still follow the Python world a bit, but I haven’t tried uv myself, just read and heard about it.)

2 Likes

collections is also in the standard library

1 Like

The tail-call closure capture bug is fixed in Zokka I think ? Just thinking, if there is going to be an Elm 0.19.2 to address some of the recent CI issues, it might be worth trying to get that fix, or equivalent, in that release too? You will likely run into this bug if doing continuation passing style with TCO.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.