@@ -1424,69 +1424,32 @@ object Serializers {
1424
1424
* so that `Throw(e)` only ever throws the value of `e`, while the NPE UB
1425
1425
* is specified by `UnwrapFromThrowable`. Among other things, this allows
1426
1426
* the user-space code `js.special.throw(e)` to indiscriminately throw `e`
1427
- * even if it is `null`.
1427
+ * even if it is `null`. Later, in Scala.js 1.18, we further separated the
1428
+ * null check of `UnwrapFromThrowable` to be an explicit `CheckNotNull`.
1428
1429
*
1429
- * With this hack, we patch `Throw(e)` where `e` is a nullable `Throwable`
1430
- * by inserting an appropriate `UnwrapFromThrowable `.
1430
+ * With this hack, we patch `Throw(e)` by inserting an appropriate
1431
+ * `CheckNotNull `.
1431
1432
*
1432
- * Naively, we would just return `UnwrapFromThrowable(e)`. Unfortunately,
1433
- * we cannot prove that this is type-correct when the type of `e` is a
1434
- * `ClassType(cls)`, as we cannot test whether `cls` is a subclass of
1435
- * `java.lang.Throwable`. So we have to produce the following instead:
1436
- *
1437
- * {{{
1438
- * if (expr === null) unwrapFromThrowable(null) else expr
1439
- * }}}
1440
- *
1441
- * except that evaluates `expr` twice. If it is a `VarRef`, which is a
1442
- * common case, that is fine. Otherwise, we have to wrap this pattern in
1443
- * an IIFE.
1444
- *
1445
- * We also have to avoid the transformation altogether when the `expr` is
1446
- * an `AnyType`. This happens when the previous Scala.js compiler already
1447
- * provides the unwrapped exception, which is either
1433
+ * However, we must not do that when the previous Scala.js compiler
1434
+ * already provides the *unwrapped* exception. This happened in two
1435
+ * situations:
1448
1436
*
1449
1437
* - when automatically re-throwing an unhandled exception at the end of a
1450
1438
* `try..catch`, or
1451
1439
* - when throwing a maybe-JavaScriptException, with an explicit call to
1452
1440
* `runtime.package$.unwrapJavaScriptException(x)`.
1441
+ *
1442
+ * Fortunately, in both situations, the type of the `expr` is always
1443
+ * `AnyType`. We can accurately use that test to know whether we need to
1444
+ * apply the patch.
1453
1445
*/
1454
1446
private def throwArgumentHack8 (expr : Tree )(implicit pos : Position ): Tree = {
1455
- def unwrapFromThrowable (t : Tree ): Tree =
1456
- UnaryOp (UnaryOp .UnwrapFromThrowable , t)
1457
-
1458
- expr.tpe match {
1459
- case NullType =>
1460
- // Evaluate the expression then definitely run into an NPE UB
1461
- unwrapFromThrowable(expr)
1462
-
1463
- case ClassType (_, _) =>
1464
- expr match {
1465
- case New (_, _, _) =>
1466
- // Common case (`throw new SomeException(...)`) that is known not to be `null`
1467
- expr
1468
- case VarRef (_) =>
1469
- /* Common case (explicit re-throw of the form `throw th`) where we don't need the IIFE.
1470
- * if (expr === null) unwrapFromThrowable(null) else expr
1471
- */
1472
- If (BinaryOp (BinaryOp .=== , expr, Null ()), unwrapFromThrowable(Null ()), expr)(AnyType )
1473
- case _ =>
1474
- /* General case where we need to avoid evaluating `expr` twice.
1475
- * ((x) => if (x === null) unwrapFromThrowable(null) else x)(expr)
1476
- */
1477
- val x = LocalIdent (LocalName (" x" ))
1478
- val xParamDef = ParamDef (x, OriginalName .NoOriginalName , AnyType , mutable = false )
1479
- val xRef = xParamDef.ref
1480
- val closure = Closure (arrow = true , Nil , List (xParamDef), None , {
1481
- If (BinaryOp (BinaryOp .=== , xRef, Null ()), unwrapFromThrowable(Null ()), xRef)(AnyType )
1482
- }, Nil )
1483
- JSFunctionApply (closure, List (expr))
1484
- }
1485
-
1486
- case _ =>
1487
- // Do not transform expressions of other types, in particular `AnyType`
1488
- expr
1489
- }
1447
+ if (expr.tpe == AnyType )
1448
+ expr
1449
+ else if (! expr.tpe.isNullable)
1450
+ expr // no CheckNotNull needed; common case because of `throw new ...`
1451
+ else
1452
+ UnaryOp (UnaryOp .CheckNotNull , expr)
1490
1453
}
1491
1454
1492
1455
def readTrees (): List [Tree ] =
0 commit comments