The followfing code doesn't compile:
import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
val i1: Int Refined Positive = 5
The error is:
[error] Found: (5 : Int)
[error] Required: Int Refined eu.timepit.refined.numeric.Positive
[error] val i1: Int Refined Positive = 5
I used Scala 3.2.2
and latest Refined eu.timepit::refined:0.10.2
According to documentation https://github.com/fthomas/refined it shoud compile.
Refined implicit conversions eu.timepit.refined.auto._
are macro-based (Scala 2 macros):
// Scala 2
implicit def autoRefineV[T, P](t: T)(implicit
rt: RefType[Refined],
v: Validate[T, P]
): Refined[T, P] = macro RefineMacro.impl[Refined, T, P]
Scala 2 macros do not expand in Scala 3
https://scalacenter.github.io/scala-3-migration-guide/docs/macros/macro-libraries.html
So the code you provided compiles in Scala 2: https://scastie.scala-lang.org/DmytroMitin/aj78AodyQkK1b9F66RXTsA/3
but not in Scala 3: https://scastie.scala-lang.org/DmytroMitin/aj78AodyQkK1b9F66RXTsA/1
See the ticket Macros missing for Scala 3 https://github.com/fthomas/refined/issues/932
The issue is that Refined Scala 2 macros use context.eval
.
What c.eval
does is transforming (compiling, evaluating) an abstract syntax tree (AST) into the value of this tree:
Scala: what can code in Context.eval reference?
Def Macro, pass parameter from a value
Scala: how to force converting a statement to literal?
Compile-time c.eval
used in macros is similar to runtime toolbox.eval
used in runtime compilation
How can I run generated code during script runtime? (Scala 2)
How to compile and execute scala code at run-time in Scala3? (Scala 3)
c.eval
is absent in Scala 3. More precisely, in Scala 3 there is staging.run
similar to tb.eval
but it's forbidden in Scala 3 macros because this would violate the phase consistency principle (PCP). Indeed, c.eval
/tb.eval
/staging.run
transforms a tree (a value from a previous stage) into the value of this tree (a value from a next stage).
Sometimes c.eval
can be emulated in Scala 3 (but starting from a source code rather than tree): get annotations from class in scala 3 macros
In order to use actual c.eval
/tb.eval
/staging.run
(starting from a tree) in Scala 3 macros, one would need to patch Scala 3 compiler: https://github.com/DmytroMitin/dotty-patched (or maybe a compiler plugin would be enough).
Scala 2 macros: https://docs.scala-lang.org/overviews/macros/overview.html
Scala 3 macros: https://docs.scala-lang.org/scala3/reference/metaprogramming/macros.html
Scala 2 macros to Scala 3 macros migration guide: https://docs.scala-lang.org/scala3/guides/migration/compatibility-metaprogramming.html