summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/UnCurry.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/UnCurry.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala121
1 files changed, 82 insertions, 39 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index f319abd060..4ae4042cc7 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -133,11 +133,9 @@ abstract class UnCurry extends InfoTransform
/** Return non-local return key for given method */
private def nonLocalReturnKey(meth: Symbol) =
- nonLocalReturnKeys.getOrElseUpdate(meth, {
- meth.newValue(meth.pos, unit.freshTermName("nonLocalReturnKey"))
- .setFlag (SYNTHETIC)
- .setInfo (ObjectClass.tpe)
- })
+ nonLocalReturnKeys.getOrElseUpdate(meth,
+ meth.newValue(unit.freshTermName("nonLocalReturnKey"), meth.pos, SYNTHETIC) setInfo ObjectClass.tpe
+ )
/** Generate a non-local return throw with given return expression from given method.
* I.e. for the method's non-local return key, generate:
@@ -255,7 +253,7 @@ abstract class UnCurry extends InfoTransform
if (fun1 ne fun) fun1
else {
val (formals, restpe) = (targs.init, targs.last)
- val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag)
+ val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag)
def parents =
if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
@@ -291,46 +289,90 @@ abstract class UnCurry extends InfoTransform
val substParam = new TreeSymSubstituter(List(vparam), List(idparam))
def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t))
+ // waiting here until we can mix case classes and extractors reliably (i.e., when virtpatmat becomes the default)
+ // object VirtPatmatOpt {
+ // object Last {
+ // def unapply[T](xs: List[T]) = xs.lastOption
+ // }
+ // // keep this in synch by what's generated by combineCases/runOrElse
+ // object MatcherBlock {
+ // def unapply(matcher: Tree): Option[(ValDef, ValDef, ValDef, ValDef, List[Tree])] = matcher match { // TODO: BUG the unapplySeq version of the case below does not seem to work in virtpatmat??
+ // case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _) => Some(zero, x, matchRes, keepGoing, stats)
+ // case _ => None
+ // }
+ // }
+ // // TODO: virtpatmat use case: would be nice if could abstract over the repeated pattern more easily
+ // // case Block(Last(P)) =>
+ // // case P =>
+ // def unapply(matcher: Tree): Option[(ValDef, ValDef, ValDef, ValDef, List[Tree], Tree => Tree)] = matcher match {
+ // case MatcherBlock(zero, x, matchRes, keepGoing, stats) => Some(zero, x, matchRes, keepGoing, stats, identity[Tree])
+ // case Block(outerStats, MatcherBlock(zero, x, matchRes, keepGoing, stats)) => Some(zero, x, matchRes, keepGoing, stats, inner => Block(outerStats, inner))
+ // case b => treeBrowser browse b; None
+ // }
+ // }
+
+ // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly
+ def dupMatch(selector: Tree, cases: List[CaseDef], wrap: Match => Tree = identity) = {
+ def transformCase(cdef: CaseDef): CaseDef =
+ CaseDef(cdef.pat, cdef.guard, Literal(Constant(true)))
+ def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+
+ gen.mkUncheckedMatch(
+ if (cases exists treeInfo.isDefaultCase) Literal(Constant(true))
+ else substTree(wrap(Match(selector, (cases map transformCase) :+ defaultCase)).duplicate)
+ )
+ }
+
+ def dupVirtMatch(zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], wrap: Block => Tree = identity) = {
+ object dropMatchResAssign extends Transformer {
+ // override val treeCopy = newStrictTreeCopier // will duplicate below
+ override def transform(tree: Tree): Tree = tree match {
+ // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing
+ case Block(List(matchRes, ass@Assign(keepGoingLhs, falseLit)), zero) if keepGoingLhs.symbol eq keepGoing.symbol =>
+ Block(List(ass), zero)
+ case _ =>
+ super.transform(tree)
+ }
+ }
+ val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList
+ val idaBlock = wrap(Block(
+ zero ::
+ x ::
+ /* drop matchRes def */
+ keepGoing ::
+ statsNoMatchRes,
+ NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` by `!keepGoing`
+ ))
+ substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed
+ }
+
DefDef(m, (fun.body: @unchecked) match {
case Match(selector, cases) =>
- def transformCase(cdef: CaseDef): CaseDef =
- substTree(CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(Constant(true))))
- def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
-
- gen.mkUncheckedMatch(
- if (cases exists treeInfo.isDefaultCase) Literal(Constant(true))
- else Match(substTree(selector.duplicate), (cases map transformCase) :+ defaultCase)
- )
- // TODO: check tgt.tpe.typeSymbol isNonBottomSubclass MatchingStrategyClass
+ dupMatch(selector, cases)
+ case Block((vd: ValDef) :: Nil, Match(selector, cases)) => // can't factor this out using an extractor due to bugs in the old pattern matcher
+ dupMatch(selector, cases, m => Block(List(vd), m))
+ // virtpatmat -- TODO: find a better way to keep this in synch with the code generated by patmatvirtualizer
case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), args_scrut), args_pm) if opt.virtPatmat =>
object noOne extends Transformer {
override val treeCopy = newStrictTreeCopier // must duplicate everything
- val one = tgt.tpe member "caseResult".toTermName
+ val one = tgt.tpe member newTermName("one")
override def transform(tree: Tree): Tree = tree match {
case Apply(fun, List(a)) if fun.symbol == one =>
// blow one's argument away since all we want to know is whether the match succeeds or not
// (the alternative, making `one` CBN, would entail moving away from Option)
- val zero = // must use subtyping (no need for equality thanks to covariance), as otherwise we miss types like `Any with Int`
- if (UnitClass.tpe <:< a.tpe) Literal(Constant())
- else if (BooleanClass.tpe <:< a.tpe) Literal(Constant(false))
- else if (FloatClass.tpe <:< a.tpe) Literal(Constant(0.0f))
- else if (DoubleClass.tpe <:< a.tpe) Literal(Constant(0.0d))
- else if (ByteClass.tpe <:< a.tpe) Literal(Constant(0.toByte))
- else if (ShortClass.tpe <:< a.tpe) Literal(Constant(0.toShort))
- 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 {
- 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))
+ Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe)))
case _ =>
super.transform(tree)
}
}
- substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member("isSuccess".toTermName)), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform)))
+ substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform)))
+ // for the optimized version of virtpatmat
+ case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _) if opt.virtPatmat =>
+ dupVirtMatch(zero, x, matchRes, keepGoing, stats)
+ case Block(outerStats, Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _)) if opt.virtPatmat => // can't factor this out using an extractor due to bugs in the old pattern matcher
+ dupVirtMatch(zero, x, matchRes, keepGoing, stats, m => Block(outerStats, m))
+ // case other =>
+ // treeBrowser browse other
})
}
@@ -408,7 +450,7 @@ abstract class UnCurry extends InfoTransform
atPhase(phase.next) {
if (isJava && isPrimitiveArray(suffix.tpe) && isArrayOfSymbol(fun.tpe.params.last.tpe, ObjectClass)) {
suffix = localTyper.typedPos(pos) {
- gen.mkRuntimeCall("toObjectArray", List(suffix))
+ gen.mkRuntimeCall(nme.toObjectArray, List(suffix))
}
}
}
@@ -417,7 +459,7 @@ abstract class UnCurry extends InfoTransform
val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args
- (formals, args1).zipped map { (formal, arg) =>
+ map2(formals, args1) { (formal, arg) =>
if (!isByNameParamType(formal)) {
arg
} else if (isByNameRef(arg)) {
@@ -515,6 +557,7 @@ abstract class UnCurry extends InfoTransform
}
case ValDef(_, _, _, rhs) =>
val sym = tree.symbol
+ if (sym eq NoSymbol) throw new IllegalStateException("Encountered Valdef without symbol: "+ tree + " in "+ unit)
// a local variable that is mutable and free somewhere later should be lifted
// as lambda lifting (coming later) will wrap 'rhs' in an Ref object.
if (!sym.owner.isSourceMethod)
@@ -726,8 +769,8 @@ abstract class UnCurry extends InfoTransform
case p => p.symbol.tpe
}
val forwresult = dd.symbol.tpe.finalResultType
- val forwformsyms = (forwformals, flatparams).zipped map ((tp, oldparam) =>
- currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp)
+ val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) =>
+ currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp)
)
def mono = MethodType(forwformsyms, forwresult)
val forwtype = dd.symbol.tpe match {
@@ -744,7 +787,7 @@ abstract class UnCurry extends InfoTransform
// create the tree
val forwtree = theTyper.typedPos(dd.pos) {
- val locals = (forwsym ARGS, flatparams).zipped map {
+ val locals = map2(forwsym ARGS, flatparams) {
case (_, fp) if !rpsymbols(fp.symbol) => null
case (argsym, fp) =>
Block(Nil,
@@ -754,7 +797,7 @@ abstract class UnCurry extends InfoTransform
)
)
}
- val seqargs = (locals, forwsym ARGS).zipped map {
+ val seqargs = map2(locals, forwsym ARGS) {
case (null, argsym) => Ident(argsym)
case (l, _) => l
}