Skip to content

Commit 16a67dc

Browse files
authored
Don't StackOverflow when printing RecursiveType structure. (#22859)
Fixes #22649. The printed representation looks like this: ``` RecursiveType(rec12 => ... RecursiveThis(<rec12>) ...) ```
2 parents 605081b + 3a59413 commit 16a67dc

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

compiler/src/scala/quoted/runtime/impl/printers/Extractors.scala

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package scala.quoted
22
package runtime.impl.printers
33

4+
import scala.collection.mutable
45
import scala.quoted.*
56

67
object Extractors {
@@ -67,6 +68,12 @@ object Extractors {
6768
import quotes.reflect.*
6869

6970
private val sb: StringBuilder = new StringBuilder
71+
private var recTypeCounter = 0
72+
private val recTypeIds = mutable.Map.empty[RecursiveType, Int]
73+
74+
private def nextRecTypeId(): Int =
75+
recTypeCounter += 1
76+
recTypeCounter
7077

7178
def result(): String = sb.result()
7279

@@ -226,9 +233,14 @@ object Extractors {
226233
case SuperType(thistpe, supertpe) =>
227234
this += "SuperType(" += thistpe += ", " += supertpe += ")"
228235
case RecursiveThis(binder) =>
229-
this += "RecursiveThis(" += binder += ")"
230-
case RecursiveType(underlying) =>
231-
this += "RecursiveType(" += underlying += ")"
236+
val id = recTypeIds.getOrElse(binder, -1)
237+
if (id == -1)
238+
this += "RecursiveThis(" += binder += ")"
239+
else
240+
this += "RecursiveThis(<rec" += id += ">)"
241+
case rt @ RecursiveType(underlying) =>
242+
val id = recTypeIds.getOrElseUpdate(rt, nextRecTypeId())
243+
this += "RecursiveType(rec" += id += " => " += underlying += ")"
232244
case MethodType(argNames, argTypes, resType) =>
233245
this += "MethodType(" ++= argNames += ", " ++= argTypes += ", " += resType += ")"
234246
case PolyType(argNames, argBounds, resType) =>

tests/run/i22649/Macro_1.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.quoted.*
2+
3+
inline def structureOf[T]: String =
4+
${ structureOfImpl[T] }
5+
6+
private def structureOfImpl[T](using Quotes, Type[T]): Expr[String] =
7+
import quotes.reflect.*
8+
val str = Printer.TypeReprStructure.show(TypeRepr.of[T])
9+
Expr(str)

tests/run/i22649/Test_2.scala

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@main def Test =
2+
val str =
3+
structureOf[{
4+
type T
5+
def make: T
6+
}]
7+
8+
assert(
9+
str == """RecursiveType(rec1 => Refinement(Refinement(TypeRef(ThisType(TypeRef(NoPrefix(), "lang")), "Object"), "T", TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Nothing"), TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Any"))), "make", ByNameType(TypeRef(RecursiveThis(<rec1>), "T"))))""",
10+
s"Was $str"
11+
)

0 commit comments

Comments
 (0)