diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 1572ed476c6c..9e5743147122 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -2553,6 +2553,8 @@ class JSCodeGen()(using genCtx: Context) { genCoercion(tree, receiver, code) else if (code == JSPrimitives.THROW) genThrow(tree, args) + else if (code == JSPrimitives.NEW_ARRAY) + genNewArray(tree, args) else if (JSPrimitives.isJSPrimitive(code)) genJSPrimitive(tree, args, code, isStat) else @@ -3022,6 +3024,24 @@ class JSCodeGen()(using genCtx: Context) { } } + /** Gen a call to the special `newArray` method. */ + private def genNewArray(tree: Apply, args: List[Tree]): js.Tree = { + implicit val pos: SourcePosition = tree.sourcePos + + val List(elemClazz, Literal(arrayClassConstant), dimsArray: JavaSeqLiteral) = args: @unchecked + + dimsArray.elems match { + case singleDim :: Nil => + // Use a js.NewArray + val arrayTypeRef = toTypeRef(arrayClassConstant.typeValue).asInstanceOf[jstpe.ArrayTypeRef] + js.NewArray(arrayTypeRef, List(genExpr(singleDim))) + case _ => + // Delegate to jlr.Array.newInstance + js.ApplyStatic(js.ApplyFlags.empty, JLRArrayClassName, js.MethodIdent(JLRArrayNewInstanceMethodName), + List(genExpr(elemClazz), genJavaSeqLiteral(dimsArray)))(jstpe.AnyType) + } + } + /** Gen a "normal" apply (to a true method). * * But even these are further refined into: @@ -4835,6 +4855,7 @@ class JSCodeGen()(using genCtx: Context) { object JSCodeGen { private val NullPointerExceptionClass = ClassName("java.lang.NullPointerException") + private val JLRArrayClassName = ClassName("java.lang.reflect.Array") private val JSObjectClassName = ClassName("scala.scalajs.js.Object") private val JavaScriptExceptionClassName = ClassName("scala.scalajs.js.JavaScriptException") @@ -4844,6 +4865,9 @@ object JSCodeGen { private val selectedValueMethodName = MethodName("selectedValue", Nil, ObjectClassRef) + private val JLRArrayNewInstanceMethodName = + MethodName("newInstance", List(jstpe.ClassRef(jsNames.ClassClass), jstpe.ArrayTypeRef(jstpe.IntRef, 1)), ObjectClassRef) + private val ObjectArgConstructorName = MethodName.constructor(List(ObjectClassRef)) private val thisOriginalName = OriginalName("this") diff --git a/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala b/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala index a3a37795826a..f23c816b5204 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala @@ -48,9 +48,10 @@ object JSPrimitives { inline val UNWRAP_FROM_THROWABLE = WRAP_AS_THROWABLE + 1 // js.special.unwrapFromThrowable inline val DEBUGGER = UNWRAP_FROM_THROWABLE + 1 // js.special.debugger - inline val THROW = DEBUGGER + 1 + inline val THROW = DEBUGGER + 1 // .throw + inline val NEW_ARRAY = THROW + 1 // scala.runtime.Arrays.newArray - inline val UNION_FROM = THROW + 1 // js.|.from + inline val UNION_FROM = NEW_ARRAY + 1 // js.|.from inline val UNION_FROM_TYPE_CONSTRUCTOR = UNION_FROM + 1 // js.|.fromTypeConstructor inline val REFLECT_SELECTABLE_SELECTDYN = UNION_FROM_TYPE_CONSTRUCTOR + 1 // scala.reflect.Selectable.selectDynamic @@ -137,6 +138,7 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) { addPrimitive(jsdefn.Special_debugger, DEBUGGER) addPrimitive(defn.throwMethod, THROW) + addPrimitive(defn.newArrayMethod, NEW_ARRAY) addPrimitive(jsdefn.PseudoUnion_from, UNION_FROM) addPrimitive(jsdefn.PseudoUnion_fromTypeConstructor, UNION_FROM_TYPE_CONSTRUCTOR) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ac6089516571..1113f7413e6e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5794,11 +5794,13 @@ object Types extends TypeUtils { protected def derivedLambdaType(tp: LambdaType)(formals: List[tp.PInfo], restpe: Type): Type = tp.derivedLambdaType(tp.paramNames, formals, restpe) + protected def mapArg(arg: Type, tparam: ParamInfo): Type = arg match + case arg: TypeBounds => this(arg) + case arg => atVariance(variance * tparam.paramVarianceSign)(this(arg)) + protected def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match case arg :: otherArgs if tparams.nonEmpty => - val arg1 = arg match - case arg: TypeBounds => this(arg) - case arg => atVariance(variance * tparams.head.paramVarianceSign)(this(arg)) + val arg1 = mapArg(arg, tparams.head) val otherArgs1 = mapArgs(otherArgs, tparams.tail) if ((arg1 eq arg) && (otherArgs1 eq otherArgs)) args else arg1 :: otherArgs1 diff --git a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala index b65f23fae40f..d909b6ee7e04 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala @@ -281,7 +281,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments: sym, () => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava, contentType, - ) + ).nn documentation.nn.toScala end symbolDocumentation end extension