explicitouter.scala

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

SCALA
511
字号
   *      that are accessed from an inner class.   *    </li>   *    <li> <!-- 10 -->   *      Remove <code>protected</code> modifier from class members <code>M</code>   *      that are accessed without a super qualifier accessed from an inner   *      class or trait.   *    </li>   *    <li> <!-- 11 -->   *      Remove <code>private</code> and <code>protected</code> modifiers   *      from type symbols   *    </li>   *    <li> <!-- 12 -->   *      Remove <code>private</code> modifiers from members of traits   *    </li>   *  </ol>   *  <p>   *    Note: The whole transform is run in phase <code>explicitOuter.next</code>.   *  </p>   */  class ExplicitOuterTransformer(unit: CompilationUnit) extends OuterPathTransformer(unit) {    /** The definition tree of the outer accessor of current class     */    def outerFieldDef: Tree = {      val outerF = outerField(currentClass)      ValDef(outerF, EmptyTree)    }    /** The definition tree of the outer accessor of current class     */    def outerAccessorDef: Tree = {      val outerAcc = outerAccessor(currentClass)      var rhs = if (outerAcc.isDeferred) EmptyTree                else Select(This(currentClass), outerField(currentClass))      localTyper.typed {        atPos(currentClass.pos) {          DefDef(outerAcc, {vparamss => rhs})        }      }    }    /** The definition tree of the outer accessor for class     * <code>mixinClass</code>.     *     *  @param mixinClass The mixin class which defines the abstract outer     *                    accessor which is implemented by the generated one.     *  @pre mixinClass is an inner class     */    def mixinOuterAccessorDef(mixinClass: Symbol): Tree = {      val outerAcc = outerAccessor(mixinClass).overridingSymbol(currentClass)      assert(outerAcc != NoSymbol)      val path =         if (mixinClass.owner.isTerm) gen.mkAttributedThis(mixinClass.owner.enclClass)        else gen.mkAttributedQualifier(currentClass.thisType.baseType(mixinClass).prefix)      val rhs = ExplicitOuterTransformer.this.transform(path)      rhs.setPos(currentClass.pos) // see note below      localTyper.typed {        atPos(currentClass.pos) {            // @S: atPos not good enough because of nested atPos in DefDef method, which gives position from wrong class!          DefDef(outerAcc, {vparamss=>rhs}).setPos(currentClass.pos)        }      }    }    /** The main transformation method */    override def transform(tree: Tree): Tree = {      val sym = tree.symbol      if ((sym ne null) && sym.isType) {//(9)        if (sym hasFlag PRIVATE) sym setFlag notPRIVATE        if (sym hasFlag PROTECTED) sym setFlag notPROTECTED      }      tree match {        case Template(parents, self, decls) =>          val newDefs = new ListBuffer[Tree]          atOwner(tree, currentOwner) {            if (!(currentClass hasFlag INTERFACE) || (currentClass hasFlag lateINTERFACE)) {              if (isInner(currentClass)) {                if (hasOuterField(currentClass))                  newDefs += outerFieldDef // (1a)                newDefs += outerAccessorDef // (1)              }              if (!currentClass.isTrait)                for (val mc <- currentClass.mixinClasses)                  if (outerAccessor(mc) != NoSymbol)                    newDefs += mixinOuterAccessorDef(mc)            }          }          super.transform(            copy.Template(tree, parents, self,                           if (newDefs.isEmpty) decls else decls ::: newDefs.toList)          )        case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>          if (sym.isClassConstructor) {            rhs match {              case Literal(_) =>                Predef.error("unexpected case") //todo: remove              case _ =>                val clazz = sym.owner                val vparamss1 =                  if (isInner(clazz)) { // (4)                    val outerParam =                      sym.newValueParameter(sym.pos, nme.OUTER) setInfo outerField(clazz).info                    ((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail                  } else vparamss                super.transform(copy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs))            }          } else            super.transform(tree)        case This(qual) =>          if (sym == currentClass || (sym hasFlag MODULE) && sym.isStatic) tree          else atPos(tree.pos)(outerPath(outerValue, currentClass.outerClass, sym)) // (5)        case Select(qual, name) =>          if (currentClass != sym.owner/* && currentClass != sym.moduleClass*/) // (3)            sym.makeNotPrivate(sym.owner)          val qsym = qual.tpe.widen.typeSymbol          if ((sym hasFlag PROTECTED) && //(4)              (qsym.isTrait || !(qual.isInstanceOf[Super] || (qsym isSubClass currentClass))))            sym setFlag notPROTECTED          super.transform(tree)        case Apply(sel @ Select(qual, name), args)          if (name == nme.CONSTRUCTOR && isInner(sel.symbol.owner)) =>            val outerVal = atPos(tree.pos) {              if (qual.isInstanceOf[This]) { // it's a call between constructors of same class                assert(outerParam != NoSymbol)                outerValue              } else {                var pre = qual.tpe.prefix                if (pre == NoPrefix) pre = sym.owner.outerClass.thisType                gen.mkAttributedQualifier(pre)              }            }            super.transform(copy.Apply(tree, sel, outerVal :: args))        case mch @ Match(selector, cases) => // <----- transmatch hook          val tid = if (settings.debug.value) {            val q = unit.fresh.newName("tidmark")            Console.println("transforming patmat with tidmark "+q+" ncases = "+cases.length)            q          } else null		  /*          cases match {             //if ((cases.length > 1) && ...(cases(0)))            //can't use treeInfo.isDefaultCase, because that diagnoses a Bind            case CaseDef(Ident(nme.WILDCARD), EmptyTree, _)::xs if !xs.isEmpty =>               // a hack to detect when explicit outer does not work correctly              // still needed?              assert(false,"transforming too much, " + tid)			  // no!            case _ =>          }		  */                      var nselector = transform(selector)          //assert(nselector.tpe =:= selector.tpe)          //val ncases = transformCaseDefs(cases)          def makeGuardDef(vs:SymList, guard:Tree) = {            import symtab.Flags._            val gdname = cunit.fresh.newName("gd")            val fmls = new ListBuffer[Type]            val method = currentOwner.newMethod(mch.pos, gdname) setFlag (SYNTHETIC)             var vs1 = vs; while (vs1 ne Nil) {              fmls += vs1.head.tpe              vs1 = vs1.tail            }            val tpe    = new MethodType(fmls.toList, definitions.BooleanClass.tpe)            method setInfo tpe            localTyper.            typed {               DefDef(method,                      {vparamss =>                         new ChangeOwnerTraverser(currentOwner, method).traverse(guard);                        new TreeSymSubstituter(vs, vparamss.head).traverse(guard);guard})}          }          val nguard = new ListBuffer[Tree]          val ncases = new ListBuffer[CaseDef]           var cs = cases; while (cs ne Nil) {            cs.head match {              case CaseDef(p,EmptyTree,b) =>                 ncases += CaseDef(transform(p), EmptyTree, transform(b))              case CaseDef(p, guard, b) =>                 val vs       = definedVars(p)                val guardDef = makeGuardDef(vs, guard)                nguard += transform(guardDef)                val gdcall = localTyper.typed{Apply(Ident(guardDef.symbol),vs.map {Ident(_)})}                ncases += CaseDef(transform(p), gdcall, transform(b))            }            cs = cs.tail          }          var checkExhaustive = true          def isUncheckedAnnotation(tpe: Type) = tpe match {            case AnnotatedType(List(AnnotationInfo(atp, _, _)), _, _) if atp.typeSymbol == UncheckedClass =>              true            case _ =>              false          }          nselector match {            case Typed(nselector1, tpt) if isUncheckedAnnotation(tpt.tpe) =>              nselector = nselector1              checkExhaustive = false            case _ =>          }          ExplicitOuter.this.resultType = tree.tpe          //Console.println("TransMatcher currentOwner ="+currentOwner+")")          //Console.println("TransMatcher selector.tpe ="+selector.tpe+")")          //Console.println("TransMatcher resultType ="+resultType+")")          //println("handle pattern = "+nselector+"/"+ncases.toList+"/"+currentOwner+"/"+tree.tpe)          val t_untyped = handlePattern(nselector, ncases.toList, checkExhaustive, currentOwner, transform)          //println("t_untyped = "+t_untyped)	  try {            //Console.println("t_untyped "+t_untyped.toString())            val t = atPos(tree.pos) { localTyper.typed(t_untyped, resultType) }            //println("t_typed = "+t)            //t = transform(t)            //val t         = atPos(tree.pos) { typed(t_untyped, resultType) }            //val t         = atPos(tree.pos) { typed(t_untyped) }            //Console.println("t typed "+t.toString())            if (settings.debug.value)              Console.println("finished translation of " + tid)            if(nguard.isEmpty) {t} else Block(nguard.toList, t) setType t.tpe	  } catch {	    case e => 	      e.printStackTrace()	      //treeBrowser.browse(Seq.single(unit).elements)	      Console.println("[died while typechecking the translated pattern match:]")	      Console.println(t_untyped)	    null	  }        case _ =>          val x = super.transform(tree)          if (x.tpe eq null) x          else x setType transformInfo(currentOwner, x.tpe)      }    }    /** The transformation method for whole compilation units */    override def transformUnit(unit: CompilationUnit) {      cunit = unit      atPhase(phase.next) { super.transformUnit(unit) }    }  }}

⌨️ 快捷键说明

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