forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide mirror support after inlining
Mirror support runs in PostTyper to add new members to mirrors generated during Typer. But some anonymous mirrors are generated during inlining. We need to add the missing methods for them as well. Fixes scala#11542 Fixes scala#11961 Fixes scala#12052
- Loading branch information
Showing
10 changed files
with
158 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
compiler/src/dotty/tools/dotc/transform/PostInlining.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package dotty.tools.dotc | ||
package transform | ||
|
||
import core._ | ||
import Contexts.* | ||
import DenotTransformers.IdentityDenotTransformer | ||
import Decorators.* | ||
import ast.tpd.* | ||
|
||
/** A phase that adds mirror support for anonymous mirrors created at inlining. */ | ||
class PostInlining extends MacroTransform, IdentityDenotTransformer: | ||
thisPhase => | ||
|
||
override def phaseName: String = PostInlining.name | ||
override def changesMembers = true | ||
|
||
override def run(using Context): Unit = | ||
if ctx.compilationUnit.needsMirrorSupport then super.run | ||
|
||
lazy val synthMbr: SyntheticMembers = new SyntheticMembers(thisPhase) | ||
|
||
def newTransformer(using Context): Transformer = new Transformer: | ||
override def transform(tree: Tree)(using Context): Tree = | ||
super.transform(tree) match | ||
case tree1: Template => synthMbr.addMirrorSupport(tree1) | ||
case tree1 => tree1 | ||
|
||
object PostInlining: | ||
val name: String = "postInlining" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
object demo { | ||
|
||
trait Reader[A] | ||
|
||
given Reader[Int] with {} | ||
|
||
inline def summonReader[T <: Tuple]: List[Reader[_]] = inline compiletime.erasedValue[T] match { | ||
case _: EmptyTuple => Nil | ||
case _: (t *: ts) => compiletime.summonInline[Reader[t]] :: summonReader[ts] | ||
} | ||
|
||
class CombinedReader[A]( | ||
m: deriving.Mirror.ProductOf[A], | ||
childReaders: List[Reader[_]] | ||
) extends Reader[A] | ||
|
||
inline given rdr[A <: Tuple](using m: deriving.Mirror.ProductOf[A]): Reader[A] = { | ||
new CombinedReader(m, summonReader[m.MirroredElemTypes]) | ||
} | ||
|
||
} | ||
|
||
@main def Test() = { | ||
// OK | ||
//summon[demo.Reader[(Int, Int, Int)]] | ||
|
||
// Exception in thread "main" java.lang.ClassCastException: class main$package$$anon$2 cannot be cast to class scala.deriving.Mirror$Product (main$package$$anon$2 and scala.deriving.Mirror$Product are in unnamed module of loader 'app') | ||
// at main$package$.run(main.scala:25) | ||
// at run.main(main.scala:23) | ||
summon[demo.Reader[(Int, (Int, Int))]] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
type Foo = Tuple2[Int, Int] | ||
// case class Foo(x: Int, y: Int) // works | ||
class Reader(m: deriving.Mirror.ProductOf[Foo]) | ||
given reader1(using m: deriving.Mirror.ProductOf[Foo]): Reader = new Reader(m) | ||
inline def summonReader(): Reader = compiletime.summonInline[Reader] | ||
@main def Test() = summonReader() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
STRING | ||
BOOLEAN | ||
STRING | ||
BOOLEAN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import scala.deriving.* | ||
import scala.compiletime.{erasedValue, summonInline} | ||
|
||
case class Simple(a: String, b: Boolean) derives Printable | ||
case class SimpleT(a: (String, Boolean)) derives Printable | ||
|
||
@main def Test: Unit = { | ||
|
||
summon[Printable[Simple]].print // Prints STRING BOOLEAN as expected | ||
|
||
summon[Printable[SimpleT]].print // java.lang.ClassCastException: SimpleT$$anon$1 cannot be cast to scala.deriving.Mirror$Product | ||
|
||
} | ||
|
||
trait Printable[T]: | ||
def print: Unit | ||
|
||
object Printable: | ||
|
||
given Printable[String] with | ||
def print: Unit = println("STRING") | ||
|
||
given Printable[Boolean] with | ||
def print: Unit = println("BOOLEAN") | ||
|
||
def printProduct[T](p: Mirror.ProductOf[T], elems: => List[Printable[_]]): Printable[T] = | ||
new Printable[T]: | ||
def print: Unit = | ||
elems.foreach(_.print) | ||
|
||
inline given derived[T](using m: Mirror.Of[T]): Printable[T] = | ||
val elemInstances = summonAllPrintable[m.MirroredElemTypes] | ||
inline m match | ||
case p: Mirror.ProductOf[T] => printProduct(p, elemInstances) | ||
|
||
end Printable | ||
|
||
inline def summonAllPrintable[T <: Tuple]: List[Printable[_]] = | ||
inline erasedValue[T] match | ||
case _: EmptyTuple => Nil | ||
case _: (t *: ts) => summonInline[Printable[t]] :: summonAllPrintable[ts] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import scala.quoted._ | ||
import scala.deriving._ | ||
import scala.compiletime.{erasedValue, constValue, summonFrom, summonInline} | ||
|
||
class MyContext { | ||
implicit inline def autoMirrorType[T]: MirrorType[T] = MirrorType.generic | ||
} | ||
|
||
trait MirrorType[T] { | ||
def mirrorType: String | ||
} | ||
|
||
object MirrorType { | ||
class Container[T] | ||
|
||
inline def decode[T]: String = | ||
summonFrom { | ||
case ev: Mirror.ProductOf[T] => | ||
s"Product-${new Container[ev.MirroredElemLabels]}" // This is the part that splices in the cast | ||
case m: Mirror.SumOf[T] => | ||
"Sum" | ||
} | ||
|
||
inline def generic[T]: MirrorType[T] = | ||
new MirrorType[T] { | ||
def mirrorType: String = decode[T] | ||
} | ||
|
||
extension[T](inline value: T) | ||
inline def mirrorType = summonFrom { | ||
case mt: MirrorType[T] => mt.mirrorType | ||
case _ => "mirror not found" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import MirrorType._ | ||
object Test { | ||
def main(args: Array[String]): Unit = { | ||
val ctx = new MyContext(); | ||
import ctx._ | ||
val tup = ("foo", 1) | ||
assert(tup.mirrorType.isInstanceOf[String]) | ||
} | ||
} |