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.ScriptContext;
|
||||
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.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
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.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
@@ -91,8 +94,8 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
||||
ACC_PUBLIC | ACC_SUPER,
|
||||
classAsmType.getInternalName(),
|
||||
null,
|
||||
"java/lang/Object",
|
||||
ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
typeMapper.mapSupertype(DescriptorUtilsKt.getSuperClassOrAny(scriptDescriptor).getDefaultType(), null).getInternalName(),
|
||||
CodegenUtilKt.mapSupertypesNames(typeMapper, DescriptorUtilsKt.getSuperInterfaces(scriptDescriptor), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,7 +148,11 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
||||
Type classType = typeMapper.mapType(scriptDescriptor);
|
||||
|
||||
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);
|
||||
|
||||
@@ -199,6 +206,15 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
||||
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) {
|
||||
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
|
||||
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.PackageContext
|
||||
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.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
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,
|
||||
// so that we'd generate the necessary accessor for its constructor afterwards
|
||||
fun sortTopLevelClassesAndPrepareContextForSealedClasses(
|
||||
|
||||
+8
@@ -567,6 +567,9 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
||||
return parameters.invoke();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<? extends KotlinType> getInjectedSupertypes() { return null; }
|
||||
|
||||
private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
|
||||
private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
|
||||
@Override
|
||||
@@ -595,6 +598,11 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<? extends KotlinType> injectedSupertypes = getInjectedSupertypes();
|
||||
if (injectedSupertypes != null) {
|
||||
return Lists.newArrayList(Collections2.filter(injectedSupertypes, VALID_SUPERTYPE));
|
||||
}
|
||||
|
||||
KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
|
||||
if (classOrObject == null) {
|
||||
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.declarations.ClassMemberDeclarationProvider
|
||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
|
||||
class LazyScriptDescriptor(
|
||||
@@ -71,4 +73,11 @@ class LazyScriptDescriptor(
|
||||
}
|
||||
|
||||
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 {
|
||||
fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List<ScriptParameter>
|
||||
fun getScriptSuperclasses(scriptDescriptor: ScriptDescriptor): List<KotlinType> = emptyList()
|
||||
fun isScript(file: PsiFile): Boolean
|
||||
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.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptNameUtil
|
||||
import org.jetbrains.kotlin.script.ScriptParameter
|
||||
import org.jetbrains.kotlin.script.makeReflectedClassScriptParameter
|
||||
import org.jetbrains.kotlin.script.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -40,3 +37,8 @@ class ReflectedParamClassTestScriptDefinition(extension: String, val name: Strin
|
||||
override fun getScriptParameters(scriptDescriptor: ScriptDescriptor) =
|
||||
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.Test
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import java.util.*
|
||||
|
||||
class ScriptTest {
|
||||
@Test
|
||||
@@ -66,10 +68,23 @@ class ScriptTest {
|
||||
|
||||
@Test
|
||||
fun testScriptWithClassParameter() {
|
||||
val cl = TestParamClass::class
|
||||
val aClass = compileScript("fib_cp.kts", ReflectedParamClassTestScriptDefinition(".kts", "param", cl), runIsolated = false)
|
||||
val aClass = compileScript("fib_cp.kts", ReflectedParamClassTestScriptDefinition(".kts", "param", TestParamClass::class), runIsolated = false)
|
||||
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(
|
||||
@@ -102,7 +117,7 @@ class ScriptTest {
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
MessageCollectorUtil.reportException(messageCollector, t)
|
||||
return null
|
||||
throw t
|
||||
}
|
||||
|
||||
}
|
||||
@@ -112,10 +127,16 @@ class ScriptTest {
|
||||
}
|
||||
|
||||
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()
|
||||
.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> {
|
||||
|
||||
@@ -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.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>
|
||||
get() = constructors.filterNot { it.isPrimary }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user