Skip to content

Commit e33ac5c

Browse files
committed
Move internal classes that are dependent on q inside a container.
Scala 3.3.0 does not allow the `extends` clause of a class to refer to constructor parameters. It was shown to be unsound. See scala/scala3#16270 However, we can depend on paths that enclose the class definition. So we introduce a container class `TreeMaps` that takes the `q: Q` as parameter, and move the classes that extend `q.reflect.TreeMap` inside that container.
1 parent 027d078 commit e33ac5c

File tree

1 file changed

+80
-83
lines changed

1 file changed

+80
-83
lines changed

dotty/derivation/src/main/scala/perspective/derivation/inlineHkdGeneric.scala

Lines changed: 80 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -245,105 +245,101 @@ object InlineHKDGeneric:
245245
arr
246246
}
247247

248-
private class ProductElementIdExactExpander[Q <: Quotes, Fields <: Tuple: Type](using val q: Q)
249-
extends q.reflect.TreeMap {
248+
private class TreeMaps[Q <: Quotes](using val q: Q) {
250249
import q.reflect.*
251250

252-
override def transformTerm(tree: Term)(owner: Symbol): Term =
253-
try {
254-
tree.asExpr match {
255-
case '{ InlineHKDGeneric.productElementIdExact[a2, elemTop]($a, $idx) } =>
256-
transformExact(a, idx)
257-
case _ =>
258-
super.transformTerm(tree)(owner)
251+
class ProductElementIdExactExpander[Fields <: Tuple: Type] extends TreeMap {
252+
override def transformTerm(tree: Term)(owner: Symbol): Term =
253+
try {
254+
tree.asExpr match {
255+
case '{ InlineHKDGeneric.productElementIdExact[a2, elemTop]($a, $idx) } =>
256+
transformExact(a, idx)
257+
case _ =>
258+
super.transformTerm(tree)(owner)
259+
}
260+
} catch {
261+
case e: Exception =>
262+
// Tried to convert partially applied type to Expr. Ignoring it
263+
tree
259264
}
260-
} catch {
261-
case e: Exception =>
262-
// Tried to convert partially applied type to Expr. Ignoring it
263-
tree
264-
}
265265

266-
def transformExact[A](a: Expr[A], idxExpr: Expr[Int]): Term = {
267-
def findConstantIdx(tpe: TypeRepr): Option[Int] = tpe match {
268-
case AndType(a, b) => findConstantIdx(a).orElse(findConstantIdx(b))
269-
case ConstantType(IntConstant(i)) => Some(i)
270-
case Refinement(a, _, _) => findConstantIdx(a)
271-
case t => None
272-
}
266+
def transformExact[A](a: Expr[A], idxExpr: Expr[Int]): Term = {
267+
def findConstantIdx(tpe: TypeRepr): Option[Int] = tpe match {
268+
case AndType(a, b) => findConstantIdx(a).orElse(findConstantIdx(b))
269+
case ConstantType(IntConstant(i)) => Some(i)
270+
case Refinement(a, _, _) => findConstantIdx(a)
271+
case t => None
272+
}
273273

274-
val idx = findConstantIdx(idxExpr.asTerm.tpe.widenTermRefByName).getOrElse(idxExpr.valueOrAbort)
274+
val idx = findConstantIdx(idxExpr.asTerm.tpe.widenTermRefByName).getOrElse(idxExpr.valueOrAbort)
275275

276-
val field = Helpers.valuesOfConstantTuple(TypeRepr.of[Fields], Nil) match {
277-
case Some(seq) => seq(idx).asExprOf[String].valueOrAbort
278-
case None => report.errorAndAbort("productElementIdExact called with non constant fields type")
279-
}
276+
val field = Helpers.valuesOfConstantTuple(TypeRepr.of[Fields], Nil) match {
277+
case Some(seq) => seq(idx).asExprOf[String].valueOrAbort
278+
case None => report.errorAndAbort("productElementIdExact called with non constant fields type")
279+
}
280280

281-
Select.unique(a.asTerm, field)
281+
Select.unique(a.asTerm, field)
282+
}
282283
}
283-
}
284284

285-
private class RefReplacer[Q <: Quotes](using val q: Q)(oldRef: q.reflect.Symbol, newRef: q.reflect.Ref)
286-
extends q.reflect.TreeMap {
287-
import q.reflect.*
285+
class RefReplacer(oldRef: q.reflect.Symbol, newRef: q.reflect.Ref) extends TreeMap {
286+
override def transformTerm(tree: Term)(owner: Symbol): Term =
287+
tree match {
288+
case Ident(id) if id == oldRef.name => newRef
289+
case _ => super.transformTerm(tree)(owner)
290+
}
291+
}
288292

289-
override def transformTerm(tree: Term)(owner: Symbol): Term =
290-
tree match {
291-
case Ident(id) if id == oldRef.name => newRef
292-
case _ => super.transformTerm(tree)(owner)
293+
class LateInlineMatchExpander extends TreeMap {
294+
override def transformTerm(tree: Term)(owner: Symbol): Term = {
295+
tree.asExpr match {
296+
case '{ InlineHKDGeneric.lateInlineMatch[a]($a) } =>
297+
transformMatch(a, owner)
298+
case _ =>
299+
try {
300+
super.transformTerm(tree)(owner)
301+
} catch {
302+
case _: Exception =>
303+
// FIXME: Have no idea why this happens. Just ignoring it for now.
304+
tree
305+
}
306+
}
293307
}
294-
}
295308

296-
private class LateInlineMatchExpander[Q <: Quotes]()(using val q: Q) extends q.reflect.TreeMap {
297-
import q.reflect.*
309+
def transformMatch[A: Type](aExpr: Expr[A], owner: Symbol): Term = aExpr.asTerm match {
310+
case m @ Match(scrutinee, cases) =>
311+
val tpe = scrutinee.tpe.widenTermRefByName
298312

299-
override def transformTerm(tree: Term)(owner: Symbol): Term = {
300-
tree.asExpr match {
301-
case '{ InlineHKDGeneric.lateInlineMatch[a]($a) } =>
302-
transformMatch(a, owner)
303-
case _ =>
304-
try {
305-
super.transformTerm(tree)(owner)
306-
} catch {
307-
case _: Exception =>
308-
// FIXME: Have no idea why this happens. Just ignoring it for now.
309-
tree
313+
cases.foreach {
314+
case CaseDef(_, Some(_), _) => report.errorAndAbort("Cases in match can not have guards")
315+
case CaseDef(Bind(_, Typed(Ident(_), _)), _, _) =>
316+
case CaseDef(Bind(_, Ident(_)), _, _) =>
317+
case caseDef => report.errorAndAbort("Invalid case in match inside lateInlineMatch", caseDef.pos)
310318
}
311-
}
312-
}
313-
314-
def transformMatch[A: Type](aExpr: Expr[A], owner: Symbol): Term = aExpr.asTerm match {
315-
case m @ Match(scrutinee, cases) =>
316-
val tpe = scrutinee.tpe.widenTermRefByName
317319

318-
cases.foreach {
319-
case CaseDef(_, Some(_), _) => report.errorAndAbort("Cases in match can not have guards")
320-
case CaseDef(Bind(_, Typed(Ident(_), _)), _, _) =>
321-
case CaseDef(Bind(_, Ident(_)), _, _) =>
322-
case caseDef => report.errorAndAbort("Invalid case in match inside lateInlineMatch", caseDef.pos)
323-
}
320+
val hasDefaultCase = cases.exists {
321+
case CaseDef(Bind(_, Ident(_)), _, _) => true
322+
case _ => false
323+
}
324+
if !hasDefaultCase then report.errorAndAbort("Match must have a default case", m.pos)
324325

325-
val hasDefaultCase = cases.exists {
326-
case CaseDef(Bind(_, Ident(_)), _, _) => true
327-
case _ => false
328-
}
329-
if !hasDefaultCase then report.errorAndAbort("Match must have a default case", m.pos)
326+
val (bind, rhs) = cases
327+
.collectFirst {
328+
case CaseDef(bind @ Bind(_, typed @ Typed(Ident(_), _)), _, rhs) if tpe <:< typed.symbol.typeRef =>
329+
(bind, rhs)
330+
}
331+
.getOrElse {
332+
cases.collectFirst { case CaseDef(bind @ Bind(_, Ident(_)), _, rhs) =>
333+
(bind, rhs)
334+
}.get
335+
}
330336

331-
val (bind, rhs) = cases
332-
.collectFirst {
333-
case CaseDef(bind @ Bind(_, typed @ Typed(Ident(_), _)), _, rhs) if tpe <:< typed.symbol.typeRef =>
334-
(bind, rhs)
335-
}
336-
.getOrElse {
337-
cases.collectFirst { case CaseDef(bind @ Bind(_, Ident(_)), _, rhs) =>
338-
(bind, rhs)
339-
}.get
337+
ValDef.let(owner, bind.name + "Replaced", scrutinee) { newRef =>
338+
val replacer = new RefReplacer(bind.symbol, newRef)
339+
replacer.transformTerm(rhs)(owner)
340340
}
341-
342-
ValDef.let(owner, bind.name + "Replaced", scrutinee) { newRef =>
343-
val replacer = new RefReplacer[q.type](bind.symbol, newRef)
344-
replacer.transformTerm(rhs)(owner)
345-
}
346-
case _ => report.errorAndAbort("Body of lateInlineMatch must be a match", aExpr)
341+
case _ => report.errorAndAbort("Body of lateInlineMatch must be a match", aExpr)
342+
}
347343
}
348344
}
349345

@@ -352,8 +348,9 @@ object InlineHKDGeneric:
352348
): Expr[A] =
353349
import q.reflect.*
354350

355-
val productElementIdExactExpander = new ProductElementIdExactExpander[q.type, Fields]()
356-
val lateInlineMatchExpander = new LateInlineMatchExpander[q.type]()
351+
val treeMaps = new TreeMaps[q.type]()
352+
val productElementIdExactExpander = new treeMaps.ProductElementIdExactExpander[Fields]()
353+
val lateInlineMatchExpander = new treeMaps.LateInlineMatchExpander()
357354

358355
val r1 = productElementIdExactExpander.transformTerm(e.asTerm)(Symbol.spliceOwner)
359356
val r2 = lateInlineMatchExpander.transformTerm(r1)(Symbol.spliceOwner)

0 commit comments

Comments
 (0)