diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-05-02 16:45:49 +0200 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-05-02 16:45:49 +0200 |
commit | 5b9a37529b0cd103cd25c11600b8ed8320a424fe (patch) | |
tree | ded799e4abbce8cde551f90ec60e26767d644ec3 | |
parent | e9ed9d4280246fece2268e69cca0fe316ba19b98 (diff) | |
download | scala-5b9a37529b0cd103cd25c11600b8ed8320a424fe.tar.gz scala-5b9a37529b0cd103cd25c11600b8ed8320a424fe.tar.bz2 scala-5b9a37529b0cd103cd25c11600b8ed8320a424fe.zip |
cleaned up partialfun synth in uncurry
removed dead code due to new-style matches getting their partialfun treatment during typers
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 288 |
1 files changed, 102 insertions, 186 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 35e26b39b5..ef70271371 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/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 |