/
ShouldNotTypecheck.scala
37 lines (30 loc) · 1.37 KB
/
ShouldNotTypecheck.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.typesafe.slick.testkit.util
import scala.language.experimental.macros
import scala.reflect.macros.{Context, TypecheckException}
import scala.util.control.NonFatal
import java.util.regex.Pattern
/**
* A macro that ensures that a code snippet does not typecheck.
*/
object ShouldNotTypecheck {
def apply(code: String): Unit = macro applyImplNoExp
def apply(code: String, expected: String): Unit = macro applyImpl
def applyImplNoExp(ctx: Context)(code: ctx.Expr[String]) = applyImpl(ctx)(code, null)
def applyImpl(ctx: Context)(code: ctx.Expr[String], expected: ctx.Expr[String]): ctx.Expr[Unit] = {
import ctx.universe._
val Expr(Literal(Constant(codeStr: String))) = code
val (expPat, expMsg) = expected match {
case null => (null, "Expected some error.")
case Expr(Literal(Constant(s: String))) =>
(Pattern.compile(s, Pattern.CASE_INSENSITIVE | Pattern.DOTALL), "Expected error matching: "+s)
}
try ctx.typeCheck(ctx.parse("{ "+codeStr+" }")) catch { case e: TypecheckException =>
val msg = e.getMessage
if((expected ne null) && !(expPat.matcher(msg)).matches)
ctx.abort(ctx.enclosingPosition, "Type-checking failed in an unexpected way.\n"+
expMsg+"\nActual error: "+msg)
else return reify(())
}
ctx.abort(ctx.enclosingPosition, "Type-checking succeeded unexpectedly.\n"+expMsg)
}
}