Skip to content

Commit 47a1586

Browse files
committed
Keep QuoteContext found in typer for quoted.Type
We already do this for quoted terms. We missed this last one. After this change we won't need to do implicit search after pickling anymore.
1 parent f807eee commit 47a1586

File tree

18 files changed

+54
-50
lines changed

18 files changed

+54
-50
lines changed

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

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,32 +131,20 @@ class ReifyQuotes extends MacroTransform {
131131
val body1 = nested(isQuote = true).transform(body)(quoteContext)
132132
super.transformQuotation(body1, quote)
133133
}
134-
else body match {
135-
case body: RefTree if isCaptured(body.symbol, level + 1) =>
136-
// Optimization: avoid the full conversion when capturing `x`
137-
// in '{ x } to '{ ${x$1} } and go directly to `x$1`
138-
capturers(body.symbol)(body)
139-
case _ =>
140-
val (body1, splices) = nested(isQuote = true).splitQuote(body)(quoteContext)
141-
if (level == 0) {
142-
val body2 =
143-
if (body1.isType) body1
144-
else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1)
145-
pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span)
146-
}
147-
else
148-
body
134+
else {
135+
val (body1, splices) = nested(isQuote = true).splitQuote(body)(quoteContext)
136+
if (level == 0) {
137+
val body2 =
138+
if (body1.isType) body1
139+
else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1)
140+
pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span)
141+
}
142+
else
143+
body
149144
}
150145
}
151146

152147
private def pickledQuote(body: Tree, splices: List[Tree], originalTp: Type, isType: Boolean)(implicit ctx: Context) = {
153-
def qctx: Tree = {
154-
val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, body.span)
155-
if (qctx.tpe.isInstanceOf[SearchFailureType])
156-
ctx.error(ctx.typer.missingArgMsg(qctx, defn.QuoteContextClass.typeRef, ""), ctx.source.atSpan(body.span))
157-
qctx
158-
}
159-
160148
def pickleAsLiteral(lit: Literal) = {
161149
def liftedValue(lifter: Symbol) =
162150
ref(lifter).appliedToType(originalTp).select(nme.toExpr).appliedTo(lit)
@@ -185,9 +173,9 @@ class ReifyQuotes extends MacroTransform {
185173
}
186174

187175
if (isType) {
188-
def tag(tagName: String) = ref(defn.QuotedTypeModule).select(tagName.toTermName).appliedTo(qctx)
176+
def tag(tagName: String) = ref(defn.QuotedTypeModule).select(tagName.toTermName)
189177
if (splices.isEmpty && body.symbol.isPrimitiveValueClass) tag(s"${body.symbol.name}Tag")
190-
else pickleAsTasty().select(nme.apply).appliedTo(qctx)
178+
else pickleAsTasty()
191179
}
192180
else getLiteral(body) match {
193181
case Some(lit) => pickleAsLiteral(lit)
@@ -362,6 +350,10 @@ class ReifyQuotes extends MacroTransform {
362350
transform(tree)(ctx.withSource(tree.source))
363351
else reporting.trace(i"Reifier.transform $tree at $level", show = true) {
364352
tree match {
353+
case Apply(Select(TypeApply(fn, (body: RefTree) :: Nil), _), _) if fn.symbol == defn.InternalQuoted_typeQuote && isCaptured(body.symbol, level + 1) =>
354+
// Optimization: avoid the full conversion when capturing `x`
355+
// in '{ x } to '{ ${x$1} } and go directly to `x$1`
356+
capturers(body.symbol)(body)
365357
case tree: RefTree if isCaptured(tree.symbol, level) =>
366358
val body = capturers(tree.symbol).apply(tree)
367359
val splice: Tree =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ object Splicer {
228228
}
229229
interpretQuote(quoted1)
230230

231-
case TypeApply(fn, quoted :: Nil) if fn.symbol == defn.InternalQuoted_typeQuote =>
231+
case Apply(Select(TypeApply(fn, quoted :: Nil), _), _) if fn.symbol == defn.InternalQuoted_typeQuote =>
232232
interpretTypeQuote(quoted)
233233

234234
case Literal(Constant(value)) =>

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
9292
}
9393

9494
tree match {
95+
case Apply(Select(Quoted(quotedTree), _), _) if quotedTree.isType =>
96+
dropEmptyBlocks(quotedTree) match
97+
case Spliced(t) =>
98+
// '[ x.$splice ] --> x
99+
transform(t)
100+
case _ =>
101+
super.transform(tree)
95102

96103
case Quoted(quotedTree) =>
97104
val old = inQuoteOrSplice

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ trait QuotesAndSplices {
5757
if ctx.mode.is(Mode.Pattern) then
5858
typedQuotePattern(tree, pt, qctx)
5959
else if (tree.quoted.isType)
60-
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuote.termRef), tree.quoted :: Nil), pt)(using quoteContext)
60+
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuote.termRef), tree.quoted :: Nil), pt)(using quoteContext).select(nme.apply).appliedTo(qctx)
6161
else
6262
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuote.termRef), tree.quoted), pt)(using pushQuoteContext(qctx)).select(nme.apply).appliedTo(qctx)
6363
tree1.withSpan(tree.span)
@@ -401,7 +401,7 @@ trait QuotesAndSplices {
401401
val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeClass
402402
val quotedPattern =
403403
if (tree.quoted.isTerm) ref(defn.InternalQuoted_exprQuote.termRef).appliedToType(defn.AnyType).appliedTo(shape).select(nme.apply).appliedTo(qctx)
404-
else ref(defn.InternalQuoted_typeQuote.termRef).appliedToTypeTree(shape)
404+
else ref(defn.InternalQuoted_typeQuote.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx)
405405
UnApply(
406406
fun = ref(unapplySym.termRef).appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil),
407407
implicits = quotedPattern :: Literal(Constant(typeBindings.nonEmpty)) :: qctx :: Nil,

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
5555
def quotedType(t: Type) =
5656
if StagingContext.level == 0 then
5757
ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes
58-
ref(defn.InternalQuoted_typeQuote).appliedToType(t)
58+
val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, span)
59+
qctx.tpe match
60+
case tpe: Implicits.SearchFailureType => ctx.error(tpe.msg, ctx.source.atSpan(span))
61+
case _ =>
62+
ref(defn.InternalQuoted_typeQuote).appliedToType(t).select(nme.apply).appliedTo(qctx)
5963
formal.argInfos match
6064
case arg :: Nil =>
6165
val deepDealias = new TypeMap:

library/src-bootstrapped/scala/internal/quoted/CompileTime.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ object CompileTime {
2222

2323
/** A type quote is desugared by the compiler into a call to this method */
2424
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.typeQuote`")
25-
def typeQuote[T <: AnyKind]: Type[T] = ???
25+
def typeQuote[T <: AnyKind]: QuoteContext ?=> Type[T] = ???
2626

2727
/** A splice in a quoted pattern is desugared by the compiler into a call to this method */
2828
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternHole`")

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,31 @@ class Type[T <: AnyKind] private[scala] {
2323
/** Some basic type tags, currently incomplete */
2424
object Type {
2525

26-
given UnitTag(using qctx: QuoteContext) as Type[Unit] =
26+
def UnitTag: QuoteContext ?=> Type[Unit] =
2727
qctx.tasty.defn.UnitType.seal.asInstanceOf[quoted.Type[Unit]]
2828

29-
given BooleanTag(using qctx: QuoteContext) as Type[Boolean] =
29+
def BooleanTag: QuoteContext ?=> Type[Boolean] =
3030
qctx.tasty.defn.BooleanType.seal.asInstanceOf[quoted.Type[Boolean]]
3131

32-
given ByteTag(using qctx: QuoteContext) as Type[Byte] =
32+
def ByteTag: QuoteContext ?=> Type[Byte] =
3333
qctx.tasty.defn.ByteType.seal.asInstanceOf[quoted.Type[Byte]]
3434

35-
given CharTag(using qctx: QuoteContext) as Type[Char] =
35+
def CharTag: QuoteContext ?=> Type[Char] =
3636
qctx.tasty.defn.CharType.seal.asInstanceOf[quoted.Type[Char]]
3737

38-
given ShortTag(using qctx: QuoteContext) as Type[Short] =
38+
def ShortTag: QuoteContext ?=> Type[Short] =
3939
qctx.tasty.defn.ShortType.seal.asInstanceOf[quoted.Type[Short]]
4040

41-
given IntTag(using qctx: QuoteContext) as Type[Int] =
41+
def IntTag: QuoteContext ?=> Type[Int] =
4242
qctx.tasty.defn.IntType.seal.asInstanceOf[quoted.Type[Int]]
4343

44-
given LongTag(using qctx: QuoteContext) as Type[Long] =
44+
def LongTag: QuoteContext ?=> Type[Long] =
4545
qctx.tasty.defn.LongType.seal.asInstanceOf[quoted.Type[Long]]
4646

47-
given FloatTag(using qctx: QuoteContext) as Type[Float] =
47+
def FloatTag: QuoteContext ?=> Type[Float] =
4848
qctx.tasty.defn.FloatType.seal.asInstanceOf[quoted.Type[Float]]
4949

50-
given DoubleTag(using qctx: QuoteContext) as Type[Double] =
50+
def DoubleTag: QuoteContext ?=> Type[Double] =
5151
qctx.tasty.defn.DoubleType.seal.asInstanceOf[quoted.Type[Double]]
5252

5353
}
File renamed without changes.

tests/pos-macros/i4023/Test_2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
object Test {
1+
def test(using quoted.QuoteContext) = {
22
Macro.ff(3)
33
}

tests/pos-macros/i4023b/Test_2.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
object Test {
2+
given quoted.QuoteContext = ???
23
Macro.ff[Int]
34
}

tests/pos/i6588.scala renamed to tests/pos-macros/i6588.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import scala.quoted._
22

33
inline def foo[T:Type]: Int = 10
44

5-
def main = {
5+
def main(using QuoteContext) = {
66
type S = Int
77
foo[S]
88
foo[Int]
File renamed without changes.
File renamed without changes.

tests/pos/i8302.scala renamed to tests/pos-macros/i8302.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.quoted._
22
def foo[T](using qctx: QuoteContext, tpe: Type[T]): Expr[Any] =
3-
'{
3+
'{ (using qctx: QuoteContext) =>
44
type TT = T
55
val t = '[TT]
66
???

tests/run-custom-args/run-macros-erased/reflect-isFunctionType/macro_1.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
import scala.quoted._
22

33

4-
inline def isFunctionType[T:Type]: Boolean = ${ isFunctionTypeImpl('[T]) }
4+
inline def isFunctionType[T]: Boolean = ${ isFunctionTypeImpl('[T]) }
55

66
def isFunctionTypeImpl[T](tp: Type[T])(using qctx: QuoteContext) : Expr[Boolean] = {
77
import qctx.tasty._
88
Expr(tp.unseal.tpe.isFunctionType)
99
}
1010

1111

12-
inline def isContextFunctionType[T:Type]: Boolean = ${ isContextFunctionTypeImpl('[T]) }
12+
inline def isContextFunctionType[T]: Boolean = ${ isContextFunctionTypeImpl('[T]) }
1313

1414
def isContextFunctionTypeImpl[T](tp: Type[T])(using qctx: QuoteContext) : Expr[Boolean] = {
1515
import qctx.tasty._
1616
Expr(tp.unseal.tpe.isContextFunctionType)
1717
}
1818

1919

20-
inline def isErasedFunctionType[T:Type]: Boolean = ${ isErasedFunctionTypeImpl('[T]) }
20+
inline def isErasedFunctionType[T]: Boolean = ${ isErasedFunctionTypeImpl('[T]) }
2121

2222
def isErasedFunctionTypeImpl[T](tp: Type[T])(using qctx: QuoteContext) : Expr[Boolean] = {
2323
import qctx.tasty._
2424
Expr(tp.unseal.tpe.isErasedFunctionType)
2525
}
2626

27-
inline def isDependentFunctionType[T:Type]: Boolean = ${ isDependentFunctionTypeImpl('[T]) }
27+
inline def isDependentFunctionType[T]: Boolean = ${ isDependentFunctionTypeImpl('[T]) }
2828

2929
def isDependentFunctionTypeImpl[T](tp: Type[T])(using qctx: QuoteContext) : Expr[Boolean] = {
3030
import qctx.tasty._
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
{
2-
val t: scala.quoted.Type[scala.Predef.String] = scala.internal.quoted.CompileTime.typeQuote[scala.Predef.String]
1+
((qtx: scala.quoted.QuoteContext) ?=> {
2+
val t: scala.quoted.Type[scala.Predef.String] = scala.internal.quoted.CompileTime.typeQuote[scala.Predef.String].apply(using qtx)
33

44
(t: scala.quoted.Type[scala.Predef.String])
5-
}
5+
})

tests/run-staging/quote-nested-4.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ object Test {
55
given Toolbox = Toolbox.make(getClass.getClassLoader)
66
def main(args: Array[String]): Unit = withQuoteContext {
77

8-
val q = '{
8+
val q = '{ (qtx: QuoteContext) ?=>
99
val t = '[String]
1010
t
1111
}

tests/run-staging/staged-tuples/Test.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Test {
66
def main(args: Array[String]): Unit = {
77
implicit val toolbox: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)
88

9-
assert(run(fromArrayStaged('{ Array.empty[Object] }, Some(0))).==(()))
9+
assert(run(fromArrayStaged[Unit]('{ Array.empty[Object] }, Some(0))).==(()))
1010
assert(run(fromArrayStaged[Tuple1[String]]('{ Array[Object]("a") }, Some(1))) == Tuple1("a"))
1111
assert(run(fromArrayStaged[(String, String)]('{ Array[Object]("a", "b") }, Some(2))) == ("a", "b"))
1212
assert(run(fromArrayStaged[(String, String, String)]('{ Array[Object]("a", "b", "c") }, Some(3))) == ("a", "b", "c"))

0 commit comments

Comments
 (0)