Skip to content

Commit

Permalink
Add TransformTypeConstraintRule and TransformImplicitConversionRule
Browse files Browse the repository at this point in the history
  • Loading branch information
MateuszKubuszok committed Jan 16, 2025
1 parent a24bab8 commit ef67255
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package io.scalaland.chimney.internal.compiletime

import scala.collection.compat.Factory

import TypeAlias.<:<<

private[compiletime] trait TypesPlatform extends Types { this: DefinitionsPlatform =>

import c.universe.{internal as _, Transformer as _, *}
Expand Down Expand Up @@ -185,6 +187,12 @@ private[compiletime] trait TypesPlatform extends Types { this: DefinitionsPlatfo
object CharLiteral extends LiteralImpl[Char] with CharLiteralModule
object StringLiteral extends LiteralImpl[String] with StringLiteralModule

object <:< extends `<:<Module` {
def apply[From: Type, To: Type]: Type[From <:<< To] = weakTypeTag[From <:<< To]
def unapply[A](A: Type[A]): Option[(??, ??)] =
A.asCtor[<:<<[?, ?]].map(A0 => A0.param(0) -> A0.param(1))
}

def isTuple[A](A: Type[A]): Boolean = A.tpe.typeSymbol.fullName.startsWith("scala.Tuple")

def isSubtypeOf[A, B](A: Type[A], B: Type[B]): Boolean = A.tpe <:< B.tpe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package io.scalaland.chimney.internal.compiletime
import scala.quoted
import scala.collection.compat.Factory

import TypeAlias.<:<<

private[compiletime] trait TypesPlatform extends Types { this: DefinitionsPlatform =>

import quotes.*, quotes.reflect.*
Expand Down Expand Up @@ -261,6 +263,14 @@ private[compiletime] trait TypesPlatform extends Types { this: DefinitionsPlatfo
object CharLiteral extends LiteralImpl[Char](CharConstant(_)) with CharLiteralModule
object StringLiteral extends LiteralImpl[String](StringConstant(_)) with StringLiteralModule

object <:< extends `<:<Module` {
def apply[From: Type, To: Type]: Type[From <:<< To] = quoted.Type.of[From <:<< To]
def unapply[A](A: Type[A]): Option[(??, ??)] = A match {
case '[<:<<[from, to]] => Some(Type[to].as_?? -> Type[to].as_??)
case _ => scala.None
}
}

def isTuple[A](A: Type[A]): Boolean = TypeRepr.of(using A).typeSymbol.fullName.startsWith("scala.Tuple")

def isSubtypeOf[A, B](A: Type[A], B: Type[B]): Boolean = TypeRepr.of(using A) <:< TypeRepr.of(using B)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package io.scalaland.chimney.internal.compiletime
import scala.collection.compat.Factory
import scala.collection.immutable.ListSet

import TypeAlias.<:<<

private[compiletime] trait Types { this: (Existentials & Results) =>

/** Platform-specific type representation (`c.WeakTypeTag[A]` in 2, `scala.quoted.Type[A]` in 3) */
Expand Down Expand Up @@ -145,6 +147,9 @@ private[compiletime] trait Types { this: (Existentials & Results) =>
val StringLiteral: StringLiteralModule
trait StringLiteralModule extends Literal[String] { this: StringLiteral.type => }

val <:< : `<:<Module`
trait `<:<Module` extends Ctor2[<:<<] { this: `<:<`.type => }

// You can `import Type.Implicits.*` in your shared code to avoid providing types manually, while avoiding conflicts
// with implicit types seen in platform-specific scopes (which would happen if those implicits were always used).
object Implicits {
Expand Down Expand Up @@ -183,6 +188,8 @@ private[compiletime] trait Types { this: (Existentials & Results) =>
implicit def MapType[K: Type, V: Type]: Type[scala.collection.Map[K, V]] = Map[K, V]
implicit def IteratorType[A: Type]: Type[Iterator[A]] = Iterator[A]
implicit def FactoryType[A: Type, C: Type]: Type[Factory[A, C]] = Factory[A, C]

implicit def `<:<Type`[From: Type, To: Type]: Type[From <:<< To] = <:<[From, To]
}

// Implementations of extension methods
Expand Down Expand Up @@ -254,3 +261,8 @@ private[compiletime] trait Types { this: (Existentials & Results) =>
def extractStringSingleton: String = Type.extractStringSingleton(tpe)
}
}
private[compiletime] object TypeAlias {
// Workaround for "type <:< is not a member of object Predef":
// apparently on 2.13/3 <:< is seen as defined in scala not scala.Predef.
type <:<<[-From, +To] = From <:< To
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ trait DerivationPlatform
with datatypes.ValueClassesPlatform
with rules.TransformImplicitRuleModule
with rules.TransformImplicitOuterTransformerRuleModule
with rules.TransformImplicitConversionRuleModule
with rules.TransformSubtypesRuleModule
with rules.TransformTypeConstraintRuleModule
with rules.TransformToSingletonRuleModule
with rules.TransformOptionToOptionRuleModule
with rules.TransformPartialOptionToNonOptionRuleModule
Expand All @@ -28,7 +30,9 @@ trait DerivationPlatform
override protected val rulesAvailableForPlatform: List[Rule] = List(
TransformImplicitRule,
TransformImplicitOuterTransformerRule,
TransformImplicitConversionRule,
TransformSubtypesRule,
TransformTypeConstraintRule,
TransformToSingletonRule,
TransformOptionToOptionRule,
TransformPartialOptionToNonOptionRule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ abstract private[compiletime] class DerivationPlatform(q: scala.quoted.Quotes)
with datatypes.ValueClassesPlatform
with rules.TransformImplicitRuleModule
with rules.TransformImplicitOuterTransformerRuleModule
with rules.TransformImplicitConversionRuleModule
with rules.TransformSubtypesRuleModule
with rules.TransformTypeConstraintRuleModule
with rules.TransformToSingletonRuleModule
with rules.TransformOptionToOptionRuleModule
with rules.TransformPartialOptionToNonOptionRuleModule
Expand All @@ -29,7 +31,9 @@ abstract private[compiletime] class DerivationPlatform(q: scala.quoted.Quotes)
override protected val rulesAvailableForPlatform: List[Rule] = List(
TransformImplicitRule,
TransformImplicitOuterTransformerRule,
TransformImplicitConversionRule,
TransformSubtypesRule,
TransformTypeConstraintRule,
TransformToSingletonRule,
TransformOptionToOptionRule,
TransformPartialOptionToNonOptionRule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.scalaland.chimney.internal.compiletime.derivation.transformer.rules

import io.scalaland.chimney.internal.compiletime.DerivationResult
import io.scalaland.chimney.internal.compiletime.derivation.transformer.Derivation

private[compiletime] trait TransformImplicitConversionRuleModule { this: Derivation =>

import Type.Implicits.*

protected object TransformImplicitConversionRule extends Rule("ImplicitConversion") {

def expand[From, To](implicit ctx: TransformationContext[From, To]): DerivationResult[Rule.ExpansionResult[To]] =
if (ctx.config.flags.implicitConversions) {
Expr.summonImplicit[From => To] match {
case Some(ev) => transformWithConversion[From, To](ev)
case None => DerivationResult.attemptNextRule
}
} else DerivationResult.attemptNextRuleBecause("Implicit conversions are disabled")

private def transformWithConversion[From, To](ev: Expr[From => To])(implicit
ctx: TransformationContext[From, To]
): DerivationResult[Rule.ExpansionResult[To]] =
// We're constructing:
// '{ ${ ev }.apply(${ src }) }
DerivationResult.expandedTotal(ev.apply(ctx.src))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.scalaland.chimney.internal.compiletime.derivation.transformer.rules

import io.scalaland.chimney.internal.compiletime.DerivationResult
import io.scalaland.chimney.internal.compiletime.derivation.transformer.Derivation

private[compiletime] trait TransformTypeConstraintRuleModule { this: Derivation =>

import Type.Implicits.*

protected object TransformTypeConstraintRule extends Rule("TypeConstraint") {

def expand[From, To](implicit ctx: TransformationContext[From, To]): DerivationResult[Rule.ExpansionResult[To]] =
if (ctx.config.flags.typeConstraintEvidence) {
Expr.summonImplicit[From <:< To] match {
case Some(ev) => transformWithEvidence[From, To](ev)
case None => DerivationResult.attemptNextRule
}
} else DerivationResult.attemptNextRuleBecause("<:< evidence is disabled")

private def transformWithEvidence[From, To](ev: Expr[From <:< To])(implicit
ctx: TransformationContext[From, To]
): DerivationResult[Rule.ExpansionResult[To]] =
// We're constructing:
// '{ ${ ev }.apply(${ src }) }
DerivationResult.expandedTotal(ev.upcastToExprOf[From => To].apply(ctx.src))
}
}

0 comments on commit ef67255

Please sign in to comment.