Skip to content

Commit 9753dc6

Browse files
committed
WIP
1 parent f87554b commit 9753dc6

Some content is hidden

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

43 files changed

+248
-163
lines changed

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,8 +838,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
838838
* The result can be the contents of a term or type quote, which
839839
* will return a term or type tree respectively.
840840
*/
841-
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
842-
case tree: GenericApply[Type] if tree.symbol.isQuote => Some(tree.args.head)
841+
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[(tpd.Tree, tpd.Tree)] = tree match {
842+
case Apply(Apply(_, quoted :: Nil), qctx :: Nil) if tree.symbol.isQuote => Some((quoted, qctx))
843+
case TypeApply(_, quoted :: Nil) if tree.symbol.isQuote => Some((quoted, Literal(Constants.Constant(null))))
843844
case _ => None
844845
}
845846
}
@@ -856,6 +857,30 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
856857
case _ => None
857858
}
858859
}
860+
861+
/** Extractors for splices */
862+
object SplicedExpr {
863+
/** Extracts the content of a spliced tree.
864+
* The result can be the contents of a term or type splice, which
865+
* will return a term or type tree respectively.
866+
*/
867+
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
868+
case tree: tpd.Apply if tree.symbol.isSplice => Some(tree.args.head)
869+
case _ => None
870+
}
871+
}
872+
873+
/** Extractors for splices */
874+
object SplicedType {
875+
/** Extracts the content of a spliced tree.
876+
* The result can be the contents of a term or type splice, which
877+
* will return a term or type tree respectively.
878+
*/
879+
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
880+
case tree: tpd.Select if tree.symbol.isSplice => Some(tree.qualifier)
881+
case _ => None
882+
}
883+
}
859884
}
860885

861886
object TreeInfo {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import dotty.tools.dotc.core.Types._
1414
import dotty.tools.dotc.core.tasty.TreePickler.Hole
1515
import dotty.tools.dotc.core.tasty.{PositionPickler, TastyPickler, TastyPrinter, TastyString}
1616
import dotty.tools.dotc.core.tasty.TreeUnpickler.UnpickleMode
17+
import dotty.tools.dotc.tastyreflect.ReflectionImpl
1718

1819
import scala.internal.quoted._
1920
import scala.reflect.ClassTag
@@ -47,7 +48,7 @@ object PickledQuotes {
4748
forceAndCleanArtefacts.transform(unpickled)
4849
case expr: TastyTreeExpr[Tree] @unchecked => healOwner(expr.tree)
4950
case expr: FunctionAppliedTo[_] =>
50-
functionAppliedTo(quotedExprToTree(expr.f), expr.args.map(arg => quotedExprToTree(arg)).toList)
51+
functionAppliedTo(quotedExprToTree(expr.f), expr.args.map(arg => quotedExprToTree(arg(new scala.quoted.QuoteContext(ReflectionImpl(ctx))))).toList)
5152
}
5253

5354
/** Transform the expression into its fully spliced TypeTree */

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,14 +1274,15 @@ class TreeUnpickler(reader: TastyReader,
12741274
val args = until(end)(readTerm())
12751275
val splice = splices(idx)
12761276
def wrap(arg: Tree) =
1277-
if (arg.isTerm) new TastyTreeExpr(arg)
1277+
if (arg.isTerm) given (qctx: scala.quoted.QuoteContext) => new TastyTreeExpr(arg)
12781278
else new TreeType(arg)
12791279
val reifiedArgs = args.map(wrap)
12801280
val filled = if (isType) {
12811281
val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs)
12821282
PickledQuotes.quotedTypeToTree(quotedType)
12831283
} else {
1284-
val quotedExpr = splice.asInstanceOf[Seq[Any] => quoted.Expr[_]](reifiedArgs)
1284+
val splice1 = splice.asInstanceOf[Seq[Any] => given scala.quoted.QuoteContext => quoted.Expr[_]]
1285+
val quotedExpr = splice1(reifiedArgs) given new scala.quoted.QuoteContext(tastyreflect.ReflectionImpl(ctx))
12851286
PickledQuotes.quotedExprToTree(quotedExpr)
12861287
}
12871288
// We need to make sure a hole is created with the source file of the surrounding context, even if

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
365365
changePrec (GlobalPrec) {
366366
keywordStr("throw ") ~ toText(args.head)
367367
}
368-
else if (!printDebug && fun.hasType && fun.symbol == defn.InternalQuoted_exprQuote)
369-
keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
370-
else if (!printDebug && fun.hasType && fun.symbol == defn.InternalQuoted_exprSplice)
368+
else if (!printDebug && fun.hasType && fun.symbol == defn.InternalQuoted_exprQuote) {
369+
val Apply(_, args2) = fun
370+
keywordStr("'{") ~ toTextGlobal(args2, ", ") ~ keywordStr("}")
371+
} else if (!printDebug && fun.hasType && fun.symbol == defn.InternalQuoted_exprSplice)
371372
keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
372373
else if (app.isGivenApply && !homogenizedView)
373374
changePrec(InfixPrec) {

compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@ import dotty.tools.dotc.core.Decorators._
1414
import dotty.tools.dotc.tastyreflect.FromSymbol.{definitionFromSym, packageDefFromSym}
1515
import dotty.tools.dotc.parsing.Parsers.Parser
1616
import dotty.tools.dotc.typer.Implicits.{AmbiguousImplicits, DivergingImplicit, NoMatchingImplicits, SearchFailure, SearchFailureType}
17-
import dotty.tools.dotc.util.SourceFile
17+
import dotty.tools.dotc.util.{SourceFile, SourcePosition, Spans}
1818

1919
import scala.tasty.reflect.Kernel
2020

21-
class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util.SourcePosition) extends Kernel {
21+
class KernelImpl(val rootContext: core.Contexts.Context) extends Kernel {
2222

2323
private implicit def ctx: core.Contexts.Context = rootContext
2424

2525
def settings: Settings = rootContext.settings
2626

27+
def rootPosition: util.SourcePosition =
28+
tastyreflect.MacroExpansion.position.getOrElse(SourcePosition(rootContext.source, Spans.NoSpan))
29+
2730
//
2831
// CONTEXT
2932
//
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core._
5+
import dotty.tools.dotc.core.Contexts._
6+
import dotty.tools.dotc.util.{Property, SourcePosition, Spans}
7+
8+
object MacroExpansion {
9+
10+
private val MacroExpansionPosition = new Property.Key[SourcePosition]
11+
12+
def position(implicit ctx: Context): Option[SourcePosition] =
13+
ctx.property(MacroExpansionPosition)
14+
15+
def context(inlinedFrom: tpd.Tree)(implicit ctx: Context): Context =
16+
ctx.fresh.setProperty(MacroExpansionPosition, SourcePosition(inlinedFrom.source, inlinedFrom.span)).withSource(inlinedFrom.source)
17+
18+
}

compiler/src/dotty/tools/dotc/tastyreflect/ReflectionImpl.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,17 @@ package dotty.tools.dotc.tastyreflect
22

33
import dotty.tools.dotc.ast.tpd
44
import dotty.tools.dotc.core._
5-
import dotty.tools.dotc.util.{SourcePosition, Spans}
5+
import dotty.tools.dotc.core.Contexts._
66

77
import scala.quoted.show.SyntaxHighlight
88

99
object ReflectionImpl {
1010

1111
def apply(rootContext: Contexts.Context): scala.tasty.Reflection =
12-
apply(rootContext, SourcePosition(rootContext.source, Spans.NoSpan))
13-
14-
def apply(rootContext: Contexts.Context, rootPosition: SourcePosition): scala.tasty.Reflection =
15-
new scala.tasty.Reflection(new KernelImpl(rootContext, rootPosition))
12+
new scala.tasty.Reflection(new KernelImpl(rootContext))
1613

1714
def showTree(tree: tpd.Tree)(implicit ctx: Contexts.Context): String = {
18-
val refl = new scala.tasty.Reflection(new KernelImpl(ctx, tree.sourcePos))
15+
val refl = new scala.tasty.Reflection(new KernelImpl(MacroExpansion.context(tree)))
1916
val reflCtx = ctx.asInstanceOf[refl.Context]
2017
val reflTree = tree.asInstanceOf[refl.Tree]
2118
val syntaxHighlight =

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
4343
}
4444

4545
/** Transform quoted trees while maintaining phase correctness */
46-
override protected def transformQuotation(body: Tree, quote: Tree)(implicit ctx: Context): Tree = {
46+
override protected def transformQuotation(body: Tree, qctx: Tree, quote: Tree)(implicit ctx: Context): Tree = {
4747
val body1 = transform(body)(quoteContext)
48-
super.transformQuotation(body1, quote)
48+
val qctx1 = transform(qctx)
49+
super.transformQuotation(body1, qctx1, quote)
4950
}
5051

5152
/** Transform splice
@@ -75,7 +76,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
7576
protected def checkLevel(tree: Tree)(implicit ctx: Context): Tree = {
7677
def checkTp(tp: Type): Type = checkType(tree.sourcePos).apply(tp)
7778
tree match {
78-
case Quoted(_) | Spliced(_) =>
79+
case Quoted(_, _) | Spliced(_) =>
7980
tree
8081
case tree: RefTree if tree.symbol.isAllOf(InlineParam) =>
8182
tree

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

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -175,68 +175,65 @@ class ReifyQuotes extends MacroTransform {
175175
* `scala.quoted.Unpickler.unpickleExpr` that matches `tpe` with
176176
* core and splices as arguments.
177177
*/
178-
override protected def transformQuotation(body: Tree, quote: Tree)(implicit ctx: Context): Tree = {
178+
override protected def transformQuotation(body: Tree, qctx: Tree, quote: Tree)(implicit ctx: Context): Tree = {
179179
val isType = quote.symbol eq defn.InternalQuoted_typeQuote
180-
assert(!(body.symbol.isSplice && (body.isInstanceOf[GenericApply[_]] || body.isInstanceOf[Select])))
181180
if (level > 0) {
182181
val body1 = nested(isQuote = true).transform(body)(quoteContext)
183-
super.transformQuotation(body1, quote)
182+
super.transformQuotation(body1, qctx, quote)
184183
}
185184
else body match {
186185
case body: RefTree if isCaptured(body.symbol, level + 1) =>
187186
// Optimization: avoid the full conversion when capturing `x`
188187
// in '{ x } to '{ ${x$1} } and go directly to `x$1`
189-
capturers(body.symbol)(body)
188+
capturers(body.symbol)(body).select(nme.apply).appliedTo(qctx)
190189
case _=>
191190
val (body1, splices) = nested(isQuote = true).splitQuote(body)(quoteContext)
192191
if (level == 0) {
193192
val body2 =
194193
if (body1.isType) body1
195194
else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1)
196-
pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span)
195+
pickledQuote(body2, splices, qctx, body.tpe, isType).withSpan(quote.span)
197196
}
198197
else {
199198
body
200199
}
201200
}
202201
}
203202

204-
private def pickledQuote(body: Tree, splices: List[Tree], originalTp: Type, isType: Boolean)(implicit ctx: Context) = {
205-
206-
def liftedValue[T](value: T, name: TermName, qctx: Tree) =
203+
private def pickledQuote(body: Tree, splices: List[Tree], qctx: Tree, originalTp: Type, isType: Boolean)(implicit ctx: Context) = {
204+
def liftedValue[T](value: T, name: TermName) =
207205
ref(defn.LiftableModule).select(name).select("toExpr".toTermName).appliedTo(Literal(Constant(value))).appliedTo(qctx)
208206

209207
def pickleAsValue[T](value: T) = {
210-
val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, body.span)
211-
if (qctx.tpe.isInstanceOf[SearchFailureType])
212-
ctx.error(ctx.typer.missingArgMsg(qctx, defn.QuoteContextClass.typeRef, ""), ctx.source.atSpan(body.span))
213208
value match {
214209
case null => ref(defn.QuotedExprModule).select("nullExpr".toTermName).appliedTo(qctx)
215210
case _: Unit => ref(defn.QuotedExprModule).select("unitExpr".toTermName).appliedTo(qctx)
216-
case _: Boolean => liftedValue(value, "Liftable_Boolean_delegate".toTermName, qctx)
217-
case _: Byte => liftedValue(value, "Liftable_Byte_delegate".toTermName, qctx)
218-
case _: Short => liftedValue(value, "Liftable_Short_delegate".toTermName, qctx)
219-
case _: Int => liftedValue(value, "Liftable_Int_delegate".toTermName, qctx)
220-
case _: Long => liftedValue(value, "Liftable_Long_delegate".toTermName, qctx)
221-
case _: Float => liftedValue(value, "Liftable_Float_delegate".toTermName, qctx)
222-
case _: Double => liftedValue(value, "Liftable_Double_delegate".toTermName, qctx)
223-
case _: Char => liftedValue(value, "Liftable_Char_delegate".toTermName, qctx)
224-
case _: String => liftedValue(value, "Liftable_String_delegate".toTermName, qctx)
211+
case _: Boolean => liftedValue(value, "Liftable_Boolean_delegate".toTermName)
212+
case _: Byte => liftedValue(value, "Liftable_Byte_delegate".toTermName)
213+
case _: Short => liftedValue(value, "Liftable_Short_delegate".toTermName)
214+
case _: Int => liftedValue(value, "Liftable_Int_delegate".toTermName)
215+
case _: Long => liftedValue(value, "Liftable_Long_delegate".toTermName)
216+
case _: Float => liftedValue(value, "Liftable_Float_delegate".toTermName)
217+
case _: Double => liftedValue(value, "Liftable_Double_delegate".toTermName)
218+
case _: Char => liftedValue(value, "Liftable_Char_delegate".toTermName)
219+
case _: String => liftedValue(value, "Liftable_String_delegate".toTermName)
225220
}
226221
}
227222

228223
def pickleAsTasty() = {
229224
val meth =
230225
if (isType) ref(defn.Unpickler_unpickleType).appliedToType(originalTp)
231226
else ref(defn.Unpickler_unpickleExpr).appliedToType(originalTp.widen)
232-
def wildcardQuotedType = defn.QuotedTypeClass.typeRef.appliedTo(WildcardType)
233227
val spliceResType =
234-
if (isType) wildcardQuotedType
235-
else defn.QuotedExprClass.typeRef.appliedTo(defn.AnyType) | wildcardQuotedType
236-
meth.appliedTo(
237-
liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType),
238-
liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), spliceResType)))
228+
if (isType) defn.QuotedTypeClass.typeRef.appliedTo(WildcardType)
229+
else defn.FunctionType(1, isContextual = true).appliedTo(defn.QuoteContextClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(defn.AnyType)) | defn.QuotedTypeClass.typeRef.appliedTo(WildcardType)
230+
val pickledQuoteStrings = liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType)
231+
val splicesList = liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), spliceResType))
232+
val pickled = meth.appliedTo(pickledQuoteStrings, splicesList)
233+
if (isType) pickled
234+
else pickled.appliedTo(qctx)
239235
}
236+
240237
if (splices.nonEmpty) pickleAsTasty()
241238
else if (isType) {
242239
def tag(tagName: String) = ref(defn.QuotedTypeModule).select(tagName.toTermName)
@@ -315,7 +312,7 @@ class ReifyQuotes extends MacroTransform {
315312
assert(tpw.isInstanceOf[ValueType])
316313
val argTpe =
317314
if (tree.isType) defn.QuotedTypeClass.typeRef.appliedTo(tpw)
318-
else defn.QuotedExprClass.typeRef.appliedTo(tpw)
315+
else defn.FunctionType(1, isContextual = true).appliedTo(defn.QuoteContextClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(tpw))
319316
val selectArg = arg.select(nme.apply).appliedTo(Literal(Constant(i))).cast(argTpe)
320317
val capturedArg = SyntheticValDef(UniqueName.fresh(tree.symbol.name.toTermName).toTermName, selectArg)
321318
i += 1
@@ -356,7 +353,9 @@ class ReifyQuotes extends MacroTransform {
356353
val tree2 = transform(tree)
357354
capturers --= outer.localSymbols
358355

359-
seq(captured.result().valuesIterator.toList, tree2)
356+
val captures = captured.result().valuesIterator.toList
357+
if (captures.isEmpty) tree2
358+
else Block(captures, tree2)
360359
}
361360

362361
/** Returns true if this tree will be captured by `makeLambda`. Checks phase consistency and presence of capturer. */

0 commit comments

Comments
 (0)