[JS IR] Implemented a set of JS code checks before klib serialization
The diagnostics cannot be implemented with the FIR frontend checker because it requires constant evaluation over FIR. Therefore, the diagnostics are implemented as a set of klib checks over IR. For the diagnostics, the js() call argument must be evaluated and inlined as IrConst<String> into IR in the same way as const val initializers and annotation arguments. ^KT-59388 Fixed ^KT-59399 Fixed ^KT-62425 Fixed
This commit is contained in:
committed by
Space Team
parent
71eaf651e8
commit
629e0628d6
@@ -6,6 +6,8 @@ plugins {
|
||||
dependencies {
|
||||
compileOnly(project(":compiler:ir.tree"))
|
||||
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||
|
||||
implementation(project(":core:compiler.common.js"))
|
||||
}
|
||||
|
||||
optInToUnsafeDuringIrConstructionAPI()
|
||||
|
||||
+4
-4
@@ -42,14 +42,14 @@ internal abstract class IrConstExpressionTransformer(
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: Data): IrStatement {
|
||||
if (declaration.kind == ClassKind.ANNOTATION_CLASS) {
|
||||
return super.visitClass(declaration, data.copy(inAnnotation = true))
|
||||
return super.visitClass(declaration, data.copy(inConstantExpression = true))
|
||||
}
|
||||
return super.visitClass(declaration, data)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Data): IrElement {
|
||||
if (expression.canBeInterpreted()) {
|
||||
return expression.interpret(failAsError = data.inAnnotation)
|
||||
return expression.interpret(failAsError = data.inConstantExpression)
|
||||
}
|
||||
return super.visitCall(expression, data)
|
||||
}
|
||||
@@ -68,7 +68,7 @@ internal abstract class IrConstExpressionTransformer(
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: Data): IrExpression {
|
||||
if (expression.canBeInterpreted()) {
|
||||
return expression.interpret(failAsError = data.inAnnotation)
|
||||
return expression.interpret(failAsError = data.inConstantExpression)
|
||||
}
|
||||
return super.visitGetField(expression, data)
|
||||
}
|
||||
@@ -78,7 +78,7 @@ internal abstract class IrConstExpressionTransformer(
|
||||
this.startOffset, this.endOffset, expression.type, listOf(this@wrapInStringConcat)
|
||||
)
|
||||
|
||||
fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = data.inAnnotation)
|
||||
fun IrExpression.wrapInToStringConcatAndInterpret(): IrExpression = wrapInStringConcat().interpret(failAsError = data.inConstantExpression)
|
||||
fun IrExpression.getConstStringOrEmpty(): String = if (this is IrConst<*>) value.toString() else ""
|
||||
|
||||
// If we have some complex expression in arguments (like some `IrComposite`) we will skip it,
|
||||
|
||||
+12
-6
@@ -11,16 +11,19 @@ import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
||||
import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker
|
||||
import org.jetbrains.kotlin.ir.interpreter.isConst
|
||||
import org.jetbrains.kotlin.ir.interpreter.property
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
|
||||
/**
|
||||
* This transformer will visit all expressions and will evaluate only those that are necessary. By "necessary" we mean expressions
|
||||
* that are used in `const val` and inside annotations.
|
||||
* This transformer will visit all expressions and will evaluate only those that are necessary.
|
||||
* By "necessary" we mean expressions that are used in `const val`, inside annotations and js() call arguments.
|
||||
*/
|
||||
internal class IrConstOnlyNecessaryTransformer(
|
||||
interpreter: IrInterpreter,
|
||||
@@ -35,10 +38,13 @@ internal class IrConstOnlyNecessaryTransformer(
|
||||
) : IrConstExpressionTransformer(
|
||||
interpreter, irFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions
|
||||
) {
|
||||
private val jsCodeFqName = JsStandardClassIds.Callables.JsCode.asSingleFqName()
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Data): IrElement {
|
||||
val isConstGetter = expression.symbol.owner.property.isConst
|
||||
if (!data.inAnnotation && !isConstGetter) {
|
||||
expression.transformChildren(this, data)
|
||||
val isJsCodeCall = expression.symbol.owner.fqNameWhenAvailable == jsCodeFqName
|
||||
if (isJsCodeCall || (!data.inConstantExpression && !isConstGetter)) {
|
||||
expression.transformChildren(this, data.copy(inConstantExpression = data.inConstantExpression || isJsCodeCall))
|
||||
return expression
|
||||
}
|
||||
return super.visitCall(expression, data)
|
||||
@@ -46,12 +52,12 @@ internal class IrConstOnlyNecessaryTransformer(
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: Data): IrExpression {
|
||||
val isConst = expression.symbol.owner.property.isConst
|
||||
if (!data.inAnnotation && !isConst) return expression
|
||||
if (!data.inConstantExpression && !isConst) return expression
|
||||
return super.visitGetField(expression, data)
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Data): IrExpression {
|
||||
if (!data.inAnnotation) {
|
||||
if (!data.inConstantExpression) {
|
||||
expression.transformChildren(this, data)
|
||||
return expression
|
||||
}
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ internal abstract class IrConstTransformer(
|
||||
private val onError: (IrFile, IrElement, IrErrorExpression) -> Unit,
|
||||
private val suppressExceptions: Boolean,
|
||||
) : IrElementTransformer<IrConstTransformer.Data> {
|
||||
internal data class Data(val inAnnotation: Boolean = false)
|
||||
internal data class Data(val inConstantExpression: Boolean = false)
|
||||
|
||||
private fun IrExpression.warningIfError(original: IrExpression): IrExpression {
|
||||
if (this is IrErrorExpression) {
|
||||
|
||||
Reference in New Issue
Block a user