mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-25 08:31:32 +00:00
Compare commits
199 Commits
rr/faster_
...
kylchik/ir
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e8dd98968 | ||
|
|
53da9b9028 | ||
|
|
aef5af5298 | ||
|
|
15d93a6931 | ||
|
|
ffe8ef1d0b | ||
|
|
f5c0b212bf | ||
|
|
0fca4c8144 | ||
|
|
56f7bcf3fe | ||
|
|
fee7323e33 | ||
|
|
8bc3c486a3 | ||
|
|
65684d496a | ||
|
|
0d9064a298 | ||
|
|
aabbdf40d1 | ||
|
|
cc3dc8d0da | ||
|
|
7e837775fc | ||
|
|
bd57b54592 | ||
|
|
d20a75eb64 | ||
|
|
378a0e7016 | ||
|
|
d8189eed95 | ||
|
|
e206eeb280 | ||
|
|
82dd52ca09 | ||
|
|
b86e393871 | ||
|
|
039ebaf8f8 | ||
|
|
f74e9d0a9f | ||
|
|
6f349c9096 | ||
|
|
c75d513b9d | ||
|
|
a7af0e3562 | ||
|
|
52cb820370 | ||
|
|
b070b5fc1d | ||
|
|
8759fa4364 | ||
|
|
585bdeef38 | ||
|
|
e4fb85d337 | ||
|
|
000cad3ac2 | ||
|
|
f4a97527b0 | ||
|
|
e2dbb5e262 | ||
|
|
e441168f34 | ||
|
|
92397ea879 | ||
|
|
ec3c1f03bc | ||
|
|
fb03015cbb | ||
|
|
e43fa7883e | ||
|
|
07ed11b8e6 | ||
|
|
196c2e1e57 | ||
|
|
5498e1db1f | ||
|
|
13ae1e36f1 | ||
|
|
ca2fe3337a | ||
|
|
3f24334396 | ||
|
|
14f618f01b | ||
|
|
4e3226ca7a | ||
|
|
c1fa0d26f3 | ||
|
|
656ecd6e8b | ||
|
|
e6b2ecf9f6 | ||
|
|
9d6dbc30b7 | ||
|
|
a2da6a9658 | ||
|
|
8597a20113 | ||
|
|
f6041ab003 | ||
|
|
4ee4f70ddc | ||
|
|
926714b04e | ||
|
|
68cf5f02dc | ||
|
|
57a368b40d | ||
|
|
2830e7b531 | ||
|
|
f085a6a4b8 | ||
|
|
390e685495 | ||
|
|
17bad5eea2 | ||
|
|
abe7b5aa81 | ||
|
|
0eb557fe0b | ||
|
|
e01326b58b | ||
|
|
a7ed79a8ef | ||
|
|
f5b718a785 | ||
|
|
9c9694bf86 | ||
|
|
5a4e3f64df | ||
|
|
5558f4ddc9 | ||
|
|
7c8b6a1d86 | ||
|
|
c664baff4b | ||
|
|
aed167876d | ||
|
|
131b498928 | ||
|
|
eb68a9420f | ||
|
|
84f73bd388 | ||
|
|
bceaf43c8a | ||
|
|
1873fed551 | ||
|
|
533c1e672a | ||
|
|
e12146c39b | ||
|
|
b0a38d47c8 | ||
|
|
f301ae70cb | ||
|
|
310e17103d | ||
|
|
17daea6c0c | ||
|
|
0506ab45d8 | ||
|
|
d48080340a | ||
|
|
e34b099346 | ||
|
|
30aee310fd | ||
|
|
9e9be0a563 | ||
|
|
15d7100317 | ||
|
|
815a02b60a | ||
|
|
2d1a1ca267 | ||
|
|
9ae85f32fa | ||
|
|
c71a7256f3 | ||
|
|
32e55520bb | ||
|
|
9fa66ea6df | ||
|
|
dfdb0a10f1 | ||
|
|
754ff3365b | ||
|
|
d0399e22f5 | ||
|
|
653b2472d7 | ||
|
|
8e8b3f6e40 | ||
|
|
59696a2bfa | ||
|
|
16389a0bae | ||
|
|
e6a39f5447 | ||
|
|
6a910f8aa9 | ||
|
|
751b19ebde | ||
|
|
19d3596a8c | ||
|
|
abaa7f5fc4 | ||
|
|
c3206ef39a | ||
|
|
c12cad78e6 | ||
|
|
4206c27885 | ||
|
|
fc4c0aeed1 | ||
|
|
b4b634858f | ||
|
|
abd8a07e1f | ||
|
|
c1523366ad | ||
|
|
c9a92f5caf | ||
|
|
953ed5e8b6 | ||
|
|
358e465ae2 | ||
|
|
84d07cb614 | ||
|
|
803d2dd212 | ||
|
|
f6f1754508 | ||
|
|
e3629d12fd | ||
|
|
f90f181273 | ||
|
|
88245019ac | ||
|
|
6a40a2ed7a | ||
|
|
b37c4f191d | ||
|
|
ce8174321e | ||
|
|
deac29349e | ||
|
|
e1025129ee | ||
|
|
bfe7e791f3 | ||
|
|
11774994c6 | ||
|
|
ee124cbee5 | ||
|
|
d678eb0d0d | ||
|
|
6c6244b630 | ||
|
|
1b9aa7ffd3 | ||
|
|
8f587c7b17 | ||
|
|
2e2eb1e550 | ||
|
|
538750ef77 | ||
|
|
cb4b6e0019 | ||
|
|
74c0c8588a | ||
|
|
d94a46021b | ||
|
|
60297251ce | ||
|
|
8eefb31a6a | ||
|
|
08055885be | ||
|
|
48b801965b | ||
|
|
9748449b4e | ||
|
|
d14e960599 | ||
|
|
26d277ae7b | ||
|
|
2a0cc9cc8d | ||
|
|
9f49e3a022 | ||
|
|
e7695c4f57 | ||
|
|
652144ce23 | ||
|
|
ac8dbba2f5 | ||
|
|
3052c6ed57 | ||
|
|
750f5cc5e3 | ||
|
|
b90fd16458 | ||
|
|
2e6d9138a7 | ||
|
|
b8cc94d705 | ||
|
|
939a5e2ce0 | ||
|
|
890b911c41 | ||
|
|
bc719f7e90 | ||
|
|
4a710f63fc | ||
|
|
afa20b1867 | ||
|
|
5431be34f1 | ||
|
|
a0daa70a98 | ||
|
|
8f2557729f | ||
|
|
8e09285e65 | ||
|
|
f87d4735f7 | ||
|
|
2d1aa10bc3 | ||
|
|
1de90a2fa2 | ||
|
|
cd5772f769 | ||
|
|
fec89e9829 | ||
|
|
98a076fa6b | ||
|
|
353149cd3e | ||
|
|
9e8a78183e | ||
|
|
861d96f2f3 | ||
|
|
fd85f4ab48 | ||
|
|
834c0a3ff1 | ||
|
|
0e58e89f21 | ||
|
|
35fe33d8a8 | ||
|
|
d396c84d96 | ||
|
|
b39cfe3f03 | ||
|
|
837de8f30c | ||
|
|
511802f36c | ||
|
|
717b2314b0 | ||
|
|
5c9c2bea0a | ||
|
|
e0a22eda64 | ||
|
|
0bb6fbdbe4 | ||
|
|
d2197a7763 | ||
|
|
c2a8398f15 | ||
|
|
2d83d619a7 | ||
|
|
171b3a94db | ||
|
|
3b6113de0f | ||
|
|
4dfe9c0825 | ||
|
|
74436a7f73 | ||
|
|
8d6f846546 | ||
|
|
8b430b1a58 | ||
|
|
1bae1c7bde |
@@ -467,6 +467,12 @@ default: `indy-with-constants` for JVM target 9 or greater, `inline` otherwise""
|
||||
)
|
||||
var suppressDeprecatedJvmTargetWarning: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(
|
||||
value = "-Xserialize-ir",
|
||||
description = "Save IR to metadata"
|
||||
)
|
||||
var serializeIr: Boolean by FreezableVar(false)
|
||||
|
||||
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
||||
val result = super.configureAnalysisFlags(collector)
|
||||
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
|
||||
import org.jetbrains.kotlin.backend.jvm.jvmPhases
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
||||
@@ -61,6 +62,9 @@ import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
import org.jetbrains.kotlin.fir.session.FirJvmModuleInfo
|
||||
import org.jetbrains.kotlin.fir.session.FirSessionFactory
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.jvmResolveLibraries
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
|
||||
import org.jetbrains.kotlin.modules.Module
|
||||
@@ -353,8 +357,9 @@ object KotlinToJVMBytecodeCompiler {
|
||||
performanceManager?.notifyGenerationStarted()
|
||||
|
||||
performanceManager?.notifyIRTranslationStarted()
|
||||
val extensions = JvmGeneratorExtensions()
|
||||
val (moduleFragment, symbolTable, sourceManager, components) = firAnalyzerFacade.convertToIr(extensions)
|
||||
val symbolTable = SymbolTable(JvmIdSignatureDescriptor(JvmManglerDesc()), IrFactoryImpl)
|
||||
val extensions = JvmGeneratorExtensions(symbolTable)
|
||||
val (moduleFragment, sourceManager, components) = firAnalyzerFacade.convertToIr(environment.project, symbolTable, extensions)
|
||||
|
||||
performanceManager?.notifyIRTranslationFinished()
|
||||
|
||||
|
||||
@@ -249,6 +249,8 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
|
||||
put(JVMConfigurationKeys.NO_RESET_JAR_TIMESTAMPS, arguments.noResetJarTimestamps)
|
||||
put(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS, arguments.noUnifiedNullChecks)
|
||||
|
||||
put(JVMConfigurationKeys.SERIALIZE_IR, arguments.serializeIr)
|
||||
|
||||
if (!JVMConstructorCallNormalizationMode.isSupportedValue(arguments.constructorCallNormalizationMode)) {
|
||||
messageCollector.report(
|
||||
ERROR,
|
||||
|
||||
@@ -152,4 +152,7 @@ public class JVMConfigurationKeys {
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> NO_REFLECT =
|
||||
CompilerConfigurationKey.create("Don't automatically include kotlin-reflect.jar into the output if the output is a jar");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> SERIALIZE_IR =
|
||||
CompilerConfigurationKey.create("serialize IR to class metadata");
|
||||
}
|
||||
|
||||
@@ -4320,6 +4320,40 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/constexpr")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Constexpr {
|
||||
@Test
|
||||
public void testAllFilesPresentInConstexpr() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/constexpr"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compileTimeMember.kt")
|
||||
public void testCompileTimeMember() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/constexpr/compileTimeMember.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constInitializer.kt")
|
||||
public void testConstInitializer() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/constexpr/constInitializer.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonCompileTimeInDeclaration.kt")
|
||||
public void testNonCompileTimeInDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/constexpr/nonCompileTimeInDeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonConstInitializer.kt")
|
||||
public void testNonConstInitializer() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/constexpr/nonConstInitializer.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/constructorConsistency")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.SingleClassJvmIrProvider
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
|
||||
@@ -25,6 +26,8 @@ import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveProcessor
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||
import java.io.File
|
||||
@@ -82,16 +85,21 @@ class FirAnalyzerFacade(
|
||||
return collectedDiagnostics!!
|
||||
}
|
||||
|
||||
fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult {
|
||||
fun convertToIr(project: Project, symbolTable: SymbolTable, extensions: GeneratorExtensions): Fir2IrResult {
|
||||
if (scopeSession == null) runResolution()
|
||||
val signaturer = JvmIdSignatureDescriptor(JvmManglerDesc())
|
||||
|
||||
return Fir2IrConverter.createModuleFragment(
|
||||
session, scopeSession!!, firFiles!!,
|
||||
languageVersionSettings, signaturer,
|
||||
extensions, FirJvmKotlinMangler(session), IrFactoryImpl,
|
||||
languageVersionSettings, symbolTable,
|
||||
extensions, FirJvmKotlinMangler(session), symbolTable.irFactory,
|
||||
FirJvmVisibilityConverter,
|
||||
Fir2IrJvmSpecialAnnotationSymbolProvider()
|
||||
)
|
||||
) { moduleDescriptor, irBuiltIns ->
|
||||
SingleClassJvmIrProvider(
|
||||
moduleDescriptor, irBuiltIns, symbolTable,
|
||||
IrFactoryImpl,
|
||||
VirtualFileFinder.SERVICE.getInstance(project, moduleDescriptor)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.linkage.IrProvider
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -247,15 +248,15 @@ class Fir2IrConverter(
|
||||
scopeSession: ScopeSession,
|
||||
firFiles: List<FirFile>,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
signaturer: IdSignatureComposer,
|
||||
symbolTable: SymbolTable,
|
||||
generatorExtensions: GeneratorExtensions,
|
||||
mangler: FirMangler,
|
||||
irFactory: IrFactory,
|
||||
visibilityConverter: Fir2IrVisibilityConverter,
|
||||
specialSymbolProvider: Fir2IrSpecialSymbolProvider?
|
||||
specialSymbolProvider: Fir2IrSpecialSymbolProvider?,
|
||||
deserializedIrProviderProvider: (FirModuleDescriptor, IrBuiltIns) -> IrProvider?,
|
||||
): Fir2IrResult {
|
||||
val moduleDescriptor = FirModuleDescriptor(session)
|
||||
val symbolTable = SymbolTable(signaturer, irFactory)
|
||||
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
|
||||
val typeTranslator = TypeTranslator(
|
||||
symbolTable,
|
||||
@@ -290,7 +291,8 @@ class Fir2IrConverter(
|
||||
}
|
||||
val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, irBuiltIns, irFiles)
|
||||
val irProviders =
|
||||
generateTypicalIrProviderList(irModuleFragment.descriptor, irBuiltIns, symbolTable, extensions = generatorExtensions)
|
||||
listOfNotNull(deserializedIrProviderProvider(moduleDescriptor, irBuiltIns)) +
|
||||
generateTypicalIrProviderList(irModuleFragment.descriptor, irBuiltIns, symbolTable, extensions = generatorExtensions)
|
||||
val externalDependenciesGenerator = ExternalDependenciesGenerator(
|
||||
symbolTable,
|
||||
irProviders
|
||||
@@ -321,7 +323,7 @@ class Fir2IrConverter(
|
||||
|
||||
evaluateConstants(irModuleFragment)
|
||||
|
||||
return Fir2IrResult(irModuleFragment, symbolTable, sourceManager, components)
|
||||
return Fir2IrResult(irModuleFragment, sourceManager, components)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,4 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
|
||||
data class Fir2IrResult(val irModuleFragment: IrModuleFragment, val symbolTable: SymbolTable, val sourceManager: PsiSourceManager, val components: Fir2IrComponents)
|
||||
data class Fir2IrResult(val irModuleFragment: IrModuleFragment, val sourceManager: PsiSourceManager, val components: Fir2IrComponents)
|
||||
@@ -25,9 +25,13 @@ sealed class FirMetadataSource : MetadataSource {
|
||||
else -> null
|
||||
}
|
||||
|
||||
class File(override val fir: FirFile) : FirMetadataSource(), MetadataSource.File
|
||||
class File(override val fir: FirFile) : FirMetadataSource(), MetadataSource.File {
|
||||
override var serializedIr: ByteArray? = null
|
||||
}
|
||||
|
||||
class Class(override val fir: FirClass<*>) : FirMetadataSource(), MetadataSource.Class
|
||||
class Class(override val fir: FirClass<*>) : FirMetadataSource(), MetadataSource.Class {
|
||||
override var serializedIr: ByteArray? = null
|
||||
}
|
||||
|
||||
class Function(override val fir: FirFunction<*>) : FirMetadataSource(), MetadataSource.Function
|
||||
|
||||
|
||||
@@ -6,28 +6,23 @@
|
||||
package org.jetbrains.kotlin.fir.backend.evaluate
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.EvaluationMode
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrCompileTimeChecker
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
|
||||
import org.jetbrains.kotlin.ir.interpreter.checker.IrCompileTimeChecker
|
||||
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
|
||||
fun evaluateConstants(irModuleFragment: IrModuleFragment) {
|
||||
val irConstTransformer = IrConstTransformer(irModuleFragment.irBuiltins)
|
||||
irModuleFragment.files.forEach { it.transformChildren(irConstTransformer, null) }
|
||||
val interpreter = IrInterpreter(irModuleFragment.irBuiltins)
|
||||
irModuleFragment.files.forEach { it.transformChildren(IrConstTransformer(interpreter, it), null) }
|
||||
}
|
||||
|
||||
//TODO create abstract class that will be common for this and lowering
|
||||
class IrConstTransformer(irBuiltIns: IrBuiltIns) : IrElementTransformerVoid() {
|
||||
private val interpreter = IrInterpreter(irBuiltIns)
|
||||
class IrConstTransformer(private val interpreter: IrInterpreter, private val irFile: IrFile) : IrElementTransformerVoid() {
|
||||
|
||||
private fun IrExpression.replaceIfError(original: IrExpression): IrExpression {
|
||||
return if (this !is IrErrorExpression) this else original
|
||||
@@ -35,7 +30,7 @@ class IrConstTransformer(irBuiltIns: IrBuiltIns) : IrElementTransformerVoid() {
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if (expression.accept(IrCompileTimeChecker(mode = EvaluationMode.ONLY_BUILTINS), null)) {
|
||||
return interpreter.interpret(expression).replaceIfError(expression)
|
||||
return interpreter.interpret(expression, irFile).replaceIfError(expression)
|
||||
}
|
||||
return expression
|
||||
}
|
||||
@@ -48,7 +43,7 @@ class IrConstTransformer(irBuiltIns: IrBuiltIns) : IrElementTransformerVoid() {
|
||||
if (expression is IrConst<*>) return declaration
|
||||
val isConst = declaration.correspondingPropertySymbol?.owner?.isConst == true
|
||||
if (isConst && expression.accept(IrCompileTimeChecker(declaration, mode = EvaluationMode.ONLY_BUILTINS), null)) {
|
||||
initializer.expression = interpreter.interpret(expression).replaceIfError(expression)
|
||||
initializer.expression = interpreter.interpret(expression, irFile).replaceIfError(expression)
|
||||
}
|
||||
|
||||
return declaration
|
||||
@@ -94,7 +89,7 @@ class IrConstTransformer(irBuiltIns: IrBuiltIns) : IrElementTransformerVoid() {
|
||||
|
||||
private fun IrExpression.transformSingleArg(expectedType: IrType): IrExpression {
|
||||
if (this.accept(IrCompileTimeChecker(mode = EvaluationMode.ONLY_BUILTINS), null)) {
|
||||
val const = interpreter.interpret(this).replaceIfError(this)
|
||||
val const = interpreter.interpret(this, irFile).replaceIfError(this)
|
||||
return const.convertToConstIfPossible(expectedType)
|
||||
} else if (this is IrConstructorCall) {
|
||||
transformAnnotation(this)
|
||||
|
||||
@@ -294,6 +294,8 @@ public interface Errors {
|
||||
DiagnosticFactory1<PsiElement, KotlinType> TYPE_CANT_BE_USED_FOR_CONST_VAL = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> CONST_VAL_WITHOUT_INITIALIZER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtExpression> CONST_VAL_WITH_NON_CONST_INITIALIZER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtExpression> NON_COMPILE_TIME_EXPRESSION_IN_COMPILE_TIME_DECLARATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, KtClassOrObject, KtNamedDeclaration> COMPILE_TIME_MEMBER_NOT_IMPLEMENTED = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtExpression> NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
@@ -966,6 +966,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(TYPE_CANT_BE_USED_FOR_CONST_VAL, "Const ''val'' has type ''{0}''. Only primitives and String are allowed", RENDER_TYPE);
|
||||
MAP.put(CONST_VAL_WITHOUT_INITIALIZER, "Const 'val' should have an initializer");
|
||||
MAP.put(CONST_VAL_WITH_NON_CONST_INITIALIZER, "Const 'val' initializer should be a constant value");
|
||||
MAP.put(NON_COMPILE_TIME_EXPRESSION_IN_COMPILE_TIME_DECLARATION, "Compile time declaration must contains only compile time expressions");
|
||||
MAP.put(COMPILE_TIME_MEMBER_NOT_IMPLEMENTED, "{0} is marked as compile time and method ''{1}'' must be also compile time", RENDER_CLASS_OR_OBJECT, DECLARATION_NAME);
|
||||
MAP.put(NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION, "Only 'const val' can be used in constant expressions");
|
||||
|
||||
MAP.put(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE, "An overriding function is not allowed to specify default values for its parameters");
|
||||
|
||||
@@ -44,6 +44,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
SealedInheritorInSamePackageChecker,
|
||||
SealedInheritorInSameModuleChecker,
|
||||
SealedInterfaceAllowedChecker,
|
||||
ConstexprDeclarationChecker
|
||||
)
|
||||
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
@@ -58,7 +59,7 @@ private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(),
|
||||
MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, SuspendConversionCallChecker,
|
||||
UnitConversionCallChecker, FunInterfaceConstructorReferenceChecker, NullableExtensionOperatorWithSafeCallChecker,
|
||||
ReferencingToUnderscoreNamedParameterOfCatchBlockChecker, VarargWrongExecutionOrderChecker
|
||||
ReferencingToUnderscoreNamedParameterOfCatchBlockChecker, VarargWrongExecutionOrderChecker, ConstexprCallChecker
|
||||
)
|
||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||
import org.jetbrains.kotlin.descriptors.impl.VariableDescriptorWithInitializerImpl
|
||||
@@ -127,7 +128,8 @@ class VariableTypeAndInitializerResolver(
|
||||
val constant = constantExpressionEvaluator.evaluateExpression(initializer, trace, initializerType)
|
||||
?: return@computeInitializer null
|
||||
|
||||
if (constant.usesNonConstValAsConstant && variableDescriptor.isConst) {
|
||||
val supportsCompileTime = languageVersionSettings.supportsFeature(LanguageFeature.CompileTimeCalculations)
|
||||
if (!supportsCompileTime && constant.usesNonConstValAsConstant && variableDescriptor.isConst) {
|
||||
trace.report(Errors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.on(initializer))
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
||||
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.AbstractReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.AbbreviatedType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object ConstexprCallChecker : CallChecker {
|
||||
private val compileTimeAnnotationName = FqName("kotlin.CompileTimeCalculation")
|
||||
private val compileTimeTypeAliases = setOf(
|
||||
"java.lang.StringBuilder", "java.lang.IllegalArgumentException", "java.util.NoSuchElementException"
|
||||
)
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.CompileTimeCalculations)) return
|
||||
if (resolvedCall.call.callElement is KtAnnotationEntry || resolvedCall.candidateDescriptor.isAnnotationConstructor()) return
|
||||
if (hasEnclosingIntrinsicDeclaration(context)) return
|
||||
|
||||
val isConst = (context.scope.ownerDescriptor as? PropertyDescriptor)?.isConst == true
|
||||
val isInsideCompileTimeFun = hasEnclosingConstDeclaration(context)
|
||||
if (!isConst && !isInsideCompileTimeFun) return
|
||||
|
||||
val isCompileTime = isCompileTime(resolvedCall.resultingDescriptor, context) || isCompileTimeTypeAlias(resolvedCall)
|
||||
if (isConst && !isCompileTime) {
|
||||
context.trace.report(Errors.CONST_VAL_WITH_NON_CONST_INITIALIZER.on(resolvedCall.call.calleeExpression!!))
|
||||
} else if (isInsideCompileTimeFun && !isCompileTime) {
|
||||
context.trace.report(Errors.NON_COMPILE_TIME_EXPRESSION_IN_COMPILE_TIME_DECLARATION.on(resolvedCall.call.calleeExpression!!))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isCompileTimeTypeAlias(resolvedCall: ResolvedCall<*>): Boolean {
|
||||
if (!resolvedCall.resultingDescriptor.containingDeclaration.fqNameSafe.startsWith(Name.identifier("java"))) return false
|
||||
val type = (resolvedCall.dispatchReceiver as AbstractReceiverValue).type
|
||||
if (type !is AbbreviatedType) return false
|
||||
|
||||
return type.abbreviation.constructor.declarationDescriptor?.isMarkedAsCompileTime() ?: false
|
||||
}
|
||||
|
||||
private fun isCompileTime(descriptor: CallableDescriptor, context: CallCheckerContext): Boolean {
|
||||
return when (descriptor) {
|
||||
is TypeAliasConstructorDescriptor -> descriptor.typeAliasDescriptor.isMarkedAsCompileTime()
|
||||
is PropertyAccessorDescriptor ->
|
||||
isCompileTime(descriptor.correspondingProperty, context) && (descriptor.isMarkedAsCompileTime() || descriptor.isDefault)
|
||||
is FunctionDescriptor ->
|
||||
descriptor.isMarkedAsCompileTime() || descriptor.isSpecial() || descriptor.overriddenDescriptors.any { it.isMarkedAsCompileTime() }
|
||||
is PropertyDescriptor ->
|
||||
descriptor.isMarkedAsCompileTime() || descriptor.isConst || descriptor.hasCompileTimePrimaryConstructor(context.trace.bindingContext)
|
||||
is ValueParameterDescriptor, is ReceiverParameterDescriptor, is VariableDescriptor ->
|
||||
context.scope.ownerDescriptor.isMarkedAsCompileTime()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isMarkedWith(annotation: FqName): Boolean {
|
||||
if (this.annotations.hasAnnotation(annotation)) return true
|
||||
if (this is FunctionInvokeDescriptor) return true
|
||||
if (this is ClassDescriptor && this.fqNameSafe.asString() in compileTimeTypeAliases) return true
|
||||
if (this is ClassDescriptor && this.isCompanionObject) return false
|
||||
if (this is AnonymousFunctionDescriptor) return this.containingDeclaration.isMarkedWith(annotation)
|
||||
return (this.containingDeclaration as? ClassDescriptor)?.isMarkedWith(annotation) ?: false
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isMarkedAsCompileTime(): Boolean {
|
||||
return this.isMarkedWith(compileTimeAnnotationName) || this.safeAs<PropertyDescriptor>()?.isConst == true
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.hasCompileTimePrimaryConstructor(bindingContext: BindingContext): Boolean {
|
||||
val property = this.findTopMostOverriddenDescriptors().first()
|
||||
val ktParameter = property.source.getPsi() as? KtParameter ?: return false
|
||||
val primaryConstructor = ktParameter.ownerFunction as? KtPrimaryConstructor ?: return false
|
||||
val classOwner = primaryConstructor.getContainingClassOrObject()
|
||||
val annotations = primaryConstructor.annotationEntries.mapNotNull { bindingContext[BindingContext.ANNOTATION, it] } +
|
||||
classOwner.annotationEntries.mapNotNull { bindingContext[BindingContext.ANNOTATION, it] }
|
||||
return annotations.any { it.fqName == compileTimeAnnotationName }
|
||||
}
|
||||
|
||||
private fun hasEnclosingConstDeclaration(context: CallCheckerContext): Boolean {
|
||||
return context.scope.ownerDescriptor.isMarkedAsCompileTime()
|
||||
}
|
||||
|
||||
private fun hasEnclosingIntrinsicDeclaration(context: CallCheckerContext): Boolean {
|
||||
return context.scope.ownerDescriptor.isMarkedWith(FqName("kotlin.EvaluateIntrinsic"))
|
||||
}
|
||||
|
||||
// TODO add annotation to special functions?
|
||||
private fun CallableDescriptor.isSpecial(): Boolean {
|
||||
return this.name.asString().contains("SPECIAL-FUNCTION")
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
@@ -31,7 +34,7 @@ object ConstModifierChecker : DeclarationChecker {
|
||||
|
||||
val constModifierPsiElement = declaration.modifierList!!.getModifier(KtTokens.CONST_KEYWORD)!!
|
||||
|
||||
val diagnostic = checkCanBeConst(declaration, constModifierPsiElement, descriptor).diagnostic
|
||||
val diagnostic = checkCanBeConst(declaration, constModifierPsiElement, descriptor, context.languageVersionSettings).diagnostic
|
||||
if (diagnostic != null) {
|
||||
context.trace.report(diagnostic)
|
||||
}
|
||||
@@ -43,12 +46,14 @@ object ConstModifierChecker : DeclarationChecker {
|
||||
private fun checkCanBeConst(
|
||||
declaration: KtDeclaration,
|
||||
constModifierPsiElement: PsiElement,
|
||||
descriptor: VariableDescriptor
|
||||
descriptor: VariableDescriptor,
|
||||
languageSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
|
||||
): ConstApplicability {
|
||||
if (descriptor.isVar) {
|
||||
return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable()
|
||||
}
|
||||
|
||||
// TODO remove the following check after introducing constexpr modifier
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (containingDeclaration is ClassDescriptor && containingDeclaration.kind != ClassKind.OBJECT) {
|
||||
return Errors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT.on(constModifierPsiElement).nonApplicable()
|
||||
@@ -76,7 +81,7 @@ object ConstModifierChecker : DeclarationChecker {
|
||||
return Errors.CONST_VAL_WITHOUT_INITIALIZER.on(constModifierPsiElement).nonApplicable()
|
||||
}
|
||||
|
||||
if (descriptor.compileTimeInitializer == null) {
|
||||
if (!languageSettings.supportsFeature(LanguageFeature.CompileTimeCalculations) && descriptor.compileTimeInitializer == null) {
|
||||
return Errors.CONST_VAL_WITH_NON_CONST_INITIALIZER.on(declaration.initializer!!).nonApplicable()
|
||||
}
|
||||
|
||||
@@ -89,4 +94,4 @@ sealed class ConstApplicability(val canBeConst: Boolean, val diagnostic: Diagnos
|
||||
class NonApplicable(diagnostic: Diagnostic? = null) : ConstApplicability(false, diagnostic)
|
||||
}
|
||||
|
||||
private fun Diagnostic.nonApplicable() = ConstApplicability.NonApplicable(this)
|
||||
private fun Diagnostic.nonApplicable() = ConstApplicability.NonApplicable(this)
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.resolve.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClass
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
object ConstexprDeclarationChecker : DeclarationChecker {
|
||||
private val compileTimeAnnotationName = FqName("kotlin.CompileTimeCalculation")
|
||||
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.CompileTimeCalculations)) return
|
||||
if (!descriptor.annotations.hasAnnotation(compileTimeAnnotationName)) return
|
||||
|
||||
val ktClass = when (declaration) {
|
||||
is KtClass -> declaration
|
||||
is KtPrimaryConstructor -> declaration.getContainingClassOrObject()
|
||||
else -> return
|
||||
}
|
||||
|
||||
val overriddenDeclaration = ktClass.declarations
|
||||
.filterIsInstance<KtNamedDeclaration>()
|
||||
.filter { it.hasModifier(KtTokens.OVERRIDE_KEYWORD) }
|
||||
for (ktDeclaration in overriddenDeclaration) {
|
||||
val annotationEntries = ktDeclaration.annotationEntries
|
||||
val classAnnotationEntries = ktDeclaration.containingClass()?.annotationEntries
|
||||
|
||||
fun List<KtAnnotationEntry>?.containsCompileTimeAnnotation(): Boolean {
|
||||
this ?: return false
|
||||
return this.any { context.trace.bindingContext[BindingContext.ANNOTATION, it]?.fqName == compileTimeAnnotationName }
|
||||
}
|
||||
|
||||
if (!annotationEntries.containsCompileTimeAnnotation() && !classAnnotationEntries.containsCompileTimeAnnotation()) {
|
||||
context.trace.report(Errors.COMPILE_TIME_MEMBER_NOT_IMPLEMENTED.on(ktDeclaration, ktClass, ktDeclaration))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.ir.interpreter.checker.IrCompileTimeChecker
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
|
||||
class CompileTimeCalculationLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
private val isTest = context.configuration[CommonConfigurationKeys.MODULE_NAME] == "<test-module>"
|
||||
private val interpreter = IrInterpreter(context.ir.irModule)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
if (!context.configuration.languageVersionSettings.supportsFeature(LanguageFeature.CompileTimeCalculations)) return
|
||||
if (irFile.fileEntry.name.contains("/kotlin/libraries/")) return
|
||||
irFile.transformChildren(Transformer(irFile), null)
|
||||
}
|
||||
|
||||
private inner class Transformer(private val irFile: IrFile) : IrElementTransformerVoid() {
|
||||
private fun IrExpression.report(original: IrExpression): IrExpression {
|
||||
if (this == original) return this
|
||||
val isError = this is IrErrorExpression && isTest
|
||||
val message = when (this) {
|
||||
is IrConst<*> -> this.value.toString()
|
||||
is IrErrorExpression -> this.description
|
||||
else -> TODO("unsupported type ${this::class.java}")
|
||||
}
|
||||
context.report(original, irFile, message, isError)
|
||||
return if (this !is IrErrorExpression) this else original
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.symbol.owner.valueParameters
|
||||
.forEachIndexed { index, parameter ->
|
||||
if (expression.getValueArgument(index) != null || !expression.symbol.owner.isInline) return@forEachIndexed
|
||||
val default = parameter.defaultValue?.expression as? IrCall ?: return@forEachIndexed
|
||||
val withNewOffsets = IrCallImpl(
|
||||
expression.startOffset, expression.endOffset, default.type, default.symbol,
|
||||
default.typeArgumentsCount, default.valueArgumentsCount, default.origin, default.superQualifierSymbol
|
||||
)
|
||||
withNewOffsets.copyTypeAndValueArgumentsFrom(default)
|
||||
if (withNewOffsets.accept(IrCompileTimeChecker(), null)) {
|
||||
interpreter.interpret(withNewOffsets, irFile)
|
||||
.report(withNewOffsets)
|
||||
.takeIf { it != withNewOffsets }
|
||||
?.apply { expression.putArgument(parameter, this) }
|
||||
}
|
||||
}
|
||||
if (expression.accept(IrCompileTimeChecker(), null)) {
|
||||
return interpreter.interpret(expression, irFile).report(expression)
|
||||
}
|
||||
return super.visitCall(expression)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField): IrStatement {
|
||||
val initializer = declaration.initializer
|
||||
val expression = initializer?.expression ?: return declaration
|
||||
if (expression is IrConst<*>) return declaration
|
||||
// must pass declaration symbol as initial containing declaration because of complex constructions such as try block or safe call
|
||||
val isCompileTimeComputable = expression.accept(IrCompileTimeChecker(declaration), null)
|
||||
val isConst = declaration.correspondingPropertySymbol?.owner?.isConst == true
|
||||
if (isConst && !isCompileTimeComputable) {
|
||||
context.report(expression, irFile, "Const property is used only with functions annotated as CompileTimeCalculation", true)
|
||||
} else if (isCompileTimeComputable) {
|
||||
initializer.expression = interpreter.interpret(expression, irFile).report(expression)
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
|
||||
//todo annotation call
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,8 @@ internal fun IrFactory.buildClass(builder: IrClassBuilder): IrClass = with(build
|
||||
startOffset, endOffset, origin,
|
||||
IrClassSymbolImpl(),
|
||||
name, kind, visibility, modality,
|
||||
isCompanion, isInner, isData, isExternal, isInline, isExpect, isFun
|
||||
isCompanion, isInner, isData, isExternal, isInline, isExpect, isFun,
|
||||
source
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ dependencies {
|
||||
compile(project(":compiler:ir.tree.impl"))
|
||||
compile(project(":js:js.ast"))
|
||||
compile(project(":js:js.frontend"))
|
||||
compile(project(":compiler:cli"))
|
||||
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.backend.common.atMostOne
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
@@ -23,6 +25,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
@@ -33,6 +36,12 @@ 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
|
||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -362,6 +371,21 @@ class JsIrBackendContext(
|
||||
|
||||
override fun report(element: IrElement?, irFile: IrFile?, message: String, isError: Boolean) {
|
||||
/*TODO*/
|
||||
val psiFileEntry = irFile?.fileEntry as? PsiSourceManager.PsiFileEntry
|
||||
val elementInfo = when {
|
||||
psiFileEntry != null && element != null -> {
|
||||
var psi = psiFileEntry.findPsiElement(element)
|
||||
while (psi?.parent !is KtProperty && psi?.parent !is KtBlockExpression && psi?.parent is KtExpression) psi = psi.parent
|
||||
val prefixIfDefault = (psi as? KtCallElement)?.getCallNameExpression()?.getReferencedName()
|
||||
?.let { if (element is IrCall && it != element.symbol.owner.name.asString()) " (it's default argument)" else "" } ?: ""
|
||||
"${psi?.text}$prefixIfDefault at ${psiFileEntry.getLineNumber(element.startOffset) + 1} line"
|
||||
}
|
||||
else -> ""
|
||||
}
|
||||
val messageCollector = configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!!
|
||||
val severity = if (isError) CompilerMessageSeverity.EXCEPTION else CompilerMessageSeverity.INFO
|
||||
val textInTheMiddle = if (isError) "will produce exception:" else "will be replaced on:"
|
||||
messageCollector.report(severity, "$elementInfo $textInTheMiddle $message")
|
||||
print(message)
|
||||
}
|
||||
|
||||
|
||||
@@ -709,6 +709,13 @@ private val captureStackTraceInThrowablesPhase = makeBodyLoweringPhase(
|
||||
description = "Capture stack trace in Throwable constructors"
|
||||
)
|
||||
|
||||
val compileTimeEvaluationPhase = makeJsModulePhase(
|
||||
::CompileTimeCalculationLowering,
|
||||
name = "CompileTimeEvaluation",
|
||||
//TODO change annotation to modifier
|
||||
description = "Evaluate calls that are marked with @CompileTimeCalculation annotation",
|
||||
).toModuleLowering()
|
||||
|
||||
private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
||||
{ CleanupLowering() },
|
||||
name = "CleanupLowering",
|
||||
@@ -719,6 +726,7 @@ private val loweringList = listOf<Lowering>(
|
||||
scriptRemoveReceiverLowering,
|
||||
validateIrBeforeLowering,
|
||||
expectDeclarationsRemovingPhase,
|
||||
compileTimeEvaluationPhase,
|
||||
stripTypeAliasDeclarationsPhase,
|
||||
jsCodeOutliningPhase,
|
||||
arrayConstructorPhase,
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.Mapping
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
|
||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||
@@ -19,9 +20,11 @@ import org.jetbrains.kotlin.backend.jvm.lower.CollectionStubComputer
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.JvmInnerClassesSupport
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.MemoizedInlineClassReplacements
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmGlobalDeclarationTable
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.builders.irBlock
|
||||
@@ -29,12 +32,15 @@ import org.jetbrains.kotlin.ir.builders.irNull
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
|
||||
import org.jetbrains.kotlin.psi2ir.PsiErrorBuilder
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
@@ -144,6 +150,22 @@ class JvmBackendContext(
|
||||
|
||||
override fun report(element: IrElement?, irFile: IrFile?, message: String, isError: Boolean) {
|
||||
/*TODO*/
|
||||
val psiFileEntry = irFile?.fileEntry as? PsiSourceManager.PsiFileEntry
|
||||
val elementInfo = when {
|
||||
psiFileEntry != null && element != null -> {
|
||||
var psi = psiFileEntry.findPsiElement(element)
|
||||
while (psi?.parent !is KtProperty && psi?.parent !is KtBlockExpression && psi?.parent is KtExpression) psi = psi.parent
|
||||
val prefixIfDefault = (psi as? KtCallElement)?.getCallNameExpression()?.getReferencedName()
|
||||
?.let { if (element is IrCall && it != element.symbol.owner.name.asString()) " (it's default argument)" else "" } ?: ""
|
||||
"${psi?.text}$prefixIfDefault at ${psiFileEntry.getLineNumber(element.startOffset) + 1} line"
|
||||
}
|
||||
else -> ""
|
||||
}
|
||||
//val messageCollector = configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!!
|
||||
val severity = if (isError) "EXCEPTION" else "INFO"
|
||||
val textInTheMiddle = if (isError) "will produce exception:" else "will be replaced on:"
|
||||
//messageCollector.report(severity, "$elementInfo $textInTheMiddle $message")
|
||||
psiErrorBuilder.at(element!!, irFile!!).report(Errors.NEW_INFERENCE_DIAGNOSTIC, "$severity: $elementInfo $textInTheMiddle $message")
|
||||
print(message)
|
||||
}
|
||||
|
||||
@@ -213,4 +235,6 @@ class JvmBackendContext(
|
||||
|
||||
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||
}
|
||||
|
||||
val declarationTable = DeclarationTable(JvmGlobalDeclarationTable())
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
|
||||
import org.jetbrains.kotlin.codegen.SamType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerIr
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -21,6 +23,7 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
@@ -49,9 +52,11 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
|
||||
|
||||
class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : GeneratorExtensions() {
|
||||
class JvmGeneratorExtensions(symbolTable: SymbolTable, private val generateFacades: Boolean = true) : GeneratorExtensions() {
|
||||
val classNameOverride = mutableMapOf<IrClass, JvmClassName>()
|
||||
|
||||
private val signaturer = IdSignatureSerializer(JvmManglerIr)
|
||||
|
||||
override val samConversion: SamConversion
|
||||
get() = JvmSamConversion
|
||||
|
||||
@@ -72,7 +77,7 @@ class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : Gene
|
||||
else
|
||||
null
|
||||
|
||||
override fun computeExternalDeclarationOrigin(descriptor: DeclarationDescriptor): IrDeclarationOrigin? =
|
||||
override fun computeExternalDeclarationOrigin(descriptor: DeclarationDescriptor): IrDeclarationOrigin =
|
||||
if (descriptor is JavaCallableMemberDescriptor || descriptor is JavaClassDescriptor)
|
||||
IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
else
|
||||
@@ -171,14 +176,20 @@ class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : Gene
|
||||
private val enhancedNullabilityAnnotationClass =
|
||||
createSpecialAnnotationClass(ENHANCED_NULLABILITY_ANNOTATION_FQ_NAME, kotlinJvmInternalPackage)
|
||||
|
||||
override val flexibleNullabilityAnnotationConstructor: IrConstructor? =
|
||||
flexibleNullabilityAnnotationClass.constructors.single()
|
||||
override val flexibleNullabilityAnnotationConstructor: IrConstructor =
|
||||
flexibleNullabilityAnnotationClass.constructors.single().also {
|
||||
symbolTable.storeConstructorBySignature(signaturer.composeSignatureForDeclaration(it), it)
|
||||
}
|
||||
|
||||
override val enhancedNullabilityAnnotationConstructor: IrConstructor? =
|
||||
enhancedNullabilityAnnotationClass.constructors.single()
|
||||
override val enhancedNullabilityAnnotationConstructor: IrConstructor =
|
||||
enhancedNullabilityAnnotationClass.constructors.single().also {
|
||||
symbolTable.storeConstructorBySignature(signaturer.composeSignatureForDeclaration(it), it)
|
||||
}
|
||||
|
||||
override val rawTypeAnnotationConstructor: IrConstructor? =
|
||||
rawTypeAnnotationClass.constructors.single()
|
||||
override val rawTypeAnnotationConstructor: IrConstructor =
|
||||
rawTypeAnnotationClass.constructors.single().also {
|
||||
symbolTable.storeConstructorBySignature(signaturer.composeSignatureForDeclaration(it), it)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME =
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.SingleClassJvmIrProvider
|
||||
import org.jetbrains.kotlin.codegen.CodegenFactory
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
@@ -26,12 +27,14 @@ import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
||||
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.MetadataSource
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.linkage.IrProvider
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
@@ -59,10 +62,10 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory
|
||||
|
||||
@JvmOverloads
|
||||
fun convertToIr(state: GenerationState, files: Collection<KtFile>, ignoreErrors: Boolean = false): JvmIrBackendInput {
|
||||
val extensions = JvmGeneratorExtensions()
|
||||
val mangler = JvmManglerDesc(MainFunctionDetector(state.bindingContext, state.languageVersionSettings))
|
||||
val psi2ir = Psi2IrTranslator(state.languageVersionSettings, Psi2IrConfiguration(ignoreErrors))
|
||||
val symbolTable = SymbolTable(JvmIdSignatureDescriptor(mangler), IrFactoryImpl, JvmNameProvider)
|
||||
val extensions = JvmGeneratorExtensions(symbolTable)
|
||||
val messageLogger = state.configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None
|
||||
val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext, symbolTable, extensions)
|
||||
val pluginExtensions = IrGenerationExtension.getInstances(state.project)
|
||||
@@ -135,7 +138,13 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory
|
||||
}
|
||||
irLinker.deserializeIrModuleHeader(it, kotlinLibrary)
|
||||
}
|
||||
val irProviders = listOf(irLinker)
|
||||
val irProviders = listOf(
|
||||
SingleClassJvmIrProvider(
|
||||
psi2irContext.moduleDescriptor, psi2irContext.irBuiltIns, symbolTable, psi2irContext.irFactory,
|
||||
VirtualFileFinder.SERVICE.getInstance(state.project, psi2irContext.moduleDescriptor)
|
||||
),
|
||||
irLinker
|
||||
)
|
||||
|
||||
val irModuleFragment = psi2ir.generateModuleFragment(psi2irContext, files, irProviders, pluginExtensions, expectDescriptorToSymbol = null)
|
||||
irLinker.postProcess()
|
||||
@@ -183,6 +192,24 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory
|
||||
/* JvmBackendContext creates new unbound symbols, have to resolve them. */
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
if (state.configuration.getBoolean(JVMConfigurationKeys.SERIALIZE_IR)) {
|
||||
val logger = state.configuration[IrMessageLogger.IR_MESSAGE_LOGGER]
|
||||
fun log(str: String) = logger?.report(IrMessageLogger.Severity.WARNING, str, location = null)
|
||||
|
||||
log("in serialize")
|
||||
log(irModuleFragment.files.size.toString())
|
||||
for (irFile in irModuleFragment.files) {
|
||||
(irFile.metadata as? MetadataSource.File)?.serializedIr = serializeIrFile(context, irFile)
|
||||
log("ifFile ${irFile.fileEntry.name} is serialized ${(irFile.metadata as? MetadataSource.File)?.serializedIr != null}")
|
||||
|
||||
|
||||
for (irClass in irFile.declarations.filterIsInstance<IrClass>()) {
|
||||
(irClass.metadata as? MetadataSource.Class)?.serializedIr = serializeTopLevelIrClass(context, irClass)
|
||||
log("irClass ${irClass.name} is serialized ${(irClass.metadata as? MetadataSource.Class)?.serializedIr != null}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.mapInlineClass = { descriptor ->
|
||||
context.typeMapper.mapType(context.referenceClass(descriptor).defaultType)
|
||||
}
|
||||
@@ -227,13 +254,13 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory
|
||||
backendExtension: JvmBackendExtension,
|
||||
notifyCodegenStart: () -> Unit
|
||||
) {
|
||||
val irProviders = configureBuiltInsAndgenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions)
|
||||
val irProviders = configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions)
|
||||
doGenerateFilesInternal(
|
||||
JvmIrBackendInput(state, irModuleFragment, symbolTable, sourceManager, phaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart)
|
||||
)
|
||||
}
|
||||
|
||||
fun configureBuiltInsAndgenerateIrProvidersInFrontendIRMode(
|
||||
fun configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(
|
||||
irModuleFragment: IrModuleFragment,
|
||||
symbolTable: SymbolTable,
|
||||
extensions: JvmGeneratorExtensions
|
||||
|
||||
@@ -273,6 +273,14 @@ private val kotlinNothingValueExceptionPhase = makeIrFilePhase<CommonBackendCont
|
||||
description = "Throw proper exception for calls returning value of type 'kotlin.Nothing'"
|
||||
)
|
||||
|
||||
val compileTimeEvaluationPhase = makeIrModulePhase(
|
||||
::CompileTimeCalculationLowering,
|
||||
name = "CompileTimeEvaluation",
|
||||
//TODO change annotation to modifier
|
||||
description = "Evaluate calls that are marked with @CompileTimeCalculation annotation",
|
||||
prerequisite = setOf(expectDeclarationsRemovingPhase)
|
||||
)
|
||||
|
||||
private val jvmFilePhases = listOf(
|
||||
typeAliasAnnotationMethodsPhase,
|
||||
stripTypeAliasDeclarationsPhase,
|
||||
@@ -387,6 +395,7 @@ val jvmPhases = NamedCompilerPhase(
|
||||
lower = validateIrBeforeLowering then
|
||||
processOptionalAnnotationsPhase then
|
||||
expectDeclarationsRemovingPhase then
|
||||
compileTimeEvaluationPhase then
|
||||
scriptsToClassesPhase then
|
||||
fileClassPhase then
|
||||
jvmStaticInObjectPhase then
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.BitEncoding
|
||||
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
@@ -209,6 +210,11 @@ class ClassCodegen private constructor(
|
||||
entry is MultifileFacadeFileEntry -> KotlinClassHeader.Kind.MULTIFILE_CLASS
|
||||
else -> KotlinClassHeader.Kind.SYNTHETIC_CLASS
|
||||
}
|
||||
val serializedIr = when (metadata) {
|
||||
is MetadataSource.Class -> metadata.serializedIr
|
||||
is MetadataSource.File -> metadata.serializedIr
|
||||
else -> null
|
||||
}
|
||||
|
||||
val isMultifileClassOrPart = kind == KotlinClassHeader.Kind.MULTIFILE_CLASS || kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
|
||||
|
||||
@@ -217,15 +223,15 @@ class ClassCodegen private constructor(
|
||||
extraFlags = extraFlags or JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG
|
||||
}
|
||||
|
||||
writeKotlinMetadata(visitor, state, kind, extraFlags) {
|
||||
writeKotlinMetadata(visitor, state, kind, extraFlags) { av ->
|
||||
if (metadata != null) {
|
||||
metadataSerializer.serialize(metadata)?.let { (proto, stringTable) ->
|
||||
DescriptorAsmUtil.writeAnnotationData(it, proto, stringTable)
|
||||
DescriptorAsmUtil.writeAnnotationData(av, proto, stringTable)
|
||||
}
|
||||
}
|
||||
|
||||
if (entry is MultifileFacadeFileEntry) {
|
||||
val arv = it.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME)
|
||||
val arv = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME)
|
||||
for (partFile in entry.partFiles) {
|
||||
val fileClass = partFile.declarations.singleOrNull { it.isFileClass } as IrClass?
|
||||
if (fileClass != null) arv.visit(null, typeMapper.mapClass(fileClass).internalName)
|
||||
@@ -234,14 +240,16 @@ class ClassCodegen private constructor(
|
||||
}
|
||||
|
||||
if (facadeClassName != null) {
|
||||
it.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName)
|
||||
av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName)
|
||||
}
|
||||
|
||||
if (irClass in context.classNameOverride) {
|
||||
val isFileClass = isMultifileClassOrPart || kind == KotlinClassHeader.Kind.FILE_FACADE
|
||||
assert(isFileClass) { "JvmPackageName is not supported for classes: ${irClass.render()}" }
|
||||
it.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString())
|
||||
av.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString())
|
||||
}
|
||||
|
||||
serializedIr?.let { storeSerializedIr(av, it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,3 +544,12 @@ private val Modality.flags: Int
|
||||
|
||||
private val DescriptorVisibility.flags: Int
|
||||
get() = DescriptorAsmUtil.getVisibilityAccessFlag(this) ?: throw AssertionError("Unsupported visibility $this")
|
||||
|
||||
private fun storeSerializedIr(av: AnnotationVisitor, serializedIr: ByteArray) {
|
||||
val serializedIrParts = BitEncoding.encodeBytes(serializedIr)
|
||||
val partsVisitor = av.visitArray(JvmAnnotationNames.METADATA_SERIALIZED_IR_FIELD_NAME)
|
||||
for (part in serializedIrParts) {
|
||||
partsVisitor.visit(null, part)
|
||||
}
|
||||
partsVisitor.visitEnd()
|
||||
}
|
||||
|
||||
@@ -383,7 +383,7 @@ fun collectVisibleTypeParameters(scopeOwner: IrTypeParametersContainer): Set<IrT
|
||||
// See `TypeTranslator.translateTypeAnnotations`.
|
||||
private fun JvmBackendContext.makeRawTypeAnnotation() =
|
||||
IrConstructorCallImpl.fromSymbolOwner(
|
||||
generatorExtensions.rawTypeAnnotationConstructor!!.constructedClassType,
|
||||
generatorExtensions.rawTypeAnnotationConstructor.constructedClassType,
|
||||
generatorExtensions.rawTypeAnnotationConstructor.symbol
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIrSerializer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
|
||||
fun serializeIrFile(context: JvmBackendContext, irFile: IrFile): ByteArray {
|
||||
return makeSerializer(context).serializeJvmIrFile(irFile).toByteArray()
|
||||
}
|
||||
|
||||
fun serializeTopLevelIrClass(context: JvmBackendContext, irClass: IrClass): ByteArray {
|
||||
assert(irClass.parent is IrFile)
|
||||
return makeSerializer(context).serializeTopLevelClass(irClass).toByteArray()
|
||||
}
|
||||
|
||||
private fun makeSerializer(context: JvmBackendContext) =
|
||||
JvmIrSerializer(
|
||||
context.configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None,
|
||||
context.declarationTable,
|
||||
mutableMapOf(),
|
||||
context.psiSourceManager,
|
||||
externallyVisibleOnly = false
|
||||
)
|
||||
@@ -1,10 +1,13 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:ir.tree"))
|
||||
compileOnly(project(":compiler:ir.tree"))
|
||||
compileOnly(project(":kotlin-reflect-api"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
@@ -12,3 +15,7 @@ sourceSets {
|
||||
"test" {}
|
||||
}
|
||||
|
||||
val compileKotlin: KotlinCompile by tasks
|
||||
compileKotlin.kotlinOptions {
|
||||
freeCompilerArgs = listOf("-Xinline-classes")
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.interpreter
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import java.lang.invoke.MethodHandle
|
||||
|
||||
internal interface CallInterceptor {
|
||||
val environment: IrInterpreterEnvironment
|
||||
val irBuiltIns: IrBuiltIns
|
||||
val interpreter: IrInterpreter
|
||||
|
||||
fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*> = Any::class.java): Any?
|
||||
fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>)
|
||||
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>)
|
||||
fun interceptGetObjectValue(expression: IrGetObjectValue)
|
||||
fun interceptEnumEntry(enumEntry: IrEnumEntry)
|
||||
fun interceptJavaStaticField(expression: IrGetField)
|
||||
}
|
||||
|
||||
internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : CallInterceptor {
|
||||
override val environment: IrInterpreterEnvironment = interpreter.environment
|
||||
private val callStack: CallStack = environment.callStack
|
||||
override val irBuiltIns: IrBuiltIns = environment.irBuiltIns
|
||||
private val bodyMap: Map<IdSignature, IrBody> = emptyMap()//interpreter.bodyMap
|
||||
|
||||
override fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*>): Any? {
|
||||
return interpreter.withNewCallStack(irFunction) {
|
||||
this@withNewCallStack.environment.callStack.addInstruction(CompoundInstruction(irFunction))
|
||||
valueArguments.forEach { this@withNewCallStack.environment.callStack.addVariable(it) }
|
||||
}.wrap(this@DefaultCallInterceptor, expectedResultClass)
|
||||
}
|
||||
|
||||
override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>) {
|
||||
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
|
||||
val originalCallName = call.symbol.owner.name.asString()
|
||||
when {
|
||||
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(irFunction).invokeMethod(irFunction, args)
|
||||
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
|
||||
receiver is KFunctionState && originalCallName == "invoke" -> callStack.addInstruction(CompoundInstruction(irFunction))
|
||||
receiver is ReflectionState -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, args)
|
||||
receiver is Primitive<*> -> calculateBuiltIns(irFunction, args) // check for js char, js long and get field for primitives
|
||||
irFunction.body is IrSyntheticBody -> handleIntrinsicMethods(irFunction)
|
||||
irFunction.body == null ->
|
||||
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, args)
|
||||
else -> callStack.addInstruction(CompoundInstruction(irFunction))
|
||||
}
|
||||
}
|
||||
|
||||
override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>) {
|
||||
val constructor = constructorCall.symbol.owner
|
||||
val irClass = constructor.parentAsClass
|
||||
when {
|
||||
irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
|
||||
Wrapper.getConstructorMethod(constructor).invokeMethod(constructor, args)
|
||||
if (constructorCall !is IrConstructorCall) (receiver as Common).superWrapperClass = callStack.popState() as Wrapper
|
||||
}
|
||||
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
|
||||
// array constructor doesn't have body so must be treated separately
|
||||
callStack.addVariable(Variable(constructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
|
||||
handleIntrinsicMethods(constructor)
|
||||
}
|
||||
else -> {
|
||||
callStack.pushState(receiver)
|
||||
callStack.addInstruction(CompoundInstruction(constructor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun interceptGetObjectValue(expression: IrGetObjectValue) {
|
||||
val objectClass = expression.symbol.owner
|
||||
if (objectClass.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
||||
val result = Wrapper.getCompanionObject(objectClass)
|
||||
environment.mapOfObjects[expression.symbol] = result
|
||||
callStack.pushState(result)
|
||||
}
|
||||
}
|
||||
|
||||
override fun interceptEnumEntry(enumEntry: IrEnumEntry) {
|
||||
val enumClass = enumEntry.symbol.owner.parentAsClass
|
||||
|
||||
when {
|
||||
enumClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
|
||||
val enumEntryName = enumEntry.name.asString().toState(environment.irBuiltIns.stringType)
|
||||
val valueOfFun = enumClass.declarations.single { it.nameForIrSerialization.asString() == "valueOf" } as IrFunction
|
||||
Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, listOf(enumEntryName))
|
||||
environment.mapOfEnums[enumEntry.symbol] = callStack.popState() as Complex
|
||||
}
|
||||
else -> {
|
||||
val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall)
|
||||
enumSuperCall?.apply { (0 until this.valueArgumentsCount).forEach { putValueArgument(it, null) } } // restore to null
|
||||
callStack.dropSubFrame()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun interceptJavaStaticField(expression: IrGetField) {
|
||||
val field = expression.symbol.owner
|
||||
assert(field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic)
|
||||
assert(field.initializer?.expression !is IrConst<*>)
|
||||
callStack.pushState(Wrapper.getStaticGetter(field)!!.invokeWithArguments().toState(field.type))
|
||||
}
|
||||
|
||||
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
|
||||
this ?: return handleIntrinsicMethods(irFunction)
|
||||
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(this@DefaultCallInterceptor, this.type(), args)
|
||||
withExceptionHandler(environment) {
|
||||
val result = this.invokeWithArguments(argsForMethodInvocation)
|
||||
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIntrinsicMethods(irFunction: IrFunction) {
|
||||
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
|
||||
}
|
||||
|
||||
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
|
||||
val methodName = when (val property = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol) {
|
||||
null -> irFunction.name.asString()
|
||||
else -> property.owner.name.asString()
|
||||
}
|
||||
|
||||
val receiverType = irFunction.dispatchReceiverParameter?.type
|
||||
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
|
||||
val argsValues = args.map { it.wrap(this, calledFromBuiltIns = methodName !in setOf("plus", IrBuiltIns.OperatorNames.EQEQ)) }
|
||||
|
||||
fun IrType.getOnlyName(): String {
|
||||
return when {
|
||||
this.originalKotlinType != null -> this.originalKotlinType.toString()
|
||||
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
|
||||
else -> this.render()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO replace unary, binary, ternary functions with vararg
|
||||
withExceptionHandler(environment) {
|
||||
val result = when (argsType.size) {
|
||||
1 -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0])
|
||||
2 -> when (methodName) {
|
||||
"rangeTo" -> return calculateRangeTo(irFunction.returnType, args)
|
||||
else -> interpretBinaryFunction(
|
||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1]
|
||||
)
|
||||
}
|
||||
3 -> interpretTernaryFunction(
|
||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
|
||||
argsValues[0], argsValues[1], argsValues[2]
|
||||
)
|
||||
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
|
||||
}
|
||||
// TODO check "result is Unit"
|
||||
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateRangeTo(type: IrType, args: List<State>) {
|
||||
val constructor = type.classOrNull!!.owner.constructors.first()
|
||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||
val constructorValueParameters = constructor.valueParameters.map { it.symbol }
|
||||
|
||||
val primitiveValueParameters = args.map { it as Primitive<*> }
|
||||
primitiveValueParameters.forEachIndexed { index, primitive ->
|
||||
constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type))
|
||||
}
|
||||
|
||||
callStack.addInstruction(CompoundInstruction(constructorCall))
|
||||
}
|
||||
|
||||
private fun Any?.getType(defaultType: IrType): IrType {
|
||||
return when (this) {
|
||||
is Boolean -> irBuiltIns.booleanType
|
||||
is Char -> irBuiltIns.charType
|
||||
is Byte -> irBuiltIns.byteType
|
||||
is Short -> irBuiltIns.shortType
|
||||
is Int -> irBuiltIns.intType
|
||||
is Long -> irBuiltIns.longType
|
||||
is String -> irBuiltIns.stringType
|
||||
is Float -> irBuiltIns.floatType
|
||||
is Double -> irBuiltIns.doubleType
|
||||
null -> irBuiltIns.nothingNType
|
||||
else -> defaultType
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.trySubstituteFunctionBody(): IrElement? {
|
||||
val signature = this.symbol.signature ?: return null
|
||||
this.body = bodyMap[signature] ?: return null
|
||||
callStack.addInstruction(CompoundInstruction(this))
|
||||
return body
|
||||
}
|
||||
|
||||
// TODO fix in FIR2IR; const val getter must have body with IrGetField node
|
||||
private fun IrFunction.tryCalculateLazyConst(): IrExpression? {
|
||||
if (this !is IrSimpleFunction) return null
|
||||
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
|
||||
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.interpreter
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEnvironment) {
|
||||
val callStack = environment.callStack
|
||||
when (element) {
|
||||
null -> return
|
||||
is IrSimpleFunction -> unfoldFunction(element, environment)
|
||||
is IrConstructor -> unfoldConstructor(element, callStack)
|
||||
is IrCall -> unfoldCall(element, callStack)
|
||||
is IrConstructorCall -> unfoldConstructorCall(element, callStack)
|
||||
is IrEnumConstructorCall -> unfoldEnumConstructorCall(element, callStack)
|
||||
is IrDelegatingConstructorCall -> unfoldDelegatingConstructorCall(element, callStack)
|
||||
is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack)
|
||||
is IrField -> unfoldField(element, callStack)
|
||||
is IrBody -> unfoldBody(element, callStack)
|
||||
is IrBlock -> unfoldBlock(element, callStack)
|
||||
is IrReturn -> unfoldReturn(element, callStack)
|
||||
is IrSetField -> unfoldSetField(element, callStack)
|
||||
is IrGetField -> callStack.addInstruction(SimpleInstruction(element))
|
||||
is IrGetValue -> unfoldGetValue(element, environment)
|
||||
is IrGetObjectValue -> unfoldGetObjectValue(element, environment)
|
||||
is IrGetEnumValue -> unfoldGetEnumValue(element, environment)
|
||||
is IrEnumEntry -> unfoldEnumEntry(element, environment)
|
||||
is IrConst<*> -> callStack.addInstruction(SimpleInstruction(element))
|
||||
is IrVariable -> unfoldVariable(element, callStack)
|
||||
is IrSetValue -> unfoldSetValue(element, callStack)
|
||||
is IrTypeOperatorCall -> unfoldTypeOperatorCall(element, callStack)
|
||||
is IrBranch -> unfoldBranch(element, callStack)
|
||||
is IrWhileLoop -> unfoldWhileLoop(element, callStack)
|
||||
is IrDoWhileLoop -> unfoldDoWhileLoop(element, callStack)
|
||||
is IrWhen -> unfoldWhen(element, callStack)
|
||||
is IrBreak -> unfoldBreak(element, callStack)
|
||||
is IrContinue -> unfoldContinue(element, callStack)
|
||||
is IrVararg -> unfoldVararg(element, callStack)
|
||||
is IrSpreadElement -> callStack.addInstruction(CompoundInstruction(element.expression))
|
||||
is IrTry -> unfoldTry(element, callStack)
|
||||
is IrCatch -> unfoldCatch(element, callStack)
|
||||
is IrThrow -> unfoldThrow(element, callStack)
|
||||
is IrStringConcatenation -> unfoldStringConcatenation(element, environment)
|
||||
is IrFunctionExpression -> callStack.addInstruction(SimpleInstruction(element))
|
||||
is IrFunctionReference -> unfoldFunctionReference(element, callStack)
|
||||
is IrPropertyReference -> unfoldPropertyReference(element, callStack)
|
||||
is IrClassReference -> unfoldClassReference(element, callStack)
|
||||
is IrComposite -> unfoldComposite(element, callStack)
|
||||
|
||||
else -> TODO("${element.javaClass} not supported")
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldFunction(function: IrSimpleFunction, environment: IrInterpreterEnvironment) {
|
||||
if (environment.callStack.getStackCount() >= IrInterpreterEnvironment.MAX_STACK)
|
||||
return StackOverflowError().handleUserException(environment)
|
||||
// SimpleInstruction with function is added in IrCall
|
||||
// It will serve as endpoint for all possible calls, there we drop frame and copy result to new one
|
||||
function.body?.let { environment.callStack.addInstruction(CompoundInstruction(it)) }
|
||||
?: throw InterpreterError("Ir function must be with body")
|
||||
}
|
||||
|
||||
private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack) {
|
||||
// SimpleInstruction with function is added in constructor call
|
||||
// It will serve as endpoint for all possible constructor calls, there we drop frame and return object
|
||||
callStack.addInstruction(CompoundInstruction(constructor.body!!))
|
||||
}
|
||||
|
||||
private fun unfoldCall(call: IrCall, callStack: CallStack) {
|
||||
val function = call.symbol.owner
|
||||
// new sub frame is used to store value arguments, in case then they are used in default args evaluation
|
||||
callStack.newSubFrame(call, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(call))
|
||||
unfoldValueParameters(call, callStack)
|
||||
|
||||
// must save receivers in memory in case then they are used in default args evaluation
|
||||
call.extensionReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
call.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, callStack: CallStack) {
|
||||
val constructor = constructorCall.symbol.owner
|
||||
callStack.newSubFrame(constructorCall, listOf()) // used to store value arguments, in case then they are use as default args
|
||||
// this variable is used to create object once
|
||||
callStack.addVariable(Variable(constructorCall.getThisReceiver(), Common(constructor.parentAsClass)))
|
||||
callStack.addInstruction(SimpleInstruction(constructorCall))
|
||||
unfoldValueParameters(constructorCall, callStack)
|
||||
|
||||
constructorCall.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(constructor.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, callStack: CallStack) {
|
||||
callStack.newSubFrame(enumConstructorCall, listOf()) // used to store value arguments, in case then they are use as default args
|
||||
callStack.addInstruction(SimpleInstruction(enumConstructorCall))
|
||||
unfoldValueParameters(enumConstructorCall, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctionAccessExpression, callStack: CallStack) {
|
||||
callStack.newSubFrame(delegatingConstructorCall, listOf()) // used to store value arguments, in case then they are use as default args
|
||||
callStack.addInstruction(SimpleInstruction(delegatingConstructorCall))
|
||||
unfoldValueParameters(delegatingConstructorCall, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
||||
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
||||
return defaultValue
|
||||
?: (this.parent as? IrSimpleFunction)?.overriddenSymbols
|
||||
?.map { it.owner.valueParameters[this.index].getDefault() }
|
||||
?.firstNotNullResult { it }
|
||||
}
|
||||
|
||||
fun getDefaultForParameterAt(index: Int): IrExpression? {
|
||||
return expression.symbol.owner.valueParameters[index].getDefault()?.expression
|
||||
}
|
||||
|
||||
val irFunction = expression.symbol.owner
|
||||
val valueParametersSymbols = irFunction.valueParameters.map { it.symbol }
|
||||
val valueArguments = (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it) }
|
||||
|
||||
for (i in valueParametersSymbols.indices.reversed()) {
|
||||
callStack.addInstruction(SimpleInstruction(valueParametersSymbols[i].owner))
|
||||
val arg = valueArguments[i] ?: getDefaultForParameterAt(i)
|
||||
when {
|
||||
arg != null -> callStack.addInstruction(CompoundInstruction(arg))
|
||||
else ->
|
||||
// case when value parameter is vararg and it is missing
|
||||
expression.getVarargType(i)?.let {
|
||||
callStack.addInstruction(SimpleInstruction(IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hack for extension receiver in lambda
|
||||
if (expression.valueArgumentsCount != irFunction.valueParameters.size) {
|
||||
val extensionReceiver = irFunction.getExtensionReceiver() ?: return
|
||||
callStack.addInstruction(SimpleInstruction(extensionReceiver.owner))
|
||||
valueArguments[0]?.let { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceInitializerCall, callStack: CallStack) {
|
||||
val irClass = instanceInitializerCall.classSymbol.owner
|
||||
|
||||
// init blocks processing
|
||||
val anonymousInitializer = irClass.declarations.filterIsInstance<IrAnonymousInitializer>().filter { !it.isStatic }
|
||||
anonymousInitializer.reversed().forEach { callStack.addInstruction(CompoundInstruction(it.body)) }
|
||||
|
||||
// properties processing
|
||||
val classProperties = irClass.declarations.filterIsInstance<IrProperty>()
|
||||
classProperties.filter { it.backingField?.initializer?.expression != null }.reversed()
|
||||
.forEach { callStack.addInstruction(CompoundInstruction(it.backingField)) }
|
||||
}
|
||||
|
||||
private fun unfoldField(field: IrField, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(field))
|
||||
callStack.addInstruction(CompoundInstruction(field.initializer?.expression))
|
||||
}
|
||||
|
||||
private fun unfoldBody(body: IrBody, callStack: CallStack) {
|
||||
unfoldStatements(body.statements, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldBlock(block: IrBlock, callStack: CallStack) {
|
||||
callStack.newSubFrame(block, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(block))
|
||||
unfoldStatements(block.statements, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldStatements(statements: List<IrStatement>, callStack: CallStack) {
|
||||
for (i in statements.indices.reversed()) {
|
||||
when (val statement = statements[i]) {
|
||||
is IrClass -> if (!statement.isLocal) TODO("Only local classes are supported")
|
||||
is IrFunction -> if (!statement.isLocal) TODO("Only local functions are supported")
|
||||
else -> callStack.addInstruction(CompoundInstruction(statement))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldReturn(expression: IrReturn, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(expression)) //2
|
||||
callStack.addInstruction(CompoundInstruction(expression.value)) //1
|
||||
}
|
||||
|
||||
private fun unfoldSetField(expression: IrSetField, callStack: CallStack) {
|
||||
// receiver is null, for example, for top level fields; cannot interpret set on top level var
|
||||
if (expression.receiver.let { it == null || (it.type.classifierOrNull?.owner as? IrClass)?.isObject == true }) {
|
||||
error("Cannot interpret set method on top level properties")
|
||||
}
|
||||
|
||||
callStack.addInstruction(SimpleInstruction(expression))
|
||||
callStack.addInstruction(CompoundInstruction(expression.value))
|
||||
}
|
||||
|
||||
private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnvironment) {
|
||||
val expectedClass = expression.type.classOrNull?.owner
|
||||
// used to evaluate constants inside object
|
||||
if (expectedClass != null && expectedClass.isObject && expression.symbol.owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER) {
|
||||
// TODO is this correct behaviour?
|
||||
return unfoldGetObjectValue(IrGetObjectValueImpl(0, 0, expectedClass.defaultType, expectedClass.symbol), environment)
|
||||
}
|
||||
environment.callStack.pushState(environment.callStack.getVariable(expression.symbol).state)
|
||||
}
|
||||
|
||||
private fun unfoldGetObjectValue(expression: IrGetObjectValue, environment: IrInterpreterEnvironment) {
|
||||
val callStack = environment.callStack
|
||||
val objectClass = expression.symbol.owner
|
||||
environment.mapOfObjects[objectClass.symbol]?.let { return callStack.pushState(it) }
|
||||
|
||||
callStack.newSubFrame(expression, listOf(SimpleInstruction(expression)))
|
||||
when {
|
||||
!objectClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
|
||||
val state = Common(objectClass)
|
||||
environment.mapOfObjects[objectClass.symbol] = state // must set object's state here to avoid cyclic evaluation
|
||||
callStack.addVariable(Variable(objectClass.thisReceiver!!.symbol, state))
|
||||
|
||||
val constructor = objectClass.constructors.firstOrNull() ?: return callStack.pushState(state)
|
||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||
callStack.addInstruction(CompoundInstruction(constructorCall))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterpreterEnvironment) {
|
||||
val callStack = environment.callStack
|
||||
environment.mapOfEnums[expression.symbol]?.let { return callStack.pushState(it) }
|
||||
|
||||
callStack.addInstruction(SimpleInstruction(expression))
|
||||
val enumEntry = expression.symbol.owner
|
||||
val enumClass = enumEntry.symbol.owner.parentAsClass
|
||||
enumClass.declarations.filterIsInstance<IrEnumEntry>().forEach {
|
||||
if (enumClass.hasAnnotation(evaluateIntrinsicAnnotation)) return@forEach callStack.addInstruction(SimpleInstruction(it))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldEnumEntry(enumEntry: IrEnumEntry, environment: IrInterpreterEnvironment) {
|
||||
val enumClass = enumEntry.symbol.owner.parentAsClass
|
||||
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||
|
||||
val enumSuperCall = (enumClass.primaryConstructor?.body?.statements?.firstOrNull() as? IrEnumConstructorCall)
|
||||
if (enumEntries.isNotEmpty() && enumSuperCall != null) {
|
||||
val valueArguments = listOf(
|
||||
enumEntry.name.asString().toIrConst(environment.irBuiltIns.stringType),
|
||||
enumEntries.indexOf(enumEntry).toIrConst(environment.irBuiltIns.intType)
|
||||
)
|
||||
valueArguments.forEachIndexed { index, irConst -> enumSuperCall.putValueArgument(index, irConst) }
|
||||
}
|
||||
|
||||
val enumConstructorCall = enumEntry.initializerExpression?.expression as? IrEnumConstructorCall
|
||||
?: throw InterpreterError("Initializer at enum entry ${enumEntry.fqNameWhenAvailable} is null")
|
||||
val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass))
|
||||
environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex
|
||||
|
||||
environment.callStack.newSubFrame(enumEntry, listOf(CompoundInstruction(enumConstructorCall), SimpleInstruction(enumEntry)))
|
||||
environment.callStack.addVariable(enumClassObject)
|
||||
}
|
||||
|
||||
private fun unfoldVariable(variable: IrVariable, callStack: CallStack) {
|
||||
when (variable.initializer) {
|
||||
null -> callStack.addVariable(Variable(variable.symbol))
|
||||
else -> {
|
||||
callStack.addInstruction(SimpleInstruction(variable))
|
||||
callStack.addInstruction(CompoundInstruction(variable.initializer!!))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldSetValue(expression: IrSetValue, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(expression))
|
||||
callStack.addInstruction(CompoundInstruction(expression.value))
|
||||
}
|
||||
|
||||
private fun unfoldTypeOperatorCall(element: IrTypeOperatorCall, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(element))
|
||||
callStack.addInstruction(CompoundInstruction(element.argument))
|
||||
}
|
||||
|
||||
private fun unfoldBranch(branch: IrBranch, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(branch)) //2
|
||||
callStack.addInstruction(CompoundInstruction(branch.condition)) //1
|
||||
}
|
||||
|
||||
private fun unfoldWhileLoop(loop: IrWhileLoop, callStack: CallStack) {
|
||||
callStack.newSubFrame(loop, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(loop))
|
||||
callStack.addInstruction(CompoundInstruction(loop.condition))
|
||||
}
|
||||
|
||||
private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) {
|
||||
callStack.newSubFrame(loop, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(loop))
|
||||
callStack.addInstruction(CompoundInstruction(loop.condition))
|
||||
callStack.addInstruction(CompoundInstruction(loop.body!!))
|
||||
}
|
||||
|
||||
private fun unfoldWhen(element: IrWhen, callStack: CallStack) {
|
||||
// new sub frame to drop it after
|
||||
callStack.newSubFrame(element, element.branches.map { CompoundInstruction(it) } + listOf(SimpleInstruction(element)))
|
||||
}
|
||||
|
||||
private fun unfoldContinue(element: IrContinue, callStack: CallStack) {
|
||||
callStack.unrollInstructionsForBreakContinue(element)
|
||||
}
|
||||
|
||||
private fun unfoldBreak(element: IrBreak, callStack: CallStack) {
|
||||
callStack.unrollInstructionsForBreakContinue(element)
|
||||
}
|
||||
|
||||
private fun unfoldVararg(element: IrVararg, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(element))
|
||||
element.elements.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
}
|
||||
|
||||
private fun unfoldTry(element: IrTry, callStack: CallStack) {
|
||||
callStack.newSubFrame(element, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(element))
|
||||
callStack.addInstruction(CompoundInstruction(element.tryResult))
|
||||
}
|
||||
|
||||
private fun unfoldCatch(element: IrCatch, callStack: CallStack) {
|
||||
val exceptionState = callStack.peekState() as? ExceptionState ?: return
|
||||
if (exceptionState.isSubtypeOf(element.catchParameter.type)) {
|
||||
callStack.popState()
|
||||
val frameOwner = callStack.getCurrentFrameOwner() as IrTry
|
||||
callStack.dropSubFrame() // drop other catch blocks
|
||||
callStack.newSubFrame(element, listOf()) // new frame with IrTry instruction to interpret finally block at the end
|
||||
callStack.addVariable(Variable(element.catchParameter.symbol, exceptionState))
|
||||
callStack.addInstruction(SimpleInstruction(frameOwner))
|
||||
callStack.addInstruction(CompoundInstruction(element.result))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldThrow(expression: IrThrow, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(expression))
|
||||
callStack.addInstruction(CompoundInstruction(expression.value))
|
||||
}
|
||||
|
||||
private fun unfoldStringConcatenation(expression: IrStringConcatenation, environment: IrInterpreterEnvironment) {
|
||||
val callStack = environment.callStack
|
||||
callStack.newSubFrame(expression, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(expression))
|
||||
|
||||
// this callback is used to check the need for an explicit toString call
|
||||
val explicitToStringCheck = fun() {
|
||||
when (val state = callStack.peekState()) {
|
||||
is Common -> {
|
||||
callStack.popState()
|
||||
val toStringFun = state.getToStringFunction()
|
||||
val receiver = toStringFun.dispatchReceiverParameter!!
|
||||
val toStringCall = IrCallImpl.fromSymbolOwner(0, 0, environment.irBuiltIns.stringType, toStringFun.symbol)
|
||||
toStringCall.dispatchReceiver = IrConstImpl.constNull(0, 0, receiver.type) // just stub receiver
|
||||
|
||||
callStack.newSubFrame(toStringCall, listOf(SimpleInstruction(toStringCall)))
|
||||
callStack.pushState(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
expression.arguments.reversed().forEach {
|
||||
callStack.addInstruction(CustomInstruction(explicitToStringCheck))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
||||
when (element.origin) {
|
||||
IrStatementOrigin.DESTRUCTURING_DECLARATION -> element.statements.reversed()
|
||||
.forEach { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
null -> element.statements.reversed()
|
||||
.forEach { callStack.addInstruction(CompoundInstruction(it)) } // is null for body of do while loop
|
||||
else -> TODO("${element.origin} not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
|
||||
val function = reference.symbol.owner
|
||||
callStack.newSubFrame(reference, listOf())
|
||||
callStack.addInstruction(SimpleInstruction(reference))
|
||||
|
||||
reference.extensionReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
reference.dispatchReceiver?.let {
|
||||
callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!))
|
||||
callStack.addInstruction(CompoundInstruction(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(propertyReference))
|
||||
callStack.addInstruction(CompoundInstruction(propertyReference.dispatchReceiver))
|
||||
}
|
||||
|
||||
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
|
||||
callStack.addInstruction(SimpleInstruction(classReference))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.interpreter
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.Complex
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
||||
|
||||
internal class IrInterpreterEnvironment(val irBuiltIns: IrBuiltIns, val callStack: CallStack) {
|
||||
val irExceptions = mutableListOf<IrClass>()
|
||||
var mapOfEnums = mutableMapOf<IrSymbol, Complex>()
|
||||
var mapOfObjects = mutableMapOf<IrSymbol, Complex>()
|
||||
|
||||
private constructor(environment: IrInterpreterEnvironment) : this(environment.irBuiltIns, CallStack()) {
|
||||
irExceptions.addAll(environment.irExceptions)
|
||||
mapOfEnums = environment.mapOfEnums
|
||||
mapOfObjects = environment.mapOfObjects
|
||||
}
|
||||
|
||||
constructor(irModule: IrModuleFragment) : this(irModule.irBuiltins, CallStack()) {
|
||||
irExceptions.addAll(
|
||||
irModule.files
|
||||
.flatMap { it.declarations }
|
||||
.filterIsInstance<IrClass>()
|
||||
.filter { it.isSubclassOf(irBuiltIns.throwableClass.owner) }
|
||||
)
|
||||
}
|
||||
|
||||
fun copyWithNewCallStack(): IrInterpreterEnvironment {
|
||||
return IrInterpreterEnvironment(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MAX_STACK = 10_000
|
||||
const val MAX_COMMANDS = 1_000_000
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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.interpreter
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Stack
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.Primitive
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
||||
import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
|
||||
enum class ReturnLabel {
|
||||
REGULAR, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
||||
}
|
||||
|
||||
open class ExecutionResult(val returnLabel: ReturnLabel, private val owner: IrElement? = null) {
|
||||
fun getNextLabel(irElement: IrElement, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
return when (returnLabel) {
|
||||
ReturnLabel.RETURN -> when (irElement) {
|
||||
is IrCall, is IrReturnableBlock, is IrSimpleFunction -> if (owner == irElement) Next else this
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.BREAK_WHEN -> when (irElement) {
|
||||
is IrWhen -> Next
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.BREAK_LOOP -> when (irElement) {
|
||||
is IrWhileLoop -> if (owner == irElement) Next else this
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.CONTINUE -> when (irElement) {
|
||||
is IrWhileLoop -> if (owner == irElement) irElement.interpret() else this
|
||||
else -> this
|
||||
}
|
||||
ReturnLabel.EXCEPTION -> Exception
|
||||
ReturnLabel.REGULAR -> Next
|
||||
}
|
||||
}
|
||||
|
||||
fun addOwnerInfo(owner: IrElement): ExecutionResult {
|
||||
return ExecutionResult(returnLabel, owner)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun ExecutionResult.check(toCheckLabel: ReturnLabel = ReturnLabel.REGULAR, returnBlock: (ExecutionResult) -> Unit): ExecutionResult {
|
||||
if (this.returnLabel != toCheckLabel) returnBlock(this)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is analog of `checkcast` jvm bytecode operation. Throw exception whenever actual type is not a subtype of expected.
|
||||
*/
|
||||
internal fun ExecutionResult.implicitCastIfNeeded(expectedType: IrType, actualType: IrType, stack: Stack): ExecutionResult {
|
||||
if (actualType.classifierOrNull !is IrTypeParameterSymbol) return this
|
||||
|
||||
if (expectedType.classifierOrFail is IrTypeParameterSymbol) return this
|
||||
|
||||
val actualState = stack.peekReturnValue()
|
||||
if (actualState is Primitive<*> && actualState.value == null) return this // this is handled as NullPointerException
|
||||
|
||||
if (!actualState.isSubtypeOf(expectedType)) {
|
||||
val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
|
||||
throw ClassCastException("$convertibleClassName cannot be cast to ${expectedType.render()}")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
object Next : ExecutionResult(ReturnLabel.REGULAR)
|
||||
object Return : ExecutionResult(ReturnLabel.RETURN)
|
||||
object BreakLoop : ExecutionResult(ReturnLabel.BREAK_LOOP)
|
||||
object BreakWhen : ExecutionResult(ReturnLabel.BREAK_WHEN)
|
||||
object Continue : ExecutionResult(ReturnLabel.CONTINUE)
|
||||
object Exception : ExecutionResult(ReturnLabel.EXCEPTION)
|
||||
@@ -11,19 +11,24 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.lang.invoke.MethodType
|
||||
import kotlin.math.min
|
||||
|
||||
internal fun IrFunction.getDispatchReceiver(): IrValueParameterSymbol? = this.dispatchReceiverParameter?.symbol
|
||||
|
||||
@@ -33,6 +38,8 @@ internal fun IrFunction.getReceiver(): IrSymbol? = this.getDispatchReceiver() ?:
|
||||
|
||||
internal fun IrFunctionAccessExpression.getBody(): IrBody? = this.symbol.owner.body
|
||||
|
||||
internal fun IrFunctionAccessExpression.getThisReceiver(): IrValueSymbol = this.symbol.owner.parentAsClass.thisReceiver!!.symbol
|
||||
|
||||
internal fun State.toIrExpression(expression: IrExpression): IrExpression {
|
||||
val start = expression.startOffset
|
||||
val end = expression.endOffset
|
||||
@@ -44,6 +51,9 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
|
||||
type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end)
|
||||
else -> expression // TODO support for arrays
|
||||
}
|
||||
is ExceptionState -> {
|
||||
IrErrorExpressionImpl(expression.startOffset, expression.endOffset, expression.type, "\n" + this.getFullDescription())
|
||||
}
|
||||
is Complex -> {
|
||||
val stateType = this.irClass.defaultType
|
||||
when {
|
||||
@@ -55,13 +65,17 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object from outer world to state
|
||||
*/
|
||||
internal fun Any?.toState(irType: IrType): State {
|
||||
return when (this) {
|
||||
is Proxy -> this.state
|
||||
is State -> this
|
||||
is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double, is Array<*>, is ByteArray,
|
||||
is CharArray, is ShortArray, is IntArray, is LongArray, is FloatArray, is DoubleArray, is BooleanArray -> Primitive(this, irType)
|
||||
null -> Primitive(this, irType)
|
||||
else -> Wrapper(this, irType.classOrNull!!.owner)
|
||||
else -> irType.classOrNull?.owner?.let { Wrapper(this, it) } ?: Wrapper(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +100,11 @@ fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffse
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> IrConst<T>.toPrimitive(): Primitive<T> {
|
||||
return Primitive(this.value, this.type)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun <T> IrConst<T>.toPrimitive(): Primitive<T> = when {
|
||||
type.isByte() -> Primitive((value as Number).toByte() as T, type)
|
||||
type.isShort() -> Primitive((value as Number).toShort() as T, type)
|
||||
else -> Primitive(value, type)
|
||||
}
|
||||
|
||||
fun IrAnnotationContainer?.hasAnnotation(annotation: FqName): Boolean {
|
||||
@@ -124,27 +141,6 @@ internal fun getPrimitiveClass(irType: IrType, asObject: Boolean = false): Class
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IrFunction.getArgsForMethodInvocation(args: List<Variable>): List<Any?> {
|
||||
val argsValues = args.map {
|
||||
when (val state = it.state) {
|
||||
is ExceptionState -> state.getThisAsCauseForException()
|
||||
is Wrapper -> state.value
|
||||
is Primitive<*> -> state.value
|
||||
else -> throw AssertionError("${state::class} is unsupported as argument for wrapper method invocation")
|
||||
}
|
||||
}.toMutableList()
|
||||
|
||||
// TODO if vararg isn't last parameter
|
||||
// must convert vararg array into separated elements for correct invoke
|
||||
if (this.valueParameters.lastOrNull()?.varargElementType != null) {
|
||||
val varargValue = argsValues.last()
|
||||
argsValues.removeAt(argsValues.size - 1)
|
||||
argsValues.addAll(varargValue as Array<out Any?>)
|
||||
}
|
||||
|
||||
return argsValues
|
||||
}
|
||||
|
||||
fun IrFunction.getLastOverridden(): IrFunction {
|
||||
if (this !is IrSimpleFunction) return this
|
||||
|
||||
@@ -168,53 +164,33 @@ internal fun List<Any?>.toPrimitiveStateArray(type: IrType): Primitive<*> {
|
||||
fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? {
|
||||
val varargType = this.symbol.owner.valueParameters[index].varargElementType ?: return null
|
||||
varargType.classOrNull?.let { return this.symbol.owner.valueParameters[index].type }
|
||||
val typeParameter = varargType.classifierOrFail.owner as IrTypeParameter
|
||||
return this.getTypeArgument(typeParameter.index)
|
||||
}
|
||||
|
||||
internal fun getTypeArguments(
|
||||
container: IrTypeParametersContainer, expression: IrFunctionAccessExpression, mapper: (IrTypeParameterSymbol) -> State
|
||||
): List<Variable> {
|
||||
fun IrType.getState(): State {
|
||||
return this.classOrNull?.owner?.let { Common(it) } ?: mapper(this.classifierOrFail as IrTypeParameterSymbol)
|
||||
val type = this.symbol.owner.valueParameters[index].type as? IrSimpleType ?: return null
|
||||
return type.buildSimpleType {
|
||||
val typeParameter = varargType.classifierOrFail.owner as IrTypeParameter
|
||||
arguments = listOf(makeTypeProjection(this@getVarargType.getTypeArgument(typeParameter.index)!!, Variance.OUT_VARIANCE))
|
||||
}
|
||||
|
||||
val typeArguments = container.typeParameters.mapIndexed { index, typeParameter ->
|
||||
val typeArgument = expression.getTypeArgument(index)!!
|
||||
Variable(typeParameter.symbol, typeArgument.getState())
|
||||
}.toMutableList()
|
||||
|
||||
if (container is IrSimpleFunction) {
|
||||
container.returnType.classifierOrFail.owner.safeAs<IrTypeParameter>()
|
||||
?.let { typeArguments.add(Variable(it.symbol, expression.type.getState())) }
|
||||
}
|
||||
|
||||
return typeArguments
|
||||
}
|
||||
|
||||
internal fun State?.extractNonLocalDeclarations(): List<Variable> {
|
||||
this ?: return listOf()
|
||||
val state = this.takeIf { it !is Complex } ?: (this as Complex).getOriginal()
|
||||
return state.fields.filter { it.symbol !is IrFieldSymbol }
|
||||
}
|
||||
|
||||
internal fun State?.getCorrectReceiverByFunction(irFunction: IrFunction): State? {
|
||||
if (this !is Complex) return this
|
||||
|
||||
val original: Complex? = this.getOriginal()
|
||||
val other = irFunction.parentClassOrNull?.thisReceiver ?: return this
|
||||
return generateSequence(original) { it.superClass }.firstOrNull { it.irClass.thisReceiver == other } ?: this
|
||||
return this.fields.filter { it.symbol !is IrFieldSymbol }
|
||||
}
|
||||
|
||||
internal fun IrFunction.getCapitalizedFileName() = this.file.name.replace(".kt", "Kt").capitalizeAsciiOnly()
|
||||
|
||||
internal fun IrType.isUnsigned() = this.isUByte() || this.isUShort() || this.isUInt() || this.isULong()
|
||||
internal fun IrType.isUnsignedArray(): Boolean {
|
||||
if (this !is IrSimpleType || classifier !is IrClassSymbol) return false
|
||||
val fqName = (classifier.owner as IrDeclarationWithName).fqNameWhenAvailable?.asString()
|
||||
return fqName in setOf("kotlin.UByteArray", "kotlin.UShortArray", "kotlin.UIntArray", "kotlin.ULongArray")
|
||||
}
|
||||
|
||||
internal fun IrType.isPrimitiveArray(): Boolean {
|
||||
return this.getClass()?.fqNameWhenAvailable?.toUnsafe()?.let { StandardNames.isPrimitiveArray(it) } ?: false
|
||||
}
|
||||
|
||||
internal fun IrType.isFunction() = this.getClass()?.fqNameWhenAvailable?.asString()?.startsWith("kotlin.Function") ?: false
|
||||
internal fun IrType.isKFunction() = this.getClass()?.fqNameWhenAvailable?.asString()?.startsWith("kotlin.reflect.KFunction") ?: false
|
||||
|
||||
internal fun IrType.isTypeParameter() = classifierOrNull is IrTypeParameterSymbol
|
||||
|
||||
@@ -222,6 +198,24 @@ internal fun IrType.isInterface() = classOrNull?.owner?.kind == ClassKind.INTERF
|
||||
|
||||
internal fun IrType.isThrowable() = this.getClass()?.fqNameWhenAvailable?.asString() == "kotlin.Throwable"
|
||||
|
||||
internal fun IrType.renderType(): String {
|
||||
var renderedType = this.render()
|
||||
do {
|
||||
val index = renderedType.indexOf(" of ")
|
||||
if (index == -1) break
|
||||
val replaceUntilComma = renderedType.indexOf(',', index)
|
||||
val replaceUntilTriangle = renderedType.indexOf('>', index)
|
||||
val replaceUntil = when {
|
||||
replaceUntilComma == -1 && replaceUntilTriangle == -1 -> renderedType.length
|
||||
replaceUntilComma == -1 -> replaceUntilTriangle
|
||||
replaceUntilTriangle == -1 -> replaceUntilComma
|
||||
else -> min(replaceUntilComma, replaceUntilTriangle)
|
||||
}
|
||||
renderedType = renderedType.replaceRange(index, replaceUntil, "")
|
||||
} while (true)
|
||||
return renderedType
|
||||
}
|
||||
|
||||
fun IrClass.internalName(): String {
|
||||
val internalName = StringBuilder(this.name.asString())
|
||||
generateSequence(this as? IrDeclarationParent) { (it as? IrDeclaration)?.parent }
|
||||
@@ -234,3 +228,63 @@ fun IrClass.internalName(): String {
|
||||
}
|
||||
return internalName.toString()
|
||||
}
|
||||
|
||||
internal inline fun withExceptionHandler(environment: IrInterpreterEnvironment, block: () -> Unit) {
|
||||
try {
|
||||
block()
|
||||
// check if during proxy interpretation was an exception
|
||||
val possibleException = environment.callStack.peekState() as? ExceptionState
|
||||
if (possibleException != null) environment.callStack.dropFramesUntilTryCatch()
|
||||
} catch (e: Throwable) {
|
||||
e.handleUserException(environment)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Throwable.handleUserException(environment: IrInterpreterEnvironment) {
|
||||
val exceptionName = this::class.java.simpleName
|
||||
val irExceptionClass = environment.irExceptions.firstOrNull { it.name.asString() == exceptionName }
|
||||
?: environment.irBuiltIns.throwableClass.owner
|
||||
environment.callStack.pushState(ExceptionState(this, irExceptionClass, environment.callStack.getStackTrace()))
|
||||
environment.callStack.dropFramesUntilTryCatch()
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is analog of `checkcast` jvm bytecode operation. Throw exception whenever actual type is not a subtype of expected.
|
||||
*/
|
||||
internal fun IrFunction?.checkCast(environment: IrInterpreterEnvironment): Boolean {
|
||||
this ?: return true
|
||||
val actualType = this.returnType
|
||||
if (actualType.classifierOrNull !is IrTypeParameterSymbol) return true
|
||||
|
||||
// TODO expectedType can be missing for functions called as proxy
|
||||
val expectedType = (environment.callStack.getVariable(this.symbol).state as? KTypeState)?.irType ?: return true
|
||||
if (expectedType.classifierOrFail is IrTypeParameterSymbol) return true
|
||||
|
||||
val actualState = environment.callStack.peekState() ?: return true
|
||||
if (actualState is Primitive<*> && actualState.value == null) return true // this is handled in checkNullability
|
||||
|
||||
if (!actualState.isSubtypeOf(expectedType)) {
|
||||
val convertibleClassName = environment.callStack.popState().irClass.fqNameWhenAvailable
|
||||
ClassCastException("$convertibleClassName cannot be cast to ${expectedType.render()}").handleUserException(environment)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
internal fun IrFunction.getArgsForMethodInvocation(
|
||||
callInterceptor: CallInterceptor, methodType: MethodType, args: List<State>
|
||||
): List<Any?> {
|
||||
val argsValues = args
|
||||
.mapIndexed { index, state -> state.wrap(callInterceptor, methodType.parameterType(index)) }
|
||||
.toMutableList()
|
||||
|
||||
// TODO if vararg isn't last parameter
|
||||
// must convert vararg array into separated elements for correct invoke
|
||||
if (this.valueParameters.lastOrNull()?.varargElementType != null) {
|
||||
val varargValue = argsValues.last()
|
||||
argsValues.removeAt(argsValues.size - 1)
|
||||
argsValues.addAll(varargValue as Array<out Any?>)
|
||||
}
|
||||
|
||||
return argsValues
|
||||
}
|
||||
@@ -10,28 +10,3 @@ import org.jetbrains.kotlin.name.FqName
|
||||
val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation")
|
||||
val evaluateIntrinsicAnnotation = FqName("kotlin.EvaluateIntrinsic")
|
||||
val contractsDslAnnotation = FqName("kotlin.internal.ContractsDsl")
|
||||
|
||||
data class CompileTimeFunction(val methodName: String, val args: List<String>)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> unaryOperation(
|
||||
methodName: String, receiverType: String, function: (T) -> Any?
|
||||
): Pair<CompileTimeFunction, Function1<Any?, Any?>> {
|
||||
return CompileTimeFunction(methodName, listOf(receiverType)) to function as Function1<Any?, Any?>
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T, E> binaryOperation(
|
||||
methodName: String, receiverType: String, parameterType: String, function: (T, E) -> Any?
|
||||
): Pair<CompileTimeFunction, Function2<Any?, Any?, Any?>> {
|
||||
return CompileTimeFunction(methodName, listOfNotNull(receiverType, parameterType)) to function as Function2<Any?, Any?, Any?>
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T, E, R> ternaryOperation(
|
||||
methodName: String, receiverType: String, firstParameterType: String, secondParameterType: String, function: (T, E, R) -> Any?
|
||||
): Pair<CompileTimeFunction, Function3<Any?, Any?, Any?, Any?>> {
|
||||
return CompileTimeFunction(
|
||||
methodName, listOfNotNull(receiverType, firstParameterType, secondParameterType)
|
||||
) to function as Function3<Any?, Any?, Any?, Any?>
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.interpreter.checker
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.compileTimeAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.contractsDslAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.isPrimitiveArray
|
||||
import org.jetbrains.kotlin.ir.interpreter.isUnsigned
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.types.isArray
|
||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||
import org.jetbrains.kotlin.ir.types.isString
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
enum class EvaluationMode(protected val mustCheckBody: Boolean) {
|
||||
FULL(mustCheckBody = true) {
|
||||
private val visited = mutableMapOf<String, Boolean>()
|
||||
|
||||
override fun canEvaluateFunction(function: IrFunction, expression: IrCall?): Boolean {
|
||||
return true//function.isBuiltin() || isIrBuiltin() || isIntrinsic() || function.body != null
|
||||
}
|
||||
|
||||
private fun IrFunction.isBuiltin(): Boolean {
|
||||
val parent = this.parentClassOrNull ?: return false
|
||||
val parentType = parent.defaultType
|
||||
return parentType.let { it.isPrimitiveType() || it.isString() || it.isArray() || it.isPrimitiveArray() }
|
||||
}
|
||||
|
||||
private fun isIrBuiltin(): Boolean {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isIntrinsic(): Boolean {
|
||||
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
WITH_ANNOTATIONS(mustCheckBody = false) {
|
||||
override fun canEvaluateFunction(function: IrFunction, expression: IrCall?): Boolean {
|
||||
if (function.isCompileTimeProperty()) return true
|
||||
return function.isMarkedAsCompileTime() || function.origin == IrBuiltIns.BUILTIN_OPERATOR ||
|
||||
(function is IrSimpleFunction && function.isOperator && function.name.asString() == "invoke") ||
|
||||
(function is IrSimpleFunction && function.isFakeOverride && function.overriddenSymbols.any { canEvaluateFunction(it.owner) }) ||
|
||||
function.isCompileTimeTypeAlias()
|
||||
}
|
||||
|
||||
private fun IrDeclaration?.isCompileTimeProperty(): Boolean {
|
||||
val property = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: return false
|
||||
if (property.isConst) return true
|
||||
if (property.isMarkedAsCompileTime() || property.isCompileTimeTypeAlias()) return true
|
||||
|
||||
val backingField = property.backingField
|
||||
val backingFieldExpression = backingField?.initializer?.expression as? IrGetValue
|
||||
return backingFieldExpression?.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
}
|
||||
},
|
||||
|
||||
ONLY_BUILTINS(mustCheckBody = false) {
|
||||
override fun canEvaluateFunction(function: IrFunction, expression: IrCall?): Boolean {
|
||||
if ((function as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.isConst == true) return true
|
||||
|
||||
val parent = function.parentClassOrNull ?: return false
|
||||
val parentType = parent.defaultType
|
||||
return when {
|
||||
parentType.isPrimitiveType() -> function.name.asString() !in setOf("inc", "dec", "rangeTo", "hashCode")
|
||||
parentType.isString() -> function.name.asString() !in setOf("subSequence", "hashCode")
|
||||
parentType.isAny() -> function.name.asString() == "toString" && expression?.dispatchReceiver !is IrGetObjectValue
|
||||
parent.isObject -> parent.parentClassOrNull?.defaultType?.let { it.isPrimitiveType() || it.isUnsigned() } == true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun canEvaluateFunction(function: IrFunction, expression: IrCall? = null): Boolean
|
||||
|
||||
fun canEvaluateBody(function: IrFunction): Boolean {
|
||||
return (mustCheckBody || function.isLocal) && !function.isContract() && !function.isMarkedAsEvaluateIntrinsic()
|
||||
}
|
||||
|
||||
protected val compileTimeTypeAliases = setOf(
|
||||
"java.lang.StringBuilder", "java.lang.IllegalArgumentException", "java.util.NoSuchElementException"
|
||||
)
|
||||
|
||||
fun IrDeclaration.isMarkedAsCompileTime() = isMarkedWith(compileTimeAnnotation)
|
||||
private fun IrDeclaration.isContract() = isMarkedWith(contractsDslAnnotation)
|
||||
private fun IrDeclaration.isMarkedAsEvaluateIntrinsic() = isMarkedWith(evaluateIntrinsicAnnotation)
|
||||
protected fun IrDeclaration.isCompileTimeTypeAlias() = this.parentClassOrNull?.fqNameWhenAvailable?.asString() in compileTimeTypeAliases
|
||||
|
||||
protected fun IrDeclaration.isMarkedWith(annotation: FqName): Boolean {
|
||||
if (this is IrClass && this.isCompanion) return false
|
||||
if (this.hasAnnotation(annotation)) return true
|
||||
return (this.parent as? IrClass)?.isMarkedWith(annotation) ?: false
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,8 @@
|
||||
* 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.interpreter
|
||||
package org.jetbrains.kotlin.ir.interpreter.checker
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.compileTimeAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.contractsDslAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -17,55 +14,11 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
enum class EvaluationMode {
|
||||
FULL, ONLY_BUILTINS
|
||||
}
|
||||
|
||||
class IrCompileTimeChecker(
|
||||
containingDeclaration: IrElement? = null, private val mode: EvaluationMode = EvaluationMode.FULL
|
||||
containingDeclaration: IrElement? = null, private val mode: EvaluationMode = EvaluationMode.WITH_ANNOTATIONS
|
||||
) : IrElementVisitor<Boolean, Nothing?> {
|
||||
private val visitedStack = mutableListOf<IrElement>().apply { if (containingDeclaration != null) add(containingDeclaration) }
|
||||
|
||||
private val compileTimeTypeAliases = setOf(
|
||||
"java.lang.StringBuilder", "java.lang.IllegalArgumentException", "java.util.NoSuchElementException"
|
||||
)
|
||||
|
||||
private fun IrDeclaration.isContract() = isMarkedWith(contractsDslAnnotation)
|
||||
private fun IrDeclaration.isMarkedAsEvaluateIntrinsic() = isMarkedWith(evaluateIntrinsicAnnotation)
|
||||
private fun IrDeclaration.isMarkedAsCompileTime(expression: IrCall? = null): Boolean {
|
||||
if (mode == EvaluationMode.FULL) {
|
||||
return isMarkedWith(compileTimeAnnotation) ||
|
||||
(this is IrSimpleFunction && this.isFakeOverride && this.overriddenSymbols.any { it.owner.isMarkedAsCompileTime() }) ||
|
||||
this.parentClassOrNull?.fqNameWhenAvailable?.asString() in compileTimeTypeAliases
|
||||
}
|
||||
|
||||
val parent = this.parentClassOrNull
|
||||
val parentType = parent?.defaultType
|
||||
return when {
|
||||
parentType?.isPrimitiveType() == true -> (this as IrFunction).name.asString() !in setOf("inc", "dec", "rangeTo", "hashCode")
|
||||
parentType?.isString() == true -> (this as IrDeclarationWithName).name.asString() !in setOf("subSequence", "hashCode")
|
||||
parentType?.isAny() == true -> (this as IrFunction).name.asString() == "toString" && expression?.dispatchReceiver !is IrGetObjectValue
|
||||
parent?.isObject == true -> parent.parentClassOrNull?.defaultType?.let { it.isPrimitiveType() || it.isUnsigned() } == true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrDeclaration.isMarkedWith(annotation: FqName): Boolean {
|
||||
if (this is IrClass && this.isCompanion) return false
|
||||
if (this.hasAnnotation(annotation)) return true
|
||||
return (this.parent as? IrClass)?.isMarkedWith(annotation) ?: false
|
||||
}
|
||||
|
||||
private fun IrProperty?.isCompileTime(): Boolean {
|
||||
if (this == null) return false
|
||||
if (this.isConst) return true
|
||||
if (this.isMarkedAsCompileTime()) return true
|
||||
|
||||
val backingField = this.backingField
|
||||
val backingFieldExpression = backingField?.initializer?.expression as? IrGetValue
|
||||
return backingFieldExpression?.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
}
|
||||
|
||||
private fun IrElement.asVisited(block: () -> Boolean): Boolean {
|
||||
visitedStack += this
|
||||
val result = block()
|
||||
@@ -82,26 +35,21 @@ class IrCompileTimeChecker(
|
||||
|
||||
private fun visitConstructor(expression: IrFunctionAccessExpression): Boolean {
|
||||
return when {
|
||||
expression.symbol.owner.isMarkedAsEvaluateIntrinsic() -> true
|
||||
!visitValueParameters(expression, null) -> false
|
||||
else -> expression.symbol.owner.isMarkedAsCompileTime()
|
||||
!visitValueParameters(expression, null) || !mode.canEvaluateFunction(expression.symbol.owner) -> false
|
||||
else -> if (mode.canEvaluateBody(expression.symbol.owner)) expression.symbol.owner.body?.accept(this, null) != false else true
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: Nothing?): Boolean {
|
||||
if (expression.symbol.owner.isContract()) return false
|
||||
val owner = expression.symbol.owner
|
||||
if (!mode.canEvaluateFunction(owner, expression)) return false
|
||||
|
||||
val property = (expression.symbol.owner as? IrSimpleFunction)?.correspondingPropertySymbol?.owner
|
||||
if (expression.symbol.owner.isMarkedAsCompileTime(expression) || property.isCompileTime()) {
|
||||
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, null) ?: true
|
||||
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, null) ?: true
|
||||
if (!visitValueParameters(expression, null)) return false
|
||||
val bodyComputable = if (expression.symbol.owner.isLocal) expression.symbol.owner.body?.accept(this, null) ?: true else true
|
||||
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, null) ?: true
|
||||
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, null) ?: true
|
||||
if (!visitValueParameters(expression, null)) return false
|
||||
val bodyComputable = owner.asVisited { if (mode.canEvaluateBody(owner)) owner.body?.accept(this, null) ?: true else true }
|
||||
|
||||
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
|
||||
}
|
||||
|
||||
return false
|
||||
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean {
|
||||
@@ -137,7 +85,7 @@ class IrCompileTimeChecker(
|
||||
}
|
||||
|
||||
override fun visitComposite(expression: IrComposite, data: Nothing?): Boolean {
|
||||
if (expression.origin == IrStatementOrigin.DESTRUCTURING_DECLARATION) {
|
||||
if (expression.origin == IrStatementOrigin.DESTRUCTURING_DECLARATION || expression.origin == null) {
|
||||
return visitStatements(expression.statements, data)
|
||||
}
|
||||
return false
|
||||
@@ -167,6 +115,17 @@ class IrCompileTimeChecker(
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean {
|
||||
// TODO fix later; used it here because java boolean resolves very strange,
|
||||
// its type is flexible (so its not primitive) and there is no initializer at backing field
|
||||
val fqName = expression.symbol.owner.fqNameForIrSerialization
|
||||
if (fqName.toString().let { it == "java.lang.Boolean.FALSE" || it == "java.lang.Boolean.TRUE" }) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (expression.receiver == null)
|
||||
return expression.symbol.owner.correspondingPropertySymbol?.owner?.let { it.isConst || it.backingField?.initializer?.expression is IrConst<*> } == true
|
||||
|
||||
val property = expression.symbol.owner.correspondingPropertySymbol?.owner
|
||||
val owner = expression.symbol.owner
|
||||
if (owner.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && owner.correspondingPropertySymbol?.owner?.isConst == true) {
|
||||
val receiverComputable = expression.receiver?.accept(this, null) ?: true
|
||||
@@ -175,35 +134,65 @@ class IrCompileTimeChecker(
|
||||
return true
|
||||
}
|
||||
}
|
||||
val parent = owner.parent as IrSymbolOwner
|
||||
|
||||
val parent = owner.parent as IrDeclarationContainer
|
||||
val getter = parent.declarations.filterIsInstance<IrProperty>().single { it == property }.getter
|
||||
val isJavaPrimitiveStatic = owner.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && owner.isStatic &&
|
||||
(owner.type.isPrimitiveType() || owner.type.isStringClassType())
|
||||
return visitedStack.contains(parent) || isJavaPrimitiveStatic
|
||||
return getter?.let { visitedStack.contains(it) } == true || isJavaPrimitiveStatic
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField, data: Nothing?): Boolean {
|
||||
if (expression.receiver.let { it == null || (it.type.classifierOrNull?.owner as? IrClass)?.isObject == true }) {
|
||||
return false
|
||||
}
|
||||
//todo check receiver?
|
||||
val parent = expression.symbol.owner.parent as IrSymbolOwner
|
||||
return visitedStack.contains(parent) && expression.value.accept(this, data)
|
||||
val property = expression.symbol.owner.correspondingPropertySymbol?.owner
|
||||
val parent = expression.symbol.owner.parent as IrDeclarationContainer
|
||||
val setter = parent.declarations.filterIsInstance<IrProperty>().single { it == property }.setter ?: return false
|
||||
return visitedStack.contains(setter) && expression.value.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall, data: Nothing?): Boolean {
|
||||
return visitConstructor(expression)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): Boolean {
|
||||
if (expression.symbol.owner.returnType.isAny()) return true
|
||||
return visitConstructor(expression)
|
||||
}
|
||||
|
||||
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): Boolean {
|
||||
return visitConstructor(expression)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean {
|
||||
return expression.asVisited {
|
||||
expression.symbol.owner.isMarkedAsCompileTime() && expression.symbol.owner.body?.accept(this, data) == true
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: Nothing?): Boolean {
|
||||
val irClass = expression.classSymbol.owner
|
||||
val classProperties = irClass.declarations.filterIsInstance<IrProperty>()
|
||||
val anonymousInitializer = irClass.declarations.filterIsInstance<IrAnonymousInitializer>().filter { !it.isStatic }
|
||||
|
||||
|
||||
return anonymousInitializer.all { init -> init.body.accept(this, data) } && classProperties.all {
|
||||
val propertyInitializer = it.backingField?.initializer?.expression
|
||||
if ((propertyInitializer as? IrGetValue)?.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER) return@all true
|
||||
return@all (propertyInitializer?.accept(this, data) != false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean {
|
||||
val owner = expression.symbol.owner
|
||||
if (!mode.canEvaluateFunction(owner)) return false
|
||||
|
||||
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, null) ?: true
|
||||
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, null) ?: true
|
||||
val bodyComputable = owner.asVisited { if (mode.canEvaluateBody(owner)) owner.body?.accept(this, null) ?: true else true }
|
||||
|
||||
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
|
||||
}
|
||||
|
||||
override fun visitFunctionExpression(expression: IrFunctionExpression, data: Nothing?): Boolean {
|
||||
val isLambda = expression.origin == IrStatementOrigin.LAMBDA || expression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION
|
||||
val isCompileTime = expression.function.isMarkedAsCompileTime()
|
||||
val isCompileTime = mode.canEvaluateFunction(expression.function)
|
||||
return expression.function.asVisited {
|
||||
if (isLambda || isCompileTime) expression.function.body?.accept(this, data) == true else false
|
||||
}
|
||||
@@ -263,4 +252,18 @@ class IrCompileTimeChecker(
|
||||
override fun visitThrow(expression: IrThrow, data: Nothing?): Boolean {
|
||||
return expression.value.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitPropertyReference(expression: IrPropertyReference, data: Nothing?): Boolean {
|
||||
return mode.canEvaluateFunction(expression.getter!!.owner)
|
||||
}
|
||||
|
||||
override fun visitClassReference(expression: IrClassReference, data: Nothing?): Boolean {
|
||||
return with(mode) {
|
||||
when (this) {
|
||||
EvaluationMode.FULL -> true
|
||||
EvaluationMode.WITH_ANNOTATIONS -> (expression.symbol.owner as IrClass).isMarkedAsCompileTime()
|
||||
EvaluationMode.ONLY_BUILTINS -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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.interpreter.exceptions
|
||||
|
||||
open class InterpreterError(override val message: String) : InterpreterException()
|
||||
|
||||
class InterpreterMethodNotFoundError(override val message: String) : InterpreterError(message)
|
||||
|
||||
class InterpreterTimeOutError : InterpreterError("Exceeded execution limit of constexpr expression")
|
||||
|
||||
class InterpreterEmptyReturnStackError : InterpreterError("Return values stack is empty")
|
||||
@@ -5,5 +5,4 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.exceptions
|
||||
|
||||
open class InterpreterException(override val message: String) : Exception(message) {
|
||||
}
|
||||
abstract class InterpreterException : Exception()
|
||||
@@ -1,9 +0,0 @@
|
||||
/*
|
||||
* 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.interpreter.exceptions
|
||||
|
||||
class InterpreterMethodNotFoundException(override val message: String) : InterpreterException(message) {
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* 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.interpreter.exceptions
|
||||
|
||||
class InterpreterTimeOutException : InterpreterException("Exceeded execution limit of constexpr expression") {
|
||||
|
||||
}
|
||||
@@ -5,25 +5,25 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.ExecutionResult
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterMethodNotFoundException
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Stack
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.Instruction
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterMethodNotFoundError
|
||||
|
||||
internal class IntrinsicEvaluator {
|
||||
fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
internal object IntrinsicEvaluator {
|
||||
fun unwindInstructions(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return when {
|
||||
EmptyArray.equalTo(irFunction) -> EmptyArray.evaluate(irFunction, stack, interpret)
|
||||
ArrayOf.equalTo(irFunction) -> ArrayOf.evaluate(irFunction, stack, interpret)
|
||||
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.evaluate(irFunction, stack, interpret)
|
||||
EnumValues.equalTo(irFunction) -> EnumValues.evaluate(irFunction, stack, interpret)
|
||||
EnumValueOf.equalTo(irFunction) -> EnumValueOf.evaluate(irFunction, stack, interpret)
|
||||
RegexReplace.equalTo(irFunction) -> RegexReplace.evaluate(irFunction, stack, interpret)
|
||||
EnumHashCode.equalTo(irFunction) -> EnumHashCode.evaluate(irFunction, stack, interpret)
|
||||
JsPrimitives.equalTo(irFunction) -> JsPrimitives.evaluate(irFunction, stack, interpret)
|
||||
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.evaluate(irFunction, stack, interpret)
|
||||
else -> throw InterpreterMethodNotFoundException("Method ${irFunction.name} hasn't implemented")
|
||||
EmptyArray.equalTo(irFunction) -> EmptyArray.unwind(irFunction, environment)
|
||||
ArrayOf.equalTo(irFunction) -> ArrayOf.unwind(irFunction, environment)
|
||||
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.unwind(irFunction, environment)
|
||||
EnumValues.equalTo(irFunction) -> EnumValues.unwind(irFunction, environment)
|
||||
EnumValueOf.equalTo(irFunction) -> EnumValueOf.unwind(irFunction, environment)
|
||||
EnumHashCode.equalTo(irFunction) -> EnumHashCode.unwind(irFunction, environment)
|
||||
JsPrimitives.equalTo(irFunction) -> JsPrimitives.unwind(irFunction, environment)
|
||||
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.unwind(irFunction, environment)
|
||||
SourceLocation.equalTo(irFunction) -> SourceLocation.unwind(irFunction, environment)
|
||||
AssertIntrinsic.equalTo(irFunction) -> AssertIntrinsic.unwind(irFunction, environment)
|
||||
else -> throw InterpreterMethodNotFoundError("Method ${irFunction.name} hasn't implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,20 +5,36 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Stack
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.isArray
|
||||
import org.jetbrains.kotlin.ir.types.isCharArray
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
internal sealed class IntrinsicBase {
|
||||
abstract fun equalTo(irFunction: IrFunction): Boolean
|
||||
abstract fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult
|
||||
abstract fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment)
|
||||
abstract fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction>
|
||||
|
||||
fun customEvaluateInstruction(irFunction: IrFunction, environment: IrInterpreterEnvironment): CustomInstruction {
|
||||
return CustomInstruction {
|
||||
evaluate(irFunction, environment)
|
||||
environment.callStack.dropFrameAndCopyResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object EmptyArray : IntrinsicBase() {
|
||||
@@ -27,10 +43,13 @@ internal object EmptyArray : IntrinsicBase() {
|
||||
return fqName in setOf("kotlin.emptyArray", "kotlin.ArrayIntrinsicsKt.emptyArray")
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val typeArguments = irFunction.typeParameters.map { stack.getVariable(it.symbol) }
|
||||
stack.pushReturnValue(emptyArray<Any?>().toState(irFunction.returnType).apply { addTypeArguments(typeArguments) })
|
||||
return Next
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val returnType = environment.callStack.getVariable(irFunction.symbol).state as KTypeState
|
||||
environment.callStack.pushState(emptyArray<Any?>().toState(returnType.irType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,11 +59,14 @@ internal object ArrayOf : IntrinsicBase() {
|
||||
return fqName == "kotlin.arrayOf"
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val array = irFunction.getArgsForMethodInvocation(stack.getAll()).toTypedArray()
|
||||
val typeArguments = irFunction.typeParameters.map { stack.getVariable(it.symbol) }
|
||||
stack.pushReturnValue(array.toState(irFunction.returnType).apply { addTypeArguments(typeArguments) })
|
||||
return Next
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val elementsSymbol = irFunction.valueParameters.single().symbol
|
||||
val varargVariable = environment.callStack.getVariable(elementsSymbol).state
|
||||
environment.callStack.pushState(varargVariable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,12 +76,19 @@ internal object ArrayOfNulls : IntrinsicBase() {
|
||||
return fqName == "kotlin.arrayOfNulls"
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val size = stack.getVariable(irFunction.valueParameters.first().symbol).state.asInt()
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val size = environment.callStack.getVariable(irFunction.valueParameters.first().symbol).state.asInt()
|
||||
val array = arrayOfNulls<Any?>(size)
|
||||
val typeArguments = irFunction.typeParameters.map { stack.getVariable(it.symbol) }
|
||||
stack.pushReturnValue(array.toState(irFunction.returnType).apply { addTypeArguments(typeArguments) })
|
||||
return Next
|
||||
val typeArgument = irFunction.typeParameters.map { environment.callStack.getVariable(it.symbol) }.single().state as KTypeState
|
||||
val returnType = (irFunction.returnType as IrSimpleType).buildSimpleType {
|
||||
arguments = listOf(makeTypeProjection(typeArgument.irType, Variance.INVARIANT))
|
||||
}
|
||||
|
||||
environment.callStack.pushState(array.toState(returnType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,16 +98,28 @@ internal object EnumValues : IntrinsicBase() {
|
||||
return (fqName == "kotlin.enumValues" || fqName.endsWith(".values")) && irFunction.valueParameters.isEmpty()
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val enumClass = when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.enumValues" -> stack.getVariable(irFunction.typeParameters.first().symbol).state.irClass
|
||||
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
||||
return when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.enumValues" -> {
|
||||
val kType = environment.callStack.getVariable(irFunction.typeParameters.first().symbol).state as KTypeState
|
||||
kType.irType.classOrNull!!.owner
|
||||
}
|
||||
else -> irFunction.parent as IrClass
|
||||
}
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
val enumClass = getEnumClass(irFunction, environment)
|
||||
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||
.map { entry -> entry.interpret().check { return it }.let { stack.popReturnValue() as Common } }
|
||||
stack.pushReturnValue(enumEntries.toTypedArray().toState(irFunction.returnType))
|
||||
return Next
|
||||
|
||||
return listOf(customEvaluateInstruction(irFunction, environment)) + enumEntries.reversed().map { CompoundInstruction(it) }
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val enumClass = getEnumClass(irFunction, environment)
|
||||
|
||||
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>().map { environment.mapOfEnums[it.symbol] }
|
||||
environment.callStack.pushState(enumEntries.toTypedArray().toState(irFunction.returnType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,39 +129,34 @@ internal object EnumValueOf : IntrinsicBase() {
|
||||
return (fqName == "kotlin.enumValueOf" || fqName.endsWith(".valueOf")) && irFunction.valueParameters.size == 1
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val enumClass = when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.enumValueOf" -> stack.getVariable(irFunction.typeParameters.first().symbol).state.irClass
|
||||
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
||||
return when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.enumValueOf" -> {
|
||||
val kType = environment.callStack.getVariable(irFunction.typeParameters.first().symbol).state as KTypeState
|
||||
kType.irType.classOrNull!!.owner
|
||||
}
|
||||
else -> irFunction.parent as IrClass
|
||||
}
|
||||
val enumEntryName = stack.getVariable(irFunction.valueParameters.first().symbol).state.asString()
|
||||
}
|
||||
|
||||
private fun getEnumEntryByName(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrEnumEntry? {
|
||||
val enumClass = getEnumClass(irFunction, environment)
|
||||
val enumEntryName = environment.callStack.getVariable(irFunction.valueParameters.first().symbol).state.asString()
|
||||
val enumEntry = enumClass.declarations.filterIsInstance<IrEnumEntry>().singleOrNull { it.name.asString() == enumEntryName }
|
||||
enumEntry?.interpret()?.check { return it }
|
||||
?: throw IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName")
|
||||
|
||||
return Next
|
||||
}
|
||||
}
|
||||
|
||||
internal object RegexReplace : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return fqName == "kotlin.text.Regex.replace" && irFunction.valueParameters.size == 2
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val states = stack.getAll().map { it.state }
|
||||
val regex = states.filterIsInstance<Wrapper>().single().value as Regex
|
||||
val input = states.filterIsInstance<Primitive<*>>().single().asString()
|
||||
val transform = states.filterIsInstance<Lambda>().single().irFunction
|
||||
val matchResultParameter = transform.valueParameters.single()
|
||||
val result = regex.replace(input) {
|
||||
val itAsState = Variable(matchResultParameter.symbol, Wrapper(it, matchResultParameter.type.classOrNull!!.owner))
|
||||
stack.newFrame(initPool = listOf(itAsState)) { transform.interpret() }//.check { return it }
|
||||
stack.popReturnValue().asString()
|
||||
if (enumEntry == null) {
|
||||
IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName").handleUserException(environment)
|
||||
}
|
||||
stack.pushReturnValue(result.toState(irFunction.returnType))
|
||||
return Next
|
||||
return enumEntry
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
val enumEntry = getEnumEntryByName(irFunction, environment) ?: return emptyList()
|
||||
return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(enumEntry))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val enumEntry = getEnumEntryByName(irFunction, environment)!!
|
||||
environment.callStack.pushState(environment.mapOfEnums[enumEntry.symbol]!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,10 +166,13 @@ internal object EnumHashCode : IntrinsicBase() {
|
||||
return fqName == "kotlin.Enum.hashCode"
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val hashCode = stack.getAll().single().state.hashCode()
|
||||
stack.pushReturnValue(hashCode.toState(irFunction.returnType))
|
||||
return Next
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val hashCode = environment.callStack.getVariable(irFunction.dispatchReceiverParameter!!.symbol).state.hashCode()
|
||||
environment.callStack.pushState(hashCode.toState(irFunction.returnType))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,19 +182,22 @@ internal object JsPrimitives : IntrinsicBase() {
|
||||
return fqName == "kotlin.Long.<init>" || fqName == "kotlin.Char.<init>"
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.Long.<init>" -> {
|
||||
val low = stack.getVariable(irFunction.valueParameters[0].symbol).state.asInt()
|
||||
val high = stack.getVariable(irFunction.valueParameters[1].symbol).state.asInt()
|
||||
stack.pushReturnValue((high.toLong().shl(32) + low).toState(irFunction.returnType))
|
||||
val low = environment.callStack.getVariable(irFunction.valueParameters[0].symbol).state.asInt()
|
||||
val high = environment.callStack.getVariable(irFunction.valueParameters[1].symbol).state.asInt()
|
||||
environment.callStack.pushState((high.toLong().shl(32) + low).toState(irFunction.returnType))
|
||||
}
|
||||
"kotlin.Char.<init>" -> {
|
||||
val value = stack.getVariable(irFunction.valueParameters[0].symbol).state.asInt()
|
||||
stack.pushReturnValue(value.toChar().toState(irFunction.returnType))
|
||||
val value = environment.callStack.getVariable(irFunction.valueParameters[0].symbol).state.asInt()
|
||||
environment.callStack.pushState(value.toChar().toState(irFunction.returnType))
|
||||
}
|
||||
}
|
||||
return Next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,28 +207,87 @@ internal object ArrayConstructor : IntrinsicBase() {
|
||||
return fqName.matches("kotlin\\.(Byte|Char|Short|Int|Long|Float|Double|Boolean|)Array\\.<init>".toRegex())
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
val instructions = mutableListOf<Instruction>(customEvaluateInstruction(irFunction, environment))
|
||||
|
||||
val sizeDescriptor = irFunction.valueParameters[0].symbol
|
||||
val size = stack.getVariable(sizeDescriptor).state.asInt()
|
||||
val arrayValue = MutableList<Any>(size) { 0 }
|
||||
val size = environment.callStack.getVariable(sizeDescriptor).state.asInt()
|
||||
|
||||
val initDescriptor = irFunction.valueParameters[1].symbol
|
||||
val initLambda = environment.callStack.getVariable(initDescriptor).state as KFunctionState
|
||||
environment.callStack.loadUpValues(initLambda)
|
||||
val function = initLambda.irFunction as IrSimpleFunction
|
||||
val index = initLambda.irFunction.valueParameters.single()
|
||||
for (i in 0 until size) {
|
||||
val call = IrCallImpl.fromSymbolOwner(0, 0, function.returnType, function.symbol)
|
||||
call.putValueArgument(0, IrConstImpl.int(0, 0, index.type, i))
|
||||
instructions += CompoundInstruction(call)
|
||||
}
|
||||
|
||||
return instructions
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val sizeDescriptor = irFunction.valueParameters[0].symbol
|
||||
val size = environment.callStack.getVariable(sizeDescriptor).state.asInt()
|
||||
val arrayValue = MutableList<Any?>(size) { if (irFunction.returnType.isCharArray()) 0.toChar() else 0 }
|
||||
|
||||
if (irFunction.valueParameters.size == 2) {
|
||||
val initDescriptor = irFunction.valueParameters[1].symbol
|
||||
val initLambda = stack.getVariable(initDescriptor).state as Lambda
|
||||
val index = initLambda.irFunction.valueParameters.single()
|
||||
val nonLocalDeclarations = initLambda.extractNonLocalDeclarations()
|
||||
for (i in 0 until size) {
|
||||
val indexVar = listOf(Variable(index.symbol, i.toState(index.type)))
|
||||
// TODO throw exception if label != RETURN
|
||||
stack.newFrame(
|
||||
asSubFrame = initLambda.irFunction.isLocal || initLambda.irFunction.isInline,
|
||||
initPool = nonLocalDeclarations + indexVar
|
||||
) { initLambda.irFunction.body!!.interpret() }.check(ReturnLabel.RETURN) { return it }
|
||||
arrayValue[i] = stack.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }
|
||||
arrayValue[i] = environment.callStack.popState().let {
|
||||
// TODO wrap
|
||||
when (it) {
|
||||
is Wrapper -> it.value
|
||||
is Primitive<*> -> if (it.type.isArray() || it.type.isPrimitiveArray()) it else it.value
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack.pushReturnValue(arrayValue.toPrimitiveStateArray(irFunction.parentAsClass.defaultType))
|
||||
return Next
|
||||
val type = environment.callStack.getVariable(irFunction.symbol).state as KTypeState
|
||||
environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type.irType))
|
||||
}
|
||||
}
|
||||
|
||||
internal object SourceLocation : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return fqName == "kotlin.experimental.sourceLocation" || fqName == "kotlin.experimental.SourceLocationKt.sourceLocation"
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
environment.callStack.pushState(environment.callStack.getFileAndPositionInfo().toState(irFunction.returnType))
|
||||
}
|
||||
}
|
||||
|
||||
internal object AssertIntrinsic : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return fqName == "kotlin.PreconditionsKt.assert"
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
|
||||
val messageLambda = environment.callStack.getVariable(irFunction.valueParameters.last().symbol).state as KFunctionState
|
||||
val function = messageLambda.irFunction as IrSimpleFunction
|
||||
val call = IrCallImpl.fromSymbolOwner(0, 0, function.returnType, function.symbol)
|
||||
|
||||
return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(call))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val value = environment.callStack.getVariable(irFunction.valueParameters.first().symbol).state.asBoolean()
|
||||
if (value) return
|
||||
when (irFunction.valueParameters.size) {
|
||||
1 -> AssertionError("Assertion failed").handleUserException(environment)
|
||||
2 -> AssertionError(environment.callStack.popState().asString()).handleUserException(environment)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.interpreter.proxy
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.getDispatchReceiver
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.Common
|
||||
import org.jetbrains.kotlin.ir.interpreter.toState
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverriddenFromAny
|
||||
|
||||
/**
|
||||
* calledFromBuiltIns - used to avoid cyclic calls. For example:
|
||||
* override fun toString(): String {
|
||||
* return super.toString()
|
||||
* }
|
||||
*/
|
||||
internal class CommonProxy private constructor(
|
||||
override val state: Common, override val callInterceptor: CallInterceptor, private val calledFromBuiltIns: Boolean = false
|
||||
) : Proxy {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Proxy) return false
|
||||
|
||||
val valueArguments = mutableListOf<Variable>()
|
||||
val equalsFun = state.getEqualsFunction()
|
||||
if (equalsFun.isFakeOverriddenFromAny() || calledFromBuiltIns) return this.state === other.state
|
||||
|
||||
equalsFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) }
|
||||
valueArguments.add(Variable(equalsFun.valueParameters.single().symbol, other.state))
|
||||
|
||||
return callInterceptor.interceptProxy(equalsFun, valueArguments) as Boolean
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
val valueArguments = mutableListOf<Variable>()
|
||||
val hashCodeFun = state.getHashCodeFunction()
|
||||
if (hashCodeFun.isFakeOverriddenFromAny() || calledFromBuiltIns) return System.identityHashCode(state)
|
||||
|
||||
hashCodeFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) }
|
||||
return callInterceptor.interceptProxy(hashCodeFun, valueArguments) as Int
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val valueArguments = mutableListOf<Variable>()
|
||||
val toStringFun = state.getToStringFunction()
|
||||
if (toStringFun.isFakeOverriddenFromAny() || calledFromBuiltIns) {
|
||||
return "${state.irClass.internalName()}@" + hashCode().toString(16).padStart(8, '0')
|
||||
}
|
||||
|
||||
toStringFun.getDispatchReceiver()!!.let { valueArguments.add(Variable(it, state)) }
|
||||
return callInterceptor.interceptProxy(toStringFun, valueArguments) as String
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun Common.asProxy(
|
||||
callInterceptor: CallInterceptor, extendFrom: Class<*>? = null, calledFromBuiltIns: Boolean = false
|
||||
): Any {
|
||||
val commonProxy = CommonProxy(this, callInterceptor, calledFromBuiltIns)
|
||||
|
||||
val interfaces = when (extendFrom) {
|
||||
null, Object::class.java -> arrayOf(Proxy::class.java)
|
||||
else -> arrayOf(extendFrom, Proxy::class.java)
|
||||
}
|
||||
return java.lang.reflect.Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), interfaces)
|
||||
{ /*proxy*/_, method, args ->
|
||||
when {
|
||||
method.declaringClass == Proxy::class.java && method.name == "getState" -> commonProxy.state
|
||||
method.declaringClass == Proxy::class.java && method.name == "getCallInterceptor" -> commonProxy.callInterceptor
|
||||
method.name == "equals" && method.parameterTypes.single().isObject() -> commonProxy.equals(args.single())
|
||||
method.name == "hashCode" && method.parameterTypes.isEmpty() -> commonProxy.hashCode()
|
||||
method.name == "toString" && method.parameterTypes.isEmpty() -> commonProxy.toString()
|
||||
else -> {
|
||||
val irFunction = commonProxy.state.getIrFunction(method)
|
||||
?: throw AssertionError("Cannot find method $method in ${commonProxy.state}")
|
||||
val valueArguments = mutableListOf<Variable>()
|
||||
valueArguments += Variable(irFunction.getDispatchReceiver()!!, commonProxy.state)
|
||||
valueArguments += irFunction.valueParameters
|
||||
.mapIndexed { index, parameter -> Variable(parameter.symbol, args[index].toState(parameter.type)) }
|
||||
callInterceptor.interceptProxy(irFunction, valueArguments, method.returnType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.interpreter.proxy
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.ReflectionProxy.Companion.asProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
|
||||
|
||||
internal interface Proxy {
|
||||
val state: State
|
||||
val callInterceptor: CallInterceptor
|
||||
|
||||
override fun equals(other: Any?): Boolean
|
||||
override fun hashCode(): Int
|
||||
override fun toString(): String
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare state object to be passed in outer world
|
||||
*/
|
||||
internal fun State.wrap(callInterceptor: CallInterceptor, extendFrom: Class<*>? = null, calledFromBuiltIns: Boolean = false): Any? {
|
||||
return when (this) {
|
||||
is ExceptionState -> this
|
||||
is Wrapper -> this.value
|
||||
is Primitive<*> -> this.value
|
||||
is Common -> this.asProxy(callInterceptor, extendFrom, calledFromBuiltIns)
|
||||
is ReflectionState -> this.asProxy(callInterceptor)
|
||||
else -> throw AssertionError("${this::class} is unsupported as argument for wrap function")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Class<*>.isObject(): Boolean {
|
||||
return this.name == "java.lang.Object"
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal abstract class AbstractKPropertyProxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : ReflectionProxy, KProperty<Any?> {
|
||||
protected val propertyType: IrType
|
||||
get() = state.property.getter!!.returnType
|
||||
|
||||
override val isAbstract: Boolean
|
||||
get() = state.property.modality == Modality.ABSTRACT
|
||||
override val isConst: Boolean
|
||||
get() = state.property.isConst
|
||||
override val isFinal: Boolean
|
||||
get() = state.property.modality == Modality.FINAL
|
||||
override val isLateinit: Boolean
|
||||
get() = state.property.isLateinit
|
||||
override val isOpen: Boolean
|
||||
get() = state.property.modality == Modality.OPEN
|
||||
override val isSuspend: Boolean
|
||||
get() = false
|
||||
override val name: String
|
||||
get() = state.property.name.asString()
|
||||
|
||||
override val annotations: List<Annotation>
|
||||
get() = TODO("not implemented")
|
||||
override val parameters: List<KParameter>
|
||||
get() = state.getParameters(callInterceptor)
|
||||
override val returnType: KType
|
||||
get() = state.getReturnType(callInterceptor)
|
||||
override val typeParameters: List<KTypeParameter>
|
||||
get() = listOf()
|
||||
override val visibility: KVisibility?
|
||||
get() = state.property.visibility.toKVisibility()
|
||||
|
||||
override fun call(vararg args: Any?): Any? = getter.call(*args)
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>): Any? = getter.callBy(args)
|
||||
|
||||
protected fun checkArguments(expected: Int, actual: Int) {
|
||||
if (expected != actual) {
|
||||
throw IllegalArgumentException("Callable expects $expected arguments, but $actual were provided.")
|
||||
}
|
||||
}
|
||||
|
||||
abstract inner class Getter(val getter: IrSimpleFunction) : KProperty.Getter<Any?> {
|
||||
override val property: KProperty<Any?> = this@AbstractKPropertyProxy
|
||||
|
||||
override val name: String = "<get-${this@AbstractKPropertyProxy.name.capitalize()}>"
|
||||
override val annotations: List<Annotation>
|
||||
get() = this@AbstractKPropertyProxy.annotations
|
||||
override val parameters: List<KParameter>
|
||||
get() = this@AbstractKPropertyProxy.parameters
|
||||
override val returnType: KType
|
||||
get() = this@AbstractKPropertyProxy.returnType
|
||||
override val typeParameters: List<KTypeParameter>
|
||||
get() = this@AbstractKPropertyProxy.typeParameters
|
||||
|
||||
override val isInline: Boolean = getter.isInline
|
||||
override val isExternal: Boolean = getter.isExternal
|
||||
override val isOperator: Boolean = getter.isOperator
|
||||
override val isInfix: Boolean = getter.isInfix
|
||||
override val isSuspend: Boolean = getter.isSuspend
|
||||
|
||||
override val visibility: KVisibility? = getter.visibility.toKVisibility()
|
||||
override val isFinal: Boolean = getter.modality == Modality.FINAL
|
||||
override val isOpen: Boolean = getter.modality == Modality.OPEN
|
||||
override val isAbstract: Boolean = getter.modality == Modality.ABSTRACT
|
||||
}
|
||||
|
||||
abstract inner class Setter(val setter: IrSimpleFunction) : KMutableProperty.Setter<Any?> {
|
||||
override val property: KProperty<Any?> = this@AbstractKPropertyProxy
|
||||
|
||||
override val name: String = "<set-${this@AbstractKPropertyProxy.name.capitalize()}>"
|
||||
override val annotations: List<Annotation>
|
||||
get() = this@AbstractKPropertyProxy.annotations
|
||||
override val parameters: List<KParameter>
|
||||
get() = this@AbstractKPropertyProxy.parameters
|
||||
override val returnType: KType
|
||||
get() = this@AbstractKPropertyProxy.returnType
|
||||
override val typeParameters: List<KTypeParameter>
|
||||
get() = this@AbstractKPropertyProxy.typeParameters
|
||||
|
||||
override val isInline: Boolean = setter.isInline
|
||||
override val isExternal: Boolean = setter.isExternal
|
||||
override val isOperator: Boolean = setter.isOperator
|
||||
override val isInfix: Boolean = setter.isInfix
|
||||
override val isSuspend: Boolean = setter.isSuspend
|
||||
|
||||
override val visibility: KVisibility? = setter.visibility.toKVisibility()
|
||||
override val isFinal: Boolean = setter.modality == Modality.FINAL
|
||||
override val isOpen: Boolean = setter.modality == Modality.OPEN
|
||||
override val isAbstract: Boolean = setter.modality == Modality.ABSTRACT
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is AbstractKPropertyProxy) return false
|
||||
return state == other.state
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return state.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return state.toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import kotlin.jvm.functions.FunctionN
|
||||
import kotlin.reflect.KCallable
|
||||
|
||||
// copied from core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionWithAllInvokes.kt
|
||||
// additionally added FunctionN
|
||||
internal interface FunctionWithAllInvokes :
|
||||
// (0..22).forEach { n -> println("Function$n<" + (0..n).joinToString { "Any?" } + ">,") }
|
||||
Function0<Any?>,
|
||||
Function1<Any?, Any?>,
|
||||
Function2<Any?, Any?, Any?>,
|
||||
Function3<Any?, Any?, Any?, Any?>,
|
||||
Function4<Any?, Any?, Any?, Any?, Any?>,
|
||||
Function5<Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function6<Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function7<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function8<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function9<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function10<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function11<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function12<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function13<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function14<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function15<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function16<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function17<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function18<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function19<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function20<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function21<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
Function22<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?>,
|
||||
KCallable<Any?>, FunctionN<Any?>
|
||||
{
|
||||
// (0..22).forEach { n -> println("override fun invoke(" + (1..n).joinToString { "p$it: Any?" } + "): Any? = call(" + (1..n).joinToString { "p$it" } + ")") }
|
||||
override fun invoke(): Any? = call()
|
||||
override fun invoke(p1: Any?): Any? = call(p1)
|
||||
override fun invoke(p1: Any?, p2: Any?): Any? = call(p1, p2)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?): Any? = call(p1, p2, p3)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?): Any? = call(p1, p2, p3, p4)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?): Any? = call(p1, p2, p3, p4, p5)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?): Any? = call(p1, p2, p3, p4, p5, p6)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?, p21: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21)
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?, p21: Any?, p22: Any?): Any? = call(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22)
|
||||
override fun invoke(vararg args: Any?): Any? = call(*args)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.internalName
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KClassState
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal class KClassProxy(
|
||||
override val state: KClassState, override val callInterceptor: CallInterceptor
|
||||
) : ReflectionProxy, KClass<Proxy> {
|
||||
override val simpleName: String?
|
||||
get() = state.classReference.name.takeIf { !it.isSpecial }?.asString()
|
||||
override val qualifiedName: String?
|
||||
get() = if (!state.classReference.name.isSpecial) state.classReference.internalName() else null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val constructors: Collection<KFunction<Proxy>>
|
||||
get() = state.getConstructors(callInterceptor) as Collection<KFunction<Proxy>>
|
||||
override val members: Collection<KCallable<*>>
|
||||
get() = state.getMembers(callInterceptor)
|
||||
override val nestedClasses: Collection<KClass<*>>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val objectInstance: Proxy?
|
||||
get() = TODO("Not yet implemented")
|
||||
override val typeParameters: List<KTypeParameter>
|
||||
get() = state.getTypeParameters(callInterceptor)
|
||||
override val supertypes: List<KType>
|
||||
get() = state.getSupertypes(callInterceptor)
|
||||
override val sealedSubclasses: List<KClass<out Proxy>>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val annotations: List<Annotation>
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val visibility: KVisibility?
|
||||
get() = state.classReference.visibility.toKVisibility()
|
||||
override val isFinal: Boolean
|
||||
get() = state.classReference.modality == Modality.FINAL
|
||||
override val isOpen: Boolean
|
||||
get() = state.classReference.modality == Modality.OPEN
|
||||
override val isAbstract: Boolean
|
||||
get() = state.classReference.modality == Modality.ABSTRACT
|
||||
override val isSealed: Boolean
|
||||
get() = state.classReference.modality == Modality.SEALED
|
||||
override val isData: Boolean
|
||||
get() = state.classReference.isData
|
||||
override val isInner: Boolean
|
||||
get() = state.classReference.isInner
|
||||
override val isCompanion: Boolean
|
||||
get() = state.classReference.isCompanion
|
||||
override val isFun: Boolean
|
||||
get() = state.classReference.isFun
|
||||
|
||||
override fun isInstance(value: Any?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is KClassProxy) return false
|
||||
|
||||
return state == other.state
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return state.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return state.toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
|
||||
import org.jetbrains.kotlin.ir.interpreter.toState
|
||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal class KFunctionProxy(
|
||||
override val state: KFunctionState, override val callInterceptor: CallInterceptor
|
||||
) : ReflectionProxy, KFunction<Any?>, FunctionWithAllInvokes {
|
||||
override val arity: Int = state.getArity() ?: BuiltInFunctionArity.BIG_ARITY
|
||||
|
||||
override val isInline: Boolean
|
||||
get() = state.irFunction.isInline
|
||||
override val isExternal: Boolean
|
||||
get() = state.irFunction.isExternal
|
||||
override val isOperator: Boolean
|
||||
get() = state.irFunction is IrSimpleFunction && state.irFunction.isOperator
|
||||
override val isInfix: Boolean
|
||||
get() = state.irFunction is IrSimpleFunction && state.irFunction.isInfix
|
||||
override val name: String
|
||||
get() = state.irFunction.name.asString()
|
||||
|
||||
|
||||
override val annotations: List<Annotation>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val parameters: List<KParameter>
|
||||
get() = state.getParameters(callInterceptor)
|
||||
override val returnType: KType
|
||||
get() = state.getReturnType(callInterceptor)
|
||||
override val typeParameters: List<KTypeParameter>
|
||||
get() = state.getTypeParameters(callInterceptor)
|
||||
|
||||
override fun call(vararg args: Any?): Any? {
|
||||
// TODO check arity
|
||||
var index = 0
|
||||
val dispatchReceiver = state.irFunction.dispatchReceiverParameter?.let { Variable(it.symbol, args[index++].toState(it.type)) }
|
||||
val extensionReceiver = state.irFunction.extensionReceiverParameter?.let { Variable(it.symbol, args[index++].toState(it.type)) }
|
||||
val valueArguments = listOfNotNull(dispatchReceiver, extensionReceiver) +
|
||||
state.irFunction.valueParameters.map { parameter -> Variable(parameter.symbol, args[index++].toState(parameter.type)) }
|
||||
return callInterceptor.interceptProxy(state.irFunction, valueArguments)
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override val visibility: KVisibility?
|
||||
get() = state.irFunction.visibility.toKVisibility()
|
||||
override val isFinal: Boolean
|
||||
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.FINAL
|
||||
override val isOpen: Boolean
|
||||
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.OPEN
|
||||
override val isAbstract: Boolean
|
||||
get() = state.irFunction is IrSimpleFunction && state.irFunction.modality == Modality.ABSTRACT
|
||||
override val isSuspend: Boolean
|
||||
get() = state.irFunction.isSuspend
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is ReflectionProxy) return false
|
||||
|
||||
return state == other.state
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return state.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return state.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KParameterState
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
|
||||
internal class KParameterProxy(override val state: KParameterState, override val callInterceptor: CallInterceptor) : ReflectionProxy, KParameter {
|
||||
override val index: Int
|
||||
get() = state.index
|
||||
override val name: String?
|
||||
get() = if (kind == KParameter.Kind.VALUE) state.irParameter.name.asString() else null
|
||||
override val type: KType
|
||||
get() = state.getType(callInterceptor)
|
||||
override val kind: KParameter.Kind
|
||||
get() = state.kind
|
||||
override val isOptional: Boolean
|
||||
get() = state.irParameter.defaultValue != null
|
||||
override val isVararg: Boolean
|
||||
get() = state.irParameter.varargElementType != null
|
||||
override val annotations: List<Annotation>
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is KParameterProxy) return false
|
||||
|
||||
return state == other.state
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = state.hashCode()
|
||||
|
||||
override fun toString(): String = state.toString()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
|
||||
import org.jetbrains.kotlin.ir.interpreter.toState
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal open class KProperty0Proxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : AbstractKPropertyProxy(state, callInterceptor), KProperty0<Any?> {
|
||||
override val getter: KProperty0.Getter<Any?>
|
||||
get() = object : Getter(state.property.getter!!), KProperty0.Getter<Any?> {
|
||||
override fun invoke(): Any? = call()
|
||||
|
||||
override fun call(vararg args: Any?): Any? {
|
||||
checkArguments(0, args.size)
|
||||
val actualPropertySymbol = state.property.resolveFakeOverride()?.symbol ?: state.property.symbol
|
||||
return state.dispatchReceiver!!.getState(actualPropertySymbol)!!
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(): Any? = getter.call()
|
||||
|
||||
override fun getDelegate(): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun invoke(): Any? = getter.call()
|
||||
}
|
||||
|
||||
internal class KMutableProperty0Proxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : KProperty0Proxy(state, callInterceptor), KMutableProperty0<Any?> {
|
||||
override val setter: KMutableProperty0.Setter<Any?> =
|
||||
object : Setter(state.property.setter!!), KMutableProperty0.Setter<Any?> {
|
||||
override fun invoke(p1: Any?) = call(p1)
|
||||
|
||||
override fun call(vararg args: Any?) {
|
||||
checkArguments(1, args.size)
|
||||
state.dispatchReceiver!!.setField(Variable(state.property.symbol, args.single().toState(propertyType)))
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun set(value: Any?) = setter.call(value)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
|
||||
import org.jetbrains.kotlin.ir.interpreter.toState
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal open class KProperty1Proxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : AbstractKPropertyProxy(state, callInterceptor), KProperty1<Any?, Any?> {
|
||||
override val getter: KProperty1.Getter<Any?, Any?>
|
||||
get() = object : Getter(state.property.getter!!), KProperty1.Getter<Any?, Any?> {
|
||||
override fun invoke(p1: Any?): Any? = call(p1)
|
||||
|
||||
override fun call(vararg args: Any?): Any? {
|
||||
checkArguments(1, args.size)
|
||||
val receiverParameter = getter.dispatchReceiverParameter ?: getter.extensionReceiverParameter
|
||||
val receiver = Variable(receiverParameter!!.symbol, args[0].toState(receiverParameter.type))
|
||||
return callInterceptor.interceptProxy(getter, listOf(receiver))
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(receiver: Any?): Any? = getter.call(receiver)
|
||||
|
||||
override fun getDelegate(receiver: Any?): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun invoke(p1: Any?): Any? = getter.call(p1)
|
||||
}
|
||||
|
||||
internal class KMutableProperty1Proxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : KProperty1Proxy(state, callInterceptor), KMutableProperty1<Any?, Any?> {
|
||||
override val setter: KMutableProperty1.Setter<Any?, Any?> =
|
||||
object : Setter(state.property.setter!!), KMutableProperty1.Setter<Any?, Any?> {
|
||||
override fun invoke(p1: Any?, p2: Any?) = call(p1, p2)
|
||||
|
||||
override fun call(vararg args: Any?) {
|
||||
checkArguments(2, args.size)
|
||||
val receiverParameter = setter.dispatchReceiverParameter ?: setter.extensionReceiverParameter
|
||||
val receiver = Variable(receiverParameter!!.symbol, args[0].toState(receiverParameter.type))
|
||||
val valueParameter = setter.valueParameters.single()
|
||||
val value = Variable(valueParameter.symbol, args[1].toState(valueParameter.type))
|
||||
callInterceptor.interceptProxy(setter, listOf(receiver, value))
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun set(receiver: Any?, value: Any?) = setter.call(receiver, value)
|
||||
}
|
||||
@@ -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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
|
||||
import org.jetbrains.kotlin.ir.interpreter.toState
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal open class KProperty2Proxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : AbstractKPropertyProxy(state, callInterceptor), KProperty2<Any?, Any?, Any?> {
|
||||
override val getter: KProperty2.Getter<Any?, Any?, Any?>
|
||||
get() = object : Getter(state.property.getter!!), KProperty2.Getter<Any?, Any?, Any?> {
|
||||
override fun invoke(p1: Any?, p2: Any?): Any? = call(p1, p2)
|
||||
|
||||
override fun call(vararg args: Any?): Any? {
|
||||
checkArguments(2, args.size)
|
||||
val dispatch = Variable(getter.dispatchReceiverParameter!!.symbol, args[0].toState(getter.dispatchReceiverParameter!!.type))
|
||||
val extension = Variable(getter.extensionReceiverParameter!!.symbol, args[1].toState(getter.extensionReceiverParameter!!.type))
|
||||
return callInterceptor.interceptProxy(getter, listOf(dispatch, extension))
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(receiver1: Any?, receiver2: Any?): Any? = getter.call(receiver1, receiver2)
|
||||
|
||||
override fun getDelegate(receiver1: Any?, receiver2: Any?): Any? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun invoke(p1: Any?, p2: Any?): Any? = getter.call(p1, p2)
|
||||
}
|
||||
|
||||
internal class KMutableProperty2Proxy(
|
||||
override val state: KPropertyState, override val callInterceptor: CallInterceptor
|
||||
) : KProperty2Proxy(state, callInterceptor), KMutableProperty2<Any?, Any?, Any?> {
|
||||
override val setter: KMutableProperty2.Setter<Any?, Any?, Any?>
|
||||
get() = object : Setter(state.property.setter!!), KMutableProperty2.Setter<Any?, Any?, Any?> {
|
||||
override fun invoke(p1: Any?, p2: Any?, p3: Any?) = call(p1, p2, p3)
|
||||
|
||||
override fun call(vararg args: Any?) {
|
||||
checkArguments(3, args.size)
|
||||
val receiver1 = args[0]
|
||||
val receiver2 = args[1]
|
||||
val value = args[2]
|
||||
TODO("Not yet implemented, receiver1 = $receiver1, receiver2 = $receiver2, value = $value")
|
||||
}
|
||||
|
||||
override fun callBy(args: Map<KParameter, Any?>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun set(receiver1: Any?, receiver2: Any?, value: Any?) = setter.call(receiver1, receiver2, value)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeParameterState
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal class KTypeParameterProxy(
|
||||
override val state: KTypeParameterState, override val callInterceptor: CallInterceptor
|
||||
) : ReflectionProxy, KTypeParameter {
|
||||
override val name: String
|
||||
get() = state.irTypeParameter.name.asString()
|
||||
override val upperBounds: List<KType>
|
||||
get() = state.getUpperBounds(callInterceptor)
|
||||
override val variance: KVariance
|
||||
get() = when (state.irTypeParameter.variance) {
|
||||
Variance.INVARIANT -> KVariance.INVARIANT
|
||||
Variance.IN_VARIANCE -> KVariance.IN
|
||||
Variance.OUT_VARIANCE -> KVariance.OUT
|
||||
}
|
||||
override val isReified: Boolean
|
||||
get() = state.irTypeParameter.isReified
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is KTypeParameterProxy) return false
|
||||
|
||||
return state == other.state
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = state.hashCode()
|
||||
|
||||
override fun toString(): String = state.toString()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
|
||||
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
||||
import kotlin.reflect.KClassifier
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.KTypeProjection
|
||||
|
||||
internal class KTypeProxy(override val state: KTypeState, override val callInterceptor: CallInterceptor) : ReflectionProxy, KType {
|
||||
override val classifier: KClassifier?
|
||||
get() = state.getClassifier(callInterceptor)
|
||||
override val arguments: List<KTypeProjection>
|
||||
get() = state.getArguments(callInterceptor)
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = state.irType.isMarkedNullable()
|
||||
override val annotations: List<Annotation>
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is KTypeProxy) return false
|
||||
|
||||
return state == other.state
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = state.hashCode()
|
||||
|
||||
override fun toString(): String = state.toString()
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.interpreter.proxy.reflection
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.reflection.*
|
||||
import kotlin.reflect.KVisibility
|
||||
|
||||
internal interface ReflectionProxy : Proxy {
|
||||
fun DescriptorVisibility.toKVisibility(): KVisibility? {
|
||||
return when (this) {
|
||||
DescriptorVisibilities.PUBLIC -> KVisibility.PUBLIC
|
||||
DescriptorVisibilities.PROTECTED -> KVisibility.PROTECTED
|
||||
DescriptorVisibilities.INTERNAL -> KVisibility.INTERNAL
|
||||
DescriptorVisibilities.PRIVATE -> KVisibility.PRIVATE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun ReflectionState.asProxy(callInterceptor: CallInterceptor): ReflectionProxy {
|
||||
return when (this) {
|
||||
is KPropertyState -> when {
|
||||
this.isKMutableProperty0() -> KMutableProperty0Proxy(this, callInterceptor)
|
||||
this.isKProperty0() -> KProperty0Proxy(this, callInterceptor)
|
||||
this.isKMutableProperty1() -> KMutableProperty1Proxy(this, callInterceptor)
|
||||
this.isKProperty1() -> KProperty1Proxy(this, callInterceptor)
|
||||
this.isKMutableProperty2() -> KMutableProperty2Proxy(this, callInterceptor)
|
||||
this.isKProperty2() -> KProperty2Proxy(this, callInterceptor)
|
||||
else -> TODO()
|
||||
}
|
||||
is KFunctionState -> KFunctionProxy(this, callInterceptor)
|
||||
is KClassState -> KClassProxy(this, callInterceptor)
|
||||
is KTypeState -> KTypeProxy(this, callInterceptor)
|
||||
is KTypeParameterState -> KTypeParameterProxy(this, callInterceptor)
|
||||
is KParameterState -> KParameterProxy(this, callInterceptor)
|
||||
else -> TODO("not supported reference state")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.interpreter.stack
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.CompoundInstruction
|
||||
import org.jetbrains.kotlin.ir.interpreter.Instruction
|
||||
import org.jetbrains.kotlin.ir.interpreter.SimpleInstruction
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||
|
||||
internal class CallStack {
|
||||
private val frames = mutableListOf<Frame>()
|
||||
private fun getCurrentFrame() = frames.last()
|
||||
internal fun getCurrentFrameOwner() = frames.last().currentSubFrameOwner
|
||||
|
||||
fun newFrame(frameOwner: IrElement, instructions: List<Instruction>, irFile: IrFile? = null) {
|
||||
val newFrame = SubFrame(instructions.toMutableList(), frameOwner)
|
||||
frames.add(Frame(newFrame, irFile))
|
||||
}
|
||||
|
||||
fun newFrame(frameOwner: IrFunction, instructions: List<Instruction>) {
|
||||
val newFrame = SubFrame(instructions.toMutableList(), frameOwner)
|
||||
frames.add(Frame(newFrame, frameOwner.fileOrNull))
|
||||
}
|
||||
|
||||
fun newSubFrame(frameOwner: IrElement, instructions: List<Instruction>) {
|
||||
val newFrame = SubFrame(instructions.toMutableList(), frameOwner)
|
||||
getCurrentFrame().addSubFrame(newFrame)
|
||||
}
|
||||
|
||||
fun dropFrame() {
|
||||
frames.removeLast()
|
||||
}
|
||||
|
||||
fun dropFrameAndCopyResult() {
|
||||
val result = peekState() ?: return dropFrame()
|
||||
popState()
|
||||
dropFrame()
|
||||
pushState(result)
|
||||
}
|
||||
|
||||
fun dropSubFrame() {
|
||||
getCurrentFrame().removeSubFrame()
|
||||
}
|
||||
|
||||
fun returnFromFrameWithResult(irReturn: IrReturn) {
|
||||
val result = popState()
|
||||
var frameOwner = getCurrentFrameOwner()
|
||||
while (frameOwner != irReturn.returnTargetSymbol.owner) {
|
||||
when (frameOwner) {
|
||||
is IrTry -> {
|
||||
dropSubFrame()
|
||||
pushState(result)
|
||||
addInstruction(SimpleInstruction(irReturn))
|
||||
addInstruction(CompoundInstruction(frameOwner.finallyExpression))
|
||||
return
|
||||
}
|
||||
is IrCatch -> {
|
||||
val tryBlock = getCurrentFrame().dropInstructions()!!.element as IrTry// last instruction in `catch` block is `try`
|
||||
dropSubFrame()
|
||||
pushState(result)
|
||||
addInstruction(SimpleInstruction(irReturn))
|
||||
addInstruction(CompoundInstruction(tryBlock.finallyExpression))
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
dropSubFrame()
|
||||
if (getCurrentFrame().hasNoSubFrames() && frameOwner != irReturn.returnTargetSymbol.owner) dropFrame()
|
||||
frameOwner = getCurrentFrameOwner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dropFrame()
|
||||
// check that last frame is not a function itself; use case for proxyInterpret
|
||||
if (frames.size == 0) newFrame(irReturn, emptyList()) // just stub frame
|
||||
pushState(result)
|
||||
}
|
||||
|
||||
fun unrollInstructionsForBreakContinue(breakOrContinue: IrBreakContinue) {
|
||||
var frameOwner = getCurrentFrameOwner()
|
||||
while (frameOwner != breakOrContinue.loop) {
|
||||
when (frameOwner) {
|
||||
is IrTry -> {
|
||||
addInstruction(CompoundInstruction(breakOrContinue))
|
||||
addInstruction(SimpleInstruction(frameOwner))
|
||||
return
|
||||
}
|
||||
is IrCatch -> {
|
||||
val tryInstruction = getCurrentFrame().dropInstructions()!! // last instruction in `catch` block is `try`
|
||||
addInstruction(CompoundInstruction(breakOrContinue))
|
||||
addInstruction(tryInstruction)
|
||||
return
|
||||
}
|
||||
else -> {
|
||||
getCurrentFrame().removeSubFrameWithoutDataPropagation()
|
||||
frameOwner = getCurrentFrameOwner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (breakOrContinue) {
|
||||
is IrBreak -> getCurrentFrame().removeSubFrameWithoutDataPropagation() // drop loop
|
||||
else -> addInstruction(CompoundInstruction(breakOrContinue.loop))
|
||||
}
|
||||
}
|
||||
|
||||
fun dropFramesUntilTryCatch() {
|
||||
val exception = popState()
|
||||
var frameOwner = getCurrentFrameOwner()
|
||||
while (frames.isNotEmpty()) {
|
||||
val frame = getCurrentFrame()
|
||||
while (!frame.hasNoSubFrames()) {
|
||||
frameOwner = frame.currentSubFrameOwner
|
||||
when (frameOwner) {
|
||||
is IrTry -> {
|
||||
dropSubFrame() // drop all instructions that left
|
||||
newSubFrame(frameOwner, listOf())
|
||||
addInstruction(SimpleInstruction(frameOwner)) // to evaluate finally at the end
|
||||
frameOwner.catches.reversed().forEach { addInstruction(CompoundInstruction(it)) }
|
||||
pushState(exception)
|
||||
return
|
||||
}
|
||||
is IrCatch -> {
|
||||
// in case of exception in catch, drop everything except of last `try` instruction
|
||||
addInstruction(frame.dropInstructions()!!)
|
||||
pushState(exception)
|
||||
return
|
||||
}
|
||||
else -> frame.removeSubFrameWithoutDataPropagation()
|
||||
}
|
||||
}
|
||||
dropFrame()
|
||||
}
|
||||
|
||||
if (frames.size == 0) newFrame(frameOwner, emptyList()) // just stub frame
|
||||
pushState(exception)
|
||||
}
|
||||
|
||||
fun hasNoInstructions() = frames.isEmpty() || (frames.size == 1 && frames.first().hasNoInstructions())
|
||||
|
||||
fun addInstruction(instruction: Instruction) {
|
||||
getCurrentFrame().addInstruction(instruction)
|
||||
}
|
||||
|
||||
fun popInstruction(): Instruction {
|
||||
return getCurrentFrame().popInstruction()
|
||||
}
|
||||
|
||||
fun pushState(state: State) {
|
||||
getCurrentFrame().pushState(state)
|
||||
}
|
||||
|
||||
fun popState(): State = getCurrentFrame().popState()
|
||||
fun peekState(): State? = getCurrentFrame().peekState()
|
||||
|
||||
fun addVariable(variable: Variable) {
|
||||
getCurrentFrame().addVariable(variable)
|
||||
}
|
||||
|
||||
fun getVariable(symbol: IrSymbol): Variable = getCurrentFrame().getVariable(symbol)
|
||||
|
||||
fun storeUpValues(state: StateWithClosure) {
|
||||
// TODO save only necessary declarations
|
||||
state.upValues.addAll(getCurrentFrame().getAll().toMutableList())
|
||||
}
|
||||
|
||||
fun loadUpValues(state: StateWithClosure) {
|
||||
state.upValues.forEach { addVariable(it) }
|
||||
}
|
||||
|
||||
fun copyUpValuesFromPreviousFrame() {
|
||||
frames[frames.size - 2].getAll().forEach { addVariable(it) }
|
||||
}
|
||||
|
||||
fun getStackTrace(): List<String> {
|
||||
return frames.map { it.toString() }.filter { it != Frame.NOT_DEFINED }
|
||||
}
|
||||
|
||||
fun getFileAndPositionInfo(): String {
|
||||
return frames[frames.size - 2].getFileAndPositionInfo()
|
||||
}
|
||||
|
||||
fun getStackCount(): Int = frames.size
|
||||
}
|
||||
@@ -1,79 +1,142 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2021 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.interpreter.stack
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.interpreter.Instruction
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
internal interface Frame {
|
||||
fun addVar(variable: Variable)
|
||||
fun addAll(variables: List<Variable>)
|
||||
fun getVariable(symbol: IrSymbol): Variable?
|
||||
fun getAll(): List<Variable>
|
||||
fun contains(symbol: IrSymbol): Boolean
|
||||
fun pushReturnValue(state: State)
|
||||
fun pushReturnValue(frame: Frame) // TODO rename to getReturnValueFrom
|
||||
fun peekReturnValue(): State
|
||||
fun popReturnValue(): State
|
||||
fun hasReturnValue(): Boolean
|
||||
internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
|
||||
private val innerStack = mutableListOf(subFrame)
|
||||
private var currentInstruction: Instruction? = null
|
||||
val currentSubFrameOwner: IrElement
|
||||
get() = getCurrentFrame().owner
|
||||
|
||||
companion object {
|
||||
const val NOT_DEFINED = "Not defined"
|
||||
}
|
||||
|
||||
private fun getCurrentFrame() = innerStack.last()
|
||||
|
||||
fun addSubFrame(frame: SubFrame) {
|
||||
innerStack.add(frame)
|
||||
}
|
||||
|
||||
fun removeSubFrame() {
|
||||
getCurrentFrame().peekState()?.let { if (innerStack.size > 1) innerStack[innerStack.size - 2].pushState(it) }
|
||||
removeSubFrameWithoutDataPropagation()
|
||||
}
|
||||
|
||||
fun removeSubFrameWithoutDataPropagation() {
|
||||
innerStack.removeLast()
|
||||
}
|
||||
|
||||
fun hasNoSubFrames() = innerStack.isEmpty()
|
||||
fun hasNoInstructions() = hasNoSubFrames() || (innerStack.size == 1 && innerStack.first().isEmpty())
|
||||
|
||||
fun addInstruction(instruction: Instruction) {
|
||||
getCurrentFrame().pushInstruction(instruction)
|
||||
}
|
||||
|
||||
fun popInstruction(): Instruction {
|
||||
return getCurrentFrame().popInstruction().apply { currentInstruction = this }
|
||||
}
|
||||
|
||||
fun dropInstructions() = getCurrentFrame().dropInstructions()
|
||||
|
||||
fun pushState(state: State) {
|
||||
getCurrentFrame().pushState(state)
|
||||
}
|
||||
|
||||
fun popState(): State = getCurrentFrame().popState()
|
||||
fun peekState(): State? = getCurrentFrame().peekState()
|
||||
|
||||
fun addVariable(variable: Variable) {
|
||||
getCurrentFrame().addVariable(variable)
|
||||
}
|
||||
|
||||
fun getVariable(symbol: IrSymbol): Variable {
|
||||
return innerStack.firstNotNullResult { it.getVariable(symbol) }
|
||||
?: throw InterpreterError("$symbol not found") // TODO better message
|
||||
}
|
||||
|
||||
fun getAll(): List<Variable> = innerStack.flatMap { it.getAll() }
|
||||
|
||||
private fun getLineNumberForCurrentInstruction(): String {
|
||||
irFile ?: return ""
|
||||
val frameOwner = currentInstruction?.element
|
||||
return when {
|
||||
frameOwner is IrExpression || (frameOwner is IrDeclaration && frameOwner.origin == IrDeclarationOrigin.DEFINED) ->
|
||||
":${irFile.fileEntry.getLineNumber(frameOwner.startOffset) + 1}"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getFileAndPositionInfo(): String {
|
||||
irFile ?: return NOT_DEFINED
|
||||
val lineNum = getLineNumberForCurrentInstruction()
|
||||
return "${irFile.name}$lineNum"
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
irFile ?: return NOT_DEFINED
|
||||
val fileNameCapitalized = irFile.name.replace(".kt", "Kt").capitalize()
|
||||
val entryPoint = innerStack.firstOrNull { it.owner is IrFunction }?.owner as? IrFunction
|
||||
val lineNum = getLineNumberForCurrentInstruction()
|
||||
|
||||
return "at $fileNameCapitalized.${entryPoint?.fqNameWhenAvailable ?: "<clinit>"}(${irFile.name}$lineNum)"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO replace exceptions with InterpreterException
|
||||
internal class InterpreterFrame(
|
||||
private val pool: MutableList<Variable> = mutableListOf(),
|
||||
private val typeArguments: List<Variable> = listOf()
|
||||
) : Frame {
|
||||
private val returnStack: MutableList<State> = mutableListOf()
|
||||
internal class SubFrame(private val instructions: MutableList<Instruction>, val owner: IrElement) {
|
||||
private val memory = mutableListOf<Variable>()
|
||||
private val dataStack = DataStack()
|
||||
|
||||
override fun addVar(variable: Variable) {
|
||||
pool.add(variable)
|
||||
fun isEmpty() = instructions.isEmpty()
|
||||
|
||||
fun pushInstruction(instruction: Instruction) {
|
||||
instructions.add(0, instruction)
|
||||
}
|
||||
|
||||
override fun addAll(variables: List<Variable>) {
|
||||
pool.addAll(variables)
|
||||
fun popInstruction(): Instruction {
|
||||
return instructions.removeFirst()
|
||||
}
|
||||
|
||||
override fun getVariable(symbol: IrSymbol): Variable? {
|
||||
return (if (symbol is IrTypeParameterSymbol) typeArguments else pool).firstOrNull { it.symbol == symbol }
|
||||
fun dropInstructions() = instructions.firstOrNull()?.apply { instructions.clear() }
|
||||
|
||||
fun pushState(state: State) {
|
||||
dataStack.push(state)
|
||||
}
|
||||
|
||||
override fun getAll(): List<Variable> {
|
||||
return pool
|
||||
fun popState(): State = dataStack.pop()
|
||||
fun peekState(): State? = if (!dataStack.isEmpty()) dataStack.peek() else null
|
||||
|
||||
fun addVariable(variable: Variable) {
|
||||
memory += variable
|
||||
}
|
||||
|
||||
override fun contains(symbol: IrSymbol): Boolean {
|
||||
return (typeArguments + pool).any { it.symbol == symbol }
|
||||
}
|
||||
|
||||
override fun pushReturnValue(state: State) {
|
||||
returnStack += state
|
||||
}
|
||||
|
||||
override fun pushReturnValue(frame: Frame) {
|
||||
if (frame.hasReturnValue()) this.pushReturnValue(frame.popReturnValue())
|
||||
}
|
||||
|
||||
override fun hasReturnValue(): Boolean {
|
||||
return returnStack.isNotEmpty()
|
||||
}
|
||||
|
||||
override fun peekReturnValue(): State {
|
||||
if (returnStack.isNotEmpty()) {
|
||||
return returnStack.last()
|
||||
}
|
||||
throw NoSuchElementException("Return values stack is empty")
|
||||
}
|
||||
|
||||
override fun popReturnValue(): State {
|
||||
if (returnStack.isNotEmpty()) {
|
||||
val item = returnStack.last()
|
||||
returnStack.removeAt(returnStack.size - 1)
|
||||
return item
|
||||
}
|
||||
throw NoSuchElementException("Return values stack is empty")
|
||||
}
|
||||
fun getVariable(symbol: IrSymbol): Variable? = memory.firstOrNull { it.symbol == symbol }
|
||||
fun getAll(): List<Variable> = memory
|
||||
}
|
||||
|
||||
private class DataStack {
|
||||
private val stack = mutableListOf<State>()
|
||||
|
||||
fun isEmpty() = stack.isEmpty()
|
||||
|
||||
fun push(state: State) {
|
||||
stack.add(state)
|
||||
}
|
||||
|
||||
fun pop(): State = stack.removeLast()
|
||||
fun peek(): State = stack.last()
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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.interpreter.stack
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.ExecutionResult
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterException
|
||||
import org.jetbrains.kotlin.ir.interpreter.getCapitalizedFileName
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.name
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.fileEntry
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
internal interface Stack {
|
||||
fun newFrame(asSubFrame: Boolean = false, initPool: List<Variable> = listOf(), block: () -> ExecutionResult): ExecutionResult
|
||||
|
||||
fun setCurrentFrameName(irFunction: IrFunction)
|
||||
fun getStackTrace(): List<String>
|
||||
|
||||
fun clean()
|
||||
fun addVar(variable: Variable)
|
||||
fun addAll(variables: List<Variable>)
|
||||
fun getVariable(symbol: IrSymbol): Variable
|
||||
fun getAll(): List<Variable>
|
||||
|
||||
fun contains(symbol: IrSymbol): Boolean
|
||||
fun hasReturnValue(): Boolean
|
||||
fun pushReturnValue(state: State)
|
||||
fun popReturnValue(): State
|
||||
fun peekReturnValue(): State
|
||||
}
|
||||
|
||||
internal class StackImpl : Stack {
|
||||
private val frameList = mutableListOf(FrameContainer()) // first frame is default, it is easier to work when last() is not null
|
||||
private fun getCurrentFrame() = frameList.last()
|
||||
|
||||
override fun newFrame(asSubFrame: Boolean, initPool: List<Variable>, block: () -> ExecutionResult): ExecutionResult {
|
||||
val typeArgumentsPool = initPool.filter { it.symbol is IrTypeParameterSymbol }
|
||||
val valueArguments = initPool.filter { it.symbol !is IrTypeParameterSymbol }
|
||||
val newFrame = InterpreterFrame(valueArguments.toMutableList(), typeArgumentsPool)
|
||||
if (asSubFrame) getCurrentFrame().addSubFrame(newFrame) else frameList.add(FrameContainer(newFrame))
|
||||
|
||||
return try {
|
||||
block()
|
||||
} finally {
|
||||
if (asSubFrame) getCurrentFrame().removeSubFrame() else removeLastFrame()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeLastFrame() {
|
||||
if (frameList.size > 1 && getCurrentFrame().hasReturnValue()) frameList[frameList.lastIndex - 1].pushReturnValue(getCurrentFrame())
|
||||
frameList.removeAt(frameList.lastIndex)
|
||||
}
|
||||
|
||||
override fun setCurrentFrameName(irFunction: IrFunction) {
|
||||
val fileName = irFunction.file.name
|
||||
val fileNameCapitalized = irFunction.getCapitalizedFileName()
|
||||
val lineNum = irFunction.fileEntry.getLineNumber(irFunction.startOffset) + 1
|
||||
if (getCurrentFrame().frameEntryPoint == null)
|
||||
getCurrentFrame().frameEntryPoint = "at $fileNameCapitalized.${irFunction.fqNameWhenAvailable}($fileName:$lineNum)"
|
||||
}
|
||||
|
||||
override fun getStackTrace(): List<String> {
|
||||
// TODO implement some sort of cache
|
||||
return frameList.mapNotNull { it.frameEntryPoint }
|
||||
}
|
||||
|
||||
override fun clean() {
|
||||
frameList.clear()
|
||||
frameList.add(FrameContainer())
|
||||
}
|
||||
|
||||
override fun addVar(variable: Variable) {
|
||||
getCurrentFrame().addVar(variable)
|
||||
}
|
||||
|
||||
override fun addAll(variables: List<Variable>) {
|
||||
getCurrentFrame().addAll(variables)
|
||||
}
|
||||
|
||||
override fun getVariable(symbol: IrSymbol): Variable {
|
||||
return getCurrentFrame().getVariable(symbol)
|
||||
}
|
||||
|
||||
override fun getAll(): List<Variable> {
|
||||
return getCurrentFrame().getAll()
|
||||
}
|
||||
|
||||
override fun contains(symbol: IrSymbol): Boolean {
|
||||
return getCurrentFrame().contains(symbol)
|
||||
}
|
||||
|
||||
override fun hasReturnValue(): Boolean {
|
||||
return getCurrentFrame().hasReturnValue()
|
||||
}
|
||||
|
||||
override fun pushReturnValue(state: State) {
|
||||
getCurrentFrame().pushReturnValue(state)
|
||||
}
|
||||
|
||||
override fun popReturnValue(): State {
|
||||
return getCurrentFrame().popReturnValue()
|
||||
}
|
||||
|
||||
override fun peekReturnValue(): State {
|
||||
return getCurrentFrame().peekReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
private class FrameContainer(current: Frame = InterpreterFrame()) {
|
||||
var frameEntryPoint: String? = null
|
||||
private val innerStack = mutableListOf(current)
|
||||
private fun getTopFrame() = innerStack.first()
|
||||
|
||||
fun addSubFrame(frame: Frame) {
|
||||
innerStack.add(0, frame)
|
||||
}
|
||||
|
||||
fun removeSubFrame() {
|
||||
if (getTopFrame().hasReturnValue() && innerStack.size > 1) innerStack[1].pushReturnValue(getTopFrame())
|
||||
innerStack.removeAt(0)
|
||||
}
|
||||
|
||||
fun addVar(variable: Variable) = getTopFrame().addVar(variable)
|
||||
fun addAll(variables: List<Variable>) = getTopFrame().addAll(variables)
|
||||
fun getAll() = innerStack.flatMap { it.getAll() }
|
||||
fun getVariable(symbol: IrSymbol): Variable {
|
||||
return innerStack.firstNotNullResult { it.getVariable(symbol) }
|
||||
?: throw InterpreterException("$symbol not found") // TODO better message
|
||||
}
|
||||
|
||||
fun contains(symbol: IrSymbol) = innerStack.any { it.contains(symbol) }
|
||||
fun hasReturnValue() = getTopFrame().hasReturnValue()
|
||||
fun pushReturnValue(container: FrameContainer) = getTopFrame().pushReturnValue(container.getTopFrame())
|
||||
fun pushReturnValue(state: State) = getTopFrame().pushReturnValue(state)
|
||||
fun popReturnValue() = getTopFrame().popReturnValue()
|
||||
fun peekReturnValue() = getTopFrame().peekReturnValue()
|
||||
|
||||
override fun toString() = frameEntryPoint ?: "Not defined"
|
||||
}
|
||||
@@ -5,8 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.stack
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
|
||||
// TODO maybe switch to typealias and use map instead of list
|
||||
internal data class Variable(val symbol: IrSymbol, var state: State)
|
||||
internal data class Variable(val symbol: IrSymbol) {
|
||||
lateinit var state: State
|
||||
|
||||
constructor(symbol: IrSymbol, state: State) : this(symbol) {
|
||||
this.state = state
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Variable(symbol=${(symbol.owner as? IrDeclarationWithName)?.name}, state=$state)"
|
||||
}
|
||||
}
|
||||
@@ -5,50 +5,46 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.isInterface
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
|
||||
|
||||
internal class Common private constructor(
|
||||
override val irClass: IrClass, override val fields: MutableList<Variable>
|
||||
) : Complex(irClass, fields) {
|
||||
internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList<Variable>) : Complex, StateWithClosure {
|
||||
override val upValues: MutableList<Variable> = mutableListOf()
|
||||
override var superWrapperClass: Wrapper? = null
|
||||
override var outerClass: Variable? = null
|
||||
|
||||
constructor(irClass: IrClass) : this(irClass, mutableListOf())
|
||||
|
||||
fun setSuperClassRecursive() {
|
||||
var thisClass: Common? = this
|
||||
while (thisClass != null) {
|
||||
val superClass = thisClass.irClass.superTypes.filterNot { it.isInterface() }.singleOrNull()
|
||||
val superClassOwner = superClass?.classOrNull?.owner
|
||||
val superClassState = superClassOwner?.let { Common(it) }
|
||||
superClassState?.let { thisClass!!.setSuperClassInstance(it) }
|
||||
fun copyFieldsFrom(state: Complex) {
|
||||
this.fields.addAll(state.fields)
|
||||
superWrapperClass = state.superWrapperClass ?: state as? Wrapper
|
||||
}
|
||||
|
||||
if (superClass == null && thisClass.irClass.superTypes.isNotEmpty()) {
|
||||
// cover the case when super type implement an interface and so doesn't have explicit any as super class
|
||||
thisClass.setSuperClassInstance(Common(getAnyClassRecursive()))
|
||||
}
|
||||
thisClass = superClassState
|
||||
// This method is used to get correct java method name
|
||||
private fun getKotlinName(declaringClassName: String, methodName: String): String {
|
||||
return when {
|
||||
// TODO see specialBuiltinMembers.kt
|
||||
//"kotlin.collections.Map.<get-entries>" -> "entrySet"
|
||||
//"kotlin.collections.Map.<get-keys>" -> "keySet"
|
||||
declaringClassName == "java.lang.CharSequence" && methodName == "charAt" -> "get"
|
||||
//"kotlin.collections.MutableList.removeAt" -> "remove"
|
||||
else -> methodName
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnyClassRecursive(): IrClass {
|
||||
var owner = irClass.superTypes.first().classOrNull!!.owner
|
||||
while (owner.superTypes.isNotEmpty()) owner = owner.superTypes.first().classOrNull!!.owner
|
||||
return owner
|
||||
}
|
||||
|
||||
fun getToStringFunction(): IrFunction {
|
||||
return irClass.declarations.filterIsInstance<IrFunction>()
|
||||
.filter { it.name.asString() == "toString" }
|
||||
.first { it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it as IrSimpleFunction, this) }
|
||||
fun getIrFunction(method: java.lang.reflect.Method): IrFunction? {
|
||||
val methodName = getKotlinName(method.declaringClass.name, method.name)
|
||||
return when (val declaration = irClass.declarations.singleOrNull { it.nameForIrSerialization.asString() == methodName }) {
|
||||
is IrProperty -> declaration.getter
|
||||
else -> declaration as? IrFunction
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Common(obj='${irClass.fqNameForIrSerialization}', super=$superClass, values=$fields)"
|
||||
return "Common(obj='${irClass.fqNameForIrSerialization}', values=$fields)"
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.getCorrectReceiverByFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.getLastOverridden
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -14,79 +13,76 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.overrides
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal abstract class Complex(override val irClass: IrClass, override val fields: MutableList<Variable>) : State {
|
||||
var superClass: Complex? = null
|
||||
var subClass: Complex? = null
|
||||
val interfaces: MutableList<Complex> = mutableListOf() // filled lazily, as needed
|
||||
override val typeArguments: MutableList<Variable> = mutableListOf()
|
||||
var outerClass: Variable? = null
|
||||
|
||||
fun setSuperClassInstance(superClass: Complex) {
|
||||
if (this.irClass == superClass.irClass) {
|
||||
// if superClass is just secondary constructor instance, then copy properties that isn't already present in instance
|
||||
superClass.fields.forEach { if (!this.contains(it)) fields.add(it) }
|
||||
this.superClass = superClass.superClass
|
||||
superClass.superClass?.subClass = this
|
||||
} else {
|
||||
this.superClass = superClass
|
||||
superClass.subClass = this
|
||||
}
|
||||
}
|
||||
|
||||
fun getOriginal(): Complex {
|
||||
return subClass?.getOriginal() ?: this
|
||||
}
|
||||
internal interface Complex: State {
|
||||
var superWrapperClass: Wrapper?
|
||||
var outerClass: Variable?
|
||||
|
||||
fun irClassFqName(): String {
|
||||
return irClass.fqNameForIrSerialization.toString()
|
||||
}
|
||||
|
||||
private fun contains(variable: Variable) = fields.any { it.symbol == variable.symbol }
|
||||
|
||||
private fun getIrFunction(symbol: IrFunctionSymbol): IrFunction? {
|
||||
val propertyGetters = irClass.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }
|
||||
val functions = irClass.declarations.filterIsInstance<IrFunction>()
|
||||
return (propertyGetters + functions).firstOrNull {
|
||||
if (it is IrSimpleFunction) it.overrides(symbol.owner as IrSimpleFunction) else it == symbol.owner
|
||||
}
|
||||
}
|
||||
|
||||
private fun getThisOrSuperReceiver(superIrClass: IrClass?): Complex? {
|
||||
return when {
|
||||
superIrClass == null -> this.getOriginal()
|
||||
superIrClass.isInterface -> Common(superIrClass).apply {
|
||||
interfaces.add(this)
|
||||
this.subClass = this@Complex
|
||||
private fun IrClass.getIrFunction(symbol: IrFunctionSymbol): IrFunction? {
|
||||
val propertyGetters = this.declarations.filterIsInstance<IrProperty>().mapNotNull { it.getter }
|
||||
val propertySetters = this.declarations.filterIsInstance<IrProperty>().mapNotNull { it.setter }
|
||||
val functions = this.declarations.filterIsInstance<IrFunction>()
|
||||
return (propertyGetters + propertySetters + functions).firstOrNull {
|
||||
val owner = symbol.owner
|
||||
when {
|
||||
it is IrSimpleFunction && owner is IrSimpleFunction -> it.overrides(owner) || owner.overrides(it)
|
||||
else -> it == symbol.owner
|
||||
}
|
||||
else -> this.superClass
|
||||
}
|
||||
}
|
||||
|
||||
protected fun getOverridden(owner: IrSimpleFunction, qualifier: State?): IrSimpleFunction {
|
||||
if (!owner.isFakeOverride) return owner
|
||||
if (qualifier == null || qualifier is ExceptionState || (qualifier as? Complex)?.superClass == null) {
|
||||
return owner.getLastOverridden() as IrSimpleFunction
|
||||
}
|
||||
|
||||
val overriddenOwner = owner.overriddenSymbols.single().owner
|
||||
private fun getThisOrSuperReceiver(superIrClass: IrClass?): IrClass? {
|
||||
return when {
|
||||
overriddenOwner.body != null -> overriddenOwner
|
||||
else -> getOverridden(overriddenOwner, qualifier.superClass!!)
|
||||
superIrClass == null -> this.irClass
|
||||
superIrClass.isInterface -> superIrClass
|
||||
else -> irClass.superTypes.map { it.classOrNull?.owner }.singleOrNull { it?.isInterface == false }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
|
||||
if (owner.parent == superWrapperClass?.irClass) return owner
|
||||
if (!owner.isFakeOverride || owner.body != null || owner.parentAsClass.defaultType.isAny()) return owner
|
||||
|
||||
val overriddenOwner = owner.overriddenSymbols.let { it.singleOrNull { it.owner.body != null } ?: it.singleOrNull() }?.owner
|
||||
return overriddenOwner?.let { getOverridden(it) } ?: owner.getLastOverridden() as IrSimpleFunction
|
||||
}
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||
val receiver = getThisOrSuperReceiver(expression.superQualifierSymbol?.owner) ?: return null
|
||||
|
||||
val irFunction = receiver.getIrFunction(expression.symbol) ?: return null
|
||||
return getOverridden(irFunction as IrSimpleFunction)
|
||||
}
|
||||
|
||||
return when (irFunction.body) {
|
||||
null -> getOverridden(irFunction as IrSimpleFunction, this.getCorrectReceiverByFunction(irFunction))
|
||||
else -> irFunction
|
||||
}
|
||||
fun getEqualsFunction(): IrSimpleFunction {
|
||||
val equalsFun = irClass.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.single {
|
||||
it.name == Name.identifier("equals") && it.dispatchReceiverParameter != null
|
||||
&& it.valueParameters.size == 1 && it.valueParameters[0].type.isNullableAny()
|
||||
}
|
||||
return getOverridden(equalsFun)
|
||||
}
|
||||
|
||||
fun getHashCodeFunction(): IrSimpleFunction {
|
||||
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { it.name.asString() == "hashCode" }
|
||||
.first { it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it) }
|
||||
}
|
||||
|
||||
fun getToStringFunction(): IrSimpleFunction {
|
||||
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { it.name.asString() == "toString" }
|
||||
.first { it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it) }
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,15 @@ import kotlin.math.min
|
||||
|
||||
internal class ExceptionState private constructor(
|
||||
override val irClass: IrClass, override val fields: MutableList<Variable>, stackTrace: List<String>
|
||||
) : Complex(irClass, fields) {
|
||||
) : Complex, StateWithClosure, Throwable() {
|
||||
override val upValues: MutableList<Variable> = mutableListOf()
|
||||
override var superWrapperClass: Wrapper? = null
|
||||
override var outerClass: Variable? = null
|
||||
|
||||
override val message: String?
|
||||
get() = getState(messageProperty.symbol)?.asStringOrNull()
|
||||
override val cause: Throwable?
|
||||
get() = getState(causeProperty.symbol)?.let { if (it is ExceptionState) it else null }
|
||||
|
||||
private lateinit var exceptionFqName: String
|
||||
private val exceptionHierarchy = mutableListOf<String>()
|
||||
@@ -35,9 +43,8 @@ internal class ExceptionState private constructor(
|
||||
}
|
||||
|
||||
constructor(common: Common, stackTrace: List<String>) : this(common.irClass, common.fields, stackTrace) {
|
||||
var wrapperSuperType: Complex? = common
|
||||
while (wrapperSuperType != null && wrapperSuperType !is Wrapper) wrapperSuperType = (wrapperSuperType as Common).superClass
|
||||
setUpCauseIfNeeded(wrapperSuperType as? Wrapper)
|
||||
(common.superWrapperClass?.value as? Throwable)?.let { setMessage(it.message) }
|
||||
setUpCauseIfNeeded(common.superWrapperClass)
|
||||
}
|
||||
|
||||
constructor(wrapper: Wrapper, stackTrace: List<String>) : this(wrapper.value as Throwable, wrapper.irClass, stackTrace) {
|
||||
@@ -47,6 +54,7 @@ internal class ExceptionState private constructor(
|
||||
constructor(
|
||||
exception: Throwable, irClass: IrClass, stackTrace: List<String>
|
||||
) : this(irClass, evaluateFields(exception, irClass, stackTrace), stackTrace + evaluateAdditionalStackTrace(exception)) {
|
||||
setCause(null) // TODO check this fact
|
||||
if (irClass.name.asString() != exception::class.java.simpleName) {
|
||||
// ir class wasn't found in classpath, a stub was passed => need to save java class hierarchy
|
||||
this.exceptionFqName = exception::class.java.name
|
||||
@@ -56,18 +64,11 @@ internal class ExceptionState private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
data class ExceptionData(val state: ExceptionState) : Throwable() {
|
||||
override val message: String? = state.getMessage()
|
||||
override fun fillInStackTrace() = this
|
||||
|
||||
override fun toString(): String = state.getMessageWithName()
|
||||
}
|
||||
|
||||
private fun setUpCauseIfNeeded(wrapper: Wrapper?) {
|
||||
val cause = (wrapper?.value as? Throwable)?.cause as? ExceptionData
|
||||
setCause(cause?.state)
|
||||
if (getMessage() == null && cause != null) {
|
||||
val causeMessage = cause.state.exceptionFqName + (cause.state.getMessage()?.let { ": $it" } ?: "")
|
||||
val cause = (wrapper?.value as? Throwable)?.cause as? ExceptionState
|
||||
setCause(cause)
|
||||
if (message == null && cause != null) {
|
||||
val causeMessage = cause.exceptionFqName + (cause.message?.let { ": $it" } ?: "")
|
||||
setMessage(causeMessage)
|
||||
}
|
||||
}
|
||||
@@ -87,23 +88,18 @@ internal class ExceptionState private constructor(
|
||||
setField(Variable(causeProperty.symbol, causeValue ?: Primitive<Throwable?>(null, causeProperty.getter!!.returnType)))
|
||||
}
|
||||
|
||||
fun getMessage(): String? = (getState(messageProperty.symbol) as Primitive<*>).value as String?
|
||||
private fun getMessageWithName(): String = getMessage()?.let { "$exceptionFqName: $it" } ?: exceptionFqName
|
||||
|
||||
fun getCause(): ExceptionState? = getState(causeProperty.symbol)?.let { if (it is ExceptionState) it else null }
|
||||
|
||||
fun getFullDescription(): String {
|
||||
// TODO remainder of the stack trace with "..."
|
||||
val message = getMessage().let { if (it?.isNotEmpty() == true) ": $it" else "" }
|
||||
val message = message.let { if (it?.isNotEmpty() == true) ": $it" else "" }
|
||||
val prefix = if (stackTrace.isNotEmpty()) "\n\t" else ""
|
||||
val postfix = if (stackTrace.size > 10) "\n\t..." else ""
|
||||
val causeMessage = getCause()?.getFullDescription()?.replaceFirst("Exception ", "\nCaused by: ") ?: ""
|
||||
val causeMessage = (cause as? ExceptionState)?.getFullDescription()?.replaceFirst("Exception ", "\nCaused by: ") ?: ""
|
||||
return "Exception $exceptionFqName$message" +
|
||||
stackTrace.subList(0, min(stackTrace.size, 10)).joinToString(separator = "\n\t", prefix = prefix, postfix = postfix) +
|
||||
causeMessage
|
||||
}
|
||||
|
||||
fun getThisAsCauseForException() = ExceptionData(this)
|
||||
override fun toString(): String = message?.let { "$exceptionFqName: $it" } ?: exceptionFqName
|
||||
|
||||
companion object {
|
||||
private fun IrClass.getPropertyByName(name: String): IrProperty {
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.getLastOverridden
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
internal class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State {
|
||||
override val fields: MutableList<Variable> = mutableListOf()
|
||||
override val typeArguments: MutableList<Variable> = mutableListOf()
|
||||
|
||||
private val invokeSymbol = irClass.declarations
|
||||
.single { it.nameForIrSerialization.asString() == "invoke" }
|
||||
.cast<IrSimpleFunction>()
|
||||
.getLastOverridden().symbol
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||
return if (invokeSymbol == expression.symbol) irFunction else null
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.render()
|
||||
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.render() }
|
||||
val returnType = irFunction.returnType.render()
|
||||
return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it }
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,8 @@ import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.overrides
|
||||
|
||||
internal class Primitive<T>(var value: T, val type: IrType) : State {
|
||||
internal class Primitive<T>(val value: T, val type: IrType) : State {
|
||||
override val fields: MutableList<Variable> = mutableListOf()
|
||||
override val typeArguments: MutableList<Variable> = mutableListOf()
|
||||
override val irClass: IrClass = type.classOrNull!!.owner
|
||||
|
||||
override fun getState(symbol: IrSymbol): State {
|
||||
@@ -37,26 +36,6 @@ internal class Primitive<T>(var value: T, val type: IrType) : State {
|
||||
?.let { if (it.isFakeOverride) it.getLastOverridden() else it }
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Primitive<*>
|
||||
|
||||
if (value != other.value) return false
|
||||
if (type != other.type) return false
|
||||
if (fields != other.fields) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = value?.hashCode() ?: 0
|
||||
result = 31 * result + type.hashCode()
|
||||
result = 31 * result + fields.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Primitive(value=$value, type=${irClass.defaultType})"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
||||
import org.jetbrains.kotlin.ir.interpreter.handleUserException
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
@@ -16,7 +18,6 @@ import org.jetbrains.kotlin.ir.util.defaultType
|
||||
internal interface State {
|
||||
val fields: MutableList<Variable>
|
||||
val irClass: IrClass
|
||||
val typeArguments: MutableList<Variable>
|
||||
|
||||
fun getState(symbol: IrSymbol): State? {
|
||||
return fields.firstOrNull { it.symbol == symbol }?.state
|
||||
@@ -29,10 +30,6 @@ internal interface State {
|
||||
}
|
||||
}
|
||||
|
||||
fun addTypeArguments(typeArguments: List<Variable>) {
|
||||
this.typeArguments.addAll(typeArguments)
|
||||
}
|
||||
|
||||
fun getIrFunctionByIrCall(expression: IrCall): IrFunction?
|
||||
}
|
||||
|
||||
@@ -43,15 +40,22 @@ internal fun State.asBoolean() = (this as Primitive<*>).value as Boolean
|
||||
internal fun State.asString() = (this as Primitive<*>).value.toString()
|
||||
|
||||
internal fun State.asBooleanOrNull() = (this as? Primitive<*>)?.value as? Boolean
|
||||
internal fun State.asStringOrNull() = (this as Primitive<*>).value as? String
|
||||
|
||||
internal fun State.isSubtypeOf(other: IrType): Boolean {
|
||||
if (this is Primitive<*> && this.value == null) return other.isNullable()
|
||||
if (this is ExceptionState) return this.isSubtypeOf(other.classOrNull!!.owner)
|
||||
|
||||
if (this is Primitive<*> && this.type.isArray() && other.isArray()) {
|
||||
val thisClass = this.typeArguments.single().state.irClass.symbol
|
||||
val otherArgument = (other as IrSimpleType).arguments.single()
|
||||
if (otherArgument is IrStarProjection) return true
|
||||
return thisClass.isSubtypeOfClass(otherArgument.typeOrNull!!.classOrNull!!)
|
||||
fun IrType.arraySubtypeCheck(other: IrType): Boolean {
|
||||
if (other !is IrSimpleType || this !is IrSimpleType) return false
|
||||
val thisArgument = this.arguments.single().typeOrNull ?: return false
|
||||
val otherArgument = other.arguments.single().typeOrNull ?: return other.arguments.single() is IrStarProjection
|
||||
if (thisArgument.isArray() && otherArgument.isArray()) return thisArgument.arraySubtypeCheck(otherArgument)
|
||||
if (otherArgument.classOrNull == null) return false
|
||||
return thisArgument.classOrNull?.isSubtypeOfClass(otherArgument.classOrNull!!) ?: false
|
||||
}
|
||||
return this.type.arraySubtypeCheck(other)
|
||||
}
|
||||
|
||||
return this.irClass.defaultType.isSubtypeOfClass(other.classOrNull!!)
|
||||
@@ -60,10 +64,13 @@ internal fun State.isSubtypeOf(other: IrType): Boolean {
|
||||
/**
|
||||
* This method used to check if for not null parameter there was passed null argument.
|
||||
*/
|
||||
internal fun State.checkNullability(irType: IrType?, throwException: () -> Nothing = { throw NullPointerException() }): State {
|
||||
internal fun State.checkNullability(
|
||||
irType: IrType?, environment: IrInterpreterEnvironment, exceptionToThrow: () -> Throwable = { NullPointerException() }
|
||||
): State? {
|
||||
if (irType !is IrSimpleType) return this
|
||||
if (this.isNull() && !irType.isNullable()) {
|
||||
throwException()
|
||||
exceptionToThrow().handleUserException(environment)
|
||||
return null
|
||||
}
|
||||
return this
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
|
||||
internal interface StateWithClosure {
|
||||
val upValues: MutableList<Variable>
|
||||
}
|
||||
@@ -5,28 +5,62 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||
import java.lang.invoke.MethodHandle
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.LinkedHashMap
|
||||
|
||||
internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, mutableListOf()) {
|
||||
internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex {
|
||||
override val fields: MutableList<Variable> = mutableListOf()
|
||||
|
||||
override var superWrapperClass: Wrapper? = null
|
||||
override var outerClass: Variable? = null
|
||||
|
||||
private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe()
|
||||
private val receiverClass = irClass.defaultType.getClass(true)
|
||||
|
||||
init {
|
||||
val javaClass = value::class.java
|
||||
when {
|
||||
javaClass == HashMap::class.java -> {
|
||||
val nodeClass = javaClass.declaredClasses.single { it.name.contains("\$Node") }
|
||||
val mutableMap = irClass.superTypes.mapNotNull { it.classOrNull?.owner }.single { it.isInterface }
|
||||
javaClassToIrClass += nodeClass to mutableMap.declarations.filterIsInstance<IrClass>().single()
|
||||
}
|
||||
javaClass == LinkedHashMap::class.java -> {
|
||||
val entryClass = javaClass.declaredClasses.single { it.name.contains("\$Entry") }
|
||||
val mutableMap = irClass.superTypes.mapNotNull { it.classOrNull?.owner }.single { it.isInterface }
|
||||
javaClassToIrClass += entryClass to mutableMap.declarations.filterIsInstance<IrClass>().single()
|
||||
}
|
||||
javaClass.canonicalName == "java.util.Collections.SingletonMap" -> {
|
||||
javaClassToIrClass += AbstractMap.SimpleEntry::class.java to irClass.declarations.filterIsInstance<IrClass>().single()
|
||||
javaClassToIrClass += AbstractMap.SimpleImmutableEntry::class.java to irClass.declarations.filterIsInstance<IrClass>().single()
|
||||
}
|
||||
}
|
||||
javaClassToIrClass += value::class.java to irClass
|
||||
}
|
||||
|
||||
constructor(value: Any) : this(value, javaClassToIrClass[value::class.java]!!)
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null
|
||||
|
||||
fun getMethod(irFunction: IrFunction): MethodHandle? {
|
||||
if (irFunction.getEvaluateIntrinsicValue()?.isEmpty() == true) return null // this method will handle IntrinsicEvaluator
|
||||
// if function is actually a getter, then use "get${property.name.capitalize()}" as method name
|
||||
@@ -51,12 +85,38 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val companionObjectValue = mapOf<String, Any>("kotlin.text.Regex\$Companion" to Regex.Companion)
|
||||
private val javaClassToIrClass = mutableMapOf<Class<*>, IrClass>()
|
||||
|
||||
fun associateJavaClassWithIrClass(javaClass: Class<*>, irClass: IrClass) {
|
||||
javaClassToIrClass += javaClass to irClass
|
||||
}
|
||||
|
||||
fun getReflectionMethod(irFunction: IrFunction): MethodHandle {
|
||||
val receiverClass = irFunction.dispatchReceiverParameter!!.type.getClass(asObject = true)
|
||||
val methodType = irFunction.getMethodType()
|
||||
val methodName = when (irFunction) {
|
||||
is IrSimpleFunction -> {
|
||||
val property = irFunction.correspondingPropertySymbol?.owner
|
||||
when {
|
||||
property?.getter == irFunction -> "get${property.name.asString().capitalize()}"
|
||||
property?.setter == irFunction -> "set${property.name.asString().capitalize()}"
|
||||
else -> irFunction.name.asString()
|
||||
}
|
||||
}
|
||||
else -> irFunction.name.asString()
|
||||
}
|
||||
return MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType)
|
||||
}
|
||||
|
||||
fun getCompanionObject(irClass: IrClass): Wrapper {
|
||||
val objectName = irClass.getEvaluateIntrinsicValue()!!
|
||||
val objectValue = companionObjectValue[objectName] ?: throw AssertionError("Companion object $objectName cannot be interpreted")
|
||||
val objectValue = companionObjectValue[objectName] ?: throw InternalError("Companion object $objectName cannot be interpreted")
|
||||
return Wrapper(objectValue, irClass)
|
||||
}
|
||||
|
||||
@@ -79,7 +139,7 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(
|
||||
|
||||
fun getStaticGetter(field: IrField): MethodHandle? {
|
||||
val jvmClass = field.parentAsClass.defaultType.getClass(true)
|
||||
val returnType = field.type.getClass(false)
|
||||
val returnType = field.type.let { it.getClass((it as IrSimpleType).hasQuestionMark) }
|
||||
return MethodHandles.lookup().findStaticGetter(jvmClass, field.name.asString(), returnType)
|
||||
}
|
||||
|
||||
@@ -113,19 +173,31 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(
|
||||
//TODO check if primitive array is possible here
|
||||
return when {
|
||||
notNullType.isPrimitiveType() || notNullType.isString() -> getPrimitiveClass(notNullType, asObject)!!
|
||||
notNullType.isArray() -> if (asObject) Array<Any?>::class.javaObjectType else Array<Any?>::class.java
|
||||
notNullType.isArray() -> {
|
||||
val argumentFqName = (this as IrSimpleType).arguments.single().typeOrNull?.classOrNull?.owner?.fqNameWhenAvailable
|
||||
when {
|
||||
argumentFqName != null && argumentFqName.asString() != "kotlin.Any" -> argumentFqName.let { Class.forName("[L$it;") }
|
||||
else -> Array<Any?>::class.java
|
||||
}
|
||||
}
|
||||
notNullType.isNothing() -> Nothing::class.java
|
||||
notNullType.isAny() -> Any::class.java
|
||||
notNullType.isUnit() -> if (asObject) Void::class.javaObjectType else Void::class.javaPrimitiveType!!
|
||||
notNullType.isNumber() -> Number::class.java
|
||||
notNullType.isCharSequence() -> CharSequence::class.java
|
||||
notNullType.isComparable() -> Comparable::class.java
|
||||
notNullType.isThrowable() -> Throwable::class.java
|
||||
notNullType.isIterable() -> Iterable::class.java
|
||||
|
||||
// TODO implement function mapping; all complexity is to map big arity to FunctionN
|
||||
//notNullType.isKFunction() -> Class.forName("kotlin.reflect.KFunction")
|
||||
//notNullType.isFunction() -> Class.forName("kotlin.jvm.functions.Function_TODO")
|
||||
//notNullType.isSuspendFunction() || notNullType.isKSuspendFunction() -> throw AssertionError()
|
||||
notNullType.isKFunction() -> Class.forName("kotlin.reflect.KFunction")
|
||||
notNullType.isFunction() -> {
|
||||
val arity = fqName?.removePrefix("kotlin.Function")?.toIntOrNull()
|
||||
return when {
|
||||
arity == null || arity >= BuiltInFunctionArity.BIG_ARITY -> Class.forName("kotlin.jvm.functions.FunctionN")
|
||||
else -> Class.forName("kotlin.jvm.functions.${fqName.removePrefix("kotlin.")}")
|
||||
}
|
||||
}
|
||||
//notNullType.isSuspendFunction() || notNullType.isKSuspendFunction() -> throw AssertionError() //TODO
|
||||
|
||||
fqName == "kotlin.Enum" -> Enum::class.java
|
||||
fqName == "kotlin.collections.Collection" || fqName == "kotlin.collections.MutableCollection" -> Collection::class.java
|
||||
@@ -136,6 +208,7 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(
|
||||
fqName == "kotlin.collections.Iterator" || fqName == "kotlin.collections.MutableIterator" -> Iterator::class.java
|
||||
fqName == "kotlin.collections.Map.Entry" || fqName == "kotlin.collections.MutableMap.MutableEntry" -> Map.Entry::class.java
|
||||
fqName == "kotlin.collections.ListIterator" || fqName == "kotlin.collections.MutableListIterator" -> ListIterator::class.java
|
||||
fqName == "kotlin.collections.HashMap" -> HashMap::class.java
|
||||
|
||||
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue())
|
||||
fqName == null -> Any::class.java // null if this.isTypeParameter()
|
||||
@@ -184,8 +257,4 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex(
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Wrapper(obj='$typeFqName', value=$value)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.internalName
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.*
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.KTypeParameter
|
||||
|
||||
internal class KClassState(val classReference: IrClass, override val irClass: IrClass) : ReflectionState() {
|
||||
private var _members: Collection<KCallable<*>>? = null
|
||||
private var _constructors: Collection<KFunction<*>>? = null
|
||||
private var _typeParameters: List<KTypeParameter>? = null
|
||||
private var _supertypes: List<KType>? = null
|
||||
|
||||
constructor(classReference: IrClassReference) : this(classReference.symbol.owner as IrClass, classReference.type.classOrNull!!.owner)
|
||||
|
||||
fun getMembers(callInterceptor: CallInterceptor): Collection<KCallable<*>> {
|
||||
if (_members != null) return _members!!
|
||||
_members = classReference.declarations
|
||||
.filter { it !is IrClass && it !is IrConstructor }
|
||||
.map {
|
||||
when (it) {
|
||||
is IrProperty -> {
|
||||
val withExtension = it.getter?.extensionReceiverParameter != null
|
||||
when {
|
||||
!withExtension && !it.isVar ->
|
||||
KProperty1Proxy(KPropertyState(it, callInterceptor.irBuiltIns.getKPropertyClass(false, 1).owner), callInterceptor)
|
||||
!withExtension && it.isVar ->
|
||||
KMutableProperty1Proxy(
|
||||
KPropertyState(it, callInterceptor.irBuiltIns.getKPropertyClass(true, 1).owner), callInterceptor
|
||||
)
|
||||
withExtension && !it.isVar ->
|
||||
KProperty2Proxy(KPropertyState(it, callInterceptor.irBuiltIns.getKPropertyClass(false, 2).owner), callInterceptor)
|
||||
!withExtension && it.isVar ->
|
||||
KMutableProperty2Proxy(
|
||||
KPropertyState(it, callInterceptor.irBuiltIns.getKPropertyClass(true, 2).owner), callInterceptor
|
||||
)
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
is IrFunction -> KFunctionProxy(KFunctionState(it, callInterceptor.irBuiltIns.functionFactory), callInterceptor)
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
return _members!!
|
||||
}
|
||||
|
||||
fun getConstructors(callInterceptor: CallInterceptor): Collection<KFunction<*>> {
|
||||
if (_constructors != null) return _constructors!!
|
||||
_constructors = classReference.declarations
|
||||
.filterIsInstance<IrConstructor>()
|
||||
.map { KFunctionProxy(KFunctionState(it, callInterceptor.irBuiltIns.functionFactory), callInterceptor) }
|
||||
return _constructors!!
|
||||
}
|
||||
|
||||
fun getTypeParameters(callInterceptor: CallInterceptor): List<KTypeParameter> {
|
||||
if (_typeParameters != null) return _typeParameters!!
|
||||
val kTypeParameterIrClass = irClass.getIrClassOfReflectionFromList("typeParameters")
|
||||
_typeParameters = classReference.typeParameters.map { KTypeParameterProxy(KTypeParameterState(it, kTypeParameterIrClass), callInterceptor) }
|
||||
return _typeParameters!!
|
||||
}
|
||||
|
||||
fun getSupertypes(callInterceptor: CallInterceptor): List<KType> {
|
||||
if (_supertypes != null) return _supertypes!!
|
||||
val kTypeIrClass = irClass.getIrClassOfReflectionFromList("supertypes")
|
||||
_supertypes = (classReference.superTypes.map { it } + callInterceptor.irBuiltIns.anyType).toSet()
|
||||
.map { KTypeProxy(KTypeState(it, kTypeIrClass), callInterceptor) }
|
||||
return _supertypes!!
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KClassState
|
||||
|
||||
if (classReference != other.classReference) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return classReference.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "class ${classReference.internalName()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KParameterProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeParameterProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.StateWithClosure
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.KTypeParameter
|
||||
|
||||
internal class KFunctionState(val irFunction: IrFunction, override val irClass: IrClass) : ReflectionState(), StateWithClosure {
|
||||
override val upValues: MutableList<Variable> = mutableListOf()
|
||||
override val fields: MutableList<Variable> = mutableListOf()
|
||||
private var _parameters: List<KParameter>? = null
|
||||
private var _returnType: KType? = null
|
||||
private var _typeParameters: List<KTypeParameter>? = null
|
||||
|
||||
constructor(functionReference: IrFunctionReference) : this(functionReference.symbol.owner, functionReference.type.classOrNull!!.owner)
|
||||
constructor(irFunction: IrFunction, functionFactory: IrAbstractFunctionFactory) :
|
||||
this(irFunction, functionFactory.kFunctionN(irFunction.valueParameters.size))
|
||||
|
||||
fun getParameters(callInterceptor: CallInterceptor): List<KParameter> {
|
||||
if (_parameters != null) return _parameters!!
|
||||
val kParameterIrClass = irClass.getIrClassOfReflectionFromList("parameters")
|
||||
var index = 0
|
||||
val instanceParameter = irFunction.dispatchReceiverParameter
|
||||
?.let { KParameterProxy(KParameterState(kParameterIrClass, it, index++, KParameter.Kind.INSTANCE), callInterceptor) }
|
||||
val extensionParameter = irFunction.extensionReceiverParameter
|
||||
?.let { KParameterProxy(KParameterState(kParameterIrClass, it, index++, KParameter.Kind.EXTENSION_RECEIVER), callInterceptor) }
|
||||
_parameters = listOfNotNull(instanceParameter, extensionParameter) +
|
||||
irFunction.valueParameters.map { KParameterProxy(KParameterState(kParameterIrClass, it, index++), callInterceptor) }
|
||||
return _parameters!!
|
||||
}
|
||||
|
||||
fun getReturnType(callInterceptor: CallInterceptor): KType {
|
||||
if (_returnType != null) return _returnType!!
|
||||
val kTypeIrClass = irClass.getIrClassOfReflection("returnType")
|
||||
_returnType = KTypeProxy(KTypeState(irFunction.returnType, kTypeIrClass), callInterceptor)
|
||||
return _returnType!!
|
||||
}
|
||||
|
||||
fun getTypeParameters(callInterceptor: CallInterceptor): List<KTypeParameter> {
|
||||
if (_typeParameters != null) return _typeParameters!!
|
||||
val kTypeParametersIrClass = irClass.getIrClassOfReflectionFromList("typeParameters")
|
||||
_typeParameters = irClass.typeParameters.map { KTypeParameterProxy(KTypeParameterState(it, kTypeParametersIrClass), callInterceptor) }
|
||||
return _typeParameters!!
|
||||
}
|
||||
|
||||
fun getArity(): Int? {
|
||||
return irClass.name.asString().removePrefix("Function").removePrefix("KFunction").toIntOrNull()
|
||||
}
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||
return if (expression.symbol.owner.name.asString() == "invoke") irFunction else null
|
||||
}
|
||||
|
||||
private fun isLambda(): Boolean = irFunction.name.let { it == Name.special("<anonymous>") || it == Name.special("<no name provided>") }
|
||||
|
||||
override fun toString(): String {
|
||||
return if (isLambda()) renderLambda(irFunction) else renderFunction(irFunction)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
|
||||
internal class KParameterState(
|
||||
override val irClass: IrClass, val irParameter: IrValueParameter, val index: Int, val kind: KParameter.Kind = KParameter.Kind.VALUE
|
||||
) : ReflectionState() {
|
||||
private var _type: KType? = null
|
||||
|
||||
fun getType(callInterceptor: CallInterceptor): KType {
|
||||
if (_type != null) return _type!!
|
||||
val kTypeIrClass = irClass.getIrClassOfReflection("type")
|
||||
_type = KTypeProxy(KTypeState(irParameter.type, kTypeIrClass), callInterceptor)
|
||||
return _type!!
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KParameterState
|
||||
|
||||
if (irParameter != other.irParameter) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return irParameter.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return buildString {
|
||||
when (kind) {
|
||||
KParameter.Kind.EXTENSION_RECEIVER -> append("extension receiver parameter")
|
||||
KParameter.Kind.INSTANCE -> append("instance parameter")
|
||||
KParameter.Kind.VALUE -> append("parameter #$index ${irParameter.name}")
|
||||
}
|
||||
|
||||
append(" of ")
|
||||
when (val parent = irParameter.parent) {
|
||||
is IrSimpleFunction -> parent.correspondingPropertySymbol?.owner?.let { append(renderProperty(it)) }
|
||||
?: append(renderFunction(parent))
|
||||
is IrFunction -> append(renderFunction(parent))
|
||||
is IrProperty -> append(renderProperty(parent))
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KParameterProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.KType
|
||||
|
||||
internal class KPropertyState(
|
||||
val property: IrProperty, override val irClass: IrClass, val dispatchReceiver: State? = null
|
||||
) : ReflectionState() {
|
||||
|
||||
constructor(propertyReference: IrPropertyReference, dispatchReceiver: State?)
|
||||
: this(propertyReference.symbol.owner, propertyReference.type.classOrNull!!.owner, dispatchReceiver)
|
||||
|
||||
private var _parameters: List<KParameter>? = null
|
||||
private var _returnType: KType? = null
|
||||
|
||||
fun getParameters(callInterceptor: CallInterceptor): List<KParameter> {
|
||||
if (_parameters != null) return _parameters!!
|
||||
val kParameterIrClass = irClass.getIrClassOfReflectionFromList("parameters")
|
||||
var index = 0
|
||||
val instanceParameter = property.getter?.dispatchReceiverParameter?.takeIf { dispatchReceiver == null }
|
||||
?.let { KParameterProxy(KParameterState(kParameterIrClass, it, index++, KParameter.Kind.INSTANCE), callInterceptor) }
|
||||
val extensionParameter = property.getter?.extensionReceiverParameter
|
||||
?.let { KParameterProxy(KParameterState(kParameterIrClass, it, index++, KParameter.Kind.EXTENSION_RECEIVER), callInterceptor) }
|
||||
_parameters = listOfNotNull(instanceParameter, extensionParameter)
|
||||
return _parameters!!
|
||||
}
|
||||
|
||||
fun getReturnType(callInterceptor: CallInterceptor): KType {
|
||||
if (_returnType != null) return _returnType!!
|
||||
val kTypeIrClass = irClass.getIrClassOfReflection("returnType")
|
||||
_returnType = KTypeProxy(KTypeState(property.getter!!.returnType, kTypeIrClass), callInterceptor)
|
||||
return _returnType!!
|
||||
}
|
||||
|
||||
fun isKProperty0(): Boolean = irClass.name.asString() == "KProperty0"
|
||||
|
||||
fun isKProperty1(): Boolean = irClass.name.asString() == "KProperty1"
|
||||
|
||||
fun isKProperty2(): Boolean = irClass.name.asString() == "KProperty2"
|
||||
|
||||
fun isKMutableProperty0(): Boolean = irClass.name.asString() == "KMutableProperty0"
|
||||
|
||||
fun isKMutableProperty1(): Boolean = irClass.name.asString() == "KMutableProperty1"
|
||||
|
||||
fun isKMutableProperty2(): Boolean = irClass.name.asString() == "KMutableProperty2"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KPropertyState
|
||||
|
||||
if (property != other.property) return false
|
||||
if (dispatchReceiver != other.dispatchReceiver) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = property.hashCode()
|
||||
result = 31 * result + (dispatchReceiver?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return renderProperty(property)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
|
||||
import kotlin.reflect.KType
|
||||
|
||||
internal class KTypeParameterState(val irTypeParameter: IrTypeParameter, override val irClass: IrClass) : ReflectionState() {
|
||||
private var _upperBounds: List<KType>? = null
|
||||
|
||||
fun getUpperBounds(callInterceptor: CallInterceptor): List<KType> {
|
||||
if (_upperBounds != null) return _upperBounds!!
|
||||
val kTypeIrClass = irClass.getIrClassOfReflectionFromList("upperBounds")
|
||||
_upperBounds = irTypeParameter.superTypes.map { KTypeProxy(KTypeState(it, kTypeIrClass), callInterceptor) }
|
||||
return _upperBounds!!
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KTypeParameterState
|
||||
|
||||
if (irTypeParameter != other.irTypeParameter) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return irTypeParameter.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return irTypeParameter.name.asString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KClassProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeParameterProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.proxy.reflection.KTypeProxy
|
||||
import org.jetbrains.kotlin.ir.interpreter.renderType
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.Wrapper
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import kotlin.reflect.KClassifier
|
||||
import kotlin.reflect.KTypeProjection
|
||||
|
||||
internal class KTypeState(val irType: IrType, override val irClass: IrClass) : ReflectionState() {
|
||||
private var _classifier: KClassifier? = null
|
||||
private var _arguments: List<KTypeProjection>? = null
|
||||
|
||||
fun getClassifier(callInterceptor: CallInterceptor): KClassifier? {
|
||||
if (_classifier != null) return _classifier!!
|
||||
_classifier = when (val classifier = irType.classifierOrFail.owner) {
|
||||
is IrClass -> KClassProxy(KClassState(classifier, callInterceptor.irBuiltIns.kClassClass.owner), callInterceptor)
|
||||
is IrTypeParameter -> {
|
||||
val kTypeParameterIrClass = callInterceptor.irBuiltIns.kClassClass.owner.getIrClassOfReflectionFromList("typeParameters")
|
||||
KTypeParameterProxy(KTypeParameterState(classifier, kTypeParameterIrClass), callInterceptor)
|
||||
}
|
||||
else -> TODO()
|
||||
}
|
||||
return _classifier!!
|
||||
}
|
||||
|
||||
fun getArguments(callInterceptor: CallInterceptor): List<KTypeProjection> {
|
||||
if (_arguments != null) return _arguments!!
|
||||
Wrapper.associateJavaClassWithIrClass(KTypeProjection::class.java, irClass.getIrClassOfReflectionFromList("arguments"))
|
||||
_arguments = (irType as IrSimpleType).arguments
|
||||
.map {
|
||||
when (it.getVariance()) {
|
||||
Variance.INVARIANT -> KTypeProjection.invariant(KTypeProxy(KTypeState(it.typeOrNull!!, irClass), callInterceptor))
|
||||
Variance.IN_VARIANCE -> KTypeProjection.contravariant(KTypeProxy(KTypeState(it.typeOrNull!!, irClass), callInterceptor))
|
||||
Variance.OUT_VARIANCE -> KTypeProjection.covariant(KTypeProxy(KTypeState(it.typeOrNull!!, irClass), callInterceptor))
|
||||
null -> KTypeProjection.STAR
|
||||
}
|
||||
}
|
||||
return _arguments!!
|
||||
}
|
||||
|
||||
private fun IrTypeArgument.getVariance(): Variance? {
|
||||
return when (this) {
|
||||
is IrSimpleType -> Variance.INVARIANT
|
||||
is IrTypeProjection -> this.variance
|
||||
is IrStarProjection -> null
|
||||
else -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KTypeState
|
||||
|
||||
if (irType != other.irType) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return irType.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return irType.renderType()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.interpreter.state.reflection
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.interpreter.renderType
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.State
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
|
||||
internal abstract class ReflectionState : State {
|
||||
override val fields: MutableList<Variable> = mutableListOf()
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null
|
||||
|
||||
protected fun IrClass.getIrClassOfReflectionFromList(name: String): IrClass {
|
||||
val property = this.declarations.single { it.nameForIrSerialization.asString() == name } as IrProperty
|
||||
val list = property.getter!!.returnType as IrSimpleType
|
||||
return list.arguments.single().typeOrNull!!.classOrNull!!.owner
|
||||
}
|
||||
|
||||
protected fun IrClass.getIrClassOfReflection(name: String): IrClass {
|
||||
val property = this.declarations.single { it.nameForIrSerialization.asString() == name } as IrProperty
|
||||
val type = property.getter!!.returnType as IrSimpleType
|
||||
return type.classOrNull!!.owner
|
||||
}
|
||||
|
||||
private fun renderReceivers(dispatchReceiver: IrType?, extensionReceiver: IrType?): String {
|
||||
return buildString {
|
||||
if (dispatchReceiver != null) {
|
||||
append(dispatchReceiver.renderType())
|
||||
append(".")
|
||||
}
|
||||
val addParentheses = dispatchReceiver != null && extensionReceiver != null
|
||||
if (addParentheses) append("(")
|
||||
if (extensionReceiver != null) {
|
||||
append(extensionReceiver.renderType())
|
||||
append(".")
|
||||
}
|
||||
if (addParentheses) append(")")
|
||||
}
|
||||
}
|
||||
|
||||
protected fun renderLambda(irFunction: IrFunction): String {
|
||||
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.renderType()
|
||||
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.renderType() }
|
||||
val returnType = irFunction.returnType.renderType()
|
||||
return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it }
|
||||
}
|
||||
|
||||
protected fun renderFunction(irFunction: IrFunction): String {
|
||||
val dispatchReceiver = irFunction.parentClassOrNull?.defaultType // = instanceReceiverParameter
|
||||
val extensionReceiver = irFunction.extensionReceiverParameter?.type
|
||||
val receivers = if (irFunction is IrConstructor) "" else renderReceivers(dispatchReceiver, extensionReceiver)
|
||||
val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.renderType() }
|
||||
val returnType = irFunction.returnType.renderType()
|
||||
return "fun $receivers${irFunction.name}$arguments: $returnType"
|
||||
}
|
||||
|
||||
protected fun renderProperty(property: IrProperty): String {
|
||||
val prefix = if (property.isVar) "var" else "val"
|
||||
val receivers = renderReceivers(property.getter?.dispatchReceiverParameter?.type, property.getter?.extensionReceiverParameter?.type)
|
||||
val returnType = property.getter!!.returnType.renderType()
|
||||
return "$prefix $receivers${property.name}: $returnType"
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.builders.declarations
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
|
||||
class IrClassBuilder : IrDeclarationBuilder() {
|
||||
@@ -20,6 +21,7 @@ class IrClassBuilder : IrDeclarationBuilder() {
|
||||
var isInline: Boolean = false
|
||||
var isExpect: Boolean = false
|
||||
var isFun: Boolean = false
|
||||
var source: SourceElement = SourceElement.NO_SOURCE
|
||||
|
||||
fun updateFrom(from: IrClass) {
|
||||
super.updateFrom(from)
|
||||
@@ -33,5 +35,6 @@ class IrClassBuilder : IrDeclarationBuilder() {
|
||||
isInline = from.isInline
|
||||
isExpect = from.isExpect
|
||||
isFun = from.isFun
|
||||
source = from.source
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,12 @@ import org.jetbrains.kotlin.name.Name
|
||||
interface MetadataSource {
|
||||
val name: Name?
|
||||
|
||||
interface File : MetadataSource
|
||||
interface Class : MetadataSource
|
||||
interface File : MetadataSource {
|
||||
var serializedIr: ByteArray?
|
||||
}
|
||||
interface Class : MetadataSource {
|
||||
var serializedIr: ByteArray?
|
||||
}
|
||||
interface Function : MetadataSource
|
||||
interface Property : MetadataSource {
|
||||
val isConst: Boolean
|
||||
@@ -26,9 +30,13 @@ sealed class DescriptorMetadataSource : MetadataSource {
|
||||
override val name: Name?
|
||||
get() = descriptor?.name
|
||||
|
||||
class File(val descriptors: List<DeclarationDescriptor>) : DescriptorMetadataSource(), MetadataSource.File
|
||||
class File(val descriptors: List<DeclarationDescriptor>) : DescriptorMetadataSource(), MetadataSource.File {
|
||||
override var serializedIr: ByteArray? = null
|
||||
}
|
||||
|
||||
class Class(override val descriptor: ClassDescriptor) : DescriptorMetadataSource(), MetadataSource.Class
|
||||
class Class(override val descriptor: ClassDescriptor) : DescriptorMetadataSource(), MetadataSource.Class {
|
||||
override var serializedIr: ByteArray? = null
|
||||
}
|
||||
|
||||
class Function(override val descriptor: FunctionDescriptor) : DescriptorMetadataSource(), MetadataSource.Function
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
|
||||
class IrExternalPackageFragmentImpl(
|
||||
override val symbol: IrExternalPackageFragmentSymbol,
|
||||
override val fqName: FqName
|
||||
override val fqName: FqName,
|
||||
private val _containerSource: DeserializedContainerSource? = null
|
||||
) : IrExternalPackageFragment() {
|
||||
override val startOffset: Int
|
||||
get() = UNDEFINED_OFFSET
|
||||
@@ -53,7 +54,8 @@ class IrExternalPackageFragmentImpl(
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
override val containerSource: DeserializedContainerSource?
|
||||
get() = (symbol.descriptor as? DeserializedMemberDescriptor)?.containerSource
|
||||
get() = _containerSource ?:
|
||||
(symbol.descriptor as? DeserializedMemberDescriptor)?.containerSource
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitExternalPackageFragment(this, data)
|
||||
|
||||
@@ -594,3 +594,9 @@ fun IrExpression?.isPure(anyVariable: Boolean, checkFields: Boolean = true): Boo
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
val IrDeclarationParent.isFacadeClass: Boolean
|
||||
get() = this is IrClass &&
|
||||
(origin == IrDeclarationOrigin.JVM_MULTIFILE_CLASS ||
|
||||
origin == IrDeclarationOrigin.FILE_CLASS ||
|
||||
origin == IrDeclarationOrigin.SYNTHETIC_FILE_CLASS)
|
||||
@@ -52,6 +52,8 @@ interface ReferenceSymbolTable {
|
||||
fun referenceTypeParameterFromLinker(sig: IdSignature): IrTypeParameterSymbol
|
||||
fun referenceTypeAliasFromLinker(sig: IdSignature): IrTypeAliasSymbol
|
||||
|
||||
fun storeConstructorBySignature(sig: IdSignature, declaration: IrConstructor)
|
||||
|
||||
fun enterScope(owner: IrSymbol)
|
||||
fun enterScope(owner: IrDeclaration)
|
||||
|
||||
@@ -74,6 +76,7 @@ class SymbolTable(
|
||||
abstract fun get(d: D): S?
|
||||
abstract fun set(s: S)
|
||||
abstract fun get(sig: IdSignature): S?
|
||||
abstract fun set(sig: IdSignature, s: S)
|
||||
|
||||
inline fun declare(d: D, createSymbol: () -> S, createOwner: (S) -> B): B {
|
||||
synchronized(this) {
|
||||
@@ -214,6 +217,10 @@ class SymbolTable(
|
||||
}
|
||||
|
||||
override fun get(sig: IdSignature): S? = idSigToSymbol[sig]
|
||||
|
||||
override fun set(sig: IdSignature, s: S) {
|
||||
idSigToSymbol[sig] = s
|
||||
}
|
||||
}
|
||||
|
||||
private inner class EnumEntrySymbolTable : FlatSymbolTable<ClassDescriptor, IrEnumEntry, IrEnumEntrySymbol>() {
|
||||
@@ -247,6 +254,10 @@ class SymbolTable(
|
||||
}
|
||||
}
|
||||
|
||||
operator fun set(sig: IdSignature, s: S) {
|
||||
idSigToSymbol[sig] = s
|
||||
}
|
||||
|
||||
fun getLocal(d: D) = descriptorToSymbol[d]
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
@@ -293,6 +304,12 @@ class SymbolTable(
|
||||
return scope[sig]
|
||||
}
|
||||
|
||||
|
||||
override fun set(sig: IdSignature, s: S) {
|
||||
val scope = currentScope ?: throw AssertionError("No active scope")
|
||||
scope[sig] = s
|
||||
}
|
||||
|
||||
inline fun declareLocal(d: D, createSymbol: () -> S, createOwner: (S) -> B): B {
|
||||
val scope = currentScope ?: throw AssertionError("No active scope")
|
||||
val symbol = scope.getLocal(d) ?: createSymbol().also { scope[d] = it }
|
||||
@@ -525,6 +542,10 @@ class SymbolTable(
|
||||
else IrConstructorSymbolImpl()
|
||||
}
|
||||
|
||||
override fun storeConstructorBySignature(sig: IdSignature, declaration: IrConstructor) {
|
||||
if (sig.isPublic) constructorSymbolTable.set(sig, declaration.symbol)
|
||||
}
|
||||
|
||||
val unboundConstructors: Set<IrConstructorSymbol> get() = constructorSymbolTable.unboundSymbols
|
||||
|
||||
private fun createEnumEntrySymbol(descriptor: ClassDescriptor): IrEnumEntrySymbol {
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration.DeclaratorCase.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType.KindCase.*
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
@@ -58,7 +59,7 @@ class IrDeclarationDeserializer(
|
||||
private val symbolTable: SymbolTable,
|
||||
private val irFactory: IrFactory,
|
||||
private val fileReader: IrLibraryFile,
|
||||
file: IrFile,
|
||||
packageFragment: IrPackageFragment,
|
||||
private val allowErrorNodes: Boolean,
|
||||
private val deserializeInlineFunctions: Boolean,
|
||||
private var deserializeBodies: Boolean,
|
||||
@@ -69,6 +70,8 @@ class IrDeclarationDeserializer(
|
||||
|
||||
private val bodyDeserializer = IrBodyDeserializer(builtIns, allowErrorNodes, irFactory, fileReader, this)
|
||||
|
||||
private val containerSource = (packageFragment as? IrExternalPackageFragment)?.containerSource
|
||||
|
||||
private fun deserializeName(index: Int): Name {
|
||||
val name = fileReader.deserializeString(index)
|
||||
return Name.guessByFirstCharacter(name)
|
||||
@@ -154,7 +157,7 @@ class IrDeclarationDeserializer(
|
||||
}
|
||||
}
|
||||
|
||||
private var currentParent: IrDeclarationParent = file
|
||||
private var currentParent: IrDeclarationParent = packageFragment
|
||||
|
||||
private inline fun <T : IrDeclarationParent> T.usingParent(block: T.() -> Unit): T =
|
||||
this.apply {
|
||||
@@ -272,7 +275,7 @@ class IrDeclarationDeserializer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeIrClass(proto: ProtoClass): IrClass =
|
||||
fun deserializeIrClass(proto: ProtoClass, source: SourceElement = SourceElement.NO_SOURCE): IrClass =
|
||||
withDeserializedIrDeclarationBase(proto.base) { symbol, signature, startOffset, endOffset, origin, fcode ->
|
||||
val flags = ClassFlags.decode(fcode)
|
||||
|
||||
@@ -291,6 +294,7 @@ class IrDeclarationDeserializer(
|
||||
flags.isInline,
|
||||
flags.isExpect,
|
||||
flags.isFun,
|
||||
source,
|
||||
)
|
||||
}.usingParent {
|
||||
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
|
||||
@@ -490,7 +494,8 @@ class IrDeclarationDeserializer(
|
||||
flags.isOperator,
|
||||
flags.isInfix,
|
||||
flags.isExpect,
|
||||
flags.isFakeOverride
|
||||
flags.isFakeOverride,
|
||||
containerSource
|
||||
)
|
||||
}.apply {
|
||||
overriddenSymbols = proto.overriddenList.map { deserializeIrSymbolAndRemap(it) as IrSimpleFunctionSymbol }
|
||||
@@ -617,7 +622,8 @@ class IrDeclarationDeserializer(
|
||||
flags.isDelegated,
|
||||
flags.isExternal,
|
||||
flags.isExpect,
|
||||
flags.isFakeOverride
|
||||
flags.isFakeOverride,
|
||||
containerSource
|
||||
)
|
||||
}.apply {
|
||||
if (proto.hasGetter()) {
|
||||
|
||||
@@ -146,12 +146,12 @@ class IrLibraryFileFromKlib(private val klib: IrLibrary, private val fileIndex:
|
||||
override fun body(index: Int): ByteArray = klib.body(index, fileIndex)
|
||||
}
|
||||
|
||||
internal fun IrLibraryFile.deserializeString(index: Int): String = String(string(index))
|
||||
fun IrLibraryFile.deserializeString(index: Int): String = String(string(index))
|
||||
|
||||
internal fun IrLibraryFile.deserializeFqName(fqn: List<Int>): String =
|
||||
fqn.joinToString(".", transform = ::deserializeString)
|
||||
|
||||
internal fun IrLibraryFile.createFile(moduleDescriptor: ModuleDescriptor, fileProto: ProtoFile): IrFile {
|
||||
fun IrLibraryFile.createFile(moduleDescriptor: ModuleDescriptor, fileProto: ProtoFile): IrFile {
|
||||
val fileName = fileProto.fileEntry.name
|
||||
val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray())
|
||||
val fqName = FqName(deserializeFqName(fileProto.fqNameList))
|
||||
|
||||
@@ -119,17 +119,17 @@ open class IrFileSerializer(
|
||||
// The same type can be used multiple times in a file
|
||||
// so use this index to store type data only once.
|
||||
private val protoTypeMap = mutableMapOf<IrTypeKey, Int>()
|
||||
private val protoTypeArray = arrayListOf<ProtoType>()
|
||||
protected val protoTypeArray = arrayListOf<ProtoType>()
|
||||
|
||||
private val protoStringMap = mutableMapOf<String, Int>()
|
||||
private val protoStringArray = arrayListOf<String>()
|
||||
protected val protoStringArray = arrayListOf<String>()
|
||||
|
||||
// The same signature could be used multiple times in a file
|
||||
// so use this index to store signature only once.
|
||||
private val protoIdSignatureMap = mutableMapOf<IdSignature, Int>()
|
||||
private val protoIdSignatureArray = arrayListOf<ProtoIdSignature>()
|
||||
protected val protoIdSignatureArray = arrayListOf<ProtoIdSignature>()
|
||||
|
||||
private val protoBodyArray = mutableListOf<XStatementOrExpression>()
|
||||
protected val protoBodyArray = mutableListOf<XStatementOrExpression>()
|
||||
|
||||
sealed class XStatementOrExpression {
|
||||
abstract fun toByteArray(): ByteArray
|
||||
@@ -178,7 +178,7 @@ open class IrFileSerializer(
|
||||
protoStringArray.size - 1
|
||||
}
|
||||
|
||||
private fun serializeName(name: Name): Int = serializeString(name.toString())
|
||||
protected fun serializeName(name: Name): Int = serializeString(name.toString())
|
||||
|
||||
/* ------- IdSignature ------------------------------------------------------ */
|
||||
|
||||
@@ -232,7 +232,7 @@ open class IrFileSerializer(
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
private fun protoIdSignature(declaration: IrDeclaration): Int {
|
||||
protected fun protoIdSignature(declaration: IrDeclaration): Int {
|
||||
val idSig = declarationTable.signatureByDeclaration(declaration)
|
||||
return protoIdSignature(idSig)
|
||||
}
|
||||
@@ -283,7 +283,7 @@ open class IrFileSerializer(
|
||||
TODO("Unexpected symbol kind: $symbol")
|
||||
}
|
||||
|
||||
fun serializeIrSymbol(symbol: IrSymbol): Long {
|
||||
open fun serializeIrSymbol(symbol: IrSymbol): Long {
|
||||
val declaration = symbol.owner as? IrDeclaration ?: error("Expected IrDeclaration: ${symbol.owner.render()}")
|
||||
|
||||
val symbolKind = protoSymbolKind(symbol)
|
||||
@@ -294,10 +294,10 @@ open class IrFileSerializer(
|
||||
|
||||
/* ------- IrTypes ---------------------------------------------------------- */
|
||||
|
||||
private fun serializeAnnotations(annotations: List<IrConstructorCall>) =
|
||||
protected fun serializeAnnotations(annotations: List<IrConstructorCall>) =
|
||||
annotations.map { serializeConstructorCall(it) }
|
||||
|
||||
private fun serializeFqName(fqName: String): List<Int> = fqName.split(".").map(::serializeString)
|
||||
protected fun serializeFqName(fqName: String): List<Int> = fqName.split(".").map(::serializeString)
|
||||
|
||||
private fun serializeIrStarProjection() = BinaryTypeProjection.STAR_CODE
|
||||
|
||||
@@ -1130,7 +1130,7 @@ open class IrFileSerializer(
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
private fun serializeIrClass(clazz: IrClass): ProtoClass {
|
||||
protected fun serializeIrClass(clazz: IrClass): ProtoClass {
|
||||
val proto = ProtoClass.newBuilder()
|
||||
.setBase(serializeIrDeclarationBase(clazz, ClassFlags.encode(clazz)))
|
||||
.setName(serializeName(clazz.name))
|
||||
@@ -1185,7 +1185,7 @@ open class IrFileSerializer(
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
private fun serializeDeclaration(declaration: IrDeclaration): ProtoDeclaration {
|
||||
protected fun serializeDeclaration(declaration: IrDeclaration): ProtoDeclaration {
|
||||
val proto = ProtoDeclaration.newBuilder()
|
||||
|
||||
when (declaration) {
|
||||
|
||||
@@ -199,13 +199,7 @@ abstract class DescriptorMangleComputer(protected val builder: StringBuilder, pr
|
||||
is DynamicType -> tBuilder.appendSignature(MangleConstant.DYNAMIC_MARK)
|
||||
is FlexibleType -> {
|
||||
// TODO: is that correct way to mangle flexible type?
|
||||
with(MangleConstant.FLEXIBLE_TYPE) {
|
||||
tBuilder.appendSignature(prefix)
|
||||
mangleType(tBuilder, type.lowerBound)
|
||||
tBuilder.appendSignature(separator)
|
||||
mangleType(tBuilder, type.upperBound)
|
||||
tBuilder.appendSignature(suffix)
|
||||
}
|
||||
mangleType(tBuilder, type.upperBound)
|
||||
}
|
||||
else -> error("Unexpected type $wtype")
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isVararg
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -257,7 +255,8 @@ abstract class IrMangleComputer(protected val builder: StringBuilder, private va
|
||||
isRealExpect = isRealExpect or declaration.isExpect
|
||||
|
||||
val container = declaration.correspondingPropertySymbol?.owner ?: declaration
|
||||
val isStatic = declaration.dispatchReceiverParameter == null && container.parent !is IrPackageFragment
|
||||
val isStatic = declaration.dispatchReceiverParameter == null &&
|
||||
(container.parent !is IrPackageFragment && !container.parent.isFacadeClass)
|
||||
|
||||
declaration.mangleFunction(false, isStatic, container)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.overrides.isOverridableFunction
|
||||
import org.jetbrains.kotlin.ir.overrides.isOverridableProperty
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.KotlinMangler
|
||||
import org.jetbrains.kotlin.ir.util.isFacadeClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -49,7 +50,9 @@ open class IdSignatureSerializer(val mangler: KotlinMangler.IrMangler) : IdSigna
|
||||
|
||||
private fun collectFqNames(declaration: IrDeclarationWithName) {
|
||||
declaration.parent.acceptVoid(this)
|
||||
classFqnSegments.add(declaration.name.asString())
|
||||
if (declaration !is IrClass || !declaration.isFacadeClass) {
|
||||
classFqnSegments.add(declaration.name.asString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) = error("Unexpected element ${element.render()}")
|
||||
@@ -95,6 +98,10 @@ open class IdSignatureSerializer(val mangler: KotlinMangler.IrMangler) : IdSigna
|
||||
override fun visitEnumEntry(declaration: IrEnumEntry) {
|
||||
collectFqNames(declaration)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
collectFqNames(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
private val publicSignatureBuilder = PublicIdSigBuilder()
|
||||
|
||||
@@ -11,6 +11,7 @@ dependencies {
|
||||
compile(project(":core:metadata.jvm"))
|
||||
implementation(project(":core:deserialization.common.jvm"))
|
||||
compile(project(":compiler:frontend.java"))
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
84
compiler/ir/serialization.jvm/src/JvmIr.proto
Normal file
84
compiler/ir/serialization.jvm/src/JvmIr.proto
Normal file
@@ -0,0 +1,84 @@
|
||||
syntax = "proto2";
|
||||
package org.jetbrains.kotlin.backend.jvm.serialization.proto;
|
||||
import "compiler/ir/serialization.common/src/KotlinIr.proto";
|
||||
|
||||
option java_outer_classname = "JvmIr";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
/* Stored in JVM .class annotations */
|
||||
|
||||
//message UniqIdInfo {
|
||||
// required fixed64 id = 1;
|
||||
// repeated int32 toplevel_fq_name = 2;
|
||||
//}
|
||||
|
||||
//message SignatureTable {
|
||||
// repeated common.serialization.proto.IrSignature signature = 1;
|
||||
//}
|
||||
//
|
||||
//message TypeTable {
|
||||
// repeated common.serialization.proto.IrType type = 1;
|
||||
//}
|
||||
|
||||
//message UniqIdTable {
|
||||
// repeated UniqIdInfo infos = 1;
|
||||
//}
|
||||
|
||||
//message StringTable {
|
||||
// repeated string string = 1;
|
||||
//}
|
||||
|
||||
message XStatementOrExpression {
|
||||
oneof kind {
|
||||
common.serialization.proto.IrStatement statement = 1;
|
||||
common.serialization.proto.IrExpression expression = 2;
|
||||
}
|
||||
}
|
||||
|
||||
//message StatementsAndExpressionsTable {
|
||||
// repeated XStatementOrExpression statement_or_expression = 1;
|
||||
//}
|
||||
|
||||
message FacadeClassInfo {
|
||||
required int32 signature = 1; /* signature index for a file-level declaration */
|
||||
required int32 facade_class_name = 2; /* string index for file class name */
|
||||
}
|
||||
|
||||
//
|
||||
//message JvmExternalPackage {
|
||||
// repeated int32 fq_name = 1;
|
||||
// required common.serialization.proto.IrDeclarationContainer declaration_container = 2;
|
||||
//}
|
||||
|
||||
//message ExternalRefs {
|
||||
// repeated JvmExternalPackage package = 1;
|
||||
// repeated ExternalReference reference = 2;
|
||||
//}
|
||||
|
||||
message AuxTables {
|
||||
repeated bytes type = 1;
|
||||
repeated bytes signature = 2;
|
||||
repeated bytes string = 3;
|
||||
repeated bytes body = 4;
|
||||
repeated FacadeClassInfo facade_class_info = 5;
|
||||
|
||||
// required TypeTable type_table = 2;
|
||||
// required SignatureTable signature_table = 1;
|
||||
// required StringTable string_table = 3;
|
||||
// required StatementsAndExpressionsTable statements_and_expressions_table = 4;
|
||||
|
||||
// required ExternalRefs external_refs = 5;
|
||||
// required UniqIdTable uniq_id_table = 6;
|
||||
}
|
||||
|
||||
message JvmIrFile {
|
||||
repeated common.serialization.proto.IrDeclaration declaration = 1;
|
||||
repeated common.serialization.proto.IrConstructorCall annotation = 2;
|
||||
required int32 facade_fq_name = 3;
|
||||
required AuxTables aux_tables = 4;
|
||||
}
|
||||
|
||||
message JvmIrClass {
|
||||
required common.serialization.proto.IrClass ir_class = 1;
|
||||
required AuxTables aux_tables = 2;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.jvm.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.GlobalDeclarationTable
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerIr
|
||||
|
||||
class JvmGlobalDeclarationTable : GlobalDeclarationTable(IdSignatureSerializer(JvmManglerIr), JvmManglerIr)
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.jvm.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
|
||||
import org.jetbrains.kotlin.backend.common.serialization.IrFileSerializer
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.proto.JvmIr
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.fileClasses.JvmSimpleFileClassInfo
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
|
||||
import org.jetbrains.kotlin.ir.util.isFacadeClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.ByteString
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
|
||||
class JvmIrSerializer(
|
||||
messageLogger: IrMessageLogger,
|
||||
declarationTable: DeclarationTable,
|
||||
expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>,
|
||||
private val psiSourceManager: PsiSourceManager,
|
||||
externallyVisibleOnly: Boolean = true,
|
||||
skipExpects: Boolean = false,
|
||||
) : IrFileSerializer(messageLogger, declarationTable, expectDescriptorToSymbol, externallyVisibleOnly, skipExpects) {
|
||||
|
||||
// Usage protocol: construct an instance, call only one of `serializeIrFile()` and `serializeTopLevelClass()` only once.
|
||||
|
||||
private class FacadeClassInfo(val signature: Int, val facadeName: Int)
|
||||
|
||||
private val facadeInfoArray = mutableListOf<FacadeClassInfo>()
|
||||
|
||||
fun serializeJvmIrFile(irFile: IrFile): JvmIr.JvmIrFile {
|
||||
val proto = JvmIr.JvmIrFile.newBuilder()
|
||||
|
||||
irFile.declarations.filter { it !is IrClass }.forEach { declaration ->
|
||||
proto.addDeclaration(serializeDeclaration(declaration))
|
||||
}
|
||||
proto.addAllAnnotation(serializeAnnotations(irFile.annotations))
|
||||
|
||||
|
||||
val facadeFqName = irFile.facadeFqName()
|
||||
proto.addAllFacadeFqName(serializeFqName(facadeFqName.toString()))
|
||||
|
||||
// TODO -- serialize referencesToTopLevelMap
|
||||
proto.auxTables = serializeAuxTables()
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeTopLevelClass(irClass: IrClass): JvmIr.JvmIrClass {
|
||||
val proto = JvmIr.JvmIrClass.newBuilder()
|
||||
proto.irClass = serializeIrClass(irClass)
|
||||
proto.auxTables = serializeAuxTables()
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
override fun serializeIrSymbol(symbol: IrSymbol): Long {
|
||||
val declaration = symbol.owner as? IrDeclaration ?: error("Expected IrDeclaration: ${symbol.owner.render()}")
|
||||
val parent = declaration.parent
|
||||
if ((parent is IrPackageFragment || parent.isFacadeClass) && declaration is IrMemberWithContainerSource && declaration !is IrClass) {
|
||||
val facadeClassName = declaration.facadeName() ?: return super.serializeIrSymbol(symbol)
|
||||
val facadeId = serializeName(facadeClassName)
|
||||
val signatureId = protoIdSignature(declaration)
|
||||
facadeInfoArray.add(FacadeClassInfo(signatureId, facadeId))
|
||||
}
|
||||
|
||||
return super.serializeIrSymbol(symbol)
|
||||
}
|
||||
|
||||
private fun serializeAuxTables(): JvmIr.AuxTables {
|
||||
val proto = JvmIr.AuxTables.newBuilder()
|
||||
protoTypeArray.forEach { proto.addType(it.toByteString()) }
|
||||
protoIdSignatureArray.forEach { proto.addSignature(it.toByteString()) }
|
||||
protoStringArray.forEach { proto.addString(ByteString.copyFromUtf8(it)) }
|
||||
protoBodyArray.forEach { proto.addBody(ByteString.copyFrom(it.toByteArray())) }
|
||||
facadeInfoArray.forEach {
|
||||
proto.addFacadeClassInfo(JvmIr.FacadeClassInfo.newBuilder().run {
|
||||
signature = it.signature
|
||||
facadeClassName = it.facadeName
|
||||
build()
|
||||
})
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun IrFile.facadeFqName(): FqName {
|
||||
val fileClassInfo = when (val fileEntry = fileEntry) {
|
||||
is PsiSourceManager.PsiFileEntry -> {
|
||||
val ktFile = psiSourceManager.getKtFile(fileEntry)
|
||||
?: throw AssertionError("Unexpected file entry: $fileEntry")
|
||||
JvmFileClassUtil.getFileClassInfoNoResolve(ktFile)
|
||||
}
|
||||
is NaiveSourceBasedFileEntryImpl -> {
|
||||
JvmSimpleFileClassInfo(PackagePartClassUtils.getPackagePartFqName(fqName, fileEntry.name), false)
|
||||
}
|
||||
else -> error("unknown kind of file entry: $fileEntry")
|
||||
}
|
||||
return fileClassInfo.fileClassFqName
|
||||
}
|
||||
|
||||
fun IrMemberWithContainerSource.facadeName(): Name? {
|
||||
val parent = parent
|
||||
if (this is IrClass) return null
|
||||
return when (parent) {
|
||||
is IrFile -> parent.facadeFqName().shortName()
|
||||
is IrClass -> {
|
||||
assert(parent.isFacadeClass)
|
||||
parent.name
|
||||
}
|
||||
is IrExternalPackageFragment -> {
|
||||
val source = containerSource as? JvmPackagePartSource ?: return null
|
||||
val facadeName = source.facadeClassName ?: source.className
|
||||
facadeName.fqNameForTopLevelClassMaybeWithDollars.shortName()
|
||||
}
|
||||
else -> error("Unknown IrPackageFragment kind: $parent")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.jvm.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.backend.common.overrides.DefaultFakeOverrideClassFilter
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker
|
||||
import org.jetbrains.kotlin.backend.common.serialization.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
|
||||
import org.jetbrains.kotlin.backend.jvm.serialization.proto.JvmIr
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerIr
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.linkage.IrProvider
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.load.kotlin.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.ByteString
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
/* Reads serialized IR from annotations in classfiles */
|
||||
class SingleClassJvmIrProvider(
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val irBuiltIns: IrBuiltIns,
|
||||
val symbolTable: SymbolTable,
|
||||
val irFactory: IrFactory,
|
||||
val fileFinder: VirtualFileFinder,
|
||||
) : IrProvider, FileLocalAwareLinker {
|
||||
|
||||
val descriptorFinder =
|
||||
DescriptorByIdSignatureFinder(moduleDescriptor, JvmManglerDesc(), DescriptorByIdSignatureFinder.LookupMode.MODULE_WITH_DEPENDENCIES)
|
||||
|
||||
val packageFragments = mutableMapOf<FqName, IrExternalPackageFragment>()
|
||||
|
||||
val facadeClassMap = mutableMapOf<IdSignature, Name>()
|
||||
|
||||
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? {
|
||||
val fileClassInfo = findFacadeClassInfo(symbol)
|
||||
if (fileClassInfo != null)
|
||||
loadIrFileFromFacadeClass(fileClassInfo.first, fileClassInfo.second)
|
||||
else
|
||||
symbol.signature?.let { loadToplevelClassBySignature(it) }
|
||||
return if (symbol.isBound) (symbol.owner as IrDeclaration) else null
|
||||
}
|
||||
|
||||
private fun loadIrFileFromFacadeClass(fileClassName: FqName, facadeName: FqName) {
|
||||
val vfile = fileFinder.findVirtualFileWithHeader(ClassId.topLevel(fileClassName)) ?: return
|
||||
val binaryClass = KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(vfile)?.toKotlinJvmBinaryClass() ?: return
|
||||
val classHeader = binaryClass.classHeader
|
||||
if (classHeader.serializedIr == null || classHeader.serializedIr!!.isEmpty()) return
|
||||
|
||||
val containerSource = getJvmPackagePartSource(binaryClass)
|
||||
|
||||
val irProto = JvmIr.JvmIrFile.parseFrom(classHeader.serializedIr)
|
||||
val packageFragment = getPackageFragment(facadeName.parent(), containerSource)
|
||||
val declarationDeserializer = getDeclarationDeserializer(packageFragment, irProto.auxTables)
|
||||
val facadeClass = irFactory.buildClass {
|
||||
name = facadeName.shortName()
|
||||
origin = IrDeclarationOrigin.SYNTHETIC_FILE_CLASS
|
||||
source = containerSource
|
||||
}.apply {
|
||||
parent = packageFragment
|
||||
createParameterDeclarations()
|
||||
// TODO: annotations
|
||||
}
|
||||
for (declProto in irProto.declarationList) {
|
||||
val declaration = declarationDeserializer.deserializeDeclaration(declProto)
|
||||
facadeClass.addMember(declaration)
|
||||
declaration.parent = facadeClass
|
||||
if (declaration is IrProperty) {
|
||||
declaration.getter?.parent = facadeClass
|
||||
declaration.setter?.parent = facadeClass
|
||||
declaration.backingField?.parent = facadeClass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadToplevelClassBySignature(signature: IdSignature) {
|
||||
if (signature !is IdSignature.PublicSignature) return
|
||||
val classId = ClassId.topLevel(signature.packageFqName().child(Name.identifier(signature.firstNameSegment)))
|
||||
val toplevelDescriptor = moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: return
|
||||
|
||||
/* TODO: should not be needed after we deal with fake overrides. */
|
||||
if (symbolTable.referenceClass(toplevelDescriptor).isBound) return
|
||||
|
||||
val source = toplevelDescriptor.source as? KotlinJvmBinarySourceElement ?: return
|
||||
val classHeader = source.binaryClass.classHeader
|
||||
if (classHeader.serializedIr == null || classHeader.serializedIr!!.isEmpty()) return
|
||||
|
||||
val irProto = JvmIr.JvmIrClass.parseFrom(classHeader.serializedIr)
|
||||
val packageFragment = getPackageFragment(signature.packageFqName(), source)
|
||||
val declarationDeserializer = getDeclarationDeserializer(packageFragment, irProto.auxTables)
|
||||
|
||||
declarationDeserializer.deserializeIrClass(irProto.irClass, source)
|
||||
}
|
||||
|
||||
private fun getDeclarationDeserializer(packageFragment: IrPackageFragment, auxTables: JvmIr.AuxTables): IrDeclarationDeserializer {
|
||||
val libraryFile = IrLibraryFileFromAnnotation(
|
||||
auxTables.typeList,
|
||||
auxTables.signatureList,
|
||||
auxTables.stringList,
|
||||
auxTables.bodyList
|
||||
)
|
||||
|
||||
val symbolDeserializer = IrSymbolDeserializer(
|
||||
symbolTable,
|
||||
libraryFile,
|
||||
/* TODO */ actuals = emptyList(),
|
||||
enqueueLocalTopLevelDeclaration = {}, // just link to it in symbolTable
|
||||
handleExpectActualMapping = { _, _ -> TODO() },
|
||||
deserializePublicSymbol = ::referencePublicSymbol
|
||||
)
|
||||
|
||||
populateFacadeClassMap(auxTables, libraryFile, symbolDeserializer)
|
||||
|
||||
return IrDeclarationDeserializer(
|
||||
irBuiltIns,
|
||||
symbolTable,
|
||||
irFactory,
|
||||
libraryFile,
|
||||
packageFragment,
|
||||
allowErrorNodes = false,
|
||||
deserializeInlineFunctions = true,
|
||||
deserializeBodies = true,
|
||||
symbolDeserializer = symbolDeserializer,
|
||||
platformFakeOverrideClassFilter = DefaultFakeOverrideClassFilter,
|
||||
fakeOverrideBuilder = FakeOverrideBuilder(
|
||||
linker = this,
|
||||
symbolTable,
|
||||
IdSignatureSerializer(JvmManglerIr),
|
||||
irBuiltIns
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun id(x: Any?): Any? = x
|
||||
|
||||
class IrLibraryFileFromAnnotation(
|
||||
val types: List<ByteString>,
|
||||
val signatures: List<ByteString>,
|
||||
val strings: List<ByteString>,
|
||||
val bodies: List<ByteString>,
|
||||
) : IrLibraryFile() {
|
||||
override fun irDeclaration(index: Int): ByteArray {
|
||||
error("This method is never supposed to be called")
|
||||
}
|
||||
|
||||
override fun type(index: Int): ByteArray = types[index].toByteArray()
|
||||
override fun signature(index: Int): ByteArray = signatures[index].toByteArray()
|
||||
override fun string(index: Int): ByteArray = strings[index].toByteArray()
|
||||
override fun body(index: Int): ByteArray = bodies[index].toByteArray()
|
||||
}
|
||||
|
||||
private fun getPackageFragment(fqName: FqName, containerSource: DeserializedContainerSource?): IrExternalPackageFragment =
|
||||
IrExternalPackageFragmentImpl(
|
||||
IrExternalPackageFragmentSymbolImpl(object : PackageFragmentDescriptorImpl(moduleDescriptor, fqName) {
|
||||
override fun getMemberScope() = MemberScope.Empty
|
||||
}),
|
||||
fqName,
|
||||
containerSource
|
||||
)
|
||||
|
||||
private fun referencePublicSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||
with(symbolTable) {
|
||||
val descriptor = descriptorFinder.findDescriptorBySignature(idSig)
|
||||
return if (descriptor != null) {
|
||||
when (symbolKind) {
|
||||
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClass(descriptor as ClassDescriptor)
|
||||
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructor(descriptor as ClassConstructorDescriptor)
|
||||
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntry(descriptor as ClassDescriptor)
|
||||
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceField(descriptor as PropertyDescriptor)
|
||||
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunction(descriptor as FunctionDescriptor)
|
||||
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAlias(descriptor as TypeAliasDescriptor)
|
||||
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referenceProperty(descriptor as PropertyDescriptor)
|
||||
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
|
||||
}
|
||||
} else {
|
||||
when (symbolKind) {
|
||||
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(idSig)
|
||||
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(idSig)
|
||||
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun populateFacadeClassMap(auxTables: JvmIr.AuxTables, libraryFile: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer) {
|
||||
for (protoFacadeClassInfo in auxTables.facadeClassInfoList) {
|
||||
val signature = symbolDeserializer.deserializeIdSignature(protoFacadeClassInfo.signature)
|
||||
val name = Name.identifier(libraryFile.deserializeString(protoFacadeClassInfo.facadeClassName))
|
||||
facadeClassMap[signature] = name
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
private fun findFacadeClassInfo(symbol: IrSymbol): Pair<FqName, FqName>? {
|
||||
if (symbol.hasDescriptor) {
|
||||
var descriptor = symbol.descriptor
|
||||
if (descriptor is CallableMemberDescriptor) descriptor = descriptor.propertyIfAccessor
|
||||
while (descriptor.containingDeclaration !is PackageFragmentDescriptor) {
|
||||
descriptor = descriptor.containingDeclaration!!
|
||||
}
|
||||
if (descriptor is ClassDescriptor) return null
|
||||
val source = (descriptor as? DescriptorWithContainerSource)?.containerSource as? JvmPackagePartSource ?: return null
|
||||
val facadeName = source.facadeClassName ?: source.className
|
||||
val fileClassName = source.className
|
||||
return fileClassName.fqNameForTopLevelClassMaybeWithDollars to facadeName.fqNameForTopLevelClassMaybeWithDollars
|
||||
} else {
|
||||
error("No descriptor in symbol")
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from KotlinDeserializedJvmSymbolsProvider.
|
||||
private fun getJvmPackagePartSource(binaryClass: KotlinJvmBinaryClass): JvmPackagePartSource {
|
||||
val header = binaryClass.classHeader
|
||||
val data = header.data ?: header.incompatibleData ?: error("Should not happen")
|
||||
val strings = header.strings ?: error("Should not happen")
|
||||
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(data, strings)
|
||||
return JvmPackagePartSource(
|
||||
binaryClass, packageProto, nameResolver,
|
||||
binaryClass.incompatibility, binaryClass.isPreReleaseInvisible
|
||||
)
|
||||
}
|
||||
|
||||
private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>?
|
||||
get() {
|
||||
// TODO: skipMetadataVersionCheck
|
||||
if (classHeader.metadataVersion.isCompatible()) return null
|
||||
return IncompatibleVersionErrorData(classHeader.metadataVersion, JvmMetadataVersion.INSTANCE, location, classId)
|
||||
}
|
||||
|
||||
private val KotlinJvmBinaryClass.isPreReleaseInvisible: Boolean
|
||||
get() = classHeader.isPreRelease
|
||||
|
||||
|
||||
override fun tryReferencingPropertyByLocalSignature(parent: IrDeclaration, idSignature: IdSignature): IrPropertySymbol? = null
|
||||
override fun tryReferencingSimpleFunctionByLocalSignature(parent: IrDeclaration, idSignature: IdSignature): IrSimpleFunctionSymbol? =
|
||||
null
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,10 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
|
||||
abstract class AbstractJvmManglerIr : IrBasedKotlinManglerImpl() {
|
||||
|
||||
@@ -30,6 +33,11 @@ abstract class AbstractJvmManglerIr : IrBasedKotlinManglerImpl() {
|
||||
|
||||
private class JvmIrExportChecker : IrExportCheckerVisitor() {
|
||||
override fun IrDeclaration.isPlatformSpecificExported() = false
|
||||
|
||||
override fun visitField(declaration: IrField, data: Nothing?): Boolean {
|
||||
if (declaration.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) return true
|
||||
return super.visitField(declaration, data)
|
||||
}
|
||||
}
|
||||
|
||||
private class JvmIrManglerComputer(builder: StringBuilder, mode: MangleMode) : IrMangleComputer(builder, mode) {
|
||||
|
||||
@@ -15,6 +15,7 @@ enum class TargetBackend(
|
||||
JVM_IR(true, JVM),
|
||||
JVM_MULTI_MODULE_IR_AGAINST_OLD(true, JVM_IR),
|
||||
JVM_MULTI_MODULE_OLD_AGAINST_IR(false, JVM),
|
||||
JVM_IR_SERIALIZE(true, JVM_IR),
|
||||
JS(false),
|
||||
JS_IR(true, JS),
|
||||
JS_IR_ES6(true, JS_IR),
|
||||
|
||||
2
compiler/testData/cli/jvm/extraHelp.out
vendored
2
compiler/testData/cli/jvm/extraHelp.out
vendored
@@ -107,6 +107,7 @@ where advanced options include:
|
||||
problems with parentheses in identifiers on certain platforms
|
||||
-Xscript-resolver-environment=<key=value[,]>
|
||||
Script resolver environment in key-value pairs (the value could be quoted and escaped)
|
||||
-Xserialize-ir Save IR to metadata
|
||||
-Xsingle-module Combine modules for source files and binary dependencies into a single module
|
||||
-Xskip-runtime-version-check Allow Kotlin runtime libraries of incompatible versions in the classpath
|
||||
-Xstrict-java-nullability-assertions
|
||||
@@ -194,4 +195,3 @@ where advanced options include:
|
||||
|
||||
Advanced options are non-standard and may be changed or removed without any notice.
|
||||
OK
|
||||
|
||||
|
||||
18
compiler/testData/diagnostics/tests/constexpr/compileTimeMember.fir.kt
vendored
Normal file
18
compiler/testData/diagnostics/tests/constexpr/compileTimeMember.fir.kt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// !LANGUAGE: +CompileTimeCalculations
|
||||
|
||||
@CompileTimeCalculation
|
||||
abstract class ConstExprClass {
|
||||
abstract fun getSomeValue(): Int
|
||||
}
|
||||
|
||||
@CompileTimeCalculation
|
||||
class A(val a: Int): ConstExprClass() {
|
||||
override fun getSomeValue() = a
|
||||
}
|
||||
|
||||
class B @CompileTimeCalculation constructor(val b: Int): ConstExprClass() {
|
||||
override fun getSomeValue() = b
|
||||
}
|
||||
|
||||
const val a = A(1).getSomeValue()
|
||||
const val b = B(2).getSomeValue()
|
||||
18
compiler/testData/diagnostics/tests/constexpr/compileTimeMember.kt
vendored
Normal file
18
compiler/testData/diagnostics/tests/constexpr/compileTimeMember.kt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// !LANGUAGE: +CompileTimeCalculations
|
||||
|
||||
@CompileTimeCalculation
|
||||
abstract class ConstExprClass {
|
||||
abstract fun getSomeValue(): Int
|
||||
}
|
||||
|
||||
@CompileTimeCalculation
|
||||
class A(val a: Int): ConstExprClass() {
|
||||
override fun getSomeValue() = a
|
||||
}
|
||||
|
||||
class B @CompileTimeCalculation constructor(val b: Int): ConstExprClass() {
|
||||
<!COMPILE_TIME_MEMBER_NOT_IMPLEMENTED!>override fun getSomeValue() = b<!>
|
||||
}
|
||||
|
||||
const val a = A(1).getSomeValue()
|
||||
const val b = B(2).getSomeValue()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user