From cbbae64eace76b8910170fd3022d1231a7de7ea5 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 4 Apr 2023 15:36:03 +0200 Subject: [PATCH 1/2] Use TermRef to distinguish distinct Type[T] instances We used the symbol before, but this ignored the specific path to the instance of Type[T]. Fixes #16959 --- .../tools/dotc/staging/QuoteTypeTags.scala | 6 +++--- .../dotty/tools/dotc/transform/Splicing.scala | 8 ++++---- tests/pos-macros/i16959/Macro_1.scala | 17 +++++++++++++++++ tests/pos-macros/i16959/Test_2.scala | 1 + 4 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 tests/pos-macros/i16959/Macro_1.scala create mode 100644 tests/pos-macros/i16959/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/staging/QuoteTypeTags.scala b/compiler/src/dotty/tools/dotc/staging/QuoteTypeTags.scala index c4c9c611be3a..d6f0a6576085 100644 --- a/compiler/src/dotty/tools/dotc/staging/QuoteTypeTags.scala +++ b/compiler/src/dotty/tools/dotc/staging/QuoteTypeTags.scala @@ -27,10 +27,10 @@ object QuoteTypeTags { class QuoteTypeTags(span: Span)(using Context) { import tpd.* - private val tags = collection.mutable.LinkedHashMap.empty[Symbol, TypeDef] + private val tags = collection.mutable.LinkedHashMap.empty[TermRef, TypeDef] def getTagRef(spliced: TermRef): TypeRef = { - val typeDef = tags.getOrElseUpdate(spliced.symbol, mkTagSymbolAndAssignType(spliced)) + val typeDef = tags.getOrElseUpdate(spliced, mkTagSymbolAndAssignType(spliced)) typeDef.symbol.typeRef } @@ -42,7 +42,7 @@ class QuoteTypeTags(span: Span)(using Context) { val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree) val local = newSymbol( owner = ctx.owner, - name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName, + name = UniqueName.fresh(rhs.tpe.dealias.typeSymbol.name.toTypeName), flags = Synthetic, info = TypeAlias(splicedTree.tpe.select(tpnme.Underlying)), coord = span).asType diff --git a/compiler/src/dotty/tools/dotc/transform/Splicing.scala b/compiler/src/dotty/tools/dotc/transform/Splicing.scala index bb82fba32a7c..e959f5d1451d 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicing.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicing.scala @@ -108,8 +108,8 @@ class Splicing extends MacroTransform: /** Number of holes created in this quote. Used for indexing holes. */ private var numHoles = 0 - /** Mapping from the term symbol of a `Type[T]` to it's hole. Used to deduplicate type holes. */ - private val typeHoles = mutable.Map.empty[Symbol, Hole] + /** Mapping from the term of a `Type[T]` to it's hole. Used to deduplicate type holes. */ + private val typeHoles = mutable.Map.empty[TermRef, Hole] override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match @@ -127,13 +127,13 @@ class Splicing extends MacroTransform: case tree: TypeDef if tree.symbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) => val tp @ TypeRef(qual: TermRef, _) = tree.rhs.tpe.hiBound: @unchecked quotedDefs += tree.symbol - val hole = typeHoles.get(qual.symbol) match + val hole = typeHoles.get(qual) match case Some (hole) => cpy.Hole(hole)(content = EmptyTree) case None => val holeIdx = numHoles numHoles += 1 val hole = tpd.Hole(false, holeIdx, Nil, ref(qual), TypeTree(tp)) - typeHoles.put(qual.symbol, hole) + typeHoles.put(qual, hole) hole cpy.TypeDef(tree)(rhs = hole) case Apply(Select(Apply(TypeApply(fn,_), List(code)),nme.apply),List(quotes)) diff --git a/tests/pos-macros/i16959/Macro_1.scala b/tests/pos-macros/i16959/Macro_1.scala new file mode 100644 index 000000000000..61483bff7ff1 --- /dev/null +++ b/tests/pos-macros/i16959/Macro_1.scala @@ -0,0 +1,17 @@ +import scala.quoted.* + +inline def test = ${ testImpl } + +def testImpl(using Quotes) = + import quotes.reflect.* + + val int = PackedType[Int] + val string = PackedType[String] + + assert(Type.show[(int.U, string.U, string.U)] == "scala.Tuple3[scala.Int, java.lang.String, java.lang.String]") + + '{ () } + +final class PackedType[T](using t: Type[T]): + opaque type U = T + given tpe: Type[U] = t diff --git a/tests/pos-macros/i16959/Test_2.scala b/tests/pos-macros/i16959/Test_2.scala new file mode 100644 index 000000000000..e9772d026451 --- /dev/null +++ b/tests/pos-macros/i16959/Test_2.scala @@ -0,0 +1 @@ +def app = test From 57a6867935840447a25c63b33b7612ab7422542d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 4 Apr 2023 15:39:21 +0200 Subject: [PATCH 2/2] Simplify tryHeal signature --- .../src/dotty/tools/dotc/staging/CrossStageSafety.scala | 4 ++-- compiler/src/dotty/tools/dotc/staging/HealType.scala | 4 ++-- compiler/src/dotty/tools/dotc/transform/Staging.scala | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala b/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala index 98e060488f43..ce0f323fe31a 100644 --- a/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala +++ b/compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala @@ -206,8 +206,8 @@ class CrossStageSafety extends TreeMapWithStages { * The tag is generated by an instance of `QuoteTypeTags` directly if the splice is explicit * or indirectly by `tryHeal`. */ - protected def healType(pos: SrcPos)(using Context) = - new HealType(pos) + protected def healType(pos: SrcPos)(tpe: Type)(using Context) = + new HealType(pos).apply(tpe) /** Check level consistency of terms references */ private def checkLevelConsistency(tree: Ident | This)(using Context): Unit = diff --git a/compiler/src/dotty/tools/dotc/staging/HealType.scala b/compiler/src/dotty/tools/dotc/staging/HealType.scala index 4f59e92241fb..50c2584b2fd0 100644 --- a/compiler/src/dotty/tools/dotc/staging/HealType.scala +++ b/compiler/src/dotty/tools/dotc/staging/HealType.scala @@ -51,7 +51,7 @@ class HealType(pos: SrcPos)(using Context) extends TypeMap { if level == 0 then tp else getQuoteTypeTags.getTagRef(prefix) case _: NamedType | _: ThisType | NoPrefix => if levelInconsistentRootOfPath(tp).exists then - tryHeal(tp.symbol, tp, pos) + tryHeal(tp) else tp case _ => @@ -82,7 +82,7 @@ class HealType(pos: SrcPos)(using Context) extends TypeMap { * reference to a type alias containing the equivalent of `${summon[quoted.Type[T]]}`. * Emits an error if `T` cannot be healed and returns `T`. */ - protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SrcPos): Type = { + protected def tryHeal(tp: TypeRef): Type = { val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp) val tag = ctx.typer.inferImplicitArg(reqType, pos.span) tag.tpe match diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 83b2bcdbcaa6..4fb5f5910440 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -36,8 +36,9 @@ class Staging extends MacroTransform { tree match { case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass => val checker = new CrossStageSafety { - override protected def healType(pos: SrcPos)(using Context) = new HealType(pos) { - override protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SrcPos): TypeRef = { + override protected def healType(pos: SrcPos)(tpe: Type)(using Context) = new HealType(pos) { + override protected def tryHeal(tp: TypeRef): TypeRef = { + val sym = tp.symbol def symStr = if (sym.is(ModuleClass)) sym.sourceModule.show else i"${sym.name}.this" @@ -51,7 +52,7 @@ class Staging extends MacroTransform { tp } - } + }.apply(tpe) } checker.transform(tree) case _ =>