From 45388755873246a8f5294b91dc3ad67ee2a8adfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 6 Oct 2023 10:36:55 +0200 Subject: [PATCH] Fix #18658: Handle varargs of generic types in `JSExportsGen`. When extracting the type of a varargs parameter, we have to go back to before erasure. However, that gives us a non-erased type inside as well. We need to re-erase that type to get something sensible for the back-end. --- .../tools/dotc/transform/sjs/JSSymUtils.scala | 2 +- .../jsinterop/NonNativeJSTypeTestScala3.scala | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tests/sjs-junit/test/org/scalajs/testsuite/jsinterop/NonNativeJSTypeTestScala3.scala diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala index 115d41dd3d46..ae6635bce622 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala @@ -185,7 +185,7 @@ object JSSymUtils { val list = for ((name, info) <- paramNamesAndTypes) yield { val v = - if (info.isRepeatedParam) Some(info.repeatedToSingle.widenDealias) + if (info.isRepeatedParam) Some(TypeErasure.erasure(info.repeatedToSingle)) else None name -> v } diff --git a/tests/sjs-junit/test/org/scalajs/testsuite/jsinterop/NonNativeJSTypeTestScala3.scala b/tests/sjs-junit/test/org/scalajs/testsuite/jsinterop/NonNativeJSTypeTestScala3.scala new file mode 100644 index 000000000000..ceb29d39b6a0 --- /dev/null +++ b/tests/sjs-junit/test/org/scalajs/testsuite/jsinterop/NonNativeJSTypeTestScala3.scala @@ -0,0 +1,78 @@ +package org.scalajs.testsuite.jsinterop + +import org.junit.Assert.* +import org.junit.Test + +import scala.scalajs.js +import scala.scalajs.js.annotation.* + +class NonNativeJSTypeTestScala3 { + import NonNativeJSTypeTestScala3.* + + @Test + def overloadWithVarargOfGenericType(): Unit = { + class OverloadWithVarargOfGenericType extends js.Object { + def overloaded(x: Int): Int = x + def overloaded(xs: (Int, Int)*): Int = xs.size + } + + val obj = new OverloadWithVarargOfGenericType + assertEquals(5, obj.overloaded(5)) + assertEquals(1, obj.overloaded((5, 6))) + assertEquals(2, obj.overloaded((1, 2), (3, 4))) + } + + @Test + def overloadWithVarargOfValueClass(): Unit = { + class OverloadWithVarargOfValueClass extends js.Object { + def overloaded(x: Int): Int = x + def overloaded(xs: VC*): Int = xs.size + } + + val obj = new OverloadWithVarargOfValueClass + assertEquals(5, obj.overloaded(5)) + assertEquals(1, obj.overloaded(new VC(5))) + assertEquals(2, obj.overloaded(new VC(5), new VC(6))) + } + + @Test + def overloadWithVarargOfGenericValueClass(): Unit = { + class OverloadWithVarargOfGenericValueClass extends js.Object { + def overloaded(x: Int): Int = x + def overloaded(xs: GenVC[Int]*): Int = xs.size + } + + val obj = new OverloadWithVarargOfGenericValueClass + assertEquals(5, obj.overloaded(5)) + assertEquals(1, obj.overloaded(new GenVC(5))) + assertEquals(2, obj.overloaded(new GenVC(5), new GenVC(6))) + } + + @Test + def overloadWithVarargOfOpaqueTypeAlias(): Unit = { + import OpaqueContainer.* + + class OverloadWithVarargOfOpaqueTypeAlias extends js.Object { + def overloaded(x: String): Int = x.toInt + def overloaded(xs: OpaqueInt*): Int = xs.size + } + + val obj = new OverloadWithVarargOfOpaqueTypeAlias + assertEquals(5, obj.overloaded("5")) + assertEquals(1, obj.overloaded(fromInt(5))) + assertEquals(2, obj.overloaded(fromInt(5), fromInt(6))) + } +} + +object NonNativeJSTypeTestScala3 { + final class VC(val x: Int) extends AnyVal + + final class GenVC[T](val x: T) extends AnyVal + + object OpaqueContainer { + opaque type OpaqueInt = Int + + def fromInt(x: Int): OpaqueInt = x + def toInt(x: OpaqueInt): Int = x + } +}