@@ -3562,40 +3562,48 @@ class JSCodeGen()(using genCtx: Context) {
35623562 * )
35633563 * }}}
35643564 *
3565- * and eventually reach the back-end as
3565+ * When the original `structural` value is already of a subtype of
3566+ * `scala.reflect.Selectable`, there is no conversion involved. There could
3567+ * also be any other arbitrary conversion, such as the deprecated bridge for
3568+ * Scala 2's `import scala.language.reflectiveCalls`. In general, the shape
3569+ * is therefore the following, for some `selectable: reflect.Selectable`:
35663570 *
35673571 * {{{
3568- * reflectiveSelectable(structural) .selectDynamic("foo") // same as above
3569- * reflectiveSelectable(structural) .applyDynamic("bar",
3570- * wrapRefArray([ classOf[Int], classOf[String] : jl.Class ]
3572+ * selectable .selectDynamic("foo")
3573+ * selectable .applyDynamic("bar",
3574+ * classOf[Int], classOf[String]
35713575 * )(
3572- * genericWrapArray([ Int.box(6) , "hello" : Object ])
3576+ * 6 , "hello"
35733577 * )
35743578 * }}}
35753579 *
3576- * If we use the deprecated `import scala.language.reflectiveCalls`, the
3577- * wrapper for the receiver `structural` are the following instead:
3580+ * and eventually reaches the back-end as
35783581 *
35793582 * {{{
3580- * reflectiveSelectableFromLangReflectiveCalls(structural)(
3581- * using scala.languageFeature.reflectiveCalls)
3583+ * selectable.selectDynamic("foo") // same as above
3584+ * selectable.applyDynamic("bar",
3585+ * wrapRefArray([ classOf[Int], classOf[String] : jl.Class ]
3586+ * )(
3587+ * genericWrapArray([ Int.box(6), "hello" : Object ])
3588+ * )
35823589 * }}}
35833590 *
3584- * (in which case we don't care about the contextual argument).
3585- *
35863591 * In SJSIR, they must be encoded as follows:
35873592 *
35883593 * {{{
3589- * structural .foo;R()
3590- * structural .bar;I;Ljava.lang.String;R(
3594+ * selectable.selectedValue;O() .foo;R()
3595+ * selectable.selectedValue;O() .bar;I;Ljava.lang.String;R(
35913596 * Int.box(6).asInstanceOf[int],
35923597 * "hello".asInstanceOf[java.lang.String]
35933598 * )
35943599 * }}}
35953600 *
3601+ * where `selectedValue;O()` is declared in `scala.reflect.Selectable` and
3602+ * holds the actual instance on which to perform the reflective operations.
3603+ * For the typical use case from the first snippet, it returns `structural`.
3604+ *
35963605 * This means that we must deconstruct the elaborated calls to recover:
35973606 *
3598- * - the original receiver `structural`
35993607 * - the method name as a compile-time string `foo` or `bar`
36003608 * - the `tp: Type`s that have been wrapped in `classOf[tp]`, as a
36013609 * compile-time List[Type], from which we'll derive `jstpe.Type`s for the
@@ -3607,26 +3615,10 @@ class JSCodeGen()(using genCtx: Context) {
36073615 */
36083616 private def genReflectiveCall (tree : Apply , isSelectDynamic : Boolean ): js.Tree = {
36093617 implicit val pos = tree.span
3610- val Apply (fun @ Select (receiver0 , _), args) = tree
3618+ val Apply (fun @ Select (receiver , _), args) = tree
36113619
3612- /* Extract the real receiver, which is the first argument to one of the
3613- * implicit conversions scala.reflect.Selectable.reflectiveSelectable or
3614- * scala.Selectable.reflectiveSelectableFromLangReflectiveCalls.
3615- */
3616- val receiver = receiver0 match {
3617- case Apply (fun1, receiver :: _)
3618- if fun1.symbol == jsdefn.ReflectSelectable_reflectiveSelectable ||
3619- fun1.symbol == jsdefn.Selectable_reflectiveSelectableFromLangReflectiveCalls =>
3620- genExpr(receiver)
3621-
3622- case _ =>
3623- report.error(
3624- " The receiver of Selectable.selectDynamic or Selectable.applyDynamic " +
3625- " must be a call to the (implicit) method scala.reflect.Selectable.reflectiveSelectable. " +
3626- " Other uses are not supported in Scala.js." ,
3627- tree.sourcePos)
3628- js.Undefined ()
3629- }
3620+ val selectedValueTree = js.Apply (js.ApplyFlags .empty, genExpr(receiver),
3621+ js.MethodIdent (selectedValueMethodName), Nil )(jstpe.AnyType )
36303622
36313623 // Extract the method name as a String
36323624 val methodNameStr = args.head match {
@@ -3682,7 +3674,7 @@ class JSCodeGen()(using genCtx: Context) {
36823674
36833675 val methodName = MethodName .reflectiveProxy(methodNameStr, formalParamTypeRefs)
36843676
3685- js.Apply (js.ApplyFlags .empty, receiver , js.MethodIdent (methodName), actualArgs)(jstpe.AnyType )
3677+ js.Apply (js.ApplyFlags .empty, selectedValueTree , js.MethodIdent (methodName), actualArgs)(jstpe.AnyType )
36863678 }
36873679
36883680 /** Gen actual actual arguments to Scala method call.
@@ -4296,10 +4288,13 @@ object JSCodeGen {
42964288 private val NullPointerExceptionClass = ClassName (" java.lang.NullPointerException" )
42974289 private val JSObjectClassName = ClassName (" scala.scalajs.js.Object" )
42984290
4291+ private val ObjectClassRef = jstpe.ClassRef (ir.Names .ObjectClass )
4292+
42994293 private val newSimpleMethodName = SimpleMethodName (" new" )
43004294
4301- private val ObjectArgConstructorName =
4302- MethodName .constructor(List (jstpe.ClassRef (ir.Names .ObjectClass )))
4295+ private val selectedValueMethodName = MethodName (" selectedValue" , Nil , ObjectClassRef )
4296+
4297+ private val ObjectArgConstructorName = MethodName .constructor(List (ObjectClassRef ))
43034298
43044299 private val thisOriginalName = OriginalName (" this" )
43054300
0 commit comments