@@ -2815,9 +2815,173 @@ class JSCodeGen()(using genCtx: Context) {
28152815            js.ForIn (objVarDef.ref, keyVarIdent, NoOriginalName , {
28162816              js.JSFunctionApply (fVarDef.ref, List (keyVarRef))
28172817            }))
2818+ 
2819+       case  REFLECT_SELECTABLE_SELECTDYN  => 
2820+         //  scala.reflect.Selectable.selectDynamic
2821+         genReflectiveCall(tree, isSelectDynamic =  true )
2822+       case  REFLECT_SELECTABLE_APPLYDYN  => 
2823+         //  scala.reflect.Selectable.applyDynamic
2824+         genReflectiveCall(tree, isSelectDynamic =  false )
28182825    }
28192826  }
28202827
2828+   /**  Gen the SJSIR for a reflective call. 
2829+    * 
2830+    *  Reflective calls are calls to a structural type field or method that 
2831+    *  involve a reflective Selectable. They look like the following in source 
2832+    *  code: 
2833+    *  {{{ 
2834+    *  import scala.reflect.Selectable.reflectiveSelectable 
2835+    * 
2836+    *  type Structural = { 
2837+    *    val foo: Int 
2838+    *    def bar(x: Int, y: String): String 
2839+    *  } 
2840+    * 
2841+    *  val structural: Structural = new { 
2842+    *    val foo: Int = 5 
2843+    *    def bar(x: Int, y: String): String = x.toString + y 
2844+    *  } 
2845+    * 
2846+    *  structural.foo 
2847+    *  structural.bar(6, "hello") 
2848+    *  }}} 
2849+    * 
2850+    *  After expansion by the Scala 3 rules for structural member selections and 
2851+    *  calls, they look like 
2852+    * 
2853+    *  {{{ 
2854+    *  reflectiveSelectable(structural).selectDynamic("foo") 
2855+    *  reflectiveSelectable(structural).applyDynamic("bar", 
2856+    *    ClassTag(classOf[Int]), ClassTag(classOf[String]) 
2857+    *  )( 
2858+    *    6, "hello" 
2859+    *  ) 
2860+    *  }}} 
2861+    * 
2862+    *  and eventually reach the back-end as 
2863+    * 
2864+    *  {{{ 
2865+    *  reflectiveSelectable(structural).selectDynamic("foo") // same as above 
2866+    *  reflectiveSelectable(structural).applyDynamic("bar", 
2867+    *    wrapRefArray([ ClassTag(classOf[Int]), ClassTag(classOf[String]) : ClassTag ] 
2868+    *  )( 
2869+    *    genericWrapArray([ Int.box(6), "hello" : Object ]) 
2870+    *  ) 
2871+    *  }}} 
2872+    * 
2873+    *  If we use the deprecated `import scala.language.reflectiveCalls`, the 
2874+    *  wrapper for the receiver `structural` are the following instead: 
2875+    * 
2876+    *  {{{ 
2877+    *  reflectiveSelectableFromLangReflectiveCalls(structural)( 
2878+    *    using scala.languageFeature.reflectiveCalls) 
2879+    *  }}} 
2880+    * 
2881+    *  (in which case we don't care about the contextual argument). 
2882+    * 
2883+    *  In SJSIR, they must be encoded as follows: 
2884+    * 
2885+    *  {{{ 
2886+    *  structural.foo;R() 
2887+    *  structural.bar;I;Ljava.lang.String;R( 
2888+    *    Int.box(6).asInstanceOf[int], 
2889+    *    "hello".asInstanceOf[java.lang.String] 
2890+    *  ) 
2891+    *  }}} 
2892+    * 
2893+    *  This means that we must deconstruct the elaborated calls to recover: 
2894+    * 
2895+    *  - the original receiver `structural` 
2896+    *  - the method name as a compile-time string `foo` or `bar` 
2897+    *  - the `tp: Type`s that have been wrapped in `ClassTag(classOf[tp])`, as a 
2898+    *    compile-time List[Type], from which we'll derive `jstpe.Type`s for the 
2899+    *    `asInstanceOf`s and `jstpe.TypeRef`s for the `MethodName.reflectiveProxy` 
2900+    *  - the actual arguments as a compile-time `List[Tree]` 
2901+    * 
2902+    *  Virtually all of the code in `genReflectiveCall` deals with recovering 
2903+    *  those elements. Constructing the IR Tree is the easy part after that. 
2904+    */  
2905+   private  def  genReflectiveCall (tree : Apply , isSelectDynamic : Boolean ):  js.Tree  =  {
2906+     implicit  val  pos  =  tree.span
2907+     val  Apply (fun @  Select (receiver0, _), args) =  tree
2908+ 
2909+     /*  Extract the real receiver, which is the first argument to one of the
2910+      * implicit conversions scala.reflect.Selectable.reflectiveSelectable or 
2911+      * scala.Selectable.reflectiveSelectableFromLangReflectiveCalls. 
2912+      */  
2913+     val  receiver  =  receiver0 match  {
2914+       case  Apply (fun1, receiver ::  _)
2915+           if  fun1.symbol ==  jsdefn.ReflectSelectable_reflectiveSelectable  || 
2916+               fun1.symbol ==  jsdefn.Selectable_reflectiveSelectableFromLangReflectiveCalls  => 
2917+         genExpr(receiver)
2918+ 
2919+       case  _ => 
2920+         report.error(
2921+             " The receiver of Selectable.selectDynamic or Selectable.applyDynamic " + 
2922+             " must be a call to the (implicit) method scala.reflect.Selectable.reflectiveSelectable. " + 
2923+             " Other uses are not supported in Scala.js." 
2924+             tree.sourcePos)
2925+         js.Undefined ()
2926+     }
2927+ 
2928+     //  Extract the method name as a String
2929+     val  methodNameStr  =  args.head match  {
2930+       case  Literal (Constants .Constant (name : String )) => 
2931+         name
2932+       case  _ => 
2933+         report.error(
2934+             " The method name given to Selectable.selectDynamic or Selectable.applyDynamic " + 
2935+             " must be a literal string. " + 
2936+             " Other uses are not supported in Scala.js." 
2937+             args.head.sourcePos)
2938+         " erroneous" 
2939+     }
2940+ 
2941+     val  (formalParamTypeRefs, actualArgs) =  if  (isSelectDynamic) {
2942+       (Nil , Nil )
2943+     } else  {
2944+       //  Extract the param type refs and actual args from the 2nd and 3rd argument to applyDynamic
2945+       args.tail match  {
2946+         case  WrapArray (classTagsArray : JavaSeqLiteral ) ::  WrapArray (actualArgsAnyArray : JavaSeqLiteral ) ::  Nil  => 
2947+           //  Extract jstpe.Type's and jstpe.TypeRef's from the ClassTag.apply(_) trees
2948+           val  formalParamTypesAndTypeRefs  =  classTagsArray.elems.map {
2949+             case  Apply (fun, Literal (const) ::  Nil )
2950+                 if  fun.symbol ==  defn.ClassTagModule_apply  &&  const.tag ==  Constants .ClazzTag  => 
2951+               toIRTypeAndTypeRef(const.typeValue)
2952+             case  classTag => 
2953+               report.error(
2954+                   " The ClassTags passed to Selectable.applyDynamic must be " + 
2955+                   " literal ClassTag(classOf[T]) expressions " + 
2956+                   " (typically compiler-generated). " + 
2957+                   " Other uses are not supported in Scala.js." 
2958+                   classTag.sourcePos)
2959+               (jstpe.AnyType , jstpe.ClassRef (jsNames.ObjectClass ))
2960+           }
2961+ 
2962+           //  Gen the actual args, downcasting them to the formal param types
2963+           val  actualArgs  =  actualArgsAnyArray.elems.zip(formalParamTypesAndTypeRefs).map {
2964+             (actualArgAny, formalParamTypeAndTypeRef) => 
2965+               val  genActualArgAny  =  genExpr(actualArgAny)
2966+               js.AsInstanceOf (genActualArgAny, formalParamTypeAndTypeRef._1)(genActualArgAny.pos)
2967+           }
2968+ 
2969+           (formalParamTypesAndTypeRefs.map(_._2), actualArgs)
2970+ 
2971+         case  _ => 
2972+           report.error(
2973+               " Passing the varargs of Selectable.applyDynamic with `: _*` " + 
2974+               " is not supported in Scala.js." 
2975+               tree.sourcePos)
2976+           (Nil , Nil )
2977+       }
2978+     }
2979+ 
2980+     val  methodName  =  MethodName .reflectiveProxy(methodNameStr, formalParamTypeRefs)
2981+ 
2982+     js.Apply (js.ApplyFlags .empty, receiver, js.MethodIdent (methodName), actualArgs)(jstpe.AnyType )
2983+   }
2984+ 
28212985  /**  Gen actual actual arguments to Scala method call. 
28222986   *  Returns a list of the transformed arguments. 
28232987   * 
@@ -2992,8 +3156,9 @@ class JSCodeGen()(using genCtx: Context) {
29923156    lazy  val  isWrapArray :  Set [Symbol ] =  {
29933157      val  names0  =  defn.ScalaValueClasses ().map(sym =>  nme.wrapXArray(sym.name))
29943158      val  names1  =  names0 ++  Set (nme.wrapRefArray, nme.genericWrapArray)
2995-       val  names2  =  names1.map(defn.ScalaPredefModule .requiredMethod(_))
2996-       names2.toSet
3159+       val  symsInPredef  =  names1.map(defn.ScalaPredefModule .requiredMethod(_))
3160+       val  symsInScalaRunTime  =  names1.map(defn.ScalaRuntimeModule .requiredMethod(_))
3161+       (symsInPredef ++  symsInScalaRunTime).toSet
29973162    }
29983163
29993164    def  unapply (tree : Apply ):  Option [Tree ] =  tree match  {
0 commit comments