Skip to content

Commit

Permalink
Refactors Uncurry's transform function to call a generalized
Browse files Browse the repository at this point in the history
"createMethod" in anticipation of the work to be put into Uncurry for
deferring delambdafication.
  • Loading branch information
James Iry committed Jul 23, 2013
1 parent e6125a4 commit 15ef90d
Showing 1 changed file with 56 additions and 23 deletions.
79 changes: 56 additions & 23 deletions src/compiler/scala/tools/nsc/transform/UnCurry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -233,41 +233,74 @@ abstract class UnCurry extends InfoTransform

deEta(fun) match {
// nullary or parameterless
case fun1 if fun1 ne fun => fun1
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 targs = fun.tpe.typeArgs
val (formals, restpe) = (targs.init, targs.last)

val applyMethodDef = {
val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL)
val paramSyms = map2(formals, fun.vparams) {
(tp, param) => methSym.newSyntheticValueParam(tp, param.name)

/**
* 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
*
* @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, List[ValDef]) => Tree) = {
val methSym = owner.newMethod(name, fun.pos, FINAL | additionalFlags)
val vparams = fun.vparams map (_.duplicate)

val paramSyms = map2(formals, vparams) {
(tp, vparam) => methSym.newSyntheticValueParam(tp, vparam.name)
}
methSym setInfoAndEnter MethodType(paramSyms, restpe)

fun.vparams foreach (_.symbol.owner = methSym)
fun.body changeOwner (fun.symbol -> methSym)

val body = localTyper.typedPos(fun.pos)(fun.body)
val methDef = DefDef(methSym, List(fun.vparams), body)
vparams zip paramSyms foreach {case (valdef, sym) => valdef.symbol = sym}
vparams foreach (_.symbol.owner = methSym)

val methodType = MethodType(paramSyms, restpe.deconst)

This comment has been minimized.

Copy link
@retronym

retronym Aug 29, 2013

Deconsting defensively, or to make something work (perhaps later in the commit sequence?) How could we get a X => 1.type? We shouldn't infer it. I suppose a macro could conjure one.

methSym setInfo methodType

val tempBody = bodyF(methSym, vparams)
val body = localTyper.typedPos(fun.pos)(tempBody)
val methDef = DefDef(methSym, List(vparams), 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.tpt setType localTyper.packedType(body, methSym).deconst
methDef

}

localTyper.typedPos(fun.pos) {
val funTyper = localTyper.typedPos(fun.pos) _

val block = {
val anonymousClassDef = {
val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe))
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
// apply method with same arguments and return type as orignal lambda.
val applyMethodDef = createMethod(anonClass, nme.apply, 0) {
case (methSym, vparams) =>
// stuff the lambda's body into the apply method
fun.body.substituteSymbols(fun.vparams map (_.symbol), vparams map (_.symbol))
fun.body changeOwner (fun.symbol -> methSym)
}
anonClass.info.decls enter applyMethodDef.symbol
ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)
}

Block(
List(ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)),
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
List(anonymousClassDef),
Typed(New(anonymousClassDef.symbol), TypeTree(fun.tpe))
)
}

}
funTyper(block)
}
}

def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {
Expand Down

0 comments on commit 15ef90d

Please sign in to comment.