@@ -10,14 +10,15 @@ import Names.TypeName
1010
1111import NullOpsDecorator .*
1212import ast .untpd
13+ import scala .collection .mutable .ListBuffer
1314
1415/** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes.
1516 * These fall into five categories
1617 *
1718 * 1. Partial function closures, we need to generate isDefinedAt and applyOrElse methods for these.
1819 * 2. Closures implementing non-trait classes
1920 * 3. Closures implementing classes that inherit from a class other than Object
20- * (a lambda cannot not be a run-time subtype of such a class)
21+ * (a lambda cannot be a run-time subtype of such a class)
2122 * 4. Closures that implement traits which run initialization code.
2223 * 5. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be
2324 * (1) superaccessors, (2) outer references, (3) accessors for fields.
@@ -59,7 +60,7 @@ class ExpandSAMs extends MiniPhase:
5960 // A SAM type is allowed to have type aliases refinements (see
6061 // SAMType#samParent) which must be converted into type members if
6162 // the closure is desugared into a class.
62- val refinements = collection.mutable. ListBuffer [(TypeName , TypeAlias )]()
63+ val refinements = ListBuffer .empty [(TypeName , TypeAlias )]
6364 def collectAndStripRefinements (tp : Type ): Type = tp match
6465 case RefinedType (parent, name, info : TypeAlias ) =>
6566 val res = collectAndStripRefinements(parent)
@@ -81,34 +82,40 @@ class ExpandSAMs extends MiniPhase:
8182 tree
8283 }
8384
84- /** A partial function literal :
85+ /** A pattern-matching anonymous function :
8586 *
8687 * ```
8788 * val x: PartialFunction[A, B] = { case C1 => E1; ...; case Cn => En }
8889 * ```
90+ * or
91+ * ```
92+ * x => e(x) { case C1 => E1; ...; case Cn => En }
93+ * ```
94+ * where the expression `e(x)` may be trivially `x`
8995 *
9096 * which desugars to:
9197 *
9298 * ```
9399 * val x: PartialFunction[A, B] = {
94- * def $anonfun(x: A): B = x match { case C1 => E1; ...; case Cn => En }
100+ * def $anonfun(x: A): B = e(x) match { case C1 => E1; ...; case Cn => En }
95101 * closure($anonfun: PartialFunction[A, B])
96102 * }
97103 * ```
104+ * where the expression `e(x)` defaults to `x` for a simple block of cases
98105 *
99106 * is expanded to an anonymous class:
100107 *
101108 * ```
102109 * val x: PartialFunction[A, B] = {
103110 * class $anon extends AbstractPartialFunction[A, B] {
104- * final def isDefinedAt(x: A): Boolean = x match {
111+ * final def isDefinedAt(x: A): Boolean = e(x) match {
105112 * case C1 => true
106113 * ...
107114 * case Cn => true
108115 * case _ => false
109116 * }
110117 *
111- * final def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = x match {
118+ * final def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = e(x) match {
112119 * case C1 => E1
113120 * ...
114121 * case Cn => En
@@ -120,7 +127,7 @@ class ExpandSAMs extends MiniPhase:
120127 * }
121128 * ```
122129 */
123- private def toPartialFunction (tree : Block , tpe : Type )(using Context ): Tree = {
130+ private def toPartialFunction (tree : Block , tpe : Type )(using Context ): Tree =
124131 val closureDef(anon @ DefDef (_, List (List (param)), _, _)) = tree : @ unchecked
125132
126133 // The right hand side from which to construct the partial function. This is always a Match.
@@ -146,7 +153,7 @@ class ExpandSAMs extends MiniPhase:
146153 defn.AbstractPartialFunctionClass .typeRef.appliedTo(anonTpe.firstParamTypes.head, anonTpe.resultType),
147154 defn.SerializableType )
148155
149- AnonClass (anonSym.owner, parents, tree.span) { pfSym =>
156+ AnonClass (anonSym.owner, parents, tree.span): pfSym =>
150157 def overrideSym (sym : Symbol ) = sym.copy(
151158 owner = pfSym,
152159 flags = Synthetic | Method | Final | Override ,
@@ -155,7 +162,8 @@ class ExpandSAMs extends MiniPhase:
155162 val isDefinedAtFn = overrideSym(defn.PartialFunction_isDefinedAt )
156163 val applyOrElseFn = overrideSym(defn.PartialFunction_applyOrElse )
157164
158- def translateMatch (tree : Match , pfParam : Symbol , cases : List [CaseDef ], defaultValue : Tree )(using Context ) = {
165+ def translateMatch (owner : Symbol )(pfParam : Symbol , cases : List [CaseDef ], defaultValue : Tree )(using Context ) =
166+ val tree : Match = pfRHS
159167 val selector = tree.selector
160168 val cases1 = if cases.exists(isDefaultCase) then cases
161169 else
@@ -165,31 +173,27 @@ class ExpandSAMs extends MiniPhase:
165173 cases :+ defaultCase
166174 cpy.Match (tree)(selector, cases1)
167175 .subst(param.symbol :: Nil , pfParam :: Nil )
168- // Needed because a partial function can be written as:
176+ // Needed because a partial function can be written as:
169177 // param => param match { case "foo" if foo(param) => param }
170178 // And we need to update all references to 'param'
171- }
179+ .changeOwner(anonSym, owner)
172180
173- def isDefinedAtRhs (paramRefss : List [List [Tree ]])(using Context ) = {
181+ def isDefinedAtRhs (paramRefss : List [List [Tree ]])(using Context ) =
174182 val tru = Literal (Constant (true ))
175- def translateCase (cdef : CaseDef ) =
176- cpy.CaseDef (cdef)(body = tru).changeOwner(anonSym, isDefinedAtFn)
183+ def translateCase (cdef : CaseDef ) = cpy.CaseDef (cdef)(body = tru)
177184 val paramRef = paramRefss.head.head
178185 val defaultValue = Literal (Constant (false ))
179- translateMatch(pfRHS, paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
180- }
186+ translateMatch(isDefinedAtFn)(paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
181187
182- def applyOrElseRhs (paramRefss : List [List [Tree ]])(using Context ) = {
188+ def applyOrElseRhs (paramRefss : List [List [Tree ]])(using Context ) =
183189 val List (paramRef, defaultRef) = paramRefss(1 )
184- def translateCase (cdef : CaseDef ) =
185- cdef.changeOwner(anonSym, applyOrElseFn)
186190 val defaultValue = defaultRef.select(nme.apply).appliedTo(paramRef)
187- translateMatch(pfRHS, paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
188- }
191+ translateMatch(applyOrElseFn)(paramRef.symbol, pfRHS.cases, defaultValue)
189192
190- val isDefinedAtDef = transformFollowingDeep(DefDef (isDefinedAtFn, isDefinedAtRhs(_)(using ctx.withOwner(isDefinedAtFn))))
191- val applyOrElseDef = transformFollowingDeep(DefDef (applyOrElseFn, applyOrElseRhs(_)(using ctx.withOwner(applyOrElseFn))))
193+ val isDefinedAtDef = transformFollowingDeep :
194+ DefDef (isDefinedAtFn, isDefinedAtRhs(_)(using ctx.withOwner(isDefinedAtFn)))
195+ val applyOrElseDef = transformFollowingDeep :
196+ DefDef (applyOrElseFn, applyOrElseRhs(_)(using ctx.withOwner(applyOrElseFn)))
192197 List (isDefinedAtDef, applyOrElseDef)
193- }
194- }
198+ end toPartialFunction
195199end ExpandSAMs
0 commit comments