1+ import quoted .*
2+ import scala .compiletime .testing .{typeChecks , typeCheckErrors }
3+ import scala .compiletime .testing .{Error , ErrorKind }
4+
5+ transparent inline def assertCompiles (inline code : String ): Unit =
6+ $ { assertCompilesImpl(' code , ' {typeCheckErrors(code)}) }
7+
8+ given FromExpr [ErrorKind ] with {
9+ def unapply (expr : Expr [ErrorKind ])(using Quotes ) = expr match {
10+ case ' { ErrorKind .Parser } => Some (ErrorKind .Parser )
11+ case ' { ErrorKind .Typer } => Some (ErrorKind .Typer )
12+ case _ => None
13+ }
14+ }
15+
16+ given FromExpr [Error ] with {
17+ def unapply (expr : Expr [Error ])(using Quotes ) = expr match {
18+ case ' { Error ($ {Expr (msg)}, $ {Expr (line)}, $ {Expr (col)}, $ {Expr (kind)}) } => Some (Error (msg, line, col, kind))
19+ case _ => None
20+ }
21+ }
22+
23+ private def assertCompilesImpl (self : Expr [_], typeChecked : Expr [List [Error ]])(using Quotes ): Expr [Unit ] = {
24+ import quotes .reflect ._
25+
26+ def checkCompile (code : String ): Expr [Unit ] = {
27+ // For some reason `typeChecked.valueOrError` is failing here, so instead we grab
28+ // the varargs argument to List.apply and use that to extract the list of errors
29+ val errors = typeChecked.asTerm.underlyingArgument match {
30+ case Apply (TypeApply (Select (Ident (" List" ), " apply" ), _), List (seq)) =>
31+ seq.asExprOf[Seq [Error ]].valueOrError.toList
32+ }
33+
34+ ' {}
35+ }
36+
37+ self.asTerm.underlyingArgument match {
38+
39+ case Literal (StringConstant (code)) =>
40+ checkCompile(code.toString)
41+
42+ case Apply (Select (_, " stripMargin" ), List (Literal (StringConstant (code)))) =>
43+ checkCompile(code.toString.stripMargin)
44+
45+ case _ =>
46+ report.throwError(" The 'assertCompiles' function only works with String literals." )
47+ }
48+ }
0 commit comments