Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More nested-path functionalities #493

Merged
merged 20 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
561124b
Start using stubbed Paths for recursion rules (without testing yet)
MateuszKubuszok Apr 5, 2024
ae63c21
Rewrite a few usages of tpe.Underlying into Tpe, when import tpe.Unde…
MateuszKubuszok Apr 5, 2024
8a94eaa
Prototype of a nested-paths for subtypes and collections (internally,…
MateuszKubuszok Apr 5, 2024
9b9b749
Create extension methods for onSubtype/on.../eachItem/each... in DSL
MateuszKubuszok Apr 7, 2024
2159ce8
Scala 3 DSL parsing implementation, the first test for new nested con…
MateuszKubuszok Apr 8, 2024
6d06130
Fix more issues on Scala 3
MateuszKubuszok Apr 8, 2024
0828c0f
Modify implicits and DSL on Scala 2 to make DSL extensions for nested…
MateuszKubuszok Apr 8, 2024
68ffa2e
Change everyItem, everyMapKey and everyMapValue implementation in Sca…
MateuszKubuszok Apr 9, 2024
19cb771
Add implicitNotFound to IsOption, IsEither, IsCollection, IsMap type …
MateuszKubuszok Apr 9, 2024
68e6cb1
Revert some unnecessary changes (in benchmarks, unneeded renames, Fro…
MateuszKubuszok Apr 10, 2024
78c4e6e
Restore old behavior for computing error paths for converting pair co…
MateuszKubuszok Apr 10, 2024
5b2c5e5
Limit the number of pointless asInstanceOf in generated code
MateuszKubuszok Apr 10, 2024
bc8c212
More tests in Total Product spec
MateuszKubuszok Apr 10, 2024
d53cc6e
Merge widenExpr and upcastExpr into upcastToExprOf since they are bas…
MateuszKubuszok Apr 10, 2024
7330cc8
Happy-path nested-paths tests for Products
MateuszKubuszok Apr 10, 2024
820357f
Check nested-paths DSL in Product specs
MateuszKubuszok Apr 10, 2024
9542222
Refine nested-path DSL error messages
MateuszKubuszok Apr 10, 2024
2878c21
Test nested-paths DSL with std lib types, document nested-paths DSL
MateuszKubuszok Apr 10, 2024
99551ff
Initial documentation for nested paths in Chimney DSL
MateuszKubuszok Apr 10, 2024
d1a0d40
Document evidence types and suppress their coverage
MateuszKubuszok Apr 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Prototype of a nested-paths for subtypes and collections (internally,…
… no tests nor DSL changes which would allow using it)
  • Loading branch information
MateuszKubuszok committed Apr 5, 2024
commit 8a94eaa160e6700783700b697b589d60e82d0194
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,27 @@
if (A.isCtor[runtime.Path.Match[?, ?]]) Some(A.param_<[runtime.Path](0) -> A.param(1))
else scala.None
}
object EachItem extends EachItemModule {
def apply[Init <: runtime.Path: Type]: Type[runtime.Path.EachItem[Init]] =
weakTypeTag[runtime.Path.EachItem[Init]]

Check warning on line 352 in chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L352

Added line #L352 was not covered by tests
def unapply[A](A: Type[A]): Option[?<[runtime.Path]] =
if (A.isCtor[runtime.Path.EachItem[?]]) Some(A.param_<[runtime.Path](0))
else scala.None

Check warning on line 355 in chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L354-L355

Added lines #L354 - L355 were not covered by tests
}
object EachMapKey extends EachMapKeyModule {
def apply[Init <: runtime.Path: Type]: Type[runtime.Path.EachMapKey[Init]] =
weakTypeTag[runtime.Path.EachMapKey[Init]]

Check warning on line 359 in chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L359

Added line #L359 was not covered by tests
def unapply[A](A: Type[A]): Option[?<[runtime.Path]] =
if (A.isCtor[runtime.Path.EachMapKey[?]]) Some(A.param_<[runtime.Path](0))
else scala.None

Check warning on line 362 in chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L361-L362

Added lines #L361 - L362 were not covered by tests
}
object EachMapValue extends EachMapValueModule {
def apply[Init <: runtime.Path: Type]: Type[runtime.Path.EachMapValue[Init]] =
weakTypeTag[runtime.Path.EachMapValue[Init]]

Check warning on line 366 in chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L366

Added line #L366 was not covered by tests
def unapply[A](A: Type[A]): Option[?<[runtime.Path]] =
if (A.isCtor[runtime.Path.EachMapValue[?]]) Some(A.param_<[runtime.Path](0))
else scala.None

Check warning on line 369 in chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-2/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L368-L369

Added lines #L368 - L369 were not covered by tests
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,30 @@
Some((Type[init].as_?<[runtime.Path], Type[subtype].as_??))
case _ => scala.None
}
object EachItem extends EachItemModule {
def apply[Init <: runtime.Path: Type]: Type[runtime.Path.EachItem[Init]] =
quoted.Type.of[runtime.Path.EachItem[Init]]
def unapply[A](tpe: Type[A]): Option[?<[runtime.Path]] = tpe match
case '[runtime.Path.EachItem[init]] =>
Some(Type[init].as_?<[runtime.Path])
case _ => scala.None

Check warning on line 328 in chimney/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L323-L328

Added lines #L323 - L328 were not covered by tests
}
object EachMapKey extends EachMapKeyModule {
def apply[Init <: runtime.Path: Type]: Type[runtime.Path.EachMapKey[Init]] =
quoted.Type.of[runtime.Path.EachMapKey[Init]]
def unapply[A](tpe: Type[A]): Option[?<[runtime.Path]] = tpe match
case '[runtime.Path.EachMapKey[init]] =>
Some(Type[init].as_?<[runtime.Path])
case _ => scala.None

Check warning on line 336 in chimney/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L331-L336

Added lines #L331 - L336 were not covered by tests
}
object EachMapValue extends EachMapValueModule {
def apply[Init <: runtime.Path: Type]: Type[runtime.Path.EachMapValue[Init]] =
quoted.Type.of[runtime.Path.EachMapValue[Init]]
def unapply[A](tpe: Type[A]): Option[?<[runtime.Path]] = tpe match
case '[runtime.Path.EachMapValue[init]] =>
Some(Type[init].as_?<[runtime.Path])
case _ => scala.None

Check warning on line 344 in chimney/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ChimneyTypesPlatform.scala#L339-L344

Added lines #L339 - L344 were not covered by tests
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,24 @@ private[compiletime] trait ChimneyTypes { this: ChimneyDefinitions =>
Any,
runtime.Path.Match
] { this: Match.type => }
val EachItem: EachItemModule
trait EachItemModule
extends Type.Ctor1UpperBounded[
runtime.Path,
runtime.Path.EachItem
] { this: EachItem.type => }
val EachMapKey: EachMapKeyModule
trait EachMapKeyModule
extends Type.Ctor1UpperBounded[
runtime.Path,
runtime.Path.EachMapKey
] { this: EachMapKey.type => }
val EachMapValue: EachMapValueModule
trait EachMapValueModule
extends Type.Ctor1UpperBounded[
runtime.Path,
runtime.Path.EachMapValue
] { this: EachMapValue.type => }
}

// You can `import ChimneyType.Implicits.*` in your shared code to avoid providing types manually, while avoiding conflicts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,22 @@

final protected class Path private (private val segments: Vector[Path.Segment]) {

import Path.Segment.*
import Path.*, Path.Segment.*
def select(name: String): Path = new Path(segments :+ Select(name))
def `match`[Tpe: Type]: Path = new Path(segments :+ Match(Type[Tpe].as_??))
// TODO: implement these
def eachItem: Path = Path.clean
def eachMapKey: Path = Path.clean
def eachMapValue: Path = Path.clean
def eachItem: Path = new Path(segments :+ EachItem)
def eachMapKey: Path = new Path(segments :+ EachMapKey)
def eachMapValue: Path = new Path(segments :+ EachMapValue)

@scala.annotation.tailrec
def drop(prefix: Path)(implicit ctx: TransformationContext[?, ?]): Option[Path] = (prefix, this) match {
case (Path.Root, result) => Some(result)
case (Path.AtField(name1, prefix2), Path.AtField(name2, path2)) if areFieldNamesMatching(name1, name2) =>
path2.drop(prefix2)
case (Path.AtSubtype(tpe1, prefix2), Path.AtSubtype(tpe2, path2)) if tpe1.Underlying <:< tpe2.Underlying =>
path2.drop(prefix2)
case _ => None
case (Root, result) => Some(result)
case (AtField(name, prefix2), AtField(name2, tail)) if areFieldNamesMatching(name, name2) => tail.drop(prefix2)
case (AtSubtype(tpe, prefix2), AtSubtype(tpe2, tail)) if tpe.Underlying <:< tpe2.Underlying => tail.drop(prefix2)
case (AtItem(prefix2), AtItem(tail)) => tail.drop(prefix2)
case (AtMapKey(prefix2), AtMapKey(tail)) => tail.drop(prefix2)
case (AtMapValue(prefix2), AtMapValue(tail)) => tail.drop(prefix2)

Check warning on line 102 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L100-L102

Added lines #L100 - L102 were not covered by tests
case _ => None
}

override def equals(obj: Any): Boolean = obj match {
Expand All @@ -114,8 +114,6 @@

val Root = new Path(Vector())

val clean = new Path(Vector(Segment.Clean))

object AtField {
def unapply(path: Path): Option[(String, Path)] =
path.segments.headOption.collect { case Segment.Select(name) => name -> new Path(path.segments.tail) }
Expand All @@ -126,21 +124,43 @@
path.segments.headOption.collect { case Segment.Match(tpe) => tpe -> new Path(path.segments.tail) }
}

object AtItem {
def unapply(path: Path): Option[Path] =
path.segments.headOption.collect { case Segment.EachItem => new Path(path.segments.tail) }
}

object AtMapKey {
def unapply(path: Path): Option[Path] =
path.segments.headOption.collect { case Segment.EachMapKey => new Path(path.segments.tail) }
}

object AtMapValue {
def unapply(path: Path): Option[Path] =
path.segments.headOption.collect { case Segment.EachMapValue => new Path(path.segments.tail) }
}

sealed private trait Segment extends scala.Product with Serializable
private object Segment {
final case class Select(name: String) extends Segment {
override def toString: String = s".$name"
}
final case class Match(tpe: ??) extends Segment {

override def equals(obj: Any): Boolean = obj match {
case Match(tpe2) => tpe.Underlying =:= tpe2.Underlying
case _ => false
}
// TODO: figure out a better name

override def toString: String = s".whenSubtype[${Type.prettyPrint(tpe.Underlying)}]"
}
case object Clean extends Segment
case object EachItem extends Segment {
override def toString: String = ".eachItem"

Check warning on line 156 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L156

Added line #L156 was not covered by tests
}
case object EachMapKey extends Segment {
override def toString: String = ".eachMapKey"

Check warning on line 159 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L159

Added line #L159 was not covered by tests
}
case object EachMapValue extends Segment {
override def toString: String = ".eachMapValue"

Check warning on line 162 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L162

Added line #L162 was not covered by tests
}
}
}

Expand Down Expand Up @@ -432,6 +452,15 @@
case ChimneyType.Path.Match(init, subtype) =>
import init.Underlying as PathType2, subtype.Underlying as Subtype
extractPath[PathType2].`match`[Subtype]
case ChimneyType.Path.EachItem(init) =>
import init.Underlying as PathType2
extractPath[PathType2].eachItem
case ChimneyType.Path.EachMapKey(init) =>
import init.Underlying as PathType2
extractPath[PathType2].eachMapKey
case ChimneyType.Path.EachMapValue(init) =>
import init.Underlying as PathType2
extractPath[PathType2].eachMapValue

Check warning on line 463 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L455-L463

Added lines #L455 - L463 were not covered by tests
case _ =>
// $COVERAGE-OFF$
reportError(s"Invalid internal Path shape: ${Type.prettyPrint[PathType]}!!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,9 @@
path match {
case Path.AtField(name, path2) => appendPath[A](appendPath[A](expr, name), path2)
case Path.AtSubtype(_, path2) => appendPath[A](expr, path2)
case Path.AtItem(path2) => appendPath[A](expr, path2) // TODO: ?
case Path.AtMapKey(path2) => appendPath[A](expr, path2) // TODO: ?
case Path.AtMapValue(path2) => appendPath[A](expr, path2) // TODO: ?

Check warning on line 687 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala#L685-L687

Added lines #L685 - L687 were not covered by tests
case _ => expr
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ object Path {
final class Root extends Path
final class Select[Init <: Path, FieldName <: String] extends Path
final class Match[Init <: Path, Subtype] extends Path
final class EachItem[Init <: Path] extends Path
final class EachMapKey[Init <: Path] extends Path
final class EachMapValue[Init <: Path] extends Path
}
Loading