Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active December 2, 2024 23:43
Show Gist options
  • Save xuwei-k/01294612380ecf75dd57abc7faa6f861 to your computer and use it in GitHub Desktop.
Save xuwei-k/01294612380ecf75dd57abc7faa6f861 to your computer and use it in GitHub Desktop.
Scala 3 generic numeric literals example
scalaVersion := "3.5.2"
scalacOptions += "-language:experimental.genericNumberLiterals"
package example
import scala.compiletime.testing.typeCheckErrors
object Main {
val x1: PosInt = 2
def main(args: Array[String]): Unit = {
println(x1)
val List(err) = typeCheckErrors("val x2: PosInt = -3")
println(err)
assert(err.message == "-3 is not positive")
}
}
package example
import scala.util.FromDigits
// 不正な値でのインスタンス化を防ぐためにコンストラクタはprivate
case class PosInt private (value: Int)
object PosInt {
def of(value: Int): Option[PosInt] = Option.when(value > 0)(PosInt(value))
given FromDigits[PosInt] with {
override inline def fromDigits(digits: String) = ${
PosIntMacros.fromDigitsImpl('digits)
}
}
}
package example
import scala.quoted.Expr
import scala.quoted.Quotes
object PosIntMacros {
def fromDigitsImpl(digits: Expr[String])(using q: Quotes): Expr[PosInt] = {
// 下のコメントにも書いたが、ここでvalueOrAbort呼びたいけど呼んではいけないぞ!
digits.value match {
case Some(str) =>
str.toIntOption match {
case Some(int) if int > 0 =>
'{ PosInt.of(${ Expr(int) }).get }
case _ =>
q.reflect.report.errorAndAbort(s"${str} is not positive")
}
case None =>
// ここは使われないけどダミーの実装書いておかないといけないという、謎規約で面倒
'{ ??? }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment