JS: fix translation of catch blocks so that all references to exception variable are referentially equivalent to each other

This commit is contained in:
Alexey Andreev
2016-11-01 14:42:16 +03:00
parent 674e5df7f1
commit 23bddac4fe
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.js.translate.expression
import com.google.dart.compiler.backend.js.ast.* import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.general.Translation.patternTranslator import org.jetbrains.kotlin.js.translate.general.Translation.patternTranslator
import org.jetbrains.kotlin.js.translate.general.Translation.translateAsStatementAndMergeInBlockIfNeeded import org.jetbrains.kotlin.js.translate.general.Translation.translateAsStatementAndMergeInBlockIfNeeded
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToBlock import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToBlock
import org.jetbrains.kotlin.psi.KtCatchClause import org.jetbrains.kotlin.psi.KtCatchClause
@@ -68,34 +70,49 @@ class CatchTranslator(
val firstCatch = catches.first() val firstCatch = catches.first()
val catchParameter = firstCatch.catchParameter val catchParameter = firstCatch.catchParameter
val parameterName = context().getNameForElement(catchParameter!!) val parameterDescriptor = BindingUtils.getDescriptorForElement(bindingContext(), catchParameter!!)
val parameterRef = parameterName.makeRef() val parameterName = context().getNameForDescriptor(parameterDescriptor).ident
return JsCatch(context().scope(), val jsCatch = JsCatch(context().scope(), parameterName)
parameterRef.ident, val parameterRef = jsCatch.parameter.name.makeRef()
translateCatches(parameterRef, catches.iterator())) val catchContext = context().innerContextWithAliased(parameterDescriptor, parameterRef)
jsCatch.body = JsBlock(translateCatches(catchContext, parameterDescriptor, parameterRef, catches.iterator()))
return jsCatch
} }
private fun translateCatches(parameterRef: JsNameRef, catches: Iterator<KtCatchClause>): JsStatement { private fun translateCatches(
context: TranslationContext,
parameterDescriptor: DeclarationDescriptor,
parameterRef: JsNameRef,
catches: Iterator<KtCatchClause>
): JsStatement {
if (!catches.hasNext()) return JsThrow(parameterRef) if (!catches.hasNext()) return JsThrow(parameterRef)
var nextContext = context
val catch = catches.next() val catch = catches.next()
val param = catch.catchParameter!! val param = catch.catchParameter!!
val paramName = context().getNameForElement(param) val paramName = context.getNameForElement(param)
val paramType = param.typeReference!! val paramType = param.typeReference!!
val thenBlock = translateCatchBody(context(), catch) val additionalStatements = mutableListOf<JsStatement>()
if (paramName.ident != parameterRef.ident) if (paramName.ident != parameterRef.ident) {
thenBlock.statements.add(0, JsAstUtils.newVar(paramName, parameterRef)) additionalStatements += JsAstUtils.newVar(paramName, parameterRef)
nextContext = nextContext.innerContextWithAliased(parameterDescriptor, paramName.makeRef())
}
val thenBlock = translateCatchBody(context, catch)
thenBlock.statements.addAll(0, additionalStatements)
if (paramType.isThrowable) return thenBlock if (paramType.isThrowable) return thenBlock
// translateIsCheck won't ever return `null` if its second argument is `null` // translateIsCheck won't ever return `null` if its second argument is `null`
val typeCheck = with (patternTranslator(context())) { val typeCheck = with (patternTranslator(nextContext)) {
translateIsCheck(parameterRef, null, paramType) translateIsCheck(parameterRef, null, paramType)
}!! }!!
val elseBlock = translateCatches(parameterRef, catches) val elseBlock = translateCatches(nextContext, parameterDescriptor, parameterRef, catches)
return JsIf(typeCheck, thenBlock, elseBlock) return JsIf(typeCheck, thenBlock, elseBlock)
} }