diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java index 2d2a342f380..72d84a493be 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java @@ -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 { 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 { Type classType = typeMapper.mapType(scriptDescriptor); iv.load(0, classType); - iv.invokespecial("java/lang/Object", "", "()V", false); + ClassDescriptor superclass = DescriptorUtilsKt.getSuperClassOrAny(scriptDescriptor); + assert hasDefaultConstructor(superclass); + iv.invokespecial( + typeMapper.mapSupertype(superclass.getDefaultType(), null).getInternalName(), + "", "()V", false); iv.load(0, classType); @@ -199,6 +206,15 @@ public class ScriptCodegen extends MemberCodegen { 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); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 689fc7b5f56..a7cbb844630 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -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, signatureVisitor: JvmSignatureWriter?): Array = + 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( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java index 577f43611b7..f1280a1ad20 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -567,6 +567,9 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes return parameters.invoke(); } + @Nullable + public List getInjectedSupertypes() { return null; } + private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity { private final NotNullLazyValue> parameters = c.getStorageManager().createLazyValue(new Function0>() { @Override @@ -595,6 +598,11 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes return Collections.emptyList(); } + List 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()); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptDescriptor.kt index 46fd5cda803..8354159ae7d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptDescriptor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptDescriptor.kt @@ -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? { + 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 + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt index a26523c1f78..fc5cfa4c688 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt @@ -34,6 +34,7 @@ import kotlin.reflect.KClass interface KotlinScriptDefinition { fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List + fun getScriptSuperclasses(scriptDescriptor: ScriptDescriptor): List = emptyList() fun isScript(file: PsiFile): Boolean fun getScriptName(script: KtScript): Name } diff --git a/compiler/testData/script/fib_dsl.kts b/compiler/testData/script/fib_dsl.kts new file mode 100644 index 00000000000..b8aa664b9cf --- /dev/null +++ b/compiler/testData/script/fib_dsl.kts @@ -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) + diff --git a/compiler/tests-common/org/jetbrains/kotlin/scripts/TestScriptDefinitions.kt b/compiler/tests-common/org/jetbrains/kotlin/scripts/TestScriptDefinitions.kt index db80b714e5a..aa0c7cb9d6b 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/scripts/TestScriptDefinitions.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/scripts/TestScriptDefinitions.kt @@ -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) : BaseScriptDefinition(extension) { +open class SimpleParamsTestScriptDefinition(extension: String, val parameters: List) : 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, val superclass: KClass) : SimpleParamsTestScriptDefinition(extension, parameters) { + override fun getScriptSuperclasses(scriptDescriptor: ScriptDescriptor): List = + listOf(getKotlinType(scriptDescriptor, superclass)) +} diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt index 163042bea55..655fc833229 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt @@ -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 = 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() + (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 { diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/TestScriptDsl.kt b/compiler/tests/org/jetbrains/kotlin/scripts/TestScriptDsl.kt new file mode 100644 index 00000000000..d0fa83b4bc1 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/scripts/TestScriptDsl.kt @@ -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) + diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index 97160fd1dab..8b97243ec45 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -121,6 +121,15 @@ fun ClassDescriptor.getSuperClassNotAny(): ClassDescriptor? { fun ClassDescriptor.getSuperClassOrAny(): ClassDescriptor = getSuperClassNotAny() ?: builtIns.any +fun ClassDescriptor.getSuperInterfaces(): List = + 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 get() = constructors.filterNot { it.isPrimary }