Skip to content

Commit

Permalink
Fix #18484: Query every legal child of sealed class on children call
Browse files Browse the repository at this point in the history
Sometimes, a macro or Mirror can be called/generated for a type that
may have not had its children registered by natural typechecking
procedures of the compiler. This meant that, in those cases, the Mirror
could not have been generated correctly, and macro could not obtain the
children of the class.

This was partially fixed in a previous PR by introducing a separate
procedure for querying children, outside of the regular typechecking
procedure. However, they was only queried in the owner symbol or in the
companion class, when non-enum sealed classes specifically, can
appear anywhere in the file. This commit aims to rectify this by
searching for any class that appears in the same file as the sealed
type.
  • Loading branch information
jchyb committed Sep 18, 2023
1 parent 1be790c commit 16a1ff1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
22 changes: 15 additions & 7 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1688,7 +1688,7 @@ object SymDenotations {
*/
def children(using Context): List[Symbol] =

def completeChildrenIn(owner: Symbol)(using Context) =
def completeChildrenIn(owner: Symbol, recursively: Boolean)(using Context): Unit =
// Possible children are: classes extending Scala classes and
// Scala or Java enum values that are defined in owner.
// If owner is a package, we complete only
Expand All @@ -1698,20 +1698,28 @@ object SymDenotations {
&& (!owner.is(Package)
|| sym.originDenotation.infoOrCompleter.match
case _: SymbolLoaders.SecondCompleter => sym.associatedFile == this.symbol.associatedFile
case _ => false)
case _: ClassInfo if recursively && sym.isValidInCurrentRun =>
sym.is(Package) || sym.associatedFile == this.symbol.associatedFile
case other => false)

if owner.isClass then
for c <- owner.info.decls.toList if maybeChild(c) do
c.ensureCompleted()
if recursively then completeChildrenIn(c, recursively)
end completeChildrenIn

if is(Sealed) || isAllOf(JavaEnumTrait) then
if !is(ChildrenQueried) then
// Make sure all visible children are completed, so that
// they show up in Child annotations. A possible child is visible if it
// is defined in the same scope as `cls` or in the companion object of `cls`.
completeChildrenIn(owner)
completeChildrenIn(companionClass)
if !is(Enum) then // non-enum sealed class
// Make sure all children are completed, so that
// they show up in Child annotations.
completeChildrenIn(defn.RootClass, recursively = true)
else
// Make sure all visible children are completed, so that
// they show up in Child annotations. A possible child is visible if it
// is defined in the same scope as `cls` or in the companion object of `cls`.
completeChildrenIn(owner, recursively = false)
completeChildrenIn(companionClass, recursively = false)
setFlag(ChildrenQueried)

annotations.collect { case Annotation.Child(child) => child }.reverse
Expand Down
11 changes: 11 additions & 0 deletions tests/pos/i18484/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
object Macro {
import scala.quoted.*

def subtypesImpl[A: Type](using quotes: Quotes): Expr[String] = {
import quotes.reflect.*
val a = TypeRepr.of[A].typeSymbol.children
'{""}
}

inline def subtypes[A]: String = ${ subtypesImpl[A] }
}
21 changes: 21 additions & 0 deletions tests/pos/i18484/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Test {
def test(): Unit = {
scala.compiletime.testing.typeCheckErrors("Macro.subtypes[top.inner.Inner.Shape]")
}
}

package top {
package inner {
object Inner:
sealed trait Shape
case class Circle(center: Int, rad: Double) extends Shape
object Inner2:
case class Circle2(center: Int, rad: Double) extends Shape
}
case class Circle3(center: Int, rad: Double) extends inner.Inner.Shape
}
case class Circle4(center: Int, rad: Double) extends top.inner.Inner.Shape

package top2 {
case class Circle5(center: Int, rad: Double) extends top.inner.Inner.Shape
}

0 comments on commit 16a1ff1

Please sign in to comment.