From 4a384e7aa9cec32070985bfc69d7951628780fbc Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 15 Apr 2021 17:59:55 +0200 Subject: [PATCH] Fix isInstanceOf[Array[?]] returning true on non-Array Before this commit, the `MultiArrayOf(elem, ndims)` extractor used to strip wildcards from the element type, this was surprising since it does not match what the `ArrayOf(elem)` extractor does, and lead to a bug in `TypeTestCasts.interceptTypeApply` which contains the following code: case defn.MultiArrayOf(elem, ndims) if isGenericArrayElement(elem, isScala2 = false) => `isGenericArrayElement` returns false for `Any` but true for `_ >: Nothing <: Any`, so the stripped wildcard means that this case was skipped, resulting in: x.isInstanceOf[Array[?]] being erased to: x.isInstanceOf[Object] instead of: scala.runtime.ScalaRunTime.isArray(x, 1) Fixed by tweaking `MultiArrayOf` to keep any final wildcard around like `ArrayOf` does. --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 7 ++++--- tests/run/array-erasure.scala | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 4ae31b2e05e8..c2762427539e 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1029,13 +1029,13 @@ class Definitions { /** An extractor for multi-dimensional arrays. * Note that this will also extract the high bound if an - * element type is a wildcard. E.g. + * element type is a wildcard upper-bounded by an array. E.g. * * Array[? <: Array[? <: Number]] * * would match * - * MultiArrayOf(, 2) + * MultiArrayOf(, 2) */ object MultiArrayOf { def apply(elem: Type, ndims: Int)(using Context): Type = @@ -1043,7 +1043,8 @@ class Definitions { def unapply(tp: Type)(using Context): Option[(Type, Int)] = tp match { case ArrayOf(elemtp) => def recur(elemtp: Type): Option[(Type, Int)] = elemtp.dealias match { - case TypeBounds(lo, hi) => recur(hi) + case tp @ TypeBounds(lo, hi @ MultiArrayOf(finalElemTp, n)) => + Some(finalElemTp, n) case MultiArrayOf(finalElemTp, n) => Some(finalElemTp, n + 1) case _ => Some(elemtp, 1) } diff --git a/tests/run/array-erasure.scala b/tests/run/array-erasure.scala index 264fe46c36e5..1ce727337a4f 100644 --- a/tests/run/array-erasure.scala +++ b/tests/run/array-erasure.scala @@ -65,5 +65,11 @@ object Test { arr4(x) arr5(x) arr6(x) + + + val str: Any = "" + assert(!str.isInstanceOf[Array[?]]) + assert(!str.isInstanceOf[Array[Array[?]]]) + assert(!str.isInstanceOf[Array[? <: Array[?]]]) } }