Skip to content
Browse files

Refactor away duplication between -Ydelambdafy:{inline,method}

  • Loading branch information...
1 parent 736613e commit b5be392967d84591d45153408960d0e5b68d82e9 @retronym retronym committed Nov 10, 2013
View
40 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
+ }
}
View
71 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(

0 comments on commit b5be392

Please sign in to comment.
Something went wrong with that request. Please try again.