Question

I'm trying to make a type-provider that gives updated case classes.

How might I splice in a type and a default value (or omit the default value)?

def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    import Flag._

    val result = {
      annottees.map(_.tree).toList match {
        case q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$body }" :: Nil =>
          val valType    = //TODO
          val valDefault = //TODO
          val helloVal   = q"""val x: $valType = $valDefault"""
          q"$mods class $name[..$tparams](..$first, $helloVal)(...$rest) extends ..$parents { $self => ..$body }"
      }
    }
    c.Expr[Any](result)
  }

I've tried:

I've tried simply val valType = q"String", but then I get an error as if a default value was not found: not enough arguments for method apply

I've also tried splicing in a val defined as typeOf[String], and I've also tried splicing lists of ValDefs into my q"$mods class... (like I've seen done into a q"def... in some similar questions on this site), but in each case there is a typer error.

Any tips? Thanks very much for looking.

Was it helpful?

Solution

You can use the tq interpolator in the definition of valType to create the type tree.

The rest is a little trickier. It seems to work just fine if you define the extra parameter directly:

q"""
  $mods class $name[..$tparams](
    ..$first,
    val x: $valType = $valDefault
  )(...$rest) extends ..$parents { $self => ..$body }
"""

But when you define $helloVal and then plug that in you end up without the default parameter flag. You could write a helper like this:

def makeDefault(valDef: ValDef) = valDef match {
  case ValDef(mods, name, tpt, rhs) => ValDef(
    Modifiers(
      mods.flags | DEFAULTPARAM, mods.privateWithin, mods.annotations
    ),
    name, tpt, rhs
  )
}

Now you can write the following:

val valType    = tq"String"
val valDefault = q""""foo""""
val helloVal   = makeDefault(q"val x: $valType = $valDefault")

And everything should work as expected.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top