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 + -
显示快捷键?