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