@@ -125,7 +125,14 @@ class JSCodeGen()(using genCtx: Context) {
125
125
/** Implicitly materializes the current local name generator. */
126
126
implicit def implicitLocalNames : LocalNameGenerator = localNames.get
127
127
128
- private def currentClassType = encodeClassType(currentClassSym)
128
+ def currentThisType : jstpe.Type = {
129
+ encodeClassType(currentClassSym) match {
130
+ case tpe @ jstpe.ClassType (cls) =>
131
+ jstpe.BoxedClassToPrimType .getOrElse(cls, tpe)
132
+ case tpe =>
133
+ tpe
134
+ }
135
+ }
129
136
130
137
/** Returns a new fresh local identifier. */
131
138
private def freshLocalIdent ()(implicit pos : Position ): js.LocalIdent =
@@ -1023,7 +1030,7 @@ class JSCodeGen()(using genCtx: Context) {
1023
1030
// Constructor of a non-native JS class ------------------------------------
1024
1031
1025
1032
def genJSClassCapturesAndConstructor (constructorTrees : List [DefDef ])(
1026
- implicit pos : SourcePosition ): (List [js.ParamDef ], js.JSMethodDef ) = {
1033
+ implicit pos : SourcePosition ): (List [js.ParamDef ], js.JSConstructorDef ) = {
1027
1034
/* We need to merge all Scala constructors into a single one because the
1028
1035
* IR, like JavaScript, only allows a single one.
1029
1036
*
@@ -1095,20 +1102,21 @@ class JSCodeGen()(using genCtx: Context) {
1095
1102
(exports.result(), jsClassCaptures.result())
1096
1103
}
1097
1104
1105
+ // The name 'constructor' is used for error reporting here
1098
1106
val (formalArgs, restParam, overloadDispatchBody) =
1099
1107
jsExportsGen.genOverloadDispatch(JSName .Literal (" constructor" ), exports, jstpe.IntType )
1100
1108
1101
1109
val overloadVar = js.VarDef (freshLocalIdent(" overload" ), NoOriginalName ,
1102
1110
jstpe.IntType , mutable = false , overloadDispatchBody)
1103
1111
1104
- val ctorStats = genJSClassCtorStats(overloadVar.ref, ctorTree)
1105
-
1106
- val constructorBody = js.Block (
1107
- paramVarDefs ::: List (overloadVar, ctorStats, js.Undefined ()))
1112
+ val constructorBody = wrapJSCtorBody(
1113
+ paramVarDefs :+ overloadVar,
1114
+ genJSClassCtorBody(overloadVar.ref, ctorTree),
1115
+ js.Undefined () :: Nil
1116
+ )
1108
1117
1109
- val constructorDef = js.JSMethodDef (
1110
- js.MemberFlags .empty,
1111
- js.StringLiteral (" constructor" ),
1118
+ val constructorDef = js.JSConstructorDef (
1119
+ js.MemberFlags .empty.withNamespace(js.MemberNamespace .Constructor ),
1112
1120
formalArgs, restParam, constructorBody)(OptimizerHints .empty, None )
1113
1121
1114
1122
(jsClassCaptures, constructorDef)
@@ -1150,7 +1158,8 @@ class JSCodeGen()(using genCtx: Context) {
1150
1158
assert(jsSuperCall.isDefined,
1151
1159
s " Did not find Super call in primary JS construtor at ${dd.sourcePos}" )
1152
1160
1153
- new PrimaryJSCtor (sym, genParamsAndInfo(sym, dd.paramss), jsSuperCall.get :: jsStats.result())
1161
+ new PrimaryJSCtor (sym, genParamsAndInfo(sym, dd.paramss),
1162
+ js.JSConstructorBody (Nil , jsSuperCall.get, jsStats.result())(dd.span))
1154
1163
}
1155
1164
1156
1165
private def genSecondaryJSClassCtor (dd : DefDef ): SplitSecondaryJSCtor = {
@@ -1251,9 +1260,9 @@ class JSCodeGen()(using genCtx: Context) {
1251
1260
(jsExport, jsClassCaptures)
1252
1261
}
1253
1262
1254
- /** generates a sequence of JS constructor statements based on a constructor tree. */
1255
- private def genJSClassCtorStats (overloadVar : js.VarRef ,
1256
- ctorTree : ConstructorTree [PrimaryJSCtor ])(implicit pos : Position ): js.Tree = {
1263
+ /** Generates a JS constructor body based on a constructor tree. */
1264
+ private def genJSClassCtorBody (overloadVar : js.VarRef ,
1265
+ ctorTree : ConstructorTree [PrimaryJSCtor ])(implicit pos : Position ): js.JSConstructorBody = {
1257
1266
1258
1267
/* generates a statement that conditionally executes body iff the chosen
1259
1268
* overload is any of the descendants of `tree` (including itself).
@@ -1348,21 +1357,27 @@ class JSCodeGen()(using genCtx: Context) {
1348
1357
val primaryCtor = ctorTree.ctor
1349
1358
val secondaryCtorTrees = ctorTree.subCtors
1350
1359
1351
- js. Block (
1352
- secondaryCtorTrees.map(preStats(_, primaryCtor.paramsAndInfo)) ++
1353
- primaryCtor.body ++
1360
+ wrapJSCtorBody (
1361
+ secondaryCtorTrees.map(preStats(_, primaryCtor.paramsAndInfo)),
1362
+ primaryCtor.body,
1354
1363
secondaryCtorTrees.map(postStats(_))
1355
1364
)
1356
1365
}
1357
1366
1367
+ private def wrapJSCtorBody (before : List [js.Tree ], body : js.JSConstructorBody ,
1368
+ after : List [js.Tree ]): js.JSConstructorBody = {
1369
+ js.JSConstructorBody (before ::: body.beforeSuper, body.superCall,
1370
+ body.afterSuper ::: after)(body.pos)
1371
+ }
1372
+
1358
1373
private sealed trait JSCtor {
1359
1374
val sym : Symbol
1360
1375
val paramsAndInfo : List [(Symbol , JSParamInfo )]
1361
1376
}
1362
1377
1363
1378
private class PrimaryJSCtor (val sym : Symbol ,
1364
1379
val paramsAndInfo : List [(Symbol , JSParamInfo )],
1365
- val body : List [ js.Tree ] ) extends JSCtor
1380
+ val body : js.JSConstructorBody ) extends JSCtor
1366
1381
1367
1382
private class SplitSecondaryJSCtor (val sym : Symbol ,
1368
1383
val paramsAndInfo : List [(Symbol , JSParamInfo )],
@@ -1945,9 +1960,9 @@ class JSCodeGen()(using genCtx: Context) {
1945
1960
}*/
1946
1961
1947
1962
thisLocalVarIdent.fold[js.Tree ] {
1948
- js.This ()(currentClassType )
1963
+ js.This ()(currentThisType )
1949
1964
} { thisLocalIdent =>
1950
- js.VarRef (thisLocalIdent)(currentClassType )
1965
+ js.VarRef (thisLocalIdent)(currentThisType )
1951
1966
}
1952
1967
}
1953
1968
@@ -2014,9 +2029,7 @@ class JSCodeGen()(using genCtx: Context) {
2014
2029
2015
2030
val (exceptValDef, exceptVar) = if (mightCatchJavaScriptException) {
2016
2031
val valDef = js.VarDef (freshLocalIdent(" e" ), NoOriginalName ,
2017
- encodeClassType(defn.ThrowableClass ), mutable = false , {
2018
- genModuleApplyMethod(jsdefn.Runtime_wrapJavaScriptException , origExceptVar :: Nil )
2019
- })
2032
+ encodeClassType(defn.ThrowableClass ), mutable = false , js.WrapAsThrowable (origExceptVar))
2020
2033
(valDef, valDef.ref)
2021
2034
} else {
2022
2035
(js.Skip (), origExceptVar)
@@ -2307,7 +2320,7 @@ class JSCodeGen()(using genCtx: Context) {
2307
2320
val privateFieldDefs = mutable.ListBuffer .empty[js.FieldDef ]
2308
2321
val classDefMembers = mutable.ListBuffer .empty[js.MemberDef ]
2309
2322
val instanceMembers = mutable.ListBuffer .empty[js.MemberDef ]
2310
- var constructor : Option [js.JSMethodDef ] = None
2323
+ var constructor : Option [js.JSConstructorDef ] = None
2311
2324
2312
2325
originalClassDef.memberDefs.foreach {
2313
2326
case fdef : js.FieldDef =>
@@ -2321,17 +2334,13 @@ class JSCodeGen()(using genCtx: Context) {
2321
2334
" Non-static, unexported method in non-native JS class" )
2322
2335
classDefMembers += mdef
2323
2336
2324
- case mdef : js.JSMethodDef =>
2325
- mdef.name match {
2326
- case js.StringLiteral (" constructor" ) =>
2327
- assert(! mdef.flags.namespace.isStatic, " Exported static method" )
2328
- assert(constructor.isEmpty, " two ctors in class" )
2329
- constructor = Some (mdef)
2337
+ case cdef : js.JSConstructorDef =>
2338
+ assert(constructor.isEmpty, " two ctors in class" )
2339
+ constructor = Some (cdef)
2330
2340
2331
- case _ =>
2332
- assert(! mdef.flags.namespace.isStatic, " Exported static method" )
2333
- instanceMembers += mdef
2334
- }
2341
+ case mdef : js.JSMethodDef =>
2342
+ assert(! mdef.flags.namespace.isStatic, " Exported static method" )
2343
+ instanceMembers += mdef
2335
2344
2336
2345
case property : js.JSPropertyDef =>
2337
2346
instanceMembers += property
@@ -2361,7 +2370,7 @@ class JSCodeGen()(using genCtx: Context) {
2361
2370
val jsClassCaptures = originalClassDef.jsClassCaptures.getOrElse {
2362
2371
throw new AssertionError (s " no class captures for anonymous JS class at $pos" )
2363
2372
}
2364
- val js .JSMethodDef (_, _, ctorParams, ctorRestParam, ctorBody) = constructor.getOrElse {
2373
+ val js .JSConstructorDef ( _, ctorParams, ctorRestParam, ctorBody) = constructor.getOrElse {
2365
2374
throw new AssertionError (" No ctor found" )
2366
2375
}
2367
2376
assert(ctorParams.isEmpty && ctorRestParam.isEmpty,
@@ -2396,6 +2405,9 @@ class JSCodeGen()(using genCtx: Context) {
2396
2405
case mdef : js.MethodDef =>
2397
2406
throw new AssertionError (" unexpected MethodDef" )
2398
2407
2408
+ case cdef : js.JSConstructorDef =>
2409
+ throw new AssertionError (" unexpected JSConstructorDef" )
2410
+
2399
2411
case mdef : js.JSMethodDef =>
2400
2412
implicit val pos = mdef.pos
2401
2413
val impl = memberLambda(mdef.args, mdef.restParam, mdef.body)
@@ -2468,36 +2480,43 @@ class JSCodeGen()(using genCtx: Context) {
2468
2480
}
2469
2481
2470
2482
// Transform the constructor body.
2471
- val inlinedCtorStats = new ir.Transformers .Transformer {
2472
- override def transform (tree : js.Tree , isStat : Boolean ): js.Tree = tree match {
2473
- // The super constructor call. Transform this into a simple new call.
2474
- case js.JSSuperConstructorCall (args) =>
2475
- implicit val pos = tree.pos
2476
-
2477
- val newTree = {
2478
- val ident = originalClassDef.superClass.getOrElse(throw new FatalError (" No superclass" ))
2479
- if (args.isEmpty && ident.name == JSObjectClassName )
2480
- js.JSObjectConstr (Nil )
2481
- else
2482
- js.JSNew (jsSuperClassRef, args)
2483
- }
2484
-
2485
- js.Block (
2486
- js.VarDef (selfName, thisOriginalName, jstpe.AnyType , mutable = false , newTree) ::
2487
- memberDefinitions)
2483
+ val inlinedCtorStats : List [js.Tree ] = {
2484
+ val beforeSuper = ctorBody.beforeSuper
2488
2485
2489
- case js.This () =>
2490
- selfRef(tree.pos)
2486
+ val superCall = {
2487
+ implicit val pos = ctorBody.superCall.pos
2488
+ val js .JSSuperConstructorCall (args) = ctorBody.superCall
2491
2489
2492
- // Don't traverse closure boundaries
2493
- case closure : js.Closure =>
2494
- val newCaptureValues = closure.captureValues.map(transformExpr)
2495
- closure.copy(captureValues = newCaptureValues)(closure.pos)
2490
+ val newTree = {
2491
+ val ident = originalClassDef.superClass.getOrElse(throw new FatalError (" No superclass" ))
2492
+ if (args.isEmpty && ident.name == JSObjectClassName )
2493
+ js.JSObjectConstr (Nil )
2494
+ else
2495
+ js.JSNew (jsSuperClassRef, args)
2496
+ }
2496
2497
2497
- case tree =>
2498
- super .transform(tree, isStat)
2498
+ val selfVarDef = js. VarDef (selfName, thisOriginalName, jstpe. AnyType , mutable = false , newTree)
2499
+ selfVarDef :: memberDefinitions
2499
2500
}
2500
- }.transform(ctorBody, isStat = true )
2501
+
2502
+ // After the super call, substitute `selfRef` for `This()`
2503
+ val afterSuper = new ir.Transformers .Transformer {
2504
+ override def transform (tree : js.Tree , isStat : Boolean ): js.Tree = tree match {
2505
+ case js.This () =>
2506
+ selfRef(tree.pos)
2507
+
2508
+ // Don't traverse closure boundaries
2509
+ case closure : js.Closure =>
2510
+ val newCaptureValues = closure.captureValues.map(transformExpr)
2511
+ closure.copy(captureValues = newCaptureValues)(closure.pos)
2512
+
2513
+ case tree =>
2514
+ super .transform(tree, isStat)
2515
+ }
2516
+ }.transformStats(ctorBody.afterSuper)
2517
+
2518
+ beforeSuper ::: superCall ::: afterSuper
2519
+ }
2501
2520
2502
2521
val closure = js.Closure (arrow = true , jsClassCaptures, Nil , None ,
2503
2522
js.Block (inlinedCtorStats, selfRef), jsSuperClassValue :: args)
@@ -2989,14 +3008,12 @@ class JSCodeGen()(using genCtx: Context) {
2989
3008
implicit val pos : SourcePosition = tree.sourcePos
2990
3009
val exception = args.head
2991
3010
val genException = genExpr(exception)
2992
- js.Throw {
2993
- if (exception.tpe.typeSymbol.derivesFrom(jsdefn.JavaScriptExceptionClass )) {
2994
- genModuleApplyMethod(
2995
- jsdefn.Runtime_unwrapJavaScriptException ,
2996
- List (genException))
2997
- } else {
2998
- genException
2999
- }
3011
+ genException match {
3012
+ case js.New (cls, _, _) if cls != JavaScriptExceptionClassName =>
3013
+ // Common case where ex is neither null nor a js.JavaScriptException
3014
+ js.Throw (genException)
3015
+ case _ =>
3016
+ js.Throw (js.UnwrapFromThrowable (genException))
3000
3017
}
3001
3018
}
3002
3019
@@ -3982,6 +3999,53 @@ class JSCodeGen()(using genCtx: Context) {
3982
3999
js.JSFunctionApply (fVarDef.ref, List (keyVarRef))
3983
4000
}))
3984
4001
4002
+ case JS_THROW =>
4003
+ // js.special.throw(arg)
4004
+ js.Throw (genArgs1)
4005
+
4006
+ case JS_TRY_CATCH =>
4007
+ /* js.special.tryCatch(arg1, arg2)
4008
+ *
4009
+ * We must generate:
4010
+ *
4011
+ * val body = arg1
4012
+ * val handler = arg2
4013
+ * try {
4014
+ * body()
4015
+ * } catch (e) {
4016
+ * handler(e)
4017
+ * }
4018
+ *
4019
+ * with temporary vals, because `arg2` must be evaluated before
4020
+ * `body` executes. Moreover, exceptions thrown while evaluating
4021
+ * the function values `arg1` and `arg2` must not be caught.
4022
+ */
4023
+ val (arg1, arg2) = genArgs2
4024
+ val bodyVarDef = js.VarDef (freshLocalIdent(" body" ), NoOriginalName ,
4025
+ jstpe.AnyType , mutable = false , arg1)
4026
+ val handlerVarDef = js.VarDef (freshLocalIdent(" handler" ), NoOriginalName ,
4027
+ jstpe.AnyType , mutable = false , arg2)
4028
+ val exceptionVarIdent = freshLocalIdent(" e" )
4029
+ val exceptionVarRef = js.VarRef (exceptionVarIdent)(jstpe.AnyType )
4030
+ js.Block (
4031
+ bodyVarDef,
4032
+ handlerVarDef,
4033
+ js.TryCatch (
4034
+ js.JSFunctionApply (bodyVarDef.ref, Nil ),
4035
+ exceptionVarIdent,
4036
+ NoOriginalName ,
4037
+ js.JSFunctionApply (handlerVarDef.ref, List (exceptionVarRef))
4038
+ )(jstpe.AnyType )
4039
+ )
4040
+
4041
+ case WRAP_AS_THROWABLE =>
4042
+ // js.special.wrapAsThrowable(arg)
4043
+ js.WrapAsThrowable (genArgs1)
4044
+
4045
+ case UNWRAP_FROM_THROWABLE =>
4046
+ // js.special.unwrapFromThrowable(arg)
4047
+ js.UnwrapFromThrowable (genArgs1)
4048
+
3985
4049
case UNION_FROM | UNION_FROM_TYPE_CONSTRUCTOR =>
3986
4050
/* js.|.from and js.|.fromTypeConstructor
3987
4051
* We should not have to deal with those. They have a perfectly valid
@@ -4764,6 +4828,7 @@ object JSCodeGen {
4764
4828
4765
4829
private val NullPointerExceptionClass = ClassName (" java.lang.NullPointerException" )
4766
4830
private val JSObjectClassName = ClassName (" scala.scalajs.js.Object" )
4831
+ private val JavaScriptExceptionClassName = ClassName (" scala.scalajs.js.JavaScriptException" )
4767
4832
4768
4833
private val ObjectClassRef = jstpe.ClassRef (ir.Names .ObjectClass )
4769
4834
0 commit comments