From 6fbf4e775d63270d86acff772127ecf2f27ed938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Thu, 23 May 2024 19:24:03 +0100 Subject: [PATCH] Correct Java signature for value classes appearing in type arguments As suggested in #10846 the fix to this issue should be to port https://github.com/scala/scala/pull/8127 to scala3 [Cherry-picked 2217634cdf2620a1fe97ab9929dad6ce87b57aed] --- .../dotc/transform/GenericSignatures.scala | 27 +++++++++--------- tests/pos/i10347/C_2.java | 2 +- tests/run/i10846.check | 3 ++ tests/run/i10846/i10846.scala | 28 +++++++++++++++++++ 4 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 tests/run/i10846.check create mode 100644 tests/run/i10846/i10846.scala diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index 7fbaef4bf221..e60561fb04e2 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -64,7 +64,7 @@ object GenericSignatures { ps.foreach(boxedSig) } - def boxedSig(tp: Type): Unit = jsig(tp.widenDealias, primitiveOK = false) + def boxedSig(tp: Type): Unit = jsig(tp.widenDealias, unboxedVCs = false) /** The signature of the upper-bound of a type parameter. * @@ -232,7 +232,7 @@ object GenericSignatures { } @noinline - def jsig(tp0: Type, toplevel: Boolean = false, primitiveOK: Boolean = true): Unit = { + def jsig(tp0: Type, toplevel: Boolean = false, unboxedVCs: Boolean = true): Unit = { val tp = tp0.dealias tp match { @@ -241,7 +241,7 @@ object GenericSignatures { val erasedUnderlying = fullErasure(ref.underlying.bounds.hi) // don't emit type param name if the param is upper-bounded by a primitive type (including via a value class) if erasedUnderlying.isPrimitiveValueType then - jsig(erasedUnderlying, toplevel, primitiveOK) + jsig(erasedUnderlying, toplevel, unboxedVCs) else typeParamSig(ref.paramName.lastPart) case defn.ArrayOf(elemtp) => @@ -269,15 +269,14 @@ object GenericSignatures { else if (sym == defn.NullClass) builder.append("Lscala/runtime/Null$;") else if (sym.isPrimitiveValueClass) - if (!primitiveOK) jsig(defn.ObjectType) + if (!unboxedVCs) jsig(defn.ObjectType) else if (sym == defn.UnitClass) jsig(defn.BoxedUnitClass.typeRef) else builder.append(defn.typeTag(sym.info)) else if (sym.isDerivedValueClass) { - val erasedUnderlying = fullErasure(tp) - if (erasedUnderlying.isPrimitiveValueType && !primitiveOK) - classSig(sym, pre, args) - else - jsig(erasedUnderlying, toplevel, primitiveOK) + if (unboxedVCs) { + val erasedUnderlying = fullErasure(tp) + jsig(erasedUnderlying, toplevel) + } else classSig(sym, pre, args) } else if (defn.isSyntheticFunctionClass(sym)) { val erasedSym = defn.functionTypeErasure(sym).typeSymbol @@ -286,7 +285,7 @@ object GenericSignatures { else if sym.isClass then classSig(sym, pre, args) else - jsig(erasure(tp), toplevel, primitiveOK) + jsig(erasure(tp), toplevel, unboxedVCs) case ExprType(restpe) if toplevel => builder.append("()") @@ -339,7 +338,7 @@ object GenericSignatures { val (reprParents, _) = splitIntersection(parents) val repr = reprParents.find(_.typeSymbol.is(TypeParam)).getOrElse(reprParents.head) - jsig(repr, primitiveOK = primitiveOK) + jsig(repr, unboxedVCs = unboxedVCs) case ci: ClassInfo => val tParams = tp.typeParams @@ -347,15 +346,15 @@ object GenericSignatures { superSig(ci.typeSymbol, ci.parents) case AnnotatedType(atp, _) => - jsig(atp, toplevel, primitiveOK) + jsig(atp, toplevel, unboxedVCs) case hktl: HKTypeLambda => - jsig(hktl.finalResultType, toplevel, primitiveOK) + jsig(hktl.finalResultType, toplevel, unboxedVCs) case _ => val etp = erasure(tp) if (etp eq tp) throw new UnknownSig - else jsig(etp, toplevel, primitiveOK) + else jsig(etp, toplevel, unboxedVCs) } } val throwsArgs = sym0.annotations flatMap ThrownException.unapply diff --git a/tests/pos/i10347/C_2.java b/tests/pos/i10347/C_2.java index 7525c5e7325d..6d3352a6e88f 100644 --- a/tests/pos/i10347/C_2.java +++ b/tests/pos/i10347/C_2.java @@ -1,5 +1,5 @@ public class C_2 { String hi = A.foo().head(); - String hy = A.bar().head(); + String hy = A.bar().head().s(); String hj = A.baz("").head(); } diff --git a/tests/run/i10846.check b/tests/run/i10846.check new file mode 100644 index 000000000000..ae6bbc8d4c3a --- /dev/null +++ b/tests/run/i10846.check @@ -0,0 +1,3 @@ +i10846.V: scala.Option +i10846.U: scala.Option +i10846.W: scala.Option>> diff --git a/tests/run/i10846/i10846.scala b/tests/run/i10846/i10846.scala new file mode 100644 index 000000000000..8ece0caca402 --- /dev/null +++ b/tests/run/i10846/i10846.scala @@ -0,0 +1,28 @@ +// scalajs: --skip + +package i10846 { + final class V(val x: Int) extends AnyVal + object V { def get: Option[V] = null } + + final class U(val y: String) extends AnyVal + object U { def get: Option[U] = null } + + final class W[T](val z: T) extends AnyVal + object W { def get: Option[W[Int => String]] = null } +} + + +object Test extends scala.App { + def check[T](implicit tt: reflect.ClassTag[T]): Unit = { + val companion = tt.runtimeClass.getClassLoader.loadClass(tt.runtimeClass.getName + '$') + val get = companion.getMethod("get") + assert(get.getReturnType == classOf[Option[_]]) + println(s"${tt.runtimeClass.getName}: ${get.getGenericReturnType}") + } + + import i10846._ + + check[V] + check[U] + check[W[_]] +}