scala.reflect.macros.TypecheckException Scala Examples

The following examples show how to use scala.reflect.macros.TypecheckException. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: Macro.scala    From monadless   with Apache License 2.0 5 votes vote down vote up
package io.monadless.impl

import language.higherKinds
import scala.reflect.macros.blackbox.Context
import scala.reflect.macros.TypecheckException

private[monadless] class Macro(val c: Context) {
  import c.universe._

  def lift[M[_], T](body: Expr[T])(implicit m: WeakTypeTag[M[_]]): Tree = {
    val tree = Transformer[M](c)(body.tree)
    Trees.traverse(c)(tree) {
      case tree @ q"$pack.unlift[$t]($v)" =>
        c.error(tree.pos, "Unsupported unlift position")
    }
    try c.typecheck(tree)
    catch {
      case e: TypecheckException =>
        val msg =
          s"""Can't typecheck the monadless transformation. Please file a bug report with this error and your `Monadless` instance. 
             |Failure: ${e.msg}
             |Tree: $tree""".stripMargin
        c.abort(c.enclosingPosition, msg)
    }
  }
} 
Example 2
Source File: TestSupport.scala    From monadless   with Apache License 2.0 5 votes vote down vote up
package io.monadless.impl

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import org.scalamacros.resetallattrs._
import language.higherKinds
import scala.reflect.macros.TypecheckException

private[monadless] trait TestSupport[M[_]] {
  def get[T](m: M[T]): T
  def showTree[T](t: T): Unit = macro TestSupportMacro.showTree
  def showRawTree[T](t: T): Unit = macro TestSupportMacro.showRawTree
  def forceLift[T](t: T): T = macro TestSupportMacro.forceLift
  def runLiftTest[T](expected: T)(body: T): Unit = macro TestSupportMacro.runLiftTest[M, T]
}

private[monadless] class TestSupportMacro(val c: Context) {
  import c.universe._

  def showTree(t: Tree): Tree = {
    c.warning(c.enclosingPosition, t.toString)
    q"()"
  }
  def showRawTree(t: Tree): Tree = {
    c.warning(c.enclosingPosition, showRaw(t))
    q"()"
  }

  def forceLift(t: Tree): Tree =
    c.resetAllAttrs {
      Trees.Transform(c)(t) {
        case q"$pack.unlift[$t]($v)" =>
          q"${c.prefix}.get($v)"
      }
    }

  def runLiftTest[M[_], T](expected: Tree)(body: Tree): Tree =
    c.resetAllAttrs {

      val lifted =
        q"${c.prefix}.get(${c.prefix}.lift($body))"

      val forceLifted = forceLift(body)

      q"""
        val expected = scala.util.Try($expected)
        assert(expected == ${typecheckToTry(lifted, "lifted")})
        assert(expected == ${typecheckToTry(forceLifted, "force lifted")})
        ()
      """
    }

  def typecheckToTry(tree: Tree, name: String): Tree = {
    try {
      val typeCheckedTree = c.typecheck(c.resetAllAttrs(tree))
      c.info(c.enclosingPosition, s"$name: $typeCheckedTree", force = false)
      q"scala.util.Try($typeCheckedTree)"
    } catch {
      case e: TypecheckException =>
        val msg = s"""
          |$name fails typechecking: $e
          |tree: $tree
          |""".stripMargin
        c.info(e.pos.asInstanceOf[Position], msg, force = true)
        q"""scala.util.Failure(new Exception($msg))"""
    }
  }
} 
Example 3
Source File: TestMacros.scala    From udash-core   with Apache License 2.0 5 votes vote down vote up
package io.udash
package macros

import com.avsystem.commons.macros.AbstractMacroCommons

import scala.reflect.macros.{TypecheckException, blackbox}

class TestMacros(val ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {

  import c.universe._

  private def stringLiteral(tree: Tree): String = tree match {
    case StringLiteral(str) => str
    case Select(StringLiteral(str), TermName("stripMargin")) => str.stripMargin
    case _ => abort(s"expected string literal, got $tree")
  }

  def typeErrorImpl(code: Tree): Tree = {
    val codeTree = c.parse(stringLiteral(code))
    try {
      c.typecheck(codeTree)
      abort("expected typechecking error, none was raised")
    } catch {
      case TypecheckException(_, msg) => q"$msg"
    }
  }
} 
Example 4
Source File: Macros.scala    From zio   with Apache License 2.0 5 votes vote down vote up
package zio.test

import scala.reflect.macros.TypecheckException
import scala.reflect.macros.blackbox.Context

import zio.UIO

private[test] object Macros {

  def typeCheck_impl(c: Context)(code: c.Expr[String]): c.Expr[UIO[Either[String, Unit]]] = {
    import c.universe._
    try {
      c.typecheck(c.parse(c.eval(c.Expr[String](c.untypecheck(code.tree)))))
      c.Expr(q"zio.UIO.succeed(Right(()))")
    } catch {
      case e: TypecheckException => c.Expr(q"zio.UIO.succeed(Left(${e.getMessage}))")
      case t: Throwable          => c.Expr(q"""zio.UIO.die(new RuntimeException("Compilation failed: " + ${t.getMessage}))""")
    }
  }
} 
Example 5
Source File: typechecking.scala    From perf_tester   with Apache License 2.0 5 votes vote down vote up
package shapeless.test

import scala.language.experimental.macros

import java.util.regex.Pattern

import scala.reflect.macros.{ whitebox, ParseException, TypecheckException }


object illTyped {
  def apply(code: String): Unit = macro IllTypedMacros.applyImplNoExp
  def apply(code: String, expected: String): Unit = macro IllTypedMacros.applyImpl
}

@macrocompat.bundle
class IllTypedMacros(val c: whitebox.Context) {
  import c.universe._

  def applyImplNoExp(code: Tree): Tree = applyImpl(code, null)

  def applyImpl(code: Tree, expected: Tree): Tree = {
    val Literal(Constant(codeStr: String)) = code
    val (expPat, expMsg) = expected match {
      case null => (null, "Expected some error.")
      case Literal(Constant(s: String)) =>
        (Pattern.compile(s, Pattern.CASE_INSENSITIVE | Pattern.DOTALL), "Expected error matching: "+s)
    }

    try {
      val dummy0 = TermName(c.freshName)
      val dummy1 = TermName(c.freshName)
      c.typecheck(c.parse(s"object $dummy0 { val $dummy1 = { $codeStr } }"))
      c.error(c.enclosingPosition, "Type-checking succeeded unexpectedly.\n"+expMsg)
    } catch {
      case e: TypecheckException =>
        val msg = e.getMessage
        if((expected ne null) && !(expPat.matcher(msg)).matches)
          c.error(c.enclosingPosition, "Type-checking failed in an unexpected way.\n"+expMsg+"\nActual error: "+msg)
      case e: ParseException =>
        c.error(c.enclosingPosition, s"Parsing failed.\n${e.getMessage}")
    }

    q"()"
  }
} 
Example 6
Source File: ShouldNotTypecheck.scala    From lagom   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.lagom.macrotestkit

import scala.language.experimental.macros
import java.util.regex.Pattern

import scala.reflect.macros.TypecheckException
import scala.reflect.macros.blackbox


object ShouldNotTypecheck {
  def apply(name: String, code: String): Unit = macro ShouldNotTypecheck.applyImplNoExp
  def apply(name: String, code: String, expected: String): Unit = macro ShouldNotTypecheck.applyImpl
}

final class ShouldNotTypecheck(val c: blackbox.Context) {
  import c.universe._

  def applyImplNoExp(name: Expr[String], code: Expr[String]): Expr[Unit] = applyImpl(name, code, c.Expr(EmptyTree))

  def applyImpl(name: Expr[String], code: Expr[String], expected: Expr[String]): Expr[Unit] = {
    val Expr(Literal(Constant(codeStr: String))) = code
    val Expr(Literal(Constant(nameStr: String))) = name
    val (expPat, expMsg) = expected.tree match {
      case EmptyTree => (Pattern.compile(".*"), "Expected some error.")
      case Literal(Constant(s: String)) =>
        (Pattern.compile(s, Pattern.CASE_INSENSITIVE), "Expected error matching: " + s)
    }

    try c.typecheck(c.parse("{ " + codeStr + " }"))
    catch {
      case e: TypecheckException =>
        val msg = e.getMessage
        if (!expPat.matcher(msg).matches) {
          c.abort(c.enclosingPosition, s"$nameStr failed in an unexpected way.\n$expMsg\nActual error: $msg")
        } else {
          println(s"$nameStr passed.")
          return reify(())
        }
    }

    c.abort(c.enclosingPosition, s"$nameStr succeeded unexpectedly.\n$expMsg")
  }
} 
Example 7
Source File: ShouldNotTypecheck.scala    From scala-parallel-collections   with Apache License 2.0 5 votes vote down vote up
package testutil

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.reflect.macros.TypecheckException
import java.util.regex.Pattern


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)
  }
} 
Example 8
Source File: MacroCompat.scala    From pureconfig   with Mozilla Public License 2.0 5 votes vote down vote up
package pureconfig.derivation

import scala.reflect.macros.{ TypecheckException, whitebox }

import pureconfig.Derivation


trait MacroCompat {
  val c: whitebox.Context

  import c.universe._

  // since we are inside a whitebox implicit macro, error messages from `c.abort` as not printed. A trick must be used
  // to make the compiler print our custom message. That's done by setting a @implicitNotFound annotation on our
  // `Derivation` class (idea taken from shapeless `Lazy`).
  def setImplicitNotFound(msg: String): Unit = {
    import c.internal.decorators._
    val infTree = c.typecheck(q"""new _root_.scala.annotation.implicitNotFound($msg)""", silent = false)
    typeOf[Derivation[_]].typeSymbol.setAnnotations(Annotation(infTree))
  }

  // This should be simply defined as `c.inferImplicitValue(c.weakTypeOf[A])`, but divergent implicits are wrongly
  // reported up to Scala 2.12.2. See https://github.com/scala/bug/issues/10398 for more information.
  def inferImplicitValueCompat(typ: Type): Tree = {
    val cc = c.asInstanceOf[scala.reflect.macros.contexts.Context]
    val enclosingTree =
      cc.openImplicits.headOption.map(_.tree)
        .orElse(cc.enclosingMacros.lastOption.map(_.macroApplication))
        .getOrElse(EmptyTree).asInstanceOf[cc.universe.analyzer.global.Tree]

    val res: cc.Tree = cc.universe.analyzer.inferImplicit(
      enclosingTree, typ.asInstanceOf[cc.Type], false, cc.callsiteTyper.context, true, false, cc.enclosingPosition,
      (pos, msg) => throw TypecheckException(pos, msg))

    res.asInstanceOf[c.Tree]
  }
} 
Example 9
Source File: BodyElementCollectorMacro.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.dsl

import scala.reflect.macros.{ TypecheckException, blackbox }

class BodyElementCollectorMacro(context: blackbox.Context) {
  val c: blackbox.Context = context

  import c.universe._

  private val initTreeFold: (Tree, List[Tree]) = q"Nil" -> Nil

  def collectImpl(body: Tree): Tree = {
    val contextType = c.prefix.tree.tpe
    val validContext = typeOf[BodyElementCollector[_, _]]

    if (!(contextType <:< validContext))
      c.abort(c.enclosingPosition, s"Macro only allowed to be used directly inside of a `$validContext`")
    else {
      val elementType = contextType.typeArgs.head
      blockOrApplyExpressionList(body, elementType) { elements =>
        val (finalTree, rest) = elements.foldLeft(initTreeFold) {
          case ((accTree, accSingle), elem) =>
            if (elem.tpe <:< elementType)
              accTree -> (accSingle :+ elem) //todo avoid List.append
            else
              q"$accTree ++ $accSingle ++ $elem" -> Nil
        }

        q"${c.prefix.tree}.get($finalTree ++ $rest)"
      }
    }
  }

  private def blockOrApplyExpressionList(body: Tree, elementType: Type)(typesTreesFn: List[Tree] => Tree): c.universe.Tree =
    body match {
      case block: Block =>
        blockExpressionList(block, elementType)(typesTreesFn)
      case app: Apply =>
        singleExpressionList(app, elementType)(typesTreesFn)
      case Typed(app: Apply, _) =>
        singleExpressionList(app, elementType)(typesTreesFn)
      case s @ Select(_, _) =>
        singleExpressionList(s, elementType)(typesTreesFn)
      case e =>
        val unsupportedMessage = s"Unsupported expression. Only expressions of type `$elementType` are allowed here."
        c.abort(e.pos, s"$unsupportedMessage\nfound '$e' of type '${e.tpe}'")
    }

  private def singleExpressionList(app: Tree, elementType: Type)(typesTreesFn: List[Tree] => Tree): c.universe.Tree =
    typeCheck(elementType, seqElementType(elementType))(app) match {
      case Right(checked)     => typesTreesFn(checked :: Nil)
      case Left((pos, error)) => c.abort(pos, error)
    }

  private def seqElementType(elementType: Type): Type =
    c.typecheck(q"Seq[$elementType]()").tpe

  private def blockExpressionList(block: Block, elementType: Type)(typesTreesFn: List[Tree] => Tree): c.universe.Tree = {
    val allStats = block.stats :+ block.expr //todo avoid List.append
    val seq = seqElementType(elementType)
    val checked = allStats.map(typeCheck(elementType, seq))

    if (checked.exists(_.isLeft)) {
      val errors = checked.collect { case Left(error) => error }
      errors.dropRight(1).foreach { case (pos, error) => c.error(pos, error) }
      val lastError = errors.last
      c.abort(lastError._1, lastError._2)
    } else
      typesTreesFn(checked.collect { case Right(typed) => typed })
  }

  private def typeCheck(elementType: Type, seq: Type)(tree: Tree): Either[(c.universe.Position, String), c.Tree] = {
    val checked = c.typecheck(tree)
    // checked.tpe is null if the statement is an import
    if (checked.tpe == null)
      Left(tree.pos -> s"Expected expression of either `$elementType` or `$seq` but found '$tree'")
    else if (checked.tpe <:< elementType || checked.tpe <:< seq)
      Right(checked)
    else
      try Right(c.typecheck(tree, pt = elementType)) catch {
        case TypecheckException(_, msg) => Left(tree.pos ->
          (s"Result of this expression can be either `$elementType` or `$seq`. " + msg))
      }
  }
}