diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2011-11-22 23:10:23 +0000 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2011-11-22 23:10:23 +0000 |
commit | aa1219dcdb273ac5a44521c255528b243b8e5a04 (patch) | |
tree | 6b467f8b8968d711cd021cdb05719a7a364aaddf | |
parent | ae054a1663381ada248ab020ea4993452664cd83 (diff) | |
download | scala-aa1219dcdb273ac5a44521c255528b243b8e5a04.tar.gz scala-aa1219dcdb273ac5a44521c255528b243b8e5a04.tar.bz2 scala-aa1219dcdb273ac5a44521c255528b243b8e5a04.zip |
optimizing type tests and related stuff
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala | 43 |
2 files changed, 39 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index fe54dafb1b..c4bdb73744 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -311,7 +311,11 @@ abstract class UnCurry extends InfoTransform else if (IntClass.tpe <:< a.tpe) Literal(Constant(0)) else if (LongClass.tpe <:< a.tpe) Literal(Constant(0L)) else if (CharClass.tpe <:< a.tpe) Literal(Constant(0.toChar)) - else gen.mkCast(NULL, a.tpe) // must cast, at least when a.tpe <:< NothingClass.tpe + else { + val tpA = a.tpe.normalize + if (NullClass.tpe <:< tpA) NULL + else gen.mkCast(NULL, tpA) // must cast, at least when a.tpe <:< NothingClass.tpe + } Apply(fun.duplicate, List(zero)) case _ => super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index e3ac21469e..9fb6c7668a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -843,8 +843,18 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => // repack existential types, otherwise they sometimes get unpacked in the wrong location (type inference comes up with an unexpected skolem) // TODO: I don't really know why this happens -- maybe because the owner hierarchy changes? // the other workaround (besides repackExistential) is to explicitly pass expectedTp as the type argument for the call to guard, but repacking the existential somehow feels more robust + // TODO: check if optimization makes a difference, try something else if necessary (cache?) def repackExistential(tp: Type): Type = if(tp == NoType) tp - else existentialAbstraction((tp filter {t => t.typeSymbol.isExistentiallyBound}) map (_.typeSymbol), tp) + else { + val existentials = new collection.mutable.ListBuffer[Symbol] + tp foreach { t => + val sym = t.typeSymbol + if (sym.isExistentiallyBound) existentials += sym + } + if (existentials isEmpty) tp + else existentialAbstraction(existentials toList, tp) + // existentialAbstraction((tp filter {t => t.typeSymbol.isExistentiallyBound}) map (_.typeSymbol), tp) + } object vpmName { val caseResult = "caseResult".toTermName @@ -866,6 +876,9 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => import CODE._ + // cf. !needsTypeTest from above + def typesConform(tp: Type, pt: Type) = (tp eq pt) || (tp <:< pt) + trait CommonCodeGen extends AbsCodeGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body) def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT vpmName.tupleIndex(i)) // make tree that accesses the i'th component of the tuple referenced by binder @@ -873,10 +886,22 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n)) def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya def and(a: Tree, b: Tree): Tree = a AND b - def _asInstanceOf(t: Tree, tp: Type): Tree = gen.mkAsInstanceOf(t, repackExistential(tp), true, false) - // TODO: optimize to if (!needsTypeTest(b.info.widen, repackExistential(tp))) REF(b) else ... - def _asInstanceOf(b: Symbol, tp: Type): Tree = gen.mkAsInstanceOf(REF(b), repackExistential(tp), true, false) + + def _asInstanceOf(t: Tree, tp: Type): Tree = { val tpX = repackExistential(tp) + if ((t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tpX)) t //{ println("warning: emitted redundant asInstanceOf: "+(t, t.tpe, tp)); t } //.setType(tpX) + else gen.mkAsInstanceOf(t, tpX, true, false) + } + def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), repackExistential(tp), true, false) + // { val tpX = repackExistential(tp) + // if (typesConform(b.info, tpX)) { println("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE } + // else gen.mkIsInstanceOf(REF(b), tpX, true, false) + // } + + def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = repackExistential(tp) + if (typesConform(b.info, tpX)) REF(b) //{ println("warning: emitted redundant asInstanceOf: "+(b, b.info, tp)); REF(b) } //.setType(tpX) + else gen.mkAsInstanceOf(REF(b), tpX, true, false) + } } trait MatchingStrategyGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => @@ -887,7 +912,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => def or(f: Tree, as: List[Tree]): Tree = (matchingStrategy DOT vpmName.or)((f :: as): _*) // matchingStrategy.or(f, as) def guard(c: Tree): Tree = (matchingStrategy DOT vpmName.guard)(c, UNIT) // matchingStrategy.guard(c, then) -- a user-defined guard // TODO: get rid of the cast when it's unnecessary, but this requires type checking `body` -- maybe this should be one of the optimisations we perform after generating the tree - def caseResult(res: Tree, tp: Type): Tree = (matchingStrategy DOT vpmName.caseResult) (pmgen._asInstanceOf(res, tp)) // matchingStrategy.caseResult(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case) + def caseResult(res: Tree, tp: Type): Tree = (matchingStrategy DOT vpmName.caseResult) (_asInstanceOf(res, tp)) // matchingStrategy.caseResult(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case) // an internal guard TODO: use different method call so exhaustiveness can distinguish it from user-defined guards def cond(c: Tree, then: Tree = UNIT, tp: Type = NoType): Tree = genTypeApply((matchingStrategy DOT vpmName.guard), repackExistential(tp)) APPLY (c, then) // matchingStrategy.guard(c, then) @@ -898,7 +923,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => trait MonadInstGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => // methods in the monad instance -- used directly in translation def flatMap(a: Tree, b: Tree): Tree = (a DOT vpmName.flatMap)(b) - def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (genTyped(thisCase, pt) DOT vpmName.orElse)(genTyped(elseCase, pt)) + def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (genTypeApply(thisCase DOT vpmName.orElse, pt)) APPLY (elseCase) } // when we know we're targetting Option, do some inlining the optimizer won't do @@ -947,16 +972,16 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => override def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = { val vs = freshSym(thisCase.pos, pt, "o") val isEmpty = pt member vpmName.isEmpty - val v = VAL(vs) === genTyped(thisCase, pt) + val v = VAL(vs) === thisCase // genTyped(, pt) BLOCK( v, - IF (vs DOT isEmpty) THEN genTyped(elseCase, pt) ELSE REF(vs) + IF (vs DOT isEmpty) THEN elseCase /*genTyped(, pt)*/ ELSE REF(vs) ) } } def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree) - def genTyped(t: Tree, tp: Type): Tree = if(tp == NoType) t else Typed(t, TypeTree(repackExistential(tp))) + // def genTyped(t: Tree, tp: Type): Tree = if(tp == NoType) t else Typed(t, TypeTree(repackExistential(tp))) } } |