How to make your crystal program compile reeeeeally slow

Here is a pretty innocent program that takes a really long time to compile if you use --release:

# big.cr — a def that returns a ~163KB struct by value
struct Big
  getter a : StaticArray(UInt64, 20410) # 20410 * 8 = ~163KB

  def initialize
    @a = StaticArray(UInt64, 20410).new(0_u64)
  end
end

def make : Big
  big = Big.new
  big.a[0] = 1_u64
  big # returned by value
end

x = make
y = make
puts x.a[0] + y.a[0]

Depending on the size of the struct it returns, the compile time shoots to pretty much infinite, and may even use all your RAM.

returned struct size debug build release build
1 KB 1.2s 6.3s
4 KB 1.0s 6.3s
16 KB 2.0s 7.5s
64 KB 16.6s 28.9s
256 KB >2 min >5 min
1 MB 1.7s >5 min

More in depth research (it’s LLVM’s fault) here

Yeah this has been a known issue for a decade: code with static arrays is very very slow to compile with the --release flag · Issue #2485 · crystal-lang/crystal · GitHub

I ran into this unexpectedly because I wrote a C binding that returned a large object by value and it triggered the exact same behaviour

Less noticeable is that the a’s in all those .a[0] calls already return the instance variable by reference, not by value, despite it being a StaticArray, because the compiler has special rules for method calls inside a call chain when the method body is exactly an instance variable. Otherwise the build times would have been even longer (and the program wouldn’t work as intended).

Is there a way to detect this at compile time and emit a warning, perhaps with a link to the known issue? I’m not sure what the right threshold would be, but if the compiler sees a StaticArray with a large second parameter, it might be nice to say “don’t do this”.

FWIW, I reckon huge static arrays are rarely ever a good idea.
Regardless of whether the compiler can handle them efficiently or not: Passing huge amounts of memory by value is super inefficient at runtime as well.

So yeah, perhaps a compiler warning would be good in general.
Or a linter rule in ameba?

Agree. This way you don’t need to wait for the compiler. Instant feedback

I have also encountered this issue when using cr_image.

Considering how severe this problem is, I think a simpler approach would be to skip the size check.

Any program that uses a static array should trigger an immediate warning.