Skip to content

Commit 7cb10a8

Browse files
Merge pull request #4116 from dotty-staging/fix-#3847-2
Fix #3847: Handle correctly splicing of (possibly) nested type parameters
2 parents e5ff11c + 6e861b2 commit 7cb10a8

File tree

6 files changed

+105
-23
lines changed

6 files changed

+105
-23
lines changed

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

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,17 @@ 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+
*/
121+
val explicitTags = new mutable.LinkedHashSet[TypeRef]()
122+
116123
/** A stack of entered symbols, to be unwound after scope exit */
117124
var enteredSyms: List[Symbol] = Nil
118125

@@ -128,25 +135,55 @@ class ReifyQuotes extends MacroTransformWithImplicits {
128135
* defined versions. As a side effect, prepend the expressions `tag1, ..., `tagN`
129136
* as splices to `embedded`.
130137
*/
131-
private def addTags(expr: Tree)(implicit ctx: Context): Tree =
132-
if (importedTags.isEmpty) expr
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+
156+
if (importedTags.isEmpty && explicitTags.isEmpty) expr
133157
else {
134158
val itags = importedTags.toList
159+
// The tree of the tag for each tag comes from implicit search in `tryHeal`
135160
val typeDefs = for ((tref, tag) <- itags) yield {
136-
val rhs = transform(tag.select(tpnme.UNARY_~))
137-
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs)
138-
val original = tref.symbol.asType
139-
val local = original.copy(
140-
owner = ctx.owner,
141-
flags = Synthetic,
142-
info = TypeAlias(tag.tpe.select(tpnme.UNARY_~)))
143-
ctx.typeAssigner.assignType(untpd.TypeDef(original.name, alias), local)
161+
mkTagSymbolAndAssignType(tref, tag)
144162
}
145163
importedTags.clear()
146-
Block(typeDefs,
147-
new TreeTypeMap(substFrom = itags.map(_._1.symbol), substTo = typeDefs.map(_.symbol))
148-
.apply(expr))
164+
165+
// The tree of the tag for each tag comes from a type ref e.g., ~t
166+
val explicitTypeDefs = for (tref <- explicitTags) yield {
167+
val tag = ref(tref.prefix.termSymbol)
168+
mkTagSymbolAndAssignType(tref, tag)
169+
}
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
175+
val tMap = new TypeMap() {
176+
override def apply(tp: Type): Type = map.getOrElse(tp, mapOver(tp))
177+
}
178+
179+
Block(typeDefs ++ explicitTypeDefs,
180+
new TreeTypeMap(
181+
typeMap = tMap,
182+
substFrom = itags.map(_._1.symbol),
183+
substTo = typeDefs.map(_.symbol)
184+
).apply(expr))
149185
}
186+
}
150187

151188
/** Enter staging level of symbol defined by `tree`, if applicable. */
152189
def markDef(tree: Tree)(implicit ctx: Context) = tree match {
@@ -226,8 +263,11 @@ class ReifyQuotes extends MacroTransformWithImplicits {
226263
def checkType(pos: Position)(implicit ctx: Context): TypeAccumulator[Unit] = new TypeAccumulator[Unit] {
227264
def apply(acc: Unit, tp: Type): Unit = reporting.trace(i"check type level $tp at $level") {
228265
tp match {
229-
case tp: NamedType if tp.symbol.isSplice =>
230-
if (inQuote) outer.checkType(pos).foldOver(acc, tp)
266+
case tp: TypeRef if tp.symbol.isSplice =>
267+
if (inQuote) {
268+
explicitTags += tp
269+
outer.checkType(pos).foldOver(acc, tp)
270+
}
231271
else {
232272
if (tp.isTerm) spliceOutsideQuotes(pos)
233273
tp
@@ -414,6 +454,9 @@ class ReifyQuotes extends MacroTransformWithImplicits {
414454
tree match {
415455
case Quoted(quotedTree) =>
416456
quotation(quotedTree, tree)
457+
case tree: TypeTree if tree.tpe.typeSymbol.isSplice =>
458+
val splicedType = tree.tpe.asInstanceOf[TypeRef].prefix.termSymbol
459+
splice(ref(splicedType).select(tpnme.UNARY_~))
417460
case tree: Select if tree.symbol.isSplice =>
418461
splice(tree)
419462
case tree: RefTree if needsLifting(tree) =>
@@ -423,7 +466,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
423466
val last = enteredSyms
424467
stats.foreach(markDef)
425468
mapOverTree(last)
426-
427469
case Inlined(call, bindings, InlineSplice(expansion @ Select(body, name))) =>
428470
// To maintain phase consistency, we move the binding of the this parameter into the spliced code
429471
val (splicedBindings, stagedBindings) = bindings.partition {

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+
new Array[List[Int]](1)
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]): Liftable[Array[List[T]]] = (arr: Array[List[T]]) => '{
7+
new Array[List[~t]](~arr.length.toExpr)
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)).toExpr
17+
println(arr.show)
18+
}
19+
}

tests/run-with-compiler/i3847.check

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

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.toExpr)(~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).toExpr
17+
println(arr.show)
18+
}
19+
}

tests/run-with-compiler/quote-lib.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,10 @@ package liftable {
117117
}
118118

119119
object Arrays {
120-
// FIXME missing hole for ~t
121-
// implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], ct: Expr[ClassTag[T]]): Liftable[Array[T]] = (arr: Array[T]) => '{
122-
// new Array[~t](~(arr.length: Expr[Int]))(~ct)
123-
// }
124-
120+
implicit def ArrayIsLiftable[T: Liftable](implicit t: Type[T], ct: Expr[ClassTag[T]]): Liftable[Array[T]] = (arr: Array[T]) => '{
121+
new Array[~t](~arr.length.toExpr)(~ct)
122+
}
125123
}
126124

127125
}
128-
}
126+
}

0 commit comments

Comments
 (0)