5

This gist (a partial Scala port of this Haskell tagless interpreter) compiles with scalac 2.11.1, but fails with the newer 2.11.6:

typechecker.scala:55: error: type mismatch;
  found   : Expr[B] where type B
  required: Expr[Int]
       case (lhs ::: RInt, rhs ::: RInt) => Add(lhs, rhs) ::: RInt
...

How does scalac propagate types through the pattern matches of :::? What changed from 2.11.1 to 2.11.6? I've tried looking looking at the output of scalac -print and scalac -Xprint-types but haven't found them helpful.

See the gist for complete code, but, roughly, we have

// ADT for untyped expressions
sealed trait UExpr
case class UAdd(lhs: UExpr, rhs: UExpr) extends UExpr

// GADT for typed expressions
sealed trait Expr[T]
case class Add(lhs: Expr[Int], rhs: Expr[Int]) extends Expr[Int]

// Reification of types
sealed trait RType[T]
case object RInt extends RType[Int]

// Expression annotated with reified type
class :::[A,B](val expr: Expr[A], val typ: RType[B])(implicit witness: A === B)
object ::: {
    def apply =
        ...
    def unapply =
        ...
}

// typechecker from UExpr to Expr
def typed(uexpr: UExpr): Option[:::[_,_]] = uexpr match {
    case UAdd(l, r) => typed(l, r) collect {
        // vvvvvvvv HERE vvvvvvvv
        case (lhs ::: RInt, rhs ::: RInt) => Add(lhs, rhs) ::: RInt
        // ^^^^^^^^ HERE ^^^^^^^^
    }
}

// helper for typing two expressions
def typed(lhs: UExpr, rhs: UExpr): Option[(:::[_,_], :::[_,_])] =
    ...
David B.
  • 5,700
  • 5
  • 31
  • 52

0 Answers0