eclipse-archived/ceylon

Code compiles but causes JS Runtime error.

Opened this issue · 5 comments

I am experimenting with Ceylon and have produced some code that compiles OK but produces a runtime error. I am using Ceylon 1.3.3, Eclipse (Oxygen.3a). I am compiling into Javascript, which I am running in Waterfox 56.2.3 (64-bit) via an HTML file that does:

require(['test/1.0.0/test-1.0.0' ], function(app) { app.run(); });

The code (trimmed down and abbreviated) is:

object obj1 {
    shared class Item { shared new make() {} }
    shared Item make() { return (if (true) then Item.make else Item.make)(); }
}

shared void run() { obj1.make(); }

The runtime error I get is:

TypeError: this.Item$obj1 is undefined
Stack trace:
Item$obj1$c_make@file:///home/me/eclipse-workspace/test/modules/test/1.0.0/test-1.0.0.js:35:30
$init$obj1/</obj1$.make@file:///home/me/eclipse-workspace/test/modules/test/1.0.0/test-1.0.0.js:23:9
run@file:///home/me/eclipse-workspace/test/modules/test/1.0.0/test-1.0.0.js:73:1
@file:///home/me/eclipse-workspace/test/test.html:23:56
...

The error does not occur if I change the code to:

object obj1 {
    shared class Item { shared new make() {} }
    shared Item make() { return (if (true) then obj1.Item.make else obj1.Item.make)(); }
} //                                            ^^^^^               ^^^^^

shared void run() { obj1.make(); }

or of course:

object obj1 {
    shared class Item { shared new make() {} }
    shared Item make() { return Item.make(); }
}

shared void run() { obj1.make(); }

Surely the code should either work or not compile.

So the difference in the compiled code is:

var obj1$ = this;
return (true ? obj1$.Item$obj1$c_make : obj1$.Item$obj1$c_make)();  //bad

Vs:

var obj1$ = this;
return (true ? ($4 = ($5 = obj1()), m$1.f3$($4, $4.Item$obj1$c_make)) : 
               ($6 = ($7 = obj1()), m$1.f3$($6, $6.Item$obj1$c_make)))();  //OK

So it appears to be some sort of scoping problem where this doesn't refer to quite the right thing.

Note that the bug only affects expressions like Item.make. It does not occur forthis.Item.make.

I guess it's because there is no new anywhere, so this is pointing to the wrong thing.

The problem is in FunctionHelper.generateCallable(), I'm just trying to coax it into generating the right code.

I've fixed this, I believe, but still need to add a test.