#1283 Another bug

yachris Sat 30 Oct 2010

Compiling and running this:

class BugTest
{
  static Void main()
  {
    bi1 := BugInt()
    bi2 := BugInt()
    bs1 := BugStr()

    bb := BugExample { a = [bi1, bi2]; b = [bs1] }

    echo(bb.a)
    echo(bb.b)
    echo(bb.c)
  }
}

mixin BugMixin
{
  abstract Str toMyStr()
}

class BugExample
{
  new make(|This| f)
  {
    a = [,]
    b = [,]
    f(this)
    c = a.dup.addAll(b)
  }

  BugMixin[] a
  BugMixin[] b
  BugMixin[] c
}

class BugInt : BugMixin
{
  new make()
  {
    val = 0
  }

  override Str toMyStr()
  {
    return val.toStr
  }

  Int val
}

class BugStr : BugMixin
{
  new make()
  {
    val = "none"
  }

  override Str toMyStr()
  {
    return val.toStr
  }

  Str val
}

Yields:

sys::Err: java.lang.ArrayStoreException
  java.lang.System.arraycopy (System.java)
  fan.sys.List.insertAll (List.java:402)
  fan.sys.List.addAll (List.java:354)
  BugTest_0::BugExample.make$ (/path/BugTest.fan:29)
  BugTest_0::BugExample.make (/path/BugTest.fan)
  BugTest_0::BugTest.main (/path/BugTest.fan:9)
  java.lang.reflect.Method.invoke (Method.java:597)
  fan.sys.Method.invoke (Method.java:536)
  fan.sys.Method$MethodFunc.callList (Method.java:182)
  fan.sys.Method.callList (Method.java:147)
  fanx.tools.Fan.callMain (Fan.java:135)
  fanx.tools.Fan.executeFile (Fan.java:88)
  fanx.tools.Fan.execute (Fan.java:34)
  fanx.tools.Fan.run (Fan.java:236)
  fanx.tools.Fan.main (Fan.java:274)

Thanks!

qualidafial Sat 30 Oct 2010

Your problem is here:

bb := BugExample { a = [bi1, bi2]; b = [bs1] }

Because of type inference, bb.a is assigned as a BugInt[] rather than a BugMixin[]. Thus in the BugExample constructor:

c = a.dup.addAll(b)

This causes an ArrayStoreException since a.dup is storing it's elements in a java BugInt array, and you are trying to store a BugStr into that array.

Based on this, I'd say the list type inference rules should be updated so that the left hand side's type is chosen if it is known at compile time. If the LHS is not specified, then fall back to the current type inference rules.

rosarinjroy Sat 30 Oct 2010

yachris: Let me first tell you the fix for the issue and then explain what could possibly be the issue. Change the line below:

bb := BugExample { a = [bi1, bi2]; b = [bs1] }

To:

bb := BugExample { a = BugMixin[bi1, bi2]; b = BugMixin[bs1] }

That should solve your problem. What has happened is that when you create an array using a literal, the type of the array is decided based on the type of the elements in the array. It should have been based on the declared type of the array. IMHO, this is an error. So in your version of the code, a is an array of BugInts and b is an array of BugStrs. You can modify the make() to print the type of the two arrays created to convince yourself that this is what had happened.

new make(|This| f)
{
  a = [,]
  b = [,]
  f(this)
  echo("Type of a is: ${Type.of(a)}")
  echo("Type of b is: ${Type.of(b)}")
  c = a.dup.addAll(b)
}

When List invokes System.arrayCopy() to copy the elements from b to duplicate, the source and destination array types are totally different (one is not a subtype of the other), causing the ArrayStoreException to be thrown.

Hope that helps in understanding what went wrong.

Brian: I think this thread should be promoted as a bug and fix the type inference logic. I am sure this will be a common source of errors in future as well.

Roy

yachris Sun 31 Oct 2010

Wow, I'm two for two on erroneous errors today :-).

Thanks to qualidafial and Roy -- much appreciate the insight and understanding.

brian Sun 31 Oct 2010

One recommendation: if you are having trouble with inferred types or auto-casting, you can always just use explicit type declarations or explicit casts. Another good technique is to just print what the inferred type is to make sure it is what you expect.

Login or Signup to reply.