@@ -5,7 +5,10 @@ package cc
55import core .*
66import Symbols .* , SymDenotations .* , Contexts .* , Flags .* , Types .* , Decorators .*
77import StdNames .nme
8+ import Names .Name
89import NameKinds .DefaultGetterName
10+ import Phases .checkCapturesPhase
11+ import config .Printers .capt
912
1013/** Classification and transformation methods for synthetic
1114 * case class methods that need to be treated specially.
@@ -14,17 +17,14 @@ import NameKinds.DefaultGetterName
1417 * compilation.
1518 */
1619object Synthetics :
17- def isSyntheticCopyMethod (sym : SymDenotation )(using Context ) =
20+ private def isSyntheticCopyMethod (sym : SymDenotation )(using Context ) =
1821 sym.name == nme.copy && sym.is(Synthetic ) && sym.owner.isClass && sym.owner.is(Case )
1922
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 )
2225
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 )
2828 case _ => false
2929
3030 /** Is `sym` a synthetic apply, copy, or copy default getter method?
@@ -33,8 +33,7 @@ object Synthetics:
3333 */
3434 def needsTransform (sym : SymDenotation )(using Context ): Boolean =
3535 isSyntheticCopyMethod(sym)
36- || isSyntheticApplyMethod(sym)
37- || isSyntheticUnapplyMethod(sym)
36+ || isSyntheticCompanionMethod(sym, nme.apply, nme.unapply)
3837 || isSyntheticCopyDefaultGetterMethod(sym)
3938
4039 /** Method is excluded from regular capture checking.
@@ -48,14 +47,20 @@ object Synthetics:
4847 && sym.owner.isClass
4948 && ( defn.caseClassSynthesized.exists(
5049 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+ */
5661 private def addCaptureDeps (info : Type )(using Context ): Type = info match
5762 case info : MethodType =>
58- val trackedParams = info.paramRefs.filter(atPhase(ctx.phase.next )(_.isTracked))
63+ val trackedParams = info.paramRefs.filter(atPhase(checkCapturesPhase )(_.isTracked))
5964 def augmentResult (tp : Type ): Type = tp match
6065 case tp : MethodOrPoly =>
6166 tp.derivedLambdaType(resType = augmentResult(tp.resType))
@@ -67,7 +72,8 @@ object Synthetics:
6772 CaptureSet (pref)))
6873 }
6974 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)
7177 case info : PolyType =>
7278 info.derivedLambdaType(resType = addCaptureDeps(info.resType))
7379 case _ =>
@@ -115,6 +121,7 @@ object Synthetics:
115121 case _ =>
116122 info
117123
124+ /** Augment an unapply of type `(x: C): D` to `(x: {*} C): {x} D` */
118125 private def addUnapplyCaptures (info : Type )(using Context ): Type = info match
119126 case info : MethodType =>
120127 val paramInfo :: Nil = info.paramInfos: @ unchecked
@@ -127,9 +134,11 @@ object Synthetics:
127134 case _ =>
128135 CapturingType (tp, CaptureSet (trackedParam))
129136 info.derivedLambdaType(paramInfos = newParamInfo :: Nil , resType = newResult(info.resType))
137+ .showing(i " augment unapply type $info to $result" , capt)
130138 case info : PolyType =>
131139 info.derivedLambdaType(resType = addUnapplyCaptures(info.resType))
132140
141+ /** Drop added capture information from the type of an `unapply` */
133142 private def dropUnapplyCaptures (info : Type )(using Context ): Type = info match
134143 case info : MethodType =>
135144 val CapturingType (oldParamInfo, _) :: Nil = info.paramInfos: @ unchecked
@@ -142,28 +151,30 @@ object Synthetics:
142151 case info : PolyType =>
143152 info.derivedLambdaType(resType = dropUnapplyCaptures(info.resType))
144153
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
146155 * of a case class, transform it to account for capture information.
156+ * The method is run in phase CheckCaptures.Pre
147157 * @pre needsTransform(sym)
148158 */
149159 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) =>
151161 sym.copySymDenotation(info = addDefaultGetterCapture(sym.info, sym.owner, n))
152162 case nme.unapply =>
153163 sym.copySymDenotation(info = addUnapplyCaptures(sym.info))
154- case _ =>
164+ case nme.apply | nme.copy =>
155165 sym.copySymDenotation(info = addCaptureDeps(sym.info))
156166
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
158169 * of a case class, transform it back to what it was before the CC phase.
159170 * @pre needsTransform(sym)
160171 */
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) =>
163174 sym.copySymDenotation(info = dropDefaultGetterCapture(sym.info))
164- else if sym.name == nme.unapply then
175+ case nme.unapply =>
165176 sym.copySymDenotation(info = dropUnapplyCaptures(sym.info))
166- else
177+ case nme.apply | nme.copy =>
167178 sym.copySymDenotation(info = dropCaptureDeps(sym.info))
168179
169180end Synthetics
0 commit comments