From 2680d2ad6d0a4ebeca34c85f7424b248519ef58a Mon Sep 17 00:00:00 2001
From: Jan Chyb <jan.chyb.99@gmail.com>
Date: Fri, 21 Mar 2025 18:22:34 +0100
Subject: [PATCH 1/3] Allow to unpickle a skolem type in more cases

---
 .../tools/dotc/core/tasty/TreeUnpickler.scala    |  3 ++-
 tests/pos/i22585-a/inline_1.scala                | 16 ++++++++++++++++
 tests/pos/i22585-a/main_2.scala                  |  5 +++++
 3 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 tests/pos/i22585-a/inline_1.scala
 create mode 100644 tests/pos/i22585-a/main_2.scala

diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index d6f2812dad0d..aa68ed61086f 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -507,7 +507,8 @@ class TreeUnpickler(reader: TastyReader,
     private def readSymNameRef()(using Context): Type = {
       val sym = readSymRef()
       val prefix = readType()
-      val res = NamedType(prefix, sym)
+      def pre = if TypeOps.isLegalPrefix(prefix) then prefix else QualSkolemType(prefix)
+      val res = NamedType(pre, sym)
       prefix match {
         case prefix: ThisType if (prefix.cls eq sym.owner) && !sym.is(Opaque) =>
           res.withDenot(sym.denot)
diff --git a/tests/pos/i22585-a/inline_1.scala b/tests/pos/i22585-a/inline_1.scala
new file mode 100644
index 000000000000..f8987a929655
--- /dev/null
+++ b/tests/pos/i22585-a/inline_1.scala
@@ -0,0 +1,16 @@
+import scala.quoted.*
+
+trait Hammer[I, O] {
+  def hammer(input: I): O
+}
+
+object Hammer {
+  inline def makeHammer[S, O](): Hammer[S, O] =
+    new Hammer[S, O] {
+      lazy val (hammer: Hammer[?, Int], idx: Int) = ???
+
+      override def hammer(input: S): O = {
+        hammer.hammer(???.asInstanceOf).asInstanceOf[O]
+      }
+    }
+}
diff --git a/tests/pos/i22585-a/main_2.scala b/tests/pos/i22585-a/main_2.scala
new file mode 100644
index 000000000000..d5260c0db07c
--- /dev/null
+++ b/tests/pos/i22585-a/main_2.scala
@@ -0,0 +1,5 @@
+object HammerSpec {
+  case class A(x: Int)
+  case class B(x: Int)
+  Hammer.makeHammer[A, B]()
+}

From b476bb6271a98ee27e4a2507825d600291f23e39 Mon Sep 17 00:00:00 2001
From: Jan Chyb <jan.chyb.99@gmail.com>
Date: Fri, 21 Mar 2025 20:14:11 +0100
Subject: [PATCH 2/3] Try not to update denotations that contains skolem types

---
 .../src/dotty/tools/dotc/core/Types.scala     | 47 ++++++++++++++-----
 tests/pos-macros/i22585-b/Macro.scala         | 18 +++++++
 tests/pos-macros/i22585-b/Test.scala          |  9 ++++
 tests/pos-macros/i22585-c/Macro.scala         | 22 +++++++++
 tests/pos-macros/i22585-c/Test.scala          |  5 ++
 5 files changed, 90 insertions(+), 11 deletions(-)
 create mode 100644 tests/pos-macros/i22585-b/Macro.scala
 create mode 100644 tests/pos-macros/i22585-b/Test.scala
 create mode 100644 tests/pos-macros/i22585-c/Macro.scala
 create mode 100644 tests/pos-macros/i22585-c/Test.scala

diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index df7700c73a17..810b441b20bc 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -2455,21 +2455,36 @@ object Types extends TypeUtils {
         d
       }
 
-      def fromDesignator = designator match {
+      def fromDesignator(lastdMaybe: Option[SingleDenotation]) = designator match {
         case name: Name =>
           val sym = lastSymbol
           val allowPrivate = sym == null || (sym == NoSymbol) || sym.lastKnownDenotation.flagsUNSAFE.is(Private)
           finish(memberDenot(name, allowPrivate))
         case sym: Symbol =>
           val symd = sym.lastKnownDenotation
-          if (symd.validFor.runId != ctx.runId && !stillValid(symd))
-            finish(memberDenot(symd.initial.name, allowPrivate = false))
-          else if (prefix.isArgPrefixOf(symd))
-            finish(argDenot(sym.asType))
-          else if (infoDependsOnPrefix(symd, prefix))
-            finish(memberDenot(symd.initial.name, allowPrivate = symd.is(Private)))
-          else
-            finish(symd.current)
+              if (symd.validFor.runId != ctx.runId && !stillValid(symd))
+                val res0 = memberDenot(symd.initial.name, allowPrivate = false)
+                val res = lastdMaybe match
+                  case Some(lastd) if hasSkolems(lastd.info) =>
+                    // When updating denotation, changing types from skolem may cause issues
+                    // with other parts of the tree
+                    finish(lastd.derivedSingleDenotation(res0.symbol, lastd.info, prefix))
+                  case _ =>
+                    res0
+                finish(res)
+              else if (prefix.isArgPrefixOf(symd))
+                finish(argDenot(sym.asType))
+              else if (infoDependsOnPrefix(symd, prefix))
+                val res = lastdMaybe match
+                  case Some(lastd) if hasSkolems(lastd.info) =>
+                    // When updating denotation, changing types from skolem may cause issues
+                    // with other parts of the tree
+                    finish(lastd.derivedSingleDenotation(sym, lastd.info, prefix))
+                  case _ =>
+                    memberDenot(symd.initial.name, allowPrivate = symd.is(Private))
+                finish(res)
+              else
+                finish(symd.current)
       }
 
       lastDenotation match {
@@ -2482,9 +2497,9 @@ object Types extends TypeUtils {
               if stillValid(lastd) && checkedPeriod.code != NowhereCode then finish(lastd.current)
               else finish(memberDenot(lastd.initial.name, allowPrivate = lastd.is(Private)))
             case _ =>
-              fromDesignator
+              fromDesignator(Some(lastd))
           }
-        case _ => fromDesignator
+        case _ => fromDesignator(None)
       }
     }
 
@@ -7024,6 +7039,16 @@ object Types extends TypeUtils {
     def isStable = true
   }
 
+  def hasSkolems(tpe: Type)(using Context) =
+    object hasSkolemsAcc extends TypeAccumulator[Boolean]:
+      def apply(x: Boolean, tp: Type): Boolean =
+        x || {
+          tp match
+            case _: SkolemType => true
+            case _ => foldOver(false, tp)
+        }
+    hasSkolemsAcc(false, tpe)
+
   // ----- Debug ---------------------------------------------------------
 
   @sharable var debugTrace: Boolean = false
diff --git a/tests/pos-macros/i22585-b/Macro.scala b/tests/pos-macros/i22585-b/Macro.scala
new file mode 100644
index 000000000000..6b203772e86e
--- /dev/null
+++ b/tests/pos-macros/i22585-b/Macro.scala
@@ -0,0 +1,18 @@
+import scala.quoted.*
+
+object Hammer2 {
+  inline def makeProductHammerMacro[I, O](): Hammer[I, O] =
+    ${ makeProductHammerMacroImpl[I, O] }
+
+  def makeProductHammerMacroImpl[I: Type, O: Type](using Quotes): Expr[Hammer[I, O]] =
+    '{ makeHammer[I, O]() }
+
+  inline def makeHammer[S, O](): Hammer[S, O] =
+    new Hammer[S, O] {
+      lazy val (hammer: Hammer[?, Int], idx: Int) = ???
+
+      override def hammer(input: S): O = {
+        hammer.hammer(???.asInstanceOf).asInstanceOf[O]
+      }
+    }
+}
\ No newline at end of file
diff --git a/tests/pos-macros/i22585-b/Test.scala b/tests/pos-macros/i22585-b/Test.scala
new file mode 100644
index 000000000000..80a00c296d78
--- /dev/null
+++ b/tests/pos-macros/i22585-b/Test.scala
@@ -0,0 +1,9 @@
+trait Hammer[I, O] {
+  def hammer(input: I): O
+}
+
+object HammerSpec {
+  case class A(x: Int)
+  case class B(x: Int)
+  Hammer2.makeProductHammerMacro[A, B]()
+}
\ No newline at end of file
diff --git a/tests/pos-macros/i22585-c/Macro.scala b/tests/pos-macros/i22585-c/Macro.scala
new file mode 100644
index 000000000000..0daf304ab3a7
--- /dev/null
+++ b/tests/pos-macros/i22585-c/Macro.scala
@@ -0,0 +1,22 @@
+import scala.quoted.*
+
+trait Hammer[I, O] {
+  def hammer(input: I): O
+}
+
+object Hammer {
+  inline def makeProductHammerMacro[I, O](): Hammer[I, O] =
+    ${ makeProductHammerMacroImpl[I, O] }
+
+  def makeProductHammerMacroImpl[I: Type, O: Type](using Quotes): Expr[Hammer[I, O]] =
+    '{ makeHammer[I, O]() }
+
+  inline def makeHammer[S, O](): Hammer[S, O] =
+    new Hammer[S, O] {
+      lazy val (hammer: Hammer[?, Int], idx: Int) = ???
+
+      override def hammer(input: S): O = {
+        hammer.hammer(???.asInstanceOf).asInstanceOf[O]
+      }
+    }
+}
\ No newline at end of file
diff --git a/tests/pos-macros/i22585-c/Test.scala b/tests/pos-macros/i22585-c/Test.scala
new file mode 100644
index 000000000000..6b09d1fb719c
--- /dev/null
+++ b/tests/pos-macros/i22585-c/Test.scala
@@ -0,0 +1,5 @@
+object HammerSpec {
+  case class A(x: Int)
+  case class B(x: Int)
+  Hammer.makeProductHammerMacro[A, B]()
+}
\ No newline at end of file

From 9fcd3ad6f91d159b936651e06b274bf15cea4db8 Mon Sep 17 00:00:00 2001
From: Jan Chyb <jan.chyb.99@gmail.com>
Date: Tue, 25 Mar 2025 14:15:28 +0100
Subject: [PATCH 3/3] Update run-test-pickling.excludelist

---
 compiler/test/dotc/run-test-pickling.excludelist | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/compiler/test/dotc/run-test-pickling.excludelist b/compiler/test/dotc/run-test-pickling.excludelist
index c880a4b78f23..89a3576476ab 100644
--- a/compiler/test/dotc/run-test-pickling.excludelist
+++ b/compiler/test/dotc/run-test-pickling.excludelist
@@ -50,3 +50,5 @@ named-tuples-strawman-2.scala
 typeCheckErrors.scala
 i18150.scala
 
+# issue caused by -Xprint-types
+decorators