Skip to content

Commit 35d9577

Browse files
committed
Refactor level checking / type healing logic
Disentangle level checking from type healing.
1 parent 4172269 commit 35d9577

File tree

2 files changed

+49
-51
lines changed

2 files changed

+49
-51
lines changed

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

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,26 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
6161
super.transform(tree)
6262
else tree match {
6363

64-
case _: TypeTree | _: RefTree if tree.isType =>
64+
case _: TypeTree | _: RefTree if tree.isType =>
6565
val healedType = healType(tree.srcPos)(tree.tpe)
6666
if healedType == tree.tpe then tree
6767
else TypeTree(healedType).withSpan(tree.span)
68+
case tree: Ident if isWildcardArg(tree) =>
69+
tree.withType(healType(tree.srcPos)(tree.tpe))
70+
case tree: Ident => // this is a term Ident
71+
checkLevelConsistency(tree)
72+
tree
73+
case tree: This =>
74+
checkLevelConsistency(tree)
75+
tree
6876
case _: AppliedTypeTree =>
6977
super.transform(tree) match
7078
case tree1: AppliedTypeTree if tree1 ne tree =>
7179
// propagate healed types
7280
tree1.withType(tree1.tpt.tpe.appliedTo(tree1.args.map(_.tpe)))
7381
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.
7982
case tree: DefDef if tree.symbol.is(Inline) && level > 0 =>
80-
EmptyTree
81-
83+
EmptyTree // Remove inline defs in quoted code. Already fully inlined.
8284
case tree: ValOrDefDef =>
8385
checkAnnotations(tree)
8486
healInfo(tree, tree.tpt.srcPos)
@@ -88,7 +90,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
8890
healInfo(tree, tree.srcPos)
8991
super.transform(tree)
9092
case tree: UnApply =>
91-
super.transform(tree).withType(healTypeOfTerm(tree.srcPos)(tree.tpe))
93+
super.transform(tree).withType(healType(tree.srcPos)(tree.tpe))
9294
case tree: TypeDef if tree.symbol.is(Case) && level > 0 =>
9395
report.error(reporting.CaseClassInInlinedCode(tree), tree)
9496
super.transform(tree)
@@ -118,7 +120,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
118120
if body.isTerm then
119121
// `quoted.runtime.Expr.quote[T](<body>)` --> `quoted.runtime.Expr.quote[T2](<body2>)`
120122
val TypeApply(fun, targs) = quote.fun: @unchecked
121-
val targs2 = targs.map(targ => TypeTree(healTypeOfTerm(quote.fun.srcPos)(stripAnnotsDeep(targ.tpe))))
123+
val targs2 = targs.map(targ => TypeTree(healType(quote.fun.srcPos)(stripAnnotsDeep(targ.tpe))))
122124
cpy.Apply(quote)(cpy.TypeApply(quote.fun)(fun, targs2), body2 :: Nil)
123125
else
124126
val quotes = quote.args.mapConserve(transform)
@@ -193,61 +195,57 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
193195
def apply(tp: Type): Type =
194196
tp match
195197
case tp: TypeRef =>
196-
tp.prefix match
197-
case NoPrefix if level > levelOf(tp.symbol) && !tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) =>
198-
tryHealTypeOfType(tp.symbol, tp, pos)
199-
case prefix: ThisType if !tp.symbol.isStatic && level > levelOf(prefix.cls) =>
200-
tryHealTypeOfType(tp.symbol, tp, pos)
201-
case prefix: TermRef if tp.symbol.isTypeSplice =>
202-
prefix.symbol.info.argInfos match
203-
case (tb: TypeBounds) :: _ =>
204-
report.error(em"Cannot splice $tp because it is a wildcard type", pos)
205-
case _ =>
206-
// Heal explicit type splice in the code
207-
if level > 0 then getQuoteTypeTags.getTagRef(prefix) else tp
208-
case prefix: TermRef if !prefix.symbol.isStatic && level > levelOf(prefix.symbol) =>
209-
tryHealTypeOfType(prefix.symbol, tp, pos)
210-
case _ =>
211-
mapOver(tp)
198+
healTypeRef(tp)
212199
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level > levelOf(tp.symbol) =>
213200
levelError(tp.symbol, tp, pos)
214-
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
215-
levelError(tp.cls, tp, pos)
216201
case tp: AnnotatedType =>
217202
val newAnnotTree = transform(tp.annot.tree)
218203
derivedAnnotatedType(tp, apply(tp.parent), tp.annot.derivedAnnotation(newAnnotTree))
219204
case _ =>
220205
mapOver(tp)
221206

222-
/** Try to dealias or heal reference to type `T` used in a higher level than its definition.
223-
* Returns a reference to a type tag generated by `QuoteTypeTags` that contains a
224-
* reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`.
225-
* Emits and error if `T` cannot be healed and returns `T`.
226-
*/
227-
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 !prefix.symbol.isStatic && level > levelOf(prefix.symbol) =>
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 =
228222
val tp1 = tp.dealias
229223
if tp1 != tp then apply(tp1)
230224
else tryHeal(tp.symbol, tp, pos)
231-
}
232-
}
233225

234-
/** Check phase consistency of terms and heal inconsistent type references. */
235-
private def healTypeOfTerm(pos: SrcPos)(using Context) = new TypeMap {
236-
def apply(tp: Type): Type =
237-
tp match
238-
case tp @ TypeRef(NoPrefix, _) if level > levelOf(tp.symbol) =>
239-
tryHeal(tp.symbol, tp, pos)
240-
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) =>
241-
levelError(tp.symbol, tp, pos)
242-
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
243-
levelError(tp.cls, tp, pos)
244-
case tp: AnnotatedType =>
245-
derivedAnnotatedType(tp, apply(tp.parent), tp.annot)
226+
private def checkNotWildcardSplice(splice: TypeRef)(using Context): Unit =
227+
splice.prefix.termSymbol.info.argInfos match
228+
case (tb: TypeBounds) :: _ => report.error(em"Cannot splice $splice because it is a wildcard type", pos)
246229
case _ =>
247-
if tp.typeSymbol.is(Package) then tp
248-
else mapOver(tp)
249230
}
250231

232+
/** Check level consistency of terms references */
233+
private def checkLevelConsistency(tree: Ident | This)(using Context): Unit =
234+
new TypeTraverser {
235+
def traverse(tp: Type): Unit =
236+
tp match
237+
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) =>
238+
levelError(tp.symbol, tp, tree.srcPos)
239+
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
240+
levelError(tp.cls, tp, tree.srcPos)
241+
case tp: AnnotatedType =>
242+
traverse(tp.parent)
243+
case _ if tp.typeSymbol.is(Package) =>
244+
// OK
245+
case _ =>
246+
traverseChildren(tp)
247+
}.traverse(tree.tpe)
248+
251249
/** Try to heal reference to type `T` used in a higher level than its definition.
252250
* Returns a reference to a type tag generated by `QuoteTypeTags` that contains a
253251
* reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ object TreeChecker {
678678
defn.FunctionOf(List(defn.QuotesClass.typeRef), expectedResultType, isContextual = true)
679679
val expectedContentType =
680680
defn.FunctionOf(argQuotedTypes, contextualResult)
681-
assert(content.typeOpt =:= expectedContentType)
681+
assert(content.typeOpt =:= expectedContentType, i"expected content of the hole to be ${expectedContentType} but got ${content.typeOpt}")
682682

683683
tree1
684684
}

0 commit comments

Comments
 (0)