@@ -24,6 +24,7 @@ import dotty.tools.dotc.config.ScalaRelease.*
2424import dotty .tools .dotc .staging .QuoteContext .*
2525import dotty .tools .dotc .staging .StagingLevel .*
2626import dotty .tools .dotc .staging .QuoteTypeTags
27+ import dotty .tools .dotc .staging .DirectTypeOf
2728
2829import scala .annotation .constructorOnly
2930
@@ -44,12 +45,13 @@ object Splicing:
4445 * contains the quotes with references to all cross-quote references. There are some special rules
4546 * for references in the LHS of assignments and cross-quote method references.
4647 *
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.
4849 * ```
4950 * '{ ...
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
5355 * }
5456 * ```
5557 *
@@ -60,15 +62,15 @@ object Splicing:
6062 * '{ ...
6163 * val x1: T1 = ???
6264 * 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$}) })
6668 *
6769 * }}}
6870 * }
6971 * ```
7072 *
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$}) }`.
7274 *
7375 */
7476class Splicing extends MacroTransform :
@@ -132,7 +134,7 @@ class Splicing extends MacroTransform:
132134 case None =>
133135 val holeIdx = numHoles
134136 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 ))
136138 typeHoles.put(qual.symbol, hole)
137139 hole
138140 cpy.TypeDef (tree)(rhs = hole)
@@ -154,7 +156,7 @@ class Splicing extends MacroTransform:
154156
155157 private def transformAnnotations (tree : DefTree )(using Context ): Unit =
156158 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)
158160 if (annot.tree == newAnnotTree) annot
159161 else ConcreteAnnotation (newAnnotTree)
160162 }
@@ -198,10 +200,57 @@ class Splicing extends MacroTransform:
198200 val newTree = transform(tree)
199201 val (refs, bindings) = refBindingMap.values.toList.unzip
200202 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)
202229 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)
205254 val closure = Block (ddef :: Nil , Closure (Nil , ref(meth), TypeTree (fnType)))
206255 tpd.Hole (true , holeIdx, refs, closure, TypeTree (tpe))
207256
@@ -255,6 +304,9 @@ class Splicing extends MacroTransform:
255304 if tree.symbol == defn.QuotedTypeModule_of && containsCapturedType(tpt.tpe) =>
256305 val newContent = capturedPartTypes(tpt)
257306 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)
258310 case block : Block =>
259311 inContext(ctx.withSource(tree.source)) {
260312 Apply (TypeApply (typeof, List (newContent)), List (quotes)).withSpan(tree.span)
@@ -354,7 +406,7 @@ class Splicing extends MacroTransform:
354406 private def newQuotedTypeClassBinding (tpe : Type )(using Context ) =
355407 newSymbol(
356408 spliceOwner,
357- UniqueName .fresh(nme. Type ). toTermName,
409+ UniqueName .fresh(tpe.typeSymbol.name. toTermName) ,
358410 Param ,
359411 defn.QuotedTypeClass .typeRef.appliedTo(tpe),
360412 )
0 commit comments