TeamShadow / shadow

Reference compiler for the Shadow programming language.
http://shadow-language.org/
Apache License 2.0
12 stars 8 forks source link

Crash on "constant X = X:create()" #24

Closed Brinsky closed 8 years ago

Brinsky commented 9 years ago

I can't seem to initialize a constant to a freshly created object without crashing the compiler. Here's a minimal example of some code that causes the issue:

class Test
{
        private constant Test test = Test:create();

        public create()
        {

        }

        public main(String[] args) => ()
        {

        }
}

This issue occurs regardless of the type in question (I only used Test itself for brevity) and regardless of the constant's visibility. The exception is as follows:

Exception in thread "main" java.lang.NullPointerException
        at shadow.interpreter.ShadowInterpreter.value(ShadowInterpreter.java:370)
        at shadow.interpreter.ShadowInterpreter.visit(ShadowInterpreter.java:179)
        at shadow.tac.nodes.TACCall.accept(TACCall.java:89)
        at shadow.tac.TACAbstractVisitor.visit(TACAbstractVisitor.java:79)
        at shadow.tac.TACAbstractVisitor.walk(TACAbstractVisitor.java:67)
        at shadow.output.llvm.LLVMOutput.writeModuleDefinition(LLVMOutput.java:306)
        at shadow.output.llvm.LLVMOutput.startFile(LLVMOutput.java:529)
        at shadow.output.AbstractOutput.build(AbstractOutput.java:41)
        at shadow.Main.generateLLVM(Main.java:271)
        at shadow.Main.run(Main.java:138)
        at shadow.Main.main(Main.java:68)

I have also seen the following exception under similar circumstances, but I am no longer able to reproduce it:

Exception in thread "main" java.lang.UnsupportedOperationException
        at shadow.interpreter.ShadowInterpreter.visit(ShadowInterpreter.java:17
        at shadow.tac.nodes.TACLoad.accept(TACLoad.java:54)
        at shadow.tac.TACAbstractVisitor.visit(TACAbstractVisitor.java:79)
        at shadow.tac.TACAbstractVisitor.walk(TACAbstractVisitor.java:67)
        at shadow.output.llvm.LLVMOutput.writeModuleDefinition(LLVMOutput.java:
        at shadow.output.llvm.LLVMOutput.startFile(LLVMOutput.java:529)
        at shadow.output.AbstractOutput.build(AbstractOutput.java:41)
        at shadow.Main.generateLLVM(Main.java:271)
        at shadow.Main.run(Main.java:138)
        at shadow.Main.main(Main.java:68)

Interestingly enough, using a literal string does not cause this issue, while explicitly creating one does. I assume literal strings are handled specially by the compiler, but I thought it was worth noting:

        private constant String a = ""; // Works
        private constant String b = String:create() // Doesn't work
bwittman commented 9 years ago

At present, the creation of arbitrary constant objects is not supported. String constants, numerical constants, and arithmetic and string operations that yield such constants work.

It is a thorny problem that may require additional features or at least additional firepower in the compiler to be able to tell when something is possible and when it isn't.

Regardless, the compiler should give an error message when the interpreter fails, rather than crashing.

On Sun, Sep 6, 2015 at 1:33 PM, Brian notifications@github.com wrote:

I can't seem to initialize a constant to a freshly created object without crashing the compiler. Here's a minimal example of some code that causes the issue:

class Test { private constant Test test = Test:create();

    public create()
    {

    }

    public main(String[] args) => ()
    {

    }

}

This issue occurs regardless of the type in question (I only used Test itself for brevity) and regardless of the constant's visibility. The exception is as follows:

Exception in thread "main" java.lang.NullPointerException at shadow.interpreter.ShadowInterpreter.value(ShadowInterpreter.java:370) at shadow.interpreter.ShadowInterpreter.visit(ShadowInterpreter.java:179) at shadow.tac.nodes.TACCall.accept(TACCall.java:89) at shadow.tac.TACAbstractVisitor.visit(TACAbstractVisitor.java:79) at shadow.tac.TACAbstractVisitor.walk(TACAbstractVisitor.java:67) at shadow.output.llvm.LLVMOutput.writeModuleDefinition(LLVMOutput.java:306) at shadow.output.llvm.LLVMOutput.startFile(LLVMOutput.java:529) at shadow.output.AbstractOutput.build(AbstractOutput.java:41) at shadow.Main.generateLLVM(Main.java:271) at shadow.Main.run(Main.java:138) at shadow.Main.main(Main.java:68)

I have also seen the following exception under similar circumstances, but I am no longer able to reproduce it:

Exception in thread "main" java.lang.UnsupportedOperationException at shadow.interpreter.ShadowInterpreter.visit(ShadowInterpreter.java:17 at shadow.tac.nodes.TACLoad.accept(TACLoad.java:54) at shadow.tac.TACAbstractVisitor.visit(TACAbstractVisitor.java:79) at shadow.tac.TACAbstractVisitor.walk(TACAbstractVisitor.java:67) at shadow.output.llvm.LLVMOutput.writeModuleDefinition(LLVMOutput.java: at shadow.output.llvm.LLVMOutput.startFile(LLVMOutput.java:529) at shadow.output.AbstractOutput.build(AbstractOutput.java:41) at shadow.Main.generateLLVM(Main.java:271) at shadow.Main.run(Main.java:138) at shadow.Main.main(Main.java:68)

Interestingly enough, using a literal string does not cause this issue, while explicitly creating one does. I assume literal strings are handled specially by the compiler, but I thought it was worth noting:

    private constant String a = ""; // Works
    private constant String b = String:create() // Doesn't work

— Reply to this email directly or view it on GitHub https://github.com/TeamShadow/shadow/issues/24.

bwittman commented 8 years ago

Commit ed25dbfff6f540a7d6683a81893f4cb44408201a updates the compiler so that it gives a reasonable error message when someone tries to create anything other than a String.

The default create or one that supplies a single String value both work, but the ones that take in arrays do not. Both scenarios are special case hacks. The interpreter needs some work to become more robust.