Skip to content

Commit 22d841a

Browse files
Merge pull request #8949 from dotty-staging/find-quoted-type-context-early
Keep QuoteContext found in typer for quoted.Type
2 parents f807eee + 243ac3b commit 22d841a

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+
((qctx: scala.quoted.QuoteContext) ?=> {
2+
val t: scala.quoted.Type[scala.Predef.String] = scala.internal.quoted.CompileTime.typeQuote[scala.Predef.String].apply(using qctx)
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 = '{ (using qctx: 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)