Skip to content

Commit 3c1ec5a

Browse files
nicolasstuckibiboudis
authored andcommitted
Fix #3847: Splice type splices in TypeTrees
1 parent 87d364c commit 3c1ec5a

File tree

6 files changed

+150
-27
lines changed

6 files changed

+150
-27
lines changed

compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala

Lines changed: 105 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
113113
*/
114114
val importedTags = new mutable.LinkedHashMap[TypeRef, Tree]()
115115

116+
val explicitTags = new mutable.LinkedHashSet[TypeRef]()
117+
116118
/** A stack of entered symbols, to be unwound after scope exit */
117119
var enteredSyms: List[Symbol] = Nil
118120

@@ -129,23 +131,69 @@ class ReifyQuotes extends MacroTransformWithImplicits {
129131
* as splices to `embedded`.
130132
*/
131133
private def addTags(expr: Tree)(implicit ctx: Context): Tree =
132-
if (importedTags.isEmpty) expr
134+
if (importedTags.isEmpty && explicitTags.isEmpty) expr
133135
else {
134136
val itags = importedTags.toList
137+
138+
println("addTags: expr: " + expr)
139+
println("addTags: tags: ")
140+
itags.foreach(println)
141+
135142
val typeDefs = for ((tref, tag) <- itags) yield {
136143
val rhs = transform(tag.select(tpnme.UNARY_~))
137144
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs)
138145
val original = tref.symbol.asType
139146
val local = original.copy(
140147
owner = ctx.owner,
148+
name = (original.name + "$$").toTypeName,
141149
flags = Synthetic,
142-
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~)))
143-
ctx.typeAssigner.assignType(untpd.TypeDef(original.name, alias), local)
150+
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~))).asType
151+
152+
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
144153
}
145154
importedTags.clear()
146-
Block(typeDefs,
147-
new TreeTypeMap(substFrom = itags.map(_._1.symbol), substTo = typeDefs.map(_.symbol))
155+
156+
157+
val explicitTypeDefs = for (tref <- explicitTags) yield {
158+
val tag = ref(tref.prefix.termSymbol)
159+
val rhs = transform(tag.select(tpnme.UNARY_~))
160+
161+
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs)
162+
163+
val local = ctx.newSymbol(
164+
owner = ctx.owner,
165+
name = UniqueName.fresh("ttt".toTermName).toTypeName,
166+
flags = Synthetic,
167+
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~)),
168+
coord = tref.prefix.termSymbol.coord).asType
169+
170+
(tref, ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local))
171+
}
172+
val map: Map[Type, Type] = explicitTypeDefs.map(x => (x._1, x._2.symbol.typeRef)).toMap
173+
174+
println()
175+
println(map)
176+
println()
177+
println()
178+
179+
val tMap = new TypeMap() {
180+
override def apply(tp: Type): Type = {
181+
if (map.contains(tp))
182+
map.apply(tp)
183+
else
184+
mapOver(tp)
185+
}
186+
}
187+
188+
val ret = Block(typeDefs ++ explicitTypeDefs.map(_._2),
189+
new TreeTypeMap(typeMap = tMap,
190+
substFrom = itags.map(_._1.symbol), substTo = typeDefs.map(_.symbol))
148191
.apply(expr))
192+
193+
println("addTags: ret: " + ret)
194+
println(ret.show)
195+
println()
196+
ret
149197
}
150198

151199
/** Enter staging level of symbol defined by `tree`, if applicable. */
@@ -181,26 +229,30 @@ class ReifyQuotes extends MacroTransformWithImplicits {
181229
* @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
182230
* to be added to the "inconsistent phase" message.
183231
*/
184-
def tryHeal(tp: Type, pos: Position)(implicit ctx: Context): Option[String] = tp match {
185-
case tp: TypeRef =>
186-
if (level == 0) {
187-
None
188-
} else {
189-
val reqType = defn.QuotedTypeType.appliedTo(tp)
190-
val tag = ctx.typer.inferImplicitArg(reqType, pos)
191-
tag.tpe match {
192-
case fail: SearchFailureType =>
193-
Some(i"""
194-
|
232+
def tryHeal(tp: Type, pos: Position)(implicit ctx: Context): Option[String] = {
233+
// println("tryHeal: " + tp)
234+
tp match {
235+
case tp: TypeRef =>
236+
if (level == 0) {
237+
None
238+
} else {
239+
val reqType = defn.QuotedTypeType.appliedTo(tp)
240+
val tag = ctx.typer.inferImplicitArg(reqType, pos)
241+
tag.tpe match {
242+
case fail: SearchFailureType =>
243+
Some(
244+
i"""
245+
|
195246
| The access would be accepted with the right type tag, but
196-
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
197-
case _ =>
198-
importedTags(tp) = nested(isQuote = false).transform(tag)
199-
None
247+
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
248+
case _ =>
249+
importedTags(tp) = nested(isQuote = false).transform(tag)
250+
None
251+
}
200252
}
201-
}
202-
case _ =>
203-
Some("")
253+
case _ =>
254+
Some("")
255+
}
204256
}
205257

206258
/** Check reference to `sym` for phase consistency, where `tp` is the underlying type
@@ -225,8 +277,11 @@ class ReifyQuotes extends MacroTransformWithImplicits {
225277
def checkType(pos: Position)(implicit ctx: Context): TypeAccumulator[Unit] = new TypeAccumulator[Unit] {
226278
def apply(acc: Unit, tp: Type): Unit = reporting.trace(i"check type level $tp at $level") {
227279
tp match {
228-
case tp: NamedType if tp.symbol.isSplice =>
229-
if (inQuote) outer.checkType(pos).foldOver(acc, tp)
280+
case tp: TypeRef if tp.symbol.isSplice =>
281+
if (inQuote) {
282+
explicitTags += tp
283+
outer.checkType(pos).foldOver(acc, tp)
284+
}
230285
else {
231286
if (tp.isTerm) spliceOutsideQuotes(pos)
232287
tp
@@ -291,6 +346,13 @@ class ReifyQuotes extends MacroTransformWithImplicits {
291346
}
292347
else {
293348
val (body1, splices) = nested(isQuote = true).split(body)
349+
350+
// println()
351+
// println("for quote: " + quote)
352+
// println("body: " + body1)
353+
// println("bodys: " + body1.show)
354+
355+
//splices.foreach(println)
294356
pickledQuote(body1, splices, isType).withPos(quote.pos)
295357
}
296358
}
@@ -333,6 +395,12 @@ class ReifyQuotes extends MacroTransformWithImplicits {
333395
}
334396
else {
335397
val (body1, quotes) = nested(isQuote = false).split(splice.qualifier)
398+
// println()
399+
// println("for splice: " + splice)
400+
// println("body: " + body1)
401+
// println("bodys: " + body1.show)
402+
//
403+
// quotes.foreach(println)
336404
makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
337405
}
338406
}
@@ -432,7 +500,19 @@ class ReifyQuotes extends MacroTransformWithImplicits {
432500
tree match {
433501
case Quoted(quotedTree) =>
434502
quotation(quotedTree, tree)
503+
case tree: TypeTree if tree.tpe.typeSymbol.isSplice =>
504+
val splicedType = tree.tpe.asInstanceOf[TypeRef].prefix.termSymbol
505+
val ret = splice(ref(splicedType).select(tpnme.UNARY_~))
506+
// println()
507+
// println("TypeTree: " + tree)
508+
// println("TypeTrees: " + tree.show)
509+
// println("TypeTree ret: " + ret)
510+
// println("TypeTree rets: " + ret.show)
511+
ret
512+
case tree: TypeApply =>
513+
super.transform(tree)
435514
case tree: Select if tree.symbol.isSplice =>
515+
// println("Select: " + tree)
436516
splice(tree)
437517
case tree: RefTree if needsLifting(tree) =>
438518
val lift = lifters(tree.symbol)
@@ -441,7 +521,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
441521
val last = enteredSyms
442522
stats.foreach(markDef)
443523
mapOverTree(last)
444-
445524
case Inlined(call, bindings, InlineSplice(expansion @ Select(body, name))) =>
446525
// To maintain phase consistency, we move the binding of the this parameter into the spliced code
447526
val (splicedBindings, stagedBindings) = bindings.partition {

project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ object Build {
6464

6565

6666
val agentOptions = List(
67-
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
67+
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
6868
// "-agentpath:/home/dark/opt/yjp-2013-build-13072/bin/linux-x86-64/libyjpagent.so"
6969
// "-agentpath:/Applications/YourKit_Java_Profiler_2015_build_15052.app/Contents/Resources/bin/mac/libyjpagent.jnilib",
7070
// "-XX:+HeapDumpOnOutOfMemoryError", "-Xmx1g", "-Xss2m"

tests/run-with-compiler/i3847-b.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
dotty.runtime.Arrays.newGenericArray[Int](3)(reflect.ClassTag.Int)
3+
}

tests/run-with-compiler/i3847-b.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import dotty.tools.dotc.quoted.Toolbox._
2+
import scala.quoted._
3+
import scala.reflect.ClassTag
4+
5+
object Arrays {
6+
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], ct: Expr[ClassTag[T]]): Liftable[Array[List[T]]] = (arr: Array[List[T]]) => '{
7+
new Array[List[~t]](3)
8+
// TODO add elements
9+
}
10+
}
11+
12+
object Test {
13+
def main(args: Array[String]): Unit = {
14+
import Arrays._
15+
implicit val ct: Expr[ClassTag[Int]] = '(ClassTag.Int)
16+
val arr: Expr[Array[List[Int]]] = Array[List[Int]](List(1, 2, 3))
17+
println(arr.show)
18+
}
19+
}

tests/run-with-compiler/i3847.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
dotty.runtime.Arrays.newGenericArray[Int](3)(reflect.ClassTag.Int)
3+
}

tests/run-with-compiler/i3847.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import dotty.tools.dotc.quoted.Toolbox._
2+
import scala.quoted._
3+
import scala.reflect.ClassTag
4+
5+
object Arrays {
6+
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], ct: Expr[ClassTag[T]]): Liftable[Array[T]] = (arr: Array[T]) => '{
7+
new Array[~t](~(arr.length: Expr[Int]))(~ct)
8+
// TODO add elements
9+
}
10+
}
11+
12+
object Test {
13+
def main(args: Array[String]): Unit = {
14+
import Arrays._
15+
implicit val ct: Expr[ClassTag[Int]] = '(ClassTag.Int)
16+
val arr: Expr[Array[Int]] = Array[Int](1, 2, 3)
17+
println(arr.show)
18+
}
19+
}

0 commit comments

Comments
 (0)