scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

"NoSuchElementException: head of empty list" caused by asInstanceOf with higher kinds #10700

Open tyukiand opened 6 years ago

tyukiand commented 6 years ago

scala 2.12.4 typechecker crashes when trying to run the following script with "scala script.scala":

import scala.language.higherKinds

class Foo[X]
class Bar[X]
class CrashIt[A[_]] {
  def cast(a: Any): A[Int] = a.asInstanceOf[A[Int]]
}
val c = if (true) new CrashIt[Foo] else new CrashIt[Bar]
val x = c.cast("")

Stack trace:

java.util.NoSuchElementException: head of empty list
    at scala.collection.immutable.Nil$.head(List.scala:428)
    at scala.collection.immutable.Nil$.head(List.scala:425)
    at scala.tools.nsc.typechecker.ContextErrors$InferencerContextErrors$InferErrorGen$.
      NotWithinBoundsErrorMessage(ContextErrors.scala:1045)
    at scala.tools.nsc.typechecker.ContextErrors$InferencerContextErrors$InferErrorGen$.
      NotWithinBoundsContextErrors.scala:1052)
    at scala.tools.nsc.typechecker.Infer$Inferencer.issueBoundsError$1(Infer.scala:881)
    at scala.tools.nsc.typechecker.Infer$Inferencer.check$1(Infer.scala:887)
    at scala.tools.nsc.typechecker.Infer$Inferencer.checkBounds(Infer.scala:891)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.checkBounds(RefChecks.scala:1203)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.checkTypeRef(RefChecks.scala:1384)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.$anonfun$transform$4(RefChecks.scala:1668)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.$anonfun$transform$4$adapted(RefChecks.scala:1659)
    at scala.reflect.internal.tpe.TypeMaps$ForEachTypeTraverser.traverse(TypeMaps.scala:1102)
    at scala.reflect.internal.Types$Type.foreach(Types.scala:787)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1407)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:107)
    at scala.reflect.internal.Trees.$anonfun$itransform$1(Trees.scala:1369)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1368)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStat(RefChecks.scala:1186)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.$anonfun$transformStats$1(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:107)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1416)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:107)
    at scala.reflect.api.Trees$Transformer.transformTemplate(Trees.scala:2563)
    at scala.reflect.internal.Trees.$anonfun$itransform$4(Trees.scala:1420)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1419)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStat(RefChecks.scala:1198)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.$anonfun$transformStats$1(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:107)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1378)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:107)
    at scala.reflect.internal.Trees.$anonfun$itransform$2(Trees.scala:1375)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1373)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStat(RefChecks.scala:1198)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.$anonfun$transformStats$1(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:107)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1416)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:107)
    at scala.reflect.api.Trees$Transformer.transformTemplate(Trees.scala:2563)
    at scala.reflect.internal.Trees.$anonfun$itransform$5(Trees.scala:1425)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1424)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStat(RefChecks.scala:1198)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.$anonfun$transformStats$1(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:1169)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transformStats(RefChecks.scala:107)
    at scala.reflect.internal.Trees.$anonfun$itransform$7(Trees.scala:1438)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees.itransform(Trees.scala:1438)
    at scala.reflect.internal.Trees.itransform$(Trees.scala:1348)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:1751)
    at scala.tools.nsc.typechecker.RefChecks$RefCheckTransformer.transform(RefChecks.scala:107)
    at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:140)
    at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
    at scala.tools.nsc.Global$GlobalPhase.$anonfun$applyPhase$1(Global.scala:436)
    at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:429)
    at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1(Global.scala:400)
    at scala.tools.nsc.Global$GlobalPhase.$anonfun$run$1$adapted(Global.scala:400)
    at scala.collection.Iterator.foreach(Iterator.scala:929)
    at scala.collection.Iterator.foreach$(Iterator.scala:929)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1417)
    at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:400)
    at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1452)
    at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1436)
    at scala.tools.nsc.Global$Run.compileSources(Global.scala:1429)
    at scala.tools.nsc.Global$Run.compile(Global.scala:1545)
    at scala.tools.nsc.StandardCompileServer.session(CompileServer.scala:150)
    at scala.tools.util.SocketServer.$anonfun$doSession$2(SocketServer.scala:80)
    at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at scala.Console$.withOut(Console.scala:163)
    at scala.tools.util.SocketServer.$anonfun$doSession$1(SocketServer.scala:80)
    at scala.tools.util.SocketServer.$anonfun$doSession$1$adapted(SocketServer.scala:75)
    at scala.tools.nsc.io.Socket.applyReaderAndWriter(Socket.scala:49)
    at scala.tools.util.SocketServer.doSession(SocketServer.scala:75)
    at scala.tools.util.SocketServer.loop$1(SocketServer.scala:91)
    at scala.tools.util.SocketServer.run(SocketServer.scala:103)
    at scala.tools.nsc.CompileServer$.$anonfun$execute$3(CompileServer.scala:216)
    at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.java:12)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at scala.Console$.withOut(Console.scala:163)
    at scala.tools.nsc.CompileServer$.$anonfun$execute$2(CompileServer.scala:211)
    at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.java:12)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
    at scala.Console$.withErr(Console.scala:192)
    at scala.tools.nsc.CompileServer$.main(CompileServer.scala:211)
    at scala.tools.nsc.CompileServer.main(CompileServer.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at scala.reflect.internal.util.ScalaClassLoader.$anonfun$run$2(ScalaClassLoader.scala:99)
    at scala.reflect.internal.util.ScalaClassLoader.asContext(ScalaClassLoader.scala:34)
    at scala.reflect.internal.util.ScalaClassLoader.asContext$(ScalaClassLoader.scala:30)
    at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:125)
    at scala.reflect.internal.util.ScalaClassLoader.run(ScalaClassLoader.scala:99)
    at scala.reflect.internal.util.ScalaClassLoader.run$(ScalaClassLoader.scala:91)
    at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:125)
    at scala.tools.nsc.CommonRunner.run(ObjectRunner.scala:22)
    at scala.tools.nsc.CommonRunner.run$(ObjectRunner.scala:21)
    at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
    at scala.tools.nsc.CommonRunner.runAndCatch(ObjectRunner.scala:29)
    at scala.tools.nsc.CommonRunner.runAndCatch$(ObjectRunner.scala:28)
    at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
    at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:66)
    at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:85)
    at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)    

Information about the used compiler and environment:

scala -version
Scala code runner version 2.12.4

java -version
openjdk version "1.8.0_144"
OpenJDK Runtime Environment (build 1.8.0_144-b01)
OpenJDK 64-Bit Server VM (build 25.144-b01, mixed mode)

uname -a
Linux myHostname 4.14.13-1-ARCH #1 SMP PREEMPT Wed Jan 10 11:14:50 UTC 2018 x86_64 GNU/Linux

Some observations:

Jasper-M commented 6 years ago

Just for fun, eliminating the asInstanceOf:

import scala.language.higherKinds

class Foo[X]
class Bar[X]
class CrashIt[A[_] >: Null] {
  def cast(a: Any): A[Int] = null
}
val c = if (true) new CrashIt[Foo] else new CrashIt[Bar]
val x = c.cast("")
tyukiand commented 6 years ago

Even shorter: without >: Null and without returning any instances at all:

import scala.language.higherKinds

class Foo[X]
class Bar[X]
class CrashIt[A[_]] {
  def cast(a: Any): A[Int] = ???
}
val c = if (true) new CrashIt[Foo] else new CrashIt[Bar]
val x = c.cast("")

(That's not purely code-golfing, this has fewer syntactic elements, and it has the advantage of a somewhat shorter stack trace of the error.)

joroKr21 commented 6 years ago

Ugh, just this line kills the REPL:

class CrashIt[A[_]]
if (true) new CrashIt[Option] else new CrashIt[List]
Jasper-M commented 6 years ago

Ugh, just this line kills the REPL

Yes, but it "works" outside of the REPL though... This is a very dangerous corner of the compiler :-p

hrhino commented 6 years ago

This goes way farther back (before 2.11, even).

joroKr21 commented 6 years ago

Uh-oh, note the ill-kinded type inference:

scala> List(new CrashIt[Option], new CrashIt[List])
<console>:39: error: type mismatch;
 found   : CrashIt[Option]
 required: CrashIt[_ >: List with Option <: Product with Serializable]
       List(new CrashIt[Option], new CrashIt[List])
            ^
<console>:39: error: type mismatch;
 found   : CrashIt[List]
 required: CrashIt[_ >: List with Option <: Product with Serializable]
       List(new CrashIt[Option], new CrashIt[List])
                                 ^

Also, I don't understand why:

can't existentially abstract over parameterized type

https://github.com/scala/scala/blob/8ad55a4ed8424aa6da372d3b6e41750f3d098523/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala#L722-L723

SethTisue commented 6 years ago

https://github.com/scala/scala/pull/6352 promotes this to an error for 2.13

som-snytt commented 2 years ago

My PR is just not to crash when constructing a string.