Skip to content

Commit

Permalink
Correct Java signature for value classes appearing in type arguments
Browse files Browse the repository at this point in the history
As suggested in #10846 the fix to this issue should be to port scala/scala#8127 to scala3

[Cherry-picked 2217634]
  • Loading branch information
jtjeferreira authored and WojciechMazur committed Jul 10, 2024
1 parent ea71c64 commit 6fbf4e7
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 15 deletions.
27 changes: 13 additions & 14 deletions compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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 {
Expand All @@ -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) =>
Expand Down Expand Up @@ -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
Expand All @@ -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("()")
Expand Down Expand Up @@ -339,23 +338,23 @@ 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
if (toplevel) polyParamSig(tParams)
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
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/i10347/C_2.java
Original file line number Diff line number Diff line change
@@ -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();
}
3 changes: 3 additions & 0 deletions tests/run/i10846.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
i10846.V: scala.Option<i10846.V>
i10846.U: scala.Option<i10846.U>
i10846.W: scala.Option<i10846.W<scala.Function1<java.lang.Object, java.lang.String>>>
28 changes: 28 additions & 0 deletions tests/run/i10846/i10846.scala
Original file line number Diff line number Diff line change
@@ -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[_]]
}

0 comments on commit 6fbf4e7

Please sign in to comment.