mixin.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 818 行 · 第 1/3 页

SCALA
818
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Martin Odersky */// $Id: Mixin.scala 14106 2008-02-22 13:24:21Z odersky $package scala.tools.nsc.transformimport symtab._import Flags._import scala.collection.mutable.ListBufferimport scala.tools.nsc.util.{Position,NoPosition}import scala.collection.mutable.HashMapabstract class Mixin extends InfoTransform {  import global._  import definitions._  import posAssigner.atPos  /** The name of the phase: */  val phaseName: String = "mixin"  /** The phase might set the fiollowing new flags: */  override def phaseNewFlags: Long = lateMODULE | notABSTRACT  /** This map contains a binding (class -> info) if   *  the class with this info at phase mixinPhase has been treated for mixin composition    */  private val treatedClassInfos = collection.mutable.Map[Symbol, Type]()// --------- helper functions -----------------------------------------------  /** A member of a trait is implemented statically if its implementation after the   *  mixin transform is in the static implementation module. To be statically   *  implemented, a member must be a method that belonged to the trait's implementation class   *  before (e.g. it is not abstract). Not statically implemented are   *   - non-private modules: these are implemented directly in the mixin composition class   *     (private modules, on the other hand, are implemented statically, but their   *      module variable is not. all such private modules are lifted, because    *      non-lifted private modules have been eliminated in ExplicitOuter)   *   - field accessors and superaccessors, except for lazy value accessors which become initializer   *     methods in the impl class (because they can have arbitrary initializers)   */  private def isImplementedStatically(sym: Symbol) =    sym.owner.isImplClass && sym.isMethod &&    (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED)) &&    (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.hasFlag(LAZY))  /** A member of a trait is static only if it belongs only to the   *  implementation class, not the interface, and it is implemented   *  statically.   */  private def isStaticOnly(sym: Symbol) =    isImplementedStatically(sym) && sym.isImplOnly  /** A member of a trait is forwarded if it is implemented statically and it   *  is also visible in the trait's interface. In that case, a forwarder to   *  the member's static implementation will be added to the class that   *  inherits the trait.   */  private def isForwarded(sym: Symbol) =    isImplementedStatically(sym) && !sym.isImplOnly  /** Maps the type of an implementation class to its interface;   *  maps all other types to themselves.   */  private def toInterface(tp: Type): Type =    atPhase(currentRun.mixinPhase)(tp.typeSymbol.toInterface).tpe  /** Maps all parts of this type that refer to implementation classes to   *  their corresponding interfaces.   */  private val toInterfaceMap = new TypeMap {    def apply(tp: Type): Type = mapOver( tp match {      case TypeRef(pre, sym, args) if (sym.isImplClass) =>        typeRef(pre, atPhase(currentRun.mixinPhase)(sym.toInterface), args)      case _ => tp    })  }  /** The implementation class corresponding to a currently compiled interface.   *  todo: try to use Symbol.implClass instead?   */  private def implClass(iface: Symbol): Symbol = {    val impl = iface.implClass    if (impl != NoSymbol) impl else erasure.implClass(iface)  }  /** Returns the symbol that is accessed by a super-accessor in a mixin composition.   *   *  @param base       The class in mwhich everything is mixed together   *  @param member     The symbol statically referred to by the superaccessor in the trait   *  @param mixinClass The mixin class that produced the superaccessor   */  private def rebindSuper(base: Symbol, member: Symbol, mixinClass: Symbol): Symbol =    atPhase(currentRun.refchecksPhase) {      var bcs = base.info.baseClasses.dropWhile(mixinClass !=).tail      var sym: Symbol = NoSymbol      if (settings.debug.value)        log("starting rebindsuper " + base + " " + member + ":" + member.tpe +            " " + mixinClass + " " + base.info.baseClasses)      while (!bcs.isEmpty && sym == NoSymbol) {        if (settings.debug.value) {          val other = bcs.head.info.nonPrivateDecl(member.name);          log("rebindsuper " + bcs.head + " " + other + " " + other.tpe +              " " + other.isDeferred)        }        sym = member.overridingSymbol(bcs.head).suchThat(sym => !sym.hasFlag(DEFERRED | BRIDGE))        bcs = bcs.tail      }      assert(sym != NoSymbol, member)      sym    }// --------- type transformation -----------------------------------------------  /** Add given member to given class, and mark member as mixed-in.   */  def addMember(clazz: Symbol, member: Symbol): Symbol = {    if (settings.debug.value) log("new member of " + clazz + ":" + member.defString)    clazz.info.decls enter member    member setFlag MIXEDIN  }  /** Add getters and setters for all non-module fields of an implementation   *  class to its interface unless they are already present. This is done   *  only once per class. The mixedin flag is used to remember whether late   *  members have been added to an interface.   *    - lazy fields don't get a setter.   *     *  @param clazz ...   */  def addLateInterfaceMembers(clazz: Symbol) {    if ((treatedClassInfos get clazz) != Some(clazz.info)) {      treatedClassInfos(clazz) = clazz.info      assert(phase == currentRun.mixinPhase)      /** Create a new getter. Getters are never private or local. They are       *  always accessors and deferred. */      def newGetter(field: Symbol): Symbol =        clazz.newMethod(field.pos, nme.getterName(field.name))          .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | lateDEFERRED)          .setInfo(MethodType(List(), field.info))      /** Create a new setter. Setters are never private or local. They are       *  always accessors and deferred. */      def newSetter(field: Symbol): Symbol =        clazz.newMethod(field.pos, nme.getterToSetter(nme.getterName(field.name)))          .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | lateDEFERRED)          .setInfo(MethodType(List(field.info), UnitClass.tpe))      clazz.info // make sure info is up to date, so that implClass is set.      val impl = implClass(clazz)      assert(impl != NoSymbol)      for (val member <- impl.info.decls.toList) {        if (!member.isMethod && !member.isModule && !member.isModuleVar) {          assert(member.isTerm && !member.isDeferred, member)          if (member.getter(impl) hasFlag PRIVATE) {            member.makeNotPrivate(clazz) // this will also make getter&setter not private          }          val getter = member.getter(clazz)          if (getter == NoSymbol) addMember(clazz, newGetter(member))          if (!member.tpe.isInstanceOf[ConstantType] && !member.hasFlag(LAZY)) {            val setter = member.setter(clazz)            if (setter == NoSymbol) addMember(clazz, newSetter(member))          }        }      }      if (settings.debug.value) log("new defs of " + clazz + " = " + clazz.info.decls);    }  }  /** Map a lazy, mixedin field accessor to it's trait member accessor */  val initializer = new HashMap[Symbol, Symbol]    /** Add all members to be mixed in into a (non-trait-) class   *  These are:   *    for every mixin trait T that is not also inherited by the superclass:   *     add late interface members to T and then:   *      - if a member M of T is forwarded to the implementation class, add   *        a forwarder for M unless one exists already.   *        The alias of the forwarder is the static member it forwards to.   *      - for every abstract accessor in T, add a field and an implementation for that acessor   *      - for every super accessor in T, add an implementation of that accessor   *      - for every module in T, add a module   */  def addMixedinMembers(clazz: Symbol) {    if (!(clazz hasFlag JAVA) && (treatedClassInfos get clazz) != Some(clazz.info)) {      treatedClassInfos(clazz) = clazz.info      assert(!clazz.isTrait, clazz)      assert(!clazz.info.parents.isEmpty, clazz)      // first complete the superclass with mixed in members      addMixedinMembers(clazz.superClass)      //Console.println("adding members of " + clazz.info.baseClasses.tail.takeWhile(superclazz !=) + " to " + clazz);//DEBUG      /** Mix in members of implementation class mixinClass into class clazz */      def mixinImplClassMembers(impl: Symbol, iface: Symbol) {        assert (impl.isImplClass)        for (val member <- impl.info.decls.toList) {          if (isForwarded(member)) {            val imember = member.overriddenSymbol(iface)            //Console.println("mixin member "+member+":"+member.tpe+member.locationString+" "+imember+" "+imember.overridingSymbol(clazz)+" to "+clazz+" with scope "+clazz.info.decls)//DEBUG            if (imember.overridingSymbol(clazz) == NoSymbol &&                clazz.info.findMember(member.name, 0, lateDEFERRED, false).alternatives.contains(imember)) {                  val member1 = addMember(                    clazz,                    member.cloneSymbol(clazz) setPos clazz.pos resetFlag (DEFERRED | lateDEFERRED))                  member1.asInstanceOf[TermSymbol] setAlias member;                }          }        }      }      /** Mix in members of trait mixinClass into class clazz. Also,       *  for each lazy field in mixinClass, add a link from its mixed in member to it's        *  initializer method inside the implclass.       */      def mixinTraitMembers(mixinClass: Symbol) {        // For all members of a trait's interface do:        def isConcreteAccessor(member: Symbol) =           (member hasFlag ACCESSOR) &&           (!(member hasFlag DEFERRED) || (member hasFlag lateDEFERRED))        def isOverridden(member: Symbol) =          isConcreteAccessor(member.overridingSymbol(clazz))        for (val member <- mixinClass.info.decls.toList) {          if (isConcreteAccessor(member)) {            if (isOverridden(member)) {              if (settings.debug.value) println("!!! is overridden val: "+member)            } else {              // mixin field accessors              val member1 = addMember(                clazz,                member.cloneSymbol(clazz)                  setPos clazz.pos                  setFlag FINAL resetFlag (DEFERRED | lateDEFERRED))              if (member.hasFlag(LAZY)) {                var init = implClass(mixinClass).info.decl(member.name)                assert(init != NoSymbol, "Could not find initializer for " + member.name)                initializer(member1) = init              }              if (!member.isSetter)                member.tpe match {                  case MethodType(List(), ConstantType(_)) =>                    // member is a constant; only getter is needed                    ;                  case MethodType(List(), TypeRef(_, tpeSym, _))                    if member.hasFlag(LAZY) && tpeSym == definitions.UnitClass =>                    // member is a lazy value of type unit. No field needed                    ;                  case _ =>                    // otherwise mixin a field as well                    addMember(clazz,                              clazz.newValue(member.pos, nme.getterToLocal(member.name))                              setFlag (LOCAL | PRIVATE | member.getFlag(MUTABLE | LAZY))                              setFlag (if (!member.hasFlag(STABLE)) MUTABLE else 0)                              setInfo member.tpe.resultType                              setAttributes member.attributes)                }            }          } else if (member hasFlag SUPERACCESSOR) { // mixin super accessors            val member1 = addMember(clazz, member.cloneSymbol(clazz)) setPos clazz.pos            assert(member1.alias != NoSymbol, member1)            val alias1 = rebindSuper(clazz, member.alias, mixinClass)            member1.asInstanceOf[TermSymbol] setAlias alias1          } else if (member.isMethod && member.isModule && !(member hasFlag (LIFTED | BRIDGE))) {            // mixin objects: todo what happens with abstract objects?            addMember(clazz, member.cloneSymbol(clazz))              .setPos(clazz.pos)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?