Skip to content

Commit

Permalink
fix divergency implicit errors in scala 2.12
Browse files Browse the repository at this point in the history
  • Loading branch information
dos65 committed Dec 30, 2020
1 parent 61ffd51 commit 5f715f1
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 292 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import xerial.sbt.Sonatype._

lazy val commonSettings = Seq(
//scalaVersion := "2.12.12-bin-SNAPSHOT",
scalaVersion := "2.12.12",
organization := "io.github.dos65",
version := "0.0.31-SNAPSHOT",
Expand Down
15 changes: 15 additions & 0 deletions modules/core/src/main/scala/make/Dep.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package make

import make.internal.DepMacro

/**
* This class is used to workaround wrong `divergency implicit error` on scala 2.12
* Macros uses similar trick as `shapeless.Lazy` but do not allows recursive references
*/
case class Dep[F[_], A](value: Make[F, A])

object Dep {

implicit def materialize[F[_], A]: Dep[F, A] =
macro DepMacro.materialize[F, A]
}
8 changes: 5 additions & 3 deletions modules/core/src/main/scala/make/Make.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import make.internal.MakeOps
import cats.Applicative
import scala.reflect.runtime.universe.TypeTag
import make.internal.MakeBasicOps
import make.internal.DepMacro

sealed abstract class Make[F[_], A] {
def tag: Tag[A]
}

object Make extends ContraMakeInstances with MakeTupleInstances with LowPrioMake {

def of[F[_], A](implicit m: Make[F, A]): Make[F, A] = m
def of[F[_], A](implicit m: Dep[F, A]): Make[F, A] = m.value

final private[make] case class Value[F[_], A](
v: () => F[A],
Expand Down Expand Up @@ -42,15 +43,16 @@ object Make extends ContraMakeInstances with MakeTupleInstances with LowPrioMake
def contramap[A, B](f: B => A): Contra[A, B] = new Contra[A, B](f)

final class Contra[A, B](private[make] val f: B => A)

}

trait ContraMakeInstances {

implicit def contraMakeInstance[F[_]: Applicative, A, B](implicit
contra: Make.Contra[A, B],
m: Make[F, B],
m: Dep[F, B],
tagB: Tag[A]
): Make[F, A] = MakeOps.map(m)(contra.f)
): Make[F, A] = MakeOps.map(m.value)(contra.f)
}

trait LowPrioMake {
Expand Down
47 changes: 47 additions & 0 deletions modules/core/src/main/scala/make/internal/DepMacro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package make.internal

import scala.reflect.macros.whitebox
import scala.collection.mutable
import make.Dep
import make.Make

class DepMacro(val c: whitebox.Context) {

import c.universe._

def materialize[F[_], A](implicit
ftpe: WeakTypeTag[F[X] forSome { type X }],
atpe: WeakTypeTag[A]
): c.Expr[Dep[F, A]] = {
val state = getOrCreateState
state.infer[F](ftpe.tpe, atpe.tpe) match {
case EmptyTree =>
c.abort(c.enclosingPosition, "failed")
case tree =>
c.Expr[Dep[F, A]](q"_root_.make.Dep[${ftpe.tpe}, ${atpe.tpe}]($tree)")
}
}

private def getOrCreateState: State = {
val existing =
c.openMacros.find(c => c.internal.attachments(c.macroApplication).contains[State])
.flatMap(c => c.internal.attachments(c.macroApplication).get[State])
existing match {
case None =>
val st = new State(mutable.HashSet.empty)
c.internal.updateAttachment(c.macroApplication, st)
st
case Some(st) => st
}
}


class State(val seen: mutable.HashSet[Type]) {

def infer[F[_]](ftpe: c.Type, atpe: c.Type): c.Tree = {
val makeTc = c.universe.weakTypeOf[Make[F, _]].typeConstructor
val searchType = c.universe.appliedType(makeTc, ftpe, atpe)
c.inferImplicitValue(searchType)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class MakeAnnotationMacro(val c: blackbox.Context) {

val dependencies: List[(TermName, c.Tree)] = params.zipWithIndex.map{case (dp, i) =>
val name = TermName(c.freshName(s"dep$i"))
val tree = q"$name: _root_.make.Make[$effTpe, ${dp.tpt}]"
val tree = q"$name: _root_.make.Dep[$effTpe, ${dp.tpt}]"
(name, tree)
}
val implicitDependencies = dependencies.map(_._2)
Expand All @@ -68,8 +68,8 @@ class MakeAnnotationMacro(val c: blackbox.Context) {
q"_root_.make.Make.pure[$effTpe, ${targetTpe}]($create)"
} else {
dependencies.reverse.map(_._1).foldLeft(EmptyTree){
case (EmptyTree, name) => q"_root_.make.internal.MakeOps.map(${name})($create)"
case (tree, name) => q"_root_.make.internal.MakeOps.ap(${name})($tree)"
case (EmptyTree, name) => q"_root_.make.internal.MakeOps.map(${name}.value)($create)"
case (tree, name) => q"_root_.make.internal.MakeOps.ap(${name}.value)($tree)"
}
}

Expand Down Expand Up @@ -118,7 +118,7 @@ class MakeAnnotationMacro(val c: blackbox.Context) {
case Apply(Select(New(annoSelect), _), _) =>
annoSelect
case _ =>
c.abort(c.enclosingPosition, "Annotation descontruction failed")
c.abort(c.enclosingPosition, "Annotation decontruction failed")
}
}
}
Expand Down
1 change: 1 addition & 0 deletions modules/core/src/main/scala/make/internal/MakeMacro.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class MakeMacro(val c: whitebox.Context) {
out match {
case EmptyTree =>
val st = extractInstanceSt(atpe.tpe, state.reverseTraces)
println(st)
val message = renderInstanceSt(st)
c.abort(c.enclosingPosition, s"Make for ${atpe.tpe} not found\n" + message)
case tree =>
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/make/internal/MakeOps.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package make.internal

trait MakeOps extends MakeProductNOps
trait MakeOps extends MakeProductNOps with MakeBasicOps
object MakeOps extends MakeOps
130 changes: 0 additions & 130 deletions modules/core/src/main/scala/make/internal/TpeTagMacro.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@ package make.internal
import scala.reflect.macros.blackbox
import make.Tag.TpeTag
import make.Tag
import scala.reflect.internal.Constants

class TpeTagMacro(val c: blackbox.Context) {

import c.universe._

def materializeTpeTag[A : WeakTypeTag]: c.Expr[TpeTag[A]] = {
val tpe = weakTypeOf[A]
println(s"CALL MATERIALIZE: $tpe ${tpe.typeSymbol.isParameter}")
val value = transformTpe3(tpe)
val tree = q"_root_.make.Tag.TpeTag[${tpe}]($value)"
println(s"OK!! $tree")
c.Expr[TpeTag[A]](tree)
}

Expand All @@ -34,14 +31,6 @@ class TpeTagMacro(val c: blackbox.Context) {
private def processTypeParameters(symbolName: c.Tree, t: c.Type): c.Tree = {
val inner = t.dealias.typeArgs.map(transformTpe3)
q"_root_.make.Tag.TpeTag.Type($symbolName, $inner)"
// t.dealias match {
// case ref: TypeRef =>
// val inner = ref.args.map(transformTpe3)
// q"_root_.make.Tag.TpeTag.Type($symbolName, $inner)"
// case x =>
// c.info(c.enclosingPosition, s"TpeTag not implemented for $x: ${x.getClass}", true)
// c.abort(c.enclosingPosition, "Not implemented")
// }
}

private def transformTpeParameter(t: c.Type): c.Tree = {
Expand All @@ -53,22 +42,6 @@ class TpeTagMacro(val c: blackbox.Context) {
}
case _ => searchTPTag(t)
}
// val kind = t.dealias.typeArgs
// println(s"TYPE ARGS for $t : $kind")
// kind.size match {
// case 0 => searchTPTag(t)
// case 1 => processTypeParameters(searchTCTag(t), t)
// case n => c.abort(c.enclosingPosition, "Not implemented")
// }

// t.dealias match {
// case tpe: TypeRef =>
// val inner = tpe.args.map(transformTpe3)
// q"_root_.make.Tag.TpeTag.Type(${symbolTree}, $inner)"
// case x =>
// c.info(c.enclosingPosition, s"TpeTag(parameter) not implemented for $x: ${x.getClass}", true)
// c.abort(c.enclosingPosition, "Not implemented")
// }
}


Expand All @@ -86,106 +59,6 @@ class TpeTagMacro(val c: blackbox.Context) {
.getOrElse(c.abort(c.enclosingPosition, "Not implemented"))
}

// private def transformTpe2(t: c.Type): c.Tree = {
// println(s"transform $t ${t.typeSymbol.isParameter} ${t.getClass}")
// val normalized = t
// if (t.typeSymbol.isParameter) {
// t.dealias match {
// case ref: PolyType =>
// println(s"IS POLY ${ref.typeParams} ${ref.typeArgs}")
// val kind = math.max(ref.typeParams.size, ref.typeArgs.size)
// ref.typeParams.size match {
// case 0 =>
// val inner = ref.typeArgs.map(transformTpe2)
// q"_root_.make.Tag.TpeTag.Type(${ref.typeSymbol.fullName}, $inner)"
// case 1 =>
// val tcTagTpe = appliedType(weakTypeOf[Tag.TCTag[X] forSome {type X[_]}].typeConstructor, t.typeConstructor)
// optionFromImplicitTree(c.inferImplicitValue(tcTagTpe))
// .map(t => q"$t.tpe")
// .getOrElse(c.abort(c.enclosingPosition, "Not implemented"))
// case n =>
// c.abort(c.enclosingPosition, "Not implemented")
// }
// case ref: TypeRef =>
// ref.typeParams.size match {
// case 0 =>
// val inner = ref.typeArgs.map(transformTpe2)
// q"_root_.make.Tag.TpeTag.Type(${ref.typeSymbol.fullName}, $inner)"
// case 1 =>
// val tcTagTpe = appliedType(weakTypeOf[Tag.TCTag[X] forSome {type X[_]}].typeConstructor, t.typeConstructor)
// optionFromImplicitTree(c.inferImplicitValue(tcTagTpe))
// .map(t => q"$t.tpe")
// .getOrElse(c.abort(c.enclosingPosition, "Not implemented"))
// case n =>
// c.abort(c.enclosingPosition, "Not implemented")
// }

// // case PolyType(typeParams, _) =>
// // println(s"POLY TYPE: $typeParams")
// // typeParams.size match {
// // case 1 =>
// // val tcTagTpe = appliedType(weakTypeOf[Tag.TCTag[X] forSome {type X[_]}].typeConstructor, t.typeConstructor)
// // optionFromImplicitTree(c.inferImplicitValue(tcTagTpe))
// // .map(t => q"$t.tpe")
// // .getOrElse(c.abort(c.enclosingPosition, "Not implemented"))
// // case n =>
// // c.abort(c.enclosingPosition, "Not implemented")
// // }
// // case x if x.typeSymbol.isParameter =>
// // val tagTpe = appliedType(weakTypeOf[Tag.TPTag[X] forSome {type X}].typeConstructor, t)
// // optionFromImplicitTree(c.inferImplicitValue(tagTpe))
// // .map{t => q"$t.tpe"}
// // .getOrElse(c.abort(c.enclosingPosition, "Not implemented"))
// case x =>
// c.abort(c.enclosingPosition, "Not implemented")
// }
// } else {
// t match {
// case ref: TypeRef =>
// val inner = ref.args.map(transformTpe2)
// q"_root_.make.Tag.TpeTag.Type(${ref.typeSymbol.fullName}, $inner)"
// case x =>
// c.info(c.enclosingPosition, s"TpeTag not implemented for $x: ${x.getClass}", true)
// c.abort(c.enclosingPosition, "Not implemented")
// }
// }
// }

// private def transformTpe(t: c.Type): c.Tree = {
// val normalized = t.dealias.etaExpand
// println(normalized + " " + normalized.getClass)
// val resolved =
// if (normalized.typeSymbol.isParameter) {
// normalized match {
// case PolyType(typeParams, _) =>
// println(s"POLY TYPE: $typeParams")
// typeParams.size match {
// case 1 =>
// val tcTagTpe = appliedType(weakTypeOf[Tag.TCTag[X] forSome {type X[_]}].typeConstructor, t.typeConstructor)
// optionFromImplicitTree(c.inferImplicitValue(tcTagTpe))
// .map(t => q"$t.tpe")
// case n =>
// None
// }
// case x if x.typeSymbol.isParameter =>
// val tagTpe = appliedType(weakTypeOf[Tag.TPTag[X] forSome {type X}].typeConstructor, t)
// optionFromImplicitTree(c.inferImplicitValue(tagTpe))
// .map{t => q"$t.tpe"}
// case x => None
// }
// } else {
// Some(q"${normalized.typeSymbol.fullName}")
// }

// resolved match {
// case None => c.abort(c.enclosingPosition, s"Not found Tag for $t")
// case Some(tree) =>
// tree
// // val arguments = t.typeArgs.map(transformTpe)
// // q"_root_.make.Tag.TpeTag.Type($tree, List(..$arguments))"
// }
// }

private def optionFromImplicitTree(tree: c.Tree): Option[c.Tree] =
tree match {
case EmptyTree => None
Expand All @@ -197,7 +70,6 @@ class TpeTagMacro(val c: blackbox.Context) {
): c.Expr[Tag.TCTag[F]] = {

val tpe = weakTypeTag.tpe
println(s"TCTAG: ${tpe} ${tpe.getClass}")
tpe match {
case tpe: PolyType =>
val symbol = c.internal.fullyInitialize(tpe.resultType.typeSymbol)
Expand Down Expand Up @@ -236,12 +108,10 @@ class TpeTagMacro(val c: blackbox.Context) {
// see test case with cats.Id
val skip =
name.startsWith("<local ") || name == "package" || (sym.isAbstract && sym.isParameter)
// val skip = false
val next = if (skip) acc else name :: acc
loop(sym.owner, next)
}
}
println(s.fullName)
loop(s, List.empty)
}

Expand Down
Loading

0 comments on commit 5f715f1

Please sign in to comment.