diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt index 568ed93588a..429836d5b03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * 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. @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.script import com.intellij.openapi.fileTypes.LanguageFileType import com.intellij.openapi.project.Project import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -30,12 +31,14 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.serialization.deserialization.findNonGenericClassAcrossDependencies import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.* import java.io.File -import java.util.concurrent.Future -import java.util.concurrent.TimeUnit +import java.lang.RuntimeException +import java.lang.UnsupportedOperationException import kotlin.reflect.KClass +import kotlin.reflect.KType +import kotlin.reflect.KTypeProjection +import kotlin.reflect.KVariance interface KotlinScriptDefinition { val name: String get() = "Kotlin Script" @@ -102,3 +105,33 @@ fun getKotlinTypeByFqName(scriptDescriptor: ScriptDescriptor, fqName: String): K ClassId.topLevel(FqName(fqName)), NotFoundClasses(LockBasedStorageManager.NO_LOCKS, scriptDescriptor.module) ).defaultType + +// TODO: support star projections +// TODO: support annotations on types and type parameters +// TODO: support type parameters on types and type projections +fun getKotlinTypeByKType(scriptDescriptor: ScriptDescriptor, kType: KType): KotlinType { + val classifier = kType.classifier + if (classifier !is KClass<*>) + throw UnsupportedOperationException("Only classes are supported as parameters in script template: $classifier") + + val type = getKotlinType(scriptDescriptor, classifier) + val typeProjections = kType.arguments.map { getTypeProjection(scriptDescriptor, it) } + val isNullable = kType.isMarkedNullable + + return KotlinTypeFactory.simpleType(Annotations.EMPTY, type.constructor, typeProjections, isNullable) +} + +private fun getTypeProjection(scriptDescriptor: ScriptDescriptor, kTypeProjection: KTypeProjection): TypeProjection { + val kType = kTypeProjection.type ?: throw UnsupportedOperationException("Star projections are not supported") + + val type = getKotlinTypeByKType(scriptDescriptor, kType) + + val variance = when (kTypeProjection.variance) { + KVariance.IN -> Variance.IN_VARIANCE + KVariance.OUT -> Variance.OUT_VARIANCE + KVariance.INVARIANT -> Variance.INVARIANT + null -> throw UnsupportedOperationException("Star projections are not supported") + } + + return TypeProjectionImpl(variance, type) +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt index 89b1ad77f0b..e8db6cdf9b6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt @@ -85,7 +85,7 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, override val name = template.simpleName!! override fun getScriptParameters(scriptDescriptor: ScriptDescriptor): List = - template.primaryConstructor!!.parameters.map { ScriptParameter(Name.identifier(it.name!!), getKotlinTypeByFqName(scriptDescriptor, it.type.toString())) } + template.primaryConstructor!!.parameters.map { ScriptParameter(Name.identifier(it.name!!), getKotlinTypeByKType(scriptDescriptor, it.type)) } override fun getScriptSupertypes(scriptDescriptor: ScriptDescriptor): List = listOf(getKotlinTypeByFqName(scriptDescriptor, template.qualifiedName!!)) diff --git a/compiler/testData/script/array2d_param.kts b/compiler/testData/script/array2d_param.kts new file mode 100644 index 00000000000..aa4624d2f7e --- /dev/null +++ b/compiler/testData/script/array2d_param.kts @@ -0,0 +1,4 @@ +val v: Array = param[0] +val s = v[0] + +System.out.println("first: $s, size: ${v.size}") \ No newline at end of file diff --git a/compiler/testData/script/array_parameter.kts b/compiler/testData/script/array_parameter.kts new file mode 100644 index 00000000000..86765c7017b --- /dev/null +++ b/compiler/testData/script/array_parameter.kts @@ -0,0 +1,4 @@ +val v1 = myArgs[0] +val v2 = myArgs[1] + +System.out.println("$v1 and $v2") \ No newline at end of file diff --git a/compiler/testData/script/nullable_parameter.kts b/compiler/testData/script/nullable_parameter.kts new file mode 100644 index 00000000000..f2230682110 --- /dev/null +++ b/compiler/testData/script/nullable_parameter.kts @@ -0,0 +1,4 @@ +import java.lang.RuntimeException + +val k: Int? = param +if (k == null) System.out.println("Param is null") else throw RuntimeException("param is not null") \ No newline at end of file diff --git a/compiler/testData/script/nullable_projection.kts b/compiler/testData/script/nullable_projection.kts new file mode 100644 index 00000000000..80c37c7f935 --- /dev/null +++ b/compiler/testData/script/nullable_projection.kts @@ -0,0 +1,5 @@ +import java.lang.RuntimeException + +val v: String? = param[0] + +if (v == null) System.out.println("nullable") else RuntimeException("non nullable projection") \ No newline at end of file diff --git a/compiler/testData/script/variance_parameters.kts b/compiler/testData/script/variance_parameters.kts new file mode 100644 index 00000000000..7fe96a98a6b --- /dev/null +++ b/compiler/testData/script/variance_parameters.kts @@ -0,0 +1,4 @@ +val v1 = param1[0].toString() +val v2 = param2[0].toLong() + +System.out.println("$v1 and $v2") diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt index 7631cef602e..d1ae7bd423f 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.utils.PathUtil import org.junit.Assert import org.junit.Test import java.io.File +import java.lang.Exception import java.net.URLClassLoader import java.util.concurrent.Future import kotlin.reflect.KClass @@ -90,6 +91,41 @@ class ScriptTest2 { aClass!!.getConstructor(Integer.TYPE).newInstance(4) } + @Test + fun testScriptWithArrayParam() { + val aClass = compileScript("array_parameter.kts", ScriptWithArrayParam::class, null) + Assert.assertNotNull(aClass) + aClass!!.getConstructor(Array::class.java).newInstance(arrayOf("one", "two")) + } + + @Test + fun testScriptWithNullableParam() { + val aClass = compileScript("nullable_parameter.kts", ScriptWithNullableParam::class, null) + Assert.assertNotNull(aClass) + aClass!!.getConstructor(Int::class.javaObjectType).newInstance(null) + } + + @Test + fun testScriptVarianceParams() { + val aClass = compileScript("variance_parameters.kts", ScriptVarianceParams::class, null) + Assert.assertNotNull(aClass) + aClass!!.getConstructor(Array::class.java, Array::class.java).newInstance(arrayOf("one"), arrayOf(1, 2)) + } + + @Test + fun testScriptWithNullableProjection() { + val aClass = compileScript("nullable_projection.kts", ScriptWithNullableProjection::class, null) + Assert.assertNotNull(aClass) + aClass!!.getConstructor(Array::class.java).newInstance(arrayOf(null)) + } + + @Test + fun testScriptWithArray2DParam() { + val aClass = compileScript("array2d_param.kts", ScriptWithArray2DParam::class, null) + Assert.assertNotNull(aClass) + aClass!!.getConstructor(Array>::class.java).newInstance(arrayOf(arrayOf("one"), arrayOf("two"))) + } + private fun compileScript( scriptPath: String, scriptBase: KClass, @@ -203,6 +239,21 @@ abstract class ScriptWithoutParams(num: Int) resolver = TestKotlinScriptDependenciesResolver::class) abstract class ScriptBaseClassWithOverridenProperty(override val num: Int) : TestClassWithOverridableProperty(num) +@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class) +abstract class ScriptWithArrayParam(val myArgs: Array) + +@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class) +abstract class ScriptWithNullableParam(val param: Int?) + +@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class) +abstract class ScriptVarianceParams(val param1: Array, val param2: Array) + +@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class) +abstract class ScriptWithNullableProjection(val param: Array) + +@ScriptTemplateDefinition(resolver = TestKotlinScriptDependenciesResolver::class) +abstract class ScriptWithArray2DParam(val param: Array>) + @Target(AnnotationTarget.FILE) @Retention(AnnotationRetention.RUNTIME) annotation class DependsOn(val path: String)