eclipse-archived/ceylon

Runtime error in JS calling private constructor

Closed this issue · 3 comments

The code below (and also version 2 of this gist fails with:

error undefined — Runtime error:
error undefined — --- ReferenceError: Can't find variable: Trie$c_$doiss5$gac

It works if the constructor is made shared (as was done in the gist).

// **NOTE** doesn't work on JS backend!
shared void run() {
    variable value t = Trie<Integer>();
    value count = 256;
    
    // create a list of ints
    for (i in 0:count) {
        t = t.withTrailing(i);
    }

    // update the values
    for (i in 0:count) {
        t = t.withValue(i, -i);
    }

    printAll(t);
}

alias StorageArray<out Element>
    =>  Array<out Chunk<Element>?>;

class Chunk<out Element>(data, children) {
    shared Element data;
    shared StorageArray<Element>? children;
}

shared class Trie<out Element> satisfies List<Element> {
    StorageArray<Element>? contents;

    shared actual Integer size;

    shared new () {
        size = 0;
        contents = null;
    }

    new create(Integer size, StorageArray<Element> contents) {
        this.size = size;
        this.contents = contents;
    }

    Element unsafeGet(Integer index) {
        assert (0 <= index < size);
        assert (exists contents);
        if (index < 32) {
            assert (exists chunk = contents.get(index));
            return chunk.data;
        }
        variable value c = contents;
        variable value p = path(index);
        for (i in p.exceptLast) {
            assert (exists cc = c.get(i)?.children);
            c = cc;
        }
        assert (exists chunk = c.get(index.and(31)));
        return chunk.data;
    }

    "Return an efficient copy of this [[Trie]] with the given [[item]] appended."
    shared Trie<Element | Other> withTrailing<Other>(Other item)
        =>  withValue(size, item);

    "Return an efficient copy of this [[Trie]], replacing the value at the given
     [[index]] with [[item]]. [[index]] must be no greater than [[lastIndex + 1]]."
    shared Trie<Element | Other> withValue<Other>(Integer index, Other item) {
        assert (0 <= index <= size); // allow appending

        value path = this.path(index);
        assert (exists firstIndex = path.first);

        value newContents = copyArray<Chunk<Element | Other>?>(
                contents, null, firstIndex + 1);

        variable value arrayToUpdate = newContents;

        for ([curIdx, nextIdx] in path.paired) {
            assert (exists vectorToReplace = arrayToUpdate.get(curIdx));
            value children = vectorToReplace.children;
            value newArray = copyArray(children, null, nextIdx+1);
            value newVector = Chunk(vectorToReplace.data, newArray);
            arrayToUpdate.set(curIdx, newVector);
            arrayToUpdate = newArray;
        }

        assert (exists idx = path.last);
        value oldVector = arrayToUpdate.get(idx);
        arrayToUpdate.set(idx, Chunk(item, oldVector?.children));

        return Trie.create(Integer.largest(size, index + 1), newContents);
    }

    getFromFirst(Integer index) => if (index < size) then unsafeGet(index) else null;

    lastIndex => size > 0 then size - 1;

    iterator() => object satisfies Iterator<Element> {
        // TODO optimize?
        variable value i = 0;
        next() => if (i == size) then finished else unsafeGet(i++);
    };

    hash => (super of List<Element>).hash;

    equals(Object other) => (super of List<Element>).equals(other);

    "Basically, [[index]] in base-32"
    [Integer*] path(Integer index)
        =>  loop(index)((i)
                =>  if (i.rightLogicalShift(5).zero)
                    then finished
                    else i.rightLogicalShift(5))
                        .collect((i) => i.and(31))
                        .reversed;

    "Return a copy of [[source]] at least as large as [[minSize]]"
    Array<Element> copyArray<Element>(
            Array<out Element>? source,
            Element fillItem,
            Integer minSize) {
        if (!exists source) {
            return Array<Element>.ofSize(minSize, fillItem);
        } else if (minSize <= source.size) {
            return Array<Element>(source);
        } else {
            value result = Array<Element>.ofSize(minSize, fillItem);
            source.copyTo(result);
            return result;
        }
    }
}

@chochos would you please take a look at this one. I would love to have this fixed for 1.3.3.

OK it seems the invocation uses the private name but the constructor is defined as if it was shared (naming is different). I guess the correct thing is to generate it with the private name.

A much simpler way to reproduce this:

shared class SevenOneTwoTwo {
  shared Integer x;

  shared new() {
    x = 0;
  }

  new withInt(Integer i) {
    x = i;
  }

  shared SevenOneTwoTwo add(Integer i) {
    return SevenOneTwoTwo.withInt(x + i);
  }

  string = "Value:``x``";
}

shared void run() {
  print(SevenOneTwoTwo().add(5));
}

I'm close to solving this