scala / bug

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

implicit class + value class + package object == ClassCastException #8133

Closed scabug closed 10 years ago

scabug commented 10 years ago

This is a regression since 2.10, and specific to separate compilation. I think all included elements (implicit class, value class, package objects, call to to_s comes from a closure) are necessary to reproduce this bug, but there's another bug I encountered while minimizing which I'll open next.

//  a.scala
package object pkg {
  implicit class AnyOps(val x: Any) extends AnyVal { def to_s: String = "" + x }
}
// b.scala
package pkg

package object other { }
package other { class Crash { def f() = List(1) map (_.to_s) } }

object Test {
  def main(args: Array[String]): Unit = println((new other.Crash).f())
}

Outcomes:

% scalac3 a.scala && scalac3 b.scala && scala3 pkg.Test
java.lang.ClassCastException: pkg.other.package$ cannot be cast to pkg.package$
    at pkg.other.Crash$$anonfun$f$1.apply(b.scala:4)
    at pkg.other.Crash$$anonfun$f$1.apply(b.scala:4)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:245)

% scalac3 a.scala b.scala && scala3 pkg.Test
List(1)

% scalac210 a.scala && scalac210 b.scala && scala210 pkg.Test
List(1)
scabug commented 10 years ago

Imported From: https://issues.scala-lang.org/browse/SI-8133?orig=1 Reporter: @paulp Affected Versions: 2.11.0-M7

scabug commented 10 years ago

@retronym said (edited on Jan 13, 2014 10:33:04 AM UTC): Whittled down a touch:

rm -rf *.class pkg/; qbin/scalac test/files/run/t8133/A_1.scala && qbin/scalac test/files/run/t8133/B_2.scala && qbin/scala Test 2>&1 | head -n 4
java.lang.ClassCastException: pkg.other.package$ cannot be cast to pkg.package$
    at pkg.other.Crash.<init>(B_2.scala:5)
    at Test$.main(B_2.scala:13)
    at Test.main(B_2.scala)
  /code/scala tail test/files/run/t8133/*.scala
==> test/files/run/t8133/A_1.scala <==
//  a.scala
package object pkg {
  class AnyOps(val x: Any) extends AnyVal
  def AnyOps(x: Any) = new AnyOps(x)
}

==> test/files/run/t8133/B_2.scala <==
package pkg {
  package object other
  package other {
    class Crash {
      AnyOps(0)
      ()
    }
  }
}

object Test {
  def main(args: Array[String]): Unit = {
    new pkg.other.Crash
  }
}
scabug commented 10 years ago

@paulp said: Whittled further:

//  a.scala
package object pkg {
  def foo(x: Int): String = "a"
  def foo(x: String): String = "b"
}
//  b.scala
package pkg {
  package object other
  package other { class Crash { foo("") } }
}

object Test {
  def main(args: Array[String]): Unit = new pkg.other.Crash
}

The overloaded symbol in the package object leads somehow to the call site tree not being fully qualified, it remains as package.foo(""). Later, erasure notices and inserts an ill-conceived cast between package objects (which seems like it will always be the wrong thing.) It works if the call site is pkg.foo("").

scabug commented 10 years ago

@paulp said: Rather than having a nested package object in package pkg one can simply import bar._ from any package containing a package object. You only have to have a competing package identifier in scope. By such means did I hit this bug AGAIN a day or two after I reported it. I really wonder sometimes how much usage the language actually has if I can be the first to encounter 500 bugs. My gardening thumb isn't quite that black.

scabug commented 10 years ago

@retronym said (edited on Jan 13, 2014 3:24:42 PM UTC): I'm working on this one. Need to fix a few places, really:

https://github.com/retronym/scala/compare/ticket;8133?expand=1

scabug commented 10 years ago

@retronym said: https://github.com/scala/scala/pull/3365