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

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

The newest version!
package dotty.tools.dotc
package transform

import core._
import MegaPhase._
import Contexts.Context
import Flags._
import SymUtils._
import Symbols._
import Types._
import Decorators._
import DenotTransformers._
import StdNames._
import ast.Trees._
import NameKinds.ImplMethName

/** Rewrite calls
 *
 *    super[M].f(args)
 *
 *  where M is a Scala 2.x trait implemented by the current class to
 *
 *    M.f$(this, args)
 *
 *  where f$ is a static member of M.
 */
class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhase =>
  import ast.tpd._

  override def phaseName: String = "linkScala2Impls"
  override def changesMembers: Boolean = true

  override def runsAfterGroupsOf: Set[String] = Set(Mixin.name)
    // Adds as a side effect static members to traits which can confuse Mixin,
    // that's why it is runsAfterGroupOf

  private def addStaticForwarders(mixin: ClassSymbol)(implicit ctx: Context): Unit = {
    val ops = new MixinOps(mixin, thisPhase)
    import ops._

    def newImpl(meth: TermSymbol): Symbol = {
      def staticInfo(tp: Type) = tp match {
        case mt: MethodType =>
          MethodType(nme.SELF :: mt.paramNames, mixin.typeRef :: mt.paramInfos, mt.resType)
      }
      val mold =
        if (meth.isConstructor)
          meth.copySymDenotation(
            name = nme.TRAIT_CONSTRUCTOR,
            info = MethodType(Nil, defn.UnitType))
        else meth.ensureNotPrivate
      meth.copy(
        owner = mixin,
        name = if (meth.isConstructor) mold.name.asTermName else ImplMethName(mold.name.asTermName),
        flags = Method | JavaStatic,
        info = staticInfo(mold.info)
      )
    }
    for (sym <- mixin.info.decls) {
      if (needsMixinForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred))
        newImpl(sym.asTerm).enteredAfter(thisPhase)
    }
    // The trait is now fully augmented so the flag isn't needed anymore.
    mixin.resetFlag(Scala2xPartiallyAugmented)
  }

  override def prepareForTemplate(impl: Template)(implicit ctx: Context): Context = {
    val cls = impl.symbol.owner.asClass
    for (mixin <- cls.mixins if (mixin.is(Scala2xPartiallyAugmented)))
      addStaticForwarders(mixin)
    ctx
  }

  override def transformApply(app: Apply)(implicit ctx: Context): Tree = {
    def currentClass = ctx.owner.enclosingClass.asClass
    app match {
      case Apply(sel @ Select(Super(_, _), _), args)
      if sel.symbol.owner.is(Scala2x) && currentClass.mixins.contains(sel.symbol.owner) =>
        val impl = implMethod(sel.symbol)
        if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withSpan(app.span)
        else app // could have been an abstract method in a trait linked to from a super constructor
      case _ =>
        app
    }
  }

  /** The 2.12 implementation method of a super call or implementation class target */
  private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = {
    val implName = ImplMethName(meth.name.asTermName)
    val cls = meth.owner
    if (cls.isAllOf(Scala2xTrait))
      if (meth.isConstructor)
        cls.info.decl(nme.TRAIT_CONSTRUCTOR).symbol
      else
        cls.info.decl(implName)
          .suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
          .symbol
    else throw new AssertionError(i"no impl method for $meth")
  }

  private val Scala2xTrait = Scala2x | Trait
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy