Skip to content
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

[Backport] Fix 13777: Tighten check to cache Mirror.Sum in companion #14100

Merged
merged 1 commit into from Dec 14, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 15 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/SymUtils.scala
Expand Up @@ -112,7 +112,19 @@ object SymUtils:
self.isCoDefinedGiven(res.typeSymbol)
self.isAllOf(Given | Method) && isCodefined(self.info)

def useCompanionAsMirror(using Context): Boolean = self.linkedClass.exists && !self.is(Scala2x)
def useCompanionAsSumMirror(using Context): Boolean =
self.linkedClass.exists
&& !self.is(Scala2x)
&& (
// If the sum type is compiled from source, and `self` is a "generic sum"
// then its companion object will become a sum mirror in `posttyper`. (This method
// can be called from `typer` when summoning a Mirror.)
// However if `self` is from a prior run then we should check that its companion subclasses `Mirror.Sum`.
// e.g. before Scala 3.1, hierarchical sum types were not considered "generic sums", so their
// companion would not cache the mirror. Companions from TASTy will already be typed as `Mirror.Sum`.
self.isDefinedInCurrentRun
|| self.linkedClass.isSubClass(defn.Mirror_SumClass)
)

/** Is this a sealed class or trait for which a sum mirror is generated?
* It must satisfy the following conditions:
Expand All @@ -129,7 +141,7 @@ object SymUtils:
s"it is not an abstract class"
else {
val children = self.children
val companionMirror = self.useCompanionAsMirror
val companionMirror = self.useCompanionAsSumMirror
assert(!(companionMirror && (declScope ne self.linkedClass)))
def problem(child: Symbol) = {

Expand All @@ -144,7 +156,7 @@ object SymUtils:
val s = child.whyNotGenericProduct
if (s.isEmpty) s
else if (child.is(Sealed)) {
val s = child.whyNotGenericSum(if child.useCompanionAsMirror then child.linkedClass else ctx.owner)
val s = child.whyNotGenericSum(if child.useCompanionAsSumMirror then child.linkedClass else ctx.owner)
if (s.isEmpty) s
else i"its child $child is not a generic sum because $s"
} else i"its child $child is not a generic product because $s"
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
Expand Up @@ -279,7 +279,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):

private def sumMirror(mirroredType: Type, formal: Type, span: Span)(using Context): Tree =
val cls = mirroredType.classSymbol
val useCompanion = cls.useCompanionAsMirror
val useCompanion = cls.useCompanionAsSumMirror

if cls.isGenericSum(if useCompanion then cls.linkedClass else ctx.owner) then
val elemLabels = cls.children.map(c => ConstantType(Constant(c.name.toString)))
Expand Down
@@ -0,0 +1,8 @@
package app

import scala.deriving.Mirror

object Main:
def main(args: Array[String]): Unit =
val mirrorTop = summon[Mirror.SumOf[lib.Top]]
assert(mirrorTop.ordinal(lib.Middle()) == 0)
7 changes: 7 additions & 0 deletions sbt-test/scala3-backcompat/hierarchical-mirrors/build.sbt
@@ -0,0 +1,7 @@
lazy val lib = project.in(file("lib"))
.settings(
scalaVersion := "3.0.2"
)

lazy val app = project.in(file("app"))
.dependsOn(lib)
7 changes: 7 additions & 0 deletions sbt-test/scala3-backcompat/hierarchical-mirrors/lib/Top.scala
@@ -0,0 +1,7 @@
package lib

sealed trait Top
object Top // companion is necessary

case class Middle() extends Top with Bottom
sealed trait Bottom extends Top
@@ -0,0 +1,11 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := sys.props("plugin.scalaVersion")
)
}
1 change: 1 addition & 0 deletions sbt-test/scala3-backcompat/hierarchical-mirrors/test
@@ -0,0 +1 @@
> app/run