@@ -21,6 +21,7 @@ import dotty.tools.dotc.core.Annotations._
21
21
import dotty .tools .dotc .util .Property
22
22
23
23
import scala .annotation .constructorOnly
24
+ import scala .quoted .runtime .Expr .splice
24
25
25
26
/** Checks that the Phase Consistency Principle (PCP) holds and heals types.
26
27
*
@@ -61,24 +62,26 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
61
62
super .transform(tree)
62
63
else tree match {
63
64
64
- case _ : TypeTree | _ : RefTree if tree.isType =>
65
+ case _ : TypeTree | _ : RefTree if tree.isType =>
65
66
val healedType = healType(tree.srcPos)(tree.tpe)
66
67
if healedType == tree.tpe then tree
67
68
else TypeTree (healedType).withSpan(tree.span)
69
+ case tree : Ident if isWildcardArg(tree) =>
70
+ tree.withType(healType(tree.srcPos)(tree.tpe))
71
+ case tree : Ident => // this is a term Ident
72
+ checkLevelConsistency(tree)
73
+ tree
74
+ case tree : This =>
75
+ checkLevelConsistency(tree)
76
+ tree
68
77
case _ : AppliedTypeTree =>
69
78
super .transform(tree) match
70
79
case tree1 : AppliedTypeTree if tree1 ne tree =>
71
80
// propagate healed types
72
81
tree1.withType(tree1.tpt.tpe.appliedTo(tree1.args.map(_.tpe)))
73
82
case tree1 => tree1
74
-
75
- case _ : Ident | _ : This =>
76
- tree.withType(healTypeOfTerm(tree.srcPos)(tree.tpe))
77
-
78
- // Remove inline defs in quoted code. Already fully inlined.
79
83
case tree : DefDef if tree.symbol.is(Inline ) && level > 0 =>
80
- EmptyTree
81
-
84
+ EmptyTree // Remove inline defs in quoted code. Already fully inlined.
82
85
case tree : ValOrDefDef =>
83
86
checkAnnotations(tree)
84
87
healInfo(tree, tree.tpt.srcPos)
@@ -88,7 +91,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
88
91
healInfo(tree, tree.srcPos)
89
92
super .transform(tree)
90
93
case tree : UnApply =>
91
- super .transform(tree).withType(healTypeOfTerm (tree.srcPos)(tree.tpe))
94
+ super .transform(tree).withType(healType (tree.srcPos)(tree.tpe))
92
95
case tree : TypeDef if tree.symbol.is(Case ) && level > 0 =>
93
96
report.error(reporting.CaseClassInInlinedCode (tree), tree)
94
97
super .transform(tree)
@@ -115,7 +118,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
115
118
if body.isTerm then
116
119
// `quoted.runtime.Expr.quote[T](<body>)` --> `quoted.runtime.Expr.quote[T2](<body2>)`
117
120
val TypeApply (fun, targs) = quote.fun: @ unchecked
118
- val targs2 = targs.map(targ => TypeTree (healTypeOfTerm (quote.fun.srcPos)(targ.tpe)))
121
+ val targs2 = targs.map(targ => TypeTree (healType (quote.fun.srcPos)(targ.tpe)))
119
122
cpy.Apply (quote)(cpy.TypeApply (quote.fun)(fun, targs2), body2 :: Nil )
120
123
else
121
124
val quotes = quote.args.mapConserve(transform)
@@ -190,61 +193,69 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
190
193
def apply (tp : Type ): Type =
191
194
tp match
192
195
case tp : TypeRef =>
193
- tp.prefix match
194
- case NoPrefix if level > levelOf(tp.symbol) && ! tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot ) =>
195
- tryHealTypeOfType(tp.symbol, tp, pos)
196
- case prefix : ThisType if ! tp.symbol.isStatic && level > levelOf(prefix.cls) =>
197
- tryHealTypeOfType(tp.symbol, tp, pos)
198
- case prefix : TermRef if tp.symbol.isTypeSplice =>
199
- prefix.symbol.info.argInfos match
200
- case (tb : TypeBounds ) :: _ =>
201
- report.error(em " Cannot splice $tp because it is a wildcard type " , pos)
202
- case _ =>
203
- // Heal explicit type splice in the code
204
- if level > 0 then getQuoteTypeTags.getTagRef(prefix) else tp
205
- case prefix : TermRef if ! prefix.symbol.isStatic && level > levelOf(prefix.symbol) =>
206
- tryHealTypeOfType(prefix.symbol, tp, pos)
207
- case _ =>
208
- mapOver(tp)
209
- case tp @ TermRef (NoPrefix , _) if ! tp.symbol.isStatic && level > levelOf(tp.symbol) =>
210
- levelError(tp.symbol, tp, pos)
211
- case tp : ThisType if level != - 1 && level != levelOf(tp.cls) =>
212
- levelError(tp.cls, tp, pos)
196
+ healTypeRef(tp)
197
+ case tp : TermRef =>
198
+ val inconsistentRoot = levelInconsistentRootOfPath(tp)
199
+ if inconsistentRoot.exists then levelError(inconsistent, tp, pos)
200
+ else tp
213
201
case tp : AnnotatedType =>
214
202
val newAnnotTree = transform(tp.annot.tree)
215
203
derivedAnnotatedType(tp, apply(tp.parent), tp.annot.derivedAnnotation(newAnnotTree))
216
204
case _ =>
217
205
mapOver(tp)
218
206
219
- /** Try to dealias or heal reference to type `T` used in a higher level than its definition.
220
- * Returns a reference to a type tag generated by `QuoteTypeTags` that contains a
221
- * reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`.
222
- * Emits and error if `T` cannot be healed and returns `T`.
223
- */
224
- private def tryHealTypeOfType (sym : Symbol , tp : TypeRef , pos : SrcPos )(using Context ): Type = {
207
+ private def healTypeRef (tp : TypeRef ): Type =
208
+ tp.prefix match
209
+ case prefix : TermRef if tp.symbol.isTypeSplice =>
210
+ checkNotWildcardSplice(tp)
211
+ if level == 0 then tp else getQuoteTypeTags.getTagRef(prefix)
212
+ case prefix : TermRef if levelInconsistentRootOfPath(prefix).exists =>
213
+ dealiasAndTryHeal(prefix.symbol, tp, pos)
214
+ case NoPrefix if level > levelOf(tp.symbol) && ! tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot ) =>
215
+ dealiasAndTryHeal(tp.symbol, tp, pos)
216
+ case prefix : ThisType if level > levelOf(prefix.cls) && ! tp.symbol.isStatic =>
217
+ dealiasAndTryHeal(tp.symbol, tp, pos)
218
+ case _ =>
219
+ mapOver(tp)
220
+
221
+ private def dealiasAndTryHeal (sym : Symbol , tp : TypeRef , pos : SrcPos )(using Context ): Type =
225
222
val tp1 = tp.dealias
226
223
if tp1 != tp then apply(tp1)
227
224
else tryHeal(tp.symbol, tp, pos)
228
- }
229
- }
230
225
231
- /** Check phase consistency of terms and heal inconsistent type references. */
232
- private def healTypeOfTerm (pos : SrcPos )(using Context ) = new TypeMap {
233
- def apply (tp : Type ): Type =
226
+ /** Return the root of this path if it is a variable defined in a previous level.
227
+ * If the path is consistent, return NoSymbol.
228
+ */
229
+ private def levelInconsistentRootOfPath (tp : Type )(using Context ): Symbol =
234
230
tp match
235
- case tp @ TypeRef (NoPrefix , _) if level > levelOf(tp.symbol ) =>
236
- tryHeal( tp.symbol, tp, pos )
237
- case tp @ TermRef ( NoPrefix , _) if ! tp.symbol.isStatic && level != levelOf(tp.symbol ) =>
238
- levelError(tp.symbol, tp, pos)
239
- case tp : ThisType if level != - 1 && level != levelOf(tp.cls) =>
240
- levelError(tp.cls, tp, pos)
241
- case tp : AnnotatedType =>
242
- derivedAnnotatedType(tp, apply(tp.parent), tp.annot )
231
+ case tp @ TermRef (NoPrefix , _) if ! tp.symbol.isStatic && level > levelOf(tp.termSymbol ) => tp.termSymbol
232
+ case tp @ TermRef (prefix, _) if ! tp.symbol.isStatic => levelInconsistentRootOfPath(prefix )
233
+ case tp : ThisType if level > levelOf(tp.cls ) => tp.cls
234
+ case _ => NoSymbol
235
+
236
+ private def checkNotWildcardSplice ( splice : TypeRef )( using Context ) : Unit =
237
+ splice.prefix.termSymbol.info.argInfos match
238
+ case ( tb : TypeBounds ) :: _ => report.error( em " Cannot splice $splice because it is a wildcard type " , pos )
243
239
case _ =>
244
- if tp.typeSymbol.is(Package ) then tp
245
- else mapOver(tp)
246
240
}
247
241
242
+ /** Check level consistency of terms references */
243
+ private def checkLevelConsistency (tree : Ident | This )(using Context ): Unit =
244
+ new TypeTraverser {
245
+ def traverse (tp : Type ): Unit =
246
+ tp match
247
+ case tp @ TermRef (NoPrefix , _) if ! tp.symbol.isStatic && level != levelOf(tp.symbol) =>
248
+ levelError(tp.symbol, tp, tree.srcPos)
249
+ case tp : ThisType if level != - 1 && level != levelOf(tp.cls) =>
250
+ levelError(tp.cls, tp, tree.srcPos)
251
+ case tp : AnnotatedType =>
252
+ traverse(tp.parent)
253
+ case _ if tp.typeSymbol.is(Package ) =>
254
+ // OK
255
+ case _ =>
256
+ traverseChildren(tp)
257
+ }.traverse(tree.tpe)
258
+
248
259
/** Try to heal reference to type `T` used in a higher level than its definition.
249
260
* Returns a reference to a type tag generated by `QuoteTypeTags` that contains a
250
261
* reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`.
0 commit comments