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

dotty.tools.dotc.transform.VCInlineMethods.scala Maven / Gradle / Ivy

There is a newer version: 3.6.4-RC1-bin-20241220-0bfa1af-NIGHTLY
Show newest version
package dotty.tools
package dotc
package transform

import ast.{Trees, tpd}
import core.*
import Contexts.*, Trees.*, Types.*
import DenotTransformers.*, MegaPhase.*
import ExtensionMethods.*, ValueClasses.*


/** This phase inlines calls to methods of value classes.
 *
 *  A value class V after [[ExtensionMethods]] will look like:
 *    class V[A, B, ...](val underlying: U) extends AnyVal {
 *      def foo[T, S, ...](arg1: A1, arg2: A2, ...) =
 *        V.foo$extension[T, S, ..., A, B, ...](this)(arg1, arg2, ...)
 *
 *       ...
 *    }
 *
 *  Let e have type V, if e is a stable prefix or if V does not have any class
 *  type parameter, then we can rewrite:
 *    e.foo[X, Y, ...](args)
 *  as:
 *    V.foo$extension[X, Y, ..., A', B', ...](e)(args)
 *    where A', B', ... are the class type parameters A, B, ... as seen from `e`.
 *  Otherwise, we need to evaluate e first:
 *    {
 *      val ev = e
 *      V.foo$extension[X, Y, ..., A', B', ...](ev)(args)
 *    }
 *
 *  This phase needs to be placed after phases which may introduce calls to
 *  value class methods (like [[PatternMatcher]]). This phase uses name mangling
 *  to find the correct extension method corresponding to a value class method
 *  (see [[ExtensionMethods.extensionMethod]]), therefore we choose to place it
 *  before phases which may perform their own name mangling on value class
 *  methods (like [[TypeSpecializer]]), this way [[VCInlineMethods]] does not
 *  need to have any knowledge of the name mangling done by other phases.
 */
class VCInlineMethods extends MiniPhase with IdentityDenotTransformer {
  import tpd.*

  override def phaseName: String = VCInlineMethods.name

  override def description: String = VCInlineMethods.description

  override def runsAfter: Set[String] =
    Set(ExtensionMethods.name, PatternMatcher.name)

  /** Replace a value class method call by a call to the corresponding extension method.
   *
   *  @param tree   The tree corresponding to the method call
   *  @param mtArgs Type arguments for the method call not present in `tree`
   *  @param mArgss Arguments for the method call not present in `tree`
   *  @return       A tree for the extension method call
   */
  private def rewire(tree: Tree, mtArgs: List[Tree] = Nil, mArgss: List[List[Tree]] = Nil)
    (using Context): Tree =
    tree match {
      case Apply(qual, mArgs) =>
        rewire(qual, mtArgs, mArgs :: mArgss)
      case TypeApply(qual, mtArgs2) =>
        assert(mtArgs == Nil)
        rewire(qual, mtArgs2, mArgss)
      case sel @ Select(qual, _) =>
        val origMeth = sel.symbol
        val origCls = origMeth.enclosingClass
        val ctParams = origCls.typeParams
        val extensionMeth = extensionMethod(origMeth)

        if (!ctParams.isEmpty)
          evalOnce(qual) { ev =>
            val ctArgs = ctParams.map(tparam =>
              TypeTree(tparam.typeRef.asSeenFrom(ev.tpe, origCls)))
            transformFollowing(
              ref(extensionMeth)
              .appliedToTypeTrees(mtArgs ++ ctArgs)
              .appliedTo(ev)
              .appliedToArgss(mArgss))
          }
        else
          ref(extensionMeth)
            .appliedToTypeTrees(mtArgs)
            .appliedTo(qual)
            .appliedToArgss(mArgss)
    }

  /** If this tree corresponds to a fully-applied value class method call, replace it
   *  by a call to the corresponding extension method, otherwise return it as is.
   */
  private def rewireIfNeeded(tree: Tree)(using Context) = tree.tpe.widen match {
    case tp: LambdaType =>
      tree // The rewiring will be handled by a fully-applied parent node
    case _ =>
      if (isMethodWithExtension(tree.symbol))
        rewire(tree).ensureConforms(tree.tpe).withSpan(tree.span)
      else
        tree
  }

  override def transformSelect(tree: Select)(using Context): Tree =
    rewireIfNeeded(tree)
  override def transformTypeApply(tree: TypeApply)(using Context): Tree =
    rewireIfNeeded(tree)
  override def transformApply(tree: Apply)(using Context): Tree =
    rewireIfNeeded(tree)
}

object VCInlineMethods:
  val name: String = "vcInlineMethods"
  val description: String = "inlines calls to value class methods"




© 2015 - 2025 Weber Informatics LLC | Privacy Policy