Skip to content

Commit 559e218

Browse files
committed
Add scala.quoted.Scope
1 parent a2e7b73 commit 559e218

File tree

680 files changed

+3794
-3998
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

680 files changed

+3794
-3998
lines changed

.github/workflows/ci.yaml

Lines changed: 341 additions & 341 deletions
Large diffs are not rendered by default.

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Names._, StdNames._, NameOps._, Symbols._
88
import typer.ConstFold
99
import reporting.trace
1010
import dotty.tools.dotc.transform.SymUtils._
11+
import dotty.tools.dotc.transform.TypeUtils._
1112
import Decorators._
1213
import Constants.Constant
1314

@@ -397,7 +398,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
397398
case New(_) | Closure(_, _, _) =>
398399
Pure
399400
case TypeApply(fn, _) =>
400-
if (fn.symbol.is(Erased) || fn.symbol == defn.QuotedTypeModule_apply || fn.symbol == defn.Predef_classOf) Pure else exprPurity(fn)
401+
if (fn.symbol.is(Erased) || fn.symbol == defn.ScopeTypeModule_apply || fn.symbol == defn.Predef_classOf) Pure else exprPurity(fn)
401402
case Apply(fn, args) =>
402403
def isKnownPureOp(sym: Symbol) =
403404
sym.owner.isPrimitiveValueClass
@@ -907,7 +908,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
907908
* will return a type tree.
908909
*/
909910
def unapply(tree: tpd.Select)(using Context): Option[tpd.Tree] =
910-
if tree.symbol.isTypeSplice then Some(tree.qualifier) else None
911+
if tree.tpe.isTypeSplice || (tree.qualifier.tpe.widenTermRefExpr.typeSymbol == defn.ScopeTypeClass && tree.name == tpnme.spliceType) then Some(tree.qualifier)
912+
else None
911913
}
912914

913915
/** Extractor for not-null assertions.

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ object Trees {
5959
with Attachment.Container
6060
with printing.Showable {
6161

62+
type X <: AnyKind // FIXME used for reflection. find another way to add this type
63+
6264
if (Stats.enabled) ntrees += 1
6365

6466
/** This tree, widened to `Positioned`. Used to make clear we only need the

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

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -682,13 +682,18 @@ class Definitions {
682682
@tu lazy val ClassTagModule_apply: Symbol = ClassTagModule.requiredMethod(nme.apply)
683683
@tu lazy val ReflectPackageClass: Symbol = requiredPackage("scala.reflect.package").moduleClass
684684

685-
686-
@tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr")
687-
@tu lazy val QuotedExprModule: Symbol = QuotedExprClass.companionModule
685+
@tu lazy val QuotedExprModule: Symbol = requiredModule("scala.quoted.Expr")
688686
@tu lazy val QuotedExprModule_nullExpr: Symbol = QuotedExprModule.requiredMethod(nme.nullExpr)
689687
@tu lazy val QuotedExprModule_unitExpr: Symbol = QuotedExprModule.requiredMethod(nme.unitExpr)
690688

691-
@tu lazy val QuoteContextClass: ClassSymbol = requiredClass("scala.quoted.QuoteContext")
689+
@tu lazy val TastyReflectionClass: ClassSymbol = requiredClass("scala.tasty.Reflection")
690+
691+
@tu lazy val ScopeClass: ClassSymbol = requiredClass("scala.quoted.Scope")
692+
@tu lazy val ScopeTypeModule: Symbol = ScopeClass.requiredMethod("Type")
693+
@tu lazy val ScopeTypeModule_apply: Symbol = ScopeTypeModule.requiredMethod(nme.apply)
694+
@tu lazy val ScopeExprClass: Symbol = ScopeClass.typeRef.select(tpnme.Expr).typeSymbol
695+
@tu lazy val ScopeTypeClass: Symbol = ScopeClass.typeRef.select(tpnme.Type).typeSymbol
696+
@tu lazy val Scope_Type_splice: Symbol = ScopeClass.typeRef.select(tpnme.Type).select(tpnme.spliceType).typeSymbol
692697

693698
@tu lazy val LiftableModule: Symbol = requiredModule("scala.quoted.Liftable")
694699
@tu lazy val LiftableModule_BooleanIsLiftable: Symbol = LiftableModule.requiredMethod("BooleanIsLiftable")
@@ -720,14 +725,6 @@ class Definitions {
720725
@tu lazy val InternalQuotedTypeModule: Symbol = requiredModule("scala.internal.quoted.Type")
721726
@tu lazy val InternalQuotedType_unapply: Symbol = InternalQuotedTypeModule.requiredMethod(nme.unapply)
722727

723-
@tu lazy val QuotedTypeClass: ClassSymbol = requiredClass("scala.quoted.Type")
724-
@tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.spliceType)
725-
726-
@tu lazy val QuotedTypeModule: Symbol = QuotedTypeClass.companionModule
727-
@tu lazy val QuotedTypeModule_apply: Symbol = QuotedTypeModule.requiredMethod("apply")
728-
729-
@tu lazy val TastyReflectionClass: ClassSymbol = requiredClass("scala.tasty.Reflection")
730-
731728
@tu lazy val Unpickler_unpickleExpr: Symbol = requiredMethod("scala.internal.quoted.Unpickler.unpickleExpr")
732729
@tu lazy val Unpickler_unpickleType: Symbol = requiredMethod("scala.internal.quoted.Unpickler.unpickleType")
733730

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ object StagingContext {
1717
private val QuotationLevel = new Property.Key[Int]
1818

1919
/** A key to be used in a context property that tracks the quoteation stack.
20-
* Stack containing the QuoteContext references recieved by the surrounding quotes.
20+
* Stack containing the Scope references recieved by the surrounding quotes.
2121
*/
22-
private val QuoteContextStack = new Property.Key[List[tpd.Tree]]
22+
private val ScopeStack = new Property.Key[List[tpd.Tree]]
2323

2424
private val TaggedTypes = new Property.Key[PCPCheckAndHeal.QuoteTypeTags]
2525

@@ -31,11 +31,11 @@ object StagingContext {
3131
def quoteContext(using Context): Context =
3232
ctx.fresh.setProperty(QuotationLevel, level + 1)
3333

34-
/** Context with an incremented quotation level and pushes a refecence to a QuoteContext on the quote context stack */
35-
def pushQuoteContext(qctxRef: tpd.Tree)(using Context): Context =
36-
val old = ctx.property(QuoteContextStack).getOrElse(List.empty)
34+
/** Context with an incremented quotation level and pushes a refecence to a Scope on the quote scope stack */
35+
def pushScope(scopeRef: tpd.Tree)(using Context): Context =
36+
val old = ctx.property(ScopeStack).getOrElse(List.empty)
3737
ctx.fresh.setProperty(QuotationLevel, level + 1)
38-
.setProperty(QuoteContextStack, qctxRef :: old)
38+
.setProperty(ScopeStack, scopeRef :: old)
3939

4040
/** Context with a decremented quotation level. */
4141
def spliceContext(using Context): Context =
@@ -47,17 +47,23 @@ object StagingContext {
4747
def getQuoteTypeTags(using Context): PCPCheckAndHeal.QuoteTypeTags =
4848
ctx.property(TaggedTypes).get
4949

50-
/** Context with a decremented quotation level and pops the Some of top of the quote context stack or None if the stack is empty.
50+
/** Context with a decremented quotation level and pops the Some of top of the quote scope stack or None if the stack is empty.
5151
* The quotation stack could be empty if we are in a top level splice or an eroneous splice directly witin a top level splice.
5252
*/
53-
def popQuoteContext()(using Context): (Option[tpd.Tree], Context) =
53+
def popScope()(using Context): (Option[tpd.Tree], Context) =
5454
val ctx1 = ctx.fresh.setProperty(QuotationLevel, level - 1)
5555
val head =
56-
ctx.property(QuoteContextStack) match
56+
ctx.property(ScopeStack) match
5757
case Some(x :: xs) =>
58-
ctx1.setProperty(QuoteContextStack, xs)
58+
ctx1.setProperty(ScopeStack, xs)
5959
Some(x)
6060
case _ =>
6161
None // Splice at level 0 or lower
6262
(head, ctx1)
63+
64+
def peekScope()(implicit ctx: Context): Option[tpd.Tree] =
65+
ctx.property(ScopeStack) match
66+
case Some(x :: xs) => Some(x)
67+
case _ => None // Splice at level 0 or lower
68+
6369
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ object StdNames {
579579
val setSymbol: N = "setSymbol"
580580
val setType: N = "setType"
581581
val setTypeSignature: N = "setTypeSignature"
582-
val spliceType: N = "T"
582+
val spliceType: N = "X"
583583
val standardInterpolator: N = "standardInterpolator"
584584
val staticClass : N = "staticClass"
585585
val staticModule : N = "staticModule"

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ object Types {
9292
*/
9393
abstract class Type extends Hashable with printing.Showable {
9494

95+
type X <: AnyKind // FIXME used for reflection. find another way to add this type
96+
9597
// ----- Tests -----------------------------------------------------
9698

9799
// // debug only: a unique identifier for a type

compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import dotty.tools.dotc.core.tasty.TreePickler.Hole
1515
import dotty.tools.dotc.core.tasty.{ PositionPickler, TastyPickler, TastyPrinter }
1616
import dotty.tools.dotc.core.tasty.DottyUnpickler
1717
import dotty.tools.dotc.core.tasty.TreeUnpickler.UnpickleMode
18-
import dotty.tools.dotc.quoted.QuoteContext
18+
import dotty.tools.dotc.quoted.Scope
1919
import dotty.tools.dotc.tastyreflect.ReflectionImpl
2020

2121
import dotty.tools.tasty.TastyString
@@ -31,25 +31,12 @@ object PickledQuotes {
3131
def pickleQuote(tree: Tree)(using Context): PickledQuote =
3232
if (ctx.reporter.hasErrors) Nil
3333
else {
34-
assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x`
34+
// FIXME re-enable
35+
// assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x`
3536
val pickled = pickle(tree)
3637
TastyString.pickle(pickled)
3738
}
3839

39-
/** Transform the expression into its fully spliced Tree */
40-
def quotedExprToTree[T](expr: quoted.Expr[T])(using Context): Tree = {
41-
val expr1 = expr.asInstanceOf[scala.internal.quoted.Expr[Tree]]
42-
QuoteContext.checkScopeId(expr1.scopeId)
43-
healOwner(expr1.tree)
44-
}
45-
46-
/** Transform the expression into its fully spliced TypeTree */
47-
def quotedTypeToTree(tpe: quoted.Type[?])(using Context): Tree = {
48-
val tpe1 = tpe.asInstanceOf[scala.internal.quoted.Type[Tree]]
49-
QuoteContext.checkScopeId(tpe1.scopeId)
50-
healOwner(tpe1.typeTree)
51-
}
52-
5340
/** Unpickle the tree contained in the TastyExpr */
5441
def unpickleExpr(tasty: PickledQuote, splices: PickledArgs)(using Context): Tree = {
5542
val tastyBytes = TastyString.unpickle(tasty)
@@ -76,13 +63,13 @@ object PickledQuotes {
7663
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
7764
case Hole(isTerm, idx, args) =>
7865
val reifiedArgs = args.map { arg =>
79-
if (arg.isTerm) (using qctx: scala.quoted.QuoteContext) => new scala.internal.quoted.Expr(arg, QuoteContext.scopeId)
80-
else new scala.internal.quoted.Type(arg, QuoteContext.scopeId)
66+
if (arg.isTerm) (using scope: scala.quoted.Scope) => arg
67+
else arg
8168
}
8269
if isTerm then
83-
val splice1 = splices(idx).asInstanceOf[Seq[Any] => scala.quoted.QuoteContext ?=> quoted.Expr[?]]
84-
val quotedExpr = splice1(reifiedArgs)(using dotty.tools.dotc.quoted.QuoteContext())
85-
val filled = PickledQuotes.quotedExprToTree(quotedExpr)
70+
val splice1 = splices(idx).asInstanceOf[Seq[Any] => scala.quoted.Scope ?=> Tree]
71+
val quotedExpr = splice1(reifiedArgs)(using dotty.tools.dotc.quoted.Scope())
72+
val filled = PickledQuotes.healOwner(quotedExpr)
8673

8774
// We need to make sure a hole is created with the source file of the surrounding context, even if
8875
// it filled with contents a different source file.
@@ -91,8 +78,8 @@ object PickledQuotes {
9178
else
9279
// Replaces type holes generated by ReifyQuotes (non-spliced types).
9380
// These are types defined in a quote and used at the same level in a nested quote.
94-
val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.Type[?]](reifiedArgs)
95-
PickledQuotes.quotedTypeToTree(quotedType)
81+
val quotedType = splices(idx).asInstanceOf[Seq[Any] => Tree](reifiedArgs)
82+
PickledQuotes.healOwner(quotedType)
9683
case tree: Select =>
9784
// Retain selected members
9885
val qual = transform(tree.qualifier)
@@ -134,8 +121,8 @@ object PickledQuotes {
134121
assert(tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot))
135122
val tree = tdef.rhs match
136123
case TypeBoundsTree(_, Hole(_, idx, args), _) =>
137-
val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.Type[?]](args)
138-
PickledQuotes.quotedTypeToTree(quotedType)
124+
val quotedType = splices(idx).asInstanceOf[Seq[Any] => Tree](args)
125+
PickledQuotes.healOwner(quotedType)
139126
case TypeBoundsTree(_, tpt, _) =>
140127
tpt
141128
(tdef.symbol, tree.tpe)

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ class TreePickler(pickler: TastyPickler) {
734734

735735
def pickle(trees: List[Tree])(using Context): Unit = {
736736
trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree))
737-
def missing = forwardSymRefs.keysIterator.map(sym => sym.showLocated + "(line " + sym.sourcePos.line + ")").toList
737+
def missing = forwardSymRefs.keysIterator.map(sym => sym.showLocated + (if sym.sourcePos.exists then "(line " + sym.sourcePos.line + ")" else "")).toList
738738
assert(forwardSymRefs.isEmpty, i"unresolved symbols: $missing%, % when pickling ${ctx.source}")
739739
}
740740

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import scala.collection.mutable.ListBuffer
3838
import scala.collection.mutable
3939
import config.Printers.pickling
4040
import core.quoted.PickledQuotes
41-
import dotty.tools.dotc.quoted.QuoteContext
41+
import dotty.tools.dotc.quoted.Scope
4242

4343
import dotty.tools.tasty.TastyFormat._
4444

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
367367
else if (name.isTypeName) typeText(txt)
368368
else txt
369369
case tree @ Select(qual, name) =>
370-
if (!printDebug && tree.hasType && tree.symbol.isTypeSplice) typeText("${") ~ toTextLocal(qual) ~ typeText("}")
370+
if (!printDebug && tree.hasType && tree.tpe.asInstanceOf[Type].isTypeSplice) typeText("${") ~ toTextLocal(qual) ~ typeText("}")
371371
else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name))
372372
else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided (name != nme.CONSTRUCTOR || printDebug))
373373
case tree: This =>
@@ -630,11 +630,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
630630
}
631631
case Number(digits, kind) =>
632632
digits
633-
case Quote(tree) if tree.isTerm =>
633+
case Quote(tree) if !printDebug && tree.isTerm =>
634634
keywordStr("'{") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
635-
case Splice(tree) =>
635+
case Splice(tree) if !printDebug =>
636636
keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
637-
case TypSplice(tree) =>
637+
case TypSplice(tree) if !printDebug =>
638638
keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
639639
case tree: Applications.IntegratedTypeArgs =>
640640
toText(tree.app) ~ Str("(with integrated type args)").provided(printDebug)

compiler/src/dotty/tools/dotc/quoted/QuoteContext.scala

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.core.Contexts._
4+
import dotty.tools.dotc.tastyreflect.ReflectionImpl
5+
6+
object Scope {
7+
8+
def apply()(using Context): scala.quoted.Scope =
9+
new Scope(ReflectionImpl(summon[Context]))
10+
11+
}
12+
13+
class Scope(val tasty: scala.tasty.Reflection) extends scala.quoted.Scope

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import dotty.tools.dotc.core.Types._
1717
import dotty.tools.dotc.util.SourcePosition
1818
import dotty.tools.dotc.util.Spans._
1919
import dotty.tools.dotc.transform.SymUtils._
20+
import dotty.tools.dotc.transform.TypeUtils._
2021
import dotty.tools.dotc.transform.TreeMapWithStages._
2122
import dotty.tools.dotc.typer.Checking
2223
import dotty.tools.dotc.typer.Implicits.SearchFailureType
@@ -67,7 +68,6 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
6768
checkAnnotations(tree)
6869
super.transform(tree)
6970
else tree match {
70-
7171
case _: TypeTree | _: RefTree if tree.isType =>
7272
val healedType = healType(tree.sourcePos)(tree.tpe)
7373
if healedType == tree.tpe then tree
@@ -131,11 +131,14 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
131131
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
132132
val tp = healType(splice.sourcePos)(splice.tpe.widenTermRefExpr)
133133
cpy.Apply(splice)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), body1 :: Nil)
134-
case f @ Apply(fun @ TypeApply(_, _), qctx :: Nil) =>
134+
case f @ Apply(fun @ TypeApply(_, _), scope :: Nil) if splice.isTerm =>
135135
// Type of the splice itsel must also be healed
136136
// internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...)
137137
val tp = healType(splice.sourcePos)(splice.tpe.widenTermRefExpr)
138-
cpy.Apply(splice)(cpy.Apply(f)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), qctx :: Nil), body1 :: Nil)
138+
cpy.Apply(splice)(cpy.Apply(f)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), scope :: Nil), body1 :: Nil)
139+
case splice: Select =>
140+
val tagRef = getQuoteTypeTags.getTagRef(splice.qualifier.tpe.asInstanceOf[TermRef])
141+
ref(tagRef).withSpan(splice.span)
139142
}
140143
}
141144

@@ -181,7 +184,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
181184
else tryHeal(tp.symbol, tp, pos)
182185
case prefix: ThisType if !tp.symbol.isStatic && level > levelOf(prefix.cls) =>
183186
tryHeal(tp.symbol, tp, pos)
184-
case prefix: TermRef if tp.symbol.isTypeSplice =>
187+
case prefix: TermRef if tp.isTypeSplice =>
185188
prefix.symbol.info.argInfos match
186189
case (tb: TypeBounds) :: _ =>
187190
report.error(em"Cannot splice $tp because it is a wildcard type", pos)
@@ -222,8 +225,9 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
222225
* Emits and error if `T` cannot be healed and returns `T`.
223226
*/
224227
protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(using Context): TypeRef = {
225-
val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp)
228+
val reqType = getCurrentScope.tpe.select(tpnme.Type).appliedTo(tp)
226229
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
230+
227231
tag.tpe match
228232

229233
case tp: TermRef =>

0 commit comments

Comments
 (0)