@@ -24,6 +24,7 @@ import dotty.tools.dotc.config.ScalaRelease.*
24
24
import dotty .tools .dotc .staging .QuoteContext .*
25
25
import dotty .tools .dotc .staging .StagingLevel .*
26
26
import dotty .tools .dotc .staging .QuoteTypeTags
27
+ import dotty .tools .dotc .staging .DirectTypeOf
27
28
28
29
import scala .annotation .constructorOnly
29
30
@@ -44,12 +45,13 @@ object Splicing:
44
45
* contains the quotes with references to all cross-quote references. There are some special rules
45
46
* for references in the LHS of assignments and cross-quote method references.
46
47
*
47
- * In the following code example `x1` and `x2 ` are cross-quote references.
48
+ * In the following code example `x1`, `x2` and `U ` are cross-quote references.
48
49
* ```
49
50
* '{ ...
50
- * val x1: T1 = ???
51
- * val x2: T2 = ???
52
- * ${ (q: Quotes) ?=> f('{ g(x1, x2) }) }: T3
51
+ * type U
52
+ * val x1: T = ???
53
+ * val x2: U = ???
54
+ * ${ (q: Quotes) ?=> f('{ g[U](x1, x2) }) }: T3
53
55
* }
54
56
* ```
55
57
*
@@ -60,15 +62,15 @@ object Splicing:
60
62
* '{ ...
61
63
* val x1: T1 = ???
62
64
* val x2: T2 = ???
63
- * {{{ 0 | T3 | x1, x2 |
64
- * ( x1$: Expr[T1 ], x2$: Expr[T2 ]) => // body of this lambda does not contain references to x1 or x2
65
- * (q: Quotes) ?=> f('{ g (${x1$}, ${x2$}) })
65
+ * {{{ 0 | T3 | U, x1, x2 |
66
+ * [U$1] => (U$2: Type[U$1], x1$: Expr[T ], x2$: Expr[U$1 ]) => // body of this lambda does not contain references to U, x1 or x2
67
+ * (q: Quotes) ?=> f('{ @SplicedType type U$3 = [[ [ 0 | U$2 | | U$1 ]]]; g[U$3] (${x1$}, ${x2$}) })
66
68
*
67
69
* }}}
68
70
* }
69
71
* ```
70
72
*
71
- * and then performs the same transformation on `'{ g (${x1$}, ${x2$}) }`.
73
+ * and then performs the same transformation on `'{ @SplicedType type U$3 = [[ [ 0 | U$2 | | U$1 ]]]; g[U$3] (${x1$}, ${x2$}) }`.
72
74
*
73
75
*/
74
76
class Splicing extends MacroTransform :
@@ -132,7 +134,7 @@ class Splicing extends MacroTransform:
132
134
case None =>
133
135
val holeIdx = numHoles
134
136
numHoles += 1
135
- val hole = tpd.Hole (false , holeIdx, Nil , ref(qual), TypeTree (tp))
137
+ val hole = tpd.Hole (false , holeIdx, Nil , ref(qual), TypeTree (tp.dealias ))
136
138
typeHoles.put(qual.symbol, hole)
137
139
hole
138
140
cpy.TypeDef (tree)(rhs = hole)
@@ -154,7 +156,7 @@ class Splicing extends MacroTransform:
154
156
155
157
private def transformAnnotations (tree : DefTree )(using Context ): Unit =
156
158
tree.symbol.annotations = tree.symbol.annotations.mapconserve { annot =>
157
- val newAnnotTree = transform(annot.tree)( using ctx.withOwner(tree.symbol))
159
+ val newAnnotTree = transform(annot.tree)
158
160
if (annot.tree == newAnnotTree) annot
159
161
else ConcreteAnnotation (newAnnotTree)
160
162
}
@@ -198,10 +200,57 @@ class Splicing extends MacroTransform:
198
200
val newTree = transform(tree)
199
201
val (refs, bindings) = refBindingMap.values.toList.unzip
200
202
val bindingsTypes = bindings.map(_.termRef.widenTermRefExpr)
201
- val methType = MethodType (bindingsTypes, newTree.tpe)
203
+ val types = bindingsTypes.collect {
204
+ case AppliedType (tycon, List (arg : TypeRef )) if tycon.derivesFrom(defn.QuotedTypeClass ) => arg
205
+ }
206
+ val newTypeParams = types.map { tpe =>
207
+ newSymbol(
208
+ spliceOwner,
209
+ UniqueName .fresh(tpe.symbol.name.toTypeName),
210
+ Param ,
211
+ TypeBounds .empty
212
+ )
213
+ }
214
+ val methType =
215
+ if types.nonEmpty then
216
+ PolyType (types.map(tp => UniqueName .fresh(tp.symbol.name.toTypeName)))(
217
+ pt => types.map(_ => TypeBounds .empty),
218
+ pt => {
219
+ val tpParamMap = new TypeMap {
220
+ private val mapping = types.map(_.typeSymbol).zip(pt.paramRefs).toMap
221
+ def apply (tp : Type ): Type = tp match
222
+ case tp : TypeRef => mapping.getOrElse(tp.typeSymbol, tp)
223
+ case tp => mapOver(tp)
224
+ }
225
+ MethodType (bindingsTypes.map(tpParamMap), tpParamMap(newTree.tpe))
226
+ }
227
+ )
228
+ else MethodType (bindingsTypes, newTree.tpe)
202
229
val meth = newSymbol(spliceOwner, nme.ANON_FUN , Synthetic | Method , methType)
203
- val ddef = DefDef (meth, List (bindings), newTree.tpe, newTree.changeOwner(ctx.owner, meth))
204
- val fnType = defn.FunctionType (bindings.size, isContextual = false ).appliedTo(bindingsTypes :+ newTree.tpe)
230
+
231
+ def substituteTypes (tree : Tree ): Tree =
232
+ if types.nonEmpty then
233
+ val typeIndex = types.zipWithIndex.toMap
234
+ TreeTypeMap (
235
+ typeMap = new TypeMap {
236
+ def apply (tp : Type ): Type = tp match
237
+ case tp @ TypeRef (x : TermRef , _) if tp.symbol == defn.QuotedType_splice => tp
238
+ case tp : TypeRef if tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot ) => tp
239
+ case tp : TypeRef =>
240
+ typeIndex.get(tp) match
241
+ case Some (idx) => newTypeParams(idx).typeRef
242
+ case None => mapOver(tp)
243
+ case _ => mapOver(tp)
244
+ }
245
+ ).transform(tree)
246
+ else tree
247
+ val paramss =
248
+ if types.nonEmpty then List (newTypeParams, bindings)
249
+ else List (bindings)
250
+ val ddef = substituteTypes(DefDef (meth, paramss, newTree.tpe, newTree.changeOwner(ctx.owner, meth)))
251
+ val fnType =
252
+ if types.isEmpty then defn.FunctionType (bindings.size, isContextual = false ).appliedTo(bindingsTypes :+ newTree.tpe)
253
+ else RefinedType (defn.PolyFunctionType , nme.apply, methType)
205
254
val closure = Block (ddef :: Nil , Closure (Nil , ref(meth), TypeTree (fnType)))
206
255
tpd.Hole (true , holeIdx, refs, closure, TypeTree (tpe))
207
256
@@ -255,6 +304,9 @@ class Splicing extends MacroTransform:
255
304
if tree.symbol == defn.QuotedTypeModule_of && containsCapturedType(tpt.tpe) =>
256
305
val newContent = capturedPartTypes(tpt)
257
306
newContent match
307
+ case DirectTypeOf .Healed (termRef) =>
308
+ // Optimization: `quoted.Type.of[@SplicedType type T = x.Underlying; T](quotes)` --> `x`
309
+ tpd.ref(termRef).withSpan(tpt.span)
258
310
case block : Block =>
259
311
inContext(ctx.withSource(tree.source)) {
260
312
Apply (TypeApply (typeof, List (newContent)), List (quotes)).withSpan(tree.span)
@@ -354,7 +406,7 @@ class Splicing extends MacroTransform:
354
406
private def newQuotedTypeClassBinding (tpe : Type )(using Context ) =
355
407
newSymbol(
356
408
spliceOwner,
357
- UniqueName .fresh(nme. Type ). toTermName,
409
+ UniqueName .fresh(tpe.typeSymbol.name. toTermName) ,
358
410
Param ,
359
411
defn.QuotedTypeClass .typeRef.appliedTo(tpe),
360
412
)
0 commit comments