elm/compiler

Valid recursion leads to runtime error

jvoigtlaender opened this issue · 3 comments

Edited by @evancz

The following program leads to a runtime error ("g is not a function").

import Html

g = h

h n =
  if n < 2 then 1 else g (n - 1)

main = Html.text (toString (h 10))

With the 0.18 compiler, it produces this JavaScript:

var _user$project$Main$g = _user$project$Main$h;
var _user$project$Main$h = function (n) {
	return (_elm_lang$core$Native_Utils.cmp(n, 2) < 0) ? 1 : _user$project$Main$g(n - 1);
};
var _user$project$Main$main = _elm_lang$virtual_dom$Native_VirtualDom.staticProgram(
	_elm_lang$html$Html$text(
		_elm_lang$core$Basics$toString(
			_user$project$Main$h(10))));

If the var definitions for _user$project$Main$g and _user$project$Main$h were reordered, everything would be fine. It is unclear how to detect this in general, so no concrete steps are proposed to fix this right now.


The following two programs are equivalent, but do run successfully:

import Html

h n =
  if n < 2 then 1 else g (n - 1)

g = h

main = Html.text (toString (h 10))
import Html

h n =
  if n < 2 then 1 else h (n - 1)

main = Html.text (toString (h 10))

Reproduced on elm 0.17. The issue is that the order of definition is incorrect.

RuntimeError Elm

-- leads to a runtime error "g is not a function"
import Html
g = h
h n =
    if n < 2 then
        1
    else
        g (n - 1)

main = Html.text (toString (h 10))

produces:

var _user$project$Main$g = _user$project$Main$h;
var _user$project$Main$h = function (n) {
    return (_elm_lang$core$Native_Utils.cmp(n, 2) < 0) ? 1 : _user$project$Main$g(n - 1);
};
var _user$project$Main$main = {
    main: _elm_lang$html$Html$text(
        _elm_lang$core$Basics$toString(
            _user$project$Main$h(10)))
};

Valid Elm

import Html
h n =
  if n < 2 then
      1
  else
      g (n - 1)
g = h

main = Html.text (toString (h 10))

produces:

var _user$project$Main$h = function (n) {
    return (_elm_lang$core$Native_Utils.cmp(n, 2) < 0) ? 1 : _user$project$Main$g(n - 1);
};
var _user$project$Main$g = _user$project$Main$h;
var _user$project$Main$main = {
    main: _elm_lang$html$Html$text(
        _elm_lang$core$Basics$toString(
            _user$project$Main$h(10)))
};

Added all of these to #1377 so it can be addressed alongside a bunch of similar issues.

Thanks for the report!

With latest version of the compiler, it generates this:

var user$project$Main$h = function (n) {
	return (_Utils_cmp(n, 2) < 0) ? 1 : user$project$Main$g(n - 1);
};
var user$project$Main$g = user$project$Main$h;
var user$project$Main$main = _VirtualDom_staticProgram(
	elm_lang$html$Html$text(
		elm_lang$core$Basics$toString(
			user$project$Main$h(10))));

So the program runs as expected. Thanks for the report!