Created
July 25, 2026 22:15
-
-
Save otobrglez/fa066c1086e8d26ab2a9e51e4e87b440 to your computer and use it in GitHub Desktop.
Type-safe compilation with Scala 3 and macros
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Oto Brglez - <otobrglez@gmail.com> - Jul 2026 | |
| import scala.annotation.StaticAnnotation, scala.quoted.* | |
| final case class range(val lo: Int, val hi: Int) extends StaticAnnotation | |
| object Validate: | |
| inline def validate[T](inline o: T): Unit = ${ validateI[T]('o) } | |
| private def validateI[T: Type](o: Expr[T])(using Quotes): Expr[Unit] = | |
| import quotes.reflect.* | |
| val rangeT = TypeRepr.of[range] | |
| val params = TypeRepr.of[T].typeSymbol.primaryConstructor.paramSymss.flatten.filter(!_.isType) | |
| o.asTerm.underlyingArgument match | |
| case Apply(Select(_, "apply"), args) => | |
| params.zip(args).foreach: (p, arg) => | |
| val bounds = p.annotations.collectFirst: | |
| case Apply(Select(New(tt), _), List(Literal(IntConstant(lo)), Literal(IntConstant(hi)))) | |
| if tt.tpe =:= rangeT => lo -> hi | |
| bounds -> arg match | |
| case Some(lo -> hi) -> Literal(IntConstant(v)) if v < lo || v > hi => | |
| report.errorAndAbort(s"${p.name} = $v is outside [$lo, $hi]", arg.pos) | |
| case _ => () | |
| case _ => report.errorAndAbort("tsValidate requires construction.") | |
| '{ () } | |
| // Demo (separate file) | |
| final case class Config( | |
| @range(1, 65_535) port: Int, | |
| @range(1, 256) maxThreads: Int, | |
| @range(100, 30_000) timeoutMs: Int | |
| ) | |
| @main def demoApp: Unit = | |
| import Validate.* | |
| validate(Config(port = 1, maxThreads = 10, timeoutMs = 3233)) | |
| validate(Config(port = -12, maxThreads = 10, timeoutMs = 3233)) | |
| // Compile-time explosion: | |
| // scala-cli run Validate.scala TSValidationApp.scala --server=false | |
| // Warning: setting /Users/oto/Projects/scala-sandbox as the project root directory for this run. | |
| // -- Error: /Users/oto/Projects/scala-sandbox/TSValidationApp.scala:13:25 -------- | |
| // 13 | validate(Config(port = -12, maxThreads = 10, timeoutMs = 3233)) | |
| // | ^^^ | |
| // | port = -12 is outside [1, 65535] | |
| // 1 error found | |
| // Compilation failed |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment