[JS IR | IR] Implement error element lowering to support compilation with errors
This commit is contained in:
+68
@@ -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<IrDeclaration>? {
|
||||||
|
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<IrExpression>().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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmen
|
|||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -59,6 +60,7 @@ class JsIrBackendContext(
|
|||||||
override val irFactory: IrFactory = PersistentIrFactory
|
override val irFactory: IrFactory = PersistentIrFactory
|
||||||
|
|
||||||
val devMode = configuration[JSConfigurationKeys.DEVELOPER_MODE] ?: false
|
val devMode = configuration[JSConfigurationKeys.DEVELOPER_MODE] ?: false
|
||||||
|
val errorPolicy = configuration[JSConfigurationKeys.ERROR_TOLERANCE_POLICY] ?: ErrorTolerancePolicy.DEFAULT
|
||||||
|
|
||||||
val externalPackageFragment = mutableMapOf<IrFileSymbol, IrFile>()
|
val externalPackageFragment = mutableMapOf<IrFileSymbol, IrFile>()
|
||||||
val externalDeclarations = hashSetOf<IrDeclaration>()
|
val externalDeclarations = hashSetOf<IrDeclaration>()
|
||||||
@@ -229,6 +231,9 @@ class JsIrBackendContext(
|
|||||||
|
|
||||||
// classes forced to be loaded
|
// 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 primitiveClassesObject = getIrClass(FqName("kotlin.reflect.js.internal.PrimitiveClasses"))
|
||||||
|
|
||||||
val throwableClass = getIrClass(JsIrBackendContext.KOTLIN_PACKAGE_FQN.child(Name.identifier("Throwable")))
|
val throwableClass = getIrClass(JsIrBackendContext.KOTLIN_PACKAGE_FQN.child(Name.identifier("Throwable")))
|
||||||
|
|||||||
+63
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user