@@ -13,13 +13,14 @@ import scala.collection.mutable.ListBuffer
13
13
14
14
/** Rewrite an application
15
15
*
16
- * (((x1, ..., xn) => b): T)(y1, ..., yn)
16
+ * (([X1, ..., Xm] => (x1, ..., xn) => b): T)[T1, ..., Tm] (y1, ..., yn)
17
17
*
18
18
* where
19
19
*
20
20
* - all yi are pure references without a prefix
21
21
* - the closure can also be contextual or erased, but cannot be a SAM type
22
- * _ the type ascription ...: T is optional
22
+ * - the type parameters Xi and type arguments Ti are optional
23
+ * - the type ascription ...: T is optional
23
24
*
24
25
* to
25
26
*
@@ -38,51 +39,88 @@ class BetaReduce extends MiniPhase:
38
39
39
40
override def description : String = BetaReduce .description
40
41
41
- override def transformApply (app : Apply )(using Context ): Tree = app.fun match
42
- case Select (fn, nme.apply) if defn.isFunctionType(fn.tpe) =>
43
- val app1 = BetaReduce (app, fn, app.args)
44
- if app1 ne app then report.log(i " beta reduce $app -> $app1" )
45
- app1
46
- case _ =>
47
- app
48
-
42
+ override def transformApply (app : Apply )(using Context ): Tree =
43
+ val app1 = BetaReduce (app)
44
+ if app1 ne app then report.log(i " beta reduce $app -> $app1" )
45
+ app1
49
46
50
47
object BetaReduce :
51
48
import ast .tpd ._
52
49
53
50
val name : String = " betaReduce"
54
51
val description : String = " reduce closure applications"
55
52
56
- /** Beta-reduces a call to `fn` with arguments `argSyms` or returns `tree` */
57
- def apply (original : Tree , fn : Tree , args : List [Tree ])(using Context ): Tree =
58
- fn match
59
- case Typed (expr, _) =>
60
- BetaReduce (original, expr, args)
61
- case Block ((anonFun : DefDef ) :: Nil , closure : Closure ) =>
62
- BetaReduce (anonFun, args)
63
- case Block (stats, expr) =>
64
- val tree = BetaReduce (original, expr, args)
65
- if tree eq original then original
66
- else cpy.Block (fn)(stats, tree)
67
- case Inlined (call, bindings, expr) =>
68
- val tree = BetaReduce (original, expr, args)
69
- if tree eq original then original
70
- else cpy.Inlined (fn)(call, bindings, tree)
53
+ /** Rewrite an application
54
+ *
55
+ * ((x1, ..., xn) => b)(e1, ..., en)
56
+ *
57
+ * to
58
+ *
59
+ * val/def x1 = e1; ...; val/def xn = en; b
60
+ *
61
+ * where `def` is used for call-by-name parameters. However, we shortcut any NoPrefix
62
+ * refs among the ei's directly without creating an intermediate binding.
63
+ *
64
+ * Similarly, rewrites type applications
65
+ *
66
+ * ([X1, ..., Xm] => (x1, ..., xn) => b).apply[T1, .., Tm](e1, ..., en)
67
+ *
68
+ * to
69
+ *
70
+ * type X1 = T1; ...; type Xm = Tm;val/def x1 = e1; ...; val/def xn = en; b
71
+ *
72
+ * This beta-reduction preserves the integrity of `Inlined` tree nodes.
73
+ */
74
+ def apply (tree : Tree )(using Context ): Tree =
75
+ val bindingsBuf = new ListBuffer [DefTree ]
76
+ def recur (fn : Tree , argss : List [List [Tree ]]): Option [Tree ] = fn match
77
+ case Block ((ddef : DefDef ) :: Nil , closure : Closure ) if ddef.symbol == closure.meth.symbol =>
78
+ Some (reduceApplication(ddef, argss, bindingsBuf))
79
+ case Block ((TypeDef (_, template : Template )) :: Nil , Typed (Apply (Select (New (_), _), _), _)) if template.constr.rhs.isEmpty =>
80
+ template.body match
81
+ case (ddef : DefDef ) :: Nil => Some (reduceApplication(ddef, argss, bindingsBuf))
82
+ case _ => None
83
+ case Block (stats, expr) if stats.forall(isPureBinding) =>
84
+ recur(expr, argss).map(cpy.Block (fn)(stats, _))
85
+ case Inlined (call, bindings, expr) if bindings.forall(isPureBinding) =>
86
+ recur(expr, argss).map(cpy.Inlined (fn)(call, bindings, _))
87
+ case Typed (expr, tpt) =>
88
+ recur(expr, argss)
89
+ case TypeApply (Select (expr, nme.asInstanceOfPM), List (tpt)) =>
90
+ recur(expr, argss)
91
+ case _ => None
92
+ tree match
93
+ case Apply (Select (fn, nme.apply), args) if defn.isFunctionType(fn.tpe) =>
94
+ recur(fn, List (args)) match
95
+ case Some (reduced) =>
96
+ seq(bindingsBuf.result(), reduced).withSpan(tree.span)
97
+ case None =>
98
+ tree
99
+ case Apply (TypeApply (Select (fn, nme.apply), targs), args) if fn.tpe.typeSymbol eq dotc.core.Symbols .defn.PolyFunctionClass =>
100
+ recur(fn, List (targs, args)) match
101
+ case Some (reduced) =>
102
+ seq(bindingsBuf.result(), reduced).withSpan(tree.span)
103
+ case None =>
104
+ tree
71
105
case _ =>
72
- original
73
- end apply
74
-
75
- /** Beta-reduces a call to `ddef` with arguments `args` */
76
- def apply (ddef : DefDef , args : List [Tree ])(using Context ) =
77
- val bindings = new ListBuffer [ValDef ]()
78
- val expansion1 = reduceApplication(ddef, args, bindings)
79
- val bindings1 = bindings.result()
80
- seq(bindings1, expansion1)
106
+ tree
81
107
82
108
/** Beta-reduces a call to `ddef` with arguments `args` and registers new bindings */
83
- def reduceApplication (ddef : DefDef , args : List [Tree ], bindings : ListBuffer [ValDef ])(using Context ): Tree =
84
- val vparams = ddef.termParamss.iterator.flatten.toList
85
- assert(args.hasSameLengthAs(vparams))
109
+ def reduceApplication (ddef : DefDef , argss : List [List [Tree ]], bindings : ListBuffer [DefTree ])(using Context ): Tree =
110
+ val (targs, args) = argss.flatten.partition(_.isType)
111
+ val tparams = ddef.leadingTypeParams
112
+ val vparams = ddef.termParamss.flatten
113
+
114
+ val targSyms =
115
+ for (targ, tparam) <- targs.zip(tparams) yield
116
+ targ.tpe.dealias match
117
+ case ref @ TypeRef (NoPrefix , _) =>
118
+ ref.symbol
119
+ case _ =>
120
+ val binding = TypeDef (newSymbol(ctx.owner, tparam.name, EmptyFlags , targ.tpe, coord = targ.span)).withSpan(targ.span)
121
+ bindings += binding
122
+ binding.symbol
123
+
86
124
val argSyms =
87
125
for (arg, param) <- args.zip(vparams) yield
88
126
arg.tpe.dealias match
@@ -99,8 +137,8 @@ object BetaReduce:
99
137
val expansion = TreeTypeMap (
100
138
oldOwners = ddef.symbol :: Nil ,
101
139
newOwners = ctx.owner :: Nil ,
102
- substFrom = vparams.map(_.symbol),
103
- substTo = argSyms
140
+ substFrom = (tparams ::: vparams) .map(_.symbol),
141
+ substTo = targSyms ::: argSyms
104
142
).transform(ddef.rhs)
105
143
106
144
val expansion1 = new TreeMap {
0 commit comments