All Downloads are FREE. Search and download functionalities are using the official Maven repository.

monix.execution.misc.InlineMacros.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014-2019 by The Monix Project Developers.
 * See the project homepage at: https://monix.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package monix.execution.misc

import monix.execution.misc.compat.setOrig
import scala.reflect.macros.whitebox

trait InlineMacros {
  val c: whitebox.Context

  import c.universe._

  def inlineAndReset[A](tree: Tree): c.Expr[A] = {
    c.Expr[A](inlineAndResetTree(tree))
  }

  def inlineAndResetTree(tree: Tree): Tree = {
    val inlined = inlineApplyRecursive(tree)
    val clean = c.untypecheck(inlined)
    stripUnApplyNodes().transform(clean)
  }

  def resetTree(tree: Tree): Tree = {
    val clean = c.untypecheck(tree)
    stripUnApplyNodes().transform(clean)
  }

  def inlineApplyRecursive(tree: Tree): Tree = {
    val ApplyName = TermName("apply")

    class InlineSymbol(symbol: TermName, value: Tree) extends Transformer {
      override def transform(tree: Tree): Tree = tree match {
        case i @ Ident(_) if i.name == symbol =>
          value
        case tt: TypeTree if tt.original != null =>
          //super.transform(TypeTree().setOriginal(transform(tt.original)))
          super.transform(setOrig(c)(TypeTree(), transform(tt.original)))
        case _ =>
          super.transform(tree)
      }
    }

    object InlineApply extends Transformer {
      def inlineSymbol(symbol: TermName, body: Tree, arg: Tree): Tree =
        new InlineSymbol(symbol, arg).transform(body)

      override def transform(tree: Tree): Tree = tree match {
        case Apply(Select(Function(params, body), ApplyName), args) =>
          params.zip(args).foldLeft(body) {
            case (b, (param, arg)) =>
              inlineSymbol(param.name, b, arg)
          }

        case Apply(Function(params, body), args) =>
          params.zip(args).foldLeft(body) {
            case (b, (param, arg)) =>
              inlineSymbol(param.name, b, arg)
          }

        case _ =>
          super.transform(tree)
      }
    }

    InlineApply.transform(tree)
  }

  /** Creates a macro transformer that gets rid of implicit unapply
    * in case statements.
    *
    * Workaround for:
    * [[https://issues.scala-lang.org/browse/SI-5465]]
    */
  def stripUnApplyNodes(): Transformer =
    new Transformer {
      val global = c.universe.asInstanceOf[scala.tools.nsc.Global]
      import global.nme

      override def transform(tree: Tree): Tree = {
        super.transform {
          tree match {
            case UnApply(
                Apply(Select(qualifier, nme.unapply | nme.unapplySeq), List(Ident(nme.SELECTOR_DUMMY))),
                args) =>
              Apply(transform(qualifier), transformTrees(args))
            case UnApply(
                Apply(TypeApply(Select(qualifier, nme.unapply | nme.unapplySeq), _), List(Ident(nme.SELECTOR_DUMMY))),
                args) =>
              Apply(transform(qualifier), transformTrees(args))
            case t => t
          }
        }
      }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy