@@ -3199,26 +3199,24 @@ class JSCodeGen()(using genCtx: Context) {
31993199 }
32003200
32013201 /** Gen JS code for an asInstanceOf cast (for reference types only) */
3202- private def genAsInstanceOf (value : js.Tree , to : Type )(
3203- implicit pos : Position ): js.Tree = {
3204-
3205- val sym = to.typeSymbol
3202+ private def genAsInstanceOf (value : js.Tree , to : Type )(implicit pos : Position ): js.Tree =
3203+ genAsInstanceOf(value, toIRType(to))
32063204
3207- if (sym == defn. ObjectClass || sym.isJSType) {
3208- /* asInstanceOf[Object] always succeeds, and
3209- * asInstanceOf to a raw JS type is completely erased.
3210- */
3211- value
3212- } else if (sym == defn. NullClass ) {
3213- js.If (
3214- js.BinaryOp (js.BinaryOp .=== , value, js.Null ()),
3215- js.Null (),
3216- genThrowClassCastException())(
3217- jstpe.NullType )
3218- } else if (sym == defn. NothingClass ) {
3219- js.Block (value, genThrowClassCastException())
3220- } else {
3221- js.AsInstanceOf (value, toIRType(to) )
3205+ /** Gen JS code for an asInstanceOf cast (for reference types only) */
3206+ private def genAsInstanceOf ( value : js. Tree , to : jstpe. Type )( implicit pos : Position ) : js. Tree = {
3207+ to match {
3208+ case jstpe. AnyType =>
3209+ value
3210+ case jstpe. NullType =>
3211+ js.If (
3212+ js.BinaryOp (js.BinaryOp .=== , value, js.Null ()),
3213+ js.Null (),
3214+ genThrowClassCastException())(
3215+ jstpe.NullType )
3216+ case jstpe. NothingType =>
3217+ js.Block (value, genThrowClassCastException())
3218+ case _ =>
3219+ js.AsInstanceOf (value, to )
32223220 }
32233221 }
32243222
@@ -3558,48 +3556,56 @@ class JSCodeGen()(using genCtx: Context) {
35583556 * {{{
35593557 * reflectiveSelectable(structural).selectDynamic("foo")
35603558 * reflectiveSelectable(structural).applyDynamic("bar",
3561- * ClassTag( classOf[Int]), ClassTag( classOf[String])
3559+ * classOf[Int], classOf[String]
35623560 * )(
35633561 * 6, "hello"
35643562 * )
35653563 * }}}
35663564 *
3567- * 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`:
35683570 *
35693571 * {{{
3570- * reflectiveSelectable(structural) .selectDynamic("foo") // same as above
3571- * reflectiveSelectable(structural) .applyDynamic("bar",
3572- * wrapRefArray([ ClassTag( classOf[Int]), ClassTag( classOf[String]) : ClassTag ]
3572+ * selectable .selectDynamic("foo")
3573+ * selectable .applyDynamic("bar",
3574+ * classOf[Int], classOf[String]
35733575 * )(
3574- * genericWrapArray([ Int.box(6) , "hello" : Object ])
3576+ * 6 , "hello"
35753577 * )
35763578 * }}}
35773579 *
3578- * If we use the deprecated `import scala.language.reflectiveCalls`, the
3579- * wrapper for the receiver `structural` are the following instead:
3580+ * and eventually reaches the back-end as
35803581 *
35813582 * {{{
3582- * reflectiveSelectableFromLangReflectiveCalls(structural)(
3583- * 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+ * )
35843589 * }}}
35853590 *
3586- * (in which case we don't care about the contextual argument).
3587- *
35883591 * In SJSIR, they must be encoded as follows:
35893592 *
35903593 * {{{
3591- * structural .foo;R()
3592- * structural .bar;I;Ljava.lang.String;R(
3594+ * selectable.selectedValue;O() .foo;R()
3595+ * selectable.selectedValue;O() .bar;I;Ljava.lang.String;R(
35933596 * Int.box(6).asInstanceOf[int],
35943597 * "hello".asInstanceOf[java.lang.String]
35953598 * )
35963599 * }}}
35973600 *
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+ *
35983605 * This means that we must deconstruct the elaborated calls to recover:
35993606 *
3600- * - the original receiver `structural`
36013607 * - the method name as a compile-time string `foo` or `bar`
3602- * - the `tp: Type`s that have been wrapped in `ClassTag( classOf[tp]) `, as a
3608+ * - the `tp: Type`s that have been wrapped in `classOf[tp]`, as a
36033609 * compile-time List[Type], from which we'll derive `jstpe.Type`s for the
36043610 * `asInstanceOf`s and `jstpe.TypeRef`s for the `MethodName.reflectiveProxy`
36053611 * - the actual arguments as a compile-time `List[Tree]`
@@ -3609,26 +3615,10 @@ class JSCodeGen()(using genCtx: Context) {
36093615 */
36103616 private def genReflectiveCall (tree : Apply , isSelectDynamic : Boolean ): js.Tree = {
36113617 implicit val pos = tree.span
3612- val Apply (fun @ Select (receiver0 , _), args) = tree
3618+ val Apply (fun @ Select (receiver , _), args) = tree
36133619
3614- /* Extract the real receiver, which is the first argument to one of the
3615- * implicit conversions scala.reflect.Selectable.reflectiveSelectable or
3616- * scala.Selectable.reflectiveSelectableFromLangReflectiveCalls.
3617- */
3618- val receiver = receiver0 match {
3619- case Apply (fun1, receiver :: _)
3620- if fun1.symbol == jsdefn.ReflectSelectable_reflectiveSelectable ||
3621- fun1.symbol == jsdefn.Selectable_reflectiveSelectableFromLangReflectiveCalls =>
3622- genExpr(receiver)
3623-
3624- case _ =>
3625- report.error(
3626- " The receiver of Selectable.selectDynamic or Selectable.applyDynamic " +
3627- " must be a call to the (implicit) method scala.reflect.Selectable.reflectiveSelectable. " +
3628- " Other uses are not supported in Scala.js." ,
3629- tree.sourcePos)
3630- js.Undefined ()
3631- }
3620+ val selectedValueTree = js.Apply (js.ApplyFlags .empty, genExpr(receiver),
3621+ js.MethodIdent (selectedValueMethodName), Nil )(jstpe.AnyType )
36323622
36333623 // Extract the method name as a String
36343624 val methodNameStr = args.head match {
@@ -3648,38 +3638,30 @@ class JSCodeGen()(using genCtx: Context) {
36483638 } else {
36493639 // Extract the param type refs and actual args from the 2nd and 3rd argument to applyDynamic
36503640 args.tail match {
3651- case WrapArray (classTagsArray : JavaSeqLiteral ) :: WrapArray (actualArgsAnyArray : JavaSeqLiteral ) :: Nil =>
3652- // Extract jstpe.Type's and jstpe.TypeRef's from the ClassTag.apply(_) trees
3653- val formalParamTypesAndTypeRefs = classTagsArray.elems.map {
3654- // ClassTag.apply(classOf[tp]) -> tp
3655- case Apply (fun, Literal (const) :: Nil )
3656- if fun.symbol == defn.ClassTagModule_apply && const.tag == Constants .ClazzTag =>
3641+ case WrapArray (classOfsArray : JavaSeqLiteral ) :: WrapArray (actualArgsAnyArray : JavaSeqLiteral ) :: Nil =>
3642+ // Extract jstpe.Type's and jstpe.TypeRef's from the classOf[_] trees
3643+ val formalParamTypesAndTypeRefs = classOfsArray.elems.map {
3644+ // classOf[tp] -> tp
3645+ case Literal (const) if const.tag == Constants .ClazzTag =>
36573646 toIRTypeAndTypeRef(const.typeValue)
3658- // ClassTag.SpecialType -> erasure(SepecialType.typeRef) (e.g., ClassTag.Any -> Object)
3659- case Apply (Select (classTagModule, name), Nil )
3660- if classTagModule.symbol == defn.ClassTagModule &&
3661- defn.SpecialClassTagClasses .exists(_.name == name.toTypeName) =>
3662- toIRTypeAndTypeRef(TypeErasure .erasure(
3663- defn.SpecialClassTagClasses .find(_.name == name.toTypeName).get.typeRef))
36643647 // Anything else is invalid
3665- case classTag =>
3648+ case otherTree =>
36663649 report.error(
3667- " The ClassTags passed to Selectable.applyDynamic must be " +
3668- " literal ClassTag(classOf[T]) expressions " +
3669- " (typically compiler-generated). " +
3650+ " The java.lang.Class[_] arguments passed to Selectable.applyDynamic must be " +
3651+ " literal classOf[T] expressions (typically compiler-generated). " +
36703652 " Other uses are not supported in Scala.js." ,
3671- classTag .sourcePos)
3653+ otherTree .sourcePos)
36723654 (jstpe.AnyType , jstpe.ClassRef (jsNames.ObjectClass ))
36733655 }
36743656
36753657 // Gen the actual args, downcasting them to the formal param types
36763658 val actualArgs = actualArgsAnyArray.elems.zip(formalParamTypesAndTypeRefs).map {
36773659 (actualArgAny, formalParamTypeAndTypeRef) =>
36783660 val genActualArgAny = genExpr(actualArgAny)
3679- js. AsInstanceOf (genActualArgAny, formalParamTypeAndTypeRef._1)(genActualArgAny.pos)
3661+ genAsInstanceOf (genActualArgAny, formalParamTypeAndTypeRef._1)(genActualArgAny.pos)
36803662 }
36813663
3682- (formalParamTypesAndTypeRefs.map(_ ._2), actualArgs)
3664+ (formalParamTypesAndTypeRefs.map(pair => toParamOrResultTypeRef(pair ._2) ), actualArgs)
36833665
36843666 case _ =>
36853667 report.error(
@@ -3692,7 +3674,7 @@ class JSCodeGen()(using genCtx: Context) {
36923674
36933675 val methodName = MethodName .reflectiveProxy(methodNameStr, formalParamTypeRefs)
36943676
3695- 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 )
36963678 }
36973679
36983680 /** Gen actual actual arguments to Scala method call.
@@ -4306,10 +4288,13 @@ object JSCodeGen {
43064288 private val NullPointerExceptionClass = ClassName (" java.lang.NullPointerException" )
43074289 private val JSObjectClassName = ClassName (" scala.scalajs.js.Object" )
43084290
4291+ private val ObjectClassRef = jstpe.ClassRef (ir.Names .ObjectClass )
4292+
43094293 private val newSimpleMethodName = SimpleMethodName (" new" )
43104294
4311- private val ObjectArgConstructorName =
4312- 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 ))
43134298
43144299 private val thisOriginalName = OriginalName (" this" )
43154300
0 commit comments