@@ -791,9 +791,9 @@ class JSCodeGen()(using genCtx: Context) {
791
791
toIRType(param.info), mutable = false , rest = false )
792
792
}
793
793
794
- /* if (primitives.isPrimitive(sym)) {
794
+ if (primitives.isPrimitive(sym)) {
795
795
None
796
- } else*/ if (sym.is(Deferred )) {
796
+ } else if (sym.is(Deferred )) {
797
797
Some (js.MethodDef (js.MemberFlags .empty, methodName, originalName,
798
798
jsParams, toIRType(patchedResultType(sym)), None )(
799
799
OptimizerHints .empty, None ))
@@ -2815,9 +2815,181 @@ class JSCodeGen()(using genCtx: Context) {
2815
2815
js.ForIn (objVarDef.ref, keyVarIdent, NoOriginalName , {
2816
2816
js.JSFunctionApply (fVarDef.ref, List (keyVarRef))
2817
2817
}))
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 )
2818
2825
}
2819
2826
}
2820
2827
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
+ // ClassTag.apply(classOf[tp]) -> tp
2950
+ case Apply (fun, Literal (const) :: Nil )
2951
+ if fun.symbol == defn.ClassTagModule_apply && const.tag == Constants .ClazzTag =>
2952
+ toIRTypeAndTypeRef(const.typeValue)
2953
+ // ClassTag.SpecialType -> erasure(SepecialType.typeRef) (e.g., ClassTag.Any -> Object)
2954
+ case Apply (Select (classTagModule, name), Nil )
2955
+ if classTagModule.symbol == defn.ClassTagModule &&
2956
+ defn.SpecialClassTagClasses .exists(_.name == name.toTypeName) =>
2957
+ toIRTypeAndTypeRef(TypeErasure .erasure(
2958
+ defn.SpecialClassTagClasses .find(_.name == name.toTypeName).get.typeRef))
2959
+ // Anything else is invalid
2960
+ case classTag =>
2961
+ report.error(
2962
+ " The ClassTags passed to Selectable.applyDynamic must be " +
2963
+ " literal ClassTag(classOf[T]) expressions " +
2964
+ " (typically compiler-generated). " +
2965
+ " Other uses are not supported in Scala.js." ,
2966
+ classTag.sourcePos)
2967
+ (jstpe.AnyType , jstpe.ClassRef (jsNames.ObjectClass ))
2968
+ }
2969
+
2970
+ // Gen the actual args, downcasting them to the formal param types
2971
+ val actualArgs = actualArgsAnyArray.elems.zip(formalParamTypesAndTypeRefs).map {
2972
+ (actualArgAny, formalParamTypeAndTypeRef) =>
2973
+ val genActualArgAny = genExpr(actualArgAny)
2974
+ js.AsInstanceOf (genActualArgAny, formalParamTypeAndTypeRef._1)(genActualArgAny.pos)
2975
+ }
2976
+
2977
+ (formalParamTypesAndTypeRefs.map(_._2), actualArgs)
2978
+
2979
+ case _ =>
2980
+ report.error(
2981
+ " Passing the varargs of Selectable.applyDynamic with `: _*` " +
2982
+ " is not supported in Scala.js." ,
2983
+ tree.sourcePos)
2984
+ (Nil , Nil )
2985
+ }
2986
+ }
2987
+
2988
+ val methodName = MethodName .reflectiveProxy(methodNameStr, formalParamTypeRefs)
2989
+
2990
+ js.Apply (js.ApplyFlags .empty, receiver, js.MethodIdent (methodName), actualArgs)(jstpe.AnyType )
2991
+ }
2992
+
2821
2993
/** Gen actual actual arguments to Scala method call.
2822
2994
* Returns a list of the transformed arguments.
2823
2995
*
@@ -2992,8 +3164,9 @@ class JSCodeGen()(using genCtx: Context) {
2992
3164
lazy val isWrapArray : Set [Symbol ] = {
2993
3165
val names0 = defn.ScalaValueClasses ().map(sym => nme.wrapXArray(sym.name))
2994
3166
val names1 = names0 ++ Set (nme.wrapRefArray, nme.genericWrapArray)
2995
- val names2 = names1.map(defn.ScalaPredefModule .requiredMethod(_))
2996
- names2.toSet
3167
+ val symsInPredef = names1.map(defn.ScalaPredefModule .requiredMethod(_))
3168
+ val symsInScalaRunTime = names1.map(defn.ScalaRuntimeModule .requiredMethod(_))
3169
+ (symsInPredef ++ symsInScalaRunTime).toSet
2997
3170
}
2998
3171
2999
3172
def unapply (tree : Apply ): Option [Tree ] = tree match {
0 commit comments