From c197afb0d7b2b17a081f7742d8f20118815447d4 Mon Sep 17 00:00:00 2001 From: Hamza Remmal <hamza@remmal.net> Date: Tue, 4 Feb 2025 21:04:54 +0100 Subject: [PATCH 1/3] fix: align erasure of Array[Nothing] and Array[Null] with Scala 2 --- .../src/dotty/tools/dotc/core/TypeErasure.scala | 14 ++++++++------ sbt-test/scala2-compat/erasure/dottyApp/Api.scala | 6 ++++++ sbt-test/scala2-compat/erasure/dottyApp/Main.scala | 4 ++++ sbt-test/scala2-compat/erasure/scala2Lib/Api.scala | 6 ++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 33a1b6ae789e..3ad0546761ea 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -596,8 +596,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst * will be returned. * * In all other situations, |T| will be computed as follow: - * - For a refined type scala.Array+[T]: - * - if T is Nothing or Null, []Object + * - For a refined type scala.Array[T]: + * - {Scala 2} if T is Nothing or Null, []Object * - otherwise, if T <: Object, []|T| * - otherwise, if T is a type parameter coming from Java, []Object * - otherwise, Object @@ -783,10 +783,12 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst val defn.ArrayOf(elemtp) = tp: @unchecked if (isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2)) defn.ObjectType else - try - val eElem = erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) - if eElem.isInstanceOf[WildcardType] then WildcardType - else JavaArrayType(eElem) + try + if sourceLanguage.isScala2 && (elemtp.isNullType || elemtp.isNothingType) then + JavaArrayType(defn.ObjectType) + else erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) match + case _: WildcardType => WildcardType + case elem => JavaArrayType(elem) catch case ex: Throwable => handleRecursive("erase array type", tp.show, ex) } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala index 7ce908820390..25fc4f6a0692 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala @@ -195,4 +195,10 @@ class Z { def objectARRAY_88(x: Array[Any]): Unit = {} def objectARRAY_89(x: Array[AnyRef]): Unit = {} def objectARRAY_90(x: Array[AnyVal]): Unit = {} + + def objectARRAY_91(x: Array[Nothing]): Unit = {} + def objectARRAY_92(x: Array[Null]): Unit = {} + def objectARRAY_93(x: Array[_ <: Nothing]): Unit = {} + def objectARRAY_94(x: Array[_ <: Null]): Unit = {} + } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala index be2c6c737316..a0f2df0c4e8c 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala @@ -101,6 +101,10 @@ object Main { z.objectARRAY_88(dummy) z.objectARRAY_89(dummy) z.objectARRAY_90(dummy) + z.objectARRAY_91(dummy) + z.objectARRAY_92(dummy) + z.objectARRAY_93(dummy) + z.objectARRAY_94(dummy) val methods = classOf[scala2Lib.Z].getDeclaredMethods.toList ++ classOf[dottyApp.Z].getDeclaredMethods.toList methods.foreach { m => diff --git a/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala b/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala index 2578f0556ecb..14a96b8e4004 100644 --- a/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala +++ b/sbt-test/scala2-compat/erasure/scala2Lib/Api.scala @@ -186,4 +186,10 @@ class Z { def objectARRAY_88(x: Array[Any]): Unit = {} def objectARRAY_89(x: Array[AnyRef]): Unit = {} def objectARRAY_90(x: Array[AnyVal]): Unit = {} + + def objectARRAY_91(x: Array[Nothing]): Unit = {} + def objectARRAY_92(x: Array[Null]): Unit = {} + def objectARRAY_93(x: Array[_ <: Nothing]): Unit = {} + def objectARRAY_94(x: Array[_ <: Null]): Unit = {} + } From da06de5a445892a06a7f661b3ce715a94cd13e5e Mon Sep 17 00:00:00 2001 From: Hamza Remmal <hamza@remmal.net> Date: Wed, 5 Feb 2025 14:57:01 +0100 Subject: [PATCH 2/3] fix: reliably run sbt-test scala2-compat/erasure --- sbt-test/scala2-compat/erasure/build.sbt | 2 ++ sbt-test/scala2-compat/erasure/dottyApp/Api.scala | 8 ++++---- sbt-test/scala2-compat/erasure/dottyApp/Main.scala | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sbt-test/scala2-compat/erasure/build.sbt b/sbt-test/scala2-compat/erasure/build.sbt index 694101e79388..f705299f549d 100644 --- a/sbt-test/scala2-compat/erasure/build.sbt +++ b/sbt-test/scala2-compat/erasure/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / fork := true + lazy val scala2Lib = project.in(file("scala2Lib")) .settings( scalaVersion := sys.props("plugin.scala2Version") diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala index 25fc4f6a0692..154e5027d2d1 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Api.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Api.scala @@ -196,9 +196,9 @@ class Z { def objectARRAY_89(x: Array[AnyRef]): Unit = {} def objectARRAY_90(x: Array[AnyVal]): Unit = {} - def objectARRAY_91(x: Array[Nothing]): Unit = {} - def objectARRAY_92(x: Array[Null]): Unit = {} - def objectARRAY_93(x: Array[_ <: Nothing]): Unit = {} - def objectARRAY_94(x: Array[_ <: Null]): Unit = {} + def nothing$ARRAY_91(x: Array[Nothing]): Unit = {} + def null$ARRAY_92(x: Array[Null]): Unit = {} + def nothing$ARRAY_93(x: Array[_ <: Nothing]): Unit = {} + def null$ARRAY_94(x: Array[_ <: Null]): Unit = {} } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala index a0f2df0c4e8c..ea359408692a 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala @@ -53,10 +53,10 @@ object Main { z.c_40(dummy) z.c_41(dummy) z.c_42(dummy) - z.b_43(dummy) + //z.b_43(dummy) z.c_44(dummy) z.c_45(dummy) - z.b_46(dummy) + //z.b_46(dummy) z.c_47(dummy) // z.a_48(dummy) // z.c_49(dummy) @@ -103,8 +103,8 @@ object Main { z.objectARRAY_90(dummy) z.objectARRAY_91(dummy) z.objectARRAY_92(dummy) - z.objectARRAY_93(dummy) - z.objectARRAY_94(dummy) + //z.objectARRAY_93(dummy) + //z.objectARRAY_94(dummy) val methods = classOf[scala2Lib.Z].getDeclaredMethods.toList ++ classOf[dottyApp.Z].getDeclaredMethods.toList methods.foreach { m => From f77b1f9ec59bb2c48f892d077dbfcf3d09d98698 Mon Sep 17 00:00:00 2001 From: Hamza Remmal <hamza@remmal.net> Date: Wed, 5 Feb 2025 15:53:15 +0100 Subject: [PATCH 3/3] fix: align Scala 2's erasure of Array[? <: Null] and Array[? <: Nothing] with Scala 2 --- .../dotty/tools/dotc/core/TypeErasure.scala | 18 +++++++++--------- .../scala2-compat/erasure/dottyApp/Main.scala | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 3ad0546761ea..4c705c4252c0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -326,7 +326,7 @@ object TypeErasure { val sym = t.symbol // Only a few classes have both primitives and references as subclasses. if (sym eq defn.AnyClass) || (sym eq defn.AnyValClass) || (sym eq defn.MatchableClass) || (sym eq defn.SingletonClass) - || isScala2 && !(t.derivesFrom(defn.ObjectClass) || t.isNullType) then + || isScala2 && !(t.derivesFrom(defn.ObjectClass) || t.isNullType | t.isNothingType) then NoSymbol // We only need to check for primitives because derived value classes in arrays are always boxed. else if sym.isPrimitiveValueClass then @@ -781,14 +781,14 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst private def eraseArray(tp: Type)(using Context) = { val defn.ArrayOf(elemtp) = tp: @unchecked - if (isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2)) defn.ObjectType - else - try - if sourceLanguage.isScala2 && (elemtp.isNullType || elemtp.isNothingType) then - JavaArrayType(defn.ObjectType) - else erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) match - case _: WildcardType => WildcardType - case elem => JavaArrayType(elem) + if isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2) then + defn.ObjectType + else if sourceLanguage.isScala2 && (elemtp.hiBound.isNullType || elemtp.hiBound.isNothingType) then + JavaArrayType(defn.ObjectType) + else + try erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp) match + case _: WildcardType => WildcardType + case elem => JavaArrayType(elem) catch case ex: Throwable => handleRecursive("erase array type", tp.show, ex) } diff --git a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala index ea359408692a..48b9575302a0 100644 --- a/sbt-test/scala2-compat/erasure/dottyApp/Main.scala +++ b/sbt-test/scala2-compat/erasure/dottyApp/Main.scala @@ -103,8 +103,8 @@ object Main { z.objectARRAY_90(dummy) z.objectARRAY_91(dummy) z.objectARRAY_92(dummy) - //z.objectARRAY_93(dummy) - //z.objectARRAY_94(dummy) + z.objectARRAY_93(dummy) + z.objectARRAY_94(dummy) val methods = classOf[scala2Lib.Z].getDeclaredMethods.toList ++ classOf[dottyApp.Z].getDeclaredMethods.toList methods.foreach { m =>