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].&lt;init&gt;</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 + -
显示快捷键?