From df8b9a453e56cbfb49eb06c4b64a47f4463a2589 Mon Sep 17 00:00:00 2001 From: Michal Sitko Date: Wed, 5 May 2021 23:09:13 +0200 Subject: [PATCH] Simple, hardcoded draft of macro --- .../main/scala-3.0+/eu/example/Example.scala | 17 +++++++++ .../scala-3.0+/eu/timepit/refined/auto.scala | 38 ++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 modules/core/shared/src/main/scala-3.0+/eu/example/Example.scala diff --git a/modules/core/shared/src/main/scala-3.0+/eu/example/Example.scala b/modules/core/shared/src/main/scala-3.0+/eu/example/Example.scala new file mode 100644 index 000000000..1238fa395 --- /dev/null +++ b/modules/core/shared/src/main/scala-3.0+/eu/example/Example.scala @@ -0,0 +1,17 @@ +package eu.example + +object Example { + import eu.timepit.refined.numeric._ + import eu.timepit.refined.api.Refined + import eu.timepit.refined.auto._ + import eu.timepit.refined._ + import eu.timepit.refined.api._ + import eu.timepit.refined.auto._ + + @main def main(): Unit = + val x: Int Refined Greater[5] = autoRefineV[Greater[5]](6) + // does not compile + // val x2: Int Refined Greater[5] = autoRefineV[Greater[5]](5) + println("hello") +} + diff --git a/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/auto.scala b/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/auto.scala index 9dd8c13d7..18da0143b 100644 --- a/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/auto.scala +++ b/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/auto.scala @@ -1,6 +1,11 @@ package eu.timepit.refined -import eu.timepit.refined.api.RefType +import eu.timepit.refined.api.{RefType, Refined, Validate} +import eu.timepit.refined.internal.WitnessAs + +import scala.quoted.{Expr, Quotes, ToExpr, Type, FromExpr} +import scala.compiletime.error +import scala.compiletime.{constValue, erasedValue} /** * Module that provides automatic refinements and automatic conversions @@ -30,4 +35,35 @@ object auto { */ implicit def autoUnwrap[F[_, _], T, P](tp: F[T, P])(implicit rt: RefType[F]): T = rt.unwrap(tp) + + inline def autoRefineV[P](inline t: Int)(implicit validate: Validate[Int, P]): Refined[Int, P] = + ${ autoRefineVCode[P]('t, 'validate) } + + private def autoRefineVCode[P : Type](t: Expr[Int], validate: Expr[Validate[Int, P]])(using q: Quotes): Expr[Refined[Int, P]] = + val tValue = t.valueOrError + Type.of[P] match + case '[ eu.timepit.refined.numeric.Greater[x] ] => + val tpe = q.reflect.TypeTree.of[P] + + val validateInstance = tpe.tpe match + case appliedType: q.reflect.AppliedType => + appliedType.args.headOption match + case Some(ct: q.reflect.ConstantType) => + ct.constant.value match + case limit: Int => + numeric.Greater.greaterValidate(WitnessAs.apply(limit, limit), summon[Numeric[Int]]) + case e => + q.reflect.report.throwError(s"cannot match: $e") + case e => + q.reflect.report.throwError(s"cannot match: $e") + case a => q.reflect.report.throwError(s"not here:: $a") + + val res = validateInstance.validate(tValue) + if (res.isFailed) { + val msg = validateInstance.showResult(tValue, res) + q.reflect.report.throwError(msg) + } + '{ RefType[Refined].unsafeWrap[Int, P]($t) } + case _ => + q.reflect.report.throwError("wrong: " + Type.show[P]) }