Add possibility to specify supertypes for script, with tests
This commit is contained in:
@@ -23,10 +23,13 @@ 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.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||||
@@ -91,8 +94,8 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
|||||||
ACC_PUBLIC | ACC_SUPER,
|
ACC_PUBLIC | ACC_SUPER,
|
||||||
classAsmType.getInternalName(),
|
classAsmType.getInternalName(),
|
||||||
null,
|
null,
|
||||||
"java/lang/Object",
|
typeMapper.mapSupertype(DescriptorUtilsKt.getSuperClassOrAny(scriptDescriptor).getDefaultType(), null).getInternalName(),
|
||||||
ArrayUtil.EMPTY_STRING_ARRAY);
|
CodegenUtilKt.mapSupertypesNames(typeMapper, DescriptorUtilsKt.getSuperInterfaces(scriptDescriptor), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -145,7 +148,11 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
|||||||
Type classType = typeMapper.mapType(scriptDescriptor);
|
Type classType = typeMapper.mapType(scriptDescriptor);
|
||||||
|
|
||||||
iv.load(0, classType);
|
iv.load(0, classType);
|
||||||
iv.invokespecial("java/lang/Object", "<init>", "()V", false);
|
ClassDescriptor superclass = DescriptorUtilsKt.getSuperClassOrAny(scriptDescriptor);
|
||||||
|
assert hasDefaultConstructor(superclass);
|
||||||
|
iv.invokespecial(
|
||||||
|
typeMapper.mapSupertype(superclass.getDefaultType(), null).getInternalName(),
|
||||||
|
"<init>", "()V", false);
|
||||||
|
|
||||||
iv.load(0, classType);
|
iv.load(0, classType);
|
||||||
|
|
||||||
@@ -199,6 +206,15 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasDefaultConstructor(ClassDescriptor superclass) {
|
||||||
|
for (ConstructorDescriptor ctor : superclass.getConstructors()) {
|
||||||
|
if (ctor.getValueParameters().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) {
|
private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) {
|
||||||
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
|
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
|
||||||
Type earlierClassName = typeMapper.mapType(earlierScript);
|
Type earlierClassName = typeMapper.mapType(earlierScript);
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ package org.jetbrains.kotlin.codegen
|
|||||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||||
import org.jetbrains.kotlin.codegen.context.PackageContext
|
import org.jetbrains.kotlin.codegen.context.PackageContext
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
||||||
|
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
||||||
@@ -133,6 +135,11 @@ fun populateCompanionBackingFieldNamesToOuterContextIfNeeded(companion: KtObject
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: inline and remove then ScriptCodegen is converted to Kotlin
|
||||||
|
fun mapSupertypesNames(typeMapper: KotlinTypeMapper, supertypes: List<ClassDescriptor>, signatureVisitor: JvmSignatureWriter?): Array<String> =
|
||||||
|
supertypes.map { typeMapper.mapSupertype(it.defaultType, signatureVisitor).internalName }.toTypedArray()
|
||||||
|
|
||||||
|
|
||||||
// Top level subclasses of a sealed class should be generated before that sealed class,
|
// Top level subclasses of a sealed class should be generated before that sealed class,
|
||||||
// so that we'd generate the necessary accessor for its constructor afterwards
|
// so that we'd generate the necessary accessor for its constructor afterwards
|
||||||
fun sortTopLevelClassesAndPrepareContextForSealedClasses(
|
fun sortTopLevelClassesAndPrepareContextForSealedClasses(
|
||||||
|
|||||||
+8
@@ -567,6 +567,9 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
|||||||
return parameters.invoke();
|
return parameters.invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public List<? extends KotlinType> getInjectedSupertypes() { return null; }
|
||||||
|
|
||||||
private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
|
private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
|
||||||
private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
|
private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -595,6 +598,11 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<? extends KotlinType> injectedSupertypes = getInjectedSupertypes();
|
||||||
|
if (injectedSupertypes != null) {
|
||||||
|
return Lists.newArrayList(Collections2.filter(injectedSupertypes, VALID_SUPERTYPE));
|
||||||
|
}
|
||||||
|
|
||||||
KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
|
KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
|
||||||
if (classOrObject == null) {
|
if (classOrObject == null) {
|
||||||
return Collections.singleton(c.getModuleDescriptor().getBuiltIns().getAnyType());
|
return Collections.singleton(c.getModuleDescriptor().getBuiltIns().getAnyType());
|
||||||
|
|||||||
+9
@@ -26,7 +26,9 @@ import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
|||||||
import org.jetbrains.kotlin.resolve.lazy.data.KtScriptInfo
|
import org.jetbrains.kotlin.resolve.lazy.data.KtScriptInfo
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
||||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||||
|
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
|
||||||
class LazyScriptDescriptor(
|
class LazyScriptDescriptor(
|
||||||
@@ -71,4 +73,11 @@ class LazyScriptDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getUnsubstitutedPrimaryConstructor() = super.getUnsubstitutedPrimaryConstructor()!!
|
override fun getUnsubstitutedPrimaryConstructor() = super.getUnsubstitutedPrimaryConstructor()!!
|
||||||
|
|
||||||
|
override fun getInjectedSupertypes(): List<KotlinType>? {
|
||||||
|
val file = scriptInfo.script.getContainingKtFile()
|
||||||
|
val scriptDefinition = KotlinScriptDefinitionProvider.getInstance(file.project).findScriptDefinition(file)
|
||||||
|
val superclasses = scriptDefinition.getScriptSuperclasses(this)
|
||||||
|
return if (superclasses.isEmpty()) null else superclasses
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import kotlin.reflect.KClass
|
|||||||
|
|
||||||
interface KotlinScriptDefinition {
|
interface KotlinScriptDefinition {
|
||||||
fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter>
|
fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter>
|
||||||
|
fun getScriptSuperclasses(scriptDescriptor: ScriptDescriptor): List<KotlinType> = emptyList()
|
||||||
fun isScript(file: PsiFile): Boolean
|
fun isScript(file: PsiFile): Boolean
|
||||||
fun getScriptName(script: KtScript): Name
|
fun getScriptName(script: KtScript): Name
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
import org.jetbrains.kotlin.scripts.*
|
||||||
|
|
||||||
|
// this script expected parameter num : Int
|
||||||
|
|
||||||
|
fun fib(n: Int): Int {
|
||||||
|
val v = fibCombine( { fib(it) }, n)
|
||||||
|
System.out.println("fib($n)=$v")
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("num: $num")
|
||||||
|
val result = fib(num)
|
||||||
|
|
||||||
@@ -20,10 +20,7 @@ import com.intellij.psi.PsiFile
|
|||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtScript
|
import org.jetbrains.kotlin.psi.KtScript
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
import org.jetbrains.kotlin.script.*
|
||||||
import org.jetbrains.kotlin.script.ScriptNameUtil
|
|
||||||
import org.jetbrains.kotlin.script.ScriptParameter
|
|
||||||
import org.jetbrains.kotlin.script.makeReflectedClassScriptParameter
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@@ -32,7 +29,7 @@ abstract class BaseScriptDefinition (val extension: String) : KotlinScriptDefini
|
|||||||
override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, extension)
|
override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleParamsTestScriptDefinition(extension: String, val parameters: List<ScriptParameter>) : BaseScriptDefinition(extension) {
|
open class SimpleParamsTestScriptDefinition(extension: String, val parameters: List<ScriptParameter>) : BaseScriptDefinition(extension) {
|
||||||
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor) = parameters
|
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor) = parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,3 +37,8 @@ class ReflectedParamClassTestScriptDefinition(extension: String, val name: Strin
|
|||||||
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor) =
|
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor) =
|
||||||
listOf(makeReflectedClassScriptParameter(scriptDescriptor, Name.identifier(name), parameter))
|
listOf(makeReflectedClassScriptParameter(scriptDescriptor, Name.identifier(name), parameter))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReflectedSuperclassTestScriptDefinition(extension: String, parameters: List<ScriptParameter>, val superclass: KClass<out Any>) : SimpleParamsTestScriptDefinition(extension, parameters) {
|
||||||
|
override fun getScriptSuperclasses(scriptDescriptor: ScriptDescriptor): List<KotlinType> =
|
||||||
|
listOf(getKotlinType(scriptDescriptor, superclass))
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import org.jetbrains.kotlin.utils.PathUtil
|
|||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class ScriptTest {
|
class ScriptTest {
|
||||||
@Test
|
@Test
|
||||||
@@ -66,10 +68,23 @@ class ScriptTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testScriptWithClassParameter() {
|
fun testScriptWithClassParameter() {
|
||||||
val cl = TestParamClass::class
|
val aClass = compileScript("fib_cp.kts", ReflectedParamClassTestScriptDefinition(".kts", "param", TestParamClass::class), runIsolated = false)
|
||||||
val aClass = compileScript("fib_cp.kts", ReflectedParamClassTestScriptDefinition(".kts", "param", cl), runIsolated = false)
|
|
||||||
Assert.assertNotNull(aClass)
|
Assert.assertNotNull(aClass)
|
||||||
aClass!!.getConstructor(cl.java).newInstance(TestParamClass(4))
|
aClass!!.getConstructor(TestParamClass::class.java).newInstance(TestParamClass(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptWithBaseClass() {
|
||||||
|
val aClass = compileScript("fib_dsl.kts", ReflectedSuperclassTestScriptDefinition(".kts", numIntParam(), TestDSLClass::class), runIsolated = false)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Integer.TYPE).newInstance(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testScriptWithInterface() {
|
||||||
|
val aClass = compileScript("fib_dsl.kts", ReflectedSuperclassTestScriptDefinition(".kts", numIntParam(), TestDSLInterface::class), runIsolated = false)
|
||||||
|
Assert.assertNotNull(aClass)
|
||||||
|
aClass!!.getConstructor(Integer.TYPE).newInstance(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileScript(
|
private fun compileScript(
|
||||||
@@ -102,7 +117,7 @@ class ScriptTest {
|
|||||||
}
|
}
|
||||||
catch (t: Throwable) {
|
catch (t: Throwable) {
|
||||||
MessageCollectorUtil.reportException(messageCollector, t)
|
MessageCollectorUtil.reportException(messageCollector, t)
|
||||||
return null
|
throw t
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -112,10 +127,16 @@ class ScriptTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun CompilerConfiguration.addCurrentClasspathAsRoots() {
|
private fun CompilerConfiguration.addCurrentClasspathAsRoots() {
|
||||||
System.getProperty("java.class.path")?.let {
|
|
||||||
|
val cp: MutableSet<File> = System.getProperty("java.class.path")?.let {
|
||||||
it.split(String.format("\\%s", File.pathSeparatorChar).toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
it.split(String.format("\\%s", File.pathSeparatorChar).toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
.forEach { addJvmClasspathRoot(File(it)) }
|
.map { File(it).canonicalFile }.toMutableSet()
|
||||||
}
|
} ?: LinkedHashSet<File>()
|
||||||
|
(this.javaClass.classLoader as? URLClassLoader)?.urLs
|
||||||
|
?.map { File(it.toURI()).canonicalFile }
|
||||||
|
?.filter { it.exists() }
|
||||||
|
?.forEach { cp.add(it) }
|
||||||
|
cp.forEach { addJvmClasspathRoot(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun numIntParam(): List<ScriptParameter> {
|
private fun numIntParam(): List<ScriptParameter> {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.scripts
|
||||||
|
|
||||||
|
open class TestDSLClass
|
||||||
|
|
||||||
|
fun TestDSLClass.fibCombine(f: (Int) -> Int, n: Int) = if (n < 2) 1 else f(n - 1) + f(n - 2)
|
||||||
|
|
||||||
|
interface TestDSLInterface
|
||||||
|
|
||||||
|
fun TestDSLInterface.fibCombine(f: (Int) -> Int, n: Int) = if (n < 2) 1 else f(n - 1) + f(n - 2)
|
||||||
|
|
||||||
@@ -121,6 +121,15 @@ fun ClassDescriptor.getSuperClassNotAny(): ClassDescriptor? {
|
|||||||
|
|
||||||
fun ClassDescriptor.getSuperClassOrAny(): ClassDescriptor = getSuperClassNotAny() ?: builtIns.any
|
fun ClassDescriptor.getSuperClassOrAny(): ClassDescriptor = getSuperClassNotAny() ?: builtIns.any
|
||||||
|
|
||||||
|
fun ClassDescriptor.getSuperInterfaces(): List<ClassDescriptor> =
|
||||||
|
defaultType.constructor.supertypes
|
||||||
|
.filterNot { KotlinBuiltIns.isAnyOrNullableAny(it) }
|
||||||
|
.mapNotNull {
|
||||||
|
val superClassifier = it.constructor.declarationDescriptor
|
||||||
|
if (DescriptorUtils.isInterface(superClassifier)) superClassifier as ClassDescriptor
|
||||||
|
else null
|
||||||
|
}
|
||||||
|
|
||||||
val ClassDescriptor.secondaryConstructors: List<ConstructorDescriptor>
|
val ClassDescriptor.secondaryConstructors: List<ConstructorDescriptor>
|
||||||
get() = constructors.filterNot { it.isPrimary }
|
get() = constructors.filterNot { it.isPrimary }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user