@@ -13,23 +13,44 @@ import Decorators._
1313import Names ._
1414import StdNames ._
1515import NameKinds .UniqueName
16- import Trees ._
1716import Inferencing ._
1817import util .Positions ._
1918import collection .mutable
19+ import Trees ._
2020
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 {
2331 import tpd ._
2432
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+
2545 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
2747 else {
2848 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)
3354 }
3455
3556 /** Lift out common part of lhs tree taking part in an operator assignment such as
@@ -49,7 +70,7 @@ object EtaExpansion {
4970 }
5071
5172 /** 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 =
5374 arg match {
5475 case arg @ NamedArg (name, arg1) => cpy.NamedArg (arg)(name, lift(defs, arg1, prefix))
5576 case arg => lift(defs, arg, prefix)
@@ -61,12 +82,12 @@ object EtaExpansion {
6182 def liftArgs (defs : mutable.ListBuffer [Tree ], methRef : Type , args : List [Tree ])(implicit ctx : Context ) =
6283 methRef.widen match {
6384 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)
6788 }
6889 case _ =>
69- args map (liftArg(defs, _))
90+ args. map(liftArg(defs, _))
7091 }
7192
7293 /** Lift out function prefix and all arguments from application
@@ -108,6 +129,35 @@ object EtaExpansion {
108129 case New (_) => tree
109130 case _ => if (isIdempotentExpr(tree)) tree else lift(defs, tree)
110131 }
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 ._
111161
112162 /** Eta-expanding a tree means converting a method reference to a function value.
113163 * @param tree The tree to expand
@@ -152,41 +202,3 @@ object EtaExpansion {
152202 if (defs.nonEmpty) untpd.Block (defs.toList map (untpd.TypedSplice (_)), fn) else fn
153203 }
154204}
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