From c7e88c254ea6f07f65ba4d79471594b9e6bb1bf6 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 30 Nov 2022 11:41:09 +0000 Subject: [PATCH 1/3] Fix generic signature for type params bounded by primitive --- .../dotc/transform/GenericSignatures.scala | 28 +++++++++---------- .../generic-java-signatures/i15385/Lib.scala | 24 ++++++++++++++++ .../generic-java-signatures/i15385/Test.java | 18 ++++++++++++ 3 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 tests/generic-java-signatures/i15385/Lib.scala create mode 100644 tests/generic-java-signatures/i15385/Test.java diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index 9a6ab233e239..050abf7f3cb7 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -5,16 +5,19 @@ package transform import core.Annotations._ import core.Contexts._ import core.Phases._ +import core.Decorators.* import core.Definitions import core.Flags._ import core.Names.Name import core.Symbols._ import core.TypeApplications.{EtaExpansion, TypeParamInfo} -import core.TypeErasure.{erasedGlb, erasure, isGenericArrayElement} +import core.TypeErasure.{erasedGlb, erasure, fullErasure, isGenericArrayElement} import core.Types._ import core.classfile.ClassfileConstants import SymUtils._ import TypeUtils._ +import config.Printers.transforms +import reporting.trace import java.lang.StringBuilder import scala.collection.mutable.ListBuffer @@ -130,12 +133,12 @@ object GenericSignatures { else Right(parent)) - def paramSig(param: LambdaParam): Unit = { - builder.append(sanitizeName(param.paramName)) + def paramSig(param: TypeParamInfo): Unit = { + builder.append(sanitizeName(param.paramName.lastPart)) boundsSig(hiBounds(param.paramInfo.bounds)) } - def polyParamSig(tparams: List[LambdaParam]): Unit = + def polyParamSig(tparams: List[TypeParamInfo]): Unit = if (tparams.nonEmpty) { builder.append('<') tparams.foreach(paramSig) @@ -236,7 +239,11 @@ object GenericSignatures { tp match { case ref @ TypeParamRef(_: PolyType, _) => - typeParamSig(ref.paramName.lastPart) + 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) + else typeParamSig(ref.paramName.lastPart) case defn.ArrayOf(elemtp) => if (isGenericArrayElement(elemtp, isScala2 = false)) @@ -267,7 +274,7 @@ object GenericSignatures { else if (sym == defn.UnitClass) jsig(defn.BoxedUnitClass.typeRef) else builder.append(defn.typeTag(sym.info)) else if (ValueClasses.isDerivedValueClass(sym)) { - val erasedUnderlying = core.TypeErasure.fullErasure(tp) + val erasedUnderlying = fullErasure(tp) if (erasedUnderlying.isPrimitiveValueType && !primitiveOK) classSig(sym, pre, args) else @@ -334,15 +341,6 @@ object GenericSignatures { jsig(repr, primitiveOK = primitiveOK) case ci: ClassInfo => - def polyParamSig(tparams: List[TypeParamInfo]): Unit = - if (tparams.nonEmpty) { - builder.append('<') - tparams.foreach { tp => - builder.append(sanitizeName(tp.paramName.lastPart)) - boundsSig(hiBounds(tp.paramInfo.bounds)) - } - builder.append('>') - } val tParams = tp.typeParams if (toplevel) polyParamSig(tParams) superSig(ci.typeSymbol, ci.parents) diff --git a/tests/generic-java-signatures/i15385/Lib.scala b/tests/generic-java-signatures/i15385/Lib.scala new file mode 100644 index 000000000000..81b00d964b3f --- /dev/null +++ b/tests/generic-java-signatures/i15385/Lib.scala @@ -0,0 +1,24 @@ +class Loc(val idx: Int) extends AnyVal + +class Foo: + def testNoParam[A <: Int]: A = 1.asInstanceOf[A] + def testSingleParam[A <: Int](a: A): A = 2.asInstanceOf[A] // (I)I + def testSingleParam2[A <: Int](a: A): Box[A] = new Box[A](a) // (I)LBox; + def testSingleParam3[A <: Int](box: Box[A]): A = box.value // (LBox;)I + def testOtherReturn[A <: Int](a: A): String = "3" + def testNoErasure[A <: String](a: A): A = "4".asInstanceOf[A] + def testMultiParam[A <: Int, B <: String](a: A, b: B): A = 5.asInstanceOf[A] + + def testVCNoParam[A <: Loc]: A = Loc(1).asInstanceOf[A] + def testVCSingleParam[A <: Loc](a: A): A = Loc(2).asInstanceOf[A] + def testVCOtherReturn[A <: Loc](a: A): String = "3" + def testVCNoErasure[A <: String](a: A): A = "4".asInstanceOf[A] + def testVCMultiParam[A <: Loc, B <: String](a: A, b: B): A = Loc(5).asInstanceOf[A] + +class Box[T](val value: T) + +class BarParent[X, Y] +trait BarInterface[F, G] +abstract class Bar[A <: Int](a: A) extends BarParent[A, String] with BarInterface[Int, A]: + def getMap: Map[String, A] + def bar[B](a: A, b: B): (A, B, Int) diff --git a/tests/generic-java-signatures/i15385/Test.java b/tests/generic-java-signatures/i15385/Test.java new file mode 100644 index 000000000000..184f104d0fb0 --- /dev/null +++ b/tests/generic-java-signatures/i15385/Test.java @@ -0,0 +1,18 @@ +public class Test { + public static void main(String[] args) throws Exception { + Foo foo = new Foo(); + System.out.println(foo.testNoParam()); + System.out.println(foo.testSingleParam(2)); + System.out.println(foo.testSingleParam2(21).value()); + System.out.println(foo.testSingleParam3(new Box(22))); + System.out.println(foo.testOtherReturn(3)); + System.out.println(foo.testNoErasure("4")); + System.out.println(foo.testMultiParam(5, "5")); + + System.out.println(foo.testVCNoParam()); + System.out.println(foo.testVCSingleParam(2)); + System.out.println(foo.testVCOtherReturn(3)); + System.out.println(foo.testVCNoErasure("4")); + System.out.println(foo.testVCMultiParam(5, "5")); + } +} From 5cdb001a0585852b155885793fc17da8f4b2d583 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 12 Dec 2022 10:13:03 +0000 Subject: [PATCH 2/3] Drop no-longer-necessary guard to javaSig --- .../dotty/tools/backend/jvm/BCodeHelpers.scala | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala index 3cf7d88b9282..b3066b2ea3e9 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala @@ -847,19 +847,12 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { private def getGenericSignatureHelper(sym: Symbol, owner: Symbol, memberTpe: Type)(using Context): Option[String] = { if (needsGenericSignature(sym)) { - val erasedTypeSym = TypeErasure.fullErasure(sym.denot.info).typeSymbol - if (erasedTypeSym.isPrimitiveValueClass) { - // Suppress signatures for symbols whose types erase in the end to primitive - // value types. This is needed to fix #7416. - None - } else { - val jsOpt = GenericSignatures.javaSig(sym, memberTpe) - if (ctx.settings.XverifySignatures.value) { - jsOpt.foreach(verifySignature(sym, _)) - } - - jsOpt + val jsOpt = GenericSignatures.javaSig(sym, memberTpe) + if (ctx.settings.XverifySignatures.value) { + jsOpt.foreach(verifySignature(sym, _)) } + + jsOpt } else { None } From be10979dd09cae8e6a03180016602a234ce31832 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 12 Dec 2022 20:51:51 +0000 Subject: [PATCH 3/3] Revert "Drop no-longer-necessary guard to javaSig" This reverts commit 5cdb001a0585852b155885793fc17da8f4b2d583. Breaks in CI, here's a snippet: [info] Test dotty.tools.dotc.BootstrappedOnlyCompilationTests.posWithCompiler started -- Error: compiler/src/dotty/tools/dotc/transform/CapturedVars.scala:31:20 --------------------------------------------- 31 | private[this] var Captured: Store.Location[util.ReadOnlySet[Symbol]] = _ | ^ |compiler bug: created invalid generic signature for variable Captured in dotty.tools.dotc.transform.CapturedVars |signature: I |if this is reproducible, please report bug at https://github.com/lampepfl/dotty/issues | --- .../dotty/tools/backend/jvm/BCodeHelpers.scala | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala index b3066b2ea3e9..3cf7d88b9282 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala @@ -847,12 +847,19 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { private def getGenericSignatureHelper(sym: Symbol, owner: Symbol, memberTpe: Type)(using Context): Option[String] = { if (needsGenericSignature(sym)) { - val jsOpt = GenericSignatures.javaSig(sym, memberTpe) - if (ctx.settings.XverifySignatures.value) { - jsOpt.foreach(verifySignature(sym, _)) - } + val erasedTypeSym = TypeErasure.fullErasure(sym.denot.info).typeSymbol + if (erasedTypeSym.isPrimitiveValueClass) { + // Suppress signatures for symbols whose types erase in the end to primitive + // value types. This is needed to fix #7416. + None + } else { + val jsOpt = GenericSignatures.javaSig(sym, memberTpe) + if (ctx.settings.XverifySignatures.value) { + jsOpt.foreach(verifySignature(sym, _)) + } - jsOpt + jsOpt + } } else { None }