erasure.scala

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

SCALA
919
字号
                  If(                    Apply(                      TypeApply(                        Select(x(), Object_isInstanceOf),                        List(TypeTree(BoxedArrayClass.tpe))),                      List()),                    x(),                    boxArray(x())),                  pt)              }            }          }        else if (isSeqClass(pt.typeSymbol))          typed {            atPos(tree.pos) {              gen.evalOnce(tree, context.owner, context.unit) { x =>                gen.mkAttributedCast(                  If(                    Apply(                      TypeApply(                        Select(x(), Object_isInstanceOf),                        List(TypeTree(pt))),                      List()),                    x(),                    boxArray(x())),                  pt)              }            }          }        else gen.mkAttributedCast(tree, pt)      } else gen.mkAttributedCast(tree, pt)    }        /** Is symbol a member of unboxed arrays (which will be expanded directly     *  later)?     *     *  @param sym ..     *  @return    <code>true</code> if ..      */    private def isUnboxedArrayMember(sym: Symbol) =      sym.name == nme.apply || sym.name == nme.length || sym.name == nme.update ||      sym.owner == ObjectClass    private def isUnboxedValueMember(sym: Symbol) =      sym != NoSymbol && isValueClass(sym.owner)    /** Adapt <code>tree</code> to expected type <code>pt</code>.     *     *  @param tree the given tree     *  @param pt   the expected type.     *  @return     the adapted tree     */    private def adaptToType(tree: Tree, pt: Type): Tree = {      if (settings.debug.value && pt != WildcardType)        log("adapting " + tree + ":" + tree.tpe + " : " +  tree.tpe.parents + " to " + pt)//debug      if (tree.tpe <:< pt)        tree      else if (isUnboxedClass(tree.tpe.typeSymbol) && !isUnboxedClass(pt.typeSymbol))        adaptToType(box(tree), pt)      else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.paramTypes.isEmpty) {        if (!tree.symbol.isStable) assert(false, "adapt "+tree+":"+tree.tpe+" to "+pt)        adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt)      } else if (pt <:< tree.tpe)         cast(tree, pt)      else if (isUnboxedClass(pt.typeSymbol) && !isUnboxedClass(tree.tpe.typeSymbol))        adaptToType(unbox(tree, pt), pt)      else         cast(tree, pt)    }    /** <p>     *    Replace member references as follows:     *  </p>     *  <ul>     *    <li>     *      <code>x == y</code> for <code>==</code> in class <code>Any</code>     *      becomes <code>x equals y</code> with <code>equals</code> in class     *      <code>Object</code>.     *    </li>     *    <li>     *      <code>x != y</code> for <code>!=</code> in class <code>Any</code>     *      becomes <code>!(x equals y)</code> with <code>equals</code> in     *      class <code>Object</code>.     *    </li>     *    <li>     *      <code>new BoxedArray.&lt;init&gt;(len)</code> becomes     *      <code>new BoxedAnyArray.&lt;init&gt;(len): BoxedArray</code>     *      (the widening typing is necessary so that subsequent member     *      symbols stay the same)     *    </li>     *    <li>     *      <code>x.asInstanceOf[T]</code> and <code>x.asInstanceOf$erased[T]</code>     *      become <code>x.$asInstanceOf[T]</code>     *    </li>     *    <li>     *      <code>x.isInstanceOf[T]</code> and <code>x.isInstanceOf$erased[T]</code>     *      become <code>x.$isInstanceOf[T]</code>     *    </li>     *    <li>     *      <code>x.m</code> where <code>m</code> is some other member of     *      <code>Any</code> becomes <code>x.m</code> where m is a member     *      of class <code>Object</code>     *    </li>     *    <li>     *      <code>x.m</code> where <code>x</code> has unboxed value type     *      <code>T</code> and <code>m</code> is not a directly translated     *      member of <code>T</code> becomes <code>T.box(x).m</code>     *    </li>     *    <li>     *      <code>x.m</code> where <code>x</code> has type <code>Array[T]</code>     *      and <code>m</code> is not a directly translated member of     *      <code>Array</code> becomes <code>new BoxedTArray.<init>(x).m</code>     *    </li>     *    <li>     *      <code>x.m</code> where <code>x</code> is a reference type and     *      <code>m</code> is a directly translated member of value type     *      <code>T</code> becomes <code>x.TValue().m</code>     *    </li>     *    <li>     *      All forms of <code>x.m</code> where <code>x</code> is a boxed type     *      and <code>m</code> is a member of an unboxed class become     *      <code>x.m</code> where <code>m</code> is the corresponding member     *      of the boxed class.     *    </li>     *  </ul>     */    private def adaptMember(tree: Tree): Tree = {      //Console.println("adaptMember: " + tree);      tree match {        case Apply(Select(New(tpt), name), args) if (tpt.tpe.typeSymbol == BoxedArrayClass) =>          assert(name == nme.CONSTRUCTOR);          atPos(tree.pos) {            Typed(Apply(Select(New(TypeTree(BoxedAnyArrayClass.tpe)), name), args), tpt)          }        case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())         if ((tree.symbol == Any_asInstanceOf || tree.symbol == Any_asInstanceOfErased)) =>          val qual1 = typedQualifier(qual)          val qualClass = qual1.tpe.typeSymbol          val targClass = targ.tpe.typeSymbol/*          if (isNumericValueClass(qualClass) && isNumericValueClass(targClass))            // convert numeric type casts            atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List()))          else */          if (isValueType(targClass) ||                   (targClass == ArrayClass && (qualClass isNonBottomSubClass BoxedArrayClass)))            unbox(qual1, targ.tpe)          else if (targClass == ArrayClass && qualClass == ObjectClass || isSeqClass(targClass))            cast(qual1, targ.tpe)          else             tree        case Select(qual, name) if (name != nme.CONSTRUCTOR) =>          if (tree.symbol == NoSymbol)            tree          else if (tree.symbol == Any_asInstanceOf || tree.symbol == Any_asInstanceOfErased)            adaptMember(atPos(tree.pos)(Select(qual, Object_asInstanceOf)))          else if (tree.symbol == Any_isInstanceOf || tree.symbol == Any_isInstanceOfErased)            adaptMember(atPos(tree.pos)(Select(qual, Object_isInstanceOf)))          else if (tree.symbol.owner == AnyClass)            adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))          else {            var qual1 = typedQualifier(qual);            if ((isValueType(qual1.tpe.typeSymbol) && !isUnboxedValueMember(tree.symbol)) ||                 (qual1.tpe.typeSymbol == ArrayClass && !isUnboxedArrayMember(tree.symbol)))              qual1 = box(qual1);            else if (!isValueType(qual1.tpe.typeSymbol) && isUnboxedValueMember(tree.symbol))              qual1 = unbox(qual1, tree.symbol.owner.tpe)            else if (tree.symbol.owner == ArrayClass && qual1.tpe.typeSymbol == ObjectClass)              qual1 = cast(qual1, BoxedArrayClass.tpe)                        if (isUnboxedClass(tree.symbol.owner) && !isUnboxedClass(qual1.tpe.typeSymbol))              tree.symbol = NoSymbol            else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.paramTypes.isEmpty) {              assert(qual1.symbol.isStable, qual1.symbol);              qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType;            } else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner)))              qual1 = cast(qual1, tree.symbol.owner.tpe);            copy.Select(tree, qual1, name)          }        case _ =>          tree      }    }    /** A replacement for the standard typer's <code>adapt</code> method.     *     *  @param tree ...     *  @param mode ...     *  @param pt   ...     *  @return     the adapted tree     */    override protected def adapt(tree: Tree, mode: Int, pt: Type): Tree =      adaptToType(tree, pt)    /** A replacement for the standard typer's `typed1' method */    override protected def typed1(tree: Tree, mode: Int, pt: Type): Tree = {      var tree1 = try {         super.typed1(adaptMember(tree), mode, pt)      } catch {        case ex: Exception =>          //if (settings.debug.value)           Console.println("exception when typing " + tree);          throw ex        case er: TypeError =>          Console.println("exception when typing " + tree)          Console.println(er.msg + " in file " + context.owner.sourceFile)          er.printStackTrace          throw new Error      }      def adaptCase(cdef: CaseDef): CaseDef = {        val body1 = adaptToType(cdef.body, tree1.tpe)        copy.CaseDef(cdef, cdef.pat, cdef.guard, body1) setType body1.tpe      }      def adaptBranch(branch: Tree): Tree =        if (branch == EmptyTree) branch else adaptToType(branch, tree1.tpe);      tree1 match {        case If(cond, thenp, elsep) =>          copy.If(tree1, cond, adaptBranch(thenp), adaptBranch(elsep))        case Match(selector, cases) =>          copy.Match(tree1, selector, cases map adaptCase)        case Try(block, catches, finalizer) =>          copy.Try(tree1, adaptBranch(block), catches map adaptCase, finalizer)        case Ident(_) | Select(_, _) =>          if (tree1.symbol hasFlag OVERLOADED) {            val first = tree1.symbol.alternatives.head            val sym1 = tree1.symbol.filter {               alt => alt == first || !(first.tpe looselyMatches alt.tpe)            }            if (tree.symbol ne sym1) {              tree1.symbol = sym1              tree1.tpe = sym1.tpe            }          }          tree1        case _ =>          tree1      }    }  }  /** The erasure transformer */  class ErasureTransformer(unit: CompilationUnit) extends Transformer {    /** <p>     *    Emit an error if there is a double definition. This can happen in     *    the following circumstances:     *  </p>     *  <ul>     *    <li>     *      A template defines two members with the same name and erased type.     *    </li>     *    <li>     *      A template defines and inherits two members <code>m</code> with     *      different types, but their erased types are the same.     *    </li>     *    <li>     *      A template inherits two members <code>m</code> with different     *      types, but their erased types are the same.     *    </li>     *  </ul>     */    private def checkNoDoubleDefs(root: Symbol) {      def doubleDefError(sym1: Symbol, sym2: Symbol) {        val tpe1 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym1))        val tpe2 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym2))        if (!tpe1.isErroneous && !tpe2.isErroneous)          unit.error(          if (sym1.owner == root) sym1.pos else root.pos,          (if (sym1.owner == sym2.owner) "double definition:\n"           else if (sym1.owner == root) "name clash between defined and inherited member:\n"           else "name clash between inherited members:\n") +          sym1 + ":" + tpe1 +             (if (sym1.owner == root) "" else sym1.locationString) + " and\n" +          sym2 + ":" + tpe2 +             (if (sym2.owner == root) " at line " + (sym2.pos).line.get else sym2.locationString) +          "\nhave same type" +           (if (tpe1 =:= tpe2) "" else " after erasure: " + atPhase(phase.next)(sym1.tpe)))        sym1.setInfo(ErrorType)      }      val decls = root.info.decls      var e = decls.elems      while (e ne null) {        if (e.sym.isTerm) {          var e1 = decls.lookupNextEntry(e)          while (e1 ne null) {            if (atPhase(phase.next)(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym)            e1 = decls.lookupNextEntry(e1)          }        }        e = e.next      }      val opc = new overridingPairs.Cursor(root) {        override def exclude(sym: Symbol): Boolean =          !sym.isTerm || sym.hasFlag(PRIVATE) || super.exclude(sym)        override def matches(sym1: Symbol, sym2: Symbol): Boolean =          atPhase(phase.next)(sym1.tpe =:= sym2.tpe)      }      while (opc.hasNext) {        if (!atPhase(currentRun.refchecksPhase.next)(              root.thisType.memberType(opc.overriding) matches              root.thisType.memberType(opc.overridden))) {          if (settings.debug.value)            log("" + opc.overriding.locationString + " " +                     opc.overriding.infosString +

⌨️ 快捷键说明

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