Skip to content

Backport "Align erasure of Array[Nothing] and Array[Null] with Scala 2" to 3.3 LTS #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,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
Expand Down Expand Up @@ -597,8 +597,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
Expand Down Expand Up @@ -779,12 +779,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
val eElem = erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp)
if eElem.isInstanceOf[WildcardType] then WildcardType
else JavaArrayType(eElem)
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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class PcInlayHintsProvider(
.headOption
.getOrElse(unit.tpdTree)
.enclosedChildren(pos.span)
.flatMap(tpdTree => deepFolder(InlayHints.empty(params.uri()), tpdTree).result())
.flatMap(tpdTree => deepFolder(InlayHints.empty(params.uri().nn), tpdTree).result())

private def adjustPos(pos: SourcePosition): SourcePosition =
pos.adjust(text)._1
Expand Down
2 changes: 2 additions & 0 deletions sbt-test/scala2-compat/erasure/build.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
ThisBuild / fork := true

lazy val scala2Lib = project.in(file("scala2Lib"))
.settings(
scalaVersion := sys.props("plugin.scala2Version")
Expand Down
6 changes: 6 additions & 0 deletions sbt-test/scala2-compat/erasure/dottyApp/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 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 = {}

}
8 changes: 6 additions & 2 deletions sbt-test/scala2-compat/erasure/dottyApp/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 =>
Expand Down
6 changes: 6 additions & 0 deletions sbt-test/scala2-compat/erasure/scala2Lib/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}

}