@@ -51,13 +51,12 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
51
51
if healedType == tree.tpe then tree
52
52
else TypeTree (healedType).withSpan(tree.span)
53
53
54
- case _ : This =>
55
- tree.withType(healTermType(tree.sourcePos)(tree.tpe))
56
- case _ : Ident =>
54
+ case _ : Ident | _ : This =>
57
55
tree.withType(healTermType(tree.sourcePos)(tree.tpe))
58
56
59
57
// 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
61
60
62
61
case tree : ValOrDefDef =>
63
62
checkAnnotations(tree)
@@ -129,70 +128,84 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
129
128
private def healInfo (tree : Tree , pos : SourcePosition )(using Context ): Unit =
130
129
tree.symbol.info = healType(pos)(tree.symbol.info)
131
130
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
+ */
132
142
private def healType (pos : SourcePosition )(using Context ) = new TypeMap {
133
143
def apply (tp : Type ): Type =
134
144
tp match
135
145
case tp : TypeRef =>
136
146
tp.prefix match
137
147
case NoPrefix if level > levelOf(tp.symbol) =>
138
- tryHeal(tp.symbol, tp, pos).getOrElse(tp)
148
+ tryHeal(tp.symbol, tp, pos)
139
149
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)
141
151
case prefix : TermRef if tp.symbol.isSplice =>
142
152
// Heal explice type splice in the code
143
153
if level > 0 then getQuoteTypeTags.getTagRef(prefix) else tp
144
154
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)
146
156
case _ =>
147
157
mapOver(tp)
148
158
case tp : ThisType if level != - 1 && level != levelOf(tp.cls) =>
149
159
levelError(tp.cls, tp, pos, " " )
150
- tp
151
160
case tp : AnnotatedType =>
152
161
val newAnnotTree = transform(tp.annot.tree)
153
162
derivedAnnotatedType(tp, apply(tp.parent), tp.annot.derivedAnnotation(newAnnotTree))
154
163
case _ =>
155
164
mapOver(tp)
156
165
}
157
166
167
+ /** Check phase consistency of terms and heal incosistent type references. */
158
168
private def healTermType (pos : SourcePosition )(using Context ) = new TypeMap {
159
169
def apply (tp : Type ): Type =
160
170
tp match
161
171
case tp @ TypeRef (NoPrefix , _) if level > levelOf(tp.symbol) =>
162
- tryHeal(tp.symbol, tp, pos).getOrElse(tp)
172
+ tryHeal(tp.symbol, tp, pos)
163
173
case tp @ TermRef (NoPrefix , _) if ! tp.symbol.isStatic && level != levelOf(tp.symbol) =>
164
174
levelError(tp.symbol, tp, pos, " " )
165
- tp
166
175
case tp : ThisType if level != - 1 && level != levelOf(tp.cls) =>
167
176
levelError(tp.cls, tp, pos, " " )
168
- tp
169
177
case _ =>
170
178
if tp.typeSymbol.is(Package ) then tp
171
179
else mapOver(tp)
172
180
}
173
181
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 = {
176
188
val reqType = defn.QuotedTypeClass .typeRef.appliedTo(tp)
177
189
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
178
190
tag.tpe match
191
+
179
192
case tp : TermRef =>
180
193
checkStable(tp, pos, " type witness" )
181
- Some ( getQuoteTypeTags.getTagRef(tp) )
194
+ getQuoteTypeTags.getTagRef(tp)
182
195
case _ : SearchFailureType =>
183
196
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, " " )}""" )
188
201
case _ =>
189
202
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""" )
193
206
}
194
207
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 = {
196
209
def symStr =
197
210
if (! tp.isInstanceOf [ThisType ]) sym.show
198
211
else if (sym.is(ModuleClass )) sym.sourceModule.show
@@ -201,7 +214,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
201
214
em """ access to $symStr from wrong staging level:
202
215
| - the definition is at level ${levelOf(sym)},
203
216
| - but the access is at level $level. $errMsg""" , pos)
204
- None
217
+ tp
205
218
}
206
219
207
220
}
0 commit comments