Skip to content
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

Wildcard capture goes wrong on nested wildcard #9419

Open
scabug opened this issue Jul 28, 2015 · 7 comments · Fixed by scala/scala3#16732
Open

Wildcard capture goes wrong on nested wildcard #9419

scabug opened this issue Jul 28, 2015 · 7 comments · Fixed by scala/scala3#16732
Labels
existential fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) infer should not compile
Milestone

Comments

@scabug
Copy link

scabug commented Jul 28, 2015

This should not compile; it should not be able to infer a T when calling onestep. We use that to throw a ClassCastException.

package forsomescope2

trait Magic[S] {
  def init: S
  def step(s: S): String
}

object Main extends App {
  def onestep[T](m: => Magic[T]) =
    m.step(m.init)

  def flip: () => Magic[_] = {
    var z = false
    () => {
      z = !z
      if (z) new Magic[Int] {
        def init = 0
        def step(s: Int) = (s - 1).toString
      } else new Magic[String] {
        def init = "hi"
        def step(s: String) = s.reverse
      }
    }
  }

  def boom = {
    val flipper = flip
    onestep(flipper())
  }
  boom
}

(scastie here) throws

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
	at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
	at forsomescope2.Main$$anon$1.step(ForsomeScope.scala:16)
	at forsomescope2.Main$.onestep(ForsomeScope.scala:10)
	at forsomescope2.Main$.boom(ForsomeScope.scala:28)
	at forsomescope2.Main$.delayedEndpoint$forsomescope2$Main$1(ForsomeScope.scala:30)
	at forsomescope2.Main$delayedInit$body.apply(ForsomeScope.scala:8)

This doesn't apply to the Magic variant from #9410, except if you do the intermediate introduction of forSome, which is already introduced here.

@scabug
Copy link
Author

scabug commented Jul 28, 2015

Imported From: https://issues.scala-lang.org/browse/SI-9419?orig=1
Reporter: Stephen Compall (s11001001)
Affected Versions: 2.10.5, 2.11.7
See #9410

@dwijnand
Copy link
Member

Still broken in Scala 3.

@SethTisue
Copy link
Member

@SethTisue
Copy link
Member

SethTisue commented Jan 19, 2023

Dale and I noticed that it isn't crucial to have an actual byname; you can change the reproducer to use () => Magic[T] instead of => Magic[T] and it still breaks in the same way.

(Regardless, we should test any proposed fix on both variants.)

@SethTisue SethTisue added infer and removed byname labels Jan 19, 2023
@SethTisue SethTisue added this to the Backlog milestone Jan 19, 2023
@SethTisue SethTisue changed the title existential scope escapes byname context Wildcard capture goes wrong on nested wildcard Jan 19, 2023
@SethTisue
Copy link
Member

SethTisue commented Jan 19, 2023

I'm partial to this minimization (in Scala 3 syntax):

trait Magic[S]:
  def init: S
  def step(s: S): String

object IntMagic extends Magic[Int]:
  def init = 0
  def step(s: Int): String = (s - 1).toString

object StrMagic extends Magic[String]:
  def init = "hi"
  def step(s: String): String = s.reverse

object Main:
  def onestep[T](m: () => Magic[T]): String = m().step(m().init)
  val iter: Iterator[Magic[?]] = Iterator(IntMagic, StrMagic)
  def main(args: Array[String]): Unit =
    onestep(() => iter.next())

it's not fundamentally different. Just a bit easier to grasp, perhaps.

Magic is invariant and has methods with S in both covariant and contravariant positions, as is common when we want a runtime demonstration of compile-time unsoundness.

onestep(() => iter.next()) should not compile, as there no correct instantiation for T. (Recall that Iterator[Magic[?]] means Iterator[Magic[T] forSome { type T }], not Iterator[Magic[T]] forSome { type T }.)

@SethTisue SethTisue added the fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) label Jan 26, 2023
@SethTisue
Copy link
Member

SethTisue commented Jan 26, 2023

scala/scala3#16732 is merged, so, labeling this one as "fixed in Scala 3" now

UPDATE: see also discussion at scala/scala3#16789

@SethTisue
Copy link
Member

SethTisue commented Jan 31, 2023

errant auto-closing. not fixed in Scala 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
existential fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) infer should not compile
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants