From d7d63e93f35c692b26e95db1b02d758723dde18d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 10 Nov 2013 13:40:26 +0100 Subject: Tidy up the Uncurry component of delambdafy - Use tree factories that accept symbols and encapsulate ValDef creation - Use `gen.mkForwarder` to handle the conditional addition of `: _*` for varargs functions. We don't need to predicate this on `etaExpandKeepsStar`; the only place that need to do that is EtaExpansion. --- .../scala/tools/nsc/transform/UnCurry.scala | 62 +++++++--------------- src/reflect/scala/reflect/internal/Trees.scala | 6 +++ 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 3d648ccbac..d1d4759ea5 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -217,14 +217,14 @@ abstract class UnCurry extends InfoTransform // nullary or parameterless case fun1 if fun1 ne fun => fun1 case _ => - val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe)) - val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation - anonClass setInfo ClassInfoType(parents, newScope, anonClass) + val formals :+ restpe = fun.tpe.typeArgs - val targs = fun.tpe.typeArgs - val (formals, restpe) = (targs.init, targs.last) + def typedFunPos(t: Tree) = localTyper.typedPos(fun.pos)(t) 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) { @@ -235,7 +235,7 @@ abstract class UnCurry extends InfoTransform fun.vparams foreach (_.symbol.owner = methSym) fun.body changeOwner (fun.symbol -> methSym) - val body = localTyper.typedPos(fun.pos)(fun.body) + val body = typedFunPos(fun.body) val methDef = DefDef(methSym, List(fun.vparams), body) // Have to repack the type to avoid mismatches when existentials @@ -244,7 +244,7 @@ abstract class UnCurry extends InfoTransform methDef } - localTyper.typedPos(fun.pos) { + typedFunPos { Block( List(ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) @@ -270,23 +270,17 @@ abstract class UnCurry extends InfoTransform * @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, List[ValDef]) => Tree) = { + def createMethod(owner: Symbol, name: TermName, additionalFlags: Long)(bodyF: Symbol => Tree) = { val methSym = owner.newMethod(name, fun.pos, FINAL | additionalFlags) - val vparams = fun.vparams map (_.duplicate) - val paramSyms = map2(formals, vparams) { + val paramSyms = map2(formals, fun.vparams) { (tp, vparam) => methSym.newSyntheticValueParam(tp, vparam.name) } - foreach2(vparams, paramSyms){(valdef, sym) => valdef.symbol = sym} - vparams foreach (_.symbol.owner = methSym) - val methodType = MethodType(paramSyms, restpe.deconst) - methSym setInfo methodType + methSym setInfo MethodType(paramSyms, restpe.deconst) - // TODO this is probably cleaner if bodyF only works with symbols rather than parameter ValDefs - val tempBody = bodyF(methSym, vparams) - val body = localTyper.typedPos(fun.pos)(tempBody) - val methDef = DefDef(methSym, List(vparams), body) + 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. @@ -294,35 +288,19 @@ abstract class UnCurry extends InfoTransform methDef } - val methodFlags = ARTIFACT + 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, tpnme.ANON_FUN_NAME.toTermName, methodFlags){ - case(methSym, vparams) => - fun.body.substituteSymbols(fun.vparams map (_.symbol), vparams map (_.symbol)) + 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) } - // callsite for the lifted method - val args = fun.vparams map { vparam => - val ident = Ident(vparam.symbol) - // if -Yeta-expand-keeps-star is turned on then T* types can get through. In order - // to forward them we need to forward x: T* ascribed as "x:_*" - if (settings.etaExpandKeepsStar && definitions.isRepeatedParamType(vparam.tpt.tpe)) - gen.wildcardStar(ident) - else - ident - } - - val funTyper = localTyper.typedPos(fun.pos) _ - - val liftedMethodCall = funTyper(Apply(liftedMethod.symbol, args:_*)) - // new function whose body is just a call to the lifted method - val newFun = treeCopy.Function(fun, fun.vparams, liftedMethodCall) - funTyper(Block( - List(funTyper(liftedMethod)), - super.transform(newFun) - )) + val newFun = deriveFunction(fun)(_ => typedFunPos( + gen.mkForwarder(gen.mkAttributedRef(liftedMethod.symbol), funParams :: Nil) + )) + typedFunPos(Block(liftedMethod, super.transform(newFun))) } } } diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index af0af8afe8..b0abc0be7b 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1804,6 +1804,12 @@ trait Trees extends api.Trees { case t => sys.error("Not a LabelDef: " + t + "/" + t.getClass) } + def deriveFunction(func: Tree)(applyToRhs: Tree => Tree): Function = func match { + case Function(params0, rhs0) => + treeCopy.Function(func, params0, applyToRhs(rhs0)) + case t => + sys.error("Not a Function: " + t + "/" + t.getClass) + } // -------------- Classtags -------------------------------------------------------- -- cgit v1.2.3