question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unsoundness due to type projections (no null or lazy vals necessary) (not in strict mode)

See original GitHub issue

EDIT: simpler example in the comments below

object App {
  abstract class Boo[E <: Nothing { type R }] {
    val r: E
    type R = r.type#R
  }

  trait Leibniz[+U, A <: U, B <: U] {
    def subst[F[_ <: U]](fa : F[A]): F[B]
  }
  def refl[A]: Leibniz[A, A, A] = new Leibniz[A, A, A] {
    def subst[F[_ <: A]](fa : F[A]): F[A] = fa
  }

  val p = refl[Nothing] : Leibniz[Nothing {type R}, Nothing { type R = Int }, Nothing { type R = String }]

  def main(args : Array[String]): Unit = {
    // BOOM
    val s : String = p.subst[[x <: Nothing { type R }] => Boo[x]#R](10)
  }

}
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
	at App$.main(App.scala:18)
	at App.main(App.scala)

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
hobwekivacommented, Apr 4, 2018

Refinements of Nothing are bad, but I can do it entirely without refining Nothing 😸

object App {
  def coerce[U, V](u: U): V = {
    trait X { type R >: U }
    trait Y { type R = V }

    abstract class Boo[E <: Any { type R }] {
      val r: E
      type R = r.type#R
    }

    class T[X <: Any { type R }](val value: Boo[X]#R)

    val a = new T[Y & X](u)
    a.value
  }

  def main(args : Array[String]): Unit = {
    // BOOM
    val s : String = coerce[Int, String](10)
  }
}
1reaction
hobwekivacommented, Apr 5, 2018

Adapted https://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/ to this technique:

object App {
  trait Term {
    type ap[x <: Term] <: Term
    type eval <: Term
  }

  class !#[T <: Term](val t: T) {
    type ap[x <: Term] = t.ap[x]
    type eval = t.eval
  }

  // The S combinator
  trait S extends Term {
    type ap[x <: Term] = S1[x]
    type eval = S
  }
  trait S1[x <: Term] extends Term {
    type ap[y <: Term] = S2[x, y]
    type eval = S1[x]
  }
  trait S2[x <: Term, y <: Term] extends Term {
    type ap[z <: Term] = S3[x, y, z]
    type eval = S2[x, y]
  }
  trait S3[x <: Term, y <: Term, z <: Term] extends Term {
    type ap[v <: Term] = !#[eval]#ap[v]
    type eval = !#[!#[!#[x]#ap[z]]#ap[!#[y]#ap[z]]]#eval
  }

  // The K combinator
  trait K extends Term {
    type ap[x <: Term] = K1[x]
    type eval = K
  }
  trait K1[x <: Term] extends Term {
    type ap[y <: Term] = K2[x, y]
    type eval = K1[x]
  }
  trait K2[x <: Term, y <: Term] extends Term {
    type ap[z <: Term] = !#[eval]#ap[z]
    type eval = !#[x]#eval
  }

  // The I combinator
  trait I extends Term {
    type ap[x <: Term] = I1[x]
    type eval = I
  }
  trait I1[x <: Term] extends Term {
    type ap[y <: Term] = !#[eval]#ap[y]
    type eval = !#[x]#eval
  }

  trait c extends Term {
    type ap[x <: Term] = c
    type eval = c
  }
  trait d extends Term {
    type ap[x <: Term] = d
    type eval = d
  }
  trait e extends Term {
    type ap[x <: Term] = e
    type eval = e
  }

  object Equals {
    def apply[A >: B <:B , B]: Unit = ()
  }
  Equals[Int, Int]   // compiles fine


  // Ic -> c
  Equals[I#ap[c]#eval, c]

  // Kcd -> c
  Equals[K#ap[c]#ap[d]#eval, c]

  // KKcde -> d
  Equals[K#ap[K]#ap[c]#ap[d]#ap[e]#eval, d]

  // SIIIc -> Ic
  Equals[S#ap[I]#ap[I]#ap[I]#ap[c]#eval, c]

  // SKKc -> Ic
  Equals[S#ap[K]#ap[K]#ap[c]#eval, c]

  // SIIKc -> KKc
  Equals[S#ap[I]#ap[I]#ap[K]#ap[c]#eval, K#ap[K]#ap[c]#eval]

  // SIKKc -> K(KK)c
  Equals[S#ap[I]#ap[K]#ap[K]#ap[c]#eval, K#ap[K#ap[K]]#ap[c]#eval]

  // SIKIc -> KIc
  Equals[S#ap[I]#ap[K]#ap[I]#ap[c]#eval, K#ap[I]#ap[c]#eval]

  // SKIc -> Ic
  Equals[S#ap[K]#ap[I]#ap[c]#eval, c]

  // R = S(K(SI))K  (reverse)
  type R = S#ap[K#ap[S#ap[I]]]#ap[K]
  Equals[R#ap[c]#ap[d]#eval, d#ap[c]#eval]

  // b(a) = S(Ka)(SII)
  type b[a <: Term] = S#ap[K#ap[a]]#ap[S#ap[I]#ap[I]]

  trait A0 extends Term {
    type ap[x <: Term] = c
    type eval = A0
  }
  trait A1 extends Term {
    type ap[x <: Term] = !#[!#[x]#ap[A0]]#eval
    type eval = A1
  }
  trait A2 extends Term {
    type ap[x <: Term] = !#[!#[x]#ap[A1]]#eval
    type eval = A2
  }

  trait An extends Term {
    type ap[x <: Term] = !#[!#[x]#ap[An]]#eval
    type eval = An
  }

  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  // Infinite iteration: Smashes dotc's stack
  type NNn = b[R]#ap[b[R]]#ap[An]
  Equals[NNn#eval, c]
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

isVolatile incorrect for intersection types #50 - lampepfl/dotty
This code is type correct for any T, a and b are always initialized to null , there is no particular place to...
Read more >
Explicit Nulls - Scala 3
Explicit nulls is an opt-in feature that modifies the Scala type system, which makes reference types (anything that extends AnyRef ) non-nullable.
Read more >
`def` vs `val` vs `lazy val` evaluation in Scala - Stack Overflow
lazy val defines a value with delayed initialization. It will be initialized when it's first used, so the assignment expression will be evaluated...
Read more >
Guide to lazy val in Scala - Baeldung
Learn how Scala implements its lazy val feature and some problems you may encounter when using it.
Read more >
Advanced Logical Type Systems for Untyped Languages
expressive but unchecked (and thus unsound) type predicates. ... occurrence typing is necessary but not sufficient for type checking many ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found