All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kyo.internal.FlatImplicits.scala Maven / Gradle / Ivy

There is a newer version: 0.8.5
Show newest version
package kyo.internal

import kyo._
import scala.quoted._

trait FlatImplicits0 {
  inline implicit def infer[T]: Flat[T] =
    ${ FlatImplicits.inferMacro[T] }
}

trait FlatImplicits1 extends FlatImplicits0 {
  implicit def product[T <: Product]: Flat[T] =
    Flat.unsafe.checked[T]
}

trait FlatImplicits extends FlatImplicits1 {
  implicit def anyVal[T <: AnyVal]: Flat[T] =
    Flat.unsafe.checked[T]
}

object FlatImplicits {

  def inferMacro[T: Type](using Quotes): Expr[Flat[T]] = {
    import quotes.reflect._

    val t = TypeRepr.of[T].dealias

    object Kyo {
      def unapply(tpe: TypeRepr): Option[(TypeRepr, TypeRepr)] =
        tpe match {
          case AppliedType(_, List(t, u)) if (tpe.typeSymbol == TypeRepr.of[>].typeSymbol) =>
            Some((t.dealias, u.dealias))
          case _ => None
        }
    }

    def code(str: String) =
      s"${Console.YELLOW}'$str'${Console.RESET}"

    def print(t: TypeRepr): String = {
      t match {
        case Kyo(t, s) =>
          s"${print(t)} > ${print(s)}"
        case _ => t.show
      }
    }

    def fail(msg: String) =
      report.errorAndAbort(s"Method doesn't accept nested Kyo computations.\n$msg")

    def canDerive(t: TypeRepr) =
      t.asType match {
        case '[nt] =>
          Expr.summon[Flat[nt]].isDefined
      }

    def isAny(t: TypeRepr) =
      t.typeSymbol == TypeRepr.of[Any].typeSymbol

    def isConcrete(t: TypeRepr) =
      t.typeSymbol.isClassDef

    def check(t: TypeRepr): Expr[Flat[T]] =
      if (isAny(t) || (!isConcrete(t.dealias) && !canDerive(t))) {
        fail(
            s"Cannot prove ${code(print(t))} isn't nested. Provide an implicit evidence ${code(s"kyo.Flat[${print(t)}]")}."
        )
      } else {
        '{ Flat.unsafe.checked[T] }
      }

    t match {
      case Kyo(Kyo(nt, s1), s2) =>
        val mismatch =
          if (print(s1) != print(s2)) {
            s"\nPossible pending effects mismatch: Expected ${code(print(s2))}, found ${code(print(s1))}."
          } else {
            ""
          }
        fail(
            s"Detected: ${code(print(t))}. Consider using ${code("flatten")} to resolve. " + mismatch
        )
      case Kyo(nt, s) =>
        check(nt)
      case t =>
        check(t)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy