Skip to content

Commit 3e3bb1d

Browse files
committed
wip WIP wip
1 parent 6b1bce3 commit 3e3bb1d

20 files changed

+334
-44
lines changed

compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import dotty.tools.dotc.core.tasty.{ PositionPickler, TastyPickler, TastyPrinter
1616
import dotty.tools.dotc.core.tasty.TreeUnpickler.UnpickleMode
1717
import dotty.tools.dotc.quoted.QuoteContext
1818
import dotty.tools.dotc.tastyreflect.{ReflectionImpl, TastyTreeExpr, TreeType}
19+
import dotty.tools.dotc.util.Spans.NoSpan
1920

2021
import dotty.tools.tasty.TastyString
2122

@@ -61,19 +62,91 @@ object PickledQuotes {
6162
}.apply(tp)
6263

6364
/** Unpickle the tree contained in the TastyExpr */
64-
def unpickleExpr(tasty: PickledQuote, args: PickledArgs)(implicit ctx: Context): Tree = {
65+
def unpickleExpr(tasty: PickledQuote, splices: PickledArgs)(implicit ctx: Context): Tree = {
6566
val tastyBytes = TastyString.unpickle(tasty)
66-
val unpickled = unpickle(tastyBytes, args, isType = false)(ctx.addMode(Mode.ReadPositions))
67+
val unpickled = unpickle(tastyBytes, splices, isType = false)(ctx.addMode(Mode.ReadPositions))
6768
/** Force unpickling of the tree, removes the spliced type `@quotedTypeTag type` definitions and dealiases references to `@quotedTypeTag type` */
68-
val forceAndCleanArtefacts = new TreeMap {
69-
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
69+
70+
if ctx.settings.YprintDebug.value then
71+
72+
73+
val Inlined(call, Nil, expnasion) = unpickled
74+
75+
val (typeSpliceMap, expnasion1) = expnasion match
7076
case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
71-
assert(rest.forall { case tdef: TypeDef => tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) })
72-
transform(expr1)
73-
case tree => super.transform(tree).withType(dealiasTypeTags(tree.tpe))
77+
val map = (stat :: rest).iterator.map {
78+
case tdef: TypeDef =>
79+
assert(tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot))
80+
val TypeBoundsTree(_, Hole(_, idx, args), _) = tdef.rhs
81+
val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.Type[?]](args)
82+
val tree = PickledQuotes.quotedTypeToTree(quotedType)
83+
(tdef.symbol, tree.tpe)
84+
}.toMap
85+
(map, expr1)
86+
case _ => (Map.empty, expnasion)
87+
88+
def spliceTypes(tp: Type)(implicit ctx: Context): Type = new TypeMap() {
89+
override def apply(tp: Type): Type = {
90+
val tp1 = tp match {
91+
case tp: TypeRef if tp.typeSymbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
92+
typeSpliceMap(tp.symbol)
93+
case _ => tp
94+
}
95+
mapOver(tp1)
96+
}
97+
}.apply(tp)
98+
// println("::::::::::::::::::::::::::::::::::::")
99+
// println(typeSpliceMap)
100+
// println()
101+
// println()
102+
103+
val evaluateHoles = new TreeMap {
104+
// private var typeSpliceMap = Map.empty[Symbol, Type]
105+
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
106+
// case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
107+
// val splicedTypes = (stat :: rest).map {
108+
// case tdef: TypeDef =>
109+
// assert(tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot))
110+
// val TypeBoundsTree(_, hi, _) = transform(tdef.rhs)
111+
// (tdef.symbol, hi.tpe)
112+
// }
113+
// typeSpliceMap = splicedTypes.toMap
114+
// transform(expr1)
115+
case Hole(isType, idx, args) =>
116+
assert(!isType)
117+
val splice = splices(idx)
118+
def wrap(arg: Tree) =
119+
if (arg.isTerm) (qctx: scala.quoted.QuoteContext) ?=> new TastyTreeExpr(arg, QuoteContext.scopeId)
120+
else new TreeType(arg, QuoteContext.scopeId)
121+
val reifiedArgs = args.map(wrap)
122+
123+
val splice1 = splice.asInstanceOf[Seq[Any] => scala.quoted.QuoteContext ?=> quoted.Expr[?]]
124+
val quotedExpr = splice1(reifiedArgs)(using dotty.tools.dotc.quoted.QuoteContext())
125+
val filled = PickledQuotes.quotedExprToTree(quotedExpr)
126+
127+
// We need to make sure a hole is created with the source file of the surrounding context, even if
128+
// it filled with contents a different source file.
129+
if (filled.source == ctx.source) filled
130+
else filled.cloneIn(ctx.source)
131+
132+
// super.transform(tree).withType(dealiasTypeTags(tree.tpe))
133+
case tree =>
134+
super.transform(tree).withType(spliceTypes(tree.tpe))
135+
}
74136
}
75-
}
76-
forceAndCleanArtefacts.transform(unpickled)
137+
val evaluatedExpansion = evaluateHoles.transform(expnasion1)(inlineContext(call))
138+
cpy.Inlined(unpickled)(call, Nil, evaluatedExpansion)
139+
else
140+
val forceAndCleanArtefacts = new TreeMap {
141+
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
142+
case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
143+
assert(rest.forall { case tdef: TypeDef => tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) })
144+
transform(expr1)
145+
case tree => super.transform(tree).withType(dealiasTypeTags(tree.tpe))
146+
}
147+
}
148+
forceAndCleanArtefacts.transform(unpickled)
149+
77150
}
78151

79152
/** Unpickle the tree contained in the TastyType */

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,15 @@ class TreePickler(pickler: TastyPickler) {
599599
pickleTree(alias)
600600
}
601601
case Hole(_, idx, args) =>
602+
lazy val erasedSplicesType = new TypeMap() {
603+
override def apply(tp: Type): Type = tp match {
604+
case tp: TypeRef if tp.typeSymbol.isSplice || tp.typeSymbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) => tp.dealias.typeSymbol.info.hiBound
605+
case tp =>
606+
mapOver(tp)
607+
}
608+
}
609+
val tpe = erasedSplicesType(tree.tpe)
610+
602611
writeByte(HOLE)
603612
withLength {
604613
writeNat(idx)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,33 +1291,45 @@ class TreeUnpickler(reader: TastyReader,
12911291
}
12921292

12931293
def readHole(end: Addr, isType: Boolean)(implicit ctx: Context): Tree = {
1294-
val idx = readNat()
1295-
val tpe = readType()
1296-
val args = until(end)(readTerm())
1297-
val splice = splices(idx)
1298-
def wrap(arg: Tree) =
1299-
if (arg.isTerm) (qctx: scala.quoted.QuoteContext) ?=> new TastyTreeExpr(arg, QuoteContext.scopeId)
1300-
else new TreeType(arg, QuoteContext.scopeId)
1301-
val reifiedArgs = args.map(wrap)
1302-
val filled = if (isType) {
1303-
val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[?]](reifiedArgs)
1304-
PickledQuotes.quotedTypeToTree(quotedType)
1305-
}
1306-
else {
1307-
val splice1 = splice.asInstanceOf[Seq[Any] => scala.quoted.QuoteContext ?=> quoted.Expr[?]]
1308-
val quotedExpr = splice1(reifiedArgs)(using dotty.tools.dotc.quoted.QuoteContext())
1309-
PickledQuotes.quotedExprToTree(quotedExpr)
1310-
}
1311-
// We need to make sure a hole is created with the source file of the surrounding context, even if
1312-
// it filled with contents a different source file. Otherwise nodes containing holes might end
1313-
// up without a position. PositionPickler makes sure that holes always get spans assigned,
1314-
// so we can just return the filler tree with the new source and no span here.
1315-
if (filled.source == ctx.source) filled
1316-
else {
1317-
val filled1 = filled.cloneIn(ctx.source)
1318-
filled1.span = NoSpan
1319-
filled1
1320-
}
1294+
if ctx.settings.YprintDebug.value then
1295+
val idx = readNat()
1296+
val tpe = readType()
1297+
val args = until(end)(readTerm())
1298+
TreePickler.Hole(isType, idx, args).withType(tpe)
1299+
else
1300+
val idx = readNat()
1301+
val tpe = readType() // FIXME use to set type to the unpickled tree
1302+
val args = until(end)(readTerm())
1303+
val splice = splices(idx)
1304+
// println("++++++++++++++++++++++++++++++=")
1305+
// println(tpe.show)
1306+
// println(isType)
1307+
// println()
1308+
// println()
1309+
def wrap(arg: Tree) =
1310+
if (arg.isTerm) (qctx: scala.quoted.QuoteContext) ?=> new TastyTreeExpr(arg, QuoteContext.scopeId)
1311+
else new TreeType(arg, QuoteContext.scopeId)
1312+
val reifiedArgs = args.map(wrap)
1313+
val filled = if (isType) {
1314+
val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[?]](reifiedArgs)
1315+
PickledQuotes.quotedTypeToTree(quotedType)
1316+
}
1317+
else {
1318+
val splice1 = splice.asInstanceOf[Seq[Any] => scala.quoted.QuoteContext ?=> quoted.Expr[?]]
1319+
val quotedExpr = splice1(reifiedArgs)(using dotty.tools.dotc.quoted.QuoteContext())
1320+
val a = PickledQuotes.quotedExprToTree(quotedExpr)
1321+
a.ensureConforms(tpe).withSpan(a.span)
1322+
}
1323+
// We need to make sure a hole is created with the source file of the surrounding context, even if
1324+
// it filled with contents a different source file. Otherwise nodes containing holes might end
1325+
// up without a position. PositionPickler makes sure that holes always get spans assigned,
1326+
// so we can just return the filler tree with the new source and no span here.
1327+
if (filled.source == ctx.source) filled
1328+
else {
1329+
val filled1 = filled.cloneIn(ctx.source)
1330+
filled1.span = NoSpan
1331+
filled1
1332+
}
13211333
}
13221334

13231335
// ------ Setting positions ------------------------------------------------

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
100100

101101
@Test def negMacros: Unit = {
102102
implicit val testGroup: TestGroup = TestGroup("compileNegWithCompiler")
103-
compileFilesInDir("tests/neg-macros", defaultOptions).checkExpectedErrors()
103+
compileFilesInDir("tests/neg-macros", defaultOptions and "-Yprint-debug").checkExpectedErrors()
104104
}
105105

106106
@Test def negWithCompiler: Unit = {
@@ -116,17 +116,17 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
116116
@Test def runMacros: Unit = {
117117
implicit val testGroup: TestGroup = TestGroup("runMacros")
118118
aggregateTests(
119-
compileFilesInDir("tests/run-macros", defaultOptions),
120-
compileFilesInDir("tests/run-custom-args/Yretain-trees", defaultOptions and "-Yretain-trees"),
121-
compileFilesInDir("tests/run-custom-args/run-macros-erased", defaultOptions and "-Yerased-terms"),
119+
compileFilesInDir("tests/run-macros", defaultOptions and "-Yprint-debug"),
120+
compileFilesInDir("tests/run-custom-args/Yretain-trees", defaultOptions and "-Yretain-trees" and "-Yprint-debug"),
121+
compileFilesInDir("tests/run-custom-args/run-macros-erased", defaultOptions and "-Yerased-terms" and "-Yprint-debug"),
122122
)
123123
}.checkRuns()
124124

125125
@Test def runWithCompiler: Unit = {
126126
implicit val testGroup: TestGroup = TestGroup("runWithCompiler")
127127
aggregateTests(
128128
compileFilesInDir("tests/run-with-compiler", withCompilerOptions),
129-
compileFilesInDir("tests/run-staging", withStagingOptions),
129+
compileFilesInDir("tests/run-staging", withStagingOptions and "-Yprint-debug"),
130130
compileFilesInDir("tests/run-custom-args/tasty-inspector", withTastyInspectorOptions),
131131
compileDir("tests/run-custom-args/tasty-interpreter", withTastyInspectorOptions),
132132
).checkRuns()

tests/neg-macros/delegate-match-1.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
6 | f // error
44
| ^
55
| AmbiguousImplicits
6-
| both value a1 in class Test1 and value a2 in class Test1 match type A
6+
| both value a1 in class Test1 and value a2 in class Test1 match type <empty>.this.A
77
| This location contains code that was inlined from Test_2.scala:6

tests/neg-macros/delegate-match-2.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
5 | f // error
44
| ^
55
| DivergingImplicit
6-
| method a1 in class Test produces a diverging implicit search when trying to match type A
6+
| method a1 in class Test produces a diverging implicit search when trying to match type <empty>.this.A
77
| This location contains code that was inlined from Test_2.scala:5

tests/neg-macros/delegate-match-3.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
3 | f // error
44
| ^
55
| NoMatchingImplicits
6-
| no implicit values were found that match type A
6+
| no implicit values were found that match type <empty>.this.A
77
| This location contains code that was inlined from Test_2.scala:3

tests/pos-macros/i7110a/Macro_1.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
5+
inline def m[R](sym: Symantics[R]) : R = ${ mImpl[R]('{sym}) }
6+
7+
def mImpl[R: Type](using qctx: QuoteContext)(sym: Expr[Symantics[R]]): Expr[R] = '{
8+
$sym.Meth(42)
9+
}
10+
}
11+
12+
trait Symantics[R] {
13+
def Meth(exp: Int): R
14+
def Meth(): R
15+
}

tests/pos-macros/i7110a/Test_2.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
object Test {
5+
def main(args: Array[String]): Unit = {
6+
7+
val sym = new Symantics[Int] {
8+
def Meth(exp: Int): Int = exp
9+
def Meth(): Int = 42
10+
}
11+
12+
val test = m[Int](sym)
13+
}
14+
}

tests/pos-macros/i7110b/Macro_1.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
5+
inline def m[T](sym: Symantics {type R = T}) : T = ${ mImpl[T]('{sym}) }
6+
7+
def mImpl[T: Type](using qctx: QuoteContext)(sym: Expr[Symantics { type R = T }]): Expr[T] = '{
8+
$sym.Meth(42)
9+
}
10+
}
11+
12+
trait Symantics {
13+
type R
14+
def Meth(exp: Int): R
15+
def Meth(): R
16+
}

tests/pos-macros/i7110b/Test_2.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
object Test {
5+
def main(args: Array[String]): Unit = {
6+
7+
val sym = new Symantics {
8+
type R = Int
9+
def Meth(exp: Int): Int = exp
10+
def Meth(): Int = 42
11+
}
12+
13+
val test = m(sym)
14+
}
15+
}

tests/pos-macros/i7110c/Macro_1.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
5+
inline def m[R](sym: Symantics[R]) : R = ${ mImpl[R]('{sym}) }
6+
7+
def mImpl[R: Type](using qctx: QuoteContext)(sym: Expr[Symantics[R]]): Expr[R] = '{
8+
$sym.Meth(42)
9+
}
10+
}
11+
12+
trait Symantics[R] {
13+
def Meth(exp: Int): R
14+
}

tests/pos-macros/i7110c/Test_2.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
object Test {
5+
def main(args: Array[String]): Unit = {
6+
7+
val sym = new Symantics2
8+
9+
val test = m[Int](sym)
10+
}
11+
}
12+
13+
class Symantics2 extends Symantics[Int] {
14+
def Meth(exp: Int): Int = exp
15+
def Meth(): Int = 42
16+
}

tests/pos-macros/i7110d/Macro_1.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
5+
inline def m(sym: Symantics) : Int = ${ mImpl('sym) }
6+
7+
def mImpl(using qctx: QuoteContext)(sym: Expr[Symantics]): Expr[Int] = '{
8+
$sym.Meth(42)
9+
}
10+
}
11+
12+
trait Symantics {
13+
def Meth(exp: Int): Int
14+
}

tests/pos-macros/i7110d/Test_2.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted._
2+
import Macros._
3+
4+
object Test {
5+
def main(args: Array[String]): Unit = {
6+
7+
val sym = new Symantics2
8+
9+
val test = m(sym)
10+
}
11+
}
12+
13+
class Symantics2 extends Symantics {
14+
def Meth(exp: Int): Int = exp
15+
def Meth(): Int = 42
16+
}

tests/pos-macros/i7110e/Macro_1.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
3+
object Macros {
4+
5+
inline def m(sym: Symantics, x: Int) : Int = ${ mImpl('sym, 'x) }
6+
7+
def mImpl(using qctx: QuoteContext)(sym: Expr[Symantics], x: Expr[Int]): Expr[Int] = '{
8+
$sym.Meth($x)
9+
}
10+
}
11+
12+
trait Symantics {
13+
def Meth[R](exp: R): Int
14+
def Meth(): Int
15+
}

0 commit comments

Comments
 (0)