[scripting] Fix Kotlin reflection metadata for script constructors
This commit is contained in:
committed by
teamcityserver
parent
176803689a
commit
7283ea86af
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||||
import org.jetbrains.kotlin.codegen.context.ScriptContext
|
import org.jetbrains.kotlin.codegen.context.ScriptContext
|
||||||
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
@@ -82,6 +83,8 @@ class ScriptCodegen private constructor(
|
|||||||
val jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor)
|
val jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor)
|
||||||
val asmMethod = jvmSignature.asmMethod
|
val asmMethod = jvmSignature.asmMethod
|
||||||
|
|
||||||
|
classBuilder.serializationBindings.put(METHOD_FOR_FUNCTION, scriptDescriptor.unsubstitutedPrimaryConstructor, asmMethod)
|
||||||
|
|
||||||
scriptContext.resultFieldInfo?.let { resultFieldInfo ->
|
scriptContext.resultFieldInfo?.let { resultFieldInfo ->
|
||||||
classBuilder.newField(
|
classBuilder.newField(
|
||||||
NO_ORIGIN,
|
NO_ORIGIN,
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.toArrayOrPrimitiveArrayType
|
import org.jetbrains.kotlin.ir.util.indexOrMinusOne
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.isCrossinline
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.ir.util.isNoinline
|
||||||
|
import org.jetbrains.kotlin.ir.util.varargElementType
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtScript
|
import org.jetbrains.kotlin.psi.KtScript
|
||||||
@@ -155,6 +156,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
|
|||||||
irScript.providedProperties.forEach { add(it.first) }
|
irScript.providedProperties.forEach { add(it.first) }
|
||||||
}
|
}
|
||||||
irConstructor.parent = irScript
|
irConstructor.parent = irScript
|
||||||
|
irConstructor.metadata = DescriptorMetadataSource.Function(descriptor.unsubstitutedPrimaryConstructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (d in ktScript.declarations) {
|
for (d in ktScript.declarations) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ dependencies {
|
|||||||
testImplementation(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core"))
|
testImplementation(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core"))
|
||||||
|
|
||||||
testRuntimeOnly(project(":kotlin-compiler"))
|
testRuntimeOnly(project(":kotlin-compiler"))
|
||||||
testRuntimeOnly(project(":kotlin-reflect"))
|
testImplementation(project(":kotlin-reflect"))
|
||||||
testRuntimeOnly(commonDep("org.jetbrains.intellij.deps", "trove4j"))
|
testRuntimeOnly(commonDep("org.jetbrains.intellij.deps", "trove4j"))
|
||||||
|
|
||||||
embeddableTestRuntime(project(":kotlin-scripting-jvm-host"))
|
embeddableTestRuntime(project(":kotlin-scripting-jvm-host"))
|
||||||
|
|||||||
+54
-5
@@ -11,16 +11,47 @@ import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerBase
|
|||||||
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
|
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import kotlin.reflect.KProperty1
|
||||||
|
import kotlin.reflect.full.declaredMemberProperties
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.toScriptSource
|
import kotlin.script.experimental.host.toScriptSource
|
||||||
import kotlin.script.experimental.jvm.BasicJvmReplEvaluator
|
import kotlin.script.experimental.jvm.BasicJvmReplEvaluator
|
||||||
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledModuleInMemory
|
||||||
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||||
import kotlin.script.experimental.jvm.updateClasspath
|
import kotlin.script.experimental.jvm.updateClasspath
|
||||||
import kotlin.script.experimental.jvm.util.classpathFromClass
|
import kotlin.script.experimental.jvm.util.classpathFromClass
|
||||||
import kotlin.script.experimental.jvmhost.createJvmScriptDefinitionFromTemplate
|
import kotlin.script.experimental.jvmhost.createJvmScriptDefinitionFromTemplate
|
||||||
|
import kotlin.script.experimental.util.LinkedSnippet
|
||||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||||
|
|
||||||
class ReplTest : TestCase() {
|
class ReplTest : TestCase() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDecompiledReflection() {
|
||||||
|
checkEvaluateInRepl(
|
||||||
|
sequenceOf(
|
||||||
|
"val x = 1",
|
||||||
|
),
|
||||||
|
sequenceOf(null),
|
||||||
|
compiledSnippetChecker = { linkedSnippet ->
|
||||||
|
val snippet = linkedSnippet.get()
|
||||||
|
val module = snippet.getCompiledModule() as KJvmCompiledModuleInMemory
|
||||||
|
|
||||||
|
val classLoader = module.createClassLoader(ClassLoader.getSystemClassLoader())
|
||||||
|
val kClass = classLoader.loadClass(snippet.scriptClassFQName).kotlin
|
||||||
|
val constructor = kClass.constructors.single()
|
||||||
|
val scriptInstance = constructor.call(emptyArray<Any>())
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val xProp = kClass.declaredMemberProperties.first { it.name == "x" } as KProperty1<Any, Any>
|
||||||
|
val xValue = xProp.get(scriptInstance)
|
||||||
|
|
||||||
|
assertEquals(1, xValue)
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCompileAndEval() {
|
fun testCompileAndEval() {
|
||||||
val out = captureOut {
|
val out = captureOut {
|
||||||
@@ -282,7 +313,8 @@ class ReplTest : TestCase() {
|
|||||||
snippets: Sequence<String>,
|
snippets: Sequence<String>,
|
||||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||||
limit: Int = 0
|
limit: Int = 0,
|
||||||
|
compiledSnippetChecker: CompiledSnippetChecker = {},
|
||||||
): Sequence<ResultWithDiagnostics<EvaluatedSnippet>> {
|
): Sequence<ResultWithDiagnostics<EvaluatedSnippet>> {
|
||||||
val replCompiler = KJvmReplCompilerBase<ReplCodeAnalyzerBase>()
|
val replCompiler = KJvmReplCompilerBase<ReplCodeAnalyzerBase>()
|
||||||
val replEvaluator = BasicJvmReplEvaluator()
|
val replEvaluator = BasicJvmReplEvaluator()
|
||||||
@@ -293,6 +325,7 @@ class ReplTest : TestCase() {
|
|||||||
snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
||||||
runBlocking { replCompiler.compile(snippetSource, compilationConfiguration) }
|
runBlocking { replCompiler.compile(snippetSource, compilationConfiguration) }
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
|
compiledSnippetChecker(it)
|
||||||
runBlocking { replEvaluator.eval(it, currentEvalConfig) }
|
runBlocking { replEvaluator.eval(it, currentEvalConfig) }
|
||||||
}
|
}
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
@@ -307,10 +340,17 @@ class ReplTest : TestCase() {
|
|||||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||||
limit: Int = 0,
|
limit: Int = 0,
|
||||||
ignoreDiagnostics: Boolean = false
|
ignoreDiagnostics: Boolean = false,
|
||||||
|
compiledSnippetChecker: CompiledSnippetChecker = {}
|
||||||
) {
|
) {
|
||||||
val expectedIter = (if (limit == 0) expected else expected.take(limit)).iterator()
|
val expectedIter = (if (limit == 0) expected else expected.take(limit)).iterator()
|
||||||
evaluateInRepl(snippets, compilationConfiguration, evaluationConfiguration, limit).forEachIndexed { index, res ->
|
evaluateInRepl(
|
||||||
|
snippets,
|
||||||
|
compilationConfiguration,
|
||||||
|
evaluationConfiguration,
|
||||||
|
limit,
|
||||||
|
compiledSnippetChecker
|
||||||
|
).forEachIndexed { index, res ->
|
||||||
val expectedRes = expectedIter.next()
|
val expectedRes = expectedIter.next()
|
||||||
when {
|
when {
|
||||||
res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> {
|
res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> {
|
||||||
@@ -375,9 +415,16 @@ class ReplTest : TestCase() {
|
|||||||
expected: Sequence<Any?>,
|
expected: Sequence<Any?>,
|
||||||
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
compilationConfiguration: ScriptCompilationConfiguration = simpleScriptCompilationConfiguration,
|
||||||
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration,
|
||||||
limit: Int = 0
|
limit: Int = 0,
|
||||||
|
compiledSnippetChecker: CompiledSnippetChecker = {}
|
||||||
) = checkEvaluateInReplDiags(
|
) = checkEvaluateInReplDiags(
|
||||||
snippets, expected.map { ResultWithDiagnostics.Success(it) }, compilationConfiguration, evaluationConfiguration, limit, true
|
snippets,
|
||||||
|
expected.map { ResultWithDiagnostics.Success(it) },
|
||||||
|
compilationConfiguration,
|
||||||
|
evaluationConfiguration,
|
||||||
|
limit,
|
||||||
|
true,
|
||||||
|
compiledSnippetChecker
|
||||||
)
|
)
|
||||||
|
|
||||||
class TestReceiver(
|
class TestReceiver(
|
||||||
@@ -389,3 +436,5 @@ class ReplTest : TestCase() {
|
|||||||
|
|
||||||
@Target(AnnotationTarget.FILE)
|
@Target(AnnotationTarget.FILE)
|
||||||
annotation class NewAnn
|
annotation class NewAnn
|
||||||
|
|
||||||
|
typealias CompiledSnippetChecker = (LinkedSnippet<KJvmCompiledScript>) -> Unit
|
||||||
|
|||||||
Reference in New Issue
Block a user