From 8447d5a0bf0f1048545ca5c9a8d6781c8d3b7185 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 3 Mar 2021 16:44:03 +0100 Subject: [PATCH] Heal type within quote internal encoding Fixes #11587 --- .../dotc/transform/PCPCheckAndHeal.scala | 22 +++++++++++++------ tests/pos-macros/i11587.scala | 15 +++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/pos-macros/i11587.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index a356c270ea8c..34e2b444bace 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -37,8 +37,8 @@ import scala.annotation.constructorOnly * * Type healing consists in transforming a phase inconsistent type `T` into a splice of `${summon[Type[T]]}`. * - * As references to types do not necessarily have an assosiated tree it is not always possible to replace the types directly. - * Instead we always generate a type alias for it and palce it at the start of the surounding quote. This also avoids duplication. + * As references to types do not necessarily have an associated tree it is not always possible to replace the types directly. + * Instead we always generate a type alias for it and place it at the start of the surrounding quote. This also avoids duplication. * For example: * '{ * val x: List[T] = List[T]() @@ -118,7 +118,13 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( case Nil => body1 case tags => tpd.Block(tags, body1).withSpan(body.span) - super.transformQuotation(body2, quote) + quote match { + case Apply(fn1 @ TypeApply(fn0, targs), _) => + val targs1 = targs.map(targ => TypeTree(healTypeOfTerm(fn1.srcPos)(targ.tpe))) + cpy.Apply(quote)(cpy.TypeApply(fn1)(fn0, targs1), body2 :: Nil) + case quote: TypeApply => + cpy.TypeApply(quote)(quote.fun, body2 :: Nil) + } } /** Transform splice @@ -168,8 +174,8 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( /** If the type refers to a locally defined symbol (either directly, or in a pickled type), * check that its staging level matches the current level. * - Static types and term are allowed at any level. - * - If a type reference is used a higher level, then it is insosistent. Will atempt to heal before failing. - * - If a term reference is used a different level, then it is insosistent. + * - If a type reference is used a higher level, then it is inconsistent. Will attempt to heal before failing. + * - If a term reference is used a different level, then it is inconsistent. * * If `T` is a reference to a type at the wrong level, try to heal it by replacing it with * a type tag of type `quoted.Type[T]`. @@ -207,7 +213,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( mapOver(tp) } - /** Check phase consistency of terms and heal incosistent type references. */ + /** Check phase consistency of terms and heal inconsistent type references. */ private def healTypeOfTerm(pos: SrcPos)(using Context) = new TypeMap { def apply(tp: Type): Type = tp match @@ -217,6 +223,8 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( levelError(tp.symbol, tp, pos) case tp: ThisType if level != -1 && level != levelOf(tp.cls) => levelError(tp.cls, tp, pos) + case tp: AnnotatedType => + derivedAnnotatedType(tp, apply(tp.parent), tp.annot) case _ => if tp.typeSymbol.is(Package) then tp else mapOver(tp) @@ -224,7 +232,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( /** Try to 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 - * refercence to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`. + * reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`. * Emits and error if `T` cannot be healed and returns `T`. */ protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SrcPos)(using Context): TypeRef = { diff --git a/tests/pos-macros/i11587.scala b/tests/pos-macros/i11587.scala new file mode 100644 index 000000000000..bada464eb383 --- /dev/null +++ b/tests/pos-macros/i11587.scala @@ -0,0 +1,15 @@ +import scala.quoted._ +class Foo: + def foo[T: Type](using Quotes): Unit = '{ // level 1 + given Quotes = ??? + + Type.of[T] + + '{ ??? : T } // level 2 + + '{ // level 2 + given Quotes = ??? + Type.of[T] + '{ ??? : T } // level 3 + } + }