Skip to content

Commit 0e07132

Browse files
committed
Change signature of quoted.Type encoding
1 parent e3a3974 commit 0e07132

File tree

9 files changed

+67
-38
lines changed

9 files changed

+67
-38
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -936,10 +936,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
936936
* The result can be the contents of a term or type quote, which
937937
* will return a term or type tree respectively.
938938
*/
939-
def unapply(tree: tpd.Tree)(using Context): Option[tpd.Tree] = tree match {
940-
case tree: GenericApply if tree.symbol.isQuote => Some(tree.args.head)
941-
case _ => None
942-
}
939+
def unapply(tree: tpd.Apply)(using Context): Option[tpd.Tree] =
940+
if tree.symbol == defn.QuotedRuntime_exprQuote then
941+
// quoted.runtime.Expr.quote[T](<body>)
942+
Some(tree.args.head)
943+
else if tree.symbol == defn.QuotedTypeModule_of then
944+
// quoted.Type.of[<body>](quotes)
945+
val TypeApply(_, body :: _) = tree.fun
946+
Some(body)
947+
else None
943948
}
944949

945950
/** Extractors for splices */

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
103103
}
104104

105105
/** Transform quoted trees while maintaining phase correctness */
106-
override protected def transformQuotation(body: Tree, quote: Tree)(using Context): Tree = {
106+
override protected def transformQuotation(body: Tree, quote: Apply)(using Context): Tree = {
107107
val taggedTypes = new PCPCheckAndHeal.QuoteTypeTags(quote.span)
108108

109109
if (ctx.property(InAnnotation).isDefined)
@@ -118,13 +118,16 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
118118
case Nil => body1
119119
case tags => tpd.Block(tags, body1).withSpan(body.span)
120120

121-
quote match {
122-
case Apply(fn1 @ TypeApply(fn0, targs), _) =>
123-
val targs1 = targs.map(targ => TypeTree(healTypeOfTerm(fn1.srcPos)(targ.tpe)))
124-
cpy.Apply(quote)(cpy.TypeApply(fn1)(fn0, targs1), body2 :: Nil)
125-
case quote: TypeApply =>
126-
cpy.TypeApply(quote)(quote.fun, body2 :: Nil)
127-
}
121+
if body.isTerm then
122+
// quoted.runtime.Expr.quote[T](<body>)
123+
val TypeApply(fun, targs) = quote.fun
124+
val targs1 = targs.map(targ => TypeTree(healTypeOfTerm(quote.fun.srcPos)(targ.tpe)))
125+
cpy.Apply(quote)(cpy.TypeApply(quote.fun)(fun, targs1), body2 :: Nil)
126+
else
127+
// quoted.Type.of[<body>](quotes)
128+
val TypeApply(fun, _) = quote.fun
129+
cpy.Apply(quote)(cpy.TypeApply(quote.fun)(fun, body2 :: Nil), quote.args)
130+
128131
}
129132

130133
/** Transform splice

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

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class PickleQuotes extends MacroTransform {
127127
* `scala.quoted.Unpickler.unpickleExpr` that matches `tpe` with
128128
* core and splices as arguments.
129129
*/
130-
override protected def transformQuotation(body: Tree, quote: Tree)(using Context): Tree = {
130+
override protected def transformQuotation(body: Tree, quote: Apply)(using Context): Tree = {
131131
val isType = quote.symbol eq defn.QuotedTypeModule_of
132132
if (level > 0) {
133133
val body1 = nested(isQuote = true).transform(body)(using quoteContext)
@@ -139,14 +139,14 @@ class PickleQuotes extends MacroTransform {
139139
val body2 =
140140
if (body1.isType) body1
141141
else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1)
142-
pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span)
142+
pickledQuote(quote, body2, splices, body.tpe, isType).withSpan(quote.span)
143143
}
144144
else
145145
body
146146
}
147147
}
148148

149-
private def pickledQuote(body: Tree, splices: List[Tree], originalTp: Type, isType: Boolean)(using Context) = {
149+
private def pickledQuote(quote: Apply, body: Tree, splices: List[Tree], originalTp: Type, isType: Boolean)(using Context) = {
150150
/** Encode quote using Reflection.Literal
151151
*
152152
* Generate the code
@@ -279,7 +279,7 @@ class PickleQuotes extends MacroTransform {
279279
*
280280
* Generate the code
281281
* ```scala
282-
* qctx => qctx.reflect.TypeReprMethods.asType(
282+
* qctx.reflect.TypeReprMethods.asType(
283283
* qctx.reflect.TypeRepr.typeConstructorOf(classOf[<type>]])
284284
* ).asInstanceOf[scala.quoted.Type[<type>]]
285285
* ```
@@ -288,17 +288,13 @@ class PickleQuotes extends MacroTransform {
288288
def taggedType() =
289289
val typeType = defn.QuotedTypeClass.typeRef.appliedTo(body.tpe)
290290
val classTree = TypeApply(ref(defn.Predef_classOf.termRef), body :: Nil)
291-
val lambdaTpe = MethodType(defn.QuotesClass.typeRef :: Nil, typeType)
292-
def callTypeConstructorOf(ts: List[Tree]) = {
293-
val reflect = ts.head.select("reflect".toTermName)
294-
val typeRepr = reflect.select("TypeRepr".toTermName).select("typeConstructorOf".toTermName).appliedTo(classTree)
295-
reflect.select("TypeReprMethods".toTermName).select("asType".toTermName).appliedTo(typeRepr).asInstance(typeType)
296-
}
297-
Lambda(lambdaTpe, callTypeConstructorOf).withSpan(body.span)
291+
val reflect = quote.args.head.select("reflect".toTermName)
292+
val typeRepr = reflect.select("TypeRepr".toTermName).select("typeConstructorOf".toTermName).appliedTo(classTree)
293+
reflect.select("TypeReprMethods".toTermName).select("asType".toTermName).appliedTo(typeRepr).asInstance(typeType)
298294

299295
if (isType) {
300296
if (splices.isEmpty && body.symbol.isPrimitiveValueClass) taggedType()
301-
else pickleAsTasty()
297+
else pickleAsTasty().select(nme.apply).appliedTo(quote.args.head) // TODO do not create lambda
302298
}
303299
else getLiteral(body) match {
304300
case Some(lit) => pickleAsValue(lit)
@@ -485,9 +481,9 @@ class PickleQuotes extends MacroTransform {
485481
transform(tree)(using ctx.withSource(tree.source))
486482
else reporting.trace(i"Reifier.transform $tree at $level", show = true) {
487483
tree match {
488-
case Apply(Select(TypeApply(fn, (body: RefTree) :: Nil), _), _) if fn.symbol == defn.QuotedTypeModule_of && isCaptured(body.symbol, level + 1) =>
489-
// Optimization: avoid the full conversion when capturing `x`
490-
// in '{ x } to '{ ${x$1} } and go directly to `x$1`
484+
case Apply(TypeApply(fn, (body: RefTree) :: Nil), _) if fn.symbol == defn.QuotedTypeModule_of && isCaptured(body.symbol, level + 1) =>
485+
// Optimization: avoid the full conversion when capturing `X` with `x$1: Type[X$1]`
486+
// in `Type.of[X]` to `Type.of[x$1.Underlying]` and go directly to `X$1`
491487
capturers(body.symbol)(body)
492488
case tree: RefTree if isCaptured(tree.symbol, level) =>
493489
val body = capturers(tree.symbol).apply(tree)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ object Splicer {
149149
case Apply(Select(Apply(fn, quoted :: Nil), nme.apply), _) if fn.symbol == defn.QuotedRuntime_exprQuote =>
150150
// OK
151151

152-
case Apply(Select(TypeApply(fn, List(quoted)), nme.apply), _)if fn.symbol == defn.QuotedTypeModule_of =>
152+
case Apply(TypeApply(fn, List(quoted)), _)if fn.symbol == defn.QuotedTypeModule_of =>
153153
// OK
154154

155155
case Literal(Constant(value)) =>
@@ -233,7 +233,7 @@ object Splicer {
233233
}
234234
interpretQuote(quoted1)
235235

236-
case Apply(Select(TypeApply(fn, quoted :: Nil), _), _) if fn.symbol == defn.QuotedTypeModule_of =>
236+
case Apply(TypeApply(fn, quoted :: Nil), _) if fn.symbol == defn.QuotedTypeModule_of =>
237237
interpretTypeQuote(quoted)
238238

239239
case Literal(Constant(value)) =>

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
6565
}
6666

6767
/** Transform the quote `quote` which contains the quoted `body`. */
68-
protected def transformQuotation(body: Tree, quote: Tree)(using Context): Tree =
69-
quote match {
70-
case quote: Apply => cpy.Apply(quote)(quote.fun, body :: Nil)
71-
case quote: TypeApply => cpy.TypeApply(quote)(quote.fun, body :: Nil)
72-
}
68+
protected def transformQuotation(body: Tree, quote: Apply)(using Context): Tree =
69+
if body.isTerm then
70+
// quoted.runtime.Expr.quote[T](<body>)
71+
cpy.Apply(quote)(quote.fun, body :: Nil)
72+
else
73+
// quoted.Type.of[<body>](quotes)
74+
val TypeApply(fun, _) = quote.fun
75+
cpy.Apply(quote)(cpy.TypeApply(quote.fun)(fun, body :: Nil), quote.args)
7376

7477
/** Transform the expression splice `splice` which contains the spliced `body`. */
7578
protected def transformSplice(body: Tree, splice: Apply)(using Context): Tree
@@ -103,7 +106,7 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
103106
case _ =>
104107
super.transform(tree)
105108

106-
case Quoted(quotedTree) =>
109+
case tree @ Quoted(quotedTree) =>
107110
val old = inQuoteOrSplice
108111
inQuoteOrSplice = true
109112
try dropEmptyBlocks(quotedTree) match {

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ trait QuotesAndSplices {
461461
val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeClass
462462
val quotedPattern =
463463
if (tree.quoted.isTerm) ref(defn.QuotedRuntime_exprQuote.termRef).appliedToType(defn.AnyType).appliedTo(shape).select(nme.apply).appliedTo(qctx)
464-
else ref(defn.QuotedTypeModule_of.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx)
464+
else ref(defn.QuotedTypeModule_of.termRef).appliedToTypeTree(shape).appliedTo(qctx)
465465

466466
val matchModule = if tree.quoted.isTerm then defn.QuoteMatching_ExprMatch else defn.QuoteMatching_TypeMatch
467467
val unapplyFun = qctx.asInstance(defn.QuoteMatchingClass.typeRef).select(matchModule).select(nme.unapply)

library/src/scala/quoted/Type.scala renamed to library/src-bootstrapped/scala/quoted/Type.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ object Type:
1818

1919
/** Return a quoted.Type with the given type */
2020
@compileTimeOnly("Reference to `scala.quoted.Type.of` was not handled by PickleQuotes")
21-
given of[T <: AnyKind]: (Quotes ?=> Type[T]) = ???
21+
given of[T <: AnyKind](using Quotes): Type[T] = ???
2222

2323
end Type
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package scala.quoted
2+
3+
import scala.annotation.compileTimeOnly
4+
5+
/** Type (or type constructor) `T` needed contextually when using `T` in a quoted expression `'{... T ...}` */
6+
abstract class Type[T <: AnyKind] private[scala]:
7+
/** The type represented `Type` */
8+
type Underlying = T
9+
throw Exception("non-bootstrapped-lib")
10+
end Type
11+
12+
/** Methods to interact with the current `Type[T]` in scope */
13+
object Type:
14+
15+
/** Show a source code like representation of this type without syntax highlight */
16+
def show[T <: AnyKind](using Type[T])(using Quotes): String = throw Exception("non-bootstrapped-lib")
17+
18+
/** Return a quoted.Type with the given type */
19+
@compileTimeOnly("Reference to `scala.quoted.Type.of` was not handled by PickleQuotes")
20+
given of[T <: AnyKind]: (Quotes ?=> Type[T]) = throw Exception("non-bootstrapped-lib")
21+
22+
end Type
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
((q: scala.quoted.Quotes) ?=> {
2-
val t: scala.quoted.Type[scala.Predef.String] = scala.quoted.Type.of[scala.Predef.String].apply(using q)
2+
val t: scala.quoted.Type[scala.Predef.String] = scala.quoted.Type.of[scala.Predef.String](q)
33

44
(t: scala.quoted.Type[scala.Predef.String])
55
})

0 commit comments

Comments
 (0)