Skip to content

Commit 93da8c2

Browse files
committed
Fix scala#3847: handles correctly splicing of (possibly) nested parameter types
1 parent 7c7df3b commit 93da8c2

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
@@ -109,10 +109,15 @@ class ReifyQuotes extends MacroTransformWithImplicits {
109109
def inSplice = outer != null && !inQuote
110110

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

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

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

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

177-
Block(typeDefs ++ explicitTypeDefs.map(_._2),
178-
new TreeTypeMap(typeMap = tMap,
179-
substFrom = itags.map(_._1.symbol), substTo = typeDefs.map(_.symbol))
180-
.apply(expr))
184+
Block(typeDefs ++ tagsExplicitTypeDefsPairs.map(_._2),
185+
new TreeTypeMap(
186+
typeMap = tMap,
187+
substFrom = itags.map(_._1.symbol),
188+
substTo = typeDefs.map(_.symbol)
189+
).apply(expr))
181190
}
191+
}
182192

183193
/** Enter staging level of symbol defined by `tree`, if applicable. */
184194
def markDef(tree: Tree)(implicit ctx: Context) = tree match {
@@ -449,6 +459,11 @@ class ReifyQuotes extends MacroTransformWithImplicits {
449459
tree match {
450460
case Quoted(quotedTree) =>
451461
quotation(quotedTree, tree)
462+
case tree: TypeTree if tree.tpe.typeSymbol.isSplice =>
463+
val splicedType = tree.tpe.asInstanceOf[TypeRef].prefix.termSymbol
464+
splice(ref(splicedType).select(tpnme.UNARY_~))
465+
case tree: TypeApply =>
466+
super.transform(tree)
452467
case tree: Select if tree.symbol.isSplice =>
453468
splice(tree)
454469
case tree: RefTree if needsLifting(tree) =>
@@ -458,7 +473,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
458473
val last = enteredSyms
459474
stats.foreach(markDef)
460475
mapOverTree(last)
461-
462476
case Inlined(call, bindings, InlineSplice(expansion @ Select(body, name))) =>
463477
// To maintain phase consistency, we move the binding of the this parameter into the spliced code
464478
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)