Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up"RangeError: Maximum call stack size exceeded" When concatenating to a function with a large array #389
Comments
|
It's possible it is hitting some recursive function in JavaScript, but will have to do more investigating to know for sure |
|
The problem here is specific to concatenation using the current function. Since the call itself is not in what ElixirScript considers the tail position, it causes a stack overflow. The code is in the generation of function filter_list(...__function_args__) {
function recur(...__function_args__) {
let __arg_matches__ = null;
if ((__arg_matches__ = ElixirScript.Core.Patterns.match_or_default([ElixirScript.Core.Patterns.headTail(ElixirScript.Core.Patterns.variable('head'), ElixirScript.Core.Patterns.variable('tail')), ElixirScript.Core.Patterns.variable('fun')], __function_args__, (head0, tail0, fun0) => {
return true;
})) !== null) {
let [head0, tail0, fun0] = __arg_matches__;
return ElixirScript.Core.Patterns.defmatch(ElixirScript.Core.Patterns.clause([ElixirScript.Core.Patterns.variable('x576460752303352111')], (x5764607523033521110) => {
return new ElixirScript.Core.Functions.Recurse(recur.bind(null, tail0, fun0));
}, (x5764607523033521110) => {
return x5764607523033521110 === null || x5764607523033521110 === false;
}), ElixirScript.Core.Patterns.clause([ElixirScript.Core.Patterns.variable('_')], () => {
// ERROR: stackoverflow causing line here
return ElixirScript.Core.Functions.concat(head0, filter_list(tail0, fun0));
// END ERROR
}, () => {
return true;
})).call(this, fun0(head0));
} else if ((__arg_matches__ = ElixirScript.Core.Patterns.match_or_default([[], ElixirScript.Core.Patterns.variable('_fun')], __function_args__, (_fun0) => {
return true;
})) !== null) {
let [_fun0] = __arg_matches__;
return [];
}
throw new ElixirScript.Core.Patterns.MatchError(__function_args__);
}
return ElixirScript.Core.Functions.trampoline(new ElixirScript.Core.Functions.Recurse(recur.bind(null, ...__function_args__)));
} |
|
The error can be resolved with a better way of prepending the head of an item to a list if the list is being generated from a function. To make it clearer, in Elixir it's this line: |
|
The problem is the AST generated from this [head | filter_list(tail, fun)], when compiled to JS right?
Just needs to transcompile better? Why I ask, because rewriting Enum.filter/2 for ElixirScript would not fix the core problem? |
|
Correct. I'm thinking that rewriting concatenation when a function is last will help. Still using the breaking case, this: ElixirScript.Core.Functions.concat(head0, filter_list(tail0, fun0));Can instead be translated into this: ElixirScript.Core.Functions.concat(head0, () => {
return new ElixirScript.Core.Functions.Recurse(recur.bind(null, tail0, fun0));
});
It's just a thought, but I'll have time to test it out later |
|
No success with that approach
|
EDIT: I tested recursive functions and they seem unaffected by this. It seems isolated only to Enum.filter.
Maximum callstack size on chrome is 10402. Calling Enum.filter on collections of size 1000+ ends up crashing with this
I think its to do with how the code got generated.
The very end has a filter children = Enum.filter(children, &(&1!=nil)), it crashses inside the filter.
It seems as if 10+ callstack frames are being allocated per Enum.filter iteration there.
See for yourself with the directly above code.