8000 Introduce a binary API with Scala functions in `Reflect`. · scala-js/scala-js@b223873 · GitHub
[go: up one dir, main page]

Skip to content

Commit b223873

Browse files
committed
Introduce a binary API with Scala functions in Reflect.
And make its internals independent of JS interop. This way, it will be usable in Wasm without JS host. We use new names for the methods, instead of overloads, because older compilers look for those methods by name only. If an older compiler gets a newer library on the classpath, and the methods with those names became overloaded, the compiler would crash. In this commit, we do not change the compiler yet, to test that the deprecated methods are correct.
1 parent 619202c commit b223873

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

library/src/main/scala/scala/scalajs/reflect/Reflect.scala

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import scala.scalajs.js
1818

1919
final class LoadableModuleClass private[reflect] (
2020
val runtimeClass: Class[_],
21-
loadModuleFun: js.Function0[Any]
21+
loadModuleFun: () => Any
2222
) {
2323
/** Loads the module instance and returns it. */
2424
def loadModule(): Any = loadModuleFun()
@@ -55,36 +55,64 @@ final class InstantiatableClass private[reflect] (
5555

5656
final class InvokableConstructor private[reflect] (
5757
val parameterTypes: List[Class[_]],
58-
newInstanceFun: js.Function
58+
newInstanceFun: Array[Any] => Any
5959
) {
6060
def newInstance(args: Any*): Any = {
6161
/* Check the number of actual arguments. We let the casts and unbox
6262
* operations inside `newInstanceFun` take care of the rest.
6363
*/
6464
require(args.size == parameterTypes.size)
65-
newInstanceFun.asInstanceOf[js.Dynamic].apply(
66-
args.asInstanceOf[Seq[js.Any]]: _*)
65+
newInstanceFun(args.toArray)
6766
}
6867
}
6968

7069
object Reflect {
7170
private val loadableModuleClasses =
72-
js.Dictionary.empty[LoadableModuleClass]
71+
mutable.HashMap.empty[String, LoadableModuleClass]
7372

7473
private val instantiatableClasses =
75-
js.Dictionary.empty[InstantiatableClass]
74+
mutable.HashMap.empty[String, InstantiatableClass]
7675

77-
// `protected[reflect]` makes it public in the IR
76+
@deprecated("used only by deprecated code", since = "1.20.0")
77+
@js.native
78+
private trait JSFunctionVarArgs extends js.Function {
79+
def apply(args: Any*): Any
80+
}
81+
82+
/* `protected[reflect]` makes these methods public in the IR.
83+
*
84+
* These methods are part of the "public ABI" used by the compiler codegen.
85+
* We must preserve backward binary compatibility for them, like for public
86+
* methods.
87+
*/
88+
89+
@deprecated("use registerLoadableModuleClassV2 instead", since = "1.20.0")
7890
protected[reflect] def registerLoadableModuleClass[T](
7991
fqcn: String, runtimeClass: Class[T],
8092
loadModuleFun: js.Function0[T]): Unit = {
93+
registerLoadableModuleClassV2(fqcn, runtimeClass, loadModuleFun)
94+
}
95+
96+
protected[reflect] def registerLoadableModuleClassV2[T](
97+
fqcn: String, runtimeClass: Class[T],
98+
loadModuleFun: () => T): Unit = {
8199
loadableModuleClasses(fqcn) =
82100
new LoadableModuleClass(runtimeClass, loadModuleFun)
83101
}
84102

103+
@deprecated("use registerInstantiatableClassV2 instead", since = "1.20.0")
85104
protected[reflect] def registerInstantiatableClass[T](
86105
fqcn: String, runtimeClass: Class[T],
87106
constructors: js.Array[js.Tuple2[js.Array[Class[_]], js.Function]]): Unit = {
107+
108+
registerInstantiatableClassV2(fqcn, runtimeClass, constructors.map { c =>
109+
(c._1.toArray, (args: Array[Any]) => c._2.asInstanceOf[JSFunctionVarArgs].apply(args: _*))
110+
}.toArray)
111+
}
112+
113+
protected[reflect] def registerInstantiatableClassV2[T](
114+
fqcn: String, runtimeClass: Class[T],
115+
constructors: Array[(Array[Class[_]], Array[Any] => Any)]): Unit = {
88116
val invokableConstructors = constructors.map { c =>
89117
new InvokableConstructor(c._1.toList, c._2)
90118
}

project/BinaryIncompatibilities.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ object BinaryIncompatibilities {
2020
)
2121

2222
val Library = Seq(
23+
// private[reflect], not an issue
24+
ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.scalajs.reflect.InvokableConstructor.this"),
25+
ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.scalajs.reflect.LoadableModuleClass.this"),
2326
)
2427

2528
val TestInterface = Seq(

0 commit comments

Comments
 (0)
0