aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/MixinOps.scala
blob: d91522c25f120672ae53491598d4bcaecd4941ad (plain) (tree)
1
2
3
4
5
6
7





                                                                                     
                 




                                                                                          

                                            
 

                                                        

                                                
                                       
                                                                                
                                          

       











                                                                         





                                                           





                                                                                        
     





                                                                      
                                               
                                                                     


                                                                                                                               
                                                            

                                                                                    

   








                                                                                              
                                                                                                                    
               

                                                                                                         









                                                                                                                                  

                                                                       

                                                                                      






                                                                          
 
package dotty.tools.dotc
package transform

import core._
import Symbols._, Types._, Contexts._, SymDenotations._, DenotTransformers._, Flags._
import util.Positions._
import SymUtils._
import StdNames._, NameOps._

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

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

  def implementation(member: TermSymbol): TermSymbol = {
    val res = member.copy(
      owner = cls,
      name = member.name.stripScala2LocalSuffix,
      flags = member.flags &~ Deferred,
      info = cls.thisType.memberInfo(member)).enteredAfter(thisTransform).asTerm
    res.addAnnotations(member.annotations)
    res
  }

  def superRef(target: Symbol, pos: Position = cls.pos): 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.withPos(pos), target.name)
      .withType(NamedType.withFixedSym(sup.tpe, target))
    //sup.select(target)
  }

  /** Is `sym` a member of implementing class `cls`?
   *  The test is performed at phase `thisTransform`.
   */
  def isCurrent(sym: Symbol) =
    ctx.atPhase(thisTransform) { implicit ctx =>
      cls.info.member(sym.name).hasAltWith(_.symbol == sym)
      // this is a hot spot, where we spend several seconds while compiling stdlib
      // unfortunately it will discard and recompute all the member chaches,
      // both making itself slow and slowing down anything that runs after it
      // because resolveSuper uses hacks with explicit adding to scopes through .enter
      // this cannot be fixed by a smarter caching strategy. With current implementation
      // we HAVE to discard caches here for correctness
    }

  /** 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 needsForwarder(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.is(Method, butNot = PrivateOrAccessorOrDeferred) &&
    (meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition ) &&
    isCurrent(meth)
  }

  /** Get `sym` of the method that needs a forwarder
    *  Method needs a forwarder in those cases:
    *   - there is a trait that defines a primitive version of implemented polymorphic method.
    *   - there is a trait that defines a polymorphic version of implemented primitive method.
    */
  def needsPrimitiveForwarderTo(meth: Symbol): Option[Symbol] = {
    def hasPrimitiveMissMatch(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
      case (tp1: MethodicType, tp2: MethodicType) =>
        hasPrimitiveMissMatch(tp1.resultType, tp2.resultType) ||
        tp1.paramInfoss.flatten.zip(tp1.paramInfoss.flatten).exists(args => hasPrimitiveMissMatch(args._1, args._2))
      case _ =>
        def isPrimitiveOrValueClass(sym: Symbol): Boolean = sym.isPrimitiveValueClass || sym.isValueClass
        isPrimitiveOrValueClass(tp1.typeSymbol) ^ isPrimitiveOrValueClass(tp2.typeSymbol)
    }

    def needsPrimitiveForwarder(m: Symbol): Boolean =
      m.owner != cls && !m.is(Deferred) && hasPrimitiveMissMatch(meth.info, m.info)

    if (!meth.is(Method | Deferred, butNot = PrivateOrAccessor) || meth.overriddenSymbol(cls).exists || needsForwarder(meth)) None
    else competingMethodsIterator(meth).find(needsPrimitiveForwarder)
  }

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

  def forwarder(target: Symbol) = (targs: List[Type]) => (vrefss: List[List[Tree]]) =>
    superRef(target).appliedToTypes(targs).appliedToArgss(vrefss)

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