diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ErrorExpressionLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ErrorExpressionLowering.kt new file mode 100644 index 00000000000..95630519abf --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ErrorExpressionLowering.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.lower + +import org.jetbrains.kotlin.backend.common.BodyLoweringPass +import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.DeclarationTransformer +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrErrorDeclaration +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl +import org.jetbrains.kotlin.ir.types.IrErrorType +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +abstract class ErrorDeclarationLowering : DeclarationTransformer { + abstract fun transformErrorDeclaration(declaration: IrErrorDeclaration): IrDeclaration + override fun transformFlat(declaration: IrDeclaration): List? { + if (declaration is IrErrorDeclaration) return listOf(transformErrorDeclaration(declaration)) + return null + } +} + +abstract class ErrorExpressionLowering(context: CommonBackendContext) : BodyLoweringPass { + + protected val nothingType = context.irBuiltIns.nothingType + + abstract fun transformErrorExpression(expression: IrExpression, nodeKind: String): IrExpression + + override fun lower(irBody: IrBody, container: IrDeclaration) { + irBody.transformChildrenVoid(object : IrElementTransformerVoid() { + + override fun visitErrorExpression(expression: IrErrorExpression): IrExpression { + return transformErrorExpression(expression, "Error Expression") + } + + override fun visitErrorCallExpression(expression: IrErrorCallExpression): IrExpression { + expression.transformChildrenVoid(this) + val statements = mutableListOf().apply { + expression.explicitReceiver?.let { add(it) } + addAll(expression.arguments) + add(transformErrorExpression(expression, "Error Call")) + } + return expression.run { + IrCompositeImpl(startOffset, endOffset, nothingType, null, statements) + } + } + + override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression { + expression.transformChildrenVoid(this) + if (expression.typeOperand is IrErrorType) { + return expression.run { + IrCompositeImpl( + startOffset, endOffset, nothingType, null, listOf( + argument, transformErrorExpression(this, "Error Type") + ) + ) + } + } + + return expression + } + }) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 9f78f1ceb56..eccd135c131 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmen import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -59,6 +60,7 @@ class JsIrBackendContext( override val irFactory: IrFactory = PersistentIrFactory val devMode = configuration[JSConfigurationKeys.DEVELOPER_MODE] ?: false + val errorPolicy = configuration[JSConfigurationKeys.ERROR_TOLERANCE_POLICY] ?: ErrorTolerancePolicy.DEFAULT val externalPackageFragment = mutableMapOf() val externalDeclarations = hashSetOf() @@ -229,6 +231,9 @@ class JsIrBackendContext( // classes forced to be loaded + val errorCodeSymbol: IrSimpleFunctionSymbol? = + if (errorPolicy.allowErrors) symbolTable.referenceSimpleFunction(getJsInternalFunction("errorCode")) else null + val primitiveClassesObject = getIrClass(FqName("kotlin.reflect.js.internal.PrimitiveClasses")) val throwableClass = getIrClass(JsIrBackendContext.KOTLIN_PACKAGE_FQN.child(Name.identifier("Throwable"))) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsErrorExpressionLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsErrorExpressionLowering.kt new file mode 100644 index 00000000000..dad97947c20 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsErrorExpressionLowering.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.lower + +import org.jetbrains.kotlin.backend.common.lower.ErrorDeclarationLowering +import org.jetbrains.kotlin.backend.common.lower.ErrorExpressionLowering +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.builders.declarations.buildFun +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrErrorDeclaration +import org.jetbrains.kotlin.ir.expressions.IrErrorExpression +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.name.Name + +class JsErrorDeclarationLowering(context: JsIrBackendContext) : ErrorDeclarationLowering() { + private val nothingType = context.irBuiltIns.nothingType + private val stringType = context.irBuiltIns.stringType + private val errorSymbol = context.errorCodeSymbol + private val irFactory = context.irFactory + + override fun transformErrorDeclaration(declaration: IrErrorDeclaration): IrDeclaration { + require(errorSymbol != null) { "Should be non-null if errors are allowed" } + return irFactory.buildFun { + updateFrom(declaration) + returnType = nothingType + name = Name.identifier("\$errorDeclaration") + }.also { + it.parent = declaration.parent + it.body = irFactory.createBlockBody(it.startOffset, it.endOffset) { + statements += IrCallImpl(startOffset, endOffset, nothingType, errorSymbol, 0, 1, null, null).apply { + putValueArgument(0, IrConstImpl.string(startOffset, endOffset, stringType, "ERROR DECLARATION")) + } + } + } + } +} + +class JsErrorExpressionLowering(context: JsIrBackendContext) : ErrorExpressionLowering(context) { + + private val stringType = context.irBuiltIns.nothingType + private val errorSymbol = context.errorCodeSymbol + + override fun transformErrorExpression(expression: IrExpression, nodeKind: String): IrExpression { + val errorExpression = expression as? IrErrorExpression + val description = errorExpression?.let { "$nodeKind: ${it.description}" } ?: nodeKind + return buildThrowError(expression, description) + } + + private fun buildThrowError(element: IrElement, description: String): IrExpression { + require(errorSymbol != null) { "Should be non-null if errors are allowed" } + return element.run { + IrCallImpl(startOffset, endOffset, nothingType, errorSymbol, 0, 1, null, null).apply { + putValueArgument(0, IrConstImpl.string(startOffset, endOffset, stringType, description)) + } + } + } +} \ No newline at end of file