Skip to content

Commit e2ef8bc

Browse files
Merge pull request #8497 from dotty-staging/handle-quotecontext-paths-explicitly
Handle QuoteContext paths explicitly
2 parents 97c3a1e + 1cb6558 commit e2ef8bc

File tree

11 files changed

+94
-13
lines changed

11 files changed

+94
-13
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ class Definitions {
690690
@tu lazy val InternalQuotedModule: Symbol = ctx.requiredModule("scala.internal.quoted.CompileTime")
691691
@tu lazy val InternalQuoted_exprQuote : Symbol = InternalQuotedModule.requiredMethod("exprQuote")
692692
@tu lazy val InternalQuoted_exprSplice : Symbol = InternalQuotedModule.requiredMethod("exprSplice")
693+
@tu lazy val InternalQuoted_exprNestedSplice : Symbol = InternalQuotedModule.requiredMethod("exprNestedSplice")
693694
@tu lazy val InternalQuoted_typeQuote : Symbol = InternalQuotedModule.requiredMethod("typeQuote")
694695
@tu lazy val InternalQuoted_patternHole: Symbol = InternalQuotedModule.requiredMethod("patternHole")
695696
@tu lazy val InternalQuoted_patternBindHoleAnnot: ClassSymbol = InternalQuotedModule.requiredClass("patternBindHole")

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
385385
}
386386
else if (!printDebug && fun.hasType && fun.symbol == defn.InternalQuoted_exprQuote)
387387
keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
388-
else if (!printDebug && fun.hasType && fun.symbol == defn.InternalQuoted_exprSplice)
388+
else if (!printDebug && fun.hasType && (fun.symbol == defn.InternalQuoted_exprSplice || fun.symbol == defn.InternalQuoted_exprNestedSplice))
389389
keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
390390
else
391391
toTextLocal(fun)

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,16 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
8080
protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = {
8181
val body1 = transform(body)(spliceContext)
8282
splice match {
83-
case Apply(fun @ TypeApply(_, _ :: qctx :: Nil), _) if splice.isTerm =>
83+
case Apply(fun @ TypeApply(_, _ :: Nil), _) if splice.isTerm =>
8484
// Type of the splice itsel must also be healed
8585
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
8686
val tp = checkType(splice.sourcePos).apply(splice.tpe.widenTermRefExpr)
87-
cpy.Apply(splice)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: qctx :: Nil), body1 :: Nil)
87+
cpy.Apply(splice)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), body1 :: Nil)
88+
case Apply(f @ Apply(fun @ TypeApply(_, _), qctx :: Nil), _) if splice.isTerm =>
89+
// Type of the splice itsel must also be healed
90+
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
91+
val tp = checkType(splice.sourcePos).apply(splice.tpe.widenTermRefExpr)
92+
cpy.Apply(splice)(cpy.Apply(f)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), qctx :: Nil), body1 :: Nil)
8893
case splice: Select =>
8994
val tagRef = getQuoteTypeTags.getTagRef(splice.qualifier.tpe.asInstanceOf[TermRef])
9095
ref(tagRef).withSpan(splice.span)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ class ReifyQuotes extends MacroTransform {
343343
val body = capturers(tree.symbol).apply(tree)
344344
val splice: Tree =
345345
if (tree.isType) body.select(tpnme.splice)
346-
else ref(defn.InternalQuoted_exprSplice).appliedToTypes(List(tree.tpe, defn.QuoteContextClass.typeRef)).appliedTo(body)
346+
else ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body)
347347

348348
transformSplice(body, splice)
349349

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class SymUtils(val self: Symbol) extends AnyVal {
219219

220220
/** Is symbol a splice operation? */
221221
def isSplice(implicit ctx: Context): Boolean =
222-
self == defn.InternalQuoted_exprSplice || self == defn.QuotedType_splice
222+
self == defn.InternalQuoted_exprSplice || self == defn.InternalQuoted_exprNestedSplice || self == defn.QuotedType_splice
223223

224224
def isCollectiveExtensionClass(using Context): Boolean =
225225
self.is(ModuleClass) && self.sourceModule.is(Extension, butNot = Method)

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ trait QuotesAndSplices {
8080
spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
8181
val baseType = pat.tpe.baseType(defn.QuotedExprClass)
8282
val argType = if baseType != NoType then baseType.argTypesHi.head else defn.NothingType
83-
ref(defn.InternalQuoted_exprSplice).appliedToTypes(List(argType, defn.QuoteContextClass.typeRef)).appliedTo(pat)
83+
ref(defn.InternalQuoted_exprSplice).appliedToType(argType).appliedTo(pat)
8484
}
8585
else {
8686
ctx.error(i"Type must be fully defined.\nConsider annotating the splice using a type ascription:\n ($tree: XYZ).", tree.expr.sourcePos)
@@ -113,7 +113,12 @@ trait QuotesAndSplices {
113113
val qctxParam = untpd.makeParameter(qctxParamName, qctxParamTpt, untpd.Modifiers(Given))
114114
val expr = untpd.Function(List(qctxParam), tree.expr).withSpan(tree.span)
115115

116-
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSplice.termRef), expr), pt)(ctx1).withSpan(tree.span)
116+
val internalSplice =
117+
outerQctx match
118+
case Some(qctxRef) => untpd.Apply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprNestedSplice.termRef), qctxRef), expr)
119+
case _ => untpd.Apply(untpd.ref(defn.InternalQuoted_exprSplice.termRef), expr)
120+
121+
typedApply(internalSplice, pt)(ctx1).withSpan(tree.span)
117122
}
118123
}
119124

@@ -210,10 +215,7 @@ trait QuotesAndSplices {
210215
case Typed(Apply(fn, pat :: Nil), tpt) if fn.symbol == defn.InternalQuoted_exprSplice && !tpt.tpe.derivesFrom(defn.RepeatedParamClass) =>
211216
val tpt1 = transform(tpt) // Transform type bindings
212217
val exprTpt = AppliedTypeTree(TypeTree(defn.QuotedExprClass.typeRef), tpt1 :: Nil)
213-
val newSplice =
214-
ref(defn.InternalQuoted_exprSplice)
215-
.appliedToTypes(List(tpt1.tpe, defn.QuoteContextClass.typeRef))
216-
.appliedTo(Typed(pat, exprTpt))
218+
val newSplice = ref(defn.InternalQuoted_exprSplice).appliedToType(tpt1.tpe).appliedTo(Typed(pat, exprTpt))
217219
transform(newSplice)
218220
case Apply(fn, pat :: Nil) if fn.symbol == defn.InternalQuoted_exprSplice =>
219221
try ref(defn.InternalQuoted_patternHole.termRef).appliedToType(tree.tpe).withSpan(tree.span)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package scala.internal.quoted
2+
3+
import scala.annotation.{Annotation, compileTimeOnly}
4+
import scala.quoted._
5+
6+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime`")
7+
object CompileTime {
8+
9+
/** A term quote is desugared by the compiler into a call to this method */
10+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprQuote`")
11+
def exprQuote[T](x: T): QuoteContext ?=> Expr[T] = ???
12+
13+
/** A term splice is desugared by the compiler into a call to this method */
14+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprSplice`")
15+
def exprSplice[T](x: QuoteContext ?=> Expr[T]): T = ???
16+
17+
/** A term splice nested within a quote is desugared by the compiler into a call to this method.
18+
* `ctx` is the `QuoteContext` that the quote of this splice uses.
19+
*/
20+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprNestedSplice`")
21+
def exprNestedSplice[T](ctx: QuoteContext)(x: ctx.NestedContext ?=> Expr[T]): T = ???
22+
23+
/** A type quote is desugared by the compiler into a call to this method */
24+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.typeQuote`")
25+
def typeQuote[T <: AnyKind]: Type[T] = ???
26+
27+
/** A splice in a quoted pattern is desugared by the compiler into a call to this method */
28+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternHole`")
29+
def patternHole[T]: T = ???
30+
31+
/** A splice of a name in a quoted pattern is desugared by wrapping getting this annotation */
32+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternBindHole`")
33+
class patternBindHole extends Annotation
34+
35+
/** A splice of a name in a quoted pattern is that marks the definition of a type splice */
36+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternType`")
37+
class patternType extends Annotation
38+
39+
/** A type pattern that must be aproximated from above */
40+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.fromAbove`")
41+
class fromAbove extends Annotation
42+
43+
/** Artifact of pickled type splices
44+
*
45+
* During quote reification a quote `'{ ... F[$t] ... }` will be transformed into
46+
* `'{ @quoteTypeTag type T$1 = $t ... F[T$1] ... }` to have a tree for `$t`.
47+
* This artifact is removed during quote unpickling.
48+
*
49+
* See ReifyQuotes.scala and PickledQuotes.scala
50+
*/
51+
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.quoteTypeTag`")
52+
class quoteTypeTag extends Annotation
53+
54+
}

tests/neg/i4044b.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ def test(using QuoteContext) = {
44

55
'{
66
val qctx: QuoteContext = ???
7-
given qctx.type = qctx
7+
given x1 as qctx.type = qctx
88

99
val b = '{3}
1010

1111
'{
1212
val qctx: QuoteContext = ???
13-
given qctx.type = qctx
13+
given x2 as qctx.type = qctx
1414

1515
b // error
1616
${b}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
import scala.quoted._
3+
4+
inline def power(x: Double, inline n: Int) = ${ powerCode1('x, 'n) }
5+
6+
private def powerCode1(using qctx: QuoteContext)(x: Expr[Double], n: Expr[Int]): Expr[Double] =
7+
powerCode(x, n.value)
8+
9+
private def powerCode(using qctx: QuoteContext)(x: Expr[Double], n: Int): Expr[Double] =
10+
if (n == 0) Expr(1.0)
11+
else if (n == 1) x
12+
else if (n % 2 == 0) '{ val y = $x * $x; ${ powerCode('y, n / 2) } }
13+
else '{ $x * ${ powerCode(x, n - 1) } }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@main def Test = {
2+
println(power(5, 0))
3+
println(power(5, 1))
4+
println(power(5, 2))
5+
println(power(5, 3))
6+
}

0 commit comments

Comments
 (0)