superaccessors.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 440 行 · 第 1/2 页
SCALA
440 行
copy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) case Function(vparams, body) => withInvalidOwner { copy.Function(tree, vparams, transform(body)) } case _ => super.transform(tree) }} catch { case ex : AssertionError => if (tree.symbol != null && tree.symbol != NoSymbol) Console.println("TRANSFORM: " + tree.symbol.sourceFile) Console.println("TREE: " + tree) throw ex } override def atOwner[A](owner: Symbol)(trans: => A): A = { if (owner.isClass) validCurrentOwner = true super.atOwner(owner)(trans) } private def withInvalidOwner[A](trans: => A): A = { val prevValidCurrentOwner = validCurrentOwner validCurrentOwner = false val result = trans validCurrentOwner = prevValidCurrentOwner result } /** Add a protected accessor, if needed, and return a tree that calls * the accessor and returns the the same member. The result is already * typed. */ private def makeAccessor(tree: Select, targs: List[Tree]): Tree = { val Select(qual, name) = tree val sym = tree.symbol val clazz = hostForAccessorOf(sym, currentOwner.enclClass) /** Return a list of list of types of all value parameter sections. */ def allParamTypes(tpe: Type): List[List[Type]] = tpe match { case PolyType(_, restpe) => allParamTypes(restpe) case MethodType(pts, res) => pts :: allParamTypes(res) case _ => Nil } assert(clazz != NoSymbol, sym) if (settings.debug.value) log("Decided for host class: " + clazz) val accName = nme.protName(sym.originalName) val hasArgs = sym.tpe.paramTypes != Nil val memberType = sym.tpe // transform(sym.tpe) // if the result type depends on the this type of an enclosing class, the accessor // has to take an object of exactly this type, otherwise it's more general val objType = if (isThisType(memberType.finalResultType)) clazz.thisType else clazz.typeOfThis val accType = memberType match { case PolyType(tparams, restpe) => PolyType(tparams, MethodType(List(objType), restpe.asSeenFrom(qual.tpe, sym.owner))) case _ => MethodType(List(objType), memberType.asSeenFrom(qual.tpe, sym.owner)) } if (settings.debug.value) log("accType: " + accType) var protAcc = clazz.info.decl(accName).suchThat(_.tpe == accType) if (protAcc == NoSymbol) { protAcc = clazz.newMethod(tree.pos, nme.protName(sym.originalName)).setInfo(accType) clazz.info.decls.enter(protAcc); val code = DefDef(protAcc, vparamss => { val obj = vparamss.head.head // receiver vparamss.tail.zip(allParamTypes(sym.tpe)).foldLeft(Select(Ident(obj), sym): Tree) ( (fun, pvparams) => { Apply(fun, (List.map2(pvparams._1, pvparams._2) { (v, origTpe) => makeArg(v, obj, origTpe) } )) }) }) if (settings.debug.value) log(code) accDefBuf(clazz) += typers(clazz).typed(code) } var res: Tree = atPos(tree.pos) { if (targs.head == EmptyTree) Apply(Select(This(clazz), protAcc), List(qual)) else Apply(TypeApply(Select(This(clazz), protAcc), targs), List(qual)) } if (settings.debug.value) log("Replaced " + tree + " with " + res) if (hasArgs) typer.typedOperator(res) else typer.typed(res) } /** Adapt the given argument in call to protected member. * Adaptation means adding a cast to a path-dependent type, for instance * * def prot$m(obj: Outer)(x: Inner) = obj.m(x.asInstanceOf[obj.Inner]). * * such a cast might be necessary when m expects an Outer.this.Inner (the * outer of 'obj' and 'x' have to be the same). This restriction can't be * expressed in the type system (but is implicit when defining method m). */ private def makeArg(v: Symbol, obj: Symbol, expectedTpe: Type): Tree = { val res = Ident(v) val sym = obj.tpe.typeSymbol var ownerClass: Symbol = NoSymbol val isDependentType = expectedTpe match { case TypeRef(path, _, _) => ownerClass = thisTypeOfPath(path) if (sym.isSubClass(ownerClass)) true else false case _ => false } if (isDependentType) { val preciseTpe = expectedTpe.asSeenFrom(singleType(NoPrefix, obj), ownerClass) //typeRef(singleType(NoPrefix, obj), v.tpe.symbol, List()) TypeApply(Select(res, definitions.Any_asInstanceOf), List(TypeTree(preciseTpe))) } else res } /** For a path-dependent type, return the this type. */ private def thisTypeOfPath(path: Type): Symbol = path match { case ThisType(outerSym) => outerSym case SingleType(rest, _) => thisTypeOfPath(rest) case _ => NoSymbol } /** Add an accessor for field, if needed, and return a selection tree for it . * The result is not typed. */ private def makeSetter(tree: Select): Tree = { val field = tree.symbol val clazz = hostForAccessorOf(field, currentOwner.enclClass) assert(clazz != NoSymbol, field) if (settings.debug.value) log("Decided for host class: " + clazz) val accName = nme.protSetterName(field.originalName) var protAcc = clazz.info.decl(accName) if (protAcc == NoSymbol) { protAcc = clazz.newMethod(field.pos, nme.protSetterName(field.originalName)) .setInfo(MethodType(List(clazz.typeOfThis, field.tpe), definitions.UnitClass.tpe)); clazz.info.decls.enter(protAcc) val code = DefDef(protAcc, vparamss => { val obj :: value :: Nil = vparamss.head; atPos(tree.pos) { Assign( Select(Ident(obj), field.name), Ident(value)) } }) if (settings.debug.value) log(code); accDefBuf(clazz) += typers(clazz).typed(code) } var res: Tree = atPos(tree.pos) { Select(This(clazz), protAcc) } res } /** Does `sym' need an accessor when accessed from `currentOwner'? * A special case arises for classes with explicit self-types. If the * self type is a Java class, and a protected accessor is needed, we issue * an error. If the self type is a Scala class, we don't add an accessor. * An accessor is not needed if the access boundary is larger than the * enclosing package, since that translates to 'public' on the host system. * (as Java has no real package nesting). * * If the access happens inside a 'trait', access is more problematic since * the implementation code is moved to an '$class' class which does not * inherit anything. Since we can't (yet) add accessors for 'required' * classes, this has to be signaled as error. */ private def needsProtectedAccessor(sym: Symbol, pos: Position): Boolean = { val res = /* settings.debug.value && */ ((sym hasFlag PROTECTED) && (!validCurrentOwner || !(currentOwner.enclClass.thisSym isSubClass sym.owner)) && (enclPackage(sym.owner) != enclPackage(currentOwner)) && (enclPackage(sym.owner) == enclPackage(sym.accessBoundary(sym.owner)))) if (res) { val host = hostForAccessorOf(sym, currentOwner.enclClass) if (host.thisSym != host) { if (host.thisSym.tpe.typeSymbol.hasFlag(JAVA) || currentOwner.enclClass.isTrait) unit.error(pos, "Implementation restriction: " + currentOwner.enclClass + " accesses protected " + sym + " from self type " + host.thisSym.tpe) false } else res } else res } /** Return the enclosing package of the given symbol. */ private def enclPackage(sym: Symbol): Symbol = if ((sym == NoSymbol) || sym.isPackageClass) sym else enclPackage(sym.owner) /** Return the innermost enclosing class C of referencingClass for which either * of the following holds: * - C is a subclass of sym.owner or * - C is declared in the same package as sym's owner */ private def hostForAccessorOf(sym: Symbol, referencingClass: Symbol): Symbol = { if (referencingClass.isSubClass(sym.owner.enclClass) || referencingClass.thisSym.isSubClass(sym.owner.enclClass) || enclPackage(referencingClass) == enclPackage(sym.owner)) { assert(referencingClass.isClass) referencingClass } else hostForAccessorOf(sym, referencingClass.owner.enclClass) } /** Is 'tpe' the type of a member of an enclosing class? */ private def isThisType(tpe: Type): Boolean = tpe match { case ThisType(sym) => (sym.isClass && !sym.isPackageClass) case TypeRef(pref, _, _) => isThisType(pref) case SingleType(pref, _) => isThisType(pref) case RefinedType(parents, defs) => parents.exists(isThisType(_)) case AnnotatedType(_, tp, _) => isThisType(tp) case _ => false } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?