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