Skip to content

Commit 8f077ea

Browse files
committed
Fix scala#8302: WIP
1 parent a71e099 commit 8f077ea

File tree

5 files changed

+136
-55
lines changed

5 files changed

+136
-55
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package dotty.tools.dotc.core
22

3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core.Contexts._
5+
import dotty.tools.dotc.core.Types._
6+
import dotty.tools.dotc.core.Symbols._
37
import dotty.tools.dotc.core.Contexts._
48
import dotty.tools.dotc.util.Property
59

@@ -10,6 +14,8 @@ object StagingContext {
1014
/** A key to be used in a context property that tracks the quoteation level */
1115
private val QuotationLevel = new Property.Key[Int]
1216

17+
private val TaggedTypes = new Property.Key[mutable.LinkedHashMap[Symbol, TermRef]]
18+
1319
/** All enclosing calls that are currently inlined, from innermost to outermost. */
1420
def level(implicit ctx: Context): Int =
1521
ctx.property(QuotationLevel).getOrElse(0)
@@ -21,5 +27,12 @@ object StagingContext {
2127
/** Context with a decremented quotation level. */
2228
def spliceContext(implicit ctx: Context): Context =
2329
ctx.fresh.setProperty(QuotationLevel, level - 1)
30+
31+
def contextTaggedTypes(taggedTypes: mutable.LinkedHashMap[Symbol, TermRef])(implicit ctx: Context) =
32+
ctx.fresh.setProperty(TaggedTypes, taggedTypes)
33+
34+
def getTaggedTypes(implicit ctx: Context): mutable.LinkedHashMap[Symbol, TermRef] =
35+
ctx.property(TaggedTypes).get
36+
2437
}
2538

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

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import dotty.tools.dotc.transform.TreeMapWithStages._
2121
import dotty.tools.dotc.typer.Checking
2222
import dotty.tools.dotc.typer.Implicits.SearchFailureType
2323
import dotty.tools.dotc.typer.Inliner
24+
import dotty.tools.dotc.core.Annotations._
2425

2526
import scala.collection.mutable
2627
import dotty.tools.dotc.util.SourcePosition
@@ -54,10 +55,67 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
5455

5556
/** Transform quoted trees while maintaining phase correctness */
5657
override protected def transformQuotation(body: Tree, quote: Tree)(implicit ctx: Context): Tree = {
58+
val taggedTypes = mutable.LinkedHashMap.empty[Symbol, TermRef]
59+
given Context =
60+
if level(ctx) == 0 then contextTaggedTypes(taggedTypes)(ctx)
61+
else ctx
62+
5763
if (ctx.property(InAnnotation).isDefined)
5864
ctx.error("Cannot have a quote in an annotation", quote.sourcePos)
65+
66+
def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = {
67+
val splicedTree = tpd.ref(spliced).withSpan(quote.span)
68+
val rhs = splicedTree.select(tpnme.splice)
69+
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree)
70+
val local = ctx.newSymbol(
71+
owner = ctx.owner,
72+
name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName,
73+
flags = Synthetic,
74+
info = TypeAlias(splicedTree.tpe.select(tpnme.splice)),
75+
coord = spliced.termSymbol.coord).asType
76+
local.addAnnotation(Annotation(defn.InternalQuoted_QuoteTypeTagAnnot))
77+
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
78+
}
79+
5980
val body1 = transform(body)(quoteContext)
60-
super.transformQuotation(body1, quote)
81+
val body2 =
82+
if level == 0 then
83+
84+
val tags = taggedTypes.valuesIterator.map(tref => mkTagSymbolAndAssignType(tref)).toList
85+
86+
val map: Map[Symbol, Symbol] = taggedTypes.keys.lazyZip(tags.map(_.symbol)).toMap
87+
88+
def typeMap = new TypeMap() {
89+
def apply(tp: Type): Type = tp match {
90+
// case tp: TypeRef if tp.symbol.isSplice =>
91+
// tp.prefix match {
92+
// case prefix: TermRef =>
93+
// val tagDef = tagDefCache.getOrElseUpdate(prefix.symbol, mkTagSymbolAndAssignType(prefix))
94+
// tagDef.symbol.typeRef
95+
// }
96+
case AnnotatedType(parent, _) =>
97+
apply(parent) // Only keep the Annotated tree
98+
case _ =>
99+
mapOver(tp)
100+
}
101+
}
102+
103+
def treeMap(t: Tree): Tree = t match {
104+
case t: Ident => map.get(t.symbol).map(tpd.ref).getOrElse(t)
105+
case _ => t
106+
}
107+
val tagedTree =
108+
new TreeTypeMap(
109+
// typeMap = typeMap,
110+
treeMap = treeMap,
111+
substFrom = taggedTypes.keys.toList,
112+
substTo = tags.map(_.symbol)
113+
).apply(body1)
114+
tpd.Block(tags, tagedTree)
115+
116+
else body1
117+
super.transformQuotation(body2, quote)
118+
61119
}
62120

63121
/** Transform splice
@@ -212,10 +270,12 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
212270
protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(implicit ctx: Context): Option[Tree] = {
213271
val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp)
214272
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
273+
215274
tag.tpe match
216275
case tp: TermRef =>
217276
checkStable(tp, pos)
218-
Some(tag.select(tpnme.splice))
277+
getTaggedTypes.put(sym, tp)
278+
None
219279
case _: SearchFailureType =>
220280
levelError(sym, tp, pos,
221281
i"""

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

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -119,56 +119,56 @@ class ReifyQuotes extends MacroTransform {
119119
new QuoteReifier(this, capturers, nestedEmbedded, ctx.owner)(ctx)
120120
}
121121

122-
/** Assuming <expr> contains types `${<tag1>}, ..., ${<tagN>}`, the expression
123-
*
124-
* { @quoteTypeTag type <Type1> = ${<tag1>}
125-
* ...
126-
* @quoteTypeTag type <TypeN> = ${<tagN>}
127-
* <expr>
128-
* }
129-
*
130-
* references to `TypeI` in `expr` are rewired to point to the locally
131-
* defined versions. As a side effect, prepend the expressions `tag1, ..., `tagN`
132-
* as splices.
133-
*/
134-
private def addTags(expr: Tree)(implicit ctx: Context): Tree = {
135-
136-
def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = {
137-
val splicedTree = tpd.ref(spliced).withSpan(expr.span)
138-
val rhs = transform(splicedTree.select(tpnme.splice))
139-
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree)
140-
val local = ctx.newSymbol(
141-
owner = ctx.owner,
142-
name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName,
143-
flags = Synthetic,
144-
info = TypeAlias(splicedTree.tpe.select(tpnme.splice)),
145-
coord = spliced.termSymbol.coord).asType
146-
local.addAnnotation(Annotation(defn.InternalQuoted_QuoteTypeTagAnnot))
147-
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
148-
}
149-
150-
val tagDefCache = new mutable.LinkedHashMap[Symbol, TypeDef]()
151-
152-
def typeTagMap = new TypeMap() {
153-
def apply(tp: Type): Type = tp match {
154-
case tp: TypeRef if tp.symbol.isSplice =>
155-
tp.prefix match {
156-
case prefix: TermRef =>
157-
val tagDef = tagDefCache.getOrElseUpdate(prefix.symbol, mkTagSymbolAndAssignType(prefix))
158-
tagDef.symbol.typeRef
159-
}
160-
case AnnotatedType(parent, _) =>
161-
apply(parent) // Only keep the Annotated tree
162-
case _ =>
163-
mapOver(tp)
164-
}
165-
}
166-
167-
val tagedTree = new TreeTypeMap(typeMap = typeTagMap).apply(expr)
168-
169-
if (tagDefCache.isEmpty) expr
170-
else Block(tagDefCache.valuesIterator.toList, tagedTree)
171-
}
122+
// /** Assuming <expr> contains types `${<tag1>}, ..., ${<tagN>}`, the expression
123+
// *
124+
// * { @quoteTypeTag type <Type1> = ${<tag1>}
125+
// * ...
126+
// * @quoteTypeTag type <TypeN> = ${<tagN>}
127+
// * <expr>
128+
// * }
129+
// *
130+
// * references to `TypeI` in `expr` are rewired to point to the locally
131+
// * defined versions. As a side effect, prepend the expressions `tag1, ..., `tagN`
132+
// * as splices.
133+
// */
134+
// private def addTags(expr: Tree)(implicit ctx: Context): Tree = {
135+
136+
// def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = {
137+
// val splicedTree = tpd.ref(spliced).withSpan(expr.span)
138+
// val rhs = transform(splicedTree.select(tpnme.splice))
139+
// val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree)
140+
// val local = ctx.newSymbol(
141+
// owner = ctx.owner,
142+
// name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName,
143+
// flags = Synthetic,
144+
// info = TypeAlias(splicedTree.tpe.select(tpnme.splice)),
145+
// coord = spliced.termSymbol.coord).asType
146+
// local.addAnnotation(Annotation(defn.InternalQuoted_QuoteTypeTagAnnot))
147+
// ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
148+
// }
149+
150+
// val tagDefCache = new mutable.LinkedHashMap[Symbol, TypeDef]()
151+
152+
// def typeTagMap = new TypeMap() {
153+
// def apply(tp: Type): Type = tp match {
154+
// case tp: TypeRef if tp.symbol.isSplice =>
155+
// tp.prefix match {
156+
// case prefix: TermRef =>
157+
// val tagDef = tagDefCache.getOrElseUpdate(prefix.symbol, mkTagSymbolAndAssignType(prefix))
158+
// tagDef.symbol.typeRef
159+
// }
160+
// case AnnotatedType(parent, _) =>
161+
// apply(parent) // Only keep the Annotated tree
162+
// case _ =>
163+
// mapOver(tp)
164+
// }
165+
// }
166+
167+
// val tagedTree = new TreeTypeMap(typeMap = typeTagMap).apply(expr)
168+
169+
// if (tagDefCache.isEmpty) expr
170+
// else Block(tagDefCache.valuesIterator.toList, tagedTree)
171+
// }
172172

173173
/** Split `body` into a core and a list of embedded splices.
174174
* Then if inside a splice, make a hole from these parts.
@@ -365,10 +365,10 @@ class ReifyQuotes extends MacroTransform {
365365
level == 1 && levelOf(sym).contains(1) && capturers.contains(sym)
366366

367367
/** Transform `tree` and return the resulting tree and all `embedded` quotes
368-
* or splices as a pair, after performing the `addTags` transform.
368+
* or splices as a pair.
369369
*/
370370
private def splitQuote(tree: Tree)(implicit ctx: Context): (Tree, List[Tree]) = {
371-
val tree1 = addTags(transform(tree))
371+
val tree1 = transform(tree)
372372
(tree1, embedded.getTrees)
373373
}
374374

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class Staging extends MacroTransform {
4848
if (sym.is(ModuleClass)) sym.sourceModule.show
4949
else i"${sym.name}.this"
5050
val errMsg = s"\nin ${ctx.owner.fullName}"
51-
assert(false,
51+
assert(sym.isType && levelOf(sym).getOrElse(0) > 0,
5252
em"""access to $symStr from wrong staging level:
5353
| - the definition is at level ${levelOf(sym).getOrElse(0)},
5454
| - but the access is at level $level.$errMsg""")

tests/pos/i8302.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted._
2+
def foo[T](using qctx: QuoteContext, tpe: Type[T]): Expr[Any] =
3+
'{
4+
type TT = T
5+
val t = '[TT]
6+
???
7+
}
8+

0 commit comments

Comments
 (0)