@@ -13,23 +13,44 @@ 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 pass-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
- 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)
49
+ var liftedType = fullyDefinedType(expr.tpe.widen, " lifted expression" , expr.pos)
50
+ if (liftedFlags.is(Method )) liftedType = ExprType (liftedType)
51
+ val lifted = ctx.newSymbol(ctx.owner, name, liftedFlags, liftedType, coord = positionCoord(expr.pos))
52
+ defs += liftedDef(lifted, expr).withPos(expr.pos.focus)
53
+ ref(lifted.termRef).withPos(expr.pos)
33
54
}
34
55
35
56
/** Lift out common part of lhs tree taking part in an operator assignment such as
@@ -49,7 +70,7 @@ object EtaExpansion {
49
70
}
50
71
51
72
/** Lift a function argument, stripping any NamedArg wrapper */
52
- def liftArg (defs : mutable.ListBuffer [Tree ], arg : Tree , prefix : TermName = EmptyTermName )(implicit ctx : Context ): Tree =
73
+ private def liftArg (defs : mutable.ListBuffer [Tree ], arg : Tree , prefix : TermName = EmptyTermName )(implicit ctx : Context ): Tree =
53
74
arg match {
54
75
case arg @ NamedArg (name, arg1) => cpy.NamedArg (arg)(name, lift(defs, arg1, prefix))
55
76
case arg => lift(defs, arg, prefix)
@@ -61,12 +82,12 @@ object EtaExpansion {
61
82
def liftArgs (defs : mutable.ListBuffer [Tree ], methRef : Type , args : List [Tree ])(implicit ctx : Context ) =
62
83
methRef.widen match {
63
84
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)
85
+ (args, mt.paramNames, mt.paramInfos).zipped. map { (arg, name, tp) =>
86
+ val lifter = if (tp.isInstanceOf [ExprType ]) exprLifter else this
87
+ lifter. liftArg(defs, arg, if (name.firstPart contains '$' ) EmptyTermName else name)
67
88
}
68
89
case _ =>
69
- args map (liftArg(defs, _))
90
+ args. map(liftArg(defs, _))
70
91
}
71
92
72
93
/** Lift out function prefix and all arguments from application
@@ -108,6 +129,35 @@ object EtaExpansion {
108
129
case New (_) => tree
109
130
case _ => if (isIdempotentExpr(tree)) tree else lift(defs, tree)
110
131
}
132
+ }
133
+
134
+ /** No lifting at all */
135
+ object NoLift extends Lifter {
136
+ def noLift (expr : tpd.Tree )(implicit ctx : Context ) = true
137
+ }
138
+
139
+ /** Lift all impure arguments */
140
+ class LiftImpure extends Lifter {
141
+ def noLift (expr : tpd.Tree )(implicit ctx : Context ) = tpd.isPureExpr(expr)
142
+ }
143
+ object LiftImpure extends LiftImpure
144
+
145
+ /** Lift all impure or complex arguments */
146
+ class LiftComplex extends Lifter {
147
+ def noLift (expr : tpd.Tree )(implicit ctx : Context ) = tpd.isSimplyPure(expr)
148
+ override def exprLifter = LiftToDefs
149
+ }
150
+ object LiftComplex extends LiftComplex
151
+
152
+ /** Lift all impure or complex arguments to `def`s */
153
+ object LiftToDefs extends LiftComplex {
154
+ override def liftedFlags : FlagSet = Method
155
+ override def liftedDef (sym : TermSymbol , rhs : tpd.Tree )(implicit ctx : Context ) = tpd.DefDef (sym, rhs)
156
+ }
157
+
158
+ /** Lifter for eta expansion */
159
+ object EtaExpansion extends LiftImpure {
160
+ import tpd ._
111
161
112
162
/** Eta-expanding a tree means converting a method reference to a function value.
113
163
* @param tree The tree to expand
@@ -152,41 +202,3 @@ object EtaExpansion {
152
202
if (defs.nonEmpty) untpd.Block (defs.toList map (untpd.TypedSplice (_)), fn) else fn
153
203
}
154
204
}
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