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

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

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

import core._
import Symbols._, Types._, Contexts._, DenotTransformers._, Flags._
import util.Spans._
import SymUtils._
import StdNames._, NameOps._
import Decorators._

class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Context) {
  import ast.tpd._

  val superCls: Symbol = cls.superClass
  val mixins: List[ClassSymbol] = cls.mixins

  lazy val JUnit4Annotations: List[Symbol] = List("Test", "Ignore", "Before", "After", "BeforeClass", "AfterClass").
    map(n => ctx.getClassIfDefined("org.junit." + n)).
    filter(_.exists)

  def mkForwarderSym(member: TermSymbol, extraFlags: FlagSet = EmptyFlags): TermSymbol = {
    val res = member.copy(
      owner = cls,
      name = member.name.stripScala2LocalSuffix,
      flags = member.flags &~ Deferred | Synthetic | extraFlags,
      info = cls.thisType.memberInfo(member)).enteredAfter(thisPhase).asTerm
    res.addAnnotations(member.annotations.filter(_.symbol != defn.TailrecAnnot))
    res
  }

  def superRef(target: Symbol, span: Span = cls.span): Tree = {
    val sup = if (target.isConstructor && !target.owner.is(Trait))
      Super(This(cls), tpnme.EMPTY, true)
    else
      Super(This(cls), target.owner.name.asTypeName, false, target.owner)
    //println(i"super ref $target on $sup")
    ast.untpd.Select(sup.withSpan(span), target.name)
      .withType(NamedType(sup.tpe, target))
    //sup.select(target)
  }

  /** Is `sym` a member of implementing class `cls`?
   *  The test is performed at phase `thisPhase`.
   */
  def isCurrent(sym: Symbol): Boolean =
    ctx.atPhase(thisPhase) { implicit ctx =>
      cls.info.nonPrivateMember(sym.name).hasAltWith(_.symbol == sym)
    }

  /** Does `method` need a forwarder to in  class `cls`
   *  Method needs a forwarder in those cases:
   *   - there's a class defining a method with same signature
   *   - there are multiple traits defining method with same signature
   */
  def needsMixinForwarder(meth: Symbol): Boolean = {
    lazy val competingMethods = competingMethodsIterator(meth).toList

    def needsDisambiguation = competingMethods.exists(x=> !x.is(Deferred)) // multiple implementations are available
    def hasNonInterfaceDefinition = competingMethods.exists(!_.owner.is(Trait)) // there is a definition originating from class
    !meth.isConstructor &&
    meth.is(Method, butNot = PrivateOrAccessorOrDeferred) &&
    (ctx.settings.mixinForwarderChoices.isTruthy || meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition || needsJUnit4Fix(meth)) &&
    isCurrent(meth)
  }

  private def needsJUnit4Fix(meth: Symbol): Boolean = {
    meth.annotations.nonEmpty && JUnit4Annotations.exists(annot => meth.hasAnnotation(annot)) &&
      ctx.settings.mixinForwarderChoices.isAtLeastJunit
  }

  final val PrivateOrAccessor: FlagSet = Private | Accessor
  final val PrivateOrAccessorOrDeferred: FlagSet = Private | Accessor | Deferred

  def forwarderRhsFn(target: Symbol): List[Type] => List[List[Tree]] => Tree =
    targs => vrefss => {
      val tapp = superRef(target).appliedToTypes(targs)
      vrefss match {
        case Nil | List(Nil) =>
          // Overriding is somewhat loose about `()T` vs `=> T`, so just pick
          // whichever makes sense for `target`
          tapp.ensureApplied
        case _ =>
          tapp.appliedToArgss(vrefss)
      }
    }

  private def competingMethodsIterator(meth: Symbol): Iterator[Symbol] = {
    cls.baseClasses.iterator
      .filter(_ ne meth.owner)
      .map(base => meth.overriddenSymbol(base, cls))
      .filter(_.exists)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy