Bondarenko
Bondarenko

Reputation: 293

Int Refined Positive doesn't compile

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.

Upvotes: 0

Views: 258

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51683

Refined implicit conversions eu.timepit.refined.auto._ are macro-based (Scala 2 macros):

https://github.com/fthomas/refined/blob/v0.10.2/modules/core/shared/src/main/scala-3.0-/eu/timepit/refined/auto.scala#L58-L68 (Scala 2)

https://github.com/fthomas/refined/blob/v0.10.2/modules/core/shared/src/main/scala-3.0+/eu/timepit/refined/auto.scala (Scala 3)

// 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

refined macros not yet available

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

Upvotes: 3

Related Questions