erasure.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 919 行 · 第 1/3 页
SCALA
919 行
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Martin Odersky */// $Id: Erasure.scala 14102 2008-02-22 11:00:27Z odersky $package scala.tools.nsc.transformimport scala.collection.mutable.{HashMap,ListBuffer}import scala.tools.nsc.util.Positionimport symtab._import Flags._abstract class Erasure extends AddInterfaces with typechecker.Analyzer { import global._ // the global environment import definitions._ // standard classes and methods // @S: XXX: why is this here? earsure is a typer, if you comment this // out erasure still works, uses its own typed methods. lazy val typerXXX = this.typer import typerXXX.{typed} // methods to type trees import posAssigner.atPos // for filling in tree positions val phaseName: String = "erasure" def newTransformer(unit: CompilationUnit): Transformer = new ErasureTransformer(unit)// -------- erasure on types -------------------------------------------------------- /** <p> * The erasure <code>|T|</code> of a type <code>T</code>. This is: * </p> * <ul> * <li>For a constant type, itself.</li> * <li>For a type-bounds structure, the erasure of its upper bound.</li> * <li>For every other singleton type, the erasure of its supertype.</li> * <li> * For a typeref <code>scala.Array+[T]</code> where <code>T</code> is * an abstract type, <code>scala.runtime.BoxedArray</code>. * </li> * <li> * - For a typeref scala.Array+[T] where T is not an abstract type, scala.Array+[|T|]. * - For a typeref scala.Any or scala.AnyVal, java.lang.Object. * - For a typeref scala.Unit, scala.runtime.BoxedUnit. * - For a typeref P.C[Ts] where C refers to a class, |P|.C. * - For a typeref P.C[Ts] where C refers to an alias type, the erasure of C's alias. * - For a typeref P.C[Ts] where C refers to an abstract type, the * erasure of C's upper bound. * - For a non-empty type intersection (possibly with refinement), * the erasure of its first parent. * - For an empty type intersection, java.lang.Object * - For a method type (Fs)scala.Unit, (|Fs|)scala#Unit. * - For any other method type (Fs)Y, (|Fs|)|T|. * - For a polymorphic type, the erasure of its result type * - For the class info type of java.lang.Object, the same type without any parents * - For a class info type of a value class, the same type without any parents * - For any other class info type with parents Ps, the same type with * parents |Ps|, but with duplicate references of Object removed. * - for all other types, the type itself (with any sub-components erased) * </li> * </ul> */ val erasure = new TypeMap { def apply(tp: Type): Type = { tp match { case ConstantType(_) => tp case NotNullType(tp) => // BQ to Martin: this used to be below st:SubType and unreachable, moved up apply(tp) case st: SubType => apply(st.supertype) case TypeRef(pre, sym, args) => def isGeneric(tp: Type): Boolean = tp match { case TypeRef(pre, sym, args) => sym.isAbstractType && !(sym.owner hasFlag JAVA) || sym == ArrayClass && args.length == 1 && isGeneric(args.head) case ExistentialType(tparams, restp) => isGeneric(restp) case _ => false } if (sym == ArrayClass) if (isGeneric(tp)) erasedTypeRef(BoxedArrayClass) else typeRef(apply(pre), sym, args map this) else if (sym == AnyClass || sym == AnyValClass) erasedTypeRef(ObjectClass) else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) else if (sym.isClass) typeRef(apply(if (sym.owner.isClass) sym.owner.tpe else pre), sym, List()) else apply(sym.info) case PolyType(tparams, restpe) => apply(restpe) case ExistentialType(tparams, restpe) => apply(restpe) case MethodType(formals, restpe) => MethodType( formals map apply, if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) else apply(restpe)) case RefinedType(parents, decls) => if (parents.isEmpty) erasedTypeRef(ObjectClass) else apply(parents.head) case AnnotatedType(_, atp, _) => apply(atp) case ClassInfoType(parents, decls, clazz) => ClassInfoType( if ((clazz == ObjectClass) || (isValueType(clazz))) List() else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass)) else removeDoubleObject(parents map this), decls, clazz) case _ => mapOver(tp) } } } /** Type reference after erasure */ def erasedTypeRef(sym: Symbol): Type = typeRef(erasure(sym.owner.tpe), sym, List()) /** Remove duplicate references to class Object in a list of parent classes * todo: needed? */ private def removeDoubleObject(tps: List[Type]): List[Type] = tps match { case List() => List() case tp :: tps1 => if (tp.typeSymbol == ObjectClass) tp :: tps1.filter(_.typeSymbol != ObjectClass) else tp :: removeDoubleObject(tps1) } /** <p> * The symbol's erased info. This is the type's erasure, except for the * following symbols: * </p> * <ul> * <li> * For <code>$asInstanceOf</code> : <code>[T]T</code> * </li> * <li> * For <code>$isInstanceOf</code> : <code>[T]scala#Boolean</code> * </li> * <li> * For class <code>Array</code> : <code>[T]C</code> where * <code>C</code> is the erased classinfo of the <code>Array</code> class * </li> * <li> * For <code>Array[T].<init></code> : <code>{scala#Int)Array[T]</code> * </li> * <li> * For a type parameter : A type bounds type consisting of the erasures * of its bounds. * </li> * </ul> */ def transformInfo(sym: Symbol, tp: Type): Type = if (sym == Object_asInstanceOf) sym.info else if (sym == Object_isInstanceOf || sym == ArrayClass) PolyType(sym.info.typeParams, erasure(sym.info.resultType)) else if (sym.isAbstractType) mkTypeBounds(WildcardType, WildcardType) else if (sym.isTerm && sym.owner == ArrayClass) { if (sym.isClassConstructor) tp match { case MethodType(formals, TypeRef(pre, sym, args)) => MethodType(formals map erasure, typeRef(erasure(pre), sym, args)) } else if (sym.name == nme.apply) tp else if (sym.name == nme.update) tp match { case MethodType(List(index, tvar), restpe) => MethodType(List(erasure(index), tvar), erasedTypeRef(UnitClass)) } else erasure(tp) } else transformMixinInfo(erasure(tp)); val deconstMap = new TypeMap { def apply(tp: Type): Type = tp match { case PolyType(_, _) => mapOver(tp) case MethodType(_, _) => mapOver(tp) case _ => tp.deconst } } private def isSeqClass(sym: Symbol) = (SeqClass isNonBottomSubClass sym) && (sym != ObjectClass)// -------- boxing/unboxing -------------------------------------------------------- override def newTyper(context: Context) = new Eraser(context) /** The modifier typer which retypes with erased types. */ class Eraser(context: Context) extends Typer(context) { /** Box `tree' of unboxed type */ private def box(tree: Tree): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = box(rhs) copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe case _ => typed { atPos(tree.pos) { val sym = tree.tpe.typeSymbol; if (sym == UnitClass) { if (treeInfo.isPureExpr(tree)) gen.mkAttributedRef(BoxedUnit_UNIT) else Block(List(tree), gen.mkAttributedRef(BoxedUnit_UNIT)) } else if (sym == ArrayClass) { val elemClass = tree.tpe.typeArgs.head.typeSymbol; val boxedClass = if (isValueClass(elemClass)) boxedArrayClass(elemClass) else BoxedObjectArrayClass; Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree)) } else { Apply(gen.mkAttributedRef(boxMethod(tree.tpe.typeSymbol)), List(tree)). setPos(tree.pos) setType ObjectClass.tpe } } } } /** generate ScalaRuntime.boxArray(tree) */ private def boxArray(tree: Tree): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = boxArray(rhs) copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe case _ => typed { atPos(tree.pos) { gen.mkRuntimeCall(nme.boxArray, List(tree)) } } } /** Unbox <code>tree</code> of boxed type to expected type <code>pt</code>. * * @param tree the given tree * @param pt the expected type. * @return the unboxed tree */ private def unbox(tree: Tree, pt: Type): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = unbox(rhs, pt) copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe case _ => typed { atPos(tree.pos) { if (pt.typeSymbol == UnitClass) { if (treeInfo.isPureExpr(tree)) Literal(()) else Block(List(tree), Literal(())) } else if (pt.typeSymbol == ArrayClass) { val tree1 = adaptToType(tree, BoxedArrayClass.tpe) gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head))) } else { atPos(tree.pos) { Apply(gen.mkAttributedRef(unboxMethod(pt.typeSymbol)), List(tree)) setType pt } } } } } /** <p> * Generate a cast operation from <code>tree.tpe</code> to <code>pt</code>. * The following cases need to be treated specially: * </p> * <table> * <tr> * <td><code>Object -> Array</code></td> * <td>(might be a boxedarray)</td> * </tr> * <tr> * <td><code>Object -> Boxed*Array</code></td> * <td>(might be an array, which nees to be boxed)</td> * </tr> * <tr> * <td><code>Object -> Seq, Iterable</code></td> * <td>(might be an array, which needs to be boxed)</td> * </tr> * </table> */ private def cast(tree: Tree, pt: Type): Tree = { assert(pt eq pt.normalize) if (tree.tpe.typeSymbol == ObjectClass) { if (pt.typeSymbol == ArrayClass) typed { atPos(tree.pos) { gen.evalOnce(tree, context.owner, context.unit) { x => gen.mkAttributedCast( If( Apply( TypeApply( Select(x(), Object_isInstanceOf), List(TypeTree(BoxedArrayClass.tpe))), List()), unbox(gen.mkAttributedCast(x(), BoxedArrayClass.tpe), pt), x()), pt) } } } else if (pt.typeSymbol isNonBottomSubClass BoxedArrayClass) typed { atPos(tree.pos) { gen.evalOnce(tree, context.owner, context.unit) { x => gen.mkAttributedCast(
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?