@@ -13,23 +13,43 @@ 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 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+
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)
2949 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)
3353 }
3454
3555 /** Lift out common part of lhs tree taking part in an operator assignment such as
@@ -49,7 +69,7 @@ object EtaExpansion {
4969 }
5070
5171 /** 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 =
5373 arg match {
5474 case arg @ NamedArg (name, arg1) => cpy.NamedArg (arg)(name, lift(defs, arg1, prefix))
5575 case arg => lift(defs, arg, prefix)
@@ -61,12 +81,12 @@ object EtaExpansion {
6181 def liftArgs (defs : mutable.ListBuffer [Tree ], methRef : Type , args : List [Tree ])(implicit ctx : Context ) =
6282 methRef.widen match {
6383 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)
6787 }
6888 case _ =>
69- args map (liftArg(defs, _))
89+ args. map(liftArg(defs, _))
7090 }
7191
7292 /** Lift out function prefix and all arguments from application
@@ -108,6 +128,35 @@ object EtaExpansion {
108128 case New (_) => tree
109129 case _ => if (isIdempotentExpr(tree)) tree else lift(defs, tree)
110130 }
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 ._
111160
112161 /** Eta-expanding a tree means converting a method reference to a function value.
113162 * @param tree The tree to expand
@@ -152,41 +201,3 @@ object EtaExpansion {
152201 if (defs.nonEmpty) untpd.Block (defs.toList map (untpd.TypedSplice (_)), fn) else fn
153202 }
154203}
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