@@ -10,8 +10,8 @@ import NameKinds.DefaultGetterName
10
10
import Phases .checkCapturesPhase
11
11
import config .Printers .capt
12
12
13
- /** Classification and transformation methods for synthetic
14
- * case class methods that need to be treated specially.
13
+ /** Classification and transformation methods for function methods and
14
+ * synthetic case class methods that need to be treated specially.
15
15
* In particular, compute capturing types for some of these methods which
16
16
* have inferred (result-)types that need to be established under separate
17
17
* compilation.
@@ -27,6 +27,9 @@ object Synthetics:
27
27
case DefaultGetterName (nme.copy, _) => sym.is(Synthetic ) && sym.owner.isClass && sym.owner.is(Case )
28
28
case _ => false
29
29
30
+ private val functionCombinatorNames = Set [Name ](
31
+ nme.andThen, nme.compose, nme.curried, nme.tupled)
32
+
30
33
/** Is `sym` a synthetic apply, copy, or copy default getter method?
31
34
* The types of these symbols are transformed in a special way without
32
35
* looking at the definitions's RHS
@@ -37,6 +40,7 @@ object Synthetics:
37
40
|| isSyntheticCopyDefaultGetterMethod(symd)
38
41
|| (symd.symbol eq defn.Object_eq )
39
42
|| (symd.symbol eq defn.Object_ne )
43
+ || defn.isFunctionClass(symd.owner) && functionCombinatorNames.contains(symd.name)
40
44
41
45
/** Method is excluded from regular capture checking.
42
46
* Excluded are synthetic class members
@@ -156,6 +160,37 @@ object Synthetics:
156
160
case info : PolyType =>
157
161
info.derivedLambdaType(resType = dropUnapplyCaptures(info.resType))
158
162
163
+ private def transformComposeCaptures (symd : SymDenotation , toCC : Boolean )(using Context ): Type =
164
+ val (pt : PolyType ) = symd.info: @ unchecked
165
+ val (mt : MethodType ) = pt.resType: @ unchecked
166
+ val (enclThis : ThisType ) = symd.owner.thisType: @ unchecked
167
+ val mt1 =
168
+ if toCC then
169
+ MethodType (mt.paramNames)(
170
+ mt1 => mt.paramInfos.map(_.capturing(CaptureSet .universal)),
171
+ mt1 => CapturingType (mt.resType, CaptureSet (enclThis, mt1.paramRefs.head)))
172
+ else
173
+ MethodType (mt.paramNames)(
174
+ mt1 => mt.paramInfos.map(_.stripCapturing),
175
+ mt1 => mt.resType.stripCapturing)
176
+ pt.derivedLambdaType(resType = mt1)
177
+
178
+ def transformCurriedTupledCaptures (symd : SymDenotation , toCC : Boolean )(using Context ): Type =
179
+ val (et : ExprType ) = symd.info: @ unchecked
180
+ val (enclThis : ThisType ) = symd.owner.thisType: @ unchecked
181
+ def mapFinalResult (tp : Type , f : Type => Type ): Type =
182
+ val defn .FunctionOf (args, res, isContextual) = tp : @ unchecked
183
+ if defn.isFunctionNType(res) then
184
+ defn.FunctionOf (args, mapFinalResult(res, f), isContextual)
185
+ else
186
+ f(tp)
187
+ val resType1 =
188
+ if toCC then
189
+ mapFinalResult(et.resType, CapturingType (_, CaptureSet (enclThis)))
190
+ else
191
+ et.resType.stripCapturing
192
+ ExprType (resType1)
193
+
159
194
/** If `sym` refers to a synthetic apply, unapply, copy, or copy default getter method
160
195
* of a case class, transform it to account for capture information.
161
196
* The method is run in phase CheckCaptures.Pre
@@ -168,6 +203,10 @@ object Synthetics:
168
203
sym.copySymDenotation(info = addUnapplyCaptures(sym.info))
169
204
case nme.apply | nme.copy =>
170
205
sym.copySymDenotation(info = addCaptureDeps(sym.info))
206
+ case nme.andThen | nme.compose =>
207
+ sym.copySymDenotation(info = transformComposeCaptures(sym, toCC = true ))
208
+ case nme.curried | nme.tupled =>
209
+ sym.copySymDenotation(info = transformCurriedTupledCaptures(sym, toCC = true ))
171
210
case n if n == nme.eq || n == nme.ne =>
172
211
sym.copySymDenotation(info =
173
212
MethodType (defn.ObjectType .capturing(CaptureSet .universal) :: Nil , defn.BooleanType ))
@@ -183,6 +222,10 @@ object Synthetics:
183
222
sym.copySymDenotation(info = dropUnapplyCaptures(sym.info))
184
223
case nme.apply | nme.copy =>
185
224
sym.copySymDenotation(info = dropCaptureDeps(sym.info))
225
+ case nme.andThen | nme.compose =>
226
+ sym.copySymDenotation(info = transformComposeCaptures(sym, toCC = false ))
227
+ case nme.curried | nme.tupled =>
228
+ sym.copySymDenotation(info = transformCurriedTupledCaptures(sym, toCC = false ))
186
229
case n if n == nme.eq || n == nme.ne =>
187
230
sym.copySymDenotation(info = defn.methOfAnyRef(defn.BooleanType ))
188
231
0 commit comments