diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index e2e494a95074..6d3b62357d7f 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -192,11 +192,9 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( case tp: TypeRef => tp.prefix match case NoPrefix if level > levelOf(tp.symbol) && !tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) => - val tp1 = tp.dealias - if tp1 != tp then apply(tp1) - else tryHeal(tp.symbol, tp, pos) + tryHealTypeOfType(tp.symbol, tp, pos) case prefix: ThisType if !tp.symbol.isStatic && level > levelOf(prefix.cls) => - tryHeal(tp.symbol, tp, pos) + tryHealTypeOfType(tp.symbol, tp, pos) case prefix: TermRef if tp.symbol.isTypeSplice => prefix.symbol.info.argInfos match case (tb: TypeBounds) :: _ => @@ -205,7 +203,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( // Heal explicit type splice in the code if level > 0 then getQuoteTypeTags.getTagRef(prefix) else tp case prefix: TermRef if !prefix.symbol.isStatic && level > levelOf(prefix.symbol) => - tryHeal(prefix.symbol, tp, pos) + tryHealTypeOfType(prefix.symbol, tp, pos) case _ => mapOver(tp) case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level > levelOf(tp.symbol) => @@ -217,6 +215,17 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( derivedAnnotatedType(tp, apply(tp.parent), tp.annot.derivedAnnotation(newAnnotTree)) case _ => mapOver(tp) + + /** Try to dealias or heal reference to type `T` used in a higher level than its definition. + * Returns a reference to a type tag generated by `QuoteTypeTags` that contains a + * reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`. + * Emits and error if `T` cannot be healed and returns `T`. + */ + private def tryHealTypeOfType(sym: Symbol, tp: TypeRef, pos: SrcPos)(using Context): Type = { + val tp1 = tp.dealias + if tp1 != tp then apply(tp1) + else tryHeal(tp.symbol, tp, pos) + } } /** Check phase consistency of terms and heal inconsistent type references. */ diff --git a/tests/pos-macros/i17037.scala b/tests/pos-macros/i17037.scala new file mode 100644 index 000000000000..1048d84ffe96 --- /dev/null +++ b/tests/pos-macros/i17037.scala @@ -0,0 +1,8 @@ +import scala.quoted.* + +class Foo: + type Bar = Int + +def macroImpl(using Quotes) = + val foo = new Foo + Type.of[foo.Bar] diff --git a/tests/pos-macros/i17037b.scala b/tests/pos-macros/i17037b.scala new file mode 100644 index 000000000000..60d2bec33330 --- /dev/null +++ b/tests/pos-macros/i17037b.scala @@ -0,0 +1,10 @@ +import scala.quoted.* + +class Foo: + type Bar = Int + +def macroImpl(using Quotes) = + val foo = Foo() + Type.of[foo.Bar] match + case '[foo.Bar] => '{true} + case _ => '{false} diff --git a/tests/pos-macros/i17037c.scala b/tests/pos-macros/i17037c.scala new file mode 100644 index 000000000000..56cd8f7a2d41 --- /dev/null +++ b/tests/pos-macros/i17037c.scala @@ -0,0 +1,7 @@ +import scala.quoted.* + +class Foo: + type Bar = Int + def macroImpl(using Quotes) = + val foo = new Foo + Type.of[this.Bar]