cleanup.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 569 行 · 第 1/2 页
SCALA
569 行
/* NSC -- new Scala compiler * Copyright 2005-2006 LAMP/EPFL * @author Martin Odersky */// $Id: CleanUp.scala 14428 2008-03-20 14:56:41Z dubochet $package scala.tools.nsc.transformimport symtab._import Flags._import scala.tools.nsc.util.Positionimport scala.collection.mutable.{ListBuffer, HashMap}abstract class CleanUp extends Transform { import global._ import definitions._ import posAssigner.atPos /** the following two members override abstract members in Transform */ val phaseName: String = "cleanup" protected def newTransformer(unit: CompilationUnit): Transformer = new CleanUpTransformer(unit) class CleanUpTransformer(unit: CompilationUnit) extends Transformer { private val MethodClass = if (forCLDC || forMSIL) null else definitions.getClass("java.lang.reflect.Method") private val newDefs = new ListBuffer[Tree] private val classConstantMeth = new HashMap[String, Symbol] // a map from the symbols of the Scala primitive types to the symbols // of the modules of the Java box classes private val javaBoxClassModule = new HashMap[Symbol, Symbol] if (!forMSIL) { javaBoxClassModule(BooleanClass) = getModule("java.lang.Boolean") javaBoxClassModule(ByteClass) = getModule("java.lang.Byte") javaBoxClassModule(ShortClass) = getModule("java.lang.Short") javaBoxClassModule(IntClass) = getModule("java.lang.Integer") javaBoxClassModule(CharClass) = getModule("java.lang.Character") javaBoxClassModule(LongClass) = getModule("java.lang.Long") if (!forCLDC) { javaBoxClassModule(FloatClass) = getModule("java.lang.Float") javaBoxClassModule(DoubleClass) = getModule("java.lang.Double") javaBoxClassModule(UnitClass) = getModule("java.lang.Void") } } private var localTyper: analyzer.Typer = null private def classConstantMethod(pos: Position, sig: String): Symbol = classConstantMeth.get(sig) match { case Some(meth) => meth case None => val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName) val owner = currentOwner.enclClass val cvar = owner.newVariable(pos, unit.fresh.newName("class$Cache")) .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC).setInfo(ClassClass.tpe) owner.info.decls.enter(cvar) val cdef = localTyper.typed { atPos(pos) { ValDef(cvar, Literal(Constant(null))) } } val meth = owner.newMethod(pos, unit.fresh.newName("class$Method")) .setFlag(PRIVATE | STATIC | SYNTHETIC).setInfo(MethodType(List(), ClassClass.tpe)) owner.info.decls.enter(meth) val mdef = localTyper.typed { atPos(pos) { DefDef(meth, vparamss => gen.mkCached( cvar, Apply( gen.mkAttributedRef(forName), List(Literal(sig))))) } } newDefs.append(cdef, mdef); classConstantMeth.update(sig, meth) meth } private val existingReflectiveMethodCache = new HashMap[(String, List[Type]), Symbol] /* Transforms a list of types into a list of trees representing these types * as java.lang.Class instances. */ private def paramTypeClasses(paramTypes: List[Type]): List[Tree] = paramTypes map { pt => Literal(Constant(pt)) } private def reflectiveMethodCache(pos: Position, method: String, paramTypes: List[Type]): Symbol = existingReflectiveMethodCache.get((method, paramTypes)) match { case Some(cache) => cache case None => val owner = currentOwner.enclClass val rmvar = owner.newVariable(pos, unit.fresh.newName("reflMethod$Cache")) .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC) .setInfo(MethodClass.tpe) owner.info.decls.enter(rmvar) val rmdef = localTyper.typed { atPos(pos) { ValDef(rmvar, Literal(Constant(null))) } } val rmcvar = owner.newVariable(pos, unit.fresh.newName("reflClass$Cache")) .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC) .setInfo(ClassClass.tpe) owner.info.decls.enter(rmcvar) val rmcdef = localTyper.typed { atPos(pos) { ValDef(rmcvar, Literal(Constant(null))) } } val rmmeth = owner.newMethod(pos, unit.fresh.newName("reflMethod$Method")) .setFlag(STATIC | SYNTHETIC) .setInfo(MethodType(List(ClassClass.tpe), MethodClass.tpe)) owner.info.decls.enter(rmmeth) val rmmdef = localTyper.typed { atPos(pos) { DefDef(rmmeth, { vparamss => val callClass = vparamss(0)(0) Block( List( If( gen.mkOr( Apply(Select(Select(This(owner), rmvar), nme.eq), List(Literal(Constant(null)))), Apply(Select(Select(This(owner), rmcvar), nme.ne), List(gen.mkAttributedRef(callClass))) ), Block( List( Assign( Select(This(owner), rmvar), Apply( Select( gen.mkAttributedRef(callClass), ClassClass.tpe.member(nme.getMethod_) ), List( Literal(Constant(method)), ArrayValue(TypeTree(ClassClass.tpe), paramTypeClasses(paramTypes)) ) ) ), Assign(Select(This(owner), rmcvar), gen.mkAttributedRef(callClass)) ), Literal(Constant(())) ), EmptyTree ) ), Select(This(owner), rmvar) ) }) } } newDefs.append(transform(rmdef), transform(rmcdef), transform(rmmdef)); existingReflectiveMethodCache.update((method, paramTypes), rmmeth) rmmeth } override def transformUnit(unit: CompilationUnit) = unit.body = transform(unit.body) /** A value class is defined to be only Java-compatible values: unit is * not part of it, as opposed to isValueClass in definitions. scala.Int is * a value class, java.lang.Integer is not. */ def isValueClass(sym: Symbol) = boxedClass contains sym override def transform(tree: Tree): Tree = tree match { /* Transforms dynamic calls (i.e. calls to methods that are undefined * in the erased type space) to -- dynamically -- unsafe calls using * reflection. This is used for structural sub-typing of refinement * types. * For 'a.f(b)' it will generate something like: * 'a.getClass(). * ' getMethod("f", Array(classOf[b.type])). * ' invoke(a, Array(b)) * plus all the necessary casting/boxing/etc. machinery required * for type-compatibility (see fixResult and fixParams). * * USAGE CONTRACT: * There are a number of assumptions made on the way a dynamic apply * is used. Assumptions relative to type are handled by the erasure * phase. * - The applied arguments are compatible with AnyRef, which means * that an argument tree typed as AnyVal has already been extended * with the necessary boxing calls. This implies that passed * arguments might not be strictly compatible with the method's * parameter types (a boxed integeer while int is expected). * - The expected return type is an AnyRef, even when the method's * return type is an AnyVal. This means that the tree containing the * call has already been extended with the necessary unboxing calls * (or keeps the boxed type). * - The type-checker has prevented dynamic applies on methods which * parameter's erased types are not statically known at the call site. * This is necessary to allow dispatching the call to the correct * method (dispatching on paramters is static in Scala). In practice, * this limitation only arises when the called method is defined as a * refinement, where the refinement defines a parameter based on a * type variable. */ case ad@ApplyDynamic(qual, params) => assert(ad.symbol.isPublic) val testForNumber: Tree = gen.mkOr( Apply( TypeApply( gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf), List(TypeTree(BoxedNumberClass.tpe.normalize)) ), List() ), Apply( TypeApply( gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf), List(TypeTree(BoxedCharacterClass.tpe.normalize)) ), List() ) ) val testForBoolean: Tree = Apply( TypeApply( gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf), List(TypeTree(BoxedBooleanClass.tpe.normalize)) ), List() ) val testForNumberOrBoolean: Tree = gen.mkOr(testForNumber, testForBoolean) def getPrimitiveReplacementForStructuralCall: PartialFunction[Name, (Symbol, Tree)] = { /* Unary arithmetic */ case nme.UNARY_+ => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("positive")), testForNumber) case nme.UNARY_- => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("negate")), testForNumber) /* Unary logic */ case nme.UNARY_~ => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("complement")), testForNumber) case nme.UNARY_! => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeNot")), testForBoolean) /* Binary arithmetic */ case nme.ADD => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("add")), testForNumber) case nme.SUB => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("subtract")), testForNumber) case nme.MUL => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("multiply")), testForNumber) case nme.DIV => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("divide")), testForNumber) case nme.MOD => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeModulo")), testForNumber) /* Binary logic */ case nme.OR => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeOr")), testForNumberOrBoolean) case nme.XOR => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeXor")), testForNumberOrBoolean) case nme.AND => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeAnd")), testForNumberOrBoolean) case nme.ZOR => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeConditionalOr")), testForBoolean) case nme.ZAND => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeConditionalAnd")), testForBoolean) /* Shifting */ case nme.LSL => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedLeft")), testForNumber) case nme.LSR => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedRight")), testForNumber) case nme.ASR => (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftLogicalRight")), testForNumber) case nme.EQ =>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?