ghcjs / ghcjs-base

base library for GHCJS for JavaScript interaction and marshalling, used by higher level libraries like JSC
MIT License
45 stars 67 forks source link

JSArray.fromListIO is missing a JSRef constructor #27

Closed wuzzeb closed 9 years ago

wuzzeb commented 9 years ago

Here is the simple test program

module Main where

import GHCJS.Marshal
import GHCJS.Types
import JavaScript.Array (fromListIO, JSArray)

foreign import javascript unsafe
    "console.log($1)"
    js_log :: JSArray -> IO ()

main :: IO ()
main = do
    e <- fromListIO =<< mapM toJSRef ([1, 15, 25] :: [Int])
    js_log e

When I run it with node, I get the error

uncaught exception in Haskell main thread: TypeError: Cannot read property 't' of undefined
TypeError: Cannot read property 't' of undefined
    at h$e (/home/wuzzeb/projects/react-flux/dist/build/test/test.jsexe/all.js:20397:20)
    at h$$lG (/home/wuzzeb/projects/react-flux/dist/build/test/test.jsexe/all.js:37675:10)
    at Immediate.h$mainLoop (/home/wuzzeb/projects/react-flux/dist/build/test/test.jsexe/all.js:9798:25)
    at processImmediate [as _immediateCallback] (timers.js:367:17)

The functions look like

function h$$lG()
{
  var a = h$stack[(h$sp - 1)];
  h$sp -= 2;
  var b = h$fromHsListJSRef(a);
  h$p1(h$$lH);
  return h$e(b);
};

....

function h$e(h$RTS_578)
{
  h$r1 = h$RTS_578;
  if((typeof h$RTS_578 !== "object"))
  {
    return h$stack[h$sp];
  };
  var h$RTS_579 = h$RTS_578.f;
  if((h$RTS_579 === h$unbox_e))
  {
    h$r1 = h$RTS_578.d1;
    return h$stack[h$sp];
  };
  if (!h$RTS_579) { return h$RTS_579; }
  switch (h$RTS_579.t)
  {

...

I added a console.log to h$$lG, and the variable b inside it the javascript list [1, 15, 25]. The function h$e goes on to access the f property of this list which is undefined.

What I guess is the error is that fromListIO is defined as

fromListIO xs = IO (\s -> rnf xs `seq` js_toJSArray (unsafeCoerce xs) s)

foreign import javascript unsafe "h$fromHsListJSRef($1)"
  js_toJSArray :: Exts.Any -> State# s -> (# State# s, SomeJSArray m #)

But h$fromHsListJSRef returns a javascript array and we never put a JSRef constructor on this javascript array. I suspect that js_toJSArray should change to

foreign import javascript unsafe "h$fromHsListJSRef($1)"
 js_toJSArray :: Exts.Any -> IO (SomeJSArray m)

But I don't know why js_toJSArray was defined to expose the State# in the first place.

luite commented 9 years ago

This is the same problem as #21, the reason is that unboxed tuple returns aren't automatically wrapped yet. I'll change that in GHCJS soon, apologies for the problem.

int-index commented 9 years ago

Also the same problem as https://github.com/ghcjs/ghcjs/issues/392.

luite commented 9 years ago

Has been fixed by a change in desugaring foreign imports. Make sure that your GHCJS and boot libraries (run ghcjs-boot with the --clean option to be sure) are up to date if you still see problems like this.