@@ -6,6 +6,8 @@ import MegaPhase.MiniPhase
6
6
import core .*
7
7
import Symbols .* , Contexts .* , Types .* , Decorators .*
8
8
import StdNames .nme
9
+ import SymUtils .*
10
+ import NameKinds .AdaptedClosureName
9
11
10
12
/** Rewrite `(x1, ... xN) => f(x1, ... xN)` for N >= 0 to `f`,
11
13
* provided `f` is a pure path of function type.
@@ -15,6 +17,11 @@ import StdNames.nme
15
17
* where a context function is expected, unless that value has the
16
18
* syntactic form of a context function literal.
17
19
*
20
+ * Also handle variants of eta-expansions where
21
+ * - result f.apply(X_1,...,X_n) is subject to a synthetic cast, or
22
+ * - the application uses a specialized apply method, or
23
+ * - the closure is adapted (see Erasure#adaptClosure)
24
+ *
18
25
* Without this phase, when a contextual function is passed as an argument to a
19
26
* recursive function, that would have the unfortunate effect of a linear growth
20
27
* in transient thunks of identical type wrapped around each other, leading
@@ -27,20 +34,36 @@ class EtaReduce extends MiniPhase:
27
34
28
35
override def description : String = EtaReduce .description
29
36
30
- override def transformBlock (tree : Block )(using Context ): Tree = tree match
31
- case Block (( meth : DefDef ) :: Nil , closure : Closure )
32
- if meth.symbol == closure.meth.symbol =>
33
- meth.rhs match
34
- case Apply ( Select (fn, nme.apply), args )
35
- if meth .paramss.head.corresponds(args)((param, arg) =>
37
+ override def transformBlock (tree : Block )(using Context ): Tree =
38
+
39
+ def tryReduce ( mdef : DefDef , rhs : Tree ) : Tree = rhs match
40
+ case Apply ( Select (fn, name), args)
41
+ if (name == nme.apply || defn. FunctionSpecializedApplyNames .contains(name) )
42
+ && mdef .paramss.head.corresponds(args)((param, arg) =>
36
43
arg.isInstanceOf [Ident ] && arg.symbol == param.symbol)
37
- && isPurePath(fn)
38
- && fn.tpe <:< tree.tpe
39
- && defn.isFunctionClass(fn.tpe.widen.typeSymbol) =>
40
- report.log(i " eta reducing $tree --> $fn" )
41
- fn
42
- case _ => tree
43
- case _ => tree
44
+ && isPurePath(fn)
45
+ && fn.tpe <:< tree.tpe
46
+ && defn.isFunctionClass(fn.tpe.widen.typeSymbol) =>
47
+ report.log(i " eta reducing $tree --> $fn" )
48
+ fn
49
+ case TypeApply (Select (qual, _), _) if rhs.symbol.isTypeCast && rhs.span.isSynthetic =>
50
+ tryReduce(mdef, qual)
51
+ case _ =>
52
+ tree
53
+
54
+ tree match
55
+ case Block ((meth : DefDef ) :: Nil , expr) if meth.symbol.isAnonymousFunction =>
56
+ expr match
57
+ case closure : Closure if meth.symbol == closure.meth.symbol =>
58
+ tryReduce(meth, meth.rhs)
59
+ case Block ((adapted : DefDef ) :: Nil , closure : Closure )
60
+ if adapted.name.is(AdaptedClosureName ) && adapted.symbol == closure.meth.symbol =>
61
+ tryReduce(meth, meth.rhs)
62
+ case _ =>
63
+ tree
64
+ case _ =>
65
+ tree
66
+ end transformBlock
44
67
45
68
end EtaReduce
46
69
0 commit comments