Skip to content

Fix #9069: Complete children of sealed classes early #9083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ object Flags {
val (_, DefaultMethod @ _, _) = newFlags(38, "<defaultmethod>")

/** Symbol is an enum class or enum case (if used with case) */
val (Enum @ _, _, _) = newFlags(40, "enum")
val (Enum @ _, EnumVal @ _, _) = newFlags(40, "enum")

/** An export forwarder */
val (Exported @ _, _, _) = newFlags(41, "exported")
Expand Down Expand Up @@ -530,7 +530,7 @@ object Flags {
val DeferredOrLazyOrMethod: FlagSet = Deferred | Lazy | Method
val DeferredOrTermParamOrAccessor: FlagSet = Deferred | ParamAccessor | TermParam // term symbols without right-hand sides
val DeferredOrTypeParam: FlagSet = Deferred | TypeParam // type symbols without right-hand sides
val EnumValue: FlagSet = Enum | StableRealizable // A Scala enum value
val EnumValue: FlagSet = Enum | StableRealizable // A Scala enum value
val StableOrErased: FlagSet = Erased | StableRealizable // Assumed to be pure
val ExtensionMethod: FlagSet = Extension | Method
val FinalOrInline: FlagSet = Final | Inline
Expand Down
33 changes: 33 additions & 0 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,39 @@ object SymDenotations {
if (is(Private))
copySymDenotation(name = expandedName, initFlags = this.flags &~ Private)
else this

/** If this is a sealed class, its known children in the order of textual occurrence
*/
def children(using Context): List[Symbol] =

def completeChildrenIn(owner: Symbol)(using Context) =
// 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
// children that are defined in the same file as their parents.
def maybeChild(sym: Symbol) =
(sym.isClass && !this.is(JavaDefined) || sym.originDenotation.is(EnumVal))
&& !owner.is(Package)
|| sym.originDenotation.infoOrCompleter.match
case _: SymbolLoaders.SecondCompleter => sym.associatedFile == this.symbol.associatedFile
case _ => false

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

if is(Sealed) 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)
setFlag(ChildrenQueried)

annotations.collect { case Annotation.Child(child) => child }.reverse
end children
}

/** The contents of a class definition during a period
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1780,7 +1780,7 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
}

def Symbol_children(self: Symbol)(using ctx: Context): List[Symbol] =
dotty.tools.dotc.transform.SymUtils(self).children
self.children

private def isField(sym: Symbol)(using ctx: Context): Boolean = sym.isTerm && !sym.is(Flags.Method)

Expand Down
15 changes: 1 addition & 14 deletions compiler/src/dotty/tools/dotc/transform/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,21 +188,8 @@ class SymUtils(val self: Symbol) extends AnyVal {
|| sym.isType && isAccessible(sym.owner, cls)
!isAccessible(self.owner, cls)

/** If this is a sealed class, its known children in the order of textual occurrence */
def children(implicit ctx: Context): List[Symbol] = {
if (self.isType)
self.setFlag(ChildrenQueried)

if (self.isAllOf(JavaEnumTrait))
self.linkedClass.info.decls.foreach(_.ensureCompleted())

self.annotations.collect {
case Annotation.Child(child) => child
}.reverse
}

def hasAnonymousChild(implicit ctx: Context): Boolean =
children.exists(_ `eq` self)
self.children.exists(_ `eq` self)

/** Is symbol directly or indirectly owned by a term symbol? */
@tailrec final def isLocal(implicit ctx: Context): Boolean = {
Expand Down
3 changes: 3 additions & 0 deletions tests/pos/i9069/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def Test =
val mirror = summon[deriving.Mirror.SumOf[Foo]]
summon[mirror.MirroredElemTypes =:= (Foo.Baz.type, Bar)]
4 changes: 4 additions & 0 deletions tests/pos/i9069/Wrapper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
sealed trait Foo
object Foo:
case object Baz extends Foo
case class Bar(x: Int) extends Foo
8 changes: 4 additions & 4 deletions tests/run-staging/i6281.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import scala.quoted._
import scala.quoted.staging._

object Test extends App {
sealed trait HList
sealed trait HNil extends HList
sealed trait ::[E, T <: HList] extends HList

sealed trait HList
sealed trait HNil extends HList
sealed trait ::[E, T <: HList] extends HList
object Test extends App {

type STM[A, L <: HList] = L match {
case HNil => Expr[A]
Expand Down