Skip to content

Commit

Permalink
Merge pull request #238 from tofu-tf/ArgPassing
Browse files Browse the repository at this point in the history
Pass target type as type argument for the macros
  • Loading branch information
Odomontois authored Mar 18, 2021
2 parents 520b024 + a4922db commit b0539e9
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 26 deletions.
24 changes: 21 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,28 @@ lazy val reactivemongo = project dependsOn core settings common
lazy val catsTagless = project dependsOn core settings common
lazy val pureconfig = project dependsOn core settings common
lazy val scalacheck = project dependsOn core settings common
lazy val tests =
project
.dependsOn(core, circe, ciris, tethys, reactivemongo, catsTagless, pureconfig)
.settings(common, skip in publish := true)

lazy val derevo = project in file(".") settings (common, skip in publish := true) aggregate (
core, cats, circe, circeMagnolia, ciris, tethys, tschema, reactivemongo, catsTagless, pureconfig, scalacheck
)
lazy val derevo = project
.in(file("."))
.settings(common, skip in publish := true)
.aggregate(
core,
cats,
circe,
circeMagnolia,
ciris,
tethys,
tschema,
reactivemongo,
catsTagless,
pureconfig,
scalacheck,
tests,
)

addCommandAlias("fmt", "all scalafmtSbt scalafmt test:scalafmt")
addCommandAlias("checkfmt", "all scalafmtSbtCheck scalafmtCheck test:scalafmtCheck")
62 changes: 39 additions & 23 deletions core/src/main/scala/derevo/Derevo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package derevo

import scala.language.higherKinds
import scala.reflect.macros.blackbox
import scala.annotation.nowarn
import Derevo._

class Derevo(val c: blackbox.Context) {
import c.universe._
val DelegatingSymbol = typeOf[delegating].typeSymbol
val PhantomSymbol = typeOf[phantom].typeSymbol

type Newtype = NewtypeP[Tree]
type NameAndTypes = NameAndTypesP[c.Type]

val DelegatingSymbol = typeOf[delegating].typeSymbol
val PhantomSymbol = typeOf[phantom].typeSymbol
val PassTypeArgsSymbol = typeOf[PassTypeArgs].typeSymbol

val instanceDefs = Vector(
)
Expand Down Expand Up @@ -220,9 +225,11 @@ class Derevo(val c: blackbox.Context) {

val resT = mkAppliedType(mode.to, outTyp)

val callWithT = if (mode.passArgs) q"$call[$outTyp]" else call

q"""
@java.lang.SuppressWarnings(scala.Array("org.wartremover.warts.All", "scalafix:All", "all"))
implicit def $tn[..$tparams](implicit ..$implicits): $resT = $call
implicit def $tn[..$tparams](implicit ..$implicits): $resT = $callWithT
"""
}
}
Expand All @@ -232,34 +239,25 @@ class Derevo(val c: blackbox.Context) {
case _ => tq"$tc[$arg]"
}

private sealed trait Newtype {
def underlying: Tree
}
@nowarn
private final case class NewtypeCls(underlying: Tree) extends Newtype
@nowarn
private final case class NewtypeMod(underlying: Tree, res: Tree) extends Newtype

@nowarn
private final class NameAndTypes(
val name: String,
val from: Type,
val to: Type,
val newtype: Type,
val drop: Int,
val cascade: Boolean
)

private def nameAndTypes(obj: Tree): NameAndTypes = {
val mangledName = obj.toString.replaceAll("[^\\w]", "_")
val name = c.freshName(mangledName)

c.typecheck(obj).tpe match {
val objTyp = c.typecheck(obj).tpe

val nt = objTyp match {
case IsSpecificDerivation(f, t, nt, d) => new NameAndTypes(name, f, t, nt, d, true)
case IsDerivation(f, t, nt, d) => new NameAndTypes(name, f, t, nt, d, true)
case HKDerivation(f, t, nt, d) => new NameAndTypes(name, f, t, nt, d, false)
case _ => abort(s"$obj seems not extending InstanceDef traits")
}

val passArgs = objTyp.baseType(PassTypeArgsSymbol) match {
case TypeRef(_, _, _) => true
case _ => false
}

nt.copy(passArgs = passArgs)
}

class DerivationList(ds: IsInstanceDef*) {
Expand Down Expand Up @@ -288,3 +286,21 @@ class Derevo(val c: blackbox.Context) {
)
private def abort(s: String) = c.abort(c.enclosingPosition, s)
}

object Derevo {
private[Derevo] sealed trait NewtypeP[tree] {
def underlying: tree
}
private[Derevo] final case class NewtypeCls[tree](underlying: tree) extends NewtypeP[tree]
private[Derevo] final case class NewtypeMod[tree](underlying: tree, res: tree) extends NewtypeP[tree]

private[Derevo] final case class NameAndTypesP[typ](
name: String,
from: typ,
to: typ,
newtype: typ,
drop: Int,
cascade: Boolean,
passArgs: Boolean = false,
)
}
2 changes: 2 additions & 0 deletions core/src/main/scala/derevo/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package derevo {
def macroTransform(annottees: Any*): Any = macro Derevo.deriveMacro
}

trait PassTypeArgs

class delegating(to: String, args: Any*) extends StaticAnnotation
class phantom extends StaticAnnotation

Expand Down
22 changes: 22 additions & 0 deletions tests/src/main/scala/derevo/tests/Jampa.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package derevo
package tests

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

trait Jampa[_]

object JJ {
type Of[U[_[_]]] = U[Jampa]
}

object Jampa extends DerivationKN3[JJ.Of] with PassTypeArgs {
def instance[U[f[_]]]: U[Jampa] = macro jampa[U]

def jampa[U[f[_]]](c: blackbox.Context)(implicit t: c.WeakTypeTag[U[Any]]): c.Tree = {
import c.universe._
val u = t.tpe.typeConstructor.typeSymbol
val jampa = typeOf[Jampa[Any]].typeConstructor
q"new $u[$jampa]{}"
}
}
18 changes: 18 additions & 0 deletions tests/src/test/scala/derevo/tests/HigherKindedSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package derevo
package tests

import scala.languageFeature.experimental.macros
import scala.reflect.ClassTag

import org.scalatest.funsuite.AnyFunSuite

@derive(Jampa)
trait Goo[G[_]] {
def goo = "goo"
}

class HigherKindedMacroSuite extends AnyFunSuite {
test("goo should be goo") {
assert(implicitly[Goo[Jampa]].goo === "goo")
}
}

0 comments on commit b0539e9

Please sign in to comment.