From b5be392967d84591d45153408960d0e5b68d82e9 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 10 Nov 2013 15:00:06 +0100 Subject: Refactor away duplication between -Ydelambdafy:{inline,method} --- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 40 ++++++++++++ .../scala/tools/nsc/transform/UnCurry.scala | 71 +++------------------- 2 files changed, 47 insertions(+), 64 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index d4ac21a6b8..4ac6672727 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -256,4 +256,44 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { val stats1 = if (stats.isEmpty) List(Literal(Constant(()))) else stats mkNew(Nil, noSelfType, stats1, NoPosition, NoPosition) } + + /** + * Create a method based on a Function + * + * Used both to under `-Ydelambdafy:method` create a lifted function and + * under `-Ydelamdafy:inline` to create the apply method on the anonymous + * class. + * + * It creates a method definition with value params cloned from the + * original lambda. Then it calls a supplied function to create + * the body and types the result. Finally + * everything is wrapped up in a DefDef + * + * @param owner The owner for the new method + * @param name name for the new method + * @param additionalFlags flags to be put on the method in addition to FINAL + */ + def mkMethodFromFunction(localTyper: analyzer.Typer) + (fun: Function, owner: Symbol, name: TermName, additionalFlags: FlagSet = NoFlags) = { + val funParams = fun.vparams map (_.symbol) + val formals :+ restpe = fun.tpe.typeArgs + + val methSym = owner.newMethod(name, fun.pos, FINAL | additionalFlags) + + val paramSyms = map2(formals, fun.vparams) { + (tp, vparam) => methSym.newSyntheticValueParam(tp, vparam.name) + } + + methSym setInfo MethodType(paramSyms, restpe.deconst) + + fun.body.substituteSymbols(funParams, paramSyms) + fun.body changeOwner (fun.symbol -> methSym) + + val methDef = DefDef(methSym, fun.body) + + // Have to repack the type to avoid mismatches when existentials + // appear in the result - see SI-4869. + methDef.tpt setType localTyper.packedType(fun.body, methSym).deconst + methDef + } } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index a851585442..844774e75f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -217,84 +217,27 @@ abstract class UnCurry extends InfoTransform // nullary or parameterless case fun1 if fun1 ne fun => fun1 case _ => - val formals :+ restpe = fun.tpe.typeArgs - def typedFunPos(t: Tree) = localTyper.typedPos(fun.pos)(t) + val funParams = fun.vparams map (_.symbol) + def mkMethod(owner: Symbol, name: TermName, additionalFlags: FlagSet = NoFlags): DefDef = + gen.mkMethodFromFunction(localTyper)(fun, owner, name, additionalFlags) if (inlineFunctionExpansion) { val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe)) val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation anonClass setInfo ClassInfoType(parents, newScope, anonClass) - val applyMethodDef = { - val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL) - val paramSyms = map2(formals, fun.vparams) { - (tp, param) => methSym.newSyntheticValueParam(tp, param.name) - } - methSym setInfoAndEnter MethodType(paramSyms, restpe) - - fun.body changeOwner (fun.symbol -> methSym) - fun.body substituteSymbols (fun.vparams.map(_.symbol), paramSyms) - val body = typedFunPos(fun.body) - val methDef = DefDef(methSym, body) - - // 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 applyMethodDef = mkMethod(anonClass, nme.apply) + anonClass.info.decls enter applyMethodDef.symbol typedFunPos { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)), + ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } } else { - /** - * Abstracts away the common functionality required to create both - * the lifted function and the apply method on the anonymous class - * It creates a method definition with value params cloned from the - * original lambda. Then it calls a supplied function to create - * the body and types the result. Finally - * everything is wrapped up in a MethodDef - * - * TODO it is intended that this common functionality be used - * whether inlineFunctionExpansion is true or not. However, it - * seems to introduce subtle ownwership changes that produce - * binary incompatible changes and so it is completely - * hidden behind the inlineFunctionExpansion for now. - * - * @param owner The owner for the new method - * @param name name for the new method - * @param additionalFlags flags to be put on the method in addition to FINAL - * @bodyF function that turns the method symbol and list of value params - * into a body for the method - */ - def createMethod(owner: Symbol, name: TermName, additionalFlags: Long)(bodyF: Symbol => Tree) = { - val methSym = owner.newMethod(name, fun.pos, FINAL | additionalFlags) - - val paramSyms = map2(formals, fun.vparams) { - (tp, vparam) => methSym.newSyntheticValueParam(tp, vparam.name) - } - - methSym setInfo MethodType(paramSyms, restpe.deconst) - - val body = typedFunPos(bodyF(methSym)) - val methDef = DefDef(methSym, body) - - // Have to repack the type to avoid mismatches when existentials - // appear in the result - see SI-4869. - methDef.tpt setType localTyper.packedType(body, methSym).deconst - methDef - } - - val funParams = fun.vparams map (_.symbol) // method definition with the same arguments, return type, and body as the original lambda - val liftedMethod = createMethod(fun.symbol.owner, nme.ANON_FUN_NAME, additionalFlags = ARTIFACT) { - methSym => - fun.body.substituteSymbols(funParams, methSym.paramss.head) - fun.body changeOwner (fun.symbol -> methSym) - } + val liftedMethod = mkMethod(fun.symbol.owner, nme.ANON_FUN_NAME, additionalFlags = ARTIFACT) // new function whose body is just a call to the lifted method val newFun = deriveFunction(fun)(_ => typedFunPos( -- cgit v1.2.3