@@ -13,23 +13,43 @@ import Decorators._
13
13
import Names ._
14
14
import StdNames ._
15
15
import NameKinds .UniqueName
16
- import Trees ._
17
16
import Inferencing ._
18
17
import util .Positions ._
19
18
import collection .mutable
19
+ import Trees ._
20
20
21
- object EtaExpansion {
22
-
21
+ /** A class that handles argument lifting. Argument lifting is needed in the following
22
+ * scenarios:
23
+ * - eta expansion
24
+ * - applications with default arguments
25
+ * - applications with out-of-order named arguments
26
+ * Lifting generally lifts impure expressions only, except in the case of possible
27
+ * default arguments, where we lift also complex pure expressions, since in that case
28
+ * arguments can be duplicated as arguments to default argument methods.
29
+ */
30
+ abstract class Lifter {
23
31
import tpd ._
24
32
33
+ /** Test indicating `expr` does not need lifting */
34
+ def noLift (expr : Tree )(implicit ctx : Context ): Boolean
35
+
36
+ /** The corresponding lifter for paam-by-name arguments */
37
+ protected def exprLifter : Lifter = NoLift
38
+
39
+ /** The flags of a lifted definition */
40
+ protected def liftedFlags : FlagSet = EmptyFlags
41
+
42
+ /** The tree of a lifted definition */
43
+ protected def liftedDef (sym : TermSymbol , rhs : Tree )(implicit ctx : Context ): MemberDef = ValDef (sym, rhs)
44
+
25
45
private def lift (defs : mutable.ListBuffer [Tree ], expr : Tree , prefix : TermName = EmptyTermName )(implicit ctx : Context ): Tree =
26
- if (isPureExpr (expr)) expr
46
+ if (noLift (expr)) expr
27
47
else {
28
48
val name = UniqueName .fresh(prefix)
29
49
val liftedType = fullyDefinedType(expr.tpe.widen, " lifted expression" , expr.pos)
30
- val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags , liftedType, coord = positionCoord(expr.pos))
31
- defs += ValDef (sym , expr).withPos(expr.pos.focus)
32
- ref(sym .termRef).withPos(expr.pos)
50
+ val lifted = ctx.newSymbol(ctx.owner, name, liftedFlags , liftedType, coord = positionCoord(expr.pos))
51
+ defs += liftedDef(lifted , expr).withPos(expr.pos.focus)
52
+ ref(lifted .termRef).withPos(expr.pos)
33
53
}
34
54
35
55
/** Lift out common part of lhs tree taking part in an operator assignment such as
@@ -49,7 +69,7 @@ object EtaExpansion {
49
69
}
50
70
51
71
/** Lift a function argument, stripping any NamedArg wrapper */
52
- def liftArg (defs : mutable.ListBuffer [Tree ], arg : Tree , prefix : TermName = EmptyTermName )(implicit ctx : Context ): Tree =
72
+ private def liftArg (defs : mutable.ListBuffer [Tree ], arg : Tree , prefix : TermName = EmptyTermName )(implicit ctx : Context ): Tree =
53
73
arg match {
54
74
case arg @ NamedArg (name, arg1) => cpy.NamedArg (arg)(name, lift(defs, arg1, prefix))
55
75
case arg => lift(defs, arg, prefix)
@@ -61,12 +81,12 @@ object EtaExpansion {
61
81
def liftArgs (defs : mutable.ListBuffer [Tree ], methRef : Type , args : List [Tree ])(implicit ctx : Context ) =
62
82
methRef.widen match {
63
83
case mt : MethodType =>
64
- (args, mt.paramNames, mt.paramInfos).zipped map { (arg, name, tp) =>
65
- if (tp.isInstanceOf [ExprType ]) arg
66
- else liftArg(defs, arg, if (name.firstPart contains '$' ) EmptyTermName else name)
84
+ (args, mt.paramNames, mt.paramInfos).zipped. map { (arg, name, tp) =>
85
+ val lifter = if (tp.isInstanceOf [ExprType ]) exprLifter else this
86
+ lifter. liftArg(defs, arg, if (name.firstPart contains '$' ) EmptyTermName else name)
67
87
}
68
88
case _ =>
69
- args map (liftArg(defs, _))
89
+ args. map(liftArg(defs, _))
70
90
}
71
91
72
92
/** Lift out function prefix and all arguments from application
@@ -108,6 +128,35 @@ object EtaExpansion {
108
128
case New (_) => tree
109
129
case _ => if (isIdempotentExpr(tree)) tree else lift(defs, tree)
110
130
}
131
+ }
132
+
133
+ /** No lifting at all */
134
+ object NoLift extends Lifter {
135
+ def noLift (expr : tpd.Tree )(implicit ctx : Context ) = true
136
+ }
137
+
138
+ /** Lift all impure arguments */
139
+ class LiftImpure extends Lifter {
140
+ def noLift (expr : tpd.Tree )(implicit ctx : Context ) = tpd.isPureExpr(expr)
141
+ }
142
+ object LiftImpure extends LiftImpure
143
+
144
+ /** Lift all impure or complex arguments */
145
+ class LiftComplex extends Lifter {
146
+ def noLift (expr : tpd.Tree )(implicit ctx : Context ) = tpd.isPurePath(expr)
147
+ override def exprLifter = LiftToDefs
148
+ }
149
+ object LiftComplex extends LiftComplex
150
+
151
+ /** Lift all impure or complex arguments to `def`s */
152
+ object LiftToDefs extends LiftComplex {
153
+ override def liftedFlags : FlagSet = Method
154
+ override def liftedDef (sym : TermSymbol , rhs : tpd.Tree )(implicit ctx : Context ) = tpd.DefDef (sym, rhs)
155
+ }
156
+
157
+ /** Lifter for eta expansion */
158
+ object EtaExpansion extends LiftImpure {
159
+ import tpd ._
111
160
112
161
/** Eta-expanding a tree means converting a method reference to a function value.
113
162
* @param tree The tree to expand
@@ -152,41 +201,3 @@ object EtaExpansion {
152
201
if (defs.nonEmpty) untpd.Block (defs.toList map (untpd.TypedSplice (_)), fn) else fn
153
202
}
154
203
}
155
-
156
- /** <p> not needed
157
- * Expand partial function applications of type `type`.
158
- * </p><pre>
159
- * p.f(es_1)...(es_n)
160
- * ==> {
161
- * <b>private synthetic val</b> eta$f = p.f // if p is not stable
162
- * ...
163
- * <b>private synthetic val</b> eta$e_i = e_i // if e_i is not stable
164
- * ...
165
- * (ps_1 => ... => ps_m => eta$f([es_1])...([es_m])(ps_1)...(ps_m))
166
- * }</pre>
167
- * <p>
168
- * tree is already attributed
169
- * </p>
170
- def etaExpandUntyped(tree: Tree)(implicit ctx: Context): untpd.Tree = { // kept as a reserve for now
171
- def expand(tree: Tree): untpd.Tree = tree.tpe match {
172
- case mt @ MethodType(paramNames, paramTypes) if !mt.isImplicit =>
173
- val paramsArgs: List[(untpd.ValDef, untpd.Tree)] =
174
- (paramNames, paramTypes).zipped.map { (name, tp) =>
175
- val droppedStarTpe = defn.underlyingOfRepeated(tp)
176
- val param = ValDef(
177
- Modifiers(Param), name,
178
- untpd.TypedSplice(TypeTree(droppedStarTpe)), untpd.EmptyTree)
179
- var arg: untpd.Tree = Ident(name)
180
- if (defn.isRepeatedParam(tp))
181
- arg = Typed(arg, Ident(tpnme.WILDCARD_STAR))
182
- (param, arg)
183
- }
184
- val (params, args) = paramsArgs.unzip
185
- untpd.Function(params, Apply(untpd.TypedSplice(tree), args))
186
- }
187
-
188
- val defs = new mutable.ListBuffer[Tree]
189
- val tree1 = liftApp(defs, tree)
190
- Block(defs.toList map untpd.TypedSplice, expand(tree1))
191
- }
192
- */
0 commit comments