1
+ package dotty .tools
2
+ package dotc
3
+ package transform
4
+
5
+ import MegaPhase .MiniPhase
6
+ import core .*
7
+ import Symbols .* , Contexts .* , Types .* , Decorators .*
8
+ import StdNames .nme
9
+ import ast .Trees .*
10
+
11
+ /** Rewrite `(x1, ... xN) => f(x1, ... xN)` for N >= 0 to `f`,
12
+ * provided `f` is a pure path of function type.
13
+ *
14
+ * This optimization is crucial for context functions. The compiler
15
+ * produces a contextual closure around values passed as arguments
16
+ * where a context function is expected, unless that value has the
17
+ * syntactic form of a context function literal.
18
+ *
19
+ * Without this phase, when a contextual function is passed as an argument to a
20
+ * recursive function, that would have the unfortunate effect of a linear growth
21
+ * in transient thunks of identical type wrapped around each other, leading
22
+ * to performance degradation, and in some cases, stack overflows.
23
+ */
24
+ class EtaReduce extends MiniPhase :
25
+ import ast .tpd ._
26
+
27
+ override def phaseName : String = " etaReduce"
28
+
29
+ override def transformBlock (tree : Block )(using Context ): Tree = tree match
30
+ case Block ((meth : DefDef ) :: Nil , closure : Closure )
31
+ if meth.symbol == closure.meth.symbol =>
32
+ meth.rhs match
33
+ case Apply (Select (fn, nme.apply), args)
34
+ if meth.paramss.head.corresponds(args)((param, arg) =>
35
+ arg.isInstanceOf [Ident ] && arg.symbol == param.symbol)
36
+ && isPurePath(fn)
37
+ && fn.tpe <:< tree.tpe
38
+ && defn.isFunctionClass(fn.tpe.widen.typeSymbol) =>
39
+ report.log(i " eta reducing $tree --> $fn" )
40
+ fn
41
+ case _ => tree
42
+ case _ => tree
43
+
44
+ end EtaReduce
0 commit comments