@@ -56,177 +56,155 @@ object Synthetics:
5656 || isSyntheticCompanionMethod(sym, nme.fromProduct)
5757 || needsTransform(sym))
5858
59- /** Add capture dependencies to the type of the `apply` or `copy` method of a case class.
60- * An apply method in a case class like this:
61- * case class CC(a: {d} A, b: B, {cap} c: C)
62- * would get type
63- * def apply(a': {d} A, b: B, {cap} c': C): {a', c'} CC { val a = {a'} A, val c = {c'} C }
64- * where `'` is used to indicate the difference between parameter symbol and refinement name.
65- * Analogous for the copy method.
59+ /** Transform the type of a method either to its type under capture checking
60+ * or back to its previous type.
61+ * @param sym The method to transform @pre needsTransform(sym) must hold.
62+ * @param toCC Whether to transform the type to capture checking or back.
6663 */
67- private def addCaptureDeps (info : Type )(using Context ): Type = info match
68- case info : MethodType =>
69- val trackedParams = info.paramRefs.filter(atPhase(checkCapturesPhase)(_.isTracked))
70- def augmentResult (tp : Type ): Type = tp match
71- case tp : MethodOrPoly =>
72- tp.derivedLambdaType(resType = augmentResult(tp.resType))
73- case _ =>
74- val refined = trackedParams.foldLeft(tp) { (parent, pref) =>
75- RefinedType (parent, pref.paramName,
76- CapturingType (
77- atPhase(ctx.phase.next)(pref.underlying.stripCapturing),
78- CaptureSet (pref)))
79- }
80- CapturingType (refined, CaptureSet (trackedParams* ))
81- if trackedParams.isEmpty then info
82- else augmentResult(info).showing(i " augment apply/copy type $info to $result" , capt)
83- case info : PolyType =>
84- info.derivedLambdaType(resType = addCaptureDeps(info.resType))
85- case _ =>
86- info
87-
88- /** Drop capture dependencies from the type of `apply` or `copy` method of a case class */
89- private def dropCaptureDeps (tp : Type )(using Context ): Type = tp match
90- case tp : MethodOrPoly =>
91- tp.derivedLambdaType(resType = dropCaptureDeps(tp.resType))
92- case CapturingType (parent, _) =>
93- dropCaptureDeps(parent)
94- case RefinedType (parent, _, _) =>
95- dropCaptureDeps(parent)
96- case _ =>
97- tp
98-
99- /** Add capture information to the type of the default getter of a case class copy method */
100- private def addDefaultGetterCapture (info : Type , owner : Symbol , idx : Int )(using Context ): Type = info match
101- case info : MethodOrPoly =>
102- info.derivedLambdaType(resType = addDefaultGetterCapture(info.resType, owner, idx))
103- case info : ExprType =>
104- info.derivedExprType(addDefaultGetterCapture(info.resType, owner, idx))
105- case EventuallyCapturingType (parent, _) =>
106- addDefaultGetterCapture(parent, owner, idx)
107- case info @ AnnotatedType (parent, annot) =>
108- info.derivedAnnotatedType(addDefaultGetterCapture(parent, owner, idx), annot)
109- case _ if idx < owner.asClass.paramGetters.length =>
110- val param = owner.asClass.paramGetters(idx)
111- val pinfo = param.info
112- atPhase(ctx.phase.next) {
113- if pinfo.captureSet.isAlwaysEmpty then info
114- else CapturingType (pinfo.stripCapturing, CaptureSet (param.termRef))
115- }
116- case _ =>
117- info
118-
119- /** Drop capture information from the type of the default getter of a case class copy method */
120- private def dropDefaultGetterCapture (info : Type )(using Context ): Type = info match
121- case info : MethodOrPoly =>
122- info.derivedLambdaType(resType = dropDefaultGetterCapture(info.resType))
123- case CapturingType (parent, _) =>
124- parent
125- case info @ AnnotatedType (parent, annot) =>
126- info.derivedAnnotatedType(dropDefaultGetterCapture(parent), annot)
127- case _ =>
128- info
129-
130- /** Augment an unapply of type `(x: C): D` to `(x: {cap} C): {x} D` */
131- private def addUnapplyCaptures (info : Type )(using Context ): Type = info match
132- case info : MethodType =>
133- val paramInfo :: Nil = info.paramInfos: @ unchecked
134- val newParamInfo =
135- CapturingType (paramInfo, CaptureSet .universal)
136- val trackedParam = info.paramRefs.head
137- def newResult (tp : Type ): Type = tp match
138- case tp : MethodOrPoly =>
139- tp.derivedLambdaType(resType = newResult(tp.resType))
140- case _ =>
141- CapturingType (tp, CaptureSet (trackedParam))
142- info.derivedLambdaType(paramInfos = newParamInfo :: Nil , resType = newResult(info.resType))
143- .showing(i " augment unapply type $info to $result" , capt)
144- case info : PolyType =>
145- info.derivedLambdaType(resType = addUnapplyCaptures(info.resType))
146-
147- /** Drop added capture information from the type of an `unapply` */
148- private def dropUnapplyCaptures (info : Type )(using Context ): Type = info match
149- case info : MethodType =>
150- info.paramInfos match
151- case CapturingType (oldParamInfo, _) :: Nil =>
152- def oldResult (tp : Type ): Type = tp match
64+ def transform (sym : SymDenotation , toCC : Boolean )(using Context ): SymDenotation =
65+
66+ /** Add capture dependencies to the type of the `apply` or `copy` method of a case class.
67+ * An apply method in a case class like this:
68+ * case class CC(a: A^{d}, b: B, c: C^{cap})
69+ * would get type
70+ * def apply(a': A^{d}, b: B, c': C^{cap}): CC^{a', c'} { val a = A^{a'}, val c = C^{c'} }
71+ * where `'` is used to indicate the difference between parameter symbol and refinement name.
72+ * Analogous for the copy method.
73+ */
74+ def addCaptureDeps (info : Type ): Type = info match
75+ case info : MethodType =>
76+ val trackedParams = info.paramRefs.filter(atPhase(checkCapturesPhase)(_.isTracked))
77+ def augmentResult (tp : Type ): Type = tp match
78+ case tp : MethodOrPoly =>
79+ tp.derivedLambdaType(resType = augmentResult(tp.resType))
80+ case _ =>
81+ val refined = trackedParams.foldLeft(tp) { (parent, pref) =>
82+ RefinedType (parent, pref.paramName,
83+ CapturingType (
84+ atPhase(ctx.phase.next)(pref.underlying.stripCapturing),
85+ CaptureSet (pref)))
86+ }
87+ CapturingType (refined, CaptureSet (trackedParams* ))
88+ if trackedParams.isEmpty then info
89+ else augmentResult(info).showing(i " augment apply/copy type $info to $result" , capt)
90+ case info : PolyType =>
91+ info.derivedLambdaType(resType = addCaptureDeps(info.resType))
92+ case _ =>
93+ info
94+
95+ /** Drop capture dependencies from the type of `apply` or `copy` method of a case class */
96+ def dropCaptureDeps (tp : Type ): Type = tp match
97+ case tp : MethodOrPoly =>
98+ tp.derivedLambdaType(resType = dropCaptureDeps(tp.resType))
99+ case CapturingType (parent, _) =>
100+ dropCaptureDeps(parent)
101+ case RefinedType (parent, _, _) =>
102+ dropCaptureDeps(parent)
103+ case _ =>
104+ tp
105+
106+ /** Add capture information to the type of the default getter of a case class copy method
107+ * if toCC = true, or remove the added info again if toCC = false.
108+ */
109+ def transformDefaultGetterCaptures (info : Type , owner : Symbol , idx : Int )(using Context ): Type = info match
110+ case info : MethodOrPoly =>
111+ info.derivedLambdaType(resType = transformDefaultGetterCaptures(info.resType, owner, idx))
112+ case info : ExprType =>
113+ info.derivedExprType(transformDefaultGetterCaptures(info.resType, owner, idx))
114+ case EventuallyCapturingType (parent, _) =>
115+ if toCC then transformDefaultGetterCaptures(parent, owner, idx)
116+ else parent
117+ case info @ AnnotatedType (parent, annot) =>
118+ info.derivedAnnotatedType(transformDefaultGetterCaptures(parent, owner, idx), annot)
119+ case _ if toCC && idx < owner.asClass.paramGetters.length =>
120+ val param = owner.asClass.paramGetters(idx)
121+ val pinfo = param.info
122+ atPhase(ctx.phase.next) {
123+ if pinfo.captureSet.isAlwaysEmpty then info
124+ else CapturingType (pinfo.stripCapturing, CaptureSet (param.termRef))
125+ }
126+ case _ =>
127+ info
128+
129+ /** Augment an unapply of type `(x: C): D` to `(x: C^{cap}): D^{x}` if toCC is true,
130+ * or remove the added capture sets again if toCC = false.
131+ */
132+ def transformUnapplyCaptures (info : Type )(using Context ): Type = info match
133+ case info : MethodType =>
134+ if toCC then
135+ val paramInfo :: Nil = info.paramInfos: @ unchecked
136+ val newParamInfo = CapturingType (paramInfo, CaptureSet .universal)
137+ val trackedParam = info.paramRefs.head
138+ def newResult (tp : Type ): Type = tp match
153139 case tp : MethodOrPoly =>
154- tp.derivedLambdaType(resType = oldResult(tp.resType))
155- case CapturingType (tp, _) =>
156- tp
157- info.derivedLambdaType(paramInfos = oldParamInfo :: Nil , resType = oldResult(info.resType))
158- case _ =>
159- info
160- case info : PolyType =>
161- info.derivedLambdaType(resType = dropUnapplyCaptures(info.resType))
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 =
140+ tp.derivedLambdaType(resType = newResult(tp.resType))
141+ case _ =>
142+ CapturingType (tp, CaptureSet (trackedParam))
143+ info.derivedLambdaType(paramInfos = newParamInfo :: Nil , resType = newResult(info.resType))
144+ .showing(i " augment unapply type $info to $result" , capt)
145+ else info.paramInfos match
146+ case CapturingType (oldParamInfo, _) :: Nil =>
147+ def oldResult (tp : Type ): Type = tp match
148+ case tp : MethodOrPoly =>
149+ tp.derivedLambdaType(resType = oldResult(tp.resType))
150+ case CapturingType (tp, _) =>
151+ tp
152+ info.derivedLambdaType(paramInfos = oldParamInfo :: Nil , resType = oldResult(info.resType))
153+ case _ =>
154+ info
155+ case info : PolyType =>
156+ info.derivedLambdaType(resType = transformUnapplyCaptures(info.resType))
157+
158+ def transformComposeCaptures (symd : SymDenotation ) =
159+ val (pt : PolyType ) = symd.info: @ unchecked
160+ val (mt : MethodType ) = pt.resType: @ unchecked
161+ val (enclThis : ThisType ) = symd.owner.thisType: @ unchecked
162+ val mt1 =
163+ if toCC then
164+ MethodType (mt.paramNames)(
165+ mt1 => mt.paramInfos.map(_.capturing(CaptureSet .universal)),
166+ mt1 => CapturingType (mt.resType, CaptureSet (enclThis, mt1.paramRefs.head)))
167+ else
168+ MethodType (mt.paramNames)(
169+ mt1 => mt.paramInfos.map(_.stripCapturing),
170+ mt1 => mt.resType.stripCapturing)
171+ pt.derivedLambdaType(resType = mt1)
172+
173+ def transformCurriedTupledCaptures (symd : SymDenotation ) =
174+ val (et : ExprType ) = symd.info: @ unchecked
175+ val (enclThis : ThisType ) = symd.owner.thisType: @ unchecked
176+ def mapFinalResult (tp : Type , f : Type => Type ): Type =
177+ val defn .FunctionOf (args, res, isContextual) = tp : @ unchecked
178+ if defn.isFunctionNType(res) then
179+ defn.FunctionOf (args, mapFinalResult(res, f), isContextual)
180+ else
181+ f(tp)
182+ val resType1 =
183+ if toCC then
184+ mapFinalResult(et.resType, CapturingType (_, CaptureSet (enclThis)))
185+ else
186+ et.resType.stripCapturing
187+ ExprType (resType1)
188+
189+ def transformCompareCaptures =
168190 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)))
191+ MethodType (defn.ObjectType .capturing(CaptureSet .universal) :: Nil , defn.BooleanType )
172192 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-
194- /** If `sym` refers to a synthetic apply, unapply, copy, or copy default getter method
195- * of a case class, transform it to account for capture information.
196- * The method is run in phase CheckCaptures.Pre
197- * @pre needsTransform(sym)
198- */
199- def transformToCC (sym : SymDenotation )(using Context ): SymDenotation = sym.name match
200- case DefaultGetterName (nme.copy, n) =>
201- sym.copySymDenotation(info = addDefaultGetterCapture(sym.info, sym.owner, n))
202- case nme.unapply =>
203- sym.copySymDenotation(info = addUnapplyCaptures(sym.info))
204- case nme.apply | nme.copy =>
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 ))
210- case n if n == nme.eq || n == nme.ne =>
211- sym.copySymDenotation(info =
212- MethodType (defn.ObjectType .capturing(CaptureSet .universal) :: Nil , defn.BooleanType ))
213-
214- /** If `sym` refers to a synthetic apply, unapply, copy, or copy default getter method
215- * of a case class, transform it back to what it was before the CC phase.
216- * @pre needsTransform(sym)
217- */
218- def transformFromCC (sym : SymDenotation )(using Context ): SymDenotation = sym.name match
219- case DefaultGetterName (nme.copy, n) =>
220- sym.copySymDenotation(info = dropDefaultGetterCapture(sym.info))
221- case nme.unapply =>
222- sym.copySymDenotation(info = dropUnapplyCaptures(sym.info))
223- case nme.apply | nme.copy =>
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 ))
229- case n if n == nme.eq || n == nme.ne =>
230- sym.copySymDenotation(info = defn.methOfAnyRef(defn.BooleanType ))
193+ defn.methOfAnyRef(defn.BooleanType )
194+
195+ sym.copySymDenotation(info = sym.name match
196+ case DefaultGetterName (nme.copy, n) =>
197+ transformDefaultGetterCaptures(sym.info, sym.owner, n)
198+ case nme.unapply =>
199+ transformUnapplyCaptures(sym.info)
200+ case nme.apply | nme.copy =>
201+ if toCC then addCaptureDeps(sym.info) else dropCaptureDeps(sym.info)
202+ case nme.andThen | nme.compose =>
203+ transformComposeCaptures(sym)
204+ case nme.curried | nme.tupled =>
205+ transformCurriedTupledCaptures(sym)
206+ case n if n == nme.eq || n == nme.ne =>
207+ transformCompareCaptures)
208+ end transform
231209
232210end Synthetics
0 commit comments