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.<init>(len)</code> becomes * <code>new BoxedAnyArray.<init>(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 + -
显示快捷键?