@@ -10,14 +10,15 @@ import Names.TypeName
10
10
11
11
import NullOpsDecorator .*
12
12
import ast .untpd
13
+ import scala .collection .mutable .ListBuffer
13
14
14
15
/** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes.
15
16
* These fall into five categories
16
17
*
17
18
* 1. Partial function closures, we need to generate isDefinedAt and applyOrElse methods for these.
18
19
* 2. Closures implementing non-trait classes
19
20
* 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)
21
22
* 4. Closures that implement traits which run initialization code.
22
23
* 5. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be
23
24
* (1) superaccessors, (2) outer references, (3) accessors for fields.
@@ -59,7 +60,7 @@ class ExpandSAMs extends MiniPhase:
59
60
// A SAM type is allowed to have type aliases refinements (see
60
61
// SAMType#samParent) which must be converted into type members if
61
62
// the closure is desugared into a class.
62
- val refinements = collection.mutable. ListBuffer [(TypeName , TypeAlias )]()
63
+ val refinements = ListBuffer .empty [(TypeName , TypeAlias )]
63
64
def collectAndStripRefinements (tp : Type ): Type = tp match
64
65
case RefinedType (parent, name, info : TypeAlias ) =>
65
66
val res = collectAndStripRefinements(parent)
@@ -81,34 +82,40 @@ class ExpandSAMs extends MiniPhase:
81
82
tree
82
83
}
83
84
84
- /** A partial function literal :
85
+ /** A pattern-matching anonymous function :
85
86
*
86
87
* ```
87
88
* val x: PartialFunction[A, B] = { case C1 => E1; ...; case Cn => En }
88
89
* ```
90
+ * or
91
+ * ```
92
+ * x => e(x) { case C1 => E1; ...; case Cn => En }
93
+ * ```
94
+ * where the expression `e(x)` may be trivially `x`
89
95
*
90
96
* which desugars to:
91
97
*
92
98
* ```
93
99
* 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 }
95
101
* closure($anonfun: PartialFunction[A, B])
96
102
* }
97
103
* ```
104
+ * where the expression `e(x)` defaults to `x` for a simple block of cases
98
105
*
99
106
* is expanded to an anonymous class:
100
107
*
101
108
* ```
102
109
* val x: PartialFunction[A, B] = {
103
110
* 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 {
105
112
* case C1 => true
106
113
* ...
107
114
* case Cn => true
108
115
* case _ => false
109
116
* }
110
117
*
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 {
112
119
* case C1 => E1
113
120
* ...
114
121
* case Cn => En
@@ -120,7 +127,7 @@ class ExpandSAMs extends MiniPhase:
120
127
* }
121
128
* ```
122
129
*/
123
- private def toPartialFunction (tree : Block , tpe : Type )(using Context ): Tree = {
130
+ private def toPartialFunction (tree : Block , tpe : Type )(using Context ): Tree =
124
131
val closureDef(anon @ DefDef (_, List (List (param)), _, _)) = tree : @ unchecked
125
132
126
133
// The right hand side from which to construct the partial function. This is always a Match.
@@ -146,7 +153,7 @@ class ExpandSAMs extends MiniPhase:
146
153
defn.AbstractPartialFunctionClass .typeRef.appliedTo(anonTpe.firstParamTypes.head, anonTpe.resultType),
147
154
defn.SerializableType )
148
155
149
- AnonClass (anonSym.owner, parents, tree.span) { pfSym =>
156
+ AnonClass (anonSym.owner, parents, tree.span): pfSym =>
150
157
def overrideSym (sym : Symbol ) = sym.copy(
151
158
owner = pfSym,
152
159
flags = Synthetic | Method | Final | Override ,
@@ -155,7 +162,8 @@ class ExpandSAMs extends MiniPhase:
155
162
val isDefinedAtFn = overrideSym(defn.PartialFunction_isDefinedAt )
156
163
val applyOrElseFn = overrideSym(defn.PartialFunction_applyOrElse )
157
164
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
159
167
val selector = tree.selector
160
168
val cases1 = if cases.exists(isDefaultCase) then cases
161
169
else
@@ -165,31 +173,27 @@ class ExpandSAMs extends MiniPhase:
165
173
cases :+ defaultCase
166
174
cpy.Match (tree)(selector, cases1)
167
175
.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:
169
177
// param => param match { case "foo" if foo(param) => param }
170
178
// And we need to update all references to 'param'
171
- }
179
+ .changeOwner(anonSym, owner)
172
180
173
- def isDefinedAtRhs (paramRefss : List [List [Tree ]])(using Context ) = {
181
+ def isDefinedAtRhs (paramRefss : List [List [Tree ]])(using Context ) =
174
182
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)
177
184
val paramRef = paramRefss.head.head
178
185
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)
181
187
182
- def applyOrElseRhs (paramRefss : List [List [Tree ]])(using Context ) = {
188
+ def applyOrElseRhs (paramRefss : List [List [Tree ]])(using Context ) =
183
189
val List (paramRef, defaultRef) = paramRefss(1 )
184
- def translateCase (cdef : CaseDef ) =
185
- cdef.changeOwner(anonSym, applyOrElseFn)
186
190
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)
189
192
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)))
192
197
List (isDefinedAtDef, applyOrElseDef)
193
- }
194
- }
198
+ end toPartialFunction
195
199
end ExpandSAMs
0 commit comments