@@ -1609,10 +1609,10 @@ class JSCodeGen()(using genCtx: Context) {
16091609                optimizerHints, Unversioned )
16101610          } else  {
16111611            val  namespace  =  if  (isMethodStaticInIR(sym)) {
1612-               if  (sym.isPrivate ) js.MemberNamespace .PrivateStatic 
1612+               if  (sym.is( Private ) ) js.MemberNamespace .PrivateStatic 
16131613              else  js.MemberNamespace .PublicStatic 
16141614            } else  {
1615-               if  (sym.isPrivate ) js.MemberNamespace .Private 
1615+               if  (sym.is( Private ) ) js.MemberNamespace .Private 
16161616              else  js.MemberNamespace .Public 
16171617            }
16181618            val  resultIRType  =  toIRType(patchedResultType(sym))
@@ -3770,7 +3770,7 @@ class JSCodeGen()(using genCtx: Context) {
37703770  /**  Gen a statically linked call to an instance method. */  
37713771  def  genApplyMethodMaybeStatically (receiver : js.Tree , method : Symbol ,
37723772      arguments : List [js.Tree ])(implicit  pos : Position ):  js.Tree  =  {
3773-     if  (method.isPrivate  ||  method.isClassConstructor)
3773+     if  (method.is( Private )  ||  method.isClassConstructor)
37743774      genApplyMethodStatically(receiver, method, arguments)
37753775    else 
37763776      genApplyMethod(receiver, method, arguments)
@@ -3779,7 +3779,7 @@ class JSCodeGen()(using genCtx: Context) {
37793779  /**  Gen a dynamically linked call to a Scala method. */  
37803780  def  genApplyMethod (receiver : js.Tree , method : Symbol , arguments : List [js.Tree ])(
37813781      implicit  pos : Position ):  js.Tree  =  {
3782-     assert(! method.isPrivate ,
3782+     assert(! method.is( Private ) ,
37833783        s " Cannot generate a dynamic call to private method  $method at  $pos" )
37843784    js.Apply (js.ApplyFlags .empty, receiver, encodeMethodSym(method), arguments)(
37853785        toIRType(patchedResultType(method)))
@@ -3789,7 +3789,7 @@ class JSCodeGen()(using genCtx: Context) {
37893789  def  genApplyMethodStatically (receiver : js.Tree , method : Symbol , arguments : List [js.Tree ])(
37903790      implicit  pos : Position ):  js.Tree  =  {
37913791    val  flags  =  js.ApplyFlags .empty
3792-       .withPrivate(method.isPrivate  &&  ! method.isClassConstructor)
3792+       .withPrivate(method.is( Private )  &&  ! method.isClassConstructor)
37933793      .withConstructor(method.isClassConstructor)
37943794    js.ApplyStatically (flags, receiver, encodeClassName(method.owner),
37953795        encodeMethodSym(method), arguments)(
@@ -3799,7 +3799,7 @@ class JSCodeGen()(using genCtx: Context) {
37993799  /**  Gen a call to a static method. */  
38003800  private  def  genApplyStatic (method : Symbol , arguments : List [js.Tree ])(
38013801      implicit  pos : Position ):  js.Tree  =  {
3802-     js.ApplyStatic (js.ApplyFlags .empty.withPrivate(method.isPrivate ),
3802+     js.ApplyStatic (js.ApplyFlags .empty.withPrivate(method.is( Private ) ),
38033803        encodeClassName(method.owner), encodeMethodSym(method), arguments)(
38043804        toIRType(patchedResultType(method)))
38053805  }
@@ -4400,34 +4400,53 @@ class JSCodeGen()(using genCtx: Context) {
44004400   *  This tries to optimize repeated arguments (varargs) by turning them 
44014401   *  into js.WrappedArray instead of Scala wrapped arrays. 
44024402   */  
4403-   private  def  genActualArgs (sym : Symbol , args : List [Tree ])(
4404-       implicit  pos : Position ):  List [js.Tree ] =  {
4405-     args.map(genExpr)
4406-     /* val wereRepeated = exitingPhase(currentRun.typerPhase) {
4407-       sym.tpe.params.map(p => isScalaRepeatedParamType(p.tpe)) 
4403+   private  def  genActualArgs (sym : Symbol , args : List [Tree ]):  List [js.Tree ] =  {
4404+     //  Fast path for methods that do not have any repeated parameter
4405+     val  isAnyParamRepeated :  Boolean  =  atPhase(elimRepeatedPhase) {
4406+       sym.info.paramInfoss.flatten.exists(_.isRepeatedParam)
44084407    }
44094408
4410-     if (wereRepeated.size > args.size) { 
4411-       // Should not happen, but let's not crash 
4409+     if  (! isAnyParamRepeated) {
44124410      args.map(genExpr)
44134411    } else  {
4414-       /*  Arguments that are in excess compared to the type signature after 
4415-        * erasure are lambda-lifted arguments. They cannot be repeated, hence 
4416-        * the extension to `false`. 
4412+       /*  Erasure and lambdalift both insert capture params in dotc, at
4413+        * unpredictable positions. Therefore, we use the *names* of parameters 
4414+        * as the only reliable link to whether they were initially repeated. 
4415+        * We also do this in JSSymUtils.jsParamInfos for JS methods. 
44174416       */  
4418-       for ((arg, wasRepeated) <- args.zipAll(wereRepeated, EmptyTree, false)) yield { 
4419-         if (wasRepeated) { 
4420-           tryGenRepeatedParamAsJSArray(arg, handleNil = false).fold { 
4421-             genExpr(arg) 
4422-           } { genArgs => 
4423-             genNew(WrappedArrayClass, WrappedArray_ctor, 
4424-                 List(js.JSArrayConstr(genArgs))) 
4417+       val  namesOfRepeatedParams :  Set [TermName ] =  atPhase(elimRepeatedPhase) {
4418+         sym.info.paramNamess.flatten.zip(sym.info.paramInfoss.flatten).collect {
4419+           case  (paramName, paramInfo) if  paramInfo.isRepeatedParam =>  paramName
4420+         }.toSet
4421+       }
4422+ 
4423+       for  ((arg, paramName) <-  args.zip(sym.info.paramNamess.flatten)) yield  {
4424+         if  (namesOfRepeatedParams.contains(paramName)) {
4425+           /*  If the argument is a call to the compiler's chosen `wrapArray`
4426+            * method with an array literal as argument, we know it actually 
4427+            * came from expanded varargs. In that case, rewrite to calling our 
4428+            * custom `scala.scalajs.runtime.to*VarArgs` method. These methods 
4429+            * choose the best implementation of varargs depending on the 
4430+            * target platform. 
4431+            */  
4432+           arg match  {
4433+             case  MaybeAsInstanceOf (wrapArray @  WrapArray (MaybeAsInstanceOf (arrayValue : JavaSeqLiteral ))) => 
4434+               implicit  val  pos :  SourcePosition  =  wrapArray.sourcePos
4435+               js.Apply (
4436+                 js.ApplyFlags .empty,
4437+                 js.LoadModule (ScalaJSRuntimeModClassName ),
4438+                 js.MethodIdent (WrapArray .wrapArraySymToToVarArgsName(wrapArray.symbol)),
4439+                 List (genExpr(arrayValue))
4440+               )(jstpe.ClassType (encodeClassName(defn.SeqClass ), nullable =  true ))
4441+ 
4442+             case  _ => 
4443+               genExpr(arg)
44254444          }
44264445        } else  {
44274446          genExpr(arg)
44284447        }
44294448      }
4430-     }*/  
4449+     }
44314450  }
44324451
44334452  /**  Gen actual actual arguments to a JS method call. 
@@ -4496,47 +4515,28 @@ class JSCodeGen()(using genCtx: Context) {
44964515   *  `js.Array`. 
44974516   */  
44984517  private  def  genJSRepeatedParam (arg : Tree ):  List [js.TreeOrJSSpread ] =  {
4499-     tryGenRepeatedParamAsJSArray(arg, handleNil =  true ).getOrElse {
4500-       /*  Fall back to calling runtime.genTraversableOnce2jsArray
4501-        * to perform the conversion to js.Array, then wrap in a Spread 
4502-        * operator. 
4503-        */  
4504-       implicit  val  pos :  SourcePosition  =  arg.sourcePos
4505-       val  jsArrayArg  =  genModuleApplyMethod(
4506-           jsdefn.Runtime_toJSVarArgs ,
4507-           List (genExpr(arg)))
4508-       List (js.JSSpread (jsArrayArg))
4509-     }
4510-   }
4511- 
4512-   /**  Try and expand an actual argument to a repeated param `(xs: T*)`. 
4513-    * 
4514-    *  This method recognizes the shapes of tree generated by the desugaring 
4515-    *  of repeated params in Scala, and expands them. 
4516-    *  If `arg` does not have the shape of a generated repeated param, this 
4517-    *  method returns `None`. 
4518-    */  
4519-   private  def  tryGenRepeatedParamAsJSArray (arg : Tree ,
4520-       handleNil : Boolean ):  Option [List [js.Tree ]] =  {
4521-     implicit  val  pos  =  arg.span
4518+     implicit  val  pos :  SourcePosition  =  arg.sourcePos
45224519
45234520    //  Given a method `def foo(args: T*)`
45244521    arg match  {
45254522      //  foo(arg1, arg2, ..., argN) where N > 0
45264523      case  MaybeAsInstanceOf (WrapArray (MaybeAsInstanceOf (array : JavaSeqLiteral ))) => 
45274524        /*  Value classes in arrays are already boxed, so no need to use
45284525         * the type before erasure. 
4529-          * TODO Is this true in dotty? 
45304526         */  
4531-         Some ( array.elems.map(e =>  box(genExpr(e), e.tpe) ))
4527+         array.elems.map(e =>  box(genExpr(e), e.tpe))
45324528
45334529      //  foo()
4534-       case  Ident (_) if  handleNil  &&   arg.symbol ==  defn.NilModule  => 
4535-         Some ( Nil ) 
4530+       case  Ident (_) if  arg.symbol ==  defn.NilModule  => 
4531+         Nil 
45364532
45374533      //  foo(argSeq: _*) - cannot be optimized
45384534      case  _ => 
4539-         None 
4535+         /*  Fall back to calling runtime.toJSVarArgs to perform the conversion
4536+          * to js.Array, then wrap in a Spread operator. 
4537+          */  
4538+         val  jsArrayArg  =  genModuleApplyMethod(jsdefn.Runtime_toJSVarArgs , List (genExpr(arg)))
4539+         List (js.JSSpread (jsArrayArg))
45404540    }
45414541  }
45424542
@@ -4551,16 +4551,32 @@ class JSCodeGen()(using genCtx: Context) {
45514551  }
45524552
45534553  private  object  WrapArray  {
4554-     lazy  val  isWrapArray :  Set [Symbol ] =  {
4555-       val  names0  =  defn.ScalaValueClasses ().map(sym =>  nme.wrapXArray(sym.name))
4556-       val  names1  =  names0 ++  Set (nme.wrapRefArray, nme.genericWrapArray)
4557-       val  symsInPredef  =  names1.map(defn.ScalaPredefModule .requiredMethod(_))
4558-       val  symsInScalaRunTime  =  names1.map(defn.ScalaRuntimeModule .requiredMethod(_))
4559-       (symsInPredef ++  symsInScalaRunTime).toSet
4554+     lazy  val  wrapArraySymToToVarArgsName :  Map [Symbol , MethodName ] =  {
4555+       val  SeqClassRef  =  jstpe.ClassRef (encodeClassName(defn.SeqClass ))
4556+ 
4557+       val  items :  Seq [(Name , String , jstpe.TypeRef )] =  Seq (
4558+         (nme.genericWrapArray, " toGenericVarArgs" ObjectRef ),
4559+         (nme.wrapRefArray, " toRefVarArgs" ArrayTypeRef (jswkn.ObjectRef , 1 )),
4560+         (tpd.wrapArrayMethodName(defn.UnitType ), " toUnitVarArgs" ArrayTypeRef (jstpe.ClassRef (jswkn.BoxedUnitClass ), 1 )),
4561+         (tpd.wrapArrayMethodName(defn.BooleanType ), " toBooleanVarArgs" ArrayTypeRef (jstpe.BooleanRef , 1 )),
4562+         (tpd.wrapArrayMethodName(defn.CharType ), " toCharVarArgs" ArrayTypeRef (jstpe.CharRef , 1 )),
4563+         (tpd.wrapArrayMethodName(defn.ByteType ), " toByteVarArgs" ArrayTypeRef (jstpe.ByteRef , 1 )),
4564+         (tpd.wrapArrayMethodName(defn.ShortType ), " toShortVarArgs" ArrayTypeRef (jstpe.ShortRef , 1 )),
4565+         (tpd.wrapArrayMethodName(defn.IntType ), " toIntVarArgs" ArrayTypeRef (jstpe.IntRef , 1 )),
4566+         (tpd.wrapArrayMethodName(defn.LongType ), " toLongVarArgs" ArrayTypeRef (jstpe.LongRef , 1 )),
4567+         (tpd.wrapArrayMethodName(defn.FloatType ), " toFloatVarArgs" ArrayTypeRef (jstpe.FloatRef , 1 )),
4568+         (tpd.wrapArrayMethodName(defn.DoubleType ), " toDoubleVarArgs" ArrayTypeRef (jstpe.DoubleRef , 1 ))
4569+       )
4570+ 
4571+       items.map { case  (wrapArrayName, simpleName, argTypeRef) => 
4572+         val  wrapArraySym  =  defn.getWrapVarargsArrayModule.requiredMethod(wrapArrayName)
4573+         val  toVarArgsName  =  MethodName (simpleName, argTypeRef ::  Nil , SeqClassRef )
4574+         wrapArraySym ->  toVarArgsName
4575+       }.toMap
45604576    }
45614577
45624578    def  unapply (tree : Apply ):  Option [Tree ] =  tree match  {
4563-       case  Apply (wrapArray_?, List (wrapped)) if  isWrapArray (wrapArray_?.symbol) => 
4579+       case  Apply (wrapArray_?, List (wrapped)) if  wrapArraySymToToVarArgsName.contains (wrapArray_?.symbol) => 
45644580        Some (wrapped)
45654581      case  _ => 
45664582        None 
@@ -5002,6 +5018,7 @@ object JSCodeGen {
50025018  private  val  JLRArrayClassName  =  ClassName (" java.lang.reflect.Array" 
50035019  private  val  JSObjectClassName  =  ClassName (" scala.scalajs.js.Object" 
50045020  private  val  JavaScriptExceptionClassName  =  ClassName (" scala.scalajs.js.JavaScriptException" 
5021+   private  val  ScalaJSRuntimeModClassName  =  ClassName (" scala.scalajs.runtime.package$" 
50055022
50065023  private  val  ObjectArrayTypeRef  =  jstpe.ArrayTypeRef (jswkn.ObjectRef , 1 )
50075024
0 commit comments