Skip to content

Commit f7b179c

Browse files
committed
Fix #3847: handles correctly splicing of (possibly) nested parameter types
1 parent 4b63dc6 commit f7b179c

File tree

5 files changed

+51
-39
lines changed

5 files changed

+51
-39
lines changed

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

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,15 @@ class ReifyQuotes extends MacroTransformWithImplicits {
108108
val embedded = new mutable.ListBuffer[Tree]
109109

110110
/** A map from type ref T to expressions of type `quoted.Type[T]`".
111-
* These will be turned into splices using `addTags`
111+
* These will be turned into splices using `addTags` and represent type variables
112+
* that can be possibly healed.
112113
*/
113114
val importedTags = new mutable.LinkedHashMap[TypeRef, Tree]()
114115

116+
/** A map from type ref T to expressions of type `quoted.Type[T]`" like `importedTags`
117+
* These will be turned into splices using `addTags` and represent types spliced
118+
* explicitly.
119+
*/
115120
val explicitTags = new mutable.LinkedHashSet[TypeRef]()
116121

117122
/** A stack of entered symbols, to be unwound after scope exit */
@@ -129,41 +134,43 @@ class ReifyQuotes extends MacroTransformWithImplicits {
129134
* defined versions. As a side effect, prepend the expressions `tag1, ..., `tagN`
130135
* as splices to `embedded`.
131136
*/
132-
private def addTags(expr: Tree)(implicit ctx: Context): Tree =
137+
private def addTags(expr: Tree)(implicit ctx: Context): Tree = {
138+
139+
def mkTagSymbolAndAssignType(typeRef: TypeRef, tag: Tree): Tree = {
140+
val rhs = transform(tag.select(tpnme.UNARY_~))
141+
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs)
142+
143+
val original = typeRef.symbol.asType
144+
145+
val local = ctx.newSymbol(
146+
owner = ctx.owner,
147+
name = UniqueName.fresh("T".toTermName).toTypeName,
148+
flags = Synthetic,
149+
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~)),
150+
coord = typeRef.prefix.termSymbol.coord).asType
151+
152+
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
153+
}
154+
133155
if (importedTags.isEmpty && explicitTags.isEmpty) expr
134156
else {
135157
val itags = importedTags.toList
158+
// The tree of the tag for each tag comes from implicit search in `tryHeal`
136159
val typeDefs = for ((tref, tag) <- itags) yield {
137-
val rhs = transform(tag.select(tpnme.UNARY_~))
138-
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs)
139-
val original = tref.symbol.asType
140-
val local = original.copy(
141-
owner = ctx.owner,
142-
name = (original.name + "$$").toTypeName,
143-
flags = Synthetic,
144-
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~))).asType
145-
146-
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
160+
mkTagSymbolAndAssignType(tref, tag)
147161
}
148162
importedTags.clear()
149163

150-
164+
// The tree of the tag for each tag comes from a type ref e.g., ~t
151165
val explicitTypeDefs = for (tref <- explicitTags) yield {
152166
val tag = ref(tref.prefix.termSymbol)
153-
val rhs = transform(tag.select(tpnme.UNARY_~))
154-
155-
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs)
156-
157-
val local = ctx.newSymbol(
158-
owner = ctx.owner,
159-
name = UniqueName.fresh("ttt".toTermName).toTypeName,
160-
flags = Synthetic,
161-
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~)),
162-
coord = tref.prefix.termSymbol.coord).asType
163-
164-
(tref, ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local))
167+
mkTagSymbolAndAssignType(tref, tag)
165168
}
166-
val map: Map[Type, Type] = explicitTypeDefs.map(x => (x._1, x._2.symbol.typeRef)).toMap
169+
val tagsExplicitTypeDefsPairs = explicitTags.zip(explicitTypeDefs)
170+
explicitTags.clear()
171+
172+
// Maps type splices to type references of tags e.g., ~t -> some type T$1
173+
val map: Map[Type, Type] = tagsExplicitTypeDefsPairs.map(x => (x._1, x._2.symbol.typeRef)).toMap
167174
val tMap = new TypeMap() {
168175
override def apply(tp: Type): Type = {
169176
if (map.contains(tp))
@@ -173,11 +180,14 @@ class ReifyQuotes extends MacroTransformWithImplicits {
173180
}
174181
}
175182

176-
Block(typeDefs ++ explicitTypeDefs.map(_._2),
177-
new TreeTypeMap(typeMap = tMap,
178-
substFrom = itags.map(_._1.symbol), substTo = typeDefs.map(_.symbol))
179-
.apply(expr))
183+
Block(typeDefs ++ tagsExplicitTypeDefsPairs.map(_._2),
184+
new TreeTypeMap(
185+
typeMap = tMap,
186+
substFrom = itags.map(_._1.symbol),
187+
substTo = typeDefs.map(_.symbol)
188+
).apply(expr))
180189
}
190+
}
181191

182192
/** Enter staging level of symbol defined by `tree`, if applicable. */
183193
def markDef(tree: Tree)(implicit ctx: Context) = tree match {
@@ -450,6 +460,11 @@ class ReifyQuotes extends MacroTransformWithImplicits {
450460
tree match {
451461
case Quoted(quotedTree) =>
452462
quotation(quotedTree, tree)
463+
case tree: TypeTree if tree.tpe.typeSymbol.isSplice =>
464+
val splicedType = tree.tpe.asInstanceOf[TypeRef].prefix.termSymbol
465+
splice(ref(splicedType).select(tpnme.UNARY_~))
466+
case tree: TypeApply =>
467+
super.transform(tree)
453468
case tree: Select if tree.symbol.isSplice =>
454469
splice(tree)
455470
case tree: RefTree if needsLifting(tree) =>
@@ -459,7 +474,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
459474
val last = enteredSyms
460475
stats.foreach(markDef)
461476
mapOverTree(last)
462-
463477
case Inlined(call, bindings, InlineSplice(expansion @ Select(body, name))) =>
464478
// To maintain phase consistency, we move the binding of the this parameter into the spliced code
465479
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
dotty.runtime.Arrays.newGenericArray[Int](3)(reflect.ClassTag.Int)
3-
}
2+
new Array[List[Int]](1)
3+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import scala.quoted._
33
import scala.reflect.ClassTag
44

55
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)
6+
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T]): Liftable[Array[List[T]]] = (arr: Array[List[T]]) => '{
7+
new Array[List[~t]](~(arr.length: Expr[Int]))
88
// TODO add elements
99
}
1010
}

tests/run-with-compiler/i3847.check

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

0 commit comments

Comments
 (0)