From 42edcf7bb5399bba68cdc75a96a293cfe3e59c86 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Tue, 28 Oct 2025 11:44:58 +0100 Subject: [PATCH] fix: use underlying of VCs to compute generic signature --- .../dotc/transform/GenericSignatures.scala | 5 ++-- .../tools/dotc/transform/ValueClasses.scala | 5 ++++ tests/run/i24276.check | 12 +++++++++ tests/run/i24276.scala | 25 +++++++++++++++++++ tests/run/i8001/B_2.java | 2 +- 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/run/i24276.check create mode 100644 tests/run/i24276.scala diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index ed02587eb1f1..58d75e3c5524 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -276,8 +276,9 @@ object GenericSignatures { else builder.append(defn.typeTag(sym.info)) else if (sym.isDerivedValueClass) { if (unboxedVCs) { - val erasedUnderlying = fullErasure(tp) - jsig(erasedUnderlying, toplevel = toplevel, unboxedVCs = true) + val underlying = ValueClasses + .underlyingOfValueClass(sym.asClass, tp) + jsig(underlying, toplevel = toplevel, unboxedVCs = true) } else classSig(sym, pre, args) } else if (defn.isSyntheticFunctionClass(sym)) { diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala index 5cdd5d8ded43..13a3ce7c08a3 100644 --- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -44,4 +44,9 @@ object ValueClasses { /** The unboxed type that underlies a derived value class */ def underlyingOfValueClass(sym: ClassSymbol)(using Context): Type = valueClassUnbox(sym).info.resultType + + /** The unboxed type that underlies a derived value class as seen from as seen from tpe*/ + def underlyingOfValueClass(sym: ClassSymbol, tpe: Type)(using Context): Type = + valueClassUnbox(sym).info.resultType.asSeenFrom(tpe, sym) + } diff --git a/tests/run/i24276.check b/tests/run/i24276.check new file mode 100644 index 000000000000..b1fd06bf794d --- /dev/null +++ b/tests/run/i24276.check @@ -0,0 +1,12 @@ +public scala.Option> Foo.bar1(scala.Option>) +public scala.Option Foo.bar2(scala.Option) +public scala.Option Foo.bar3(scala.Option) +public A Foo.foo1(A) +public int Foo.foo2(int) +public java.lang.String Foo.foo3(java.lang.String) +public static scala.Option> Foo.sbar1(scala.Option>) +public static scala.Option Foo.sbar2(scala.Option) +public static scala.Option Foo.sbar3(scala.Option) +public static A Foo.sfoo1(A) +public static int Foo.sfoo2(int) +public static java.lang.String Foo.sfoo3(java.lang.String) diff --git a/tests/run/i24276.scala b/tests/run/i24276.scala new file mode 100644 index 000000000000..a03e06e8b8ff --- /dev/null +++ b/tests/run/i24276.scala @@ -0,0 +1,25 @@ +// scalajs: --skip + +class Box[A](value: A) extends AnyVal +class IBox(value: Int) extends AnyVal +class SBox(value: String) extends AnyVal + +class Foo: + def foo1[A](a: A): Box[A] = Box(a) + def foo2(a: IBox): IBox = a + def foo3(a: SBox): SBox = a + def bar1[A](opt: Option[Box[A]]): Option[Box[A]] = opt + def bar2[A](opt: Option[IBox]): Option[IBox] = opt + def bar3[A](opt: Option[SBox]): Option[SBox] = opt + +object Foo: + def sfoo1[A](a: A): Box[A] = Box(a) + def sfoo2(a: IBox): IBox = a + def sfoo3(a: SBox): SBox = a + def sbar1[A](opt: Option[Box[A]]): Option[Box[A]] = opt + def sbar2[A](opt: Option[IBox]): Option[IBox] = opt + def sbar3[A](opt: Option[SBox]): Option[SBox] = opt + +@main def Test = + for mtd <- classOf[Foo].getDeclaredMethods.sortBy(_.getName) do + println(mtd.toGenericString) diff --git a/tests/run/i8001/B_2.java b/tests/run/i8001/B_2.java index bde79bae36fb..31346721ca36 100644 --- a/tests/run/i8001/B_2.java +++ b/tests/run/i8001/B_2.java @@ -16,7 +16,7 @@ public static void test() { a.arr1(intArr); a.arr2(stringArr); - a.arr3(intArr); + a.arr3(intArr2); a.arr4(stringArr2); a.arrRef1(integerArr);