Skip to content

Commit ebfa025

Browse files
committed
Refactor and document
1 parent df717b5 commit ebfa025

File tree

2 files changed

+38
-25
lines changed

2 files changed

+38
-25
lines changed

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

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,12 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
5151
if healedType == tree.tpe then tree
5252
else TypeTree(healedType).withSpan(tree.span)
5353

54-
case _: This =>
55-
tree.withType(healTermType(tree.sourcePos)(tree.tpe))
56-
case _: Ident =>
54+
case _: Ident | _: This =>
5755
tree.withType(healTermType(tree.sourcePos)(tree.tpe))
5856

5957
// Remove inline defs in quoted code. Already fully inlined.
60-
case tree: DefDef if tree.symbol.is(Inline) && level > 0 => EmptyTree
58+
case tree: DefDef if tree.symbol.is(Inline) && level > 0 =>
59+
EmptyTree
6160

6261
case tree: ValOrDefDef =>
6362
checkAnnotations(tree)
@@ -129,70 +128,84 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
129128
private def healInfo(tree: Tree, pos: SourcePosition)(using Context): Unit =
130129
tree.symbol.info = healType(pos)(tree.symbol.info)
131130

131+
/** If the refers to a locally defined symbol (either directly, or in a pickled type),
132+
* check that its staging level matches the current level.
133+
* - Static types and term are allowed at any level.
134+
* - If a type reference is used a higher level, then it is insosistent. Will atempt to heal before failing.
135+
* - If a term reference is used a different level, then it is insosistent.
136+
*
137+
* If `T` is a reference to a type at the wrong level, try to heal it by replacing it with
138+
* a type tag of type `quoted.Type[T]`.
139+
* The tag is generated by an instance of `QuoteTypeTags` directly if the splice is explicit
140+
* or indirectly by `tryHeal`.
141+
*/
132142
private def healType(pos: SourcePosition)(using Context) = new TypeMap {
133143
def apply(tp: Type): Type =
134144
tp match
135145
case tp: TypeRef =>
136146
tp.prefix match
137147
case NoPrefix if level > levelOf(tp.symbol) =>
138-
tryHeal(tp.symbol, tp, pos).getOrElse(tp)
148+
tryHeal(tp.symbol, tp, pos)
139149
case prefix: ThisType if !tp.symbol.isStatic && level > levelOf(prefix.cls) =>
140-
tryHeal(tp.symbol, tp, pos).getOrElse(tp)
150+
tryHeal(tp.symbol, tp, pos)
141151
case prefix: TermRef if tp.symbol.isSplice =>
142152
// Heal explice type splice in the code
143153
if level > 0 then getQuoteTypeTags.getTagRef(prefix) else tp
144154
case prefix: TermRef if !prefix.symbol.isStatic && level != levelOf(prefix.symbol) =>
145-
tryHeal(tp.symbol, tp, pos).getOrElse(tp)
155+
tryHeal(tp.symbol, tp, pos)
146156
case _ =>
147157
mapOver(tp)
148158
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
149159
levelError(tp.cls, tp, pos, "")
150-
tp
151160
case tp: AnnotatedType =>
152161
val newAnnotTree = transform(tp.annot.tree)
153162
derivedAnnotatedType(tp, apply(tp.parent), tp.annot.derivedAnnotation(newAnnotTree))
154163
case _ =>
155164
mapOver(tp)
156165
}
157166

167+
/** Check phase consistency of terms and heal incosistent type references. */
158168
private def healTermType(pos: SourcePosition)(using Context) = new TypeMap {
159169
def apply(tp: Type): Type =
160170
tp match
161171
case tp @ TypeRef(NoPrefix, _) if level > levelOf(tp.symbol) =>
162-
tryHeal(tp.symbol, tp, pos).getOrElse(tp)
172+
tryHeal(tp.symbol, tp, pos)
163173
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level != levelOf(tp.symbol) =>
164174
levelError(tp.symbol, tp, pos, "")
165-
tp
166175
case tp: ThisType if level != -1 && level != levelOf(tp.cls) =>
167176
levelError(tp.cls, tp, pos, "")
168-
tp
169177
case _ =>
170178
if tp.typeSymbol.is(Package) then tp
171179
else mapOver(tp)
172180
}
173181

174-
// TODO return new type or else old?
175-
protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(implicit ctx: Context): Option[TypeRef] = {
182+
/** Try to heal reference to type `T` used in a higher level than its definition.
183+
* Returns a reference to a type tag generated by `QuoteTypeTags` that contains a
184+
* refercence to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`.
185+
* Emits and error if `T` cannot be healed and returns `T`.
186+
*/
187+
protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(implicit ctx: Context): TypeRef = {
176188
val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp)
177189
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
178190
tag.tpe match
191+
179192
case tp: TermRef =>
180193
checkStable(tp, pos, "type witness")
181-
Some(getQuoteTypeTags.getTagRef(tp))
194+
getQuoteTypeTags.getTagRef(tp)
182195
case _: SearchFailureType =>
183196
levelError(sym, tp, pos,
184-
i"""
185-
|
186-
| The access would be accepted with the right type tag, but
187-
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
197+
i"""
198+
|
199+
| The access would be accepted with the right type tag, but
200+
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
188201
case _ =>
189202
levelError(sym, tp, pos,
190-
i"""
191-
|
192-
| The access would be accepted with a given $reqType""")
203+
i"""
204+
|
205+
| The access would be accepted with a given $reqType""")
193206
}
194207

195-
private def levelError(sym: Symbol, tp: Type, pos: SourcePosition, errMsg: String)(using Context) = {
208+
private def levelError(sym: Symbol, tp: Type, pos: SourcePosition, errMsg: String)(using Context): tp.type = {
196209
def symStr =
197210
if (!tp.isInstanceOf[ThisType]) sym.show
198211
else if (sym.is(ModuleClass)) sym.sourceModule.show
@@ -201,7 +214,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
201214
em"""access to $symStr from wrong staging level:
202215
| - the definition is at level ${levelOf(sym)},
203216
| - but the access is at level $level.$errMsg""", pos)
204-
None
217+
tp
205218
}
206219

207220
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class Staging extends MacroTransform {
4343
tree match {
4444
case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass =>
4545
val checker = new PCPCheckAndHeal(freshStagingContext) {
46-
override protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(implicit ctx: Context): Option[TypeRef] = {
46+
override protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(implicit ctx: Context): TypeRef = {
4747
def symStr =
4848
if (sym.is(ModuleClass)) sym.sourceModule.show
4949
else i"${sym.name}.this"
@@ -55,7 +55,7 @@ class Staging extends MacroTransform {
5555
| - the definition is at level ${levelOf(sym)},
5656
| - but the access is at level $level.$errMsg""")
5757

58-
None
58+
tp
5959
}
6060
}
6161
checker.transform(tree)

0 commit comments

Comments
 (0)