explicitouter.scala

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

SCALA
511
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Martin Odersky */// $Id: ExplicitOuter.scala 13819 2008-01-28 18:43:24Z odersky $package scala.tools.nsc.transformimport symtab._import Flags._import scala.collection.mutable.{HashMap, ListBuffer}import matching.{TransMatcher, PatternNodes, CodeFactory, ParallelMatching}/** This class ... * *  @author  Martin Odersky *  @version 1.0 */abstract class ExplicitOuter extends InfoTransform with TransMatcher with PatternNodes with CodeFactory with ParallelMatching with TypingTransformers {  import global._  import definitions._  import posAssigner.atPos  /** The following flags may be set by this phase: */  override def phaseNewFlags: Long = notPRIVATE | notPROTECTED | lateFINAL  /** the name of the phase: */  val phaseName: String = "explicitouter"  /** This class does not change linearization */  override def changesBaseClasses = false  protected def newTransformer(unit: CompilationUnit): Transformer =    new ExplicitOuterTransformer(unit)  /** Is given <code>clazz</code> an inner class? */  private def isInner(clazz: Symbol) =    !clazz.isPackageClass && !clazz.outerClass.isStaticOwner  /** Does given <code>clazz</code> define an outer field? */  def hasOuterField(clazz: Symbol) = {    def hasSameOuter(parent: Type) =      parent.typeSymbol.isClass &&      clazz.owner.isClass &&      clazz.owner == parent.typeSymbol.owner &&      parent.prefix =:= clazz.owner.thisType    isInner(clazz) && !clazz.isTrait &&    (clazz.info.parents.isEmpty || !hasSameOuter(clazz.info.parents.head))  }  private def outerField(clazz: Symbol): Symbol = {    val result = clazz.info.member(nme.getterToLocal(nme.OUTER))    if (result == NoSymbol)      assert(false, "no outer field in "+clazz+clazz.info.decls+" at "+phase)    result  }  def outerAccessor(clazz: Symbol): Symbol = {    val firstTry = clazz.info.decl(clazz.expandedName(nme.OUTER))    if (firstTry != NoSymbol && firstTry.outerSource == clazz) firstTry    else {      var e = clazz.info.decls.elems      while ((e ne null) && e.sym.outerSource != clazz) e = e.next      if (e ne null) e.sym else NoSymbol    }  }  /** <p>   *    The type transformation method:   *  </p>   *  <ol>   *    <li>   *      Add an outer parameter to the formal parameters of a constructor   *      in a inner non-trait class;   *    </li>   *    <li>   *      Add a protected <code>$outer</code> field to an inner class which is   *      not a trait.   *    </li>   *    <li>   *      <p>   *        Add an outer accessor <code>$outer$$C</code> to every inner class   *        with fully qualified name <code>C</code> that is not an interface.   *        The outer accesssor is abstract for traits, concrete for other   *        classes.   *      </p>   *      <p>   *        3a. Also add overriding accessor defs to every class that inherits   *        mixin classes with outer accessor defs (unless the superclass   *        already inherits the same mixin).   *      </p>   *    </li>   *    <li>   *      Make all super accessors and modules in traits non-private, mangling   *      their names.   *    </li>   *    <li>   *      Remove protected flag from all members of traits.   *    </li>   *  </ol>   */  def transformInfo(sym: Symbol, tp: Type): Type = tp match {    case MethodType(formals, restpe1) =>      val restpe = transformInfo(sym, restpe1)      if (sym.owner.isTrait && ((sym hasFlag SUPERACCESSOR) || sym.isModule)) { // 5         sym.makeNotPrivate(sym.owner)      }      // moved form the term transformer      if (sym.owner.isTrait && (sym hasFlag (ACCESSOR | SUPERACCESSOR)))        sym.makeNotPrivate(sym.owner); //(2)      if (sym.owner.isTrait && (sym hasFlag PROTECTED)) sym setFlag notPROTECTED // 6      if (sym.isClassConstructor && isInner(sym.owner)) // 1        MethodType(sym.owner.outerClass.thisType :: formals, restpe)      else if (restpe ne restpe1)        MethodType(formals, restpe)      else tp    case ClassInfoType(parents, decls, clazz) =>      var decls1 = decls      if (isInner(clazz) && !(clazz hasFlag INTERFACE)) {        decls1 = newScope(decls.toList)        val outerAcc = clazz.newMethod(clazz.pos, nme.OUTER) // 3        outerAcc.expandName(clazz)        val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType        decls1 enter clazz.newOuterAccessor(clazz.pos).setInfo(MethodType(List(), restpe))        if (hasOuterField(clazz)) { //2          decls1 enter (            clazz.newValue(clazz.pos, nme.getterToLocal(nme.OUTER))            setFlag (SYNTHETIC | PROTECTED | PARAMACCESSOR)            setInfo clazz.outerClass.thisType)        }      }      if (!clazz.isTrait && !parents.isEmpty) {        for (val mc <- clazz.mixinClasses) {          val mixinOuterAcc: Symbol = atPhase(phase.next)(outerAccessor(mc))          if (mixinOuterAcc != NoSymbol) {            if (decls1 eq decls) decls1 = newScope(decls.toList)            val newAcc = mixinOuterAcc.cloneSymbol(clazz)             newAcc.resetFlag(DEFERRED)            newAcc.setInfo(clazz.thisType.memberType(mixinOuterAcc))            decls1 enter newAcc           }        }      }      if (decls1 eq decls) tp else ClassInfoType(parents, decls1, clazz)    case PolyType(tparams, restp) =>      val restp1 = transformInfo(sym, restp)      if (restp eq restp1) tp else PolyType(tparams, restp1)    case _ =>        tp  }  /** A base class for transformers that maintain <code>outerParam</code>   *  values for outer parameters of constructors.   *  The class provides methods for referencing via outer.   */  abstract class OuterPathTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {    /** The directly enclosing outer parameter, if we are in a constructor */    protected var outerParam: Symbol = NoSymbol    /** The first outer selection from currently transformed tree.     *  The result is typed but not positioned.     */    protected def outerValue: Tree =      if (outerParam != NoSymbol) gen.mkAttributedIdent(outerParam)      else outerSelect(gen.mkAttributedThis(currentClass))    /** Select and apply outer accessor from 'base'     *  The result is typed but not positioned.     */    private def outerSelect(base: Tree): Tree = {      val path = Apply(Select(base, outerAccessor(base.tpe.typeSymbol.toInterface)), List())      localTyper.typed(path)    }    /** The path     *  <blockquote><pre>`base'.$outer$$C1 ... .$outer$$Cn</pre></blockquote>     *  which refers to the outer instance of class <code>to</code> of     *  value <code>base</code>. The result is typed but not positioned.     *     *  @param base ...     *  @param from ...     *  @param to   ...     *  @return     ...     */    protected def outerPath(base: Tree, from: Symbol, to: Symbol): Tree = {      //Console.println("outerPath from "+from+" to "+to+" at "+base+":"+base.tpe)      //assert(base.tpe.widen.baseType(from.toInterface) != NoType, ""+base.tpe.widen+" "+from.toInterface)//DEBUG      if (from == to || from.isImplClass && from.toInterface == to) base      else outerPath(outerSelect(base), from.outerClass, to)    }    override def transform(tree: Tree): Tree = {      val savedOuterParam = outerParam      try {        tree match {          case Template(_, _, _) =>            outerParam = NoSymbol          case DefDef(_, _, _, vparamss, _, _) =>            if (tree.symbol.isClassConstructor && isInner(tree.symbol.owner)) {              outerParam = vparamss.head.head.symbol              assert(outerParam.name startsWith nme.OUTER, outerParam.name)            }          case _ =>        }        super.transform(tree)      } catch {//debug        case ex: Throwable =>          Console.println("exception when transforming " + tree)          //Console.println(ex.getMessage)          //Console.println(ex.printStackTrace())          //System.exit(-1);          throw ex      } finally {        outerParam = savedOuterParam      }    }  }  /** <p>   *    The phase performs the following transformations on terms:   *  </p>   *  <ol>   *    <li> <!-- 1 -->   *      <p>   *        An class which is not an interface and is not static gets an outer   *        accessor (@see outerDefs).   *      </p>   *      <p>   *        1a. A class which is not a trait gets an outer field.   *      </p>   *    </li>   *    <li> <!-- 4 -->   *      A constructor of a non-trait inner class gets an outer parameter.   *    </li>   *    <li> <!-- 5 -->   *      A reference <code>C.this</code> where <code>C</code> refers to an   *      outer class is replaced by a selection   *      <code>this.$outer$$C1</code> ... <code>.$outer$$Cn</code> (@see outerPath)   *    </li>   *    <li>   *    </li>   *    <li> <!-- 7 -->   *      A call to a constructor Q.<init>(args) or Q.$init$(args) where Q != this and   *      the constructor belongs to a non-static class is augmented by an outer argument.   *      E.g. <code>Q.&lt;init&gt;(OUTER, args)</code> where <code>OUTER</code>   *      is the qualifier corresponding to the singleton type <code>Q</code>.   *    </li>   *    <li>   *      A call to a constructor <code>this.&lt;init&gt;(args)</code> in a   *      secondary constructor is augmented to <code>this.&lt;init&gt;(OUTER, args)</code>   *      where <code>OUTER</code> is the last parameter of the secondary constructor.   *    </li>   *    <li> <!-- 9 -->   *      Remove <code>private</code> modifier from class members <code>M</code>

⌨️ 快捷键说明

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