Skip to content

Commit

Permalink
Uncurry: avoid intermediate lists, remove ParamTransform ADT:
Browse files Browse the repository at this point in the history
The erase method in the Uncurry file was creating several lists:

- The input lists of lists `vparamss` and `dd.symbol.info.paramss`
  were flattened, into a List that was only used in a single
  loop run, with the `map2` function, to create...
- ... `paramTransforms`, a list of objects of the "ParamTransform"
  ADT, which has the subclasses "Identity" and "Packed".
- The `allParams` was mapped from the previous one, by getting only
  the `param`. This is returned in first element of response tuple.
- A list of pairs that is obtained by a `collect`
- The lists `packedParams` and `tempVals`, that are obtained by
  unzipping the collected list above.
- The `packedParams` was only use to map it into the list of symbols,
  which is used for a symbol substitution.

We rewrite this code to avoid generating so many lists:
- We replace the list flattening with flattened iterators.
- We use mutable ListBuffers, and use a single pass over those
  iterators, so in each iteration we add an element to three lists.
- We generate three lists: the `allParams`, the symbols of the
  `packedParams`  (without the packed params), and the tempVals.
  We cannot remove the map of tempVals to symbols, because tempVals
  can be needed for the output. However...
- If we detect that the tree is the Empty tree, we avoid inserting
  the `packedParams` symbols, or the tempVals.
- We remove the `ParamTransform` ADT.

Also, since the  `Identity` and `Packed` classes were just a carrier
of its fields from one part of the `erase` method to another part of
it, we can remove them and directly add the info in their fields to
the lists were we need to.
  • Loading branch information
diesalbla committed Mar 22, 2019
1 parent 6990ee3 commit c496e6a
Showing 1 changed file with 26 additions and 14 deletions.
40 changes: 26 additions & 14 deletions src/compiler/scala/tools/nsc/transform/UnCurry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import scala.annotation.tailrec

import symtab.Flags._
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.reflect.internal.util.ListOfNil

/*<export> */
Expand Down Expand Up @@ -670,11 +671,6 @@ abstract class UnCurry extends InfoTransform
* }}}
*/
private object dependentParamTypeErasure {
sealed abstract class ParamTransform {
def param: ValDef
}
final case class Identity(param: ValDef) extends ParamTransform
final case class Packed(param: ValDef, tempVal: ValDef) extends ParamTransform

def isDependent(dd: DefDef): Boolean =
enteringUncurry {
Expand All @@ -687,10 +683,23 @@ abstract class UnCurry extends InfoTransform
*/
def erase(dd: DefDef): (List[List[ValDef]], Tree) = {
import dd.{ vparamss, rhs }
val paramTransforms: List[ParamTransform] =
map2(vparamss.flatten, dd.symbol.info.paramss.flatten) { (p, infoParam) =>
val (allParams, packedParamsSyms, tempVals): (List[ValDef], List[Symbol], List[ValDef]) = {

val allParamsBuf: ListBuffer[ValDef] = ListBuffer.empty
val packedParamsSymsBuf: ListBuffer[Symbol] = ListBuffer.empty
val tempValsBuf: ListBuffer[ValDef] = ListBuffer.empty

def addPacked(param: ValDef, tempVal: ValDef): Unit = {
allParamsBuf += param
if (rhs != EmptyTree) {
packedParamsSymsBuf += param.symbol
tempValsBuf += tempVal
}
}

def addParamTransform(p: ValDef, infoParam: Symbol): Unit = {
val packedType = infoParam.info
if (packedType =:= p.symbol.info) Identity(p)
if (packedType =:= p.symbol.info) allParamsBuf += p
else {
// The Uncurry info transformer existentially abstracted over value parameters
// from the previous parameter lists.
Expand Down Expand Up @@ -746,19 +755,22 @@ abstract class UnCurry extends InfoTransform
val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(info)
atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), info)))
}
Packed(newParam, tempVal)
addPacked(newParam, tempVal)
}
}

val allParams = paramTransforms map (_.param)
val (packedParams, tempVals) = paramTransforms.collect {
case Packed(param, tempVal) => (param, tempVal)
}.unzip
val viter = vparamss.iterator.flatten
val piter = dd.symbol.info.paramss.iterator.flatten
while (viter.hasNext && piter.hasNext)
addParamTransform(viter.next, piter.next)

(allParamsBuf.toList, packedParamsSymsBuf.toList, tempValsBuf.toList)
}

val rhs1 = if (rhs == EmptyTree || tempVals.isEmpty) rhs else {
localTyper.typedPos(rhs.pos) {
// Patch the method body to refer to the temp vals
val rhsSubstituted = rhs.substituteSymbols(packedParams map (_.symbol), tempVals map (_.symbol))
val rhsSubstituted = rhs.substituteSymbols(packedParamsSyms, tempVals.map(_.symbol))
// The new method body: { val p$1 = p.asInstanceOf[<dependent type>]; ...; <rhsSubstituted> }
Block(tempVals, rhsSubstituted)
}
Expand Down

0 comments on commit c496e6a

Please sign in to comment.