Scala "reflective toolbox failed due to unresolved free type"
Asked Answered
C

1

0

Trying quasiquotes for the first time to generically produce new case classes:

val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
import universe._
import scala.reflect.runtime.{currentMirror => m}
import scala.tools.reflect.ToolBox
val toolbox = m.mkToolBox()

trait Father
class A extends Father {
  println("I'm A")
  val a = 0
}
class B extends Father {
  println("I'm B")
  val b = 0
}

object Produce {
  def A(): A = {
    val weakT = weakTypeOf[A]
    val genTree = q"""
      case class Son() extends $weakT {
        println("I'm alive")
      }
      Son()
      """
    val compiledCode = toolbox.eval(genTree)
    compiledCode.asInstanceOf[A]
  }
  def apply[T <: Father](): T = {
    val weakT = weakTypeOf[T]
    val genTree = q"""
      case class Son() extends $weakT {
        println("I'm alive")
      }
      Son()
      """
    val compiledCode = toolbox.eval(genTree)
    compiledCode.asInstanceOf[T]
  }
}

Produce.A()

Produce[A]()

The results for Produce.A():

I'm A

I'm alive

res0: A = Son()

The results for Produce[A]():

scala.tools.reflect.ToolBoxError: reflective toolbox failed due to unresolved free type variables: T defined by apply in :32:13 have you forgotten to use TypeTag annotations for type parameters external to a reifee? if you have troubles tracking free type variables, consider using -Xlog-free-types at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.verify(ToolBoxFactory.scala:82) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:208) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:429) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:422) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:355) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:355) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:422) at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:444) at Produce$.apply(:40) ... 34 elided

Crystalcrystalline answered 5/7, 2016 at 14:11 Comment(1)
Have you tried this? def apply[T <: Father : TypeTag](): T = {Welldone
C
1

As suggested by @Andreas Jim-Hartmann, added ' : TypeTag' (see comment below) and now this code works for both generic and specific:

val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
import universe._
import scala.reflect.runtime.{currentMirror => m}
import scala.tools.reflect.ToolBox
val toolbox = m.mkToolBox()

trait Father
class A extends Father {
  println("I'm A")
  val a = 0
}
class B extends Father {
  println("I'm B")
  val b = 0
}

object Produce {
  def A(): A = {
    val weakT = weakTypeOf[A]
    val genTree = q"""
      case class Son() extends $weakT {
        println("I'm alive")
      }
      Son()
      """
    val compiledCode = toolbox.eval(genTree)
    compiledCode.asInstanceOf[A]
  }
  def apply[T <: Father : TypeTag](): T = { //Fixed here
    val weakT = weakTypeOf[T]
    val genTree = q"""
      case class Son() extends $weakT {
        println("I'm alive")
      }
      Son()
      """
    val compiledCode = toolbox.eval(genTree)
    compiledCode.asInstanceOf[T]
  }
}

Produce.A()

Produce[A]()

Produce[B]()
Crystalcrystalline answered 5/7, 2016 at 20:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.