Skip to content

Commit

Permalink
Add support for clauseInterleaving in JVM generic signatures (#21709)
Browse files Browse the repository at this point in the history
Closes #21346
  • Loading branch information
hamzaremmal authored Oct 7, 2024
2 parents 6ceaab5 + fbe0e15 commit 588e0b9
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 27 deletions.
51 changes: 24 additions & 27 deletions compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import config.Printers.transforms
import reporting.trace
import java.lang.StringBuilder

import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer

/** Helper object to generate generic java signatures, as defined in
Expand Down Expand Up @@ -294,36 +295,13 @@ object GenericSignatures {
case ExprType(restpe) =>
jsig(defn.FunctionType(0).appliedTo(restpe))

case PolyType(tparams, mtpe: MethodType) =>
assert(tparams.nonEmpty)
case mtd: MethodOrPoly =>
val (tparams, vparams, rte) = collectMethodParams(mtd)
if (toplevel && !sym0.isConstructor) polyParamSig(tparams)
jsig(mtpe)

// Nullary polymorphic method
case PolyType(tparams, restpe) =>
assert(tparams.nonEmpty)
if (toplevel) polyParamSig(tparams)
builder.append("()")
methodResultSig(restpe)

case mtpe: MethodType =>
// erased method parameters do not make it to the bytecode.
def effectiveParamInfoss(t: Type)(using Context): List[List[Type]] = t match {
case t: MethodType if t.hasErasedParams =>
t.paramInfos.zip(t.erasedParams).collect{ case (i, false) => i }
:: effectiveParamInfoss(t.resType)
case t: MethodType => t.paramInfos :: effectiveParamInfoss(t.resType)
case _ => Nil
}
val params = effectiveParamInfoss(mtpe).flatten
val restpe = mtpe.finalResultType
builder.append('(')
// TODO: Update once we support varargs
params.foreach { tp =>
jsig(tp)
}
for vparam <- vparams do jsig(vparam)
builder.append(')')
methodResultSig(restpe)
methodResultSig(rte)

case tp: AndType =>
// Only intersections appearing as the upper-bound of a type parameter
Expand Down Expand Up @@ -475,4 +453,23 @@ object GenericSignatures {
}
else x
}

private def collectMethodParams(mtd: MethodOrPoly)(using Context): (List[TypeParamInfo], List[Type], Type) =
val tparams = ListBuffer.empty[TypeParamInfo]
val vparams = ListBuffer.empty[Type]

@tailrec def recur(tpe: Type): Type = tpe match
case mtd: MethodType =>
vparams ++= mtd.paramInfos.filterNot(_.hasAnnotation(defn.ErasedParamAnnot))
recur(mtd.resType)
case PolyType(tps, tpe) =>
tparams ++= tps
recur(tpe)
case _ =>
tpe
end recur

val rte = recur(mtd)
(tparams.toList, vparams.toList, rte)
end collectMethodParams
}
10 changes: 10 additions & 0 deletions tests/run/i21346.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
======'bar'======
<X;Y>
(X,Y)
scala.Tuple2<X, Y>
============
======'foo'======
<X;Y;Z;A>
(X,Y,Z,A)
scala.Tuple4<X, Y, Z, A>
============
14 changes: 14 additions & 0 deletions tests/run/i21346.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// scalajs: --skip

object Foo:
def foo[X, Y, Z](x: X, y: Y)[A](z: Z, a: A): (X, Y, Z, A) = (x, y, z, a)
def bar[X](x: X)[Y <: x.type](y: Y): (X, Y) = (x, y)

@main def Test =
val mtds = Foo.getClass().getDeclaredMethods().filterNot(_.getName() == "writeReplace").sortBy(_.getName())
for mtd <- mtds do
println(s"======'${mtd.getName()}'======")
println(mtd.getTypeParameters().mkString("<", ";", ">"))
println(mtd.getGenericParameterTypes().mkString("(", ",", ")"))
println(mtd.getGenericReturnType())
println("============")

0 comments on commit 588e0b9

Please sign in to comment.