#994 java.lang.VerifyError on broken code

katox Thu 25 Feb 2010

By accident I typed Pod.of(this).log.info("").toStr and got this:

java.lang.VerifyError: (class: fan/sh6/FanshEval, method: _eval signature: ()Ljava/lang/Object;) Unable to pop operand off an empty stack

at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2291)
at java.lang.Class.getDeclaredFields(Class.java:1743)
at fan.sys.ClassType.finishSlots(ClassType.java:562)
at fan.sys.ClassType.finish(ClassType.java:525)
at fan.sys.Method$MethodFunc.isStatic(Method.java:459)
at fan.sys.Method$MethodFunc.callList(Method.java:175)
at fan.sys.Type.make(Type.java:242)
at fan.sys.ClassType.make(ClassType.java:110)
at fan.fansh.Evaluator.eval(Evaluator.fan:111)
at fan.fansh.Shell.run(Shell.fan:45)
at fan.fansh.Main.main(Shell.fan:201)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 ...
sys::Err: Method not mapped to java.lang.reflect correctly sh6::FanshEval.make
fan.sys.Method$MethodFunc.isStatic (Method.java:466)
fan.sys.Method$MethodFunc.callList (Method.java:175)
fan.sys.Type.make (Type.java:242)
fan.sys.ClassType.make (ClassType.java:110)
...

Not really a problem but it seems that it could be reported better...

brian Thu 25 Feb 2010

Promoted to ticket #994 and assigned to brian

tactics Mon 8 Mar 2010

Testing this out, it appears the underlying cause is that the Void type inherits from Obj, and so it inherits the Obj slots:

fansh> Void#.slots.each {echo(it) }
sys::Obj.equals
sys::Obj.compare
sys::Obj.hash
sys::Obj.toStr
sys::Obj.trap
sys::Obj.with
sys::Obj.isImmutable
sys::Obj.toImmutable
sys::Obj.typeof
sys::Obj.echo
sys::Void.make

The type checker does not seem to catch it when a method is chained after a Void-valued method call. This script raises the same error as katox posted.

class Foo
{
  static Void main()
  {
    echo("").toStr
  }
}

It looks like the fix would be adding a check for calls on Void objects in CallResolver near line 160:

. Void find()
  {
    // if already "found", then skip this step
    if (found != null) return

+    if (base.isVoid)
+      throw err("Cannot call methods on Void", loc)

    // look it up in base type
    found = findOn(base)


    // if we have an it in scope, then also attempt to resolve against it
    if (baseIt != null)
    {
      foundIt := findOn(baseIt)

brian Tue 23 Mar 2010

Ticket resolved in 1.0.52

Added a check in CheckErrors to verify not performing any sort of call on a Void target.

Thanks very much tactics for helping track this down to single line of testable code (definitely saved me a bunch of time!)

Login or Signup to reply.