Skip to content

Commit 3cc3121

Browse files
oderskyDarkDimius
authored andcommitted
Add time travelling copies
Make Apply and TypeApply copy only if function or argument types have changed.
1 parent f564340 commit 3cc3121

File tree

5 files changed

+47
-25
lines changed

5 files changed

+47
-25
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
454454
override val cpy: TypedTreeCopier = // Type ascription needed to pick up any new members in TreeCopier (currently there are none)
455455
new TypedTreeCopier
456456

457+
val cpyBetweenPhases = new TimeTravellingTreeCopier
458+
457459
class TypedTreeCopier extends TreeCopier {
458460
def postProcess(tree: Tree, copied: untpd.Tree): copied.ThisTree[Type] =
459461
copied.withTypeUnchecked(tree.tpe)
@@ -473,26 +475,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
473475
}
474476

475477
override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = {
476-
val untyped = untpd.cpy.Apply(tree)(fun, args)
477-
if (untyped.ne(tree) || !ctx.settings.optimise.value)
478-
ta.assignType(untyped, fun, args)
479-
else
480-
tree.asInstanceOf[Apply]
478+
val tree1 = untpd.cpy.Apply(tree)(fun, args)
479+
tree match {
480+
case tree: Apply
481+
if (fun.tpe eq tree.fun.tpe) && (args corresponds tree.args)(_ eq _) =>
482+
tree1.withTypeUnchecked(tree.tpe)
483+
case _ => ta.assignType(tree1, fun, args)
484+
}
481485
}
482486

483-
// Note: Reassigning the original type if `fun` and `args` have the same types as before
484-
// does not work here: The computed type depends on the widened function type, not
485-
// the function type itself. A treetransform may keep the function type the
486-
// same but its widened type might change.
487-
488487
override def TypeApply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = {
489-
val untyped = untpd.cpy.TypeApply(tree)(fun, args)
490-
if (untyped.ne(tree) || !ctx.settings.optimise.value)
491-
ta.assignType(untyped, fun, args)
492-
else
493-
tree.asInstanceOf[TypeApply]
488+
val tree1 = untpd.cpy.TypeApply(tree)(fun, args)
489+
tree match {
490+
case tree: TypeApply
491+
if (fun.tpe eq tree.fun.tpe) && (args corresponds tree.args)(_ eq _) =>
492+
tree1.withTypeUnchecked(tree.tpe)
493+
case _ => ta.assignType(tree1, fun, args)
494+
}
494495
}
495-
// Same remark as for Apply
496496

497497
override def Literal(tree: Tree)(const: Constant)(implicit ctx: Context): Literal =
498498
ta.assignType(untpd.cpy.Literal(tree)(const))
@@ -525,14 +525,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
525525
}
526526
}
527527

528-
override def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = {
529-
val untyped = untpd.cpy.Closure(tree)(env, meth, tpt)
530-
val typed = ta.assignType(untyped, meth, tpt)
531-
if (untyped.ne(tree) || !ctx.settings.optimise.value)
532-
typed
533-
else
534-
tree.asInstanceOf[Closure]
535-
}
528+
override def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure =
529+
ta.assignType(untpd.cpy.Closure(tree)(env, meth, tpt), meth, tpt)
536530
// Same remark as for Apply
537531

538532
override def Match(tree: Tree)(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = {
@@ -591,6 +585,19 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
591585
Try(tree: Tree)(expr, cases, finalizer)
592586
}
593587

588+
class TimeTravellingTreeCopier extends TypedTreeCopier {
589+
override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply =
590+
ta.assignType(untpd.cpy.Apply(tree)(fun, args), fun, args)
591+
// Note: Reassigning the original type if `fun` and `args` have the same types as before
592+
// does not work here: The computed type depends on the widened function type, not
593+
// the function type itself. A treetransform may keep the function type the
594+
// same but its widened type might change.
595+
596+
override def TypeApply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply =
597+
ta.assignType(untpd.cpy.TypeApply(tree)(fun, args), fun, args)
598+
// Same remark as for Apply
599+
}
600+
594601
override def skipTransform(tree: Tree)(implicit ctx: Context) = tree.tpe.isError
595602

596603
implicit class TreeOps[ThisTree <: tpd.Tree](val tree: ThisTree) extends AnyVal {
@@ -967,3 +974,4 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
967974
if (file != null && file.exists) new SourceFile(file, Codec(encoding)) else NoSource
968975
}
969976
}
977+

compiler/src/dotty/tools/dotc/transform/MacroTransform.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ abstract class MacroTransform extends Phase {
3030
*/
3131
protected def transformPhase(implicit ctx: Context): Phase = this
3232

33-
class Transformer extends TreeMap {
33+
class Transformer extends TreeMap(cpy = cpyBetweenPhases) {
3434

3535
protected def localCtx(tree: Tree)(implicit ctx: Context) = {
3636
val sym = tree.symbol

compiler/src/dotty/tools/dotc/transform/TreeTransform.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ object TreeTransforms {
6262

6363
def treeTransformPhase: Phase = phase.next
6464

65+
val cpy = cpyBetweenPhases
66+
6567
def prepareForIdent(tree: Ident)(implicit ctx: Context) = this
6668
def prepareForSelect(tree: Select)(implicit ctx: Context) = this
6769
def prepareForThis(tree: This)(implicit ctx: Context) = this

tests/pickling/A.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import dotty.tools.dotc.core.Decorators._
2+
import dotty.tools.dotc.core.NameOps._
3+
4+
object Test {
5+
"JFunction".toTermName.specializedFor(Nil, ???, Nil, Nil)(???)
6+
}

tests/pickling/B.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import dotty.tools.dotc.core.Contexts.Context
2+
3+
object Formatting {
4+
def rainbows(implicit ctx: Context): String =
5+
ctx.settings.color.value.toString
6+
}

0 commit comments

Comments
 (0)