Skip to content

Empty JavaSeqLiteral (vararg) is incorrectly typed, resulting in runtime error #1136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
smarter opened this issue Mar 1, 2016 · 0 comments
Closed

Comments

@smarter
Copy link
Member

smarter commented Mar 1, 2016

The following crashes at runtime, because the second argument to getMethod (an empty vararg) is incorrectly typed:

object Test {
  def main(args: Array[String]): Unit = {
    val x = classOf[String].getMethod("toString")
  }
}

The signature of getMethod is Method getMethod(String name, Class<?>... parameterTypes), so the second argument after typing should be an empty array of type Array[Class[_]], but instead we produce an empty array of type Array[Nothing]:

  final lazy module val Test: Test$ = new Test$()
  final module class Test$() extends Object() { this: Test.type => 
    def main(args: Array[String]): Unit = {
      val x: java.lang.reflect.Method = 
        classOf[String].getMethod("toString", []: Array[Nothing])
      ()
    }
  }

This is incorrect because Array[Nothing] is not a subtype of Array[Class[_]] and it blows up at runtime:

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    Test$.main([Ljava/lang/String;)V @8: invokevirtual
  Reason:
    Type '[Lscala/runtime/Nothing$;' (current frame, stack[2]) is not assignable to
    '[Ljava/lang/Class;'

The issue is in TypeAssigner#assignType:

  def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = tree match {
    case tree: JavaSeqLiteral =>
      tree.withType(defn.ArrayOf(ctx.typeComparer.lub(elems.tpes).widen))

We set the array element type to the lub of the types of the JavaSeqLiteral elements, but when the JavaSeqLiteral is empty, the lub is Nothing.

We could fix the type by hand in TypedApply#makeVarArg where the expected type is known, but if we do this then -Ycheck will fail since retyping will produce Array[Nothing] again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants