summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-06-27 20:12:16 +0000
committerPaul Phillips <paulp@improving.org>2009-06-27 20:12:16 +0000
commit4fccc851b8796d092a2910f6b746e4767d057fc4 (patch)
tree7a2bd1684270406c759df32fba3289081e421d8f /src
parentcfe07c80c3a4d9cacd870e91cb20c129821b2956 (diff)
downloadscala-4fccc851b8796d092a2910f6b746e4767d057fc4.tar.gz
scala-4fccc851b8796d092a2910f6b746e4767d057fc4.tar.bz2
scala-4fccc851b8796d092a2910f6b746e4767d057fc4.zip
Continued development of code generation DSL.
target file was the aptly named CleanUp.scala. Will continue polishing that file but checking in to keep this patch from getting out of hand.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala73
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala577
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala11
5 files changed, 291 insertions, 393 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 98a6919f27..1ef0a1bc69 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -21,16 +21,20 @@ trait TreeDSL {
def LIT(x: Any) = Literal(Constant(x))
def TRUE = LIT(true)
def FALSE = LIT(false)
+ def NULL = LIT(null)
+ def UNIT = LIT(())
+ def ZERO = LIT(0)
def WILD = Ident(nme.WILDCARD)
+ case class ExpectApply(target: Tree) {
+ def apply(args: Tree*) = Apply(target, args.toList)
+ }
+
class TreeMethods(target: Tree) {
- private def binop(lhs: Tree, op: Name, rhs: Tree) = Apply(Select(lhs, op), List(rhs))
+ private def binop(lhs: Tree, op: Name, rhs: Tree) = Apply(Select(lhs, op), List(rhs))
+ private def binop(lhs: Tree, op: Symbol, rhs: Tree) = Apply(Select(lhs, op), List(rhs))
private def toAnyRef(x: Tree) = x setType AnyRefClass.tpe
- case class ExpectApply(target: Tree) {
- def apply(args: Tree*) = Apply(target, args.toList)
- }
-
/** logical/comparison ops **/
def OR(other: Tree) =
if (target == EmptyTree) other
@@ -42,8 +46,13 @@ trait TreeDSL {
else if (other == EmptyTree) target
else gen.mkAnd(target, other)
+ def BIT_AND(other: Tree) = binop(target, Int_And, other)
def EQREF(other: Tree) = binop(target, nme.eq, toAnyRef(other))
+ def NE_REF(other: Tree) = binop(target, nme.ne, other)
def EQEQ(other: Tree) = binop(target, nme.EQ, other)
+ def EQINT(other: Tree) = binop(target, Int_==, other)
+ def EQANY(other: Tree) = binop(target, Any_==, other)
+ def NOT_==(other: Tree) = binop(target, Object_ne, other)
/** Apply, Select, Match **/
def APPLY(params: List[Tree]) = Apply(target, params)
@@ -51,17 +60,45 @@ trait TreeDSL {
def DOT(member: Name) = ExpectApply(Select(target, member))
def DOT(sym: Symbol) = ExpectApply(Select(target, sym))
- /** Casting */
- def AS(tpe: Type) = TypeApply(Select(target, Any_asInstanceOf), List(TypeTree(tpe)))
- def TOSTRING() = Select(target, nme.toString_)
+ /** Assignment */
+ def ===(rhs: Tree) = Assign(target, rhs)
+
+ /** Casting & type tests -- working our way toward understanding exactly
+ * what differs between the different forms of IS and AS.
+ */
+ def AS(tpe: Type) = TypeApply(Select(target, Any_asInstanceOf), List(TypeTree(tpe)))
+ def AS_ATTR(tpe: Type) = gen.mkAttributedCast(target, tpe)
+
+ def IS(tpe: Type) = gen.mkIsInstanceOf(target, tpe, true)
+ def IS_OBJ(tpe: Type) = gen.mkIsInstanceOf(target, tpe, false)
+
+ def TOSTRING() = Apply(Select(target, nme.toString_), Nil)
+ def GETCLASS() = Apply(Select(target, Object_getClass), Nil)
}
class CaseStart(pat: Tree, guard: Tree) {
def IF(g: Tree): CaseStart = new CaseStart(pat, g)
- def ==>(body: Tree): CaseDef = CaseDef(pat, guard, body) // DSL for =>
+ def ==>(body: Tree): CaseDef = CaseDef(pat, guard, body)
+ }
+
+ abstract class ValOrDefStart(sym: Symbol) {
+ def ===(body: Tree): ValOrDefDef
+ }
+ class DefStart(sym: Symbol) extends ValOrDefStart(sym) {
+ def ===(body: Tree) = DefDef(sym, body)
+ }
+ class ValStart(sym: Symbol) extends ValOrDefStart(sym) {
+ def ===(body: Tree) = ValDef(sym, body)
+ }
+ class IfStart(cond: Tree, thenp: Tree) {
+ def THEN(x: Tree) = new IfStart(cond, x)
+ def ELSE(elsep: Tree) = If(cond, thenp, elsep)
+ def ENDIF = If(cond, thenp, EmptyTree)
}
- class DefStart(sym: Symbol) {
- def ===(body: Tree) = DefDef(sym, body) // DSL for =
+ class TryStart(body: Tree, catches: List[CaseDef], fin: Tree) {
+ def CATCH(xs: CaseDef*) = new TryStart(body, xs.toList, fin)
+ def FINALLY(x: Tree) = Try(body, catches, x)
+ def ENDTRY = Try(body, catches, fin)
}
def CASE(pat: Tree): CaseStart = new CaseStart(pat, EmptyTree)
@@ -73,6 +110,7 @@ trait TreeDSL {
class SymbolMethods(target: Symbol) {
def BIND(body: Tree) = Bind(target, body)
+ // def DOT(member: Symbol) = new TreeMethods(Ident(target)) DOT member
// name of nth indexed argument to a method (first parameter list), defaults to 1st
def ARG(idx: Int = 0) = Ident(target.paramss.head(idx))
@@ -81,12 +119,23 @@ trait TreeDSL {
}
/** Top level accessible. */
- def THROW(sym: Symbol, msg: Tree) = Throw(New(TypeTree(sym.tpe), List(List(msg.TOSTRING))))
+ def THROW(sym: Symbol, msg: Tree = null) = {
+ val arg = if (msg == null) Nil else List(msg.TOSTRING)
+ Throw(New(TypeTree(sym.tpe), List(arg)))
+ }
+ def NEW(tpe: Tree, args: Tree*) = New(tpe, List(args.toList))
+
+ def VAL(sym: Symbol) = new ValStart(sym)
def DEF(sym: Symbol) = new DefStart(sym)
def AND(guards: Tree*) =
if (guards.isEmpty) EmptyTree
else guards reduceLeft gen.mkAnd
+ def IF(tree: Tree) = new IfStart(tree, EmptyTree)
+ def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree)
+ def REF(sym: Symbol) = gen.mkAttributedRef(sym)
+ def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last)
+
/** Implicits - some of these should probably disappear **/
implicit def mkTreeMethods(target: Tree): TreeMethods = new TreeMethods(target)
implicit def mkTreeMethodsFromSymbol(target: Symbol): TreeMethods = new TreeMethods(Ident(target))
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 221d08e824..dcdb284af2 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -174,24 +174,28 @@ abstract class TreeGen {
}
/** Builds an instance test with given value and type. */
- def mkIsInstanceOf(value: Tree, tpe: Type): Tree = // buraq: we ignore erase, no rtt
+ def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = {
+ val sym = if (any) Any_isInstanceOf else Object_isInstanceOf
Apply(
TypeApply(
- mkAttributedSelect(value, Any_isInstanceOf),
+ mkAttributedSelect(value, sym),
List(TypeTree(tpe.normalize))
),
Nil
)
+ }
/** Builds a cast with given value and type. */
- def mkAsInstanceOf(value: Tree, tpe: Type): Tree =
+ def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = {
+ val sym = if (any) Any_asInstanceOf else Object_asInstanceOf
Apply(
TypeApply(
- mkAttributedSelect(value, Any_asInstanceOf),
+ mkAttributedSelect(value, sym),
List(TypeTree(tpe.normalize))
),
Nil
)
+ }
def mkClassOf(tp: Type): Tree =
Literal(Constant(tp)) setType Predef_classOfType(tp)
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index c1ac9e15aa..f1c6641dd0 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -11,9 +11,10 @@ import Flags._
import scala.tools.nsc.util.Position
import scala.collection.mutable.{ListBuffer, HashMap}
-abstract class CleanUp extends Transform {
+abstract class CleanUp extends Transform with ast.TreeDSL {
import global._
import definitions._
+ import CODE._
/** the following two members override abstract members in Transform */
val phaseName: String = "cleanup"
@@ -22,7 +23,6 @@ abstract class CleanUp extends Transform {
new CleanUpTransformer(unit)
class CleanUpTransformer(unit: CompilationUnit) extends Transformer {
-
private val newDefs = new ListBuffer[Tree]
private val newInits = new ListBuffer[Tree]
@@ -46,40 +46,40 @@ abstract class CleanUp extends Transform {
private var localTyper: analyzer.Typer = null
- private def classConstantMethod(pos: Position, sig: String): Symbol = classConstantMeth.get(sig) match {
- case Some(meth) =>
- meth
- case None =>
+ private object MethodDispatchType extends scala.Enumeration {
+ val NO_CACHE, MONO_CACHE, POLY_CACHE = Value
+ }
+ import MethodDispatchType.{ NO_CACHE, MONO_CACHE, POLY_CACHE }
+ private def dispatchType() = settings.refinementMethodDispatch.value match {
+ case "no-cache" => NO_CACHE
+ case "mono-cache" => MONO_CACHE
+ case "poly-cache" => POLY_CACHE
+ }
+
+ private def typedWithPos(pos: Position)(tree: Tree) =
+ localTyper typed { atPos(pos)(tree) }
+
+ private def classConstantMethod(pos: Position, sig: String): Symbol =
+ (classConstantMeth get sig) getOrElse {
val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName)
val owner = currentOwner.enclClass
val cvar = owner.newVariable(pos, unit.fresh.newName(pos, "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)))
- }
- }
+ owner.info.decls enter cvar
+ val cdef = typedWithPos(pos) { VAL(cvar) === NULL }
val meth = owner.newMethod(pos, unit.fresh.newName(pos, "class$Method"))
.setFlag(PRIVATE | STATIC | SYNTHETIC).setInfo(MethodType(List(), ClassClass.tpe))
- owner.info.decls.enter(meth)
- val mdef =
- localTyper.typed {
- atPos(pos) {
- DefDef(meth, gen.mkCached(
- cvar,
- Apply(
- gen.mkAttributedRef(forName), List(Literal(sig)))))
- }
- }
+ owner.info.decls enter meth
+ val mdef = typedWithPos(pos)(DEF(meth) ===
+ gen.mkCached(cvar, Apply(REF(forName), List(Literal(sig))))
+ )
- newDefs.append(cdef, mdef);
+ newDefs.append(cdef, mdef)
classConstantMeth.update(sig, meth)
meth
- }
+ }
override def transformUnit(unit: CompilationUnit) =
unit.body = transform(unit.body)
@@ -123,61 +123,55 @@ abstract class CleanUp extends Transform {
* refinement, where the refinement defines a parameter based on a
* type variable. */
case ad@ApplyDynamic(qual0, params) =>
+ def mkName(s: String = "") =
+ if (s == "") unit.fresh newName ad.pos
+ else unit.fresh.newName(ad.pos, s)
+ def mkTerm(s: String = "") = newTermName(mkName(s))
+ val typedPos = typedWithPos(ad.pos) _
+
assert(ad.symbol.isPublic)
var qual: Tree = qual0
/* ### CREATING THE METHOD CACHE ### */
def addStaticVariableToClass(forName: String, forType: Type, forInit: Tree): Symbol = {
- val varSym = currentClass.newVariable(ad.pos, unit.fresh.newName(ad.pos, forName))
+ val varSym = currentClass.newVariable(ad.pos, mkName(forName))
.setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC)
.setInfo(forType)
- currentClass.info.decls.enter(varSym)
- val varDef =
- localTyper.typed {
- atPos(ad.pos) {
- ValDef(varSym, forInit)
- }
- }
- newDefs.append(transform(varDef))
- val varInit =
- localTyper.typed {
- atPos(ad.pos) {
- Assign(gen.mkAttributedRef(varSym), forInit)
- }
- }
- newInits.append(transform(varInit))
+ currentClass.info.decls enter varSym
+
+ val varDef = typedPos( VAL(varSym) === forInit )
+ newDefs append transform(varDef)
+
+ val varInit = typedPos( REF(varSym) === forInit )
+ newInits append transform(varInit)
+
varSym
}
def addStaticMethodToClass(forName: String, forArgsTypes: List[Type], forResultType: Type)
(forBody: Pair[Symbol, List[Symbol]] => Tree): Symbol = {
- val methSym = currentClass.newMethod(ad.pos, unit.fresh.newName(ad.pos, forName))
+ val methSym = currentClass.newMethod(ad.pos, mkName(forName))
.setFlag(STATIC | SYNTHETIC)
+
methSym.setInfo(MethodType(methSym.newSyntheticValueParams(forArgsTypes), forResultType))
- currentClass.info.decls.enter(methSym)
- val methDef =
- localTyper.typed {
- atPos(ad.pos) {
- DefDef(methSym, { forBody(Pair(methSym, methSym.paramss(0))) })
- }
- }
- newDefs.append(transform(methDef))
+ currentClass.info.decls enter methSym
+
+ val methDef = typedPos( DefDef(methSym, { forBody(Pair(methSym, methSym.paramss(0))) }) )
+ newDefs append transform(methDef)
+
methSym
}
def fromTypesToClassArrayLiteral(paramTypes: List[Type]): Tree =
- ArrayValue(TypeTree(ClassClass.tpe), paramTypes map { pt => Literal(Constant(pt)) })
+ ArrayValue(TypeTree(ClassClass.tpe), paramTypes map LIT)
def theTypeClassArray =
TypeRef(ArrayClass.tpe.prefix, ArrayClass, List(ClassClass.tpe))
/* ... */
- def reflectiveMethodCache(method: String, paramTypes: List[Type]): Symbol = {
-
- settings.refinementMethodDispatch.value match {
-
- case "no-cache" =>
+ def reflectiveMethodCache(method: String, paramTypes: List[Type]): Symbol = dispatchType match {
+ case NO_CACHE =>
/* Implementation of the cache is as follows for method "def xyz(a: A, b: B)":
@@ -191,21 +185,12 @@ abstract class CleanUp extends Transform {
val reflParamsCacheSym: Symbol =
addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes))
- val reflMethodSym: Symbol =
- addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe)
- { case Pair(reflMethodSym, List(forReceiverSym)) =>
- Apply(
- Select(gen.mkAttributedRef(forReceiverSym), Class_getMethod),
- List(
- Literal(Constant(method)),
- gen.mkAttributedRef(reflParamsCacheSym)
- )
- )
- }
-
- reflMethodSym
+ addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) {
+ case Pair(reflMethodSym, List(forReceiverSym)) =>
+ (REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym))
+ }
- case "mono-cache" =>
+ case MONO_CACHE =>
/* Implementation of the cache is as follows for method "def xyz(a: A, b: B)":
@@ -229,47 +214,26 @@ abstract class CleanUp extends Transform {
addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes))
val reflMethodCacheSym: Symbol =
- addStaticVariableToClass("reflMethod$Cache", MethodClass.tpe, Literal(Constant(null)))
+ addStaticVariableToClass("reflMethod$Cache", MethodClass.tpe, NULL)
val reflClassCacheSym: Symbol =
- addStaticVariableToClass("reflClass$Cache", ClassClass.tpe, Literal(Constant(null)))
-
-
- val reflMethodSym: Symbol =
- addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe)
- { case Pair(reflMethodSym, List(forReceiverSym)) =>
- Block(
- List(
- If(Apply(Select(gen.mkAttributedRef(reflClassCacheSym), nme.ne), List(gen.mkAttributedRef(forReceiverSym))),
- Block(
- List(
- Assign(
- gen.mkAttributedRef(reflMethodCacheSym),
- Apply(
- Select(
- gen.mkAttributedRef(forReceiverSym),
- ClassClass.tpe.member(nme.getMethod_)
- ),
- List(
- Literal(Constant(method)),
- gen.mkAttributedRef(reflParamsCacheSym)
- )
- )
- ),
- Assign(gen.mkAttributedRef(reflClassCacheSym), gen.mkAttributedRef(forReceiverSym))
- ),
- Literal(Constant(()))
- ),
- EmptyTree
- )
- ),
- gen.mkAttributedRef(reflMethodCacheSym)
- )
- }
-
- reflMethodSym
+ addStaticVariableToClass("reflClass$Cache", ClassClass.tpe, NULL)
+
+ def getMethodSym = ClassClass.tpe member nme.getMethod_
+
+ addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) {
+ case Pair(reflMethodSym, List(forReceiverSym)) =>
+ BLOCK(
+ IF (REF(reflClassCacheSym) NE_REF REF(forReceiverSym)) THEN BLOCK(
+ REF(reflMethodCacheSym) === ((REF(forReceiverSym) DOT getMethodSym)(LIT(method), REF(reflParamsCacheSym))) ,
+ REF(reflClassCacheSym) === REF(forReceiverSym),
+ UNIT
+ ) ENDIF,
+ REF(reflMethodCacheSym)
+ )
+ }
- case "poly-cache" =>
+ case POLY_CACHE =>
/* Implementation of the cache is as follows for method "def xyz(a: A, b: B)":
@@ -294,53 +258,31 @@ abstract class CleanUp extends Transform {
addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes))
val reflPolyCacheSym: Symbol =
- addStaticVariableToClass("reflPoly$Cache", MethodCacheClass.tpe, New(TypeTree(EmptyMethodCacheClass.tpe), List(Nil)))
+ addStaticVariableToClass("reflPoly$Cache", MethodCacheClass.tpe, NEW(TypeTree(EmptyMethodCacheClass.tpe)))
val reflMethodSym: Symbol =
addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe)
{ case Pair(reflMethodSym, List(forReceiverSym)) =>
- val methodSym = reflMethodSym.newVariable(ad.pos, newTermName(unit.fresh.newName(ad.pos, "method"))) setInfo MethodClass.tpe
- Block(
- List(
- ValDef(
- methodSym,
- Apply(
- Select(gen.mkAttributedRef(reflPolyCacheSym), methodCache_find),
- List(gen.mkAttributedRef(forReceiverSym))
- )
+ val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe
+
+ BLOCK(
+ VAL(methodSym) === ((REF(reflPolyCacheSym) DOT methodCache_find)(REF(forReceiverSym))) ,
+ IF (REF(methodSym) NOT_== NULL) .
+ THEN (Return(REF(methodSym)))
+ ELSE {
+ def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym)))
+ def cacheRHS = ((REF(reflPolyCacheSym) DOT methodCache_add)(REF(forReceiverSym), REF(methodSym)))
+ BLOCK(
+ REF(methodSym) === methodSymRHS,
+ REF(reflPolyCacheSym) === cacheRHS,
+ Return(REF(methodSym))
)
- ),
- If(
- Apply(Select(gen.mkAttributedRef(methodSym), Object_ne), List(Literal(Constant(null)))),
- Return(gen.mkAttributedRef(methodSym)),
- Block(
- List(
- Assign(gen.mkAttributedRef(methodSym),
- Apply(
- Select(gen.mkAttributedRef(forReceiverSym), Class_getMethod),
- List(
- Literal(Constant(method)),
- gen.mkAttributedRef(reflParamsCacheSym)
- )
- )
- ),
- Assign(
- gen.mkAttributedRef(reflPolyCacheSym),
- Apply(
- Select(gen.mkAttributedRef(reflPolyCacheSym), methodCache_add),
- List(gen.mkAttributedRef(forReceiverSym), gen.mkAttributedRef(methodSym))
- )
- )
- ),
- Return(gen.mkAttributedRef(methodSym))
- )
- )
+ }
)
}
reflMethodSym
- }
}
/* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */
@@ -356,102 +298,55 @@ abstract class CleanUp extends Transform {
}
- 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 testForNumber: Tree = (qual IS_OBJ BoxedNumberClass.tpe) OR (qual IS_OBJ BoxedCharacterClass.tpe)
+ val testForBoolean: Tree = (qual IS_OBJ BoxedBooleanClass.tpe)
+ val testForNumberOrBoolean = testForNumber OR testForBoolean
+
+ val getPrimitiveReplacementForStructuralCall: PartialFunction[Name, (Symbol, Tree)] = {
+ val testsForNumber = Map() ++ List(
+ nme.UNARY_+ -> "positive",
+ nme.UNARY_- -> "negate",
+ nme.UNARY_~ -> "complement",
+ nme.ADD -> "add",
+ nme.SUB -> "subtract",
+ nme.MUL -> "multiply",
+ nme.DIV -> "divide",
+ nme.MOD -> "takeModulo",
+ nme.LSL -> "shiftSignedLeft",
+ nme.LSR -> "shiftLogicalRight",
+ nme.ASR -> "shiftSignedRight",
+ nme.LT -> "testLessThan",
+ nme.LE -> "testLessOrEqualThan",
+ nme.GE -> "testGreaterOrEqualThan",
+ nme.GT -> "testGreaterThan",
+ nme.toByte -> "toByte",
+ nme.toShort -> "toShort",
+ nme.toChar -> "toCharacter",
+ nme.toInt -> "toInteger",
+ nme.toLong -> "toLong",
+ nme.toFloat -> "toFloat",
+ nme.toDouble-> "toDouble"
)
-
- val testForBoolean: Tree =
- Apply(
- TypeApply(
- gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
- List(TypeTree(BoxedBooleanClass.tpe.normalize))
- ),
- List()
+ val testsForBoolean = Map() ++ List(
+ nme.UNARY_! -> "takeNot",
+ nme.ZOR -> "takeConditionalOr",
+ nme.ZAND -> "takeConditionalAnd"
+ )
+ val testsForNumberOrBoolean = Map() ++ List(
+ nme.OR -> "takeOr",
+ nme.XOR -> "takeXor",
+ nme.AND -> "takeAnd",
+ nme.EQ -> "testEqual",
+ nme.NE -> "testNotEqual"
)
+ def get(name: String) = getMember(BoxesRunTimeClass, name)
- 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("shiftLogicalRight")), testForNumber)
- case nme.ASR =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedRight")), testForNumber)
- case nme.EQ =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testEqual")), testForNumberOrBoolean)
- case nme.NE =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testNotEqual")), testForNumberOrBoolean)
- case nme.LT =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testLessThan")), testForNumber)
- case nme.LE =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testLessOrEqualThan")), testForNumber)
- case nme.GE =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testGreaterOrEqualThan")), testForNumber)
- case nme.GT =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testGreaterThan")), testForNumber)
- /* Conversions */
- case nme.toByte =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toByte")), testForNumber)
- case nme.toShort =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toShort")), testForNumber)
- case nme.toChar =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toCharacter")), testForNumber)
- case nme.toInt =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toInteger")), testForNumber)
- case nme.toLong =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toLong")), testForNumber)
- case nme.toFloat =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toFloat")), testForNumber)
- case nme.toDouble =>
- (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toDouble")), testForNumber)
+ /** Begin partial function. */
+ {
+ case x if testsForNumber contains x => (get(testsForNumber(x)), testForNumber)
+ case x if testsForBoolean contains x => (get(testsForBoolean(x)), testForBoolean)
+ case x if testsForNumberOrBoolean contains x => (get(testsForNumberOrBoolean(x)), testForNumberOrBoolean)
+ }
}
/* ### BOXING PARAMS & UNBOXING RESULTS ### */
@@ -466,35 +361,21 @@ abstract class CleanUp extends Transform {
* - otherwise, the value is simply casted to the expected type. This
* is enough even for value (int et al.) values as the result of
* a dynamic call will box them as a side-effect. */
- def fixResult(resType: Type)(tree: Tree): Tree =
- localTyper.typed {
- if (resType.typeSymbol == UnitClass)
- Block (
- List(tree),
- gen.mkAttributedRef(BoxedUnit_UNIT)
- )
- else if (resType.typeSymbol == ArrayClass) {
- val sym = currentOwner.newValue(ad.pos, newTermName(unit.fresh.newName(ad.pos))) setInfo ObjectClass.tpe
- Block(
- List(ValDef(sym, tree)),
- If(
- Apply(Select(Literal(Constant(null)), Any_==), List(gen.mkAttributedRef(sym))),
- Literal(Constant(null)),
- Apply(
- Select(
- gen.mkAttributedRef(ScalaRunTimeModule),
- ScalaRunTimeModule.tpe.member(nme.boxArray)
- ),
- List(gen.mkAttributedRef(sym))
- )
- )
- )
- }
- else if (resType.typeSymbol == ObjectClass) // TODO: remove the cast always when unnecessary.
- tree
- else
- gen.mkAttributedCast(tree, resType)
+ def fixResult(resType: Type)(tree: Tree): Tree = localTyper typed {
+ def boxArray = {
+ val sym = currentOwner.newValue(ad.pos, mkTerm()) setInfo ObjectClass.tpe
+ BLOCK(
+ VAL(sym) === tree,
+ IF (NULL EQANY REF(sym)) THEN NULL ELSE gen.mkRuntimeCall(nme.boxArray, List(REF(sym)))
+ )
}
+ resType.typeSymbol match {
+ case UnitClass => BLOCK(tree, REF(BoxedUnit_UNIT))
+ case ArrayClass => boxArray
+ case ObjectClass => tree
+ case _ => tree AS_ATTR resType
+ }
+ }
/* Transforms the parameters of a dynamic apply (always AnyRefs) to
* something compatible with reclective calls. The transformation depends
@@ -503,33 +384,23 @@ abstract class CleanUp extends Transform {
* type. If it is a boxed array, the array is unboxed. If it is an
* unboxed array, it is left alone. */
def fixParams(params: List[Tree], paramTypes: List[Type]): List[Tree] =
- (params zip paramTypes) map { case (param, paramType) =>
- localTyper.typed {
+ for ((param, paramType) <- params zip paramTypes) yield {
+ localTyper typed {
if (paramType.typeSymbol == ArrayClass) {
- val sym = currentOwner.newValue(ad.pos, newTermName(unit.fresh.newName(ad.pos))) setInfo ObjectClass.tpe
- val arrayType = {
- assert(paramType.typeArgs.length == 1)
- paramType.typeArgs(0).normalize
- }
- Block(
- List(ValDef(sym, param)),
- If(
- Apply(Select(Literal(Constant(null)), Any_==), List(gen.mkAttributedRef(sym))),
- Literal(Constant(null)),
- If(
- Apply(
- TypeApply(
- gen.mkAttributedSelect(gen.mkAttributedRef(sym), definitions.Object_isInstanceOf),
- List(TypeTree(BoxedArrayClass.tpe.normalize))
- ),
- List()
- ),
- Apply(
- Select(gen.mkAttributedCast(gen.mkAttributedRef(sym), BoxedArrayClass.tpe), getMember(BoxedArrayClass, nme.unbox)),
- List(Literal(Constant(arrayType)))
- ),
- gen.mkAttributedRef(sym)
- )
+ val sym = currentOwner.newValue(ad.pos, mkTerm()) setInfo ObjectClass.tpe
+ assert(paramType.typeArgs.length == 1)
+ val arrayType = paramType.typeArgs(0).normalize
+ lazy val unboxMethod = getMember(BoxedArrayClass, nme.unbox)
+
+ BLOCK(
+ VAL(sym) === param,
+ IF (NULL EQANY REF(sym)) .
+ THEN (NULL) .
+ ELSE (
+ IF (REF(sym) IS_OBJ BoxedArrayClass.tpe) .
+ THEN (((REF(sym) AS_ATTR BoxedArrayClass.tpe) DOT unboxMethod)(LIT(arrayType)))
+ ELSE
+ REF(sym)
)
)
}
@@ -539,50 +410,35 @@ abstract class CleanUp extends Transform {
}
/* ### CALLING THE APPLY -> one for operators (see above), one for normal methods ### */
-
- def callAsOperator(paramTypes: List[Type], resType: Type): Tree = localTyper.typed {
+ def callAsOperator(paramTypes: List[Type], resType: Type): Tree = localTyper typed {
+ def default = callAsMethod(paramTypes, resType)
if (getPrimitiveReplacementForStructuralCall isDefinedAt ad.symbol.name) {
- val (operator, test) = getPrimitiveReplacementForStructuralCall(ad.symbol.name)
- If(
- test,
- Apply(
- gen.mkAttributedRef(operator),
- qual :: fixParams(params, paramTypes)
- ),
- callAsMethod(paramTypes, resType)
- )
+ val (operator, test) = getPrimitiveReplacementForStructuralCall(ad.symbol.name)
+ def args = qual :: fixParams(params, paramTypes)
+
+ IF (test) THEN (REF(operator) APPLY args) ELSE default
}
- else callAsMethod(paramTypes, resType)
+ else default
}
def callAsMethod(paramTypes: List[Type], resType: Type): Tree = localTyper.typed {
- val invokeExc =
- currentOwner.newValue(ad.pos, newTermName(unit.fresh.newName(ad.pos))) setInfo InvocationTargetExceptionClass.tpe
- Try(
- Apply(
- Select(
- Apply(
- gen.mkAttributedRef(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)),
- List(Apply(Select(qual, ObjectClass.tpe.member(nme.getClass_)), Nil))
- ),
- MethodClass.tpe.member(nme.invoke_)
- ),
- List(
- qual,
- ArrayValue(TypeTree(ObjectClass.tpe), fixParams(params, paramTypes))
- )
- ),
- List(CaseDef(
- Bind(invokeExc, Typed(Ident(nme.WILDCARD), TypeTree(InvocationTargetExceptionClass.tpe))),
- EmptyTree,
- Throw(Apply(Select(Ident(invokeExc), nme.getCause), Nil))
- )),
- EmptyTree
- )
+ // reflective method call machinery
+ val invokeName = MethodClass.tpe member nme.invoke_ // reflect.Method.invoke(...)
+ def cache = REF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
+ def lookup = Apply(cache, List(qual GETCLASS)) // get Method object from cache
+ def args = ArrayValue(TypeTree(ObjectClass.tpe), fixParams(params, paramTypes)) // args for invocation
+ def invocation = (lookup DOT invokeName)(qual, args) // .invoke(qual, ...)
+
+ // exception catching machinery
+ val invokeExc = currentOwner.newValue(ad.pos, mkTerm()) setInfo InvocationTargetExceptionClass.tpe
+ def catchVar = Bind(invokeExc, Typed(Ident(nme.WILDCARD), TypeTree(InvocationTargetExceptionClass.tpe)))
+ def catchBody = Throw(Apply(Select(Ident(invokeExc), nme.getCause), Nil))
+
+ // try { method.invoke } catch { case e: InvocationTargetExceptionClass => throw e.getCause() }
+ TRY (invocation) CATCH { CASE (catchVar) ==> catchBody } ENDTRY
}
- def getClass(q: Tree): Tree =
- Apply(Select(q, nme.getClass_), List())
+ def getClass(q: Tree): Tree = (q DOT nme.getClass_)()
if (settings.refinementMethodDispatch.value == "invoke-dynamic") {
/* val guardCallSite: Tree = {
@@ -626,42 +482,39 @@ abstract class CleanUp extends Transform {
val t: Tree = ad.symbol.tpe match {
case MethodType(mparams, resType) =>
assert(params.length == mparams.length)
- atPos(ad.pos)(localTyper.typed {
- val t1 = newTermName(unit.fresh.newName(ad.pos, "qual"))
- val sym = currentOwner.newValue(ad.pos, t1) setInfo qual0.tpe
- qual = gen.mkAttributedRef(sym)
- Block(
- List(ValDef(sym, qual0)),
- fixResult(if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType) {
- if (mayRequirePrimitiveReplacement)
- callAsOperator(mparams map (_.tpe), resType)
- else
- callAsMethod(mparams map (_.tpe), resType)
- }
+ typedPos {
+ val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe
+ qual = REF(sym)
+
+ def resTypeForFix = if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType
+ def call = if (mayRequirePrimitiveReplacement) (callAsOperator _) else (callAsMethod _)
+ BLOCK(
+ VAL(sym) === qual0,
+ fixResult(resTypeForFix)(call(mparams map (_.tpe), resType))
)
- })
+ }
}
/* For testing purposes, the dynamic application's condition
* can be printed-out in great detail. Remove? */
if (settings.debug.value) {
- Console.println(
- "Dynamically applying '" + qual + "." + ad.symbol.name +
- "(" + params.map(_.toString).mkString(", ") + ")' with"
- )
- ad.symbol.tpe match {
+ def paramsToString(xs: Any*) = xs map (_.toString) mkString ", "
+ val mstr = ad.symbol.tpe match {
case MethodType(mparams, resType) =>
- Console.println(
- " - declared parameters' types: " +
- (mparams.map(_.toString)).mkString("'",", ","'"))
- Console.println(
- " - passed arguments' types: " +
- (params.map(_.toString)).mkString("'",", ","'"))
- Console.println(
- " - result type: '" +
- resType.toString + "'")
+ """| with
+ | - declared parameter types: '%s'
+ | - passed argument types: '%s'
+ | - result type: '%s'""" .
+ stripMargin.format(
+ paramsToString(mparams),
+ paramsToString(params),
+ resType.toString
+ )
+ case _ => ""
}
- Console.println(" - resulting code: '" + t + "'")
+ Console.printf("""Dynamically application '%s.%s(%s)' %s - resulting code: '%s'""",
+ List(qual, ad.symbol.name, paramsToString(params), mstr, t) map (_.toString) : _*
+ )
}
/* We return the dynamic call tree, after making sure no other
@@ -707,12 +560,10 @@ abstract class CleanUp extends Transform {
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
- atPos(tree.pos) {
- localTyper.typed {
- if (isValueClass(tpe.typeSymbol) || tpe.typeSymbol == definitions.UnitClass)
- Select(gen.mkAttributedRef(javaBoxClassModule(tpe.typeSymbol)), "TYPE")
- else tree
- }
+ typedWithPos(tree.pos) {
+ if (isValueClass(tpe.typeSymbol) || tpe.typeSymbol == definitions.UnitClass)
+ Select(REF(javaBoxClassModule(tpe.typeSymbol)), "TYPE")
+ else tree
}
/* MSIL requires that the stack is empty at the end of a try-block.
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index d5ace3c4f6..2d3edf3a0e 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -13,7 +13,7 @@ import util.TreeSet
/** This phase converts classes with parameters into Java-like classes with
* fields, which are assigned to from constructors.
*/
-abstract class Constructors extends Transform {
+abstract class Constructors extends Transform with ast.TreeDSL {
import global._
import definitions._
@@ -130,19 +130,16 @@ abstract class Constructors extends Transform {
// Create code to copy parameter to parameter accessor field.
// If parameter is $outer, check that it is not null.
def copyParam(to: Symbol, from: Symbol): Tree = {
+ import CODE._
var result = mkAssign(to, Ident(from))
if (from.name == nme.OUTER)
result =
atPos(to.pos) {
localTyper.typed {
- If(
- Apply(
- Select(Ident(from), nme.eq),
- List(Literal(Constant(null)))),
- Throw(New(TypeTree(NullPointerExceptionClass.tpe), List(List()))),
- result)
+ IF (from EQREF NULL) THEN THROW(NullPointerExceptionClass) ELSE result
}
}
+
result
}
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index ce5329e532..9707baf392 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -3,7 +3,7 @@ package scala.tools.nsc.transform;
import scala.tools.nsc._
import scala.collection.mutable.HashMap
-abstract class LazyVals extends Transform {
+abstract class LazyVals extends Transform with ast.TreeDSL {
// inherits abstract value `global' and class `Phase' from Transform
import global._ // the global environment
@@ -146,13 +146,10 @@ abstract class LazyVals extends Transform {
(Block(List(rhs, mkSetFlag(bitmapSym, mask)), Literal(Constant(()))), Literal(()))
}
+ import CODE._
+
val result = atPos(tree.pos) {
- If(Apply(
- Select(
- Apply(Select(Ident(bitmapSym), Int_And),
- List(mask)),
- Int_==),
- List(Literal(Constant(0)))), block, EmptyTree)
+ IF ((Ident(bitmapSym) BIT_AND mask) EQINT ZERO) THEN block ENDIF
}
typed(Block(List(result), res))
}