@@ -861,8 +861,8 @@ class JSCodeGen()(implicit ctx: Context) {
861
861
case WhileDo (cond, body) =>
862
862
js.While (genExpr(cond), genStat(body))
863
863
864
- /* case t: Try =>
865
- genTry(t, isStat)*/
864
+ case t : Try =>
865
+ genTry(t, isStat)
866
866
867
867
case app : Apply =>
868
868
genApply(app, isStat)
@@ -1013,8 +1013,8 @@ class JSCodeGen()(implicit ctx: Context) {
1013
1013
case tree : Closure =>
1014
1014
genClosure(tree)
1015
1015
1016
- /* case EmptyTree =>
1017
- js.Skip()*/
1016
+ case EmptyTree =>
1017
+ js.Skip ()
1018
1018
1019
1019
case _ =>
1020
1020
throw new FatalError (" Unexpected tree in genExpr: " +
@@ -1052,6 +1052,114 @@ class JSCodeGen()(implicit ctx: Context) {
1052
1052
}
1053
1053
}
1054
1054
1055
+ /** Gen IR code for a `try..catch` or `try..finally` block.
1056
+ *
1057
+ * `try..finally` blocks are compiled straightforwardly to `try..finally`
1058
+ * blocks of the IR.
1059
+ *
1060
+ * `try..catch` blocks are a bit more subtle, as the IR does not have
1061
+ * type-based selection of exceptions to catch. We thus encode explicitly
1062
+ * the type tests, like in:
1063
+ *
1064
+ * ```
1065
+ * try { ... }
1066
+ * catch (e) {
1067
+ * if (e.isInstanceOf[IOException]) { ... }
1068
+ * else if (e.isInstanceOf[Exception]) { ... }
1069
+ * else {
1070
+ * throw e; // default, re-throw
1071
+ * }
1072
+ * }
1073
+ * ```
1074
+ *
1075
+ * In addition, there are provisions to handle catching JavaScript
1076
+ * exceptions (which do not extend `Throwable`) as wrapped in a
1077
+ * `js.JavaScriptException`.
1078
+ */
1079
+ private def genTry (tree : Try , isStat : Boolean ): js.Tree = {
1080
+ implicit val pos : SourcePosition = tree.sourcePos
1081
+ val Try (block, catches, finalizer) = tree
1082
+
1083
+ val blockAST = genStatOrExpr(block, isStat)
1084
+ val resultType = toIRType(tree.tpe)
1085
+
1086
+ val handled =
1087
+ if (catches.isEmpty) blockAST
1088
+ else genTryCatch(blockAST, catches, resultType, isStat)
1089
+
1090
+ genStat(finalizer) match {
1091
+ case js.Skip () => handled
1092
+ case ast => js.TryFinally (handled, ast)
1093
+ }
1094
+ }
1095
+
1096
+ private def genTryCatch (body : js.Tree , catches : List [CaseDef ],
1097
+ resultType : jstpe.Type ,
1098
+ isStat : Boolean )(implicit pos : SourcePosition ): js.Tree = {
1099
+ val exceptIdent = freshLocalIdent(" e" )
1100
+ val origExceptVar = js.VarRef (exceptIdent)(jstpe.AnyType )
1101
+
1102
+ val mightCatchJavaScriptException = catches.exists { caseDef =>
1103
+ caseDef.pat match {
1104
+ case Typed (Ident (nme.WILDCARD ), tpt) =>
1105
+ isMaybeJavaScriptException(tpt.tpe)
1106
+ case Ident (nme.WILDCARD ) =>
1107
+ true
1108
+ case pat @ Bind (_, _) =>
1109
+ isMaybeJavaScriptException(pat.symbol.info)
1110
+ }
1111
+ }
1112
+
1113
+ val (exceptValDef, exceptVar) = if (mightCatchJavaScriptException) {
1114
+ val valDef = js.VarDef (freshLocalIdent(" e" ),
1115
+ encodeClassType(defn.ThrowableClass ), mutable = false , {
1116
+ genModuleApplyMethod(jsdefn.Runtime_wrapJavaScriptException , origExceptVar :: Nil )
1117
+ })
1118
+ (valDef, valDef.ref)
1119
+ } else {
1120
+ (js.Skip (), origExceptVar)
1121
+ }
1122
+
1123
+ val elseHandler : js.Tree = js.Throw (origExceptVar)
1124
+
1125
+ val handler = catches.foldRight(elseHandler) { (caseDef, elsep) =>
1126
+ implicit val pos : SourcePosition = caseDef.sourcePos
1127
+ val CaseDef (pat, _, body) = caseDef
1128
+
1129
+ // Extract exception type and variable
1130
+ val (tpe, boundVar) = (pat match {
1131
+ case Typed (Ident (nme.WILDCARD ), tpt) =>
1132
+ (tpt.tpe, None )
1133
+ case Ident (nme.WILDCARD ) =>
1134
+ (defn.ThrowableType , None )
1135
+ case Bind (_, _) =>
1136
+ (pat.symbol.info, Some (encodeLocalSym(pat.symbol)))
1137
+ })
1138
+
1139
+ // Generate the body that must be executed if the exception matches
1140
+ val bodyWithBoundVar = (boundVar match {
1141
+ case None =>
1142
+ genStatOrExpr(body, isStat)
1143
+ case Some (bv) =>
1144
+ val castException = genAsInstanceOf(exceptVar, tpe)
1145
+ js.Block (
1146
+ js.VarDef (bv, toIRType(tpe), mutable = false , castException),
1147
+ genStatOrExpr(body, isStat))
1148
+ })
1149
+
1150
+ // Generate the test
1151
+ if (tpe =:= defn.ThrowableType ) {
1152
+ bodyWithBoundVar
1153
+ } else {
1154
+ val cond = genIsInstanceOf(exceptVar, tpe)
1155
+ js.If (cond, bodyWithBoundVar, elsep)(resultType)
1156
+ }
1157
+ }
1158
+
1159
+ js.TryCatch (body, exceptIdent,
1160
+ js.Block (exceptValDef, handler))(resultType)
1161
+ }
1162
+
1055
1163
/** Gen JS code for an Apply node (method call)
1056
1164
*
1057
1165
* There's a whole bunch of varieties of Apply nodes: regular method
@@ -1916,7 +2024,7 @@ class JSCodeGen()(implicit ctx: Context) {
1916
2024
* primitive instead.)
1917
2025
*/
1918
2026
private def genTypeApply (tree : TypeApply ): js.Tree = {
1919
- implicit val pos = tree.span
2027
+ implicit val pos : SourcePosition = tree.sourcePos
1920
2028
1921
2029
val TypeApply (fun, targs) = tree
1922
2030
@@ -1935,7 +2043,7 @@ class JSCodeGen()(implicit ctx: Context) {
1935
2043
if (sym == defn.Any_asInstanceOf ) {
1936
2044
genAsInstanceOf(genReceiver, to)
1937
2045
} else if (sym == defn.Any_isInstanceOf ) {
1938
- genIsInstanceOf(tree, genReceiver, to)
2046
+ genIsInstanceOf(genReceiver, to)
1939
2047
} else {
1940
2048
throw new FatalError (
1941
2049
s " Unexpected type application $fun with symbol ${sym.fullName}" )
@@ -2132,8 +2240,8 @@ class JSCodeGen()(implicit ctx: Context) {
2132
2240
}
2133
2241
2134
2242
/** Gen JS code for an isInstanceOf test (for reference types only) */
2135
- private def genIsInstanceOf (tree : Tree , value : js.Tree , to : Type ): js. Tree = {
2136
- implicit val pos = tree.span
2243
+ private def genIsInstanceOf (value : js.Tree , to : Type )(
2244
+ implicit pos : SourcePosition ) : js. Tree = {
2137
2245
val sym = to.widenDealias.typeSymbol
2138
2246
2139
2247
if (sym == defn.ObjectClass ) {
@@ -2142,7 +2250,7 @@ class JSCodeGen()(implicit ctx: Context) {
2142
2250
if (sym.is(Trait )) {
2143
2251
ctx.error(
2144
2252
s " isInstanceOf[ ${sym.fullName}] not supported because it is a JS trait " ,
2145
- tree.sourcePos )
2253
+ pos )
2146
2254
js.BooleanLiteral (true )
2147
2255
} else {
2148
2256
js.Unbox (js.JSBinaryOp (
@@ -2805,6 +2913,9 @@ class JSCodeGen()(implicit ctx: Context) {
2805
2913
)
2806
2914
}
2807
2915
2916
+ private def isMaybeJavaScriptException (tpe : Type ): Boolean =
2917
+ jsdefn.JavaScriptExceptionClass .isSubClass(tpe.typeSymbol)
2918
+
2808
2919
// Copied from DottyBackendInterface
2809
2920
2810
2921
private val desugared = new java.util.IdentityHashMap [Type , tpd.Select ]
0 commit comments