@@ -3199,26 +3199,24 @@ class JSCodeGen()(using genCtx: Context) {
3199
3199
}
3200
3200
3201
3201
/** 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))
3206
3204
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 )
3222
3220
}
3223
3221
}
3224
3222
@@ -3558,48 +3556,56 @@ class JSCodeGen()(using genCtx: Context) {
3558
3556
* {{{
3559
3557
* reflectiveSelectable(structural).selectDynamic("foo")
3560
3558
* reflectiveSelectable(structural).applyDynamic("bar",
3561
- * ClassTag( classOf[Int]), ClassTag( classOf[String])
3559
+ * classOf[Int], classOf[String]
3562
3560
* )(
3563
3561
* 6, "hello"
3564
3562
* )
3565
3563
* }}}
3566
3564
*
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`:
3568
3570
*
3569
3571
* {{{
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]
3573
3575
* )(
3574
- * genericWrapArray([ Int.box(6) , "hello" : Object ])
3576
+ * 6 , "hello"
3575
3577
* )
3576
3578
* }}}
3577
3579
*
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
3580
3581
*
3581
3582
* {{{
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
+ * )
3584
3589
* }}}
3585
3590
*
3586
- * (in which case we don't care about the contextual argument).
3587
- *
3588
3591
* In SJSIR, they must be encoded as follows:
3589
3592
*
3590
3593
* {{{
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(
3593
3596
* Int.box(6).asInstanceOf[int],
3594
3597
* "hello".asInstanceOf[java.lang.String]
3595
3598
* )
3596
3599
* }}}
3597
3600
*
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
+ *
3598
3605
* This means that we must deconstruct the elaborated calls to recover:
3599
3606
*
3600
- * - the original receiver `structural`
3601
3607
* - 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
3603
3609
* compile-time List[Type], from which we'll derive `jstpe.Type`s for the
3604
3610
* `asInstanceOf`s and `jstpe.TypeRef`s for the `MethodName.reflectiveProxy`
3605
3611
* - the actual arguments as a compile-time `List[Tree]`
@@ -3609,26 +3615,10 @@ class JSCodeGen()(using genCtx: Context) {
3609
3615
*/
3610
3616
private def genReflectiveCall (tree : Apply , isSelectDynamic : Boolean ): js.Tree = {
3611
3617
implicit val pos = tree.span
3612
- val Apply (fun @ Select (receiver0 , _), args) = tree
3618
+ val Apply (fun @ Select (receiver , _), args) = tree
3613
3619
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 )
3632
3622
3633
3623
// Extract the method name as a String
3634
3624
val methodNameStr = args.head match {
@@ -3648,38 +3638,30 @@ class JSCodeGen()(using genCtx: Context) {
3648
3638
} else {
3649
3639
// Extract the param type refs and actual args from the 2nd and 3rd argument to applyDynamic
3650
3640
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 =>
3657
3646
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))
3664
3647
// Anything else is invalid
3665
- case classTag =>
3648
+ case otherTree =>
3666
3649
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). " +
3670
3652
" Other uses are not supported in Scala.js." ,
3671
- classTag .sourcePos)
3653
+ otherTree .sourcePos)
3672
3654
(jstpe.AnyType , jstpe.ClassRef (jsNames.ObjectClass ))
3673
3655
}
3674
3656
3675
3657
// Gen the actual args, downcasting them to the formal param types
3676
3658
val actualArgs = actualArgsAnyArray.elems.zip(formalParamTypesAndTypeRefs).map {
3677
3659
(actualArgAny, formalParamTypeAndTypeRef) =>
3678
3660
val genActualArgAny = genExpr(actualArgAny)
3679
- js. AsInstanceOf (genActualArgAny, formalParamTypeAndTypeRef._1)(genActualArgAny.pos)
3661
+ genAsInstanceOf (genActualArgAny, formalParamTypeAndTypeRef._1)(genActualArgAny.pos)
3680
3662
}
3681
3663
3682
- (formalParamTypesAndTypeRefs.map(_ ._2), actualArgs)
3664
+ (formalParamTypesAndTypeRefs.map(pair => toParamOrResultTypeRef(pair ._2) ), actualArgs)
3683
3665
3684
3666
case _ =>
3685
3667
report.error(
@@ -3692,7 +3674,7 @@ class JSCodeGen()(using genCtx: Context) {
3692
3674
3693
3675
val methodName = MethodName .reflectiveProxy(methodNameStr, formalParamTypeRefs)
3694
3676
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 )
3696
3678
}
3697
3679
3698
3680
/** Gen actual actual arguments to Scala method call.
@@ -4306,10 +4288,13 @@ object JSCodeGen {
4306
4288
private val NullPointerExceptionClass = ClassName (" java.lang.NullPointerException" )
4307
4289
private val JSObjectClassName = ClassName (" scala.scalajs.js.Object" )
4308
4290
4291
+ private val ObjectClassRef = jstpe.ClassRef (ir.Names .ObjectClass )
4292
+
4309
4293
private val newSimpleMethodName = SimpleMethodName (" new" )
4310
4294
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 ))
4313
4298
4314
4299
private val thisOriginalName = OriginalName (" this" )
4315
4300
0 commit comments