@@ -5,7 +5,10 @@ package cc
5
5
import core .*
6
6
import Symbols .* , SymDenotations .* , Contexts .* , Flags .* , Types .* , Decorators .*
7
7
import StdNames .nme
8
+ import Names .Name
8
9
import NameKinds .DefaultGetterName
10
+ import Phases .checkCapturesPhase
11
+ import config .Printers .capt
9
12
10
13
/** Classification and transformation methods for synthetic
11
14
* case class methods that need to be treated specially.
@@ -14,17 +17,14 @@ import NameKinds.DefaultGetterName
14
17
* compilation.
15
18
*/
16
19
object Synthetics :
17
- def isSyntheticCopyMethod (sym : SymDenotation )(using Context ) =
20
+ private def isSyntheticCopyMethod (sym : SymDenotation )(using Context ) =
18
21
sym.name == nme.copy && sym.is(Synthetic ) && sym.owner.isClass && sym.owner.is(Case )
19
22
20
- def isSyntheticApplyMethod (sym : SymDenotation )(using Context ) =
21
- sym.name == nme.apply && sym.is(Synthetic ) && sym.owner.is(Module ) && sym.owner.companionClass.is(Case )
23
+ private def isSyntheticCompanionMethod (sym : SymDenotation , names : Name * )(using Context ): Boolean =
24
+ names.contains( sym.name) && sym.is(Synthetic ) && sym.owner.is(Module ) && sym.owner.companionClass.is(Case )
22
25
23
- def isSyntheticUnapplyMethod (sym : SymDenotation )(using Context ) =
24
- sym.name == nme.unapply && sym.is(Synthetic ) && sym.owner.is(Module ) && sym.owner.companionClass.is(Case )
25
-
26
- def isSyntheticCopyDefaultGetterMethod (sym : SymDenotation )(using Context ) = sym.name match
27
- case DefaultGetterName (nme.copy, _) => sym.is(Synthetic )
26
+ private def isSyntheticCopyDefaultGetterMethod (sym : SymDenotation )(using Context ) = sym.name match
27
+ case DefaultGetterName (nme.copy, _) => sym.is(Synthetic ) && sym.owner.isClass && sym.owner.is(Case )
28
28
case _ => false
29
29
30
30
/** Is `sym` a synthetic apply, copy, or copy default getter method?
@@ -33,8 +33,7 @@ object Synthetics:
33
33
*/
34
34
def needsTransform (sym : SymDenotation )(using Context ): Boolean =
35
35
isSyntheticCopyMethod(sym)
36
- || isSyntheticApplyMethod(sym)
37
- || isSyntheticUnapplyMethod(sym)
36
+ || isSyntheticCompanionMethod(sym, nme.apply, nme.unapply)
38
37
|| isSyntheticCopyDefaultGetterMethod(sym)
39
38
40
39
/** Method is excluded from regular capture checking.
@@ -48,14 +47,20 @@ object Synthetics:
48
47
&& sym.owner.isClass
49
48
&& ( defn.caseClassSynthesized.exists(
50
49
ccsym => sym.overriddenSymbol(ccsym.owner.asClass) == ccsym)
51
- || sym.name == nme.fromProduct
52
- || needsTransform(sym)
53
- )
54
-
55
- /** Add capture dependencies to the type of `apply` or `copy` method of a case class */
50
+ || isSyntheticCompanionMethod(sym, nme.fromProduct)
51
+ || needsTransform(sym))
52
+
53
+ /** Add capture dependencies to the type of the `apply` or `copy` method of a case class.
54
+ * An apply method in a case class like this:
55
+ * case class CC(a: {d} A, b: B, {*} c: C)
56
+ * would get type
57
+ * def apply(a': {d} A, b: B, {*} c': C): {a', c'} CC { val a = {a'} A, val c = {c'} C }
58
+ * where `'` is used to indicate the difference between parameter symbol and refinement name.
59
+ * Analogous for the copy method.
60
+ */
56
61
private def addCaptureDeps (info : Type )(using Context ): Type = info match
57
62
case info : MethodType =>
58
- val trackedParams = info.paramRefs.filter(atPhase(ctx.phase.next )(_.isTracked))
63
+ val trackedParams = info.paramRefs.filter(atPhase(checkCapturesPhase )(_.isTracked))
59
64
def augmentResult (tp : Type ): Type = tp match
60
65
case tp : MethodOrPoly =>
61
66
tp.derivedLambdaType(resType = augmentResult(tp.resType))
@@ -67,7 +72,8 @@ object Synthetics:
67
72
CaptureSet (pref)))
68
73
}
69
74
CapturingType (refined, CaptureSet (trackedParams* ))
70
- if trackedParams.isEmpty then info else augmentResult(info)
75
+ if trackedParams.isEmpty then info
76
+ else augmentResult(info).showing(i " augment apply/copy type $info to $result" , capt)
71
77
case info : PolyType =>
72
78
info.derivedLambdaType(resType = addCaptureDeps(info.resType))
73
79
case _ =>
@@ -115,6 +121,7 @@ object Synthetics:
115
121
case _ =>
116
122
info
117
123
124
+ /** Augment an unapply of type `(x: C): D` to `(x: {*} C): {x} D` */
118
125
private def addUnapplyCaptures (info : Type )(using Context ): Type = info match
119
126
case info : MethodType =>
120
127
val paramInfo :: Nil = info.paramInfos: @ unchecked
@@ -127,9 +134,11 @@ object Synthetics:
127
134
case _ =>
128
135
CapturingType (tp, CaptureSet (trackedParam))
129
136
info.derivedLambdaType(paramInfos = newParamInfo :: Nil , resType = newResult(info.resType))
137
+ .showing(i " augment unapply type $info to $result" , capt)
130
138
case info : PolyType =>
131
139
info.derivedLambdaType(resType = addUnapplyCaptures(info.resType))
132
140
141
+ /** Drop added capture information from the type of an `unapply` */
133
142
private def dropUnapplyCaptures (info : Type )(using Context ): Type = info match
134
143
case info : MethodType =>
135
144
val CapturingType (oldParamInfo, _) :: Nil = info.paramInfos: @ unchecked
@@ -142,28 +151,30 @@ object Synthetics:
142
151
case info : PolyType =>
143
152
info.derivedLambdaType(resType = dropUnapplyCaptures(info.resType))
144
153
145
- /** If `sym` refers to a synthetic apply, copy, or copy default getter method
154
+ /** If `sym` refers to a synthetic apply, unapply, copy, or copy default getter method
146
155
* of a case class, transform it to account for capture information.
156
+ * The method is run in phase CheckCaptures.Pre
147
157
* @pre needsTransform(sym)
148
158
*/
149
159
def transformToCC (sym : SymDenotation )(using Context ): SymDenotation = sym.name match
150
- case DefaultGetterName (nme.copy, n) if sym.is( Synthetic ) && sym.owner.is( Case ) =>
160
+ case DefaultGetterName (nme.copy, n) =>
151
161
sym.copySymDenotation(info = addDefaultGetterCapture(sym.info, sym.owner, n))
152
162
case nme.unapply =>
153
163
sym.copySymDenotation(info = addUnapplyCaptures(sym.info))
154
- case _ =>
164
+ case nme.apply | nme.copy =>
155
165
sym.copySymDenotation(info = addCaptureDeps(sym.info))
156
166
157
- /** If `sym` refers to a synthetic apply, copy, or copy default getter method
167
+
168
+ /** If `sym` refers to a synthetic apply, unapply, copy, or copy default getter method
158
169
* of a case class, transform it back to what it was before the CC phase.
159
170
* @pre needsTransform(sym)
160
171
*/
161
- def transformFromCC (sym : SymDenotation )(using Context ): SymDenotation =
162
- if isSyntheticCopyDefaultGetterMethod(sym) then
172
+ def transformFromCC (sym : SymDenotation )(using Context ): SymDenotation = sym.name match
173
+ case DefaultGetterName (nme.copy, n) =>
163
174
sym.copySymDenotation(info = dropDefaultGetterCapture(sym.info))
164
- else if sym.name == nme.unapply then
175
+ case nme.unapply =>
165
176
sym.copySymDenotation(info = dropUnapplyCaptures(sym.info))
166
- else
177
+ case nme.apply | nme.copy =>
167
178
sym.copySymDenotation(info = dropCaptureDeps(sym.info))
168
179
169
180
end Synthetics
0 commit comments