From 575b37404e8e135a6c37c07a30cf591fcc6cfdfe Mon Sep 17 00:00:00 2001 From: Mateusz Kubuszok Date: Wed, 2 Oct 2024 18:55:23 +0200 Subject: [PATCH] Refactor TransformerConfiguration Paths to more explicitly trace what is matched on source-side and what on target-side --- .../transformer/Configurations.scala | 108 +++++++++++------- .../derivation/transformer/Derivation.scala | 6 +- .../TransformEitherToEitherRuleModule.scala | 14 ++- ...ransformIterableToIterableRuleModule.scala | 6 +- .../rules/TransformMapToMapRuleModule.scala | 8 +- .../TransformOptionToOptionRuleModule.scala | 6 +- ...rmPartialOptionToNonOptionRuleModule.scala | 10 +- .../TransformProductToProductRuleModule.scala | 19 ++- ...HierarchyToSealedHierarchyRuleModule.scala | 32 +++--- .../TransformTypeToValueClassRuleModule.scala | 1 + .../TransformValueClassToTypeRuleModule.scala | 6 +- ...formValueClassToValueClassRuleModule.scala | 10 +- 12 files changed, 145 insertions(+), 81 deletions(-) diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala index f90e36a32..58c4dfb03 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala @@ -173,11 +173,6 @@ private[compiletime] trait Configurations { this: Derivation => path.segments.headOption.collect { case Segment.Matching(tpe) => tpe -> new Path(path.segments.tail) } } - object AtSourceSubtype { - def unapply(path: Path): Option[(??, Path)] = - path.segments.headOption.collect { case Segment.SourceMatching(tpe) => tpe -> new Path(path.segments.tail) } - } - object AtItem { def unapply(path: Path): Option[Path] = path.segments.headOption.collect { case Segment.EveryItem => new Path(path.segments.tail) } @@ -226,6 +221,31 @@ private[compiletime] trait Configurations { this: Derivation => } } + sealed protected trait SidedPath extends scala.Product with Serializable { + def path: Path = this match { + case SourcePath(fromPath) => fromPath + case TargetPath(toPath) => toPath + } + def drop(droppedFrom: Path, droppedTo: Path)(implicit ctx: TransformationContext[?, ?]): Option[SidedPath] = + this match { + case SourcePath(fromPath) => fromPath.drop(droppedFrom).map(SourcePath(_)) + case TargetPath(toPath) => toPath.drop(droppedTo).map(TargetPath(_)) + } + } + object SidedPath { + + def unapply(sidedPath: SidedPath): Some[Path] = sidedPath match { + case SourcePath(fromPath) => Some(fromPath) + case TargetPath(toPath) => Some(toPath) + } + } + final protected case class SourcePath(fromPath: Path) extends SidedPath { + override def toString: String = s"Source at $fromPath" + } + final protected case class TargetPath(toPath: Path) extends SidedPath { + override def toString: String = s"Target at $toPath" + } + sealed protected trait TransformerOverride extends scala.Product with Serializable protected object TransformerOverride { sealed trait ForField extends TransformerOverride @@ -276,17 +296,16 @@ private[compiletime] trait Configurations { this: Derivation => /** Let us distinct if flags were modified only by implicit TransformerConfiguration or maybe also locally */ private val localFlagsOverridden: Boolean = false, /** Stores all customizations provided by user */ - private val runtimeOverrides: Vector[(Path, TransformerOverride)] = Vector.empty, + private val runtimeOverrides: Vector[(SidedPath, TransformerOverride)] = Vector.empty, /** Let us prevent `implicit val foo = foo` but allow `implicit val foo = new Foo { def sth = foo }` */ private val preventImplicitSummoningForTypes: Option[(??, ??)] = None ) { private lazy val runtimeOverridesForCurrent = runtimeOverrides.filter { - case (Path.AtField(_, Path.Root), _: TransformerOverride.ForField) => true - case (Path.AtSubtype(_, Path.Root), _: TransformerOverride.ForSubtype) => true - case (Path.AtSourceSubtype(_, Path.Root), _: TransformerOverride.ForSubtype) => true - case (Path.Root, _: TransformerOverride.ForConstructor) => true - case _ => false + case (SidedPath(Path.AtField(_, Path.Root)), _: TransformerOverride.ForField) => true + case (SidedPath(Path.AtSubtype(_, Path.Root)), _: TransformerOverride.ForSubtype) => true + case (SidedPath(Path.Root), _: TransformerOverride.ForConstructor) => true + case _ => false } def allowFromToImplicitSummoning: TransformerConfiguration = @@ -304,8 +323,8 @@ private[compiletime] trait Configurations { this: Derivation => def areLocalFlagsEmpty: Boolean = !localFlagsOverridden - def addTransformerOverride(path: Path, runtimeOverride: TransformerOverride): TransformerConfiguration = - copy(runtimeOverrides = runtimeOverrides :+ (path -> runtimeOverride)) + def addTransformerOverride(sidedPath: SidedPath, runtimeOverride: TransformerOverride): TransformerConfiguration = + copy(runtimeOverrides = runtimeOverrides :+ (sidedPath -> runtimeOverride)) def areOverridesEmpty: Boolean = runtimeOverrides.isEmpty def areLocalFlagsAndOverridesEmpty: Boolean = @@ -314,69 +333,74 @@ private[compiletime] trait Configurations { this: Derivation => def filterCurrentOverridesForField(nameFilter: String => Boolean): Map[String, TransformerOverride.ForField] = ListMap.from( runtimeOverridesForCurrent.collect { - case (Path.AtField(name, _), runtimeFieldOverride: TransformerOverride.ForField) if nameFilter(name) => + case (TargetPath(Path.AtField(name, _)), runtimeFieldOverride: TransformerOverride.ForField) + if nameFilter(name) => name -> runtimeFieldOverride } ) def filterCurrentOverridesForSubtype( - sourceTypeFilter: ?? => Boolean, - @scala.annotation.unused targetTypeFilter: ?? => Boolean - ): Map[Option[??], TransformerOverride.ForSubtype] = ListMap.from( + sourceTypeFilter: ?? => Boolean + ): Map[??, TransformerOverride.ForSubtype] = ListMap.from( runtimeOverridesForCurrent.collect { - case (Path.AtSourceSubtype(tpe, _), runtimeCoproductOverride: TransformerOverride.ForSubtype) + case (SourcePath(Path.AtSubtype(tpe, _)), runtimeCoproductOverride: TransformerOverride.ForSubtype) if sourceTypeFilter(tpe) => - Some(tpe) -> runtimeCoproductOverride + tpe -> runtimeCoproductOverride } ) def filterCurrentOverridesForSome: Set[TransformerOverride.ForField] = ListSet.from( runtimeOverrides.collect { - case (Path.AtSubtype(tpe, path), runtimeFieldOverride: TransformerOverride.ForField) + case (TargetPath(Path.AtSubtype(tpe, path)), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root && tpe.Underlying <:< Type[Some[Any]] => runtimeFieldOverride } ) def filterCurrentOverridesForLeft: Set[TransformerOverride.ForField] = ListSet.from( runtimeOverrides.collect { - case (Path.AtSubtype(tpe, path), runtimeFieldOverride: TransformerOverride.ForField) + case (TargetPath(Path.AtSubtype(tpe, path)), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root && tpe.Underlying <:< Type[Left[Any, Any]] => runtimeFieldOverride } ) def filterCurrentOverridesForRight: Set[TransformerOverride.ForField] = ListSet.from( runtimeOverrides.collect { - case (Path.AtSubtype(tpe, path), runtimeFieldOverride: TransformerOverride.ForField) + case (TargetPath(Path.AtSubtype(tpe, path)), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root && tpe.Underlying <:< Type[Right[Any, Any]] => runtimeFieldOverride } ) def filterCurrentOverridesForEveryItem: Set[TransformerOverride.ForField] = ListSet.from( runtimeOverrides.collect { - case (Path.AtItem(path), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root => + case (TargetPath(Path.AtItem(path)), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root => runtimeFieldOverride } ) def filterCurrentOverridesForEveryMapKey: Set[TransformerOverride.ForField] = ListSet.from( runtimeOverrides.collect { - case (Path.AtMapKey(path), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root => + case (TargetPath(Path.AtMapKey(path)), runtimeFieldOverride: TransformerOverride.ForField) + if path == Path.Root => runtimeFieldOverride } ) def filterCurrentOverridesForEveryMapValue: Set[TransformerOverride.ForField] = ListSet.from( runtimeOverrides.collect { - case (Path.AtMapValue(path), runtimeFieldOverride: TransformerOverride.ForField) if path == Path.Root => + case (TargetPath(Path.AtMapValue(path)), runtimeFieldOverride: TransformerOverride.ForField) + if path == Path.Root => runtimeFieldOverride } ) def currentOverrideForConstructor: Option[TransformerOverride.ForConstructor] = runtimeOverridesForCurrent.collectFirst { - case (_, runtimeConstructorOverride: TransformerOverride.ForConstructor) => runtimeConstructorOverride + case (TargetPath(_), runtimeConstructorOverride: TransformerOverride.ForConstructor) => + runtimeConstructorOverride } - def prepareForRecursiveCall(toPath: Path)(implicit ctx: TransformationContext[?, ?]): TransformerConfiguration = + def prepareForRecursiveCall(fromPath: Path, toPath: Path)(implicit + ctx: TransformationContext[?, ?] + ): TransformerConfiguration = copy( localFlagsOverridden = false, runtimeOverrides = for { - (path, runtimeOverride) <- runtimeOverrides + (sidedPath, runtimeOverride) <- runtimeOverrides alwaysDropOnRoot = runtimeOverride match { // Fields are always matched with "_.fieldName" Path while subtypes are always matched with // "_ match { case _: Tpe => }" so "_" Paths are useless in their case while they might get in way of @@ -385,9 +409,9 @@ private[compiletime] trait Configurations { this: Derivation => // Constructor is always matched at "_" Path, and dropped only when going inward case _: TransformerOverride.ForConstructor => false } - newPath <- path.drop(toPath).to(Vector) - if !(newPath == Path.Root && alwaysDropOnRoot) - } yield newPath -> runtimeOverride, + newSidePath <- sidedPath.drop(fromPath, toPath).to(Vector) + if !(newSidePath.path == Path.Root && alwaysDropOnRoot) + } yield newSidePath -> runtimeOverride, preventImplicitSummoningForTypes = None ) @@ -502,70 +526,70 @@ private[compiletime] trait Configurations { this: Derivation => import toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.Const(runtimeDataStore(runtimeDataIdx)) ) case ChimneyType.TransformerOverrides.ConstPartial(toPath, cfg) => import toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.ConstPartial(runtimeDataStore(runtimeDataIdx)) ) case ChimneyType.TransformerOverrides.Computed(toPath, cfg) => import toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.Computed(runtimeDataStore(runtimeDataIdx)) ) case ChimneyType.TransformerOverrides.ComputedPartial(toPath, cfg) => import toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.ComputedPartial(runtimeDataStore(runtimeDataIdx)) ) case ChimneyType.TransformerOverrides.CaseComputed(toPath, cfg) => import toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + SourcePath(extractPath[ToPath]), TransformerOverride.CaseComputed(runtimeDataStore(runtimeDataIdx)) ) case ChimneyType.TransformerOverrides.CaseComputedPartial(toPath, cfg) => import toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + SourcePath(extractPath[ToPath]), TransformerOverride.CaseComputedPartial(runtimeDataStore(runtimeDataIdx)) ) case ChimneyType.TransformerOverrides.Constructor(args, toPath, cfg) => import args.Underlying as Args, toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.Constructor(runtimeDataStore(runtimeDataIdx), extractArgumentLists[Args]) ) case ChimneyType.TransformerOverrides.ConstructorPartial(args, toPath, cfg) => import args.Underlying as Args, toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](1 + runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.ConstructorPartial(runtimeDataStore(runtimeDataIdx), extractArgumentLists[Args]) ) case ChimneyType.TransformerOverrides.RenamedFrom(fromPath, toPath, cfg) => import fromPath.Underlying as FromPath, toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[ToPath], + TargetPath(extractPath[ToPath]), TransformerOverride.RenamedFrom(extractPath[FromPath]) ) case ChimneyType.TransformerOverrides.RenamedTo(fromPath, toPath, cfg) => import fromPath.Underlying as FromPath, toPath.Underlying as ToPath, cfg.Underlying as Tail2 extractTransformerConfig[Tail2](runtimeDataIdx, runtimeDataStore) .addTransformerOverride( - extractPath[FromPath], + SourcePath(extractPath[FromPath]), TransformerOverride.RenamedTo(extractPath[ToPath]) ) // $COVERAGE-OFF$should never happen unless someone mess around with type-level representation @@ -585,7 +609,7 @@ private[compiletime] trait Configurations { this: Derivation => extractPath[PathType2].matching[Subtype] case ChimneyType.Path.SourceMatching(init, sourceSubtype) => import init.Underlying as PathType2, sourceSubtype.Underlying as SourceSubtype - extractPath[PathType2].sourceMatching[SourceSubtype] + extractPath[PathType2].matching[SourceSubtype] case ChimneyType.Path.EveryItem(init) => import init.Underlying as PathType2 extractPath[PathType2].everyItem diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Derivation.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Derivation.scala index 3fa051f8b..d55bb2874 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Derivation.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Derivation.scala @@ -44,19 +44,21 @@ private[compiletime] trait Derivation /** Intended use case: recursive derivation within rules */ final protected def deriveRecursiveTransformationExpr[NewFrom: Type, NewTo: Type]( newSrc: Expr[NewFrom], + followFrom: Path, followTo: Path )(implicit ctx: TransformationContext[?, ?]): DerivationResult[TransformationExpr[NewTo]] = - deriveRecursiveTransformationExprUpdatingRules[NewFrom, NewTo](newSrc, followTo)(identity) + deriveRecursiveTransformationExprUpdatingRules[NewFrom, NewTo](newSrc, followFrom, followTo)(identity) /** Intended use case: recursive derivation within rules which should remove some rules from consideration */ final protected def deriveRecursiveTransformationExprUpdatingRules[NewFrom: Type, NewTo: Type]( newSrc: Expr[NewFrom], + followFrom: Path, followTo: Path )( updateRules: List[Rule] => List[Rule] )(implicit ctx: TransformationContext[?, ?]): DerivationResult[TransformationExpr[NewTo]] = { val newCtx: TransformationContext[NewFrom, NewTo] = - ctx.updateFromTo[NewFrom, NewTo](newSrc).updateConfig(_.prepareForRecursiveCall(followTo)) + ctx.updateFromTo[NewFrom, NewTo](newSrc).updateConfig(_.prepareForRecursiveCall(followFrom, followTo)) deriveTransformationResultExprUpdatingRules(updateRules)(newCtx) .logSuccess { case TransformationExpr.TotalExpr(expr) => s"Derived recursively total expression ${Expr.prettyPrint(expr)}" diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformEitherToEitherRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformEitherToEitherRuleModule.scala index 9e33a5fae..1decd0162 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformEitherToEitherRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformEitherToEitherRuleModule.scala @@ -31,6 +31,7 @@ private[compiletime] trait TransformEitherToEitherRuleModule { useOverrideIfPresentOr("matchingLeft", ctx.config.filterCurrentOverridesForLeft) { deriveRecursiveTransformationExpr[FromL, ToL]( ctx.src.upcastToExprOf[Left[FromL, FromR]].value, + Path.Root.matching[Left[FromL, FromR]], Path.Root.matching[Left[ToL, ToR]] ) } @@ -46,6 +47,7 @@ private[compiletime] trait TransformEitherToEitherRuleModule { useOverrideIfPresentOr("matchingRight", ctx.config.filterCurrentOverridesForRight) { deriveRecursiveTransformationExpr[FromR, ToR]( ctx.src.upcastToExprOf[Right[FromL, FromR]].value, + Path.Root.matching[Right[FromL, FromR]], Path.Root.matching[Right[ToL, ToR]] ) } @@ -62,7 +64,11 @@ private[compiletime] trait TransformEitherToEitherRuleModule { .promise[FromL](ExprPromise.NameGenerationStrategy.FromPrefix("left")) .traverse { (leftExpr: Expr[FromL]) => useOverrideIfPresentOr("matchingLeft", ctx.config.filterCurrentOverridesForLeft) { - deriveRecursiveTransformationExpr[FromL, ToL](leftExpr, Path.Root.matching[Left[ToL, ToR]]) + deriveRecursiveTransformationExpr[FromL, ToL]( + leftExpr, + Path.Root.matching[Either[FromL, FromR]], + Path.Root.matching[Left[ToL, ToR]] + ) } } @@ -70,7 +76,11 @@ private[compiletime] trait TransformEitherToEitherRuleModule { .promise[FromR](ExprPromise.NameGenerationStrategy.FromPrefix("right")) .traverse { (rightExpr: Expr[FromR]) => useOverrideIfPresentOr("matchingRight", ctx.config.filterCurrentOverridesForRight) { - deriveRecursiveTransformationExpr[FromR, ToR](rightExpr, Path.Root.matching[Right[ToL, ToR]]) + deriveRecursiveTransformationExpr[FromR, ToR]( + rightExpr, + Path.Root.matching[Either[FromL, FromR]], + Path.Root.matching[Right[ToL, ToR]] + ) } } diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformIterableToIterableRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformIterableToIterableRuleModule.scala index 0e88d5708..9a802e09a 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformIterableToIterableRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformIterableToIterableRuleModule.scala @@ -57,14 +57,14 @@ private[compiletime] trait TransformIterableToIterableRuleModule { .promise[FromK](ExprPromise.NameGenerationStrategy.FromPrefix("key")) .traverse { key => useOverrideIfPresentOr("everyMapKey", ctx.config.filterCurrentOverridesForEveryMapKey) { - deriveRecursiveTransformationExpr[FromK, ToK](key, Path.Root.everyMapKey) + deriveRecursiveTransformationExpr[FromK, ToK](key, Path.Root.everyMapKey, Path.Root.everyMapKey) }.map(_.ensurePartial -> key) } val toValueResult = ExprPromise .promise[FromV](ExprPromise.NameGenerationStrategy.FromPrefix("value")) .traverse { value => useOverrideIfPresentOr("everyMapValue", ctx.config.filterCurrentOverridesForEveryMapValue) { - deriveRecursiveTransformationExpr[FromV, ToV](value, Path.Root.everyMapValue) + deriveRecursiveTransformationExpr[FromV, ToV](value, Path.Root.everyMapValue, Path.Root.everyMapValue) }.map(_.ensurePartial) } @@ -119,7 +119,7 @@ private[compiletime] trait TransformIterableToIterableRuleModule { .promise[InnerFrom](ExprPromise.NameGenerationStrategy.FromExpr(ctx.src)) .traverse { (newFromSrc: Expr[InnerFrom]) => useOverrideIfPresentOr("everyItem", ctx.config.filterCurrentOverridesForEveryItem) { - deriveRecursiveTransformationExpr[InnerFrom, InnerTo](newFromSrc, Path.Root.everyItem) + deriveRecursiveTransformationExpr[InnerFrom, InnerTo](newFromSrc, Path.Root.everyItem, Path.Root.everyItem) } } .flatMap { (to2P: ExprPromise[InnerFrom, TransformationExpr[InnerTo]]) => diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformMapToMapRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformMapToMapRuleModule.scala index 91a1dea09..442a769cf 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformMapToMapRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformMapToMapRuleModule.scala @@ -76,14 +76,14 @@ private[compiletime] trait TransformMapToMapRuleModule { .promise[FromK](ExprPromise.NameGenerationStrategy.FromPrefix("key")) .traverse { key => useOverrideIfPresentOr("everyMapKey", ctx.config.filterCurrentOverridesForEveryMapKey) { - deriveRecursiveTransformationExpr[FromK, ToK](key, Path.Root.everyMapKey) + deriveRecursiveTransformationExpr[FromK, ToK](key, Path.Root.everyMapKey, Path.Root.everyMapKey) }.map(_.ensureTotal) } val toValueResult = ExprPromise .promise[FromV](ExprPromise.NameGenerationStrategy.FromPrefix("value")) .traverse { value => useOverrideIfPresentOr("everyMapValue", ctx.config.filterCurrentOverridesForEveryMapValue) { - deriveRecursiveTransformationExpr[FromV, ToV](value, Path.Root.everyMapValue) + deriveRecursiveTransformationExpr[FromV, ToV](value, Path.Root.everyMapValue, Path.Root.everyMapValue) }.map(_.ensureTotal) } @@ -123,14 +123,14 @@ private[compiletime] trait TransformMapToMapRuleModule { .promise[FromK](ExprPromise.NameGenerationStrategy.FromPrefix("key")) .traverse { key => useOverrideIfPresentOr("everyMapKey", ctx.config.filterCurrentOverridesForEveryMapKey) { - deriveRecursiveTransformationExpr[FromK, ToK](key, Path.Root.everyMapKey) + deriveRecursiveTransformationExpr[FromK, ToK](key, Path.Root.everyMapKey, Path.Root.everyMapKey) }.map(_.ensurePartial -> key) } val toValueResult = ExprPromise .promise[FromV](ExprPromise.NameGenerationStrategy.FromPrefix("value")) .traverse { value => useOverrideIfPresentOr("everyMapValue", ctx.config.filterCurrentOverridesForEveryMapValue) { - deriveRecursiveTransformationExpr[FromV, ToV](value, Path.Root.everyMapValue) + deriveRecursiveTransformationExpr[FromV, ToV](value, Path.Root.everyMapValue, Path.Root.everyMapValue) }.map(_.ensurePartial -> value) } diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala index 6b4da6c05..94980c197 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala @@ -38,7 +38,11 @@ private[compiletime] trait TransformOptionToOptionRuleModule { .promise[InnerFrom](ExprPromise.NameGenerationStrategy.FromType) .traverse { (newFromExpr: Expr[InnerFrom]) => useOverrideIfPresentOr("matchingSome", ctx.config.filterCurrentOverridesForSome) { - deriveRecursiveTransformationExpr[InnerFrom, InnerTo](newFromExpr, Path.Root.matching[Some[InnerTo]]) + deriveRecursiveTransformationExpr[InnerFrom, InnerTo]( + newFromExpr, + Path.Root.matching[Some[InnerFrom]], + Path.Root.matching[Some[InnerTo]] + ) } } .flatMap { (derivedToExprPromise: ExprPromise[InnerFrom, TransformationExpr[InnerTo]]) => diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformPartialOptionToNonOptionRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformPartialOptionToNonOptionRuleModule.scala index 9567f0368..a23c22e3c 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformPartialOptionToNonOptionRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformPartialOptionToNonOptionRuleModule.scala @@ -6,7 +6,7 @@ import io.scalaland.chimney.partial private[compiletime] trait TransformPartialOptionToNonOptionRuleModule { this: Derivation => - import ChimneyType.Implicits.* + import Type.Implicits.*, ChimneyType.Implicits.* protected object TransformPartialOptionToNonOptionRule extends Rule("PartialOptionToNonOption") { @@ -46,7 +46,13 @@ private[compiletime] trait TransformPartialOptionToNonOptionRuleModule { this: D ctx.src, ChimneyExpr.PartialResult.fromEmpty[To], Expr.Function1.instance[InnerFrom, partial.Result[To]] { (from2Expr: Expr[InnerFrom]) => - await(deriveRecursiveTransformationExpr[InnerFrom, To](from2Expr, Path.Root)).ensurePartial + await( + deriveRecursiveTransformationExpr[InnerFrom, To]( + from2Expr, + Path.Root.matching[Some[InnerFrom]], + Path.Root + ) + ).ensurePartial } ) } diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala index 4ebf800a3..4437d9abd 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala @@ -405,7 +405,11 @@ private[compiletime] trait TransformProductToProductRuleModule { this: Derivatio ) { // We're constructing: // '{ ${ derivedToElement } } // using ${ src.$name } - deriveRecursiveTransformationExpr[ExtractedSrc, CtorParam](extractedSrcExpr, Path.Root.select(toName)) + deriveRecursiveTransformationExpr[ExtractedSrc, CtorParam]( + extractedSrcExpr, + sourcePath, + Path.Root.select(toName) + ) .transformWith { expr => // If we derived partial.Result[$ctorParam] we are appending: // ${ derivedToElement }.prependErrorPath(...).prependErrorPath(...) // sourcePath @@ -454,11 +458,14 @@ private[compiletime] trait TransformProductToProductRuleModule { this: Derivatio ) { // We're constructing: // '{ ${ derivedToElement } } // using ${ src.$name } - deriveRecursiveTransformationExpr[Getter, CtorParam](get(ctx.src), Path.Root.select(toName)).transformWith { - expr => - // If we derived partial.Result[$ctorParam] we are appending: - // ${ derivedToElement }.prependErrorPath(PathElement.Accessor("fromName")) - DerivationResult.existential[TransformationExpr, CtorParam](appendPath(expr, fromName)) + deriveRecursiveTransformationExpr[Getter, CtorParam]( + get(ctx.src), + Path.Root.select(fromName), + Path.Root.select(toName) + ).transformWith { expr => + // If we derived partial.Result[$ctorParam] we are appending: + // ${ derivedToElement }.prependErrorPath(PathElement.Accessor("fromName")) + DerivationResult.existential[TransformationExpr, CtorParam](appendPath(expr, fromName)) } { errors => appendMissingTransformer[From, To, Getter, CtorParam](errors, toName) } diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala index a2f27672e..ba9166aea 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala @@ -56,18 +56,10 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { private def mapOverriddenElements[From, To](implicit ctx: TransformationContext[From, To] ): DerivationResult[List[Existential[ExprPromise[*, TransformationExpr[To]]]]] = { - val overrides = ctx.config - .filterCurrentOverridesForSubtype( - someFrom => { - import someFrom.Underlying as SomeFrom - Type[SomeFrom] <:< Type[From] - }, - _ => false - ) - .toList - .collect { case (Some(someFrom), runtimeCoproductOverride) => - someFrom -> runtimeCoproductOverride - } + val overrides = ctx.config.filterCurrentOverridesForSubtype { (someFrom: ??) => + import someFrom.Underlying as SomeFrom + Type[SomeFrom] <:< Type[From] + }.toList Traverse[List].parTraverse[ DerivationResult, @@ -108,7 +100,8 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { import someTo.Underlying as SomeTo deriveRecursiveTransformationExpr[SomeFrom, SomeTo]( someFromExpr, - Path.Root.sourceMatching[SomeFrom] + Path.Root.matching[SomeFrom], + Path.Root.matching[SomeTo] ).map( _.fold(totalExpr => TransformationExpr.fromTotal(totalExpr.asInstanceOfExpr[To])) { partialExpr => @@ -154,6 +147,7 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { lazy val fromSubtypeIntoToSubtype = deriveRecursiveTransformationExpr[FromSubtype, ToSubtype]( fromSubtypeExpr, + Path.Root.matching[FromSubtype], Path.Root.matching[ToSubtype] ).map(_.map(toUpcast)) // We're constructing: @@ -168,7 +162,8 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { ) >> deriveRecursiveTransformationExpr[FromSubtypeInner, ToSubtype]( wrapper.unwrap(fromSubtypeExpr), - Path.Root + Path.Root.matching[FromSubtype].select(wrapper.fieldName), + Path.Root.matching[ToSubtype] ).map(_.map(toUpcast)) ) case _ => None @@ -184,6 +179,7 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { ) >> deriveRecursiveTransformationExpr[FromSubtype, ToSubtypeInner]( fromSubtypeExpr, + Path.Root.matching[FromSubtype], Path.Root.select(wrapper.fieldName) ).map(_.map(wrapper.wrap)).map(_.map(toUpcast)) ) @@ -218,9 +214,11 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { DerivationResult.log( s"Falling back on ${Type.prettyPrint[FromSubtype]} to ${Type.prettyPrint[To]} (target upcasted)" ) >> - deriveRecursiveTransformationExprUpdatingRules[FromSubtype, To](fromSubtypeExpr, Path.Root)(rules => - rules.filter(rule => rule.name == "Implicit") - ) + deriveRecursiveTransformationExprUpdatingRules[FromSubtype, To]( + fromSubtypeExpr, + Path.Root.matching[FromSubtype], + Path.Root + )(rules => rules.filter(rule => rule.name == "Implicit")) } .map(Existential[ExprPromise[*, TransformationExpr[To]], FromSubtype](_)) } diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformTypeToValueClassRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformTypeToValueClassRuleModule.scala index ada269d3a..c03749c51 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformTypeToValueClassRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformTypeToValueClassRuleModule.scala @@ -33,6 +33,7 @@ private[compiletime] trait TransformTypeToValueClassRuleModule { )(implicit ctx: TransformationContext[From, To]): DerivationResult[Rule.ExpansionResult[To]] = deriveRecursiveTransformationExpr[From, InnerTo]( ctx.src, + Path.Root, Path.Root.select(innerToFieldName) ) .flatMap { derivedInnerTo => diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToTypeRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToTypeRuleModule.scala index 7b9f93bc7..ef52e822d 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToTypeRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToTypeRuleModule.scala @@ -32,7 +32,11 @@ private[compiletime] trait TransformValueClassToTypeRuleModule { )(implicit ctx: TransformationContext[From, To]): DerivationResult[Rule.ExpansionResult[To]] = // We're constructing: // '{ ${ derivedTo } /* using ${ src }.from internally */ } - deriveRecursiveTransformationExpr[InnerFrom, To](unwrapFromIntoInnerFrom(ctx.src), Path.Root) + deriveRecursiveTransformationExpr[InnerFrom, To]( + unwrapFromIntoInnerFrom(ctx.src), + Path.Root.select(innerFromFieldName), + Path.Root + ) .flatMap(DerivationResult.expanded) // fall back to case classes expansion; see https://github.com/scalalandio/chimney/issues/297 for more info .orElse(TransformProductToProductRule.expand(ctx)) diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToValueClassRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToValueClassRuleModule.scala index fc79aebfe..dc3f56695 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToValueClassRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformValueClassToValueClassRuleModule.scala @@ -12,13 +12,19 @@ private[compiletime] trait TransformValueClassToValueClassRuleModule { this: Der case (ValueClassType(from2), ValueClassType(to2)) => if (ctx.config.areOverridesEmpty) { import from2.{Underlying as InnerFrom, value as valueFrom}, to2.{Underlying as InnerTo, value as valueTo} - unwrapTransformAndWrapAgain[From, To, InnerFrom, InnerTo](valueFrom.unwrap, valueTo.fieldName, valueTo.wrap) + unwrapTransformAndWrapAgain[From, To, InnerFrom, InnerTo]( + valueFrom.fieldName, + valueFrom.unwrap, + valueTo.fieldName, + valueTo.wrap + ) } else DerivationResult.attemptNextRuleBecause("Configuration has defined overrides") case (WrapperClassType(from2), WrapperClassType(to2)) => if (ctx.config.areOverridesEmpty) { if (ctx.config.flags.nonAnyValWrappers) { import from2.{Underlying as InnerFrom, value as valueFrom}, to2.{Underlying as InnerTo, value as valueTo} unwrapTransformAndWrapAgain[From, To, InnerFrom, InnerTo]( + valueFrom.fieldName, valueFrom.unwrap, valueTo.fieldName, valueTo.wrap @@ -31,12 +37,14 @@ private[compiletime] trait TransformValueClassToValueClassRuleModule { this: Der } private def unwrapTransformAndWrapAgain[From, To, InnerFrom: Type, InnerTo: Type]( + innerFromFieldName: String, unwrapFromIntoInnerFrom: Expr[From] => Expr[InnerFrom], innerToFieldName: String, wrapInnerToIntoIo: Expr[InnerTo] => Expr[To] )(implicit ctx: TransformationContext[From, To]): DerivationResult[Rule.ExpansionResult[To]] = deriveRecursiveTransformationExpr[InnerFrom, InnerTo]( unwrapFromIntoInnerFrom(ctx.src), + Path.Root.select(innerFromFieldName), Path.Root.select(innerToFieldName) ).flatMap { (derivedInnerTo: TransformationExpr[InnerTo]) => // We're constructing: