Permalink
Browse files

cleaned up partialfun synth in uncurry

removed dead code due to new-style matches getting their partialfun treatment during typers
  • Loading branch information...
adriaanm committed May 2, 2012
1 parent e9ed9d4 commit 5b9a37529b0cd103cd25c11600b8ed8320a424fe
Showing with 102 additions and 186 deletions.
  1. +102 −186 src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -237,22 +237,21 @@ abstract class UnCurry extends InfoTransform
deEta(fun) match {
// nullary or parameterless
case fun1 if fun1 ne fun => fun1
case _ if fun.tpe.typeSymbol == PartialFunctionClass =>
// only get here when running under -Xoldpatmat
synthPartialFunction(fun)
case _ =>
def owner = fun.symbol.owner
def targs = fun.tpe.typeArgs
def isPartial = fun.tpe.typeSymbol == PartialFunctionClass
def parents =
val parents =
if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
else if (isPartial) List(appliedType(AbstractPartialFunctionClass, targs: _*), SerializableClass.tpe)
else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
val anonClass = owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
val targs = fun.tpe.typeArgs
val (formals, restpe) = (targs.init, targs.last)
def applyMethodDef = {
val applyMethodDef = {
val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL)
methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe)
@@ -268,198 +267,115 @@ abstract class UnCurry extends InfoTransform
methDef
}
// def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
def applyOrElseMethodDef = {
val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE)
val List(argtpe) = formals
val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe)
val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe)
val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe))
val params@List(x, default) = methSym newSyntheticValueParams methFormals
methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe))
val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x))
val body = localTyper.typedPos(fun.pos) { import CODE._
def defaultAction(scrut: Tree) = REF(default) APPLY (REF(x))
object withDefaultTransformer extends gen.MatchMatcher {
override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = {
val casesNoSynthCatchAll = dropSyntheticCatchAll(cases)
if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) orig
else {
val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate))
wrap(Match(/*gen.mkUnchecked*/(selector), casesNoSynthCatchAll :+ defaultCase))
}
}
override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { import CODE._
((matcher APPLY (scrut)) DOT nme.getOrElse) APPLY (defaultAction(scrut.duplicate)) // TODO: pass targs
}
override def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = { import CODE._
val scrutRef = REF(prologue.head.symbol) // scrut valdef is always emitted (except for nested matchers that handle alternatives)
val casesNewSynthCatchAll = cases.init :+ (deriveLabelDef(cases.last){
case Apply(matchEnd, List(Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _)))) if exTpt.tpe.typeSymbol eq MatchErrorClass =>
assert(matchEnd.symbol == matchEndDef.symbol, "matchEnd discrepancy "+(matchEnd, matchEndDef))
matchEnd APPLY (defaultAction(scrutRef))
case x => x
} setSymbol cases.last.symbol setType null)
val LabelDef(_, List(matchRes), rhs) = matchEndDef
val matchEnd = matchEndDef.symbol
matchRes setType B1.tpe
rhs setType B1.tpe
matchEndDef setType B1.tpe
matchRes.symbol setInfo B1.tpe
matchEnd setInfo MethodType(List(matchRes.symbol), B1.tpe)
cases foreach (c => c.symbol setInfo MethodType(List(), B1.tpe))
wrap(Block(prologue ++ casesNewSynthCatchAll, matchEndDef))
}
}
localTyper.typedPos(fun.pos) {
Block(
List(ClassDef(anonClass, NoMods, List(List()), List(List()), List(applyMethodDef), fun.pos)),
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
}
withDefaultTransformer(substParam(fun.body))
}
body.changeOwner(fun.symbol -> methSym)
}
val methDef = DefDef(methSym, body)
def synthPartialFunction(fun: Function) = {
if (!settings.XoldPatmat.value) debugwarn("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.")
val targs = fun.tpe.typeArgs
val (formals, restpe) = (targs.init, targs.last)
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
val parents = List(appliedType(AbstractPartialFunctionClass, targs: _*), SerializableClass.tpe)
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
// duplicate before applyOrElseMethodDef is run so that it does not mess up our trees and label symbols (we have a fresh set)
// otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already
val bodyForIDA = {
val duped = fun.body.duplicate
val oldParams = new mutable.ListBuffer[Symbol]()
val newParams = new mutable.ListBuffer[Symbol]()
val oldSyms0 =
duped filter {
case l@LabelDef(_, params, _) =>
params foreach {p =>
val oldSym = p.symbol
p.symbol = oldSym.cloneSymbol
oldParams += oldSym
newParams += p.symbol
}
true
case _ => false
} map (_.symbol)
val oldSyms = oldParams.toList ++ oldSyms0
val newSyms = newParams.toList ++ (oldSyms0 map (_.cloneSymbol))
// println("duping "+ oldSyms +" --> "+ (newSyms map (_.ownerChain)))
// Have to repack the type to avoid mismatches when existentials
// appear in the result - see SI-4869.
methDef.tpt setType localTyper.packedType(body, methSym)
methDef
}
val substLabels = new TreeSymSubstituter(oldSyms, newSyms)
// duplicate before applyOrElseMethodDef is run so that it does not mess up our trees and label symbols (we have a fresh set)
// otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already
val bodyForIDA = {
val duped = fun.body.duplicate
val oldParams = new mutable.ListBuffer[Symbol]()
val newParams = new mutable.ListBuffer[Symbol]()
val oldSyms0 =
duped filter {
case l@LabelDef(_, params, _) =>
params foreach {p =>
val oldSym = p.symbol
p.symbol = oldSym.cloneSymbol
oldParams += oldSym
newParams += p.symbol
}
true
case _ => false
} map (_.symbol)
val oldSyms = oldParams.toList ++ oldSyms0
val newSyms = newParams.toList ++ (oldSyms0 map (_.cloneSymbol))
// println("duping "+ oldSyms +" --> "+ (newSyms map (_.ownerChain)))
substLabels(duped)
}
val substLabels = new TreeSymSubstituter(oldSyms, newSyms)
// def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
val applyOrElseMethodDef = {
val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE)
val List(argtpe) = formals
val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe)
val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe)
val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe))
val params@List(x, default) = methSym newSyntheticValueParams methFormals
methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe))
val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x))
val body = localTyper.typedPos(fun.pos) { import CODE._
def defaultAction(scrut: Tree) = REF(default) APPLY (REF(x))
substParam(fun.body) match {
case orig@Match(selector, cases) =>
if (cases exists treeInfo.isDefaultCase) orig
else {
val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate))
Match(/*gen.mkUnchecked*/(selector), cases :+ defaultCase)
}
substLabels(duped)
}
}
body.changeOwner(fun.symbol -> methSym)
def isDefinedAtMethodDef = {
val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL)
val params = methSym newSyntheticValueParams formals
methSym setInfoAndEnter MethodType(params, BooleanClass.tpe)
val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
def doSubst(x: Tree) = substParam(resetLocalAttrsKeepLabels(x)) // see pos/t1761 for why `resetLocalAttrs`, but must keep label symbols around
object isDefinedAtTransformer extends gen.MatchMatcher {
// TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly
override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { import CODE._
val casesNoSynthCatchAll = dropSyntheticCatchAll(cases)
if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) TRUE_typed
else
doSubst(wrap(
Match(/*gen.mkUnchecked*/(selector),
(casesNoSynthCatchAll map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ (
DEFAULT ==> FALSE_typed)
)))
}
override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = {
object noOne extends Transformer {
override val treeCopy = newStrictTreeCopier // must duplicate everything
val one = _match.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)
Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe)))
case _ =>
super.transform(tree)
}
}
doSubst(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher))))
}
val methDef = DefDef(methSym, body)
override def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree) = {
val matchEnd = matchEndDef.symbol
val LabelDef(_, List(matchRes), rhs) = matchEndDef
matchRes setType BooleanClass.tpe
rhs setType BooleanClass.tpe
matchEndDef setType BooleanClass.tpe
matchRes.symbol setInfo BooleanClass.tpe
matchEnd setInfo MethodType(List(matchRes.symbol), BooleanClass.tpe)
cases foreach (c => c.symbol setInfo MethodType(List(), BooleanClass.tpe))
// println("matchEnd: "+ matchEnd)
// when the type of the selector contains a skolem owned by the applyOrElseMethod, should reskolemize everything,
// for now, just cast the RHS (since we're just trying to keep the typer happy, the cast is meaningless)
// ARGH -- this is why I would prefer the typedMatchAnonFun approach (but alas, CPS blocks that)
val newPrologue = prologue match {
case List(vd@ValDef(mods, name, tpt, rhs)) => List(treeCopy.ValDef(vd, mods, name, tpt, gen.mkAsInstanceOf(rhs, tpt.tpe, true, false)))
case _ => prologue
}
object casesReturnTrue 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, return true instead
case Apply(fun, List(res)) if fun.symbol eq matchEnd =>
// println("matchend call "+ fun.symbol)
Apply(fun, List(TRUE_typed)) setType BooleanClass.tpe
case _ => super.transform(tree)
}
}
val newCatchAll = cases.last match {
case LabelDef(n, ps, Apply(matchEnd1, List(Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _))))) if exTpt.tpe.typeSymbol eq MatchErrorClass =>
assert(matchEnd1.symbol == matchEnd, "matchEnd discrepancy "+(matchEnd, matchEndDef))
List(treeCopy.LabelDef(cases.last, n, ps, matchEnd APPLY (FALSE_typed)) setSymbol cases.last.symbol)
case x => Nil
}
val casesWithoutCatchAll = if(newCatchAll.isEmpty) cases else cases.init
doSubst(wrap(Block(newPrologue ++ casesReturnTrue.transformTrees(casesWithoutCatchAll) ++ newCatchAll, matchEndDef)))
// val duped = idaBlock //.duplicate // TODO: duplication of labeldefs is BROKEN
// duped foreach {
// case l@LabelDef(name, params, rhs) if gen.hasSynthCaseSymbol(l) => println("newInfo"+ l.symbol.info)
// case _ =>
// }
}
}
// Have to repack the type to avoid mismatches when existentials
// appear in the result - see SI-4869.
methDef.tpt setType localTyper.packedType(body, methSym)
methDef
}
val body = isDefinedAtTransformer(bodyForIDA)
body.changeOwner(fun.symbol -> methSym)
val isDefinedAtMethodDef = {
val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL)
val params = methSym newSyntheticValueParams formals
methSym setInfoAndEnter MethodType(params, BooleanClass.tpe)
DefDef(methSym, body)
}
val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
def doSubst(x: Tree) = substParam(resetLocalAttrsKeepLabels(x)) // see pos/t1761 for why `resetLocalAttrs`, but must keep label symbols around
val members =
if (isPartial) {
assert(!opt.virtPatmat, "PartialFunction should have been synthesized during typer "+ fun);
List(applyOrElseMethodDef, isDefinedAtMethodDef)
} else List(applyMethodDef)
val body = bodyForIDA match {
case Match(selector, cases) =>
if (cases exists treeInfo.isDefaultCase) TRUE_typed
else
doSubst(Match(/*gen.mkUnchecked*/(selector),
(cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ (
DEFAULT ==> FALSE_typed)))
// println("MEMBERS "+ members)
val res = localTyper.typedPos(fun.pos) {
Block(
List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
}
// println("MEMBERS TYPED "+ members)
res
}
body.changeOwner(fun.symbol -> methSym)
DefDef(methSym, body)
}
localTyper.typedPos(fun.pos) {
Block(
List(ClassDef(anonClass, NoMods, List(List()), List(List()), List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)),
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
}
}
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {
val isJava = fun.isJavaDefined

0 comments on commit 5b9a375

Please sign in to comment.