aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala
blob: f2ffaff5da61a979c471e0147f1fc10be4aab5a3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                          
                    

                 
                                                









                                                                                                 
                                                                                                                          



























                                                                                                                               
                                         





                                                                
                                           




                                                    
                                      


                                                          
                                           
                    
                                             
                                                              
                                         
                                    
                                                                          

                                     
                                                                                                                          
                                                 







                                                                    
                                                                     
                                                                                                               
                                                                                                                      






                                                                                                   
package dotty.tools.dotc
package transform

import core._
import TreeTransforms._
import Contexts.Context
import Flags._
import SymUtils._
import Symbols._
import SymDenotations._
import Types._
import Decorators._
import DenotTransformers._
import Annotations._
import StdNames._
import NameOps._
import NameKinds.{ExpandedName, TraitSetterName}
import ast.Trees._

/** This phase augments Scala2 traits with implementation classes and with additional members
 *  needed for mixin composition.
 *  These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline.
 *  Specifcally, it adds
 *
 *   - an implementation class which defines a trait constructor and trait method implementations
 *   - trait setters for vals defined in traits
 *
 *  Furthermore, it expands the names of all private getters and setters as well as super accessors in the trait and makes
 *  them not-private.
 */
class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransformer with FullParameterization { thisTransform =>
  import ast.tpd._

  override def phaseName: String = "augmentScala2Traits"

  override def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context) = NoSymbol

  override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
    val cls = impl.symbol.owner.asClass
    for (mixin <- cls.mixins)
      if (mixin.is(Scala2x))
        augmentScala2Trait(mixin, cls)
    impl
  }

  private def augmentScala2Trait(mixin: ClassSymbol, cls: ClassSymbol)(implicit ctx: Context): Unit = {
    if (mixin.implClass.is(Scala2x)) () // nothing to do, mixin was already augmented
    else {
      //println(i"creating new implclass for $mixin ${mixin.implClass}")
      val ops = new MixinOps(cls, thisTransform)
      import ops._

      val implClass = ctx.newCompleteClassSymbol(
        owner = mixin.owner,
        name = mixin.name.implClassName,
        flags = Abstract | Scala2x,
        parents = defn.ObjectType :: Nil,
        assocFile = mixin.assocFile).enteredAfter(thisTransform)

      def implMethod(meth: TermSymbol): Symbol = {
        val mold =
          if (meth.isConstructor)
            meth.copySymDenotation(
              name = nme.TRAIT_CONSTRUCTOR,
              info = MethodType(Nil, defn.UnitType))
          else meth.ensureNotPrivate
        meth.copy(
          owner = implClass,
          name = mold.name.asTermName,
          flags = Method | JavaStatic,
          info = fullyParameterizedType(mold.info, mixin))
      }

      def traitSetter(getter: TermSymbol) =
        getter.copy(
          name = getter.ensureNotPrivate.name
                  .expandedName(getter.owner, TraitSetterName)
                  .asTermName.setterName,
          flags = Method | Accessor,
          info = MethodType(getter.info.resultType :: Nil, defn.UnitType))

      for (sym <- mixin.info.decls) {
        if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred))
          implClass.enter(implMethod(sym.asTerm))
        if (sym.isGetter)
          if (sym.is(Lazy)) {
            if (!sym.hasAnnotation(defn.VolatileAnnot))
              sym.addAnnotation(Annotation(defn.VolatileAnnot, Nil))
          }
          else if (!sym.is(Deferred) && !sym.setter.exists &&
                   !sym.info.resultType.isInstanceOf[ConstantType])
            traitSetter(sym.asTerm).enteredAfter(thisTransform)
        if ((sym.is(PrivateAccessor) && !sym.name.is(ExpandedName) &&
          (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set.
          || sym.isSuperAccessor) // scala2 superaccessors are pickled as private, but are compiled as public expanded
          sym.ensureNotPrivate.installAfter(thisTransform)
      }
      ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %")
      ctx.log(i"Scala2x impl decls of $mixin = ${implClass.info.decls.toList.map(_.showDcl)}%\n %")
    }
  }
}