Skip to content

Instantly share code, notes, and snippets.

@b-studios
Last active April 10, 2019 18:07
Show Gist options
  • Save b-studios/4f1ca0356fbcd2ad8470a981ec70f2d6 to your computer and use it in GitHub Desktop.
Save b-studios/4f1ca0356fbcd2ad8470a981ec70f2d6 to your computer and use it in GitHub Desktop.
Bad interaction of type matcher and meta programming?
package examples
import scala.quoted._
object bug extends App {
val toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
implied for scala.quoted.Toolbox = toolbox
sealed trait HList
sealed trait HNil extends HList
sealed trait ::[E, T <: HList] extends HList
type STM[A, L <: HList] = L match {
case HNil => Expr[A]
case e :: rs => (Expr[A] => STM[e, rs]) => STM[e, rs]
}
type Stm[A, L <: HList] = L match {
case HNil => A
case e :: rs => (A => Stm[e, rs]) => Stm[e, rs]
}
trait Effects[L <: HList] {
def reify[A] given Type[A]: STM[A, L] => Expr[Stm[A, L]]
def reflect[A] given Type[A]: Expr[Stm[A, L]] => STM[A, L]
}
implied empty for Effects[HNil] {
def reify[A] given Type[A] = m => m
def reflect[A] given Type[A] = m => m
}
// for reify, we need type tags for E and also strangely for L.
implied cons [E, L <: HList] given Effects[L] given Type[E] given Type[L] for Effects[E :: L] {
def reify[A] given Type[A] = m => '{ k => ${ Effects[L].reify[E] { m( a => Effects[L].reflect[E]('k(a))) } }}
def reflect[A] given Type[A] = m => k => Effects[L].reflect[E] { m('{ a => ${ Effects[L].reify[E]( k('a)) } })}
}
def Effects[L <: HList] given Effects[L]: Effects[L] = the[Effects[L]]
type RS = Boolean :: RS2
type RS2 = Int :: String :: HNil
val m: STM[Int, RS] = k => k('{42})
// compiles, but results in a runtime error:
// println(Effects[RS].reify[Int] { m }.show)
//
// the implicit search results in the following value:
// val effects = cons[Boolean, RS2] given (cons[Int, String :: HNil] given (cons[String, HNil] given empty))
//
// so the above is equivalent to:
// println(effects.reify[Int] { m }.show)
//
// error:
// 37 | def reify[A] given Type[A] = m => '{ k => ${ Effects[L].reify[E] { m( a => Effects[L].reflect[E]('k(a))) } }}
// | ^
// | value apply is not a member of R
// | This location is in code that was inlined at Bug.scala:37
// manually inlining reify works
// val res : Expr[Stm[Int, RS]] = '{ k => ${ Effects[RS2].reify[Boolean] { m(a => Effects[RS2].reflect[Boolean]('k(a))) }}}
// println(res.show)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment