Fixes and refactorings after review

This commit is contained in:
Ilya Chernikov
2018-05-02 16:56:58 +02:00
parent dff4be9e04
commit 48cf0bd949
13 changed files with 236 additions and 171 deletions
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.lazy.descriptors.ScriptEnvironmentPropertyDescriptor;
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentPropertyDescriptor;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.types.ErrorUtils;
@@ -631,9 +631,9 @@ public class PropertyCodegen {
}
}
private static class ScriptEnvPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
public static final String MAP_IFACE_NAME = "java/util/Map";
public static final String MAP_FIELD_NAME = "environment";
static class ScriptEnvPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
public static final Type MAP_IFACE_TYPE = Type.getObjectType("java/util/Map");
public static final String MAP_FIELD_NAME = "$scriptEnvironment";
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
public ScriptEnvPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
@@ -645,20 +645,20 @@ public class PropertyCodegen {
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
InstructionAdapter v = codegen.v;
String intScriptName =
state.getTypeMapper().mapClass((ClassifierDescriptor)(propertyAccessorDescriptor.getCorrespondingProperty().getContainingDeclaration())).getClassName();
v.visitVarInsn(Opcodes.ALOAD, 0);
v.visitFieldInsn(Opcodes.GETFIELD, intScriptName, MAP_FIELD_NAME, Type.getObjectType(MAP_IFACE_NAME).getDescriptor());
v.visitLdcInsn(propertyAccessorDescriptor.getCorrespondingProperty().getName().asString());
Type scriptType = state.getTypeMapper().mapOwner(propertyAccessorDescriptor);
String scriptInternalName = scriptType.getInternalName();
v.load(0, scriptType);
v.getfield(scriptInternalName, MAP_FIELD_NAME, MAP_IFACE_TYPE.getDescriptor());
v.aconst(propertyAccessorDescriptor.getCorrespondingProperty().getName().asString());
if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) {
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_NAME, "get",
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true);
v.invokeinterface(MAP_IFACE_TYPE.getInternalName(), "get",
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE));
}
else {
Type valueType = state.getTypeMapper().mapType(propertyAccessorDescriptor.getCorrespondingProperty());
v.load(1, valueType);
StackValue.coerce(valueType, AsmTypes.OBJECT_TYPE, v);
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_NAME, "set",
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_TYPE.getInternalName(), "put",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true);
}
Type returnType = state.getTypeMapper().mapReturnType(propertyAccessorDescriptor);
@@ -168,10 +168,10 @@ class ScriptCodegen private constructor(
if (scriptDefinition.environmentVariables.isNotEmpty()) {
val envParamIndex = frameMap.enterTemp(AsmTypes.OBJECT_TYPE)
val mapType = Type.getObjectType("java/util/Map")
val mapType = PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_IFACE_TYPE
iv.load(0, classType)
iv.load(envParamIndex, mapType)
iv.putfield(classType.internalName, "environment", mapType.descriptor)
iv.putfield(classType.internalName, PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_FIELD_NAME, mapType.descriptor)
}
val codegen = ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this)
@@ -210,8 +210,8 @@ class ScriptCodegen private constructor(
classBuilder.newField(
NO_ORIGIN,
ACC_PUBLIC or ACC_FINAL,
"environment",
Type.getObjectType("java/util/Map").descriptor,
PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_FIELD_NAME,
PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_IFACE_TYPE.descriptor,
null,
null
)
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.lazy.descriptors.ScriptEnvironmentDescriptor
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentDescriptor
import org.jetbrains.org.objectweb.asm.Type
import kotlin.reflect.KClass
@@ -412,7 +412,7 @@ class KotlinCoreEnvironment private constructor(
setCompatibleBuild()
// If not disabled explicitly, we should always support at least the standard script definition
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
!configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).contains(StandardScriptDefinition)
StandardScriptDefinition !in configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)
) {
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
}
@@ -205,9 +205,6 @@ class KotlinCoreEnvironment private constructor(
})
sourceFiles.sortBy { it.virtualFile.path }
// We should always support at least the standard script definition
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
if (scriptDefinitionProvider != null) {
scriptDefinitionProvider.setScriptDefinitionsSources(
@@ -411,6 +408,11 @@ class KotlinCoreEnvironment private constructor(
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
setCompatibleBuild()
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
StandardScriptDefinition !in configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)
) {
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
}
val appEnv = getOrCreateApplicationEnvironmentForProduction(configuration)
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
@@ -445,7 +447,10 @@ class KotlinCoreEnvironment private constructor(
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val configuration = initialConfiguration.copy()
if (configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()) {
// in tests we assume that standard definition should only be added if no other explicit defs are already added
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()
) {
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
}
// Tests are supposed to create a single project and dispose it right after use
@@ -207,9 +207,6 @@ class KotlinCoreEnvironment private constructor(
})
sourceFiles.sortBy { it.virtualFile.path }
// We should always support at least the standard script definition
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
if (scriptDefinitionProvider != null) {
scriptDefinitionProvider.setScriptDefinitionsSources(
@@ -413,6 +410,11 @@ class KotlinCoreEnvironment private constructor(
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
setCompatibleBuild()
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
StandardScriptDefinition !in configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)
) {
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
}
val appEnv = getOrCreateApplicationEnvironmentForProduction(configuration)
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
@@ -447,7 +449,10 @@ class KotlinCoreEnvironment private constructor(
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val configuration = initialConfiguration.copy()
if (configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()) {
// in tests we assume that standard definition should only be added if no other explicit defs are already added
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()
) {
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
}
// Tests are supposed to create a single project and dispose it right after use
@@ -98,8 +98,8 @@ public interface Errors {
DiagnosticFactory2<PsiElement, String, String> API_NOT_AVAILABLE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<PsiElement, FqName> MISSING_DEPENDENCY_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, FqName> MISSING_SCRIPT_RECEIVER_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, FqName> MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_RECEIVER_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
@@ -18,11 +18,8 @@ package org.jetbrains.kotlin.resolve.lazy.descriptors
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -33,16 +30,14 @@ import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
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.lazy.descriptors.script.ScriptEnvironmentDescriptor
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.source.toSourceElement
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.ScriptHelper
import org.jetbrains.kotlin.script.ScriptPriorities
import org.jetbrains.kotlin.script.getScriptDefinition
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.ifEmpty
import kotlin.reflect.KClass
import kotlin.reflect.KType
@@ -102,8 +97,8 @@ class LazyScriptDescriptor(
}
}
internal fun findTypeDescriptor(type: KType, errorDiagnostic: DiagnosticFactory1<PsiElement, FqName>): ClassDescriptor? {
val receiverClassId = type.classifier?.let { it as? KClass<*> }?.classId
internal fun findTypeDescriptor(type: KType, errorDiagnostic: DiagnosticFactory1<PsiElement, String>): ClassDescriptor? {
val receiverClassId = type.classId
return receiverClassId?.let {
module.findClassAcrossModuleDependencies(it)
} ?: also {
@@ -111,7 +106,7 @@ class LazyScriptDescriptor(
resolveSession.trace.report(
errorDiagnostic.on(
scriptInfo.script,
receiverClassId?.asSingleFqName() ?: FqName(type.toString())
receiverClassId?.asSingleFqName()?.toString() ?: type.toString()
)
)
}
@@ -123,7 +118,7 @@ class LazyScriptDescriptor(
ScriptEnvironmentDescriptor(this)
}
override fun getScriptEnvironmentProperties(): List<PropertyDescriptor> = scriptEnvironment().properties
override fun getScriptEnvironmentProperties(): List<PropertyDescriptor> = scriptEnvironment().properties()
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
var outerScope = super.getOuterScope()
@@ -156,109 +151,3 @@ private val KClass<*>.classId: ClassId
private val KType.classId: ClassId?
get() = classifier?.let { it as? KClass<*> }?.classId
class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
MutableClassDescriptor(
script, ClassKind.CLASS, false, false,
Name.special("<synthetic script environment for ${script.name}>"), SourceElement.NO_SOURCE, LockBasedStorageManager.NO_LOCKS
) {
init {
modality = Modality.FINAL
visibility = Visibilities.PUBLIC
setTypeParameterDescriptors(emptyList())
createTypeConstructor()
}
private val memberScope by lazy {
ScriptEnvironmentMemberScope(
script.name.identifier,
properties
)
}
override fun getUnsubstitutedMemberScope(): MemberScope = memberScope
val properties by lazy {
script.scriptDefinition.environmentVariables.mapNotNull { (name, type) ->
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
name to it
}
}.map { (key, value) ->
ScriptEnvironmentPropertyDescriptor(
Name.identifier(key),
value,
thisAsReceiverParameter,
true,
script
)
}
}
}
private class ScriptEnvironmentMemberScope(
private val scriptId: String,
private val environmentProperties: List<PropertyDescriptor>
) : MemberScopeImpl() {
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> =
environmentProperties.filter { kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK) && nameFilter(it.name) }
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
environmentProperties.filter { it.name == name }
override fun printScopeStructure(p: Printer) {
p.println("Scope of script environment: $scriptId")
}
}
class ScriptEnvironmentPropertyDescriptor(
name: Name,
typeDescriptor: ClassDescriptor,
receiver: ReceiverParameterDescriptor?,
isVar: Boolean,
script: LazyScriptDescriptor
) : PropertyDescriptorImpl(
script,
null,
Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
isVar,
name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE,
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
/* isDelegated = */ true
) {
init {
setType(typeDescriptor.defaultType, emptyList<TypeParameterDescriptorImpl>(), receiver, null as KotlinType?)
initialize(
makePropertyGetterDescriptor(),
if (!isVar) null else makePropertySetterDescriptor()
)
}
}
private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() =
PropertyGetterDescriptorImpl(
this, Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
/* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE
).also {
it.initialize(returnType)
}
private fun PropertyDescriptorImpl.makePropertySetterDescriptor() =
PropertySetterDescriptorImpl(
this, Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
/* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE
).also {
it.initialize(
ValueParameterDescriptorImpl(
this, null, 0, Annotations.EMPTY, Name.special("<set-?>"), returnType,
/* declaresDefaultValue = */ false, /* isCrossinline = */ false, /* isNoinline = */ false,
null, SourceElement.NO_SOURCE
)
)
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy.descriptors.script
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.Printer
class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
MutableClassDescriptor(
script,
ClassKind.CLASS, false, false,
Name.special("<synthetic script environment for ${script.name}>"),
SourceElement.NO_SOURCE,
LockBasedStorageManager.NO_LOCKS
) {
init {
modality = Modality.FINAL
visibility = Visibilities.PUBLIC
setTypeParameterDescriptors(emptyList())
createTypeConstructor()
}
private val memberScope: () -> ScriptEnvironmentMemberScope = script.resolveSession.storageManager.createLazyValue {
ScriptEnvironmentMemberScope(
script.name.identifier,
properties()
)
}
override fun getUnsubstitutedMemberScope(): MemberScope = memberScope()
val properties: () -> List<ScriptEnvironmentPropertyDescriptor> = script.resolveSession.storageManager.createLazyValue {
script.scriptDefinition.environmentVariables.mapNotNull { (name, type) ->
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
name to it
}
}.map { (name, classDescriptor) ->
ScriptEnvironmentPropertyDescriptor(
Name.identifier(name),
classDescriptor,
thisAsReceiverParameter,
true,
script
)
}
}
private class ScriptEnvironmentMemberScope(
private val scriptId: String,
private val environmentProperties: List<PropertyDescriptor>
) : MemberScopeImpl() {
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> =
environmentProperties
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
environmentProperties.filter { it.name == name }
override fun printScopeStructure(p: Printer) {
p.println("Scope of script environment: $scriptId")
}
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy.descriptors.script
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
import org.jetbrains.kotlin.types.KotlinType
class ScriptEnvironmentPropertyDescriptor(
name: Name,
typeDescriptor: ClassDescriptor,
receiver: ReceiverParameterDescriptor?,
isVar: Boolean,
script: LazyScriptDescriptor
) : PropertyDescriptorImpl(
script,
null,
Annotations.EMPTY,
Modality.OPEN,
Visibilities.PUBLIC,
isVar,
name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE,
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
/* isDelegated = */ false
) {
init {
setType(typeDescriptor.defaultType, emptyList<TypeParameterDescriptorImpl>(), receiver, null as KotlinType?)
initialize(
makePropertyGetterDescriptor(),
if (!isVar) null else makePropertySetterDescriptor()
)
}
}
private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() =
PropertyGetterDescriptorImpl(
this,
Annotations.EMPTY,
this.modality,
this.visibility,
/* isDefault = */
false, /* isExternal = */
false, /* isInline = */
false,
this.kind,
null,
SourceElement.NO_SOURCE
).also {
it.initialize(returnType)
}
private fun PropertyDescriptorImpl.makePropertySetterDescriptor() =
PropertySetterDescriptorImpl(
this,
Annotations.EMPTY,
this.modality,
this.visibility,
/* isDefault = */
false, /* isExternal = */
false, /* isInline = */
false,
this.kind,
null,
SourceElement.NO_SOURCE
).also {
it.initialize(
ValueParameterDescriptorImpl(
this,
null,
0,
Annotations.EMPTY,
Name.special("<set-?>"),
returnType,
/* declaresDefaultValue = */
false, /* isCrossinline = */
false, /* isNoinline = */
false,
null,
SourceElement.NO_SOURCE
)
)
}
@@ -16,10 +16,12 @@
package org.jetbrains.kotlin.script
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.KotlinFileType
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
@@ -34,7 +36,10 @@ interface ScriptDefinitionProvider {
}
}
fun ScriptDefinitionProvider.findScriptDefinition(file: VirtualFile): KotlinScriptDefinition? = findScriptDefinition(file.name)
fun ScriptDefinitionProvider.findScriptDefinition(file: VirtualFile): KotlinScriptDefinition? {
assert(!file.isDirectory) { "Do not expect directory in findScriptDefinition call: $file" }
return findScriptDefinition(file.name)
}
fun getScriptDefinition(file: VirtualFile, project: Project): KotlinScriptDefinition? =
ScriptDefinitionProvider.getInstance(project).findScriptDefinition(file)
@@ -51,10 +56,9 @@ abstract class LazyScriptDefinitionProvider : ScriptDefinitionProvider {
private var _cachedDefinitions: Sequence<KotlinScriptDefinition>? = null
private val cachedDefinitions: Sequence<KotlinScriptDefinition>
get() {
// assuming it is always called under read lock
assert(lock.readLockCount > 0)
assert(lock.readLockCount > 0) { "cachedDefinitions should only be used under the read lock" }
if (_cachedDefinitions == null) lock.write {
_cachedDefinitions = CashingSequence(currentDefinitions.constrainOnce())
_cachedDefinitions = CachingSequence(currentDefinitions.constrainOnce())
}
return _cachedDefinitions!!
}
@@ -75,38 +79,31 @@ abstract class LazyScriptDefinitionProvider : ScriptDefinitionProvider {
cachedDefinitions.firstOrNull { it.isScript(fileName) }
}
override fun isScript(fileName: String) =
if (nonScriptFileName(fileName)) false
else lock.read {
cachedDefinitions.any { it.isScript(fileName) }
}
override fun isScript(fileName: String) = findScriptDefinition(fileName) != null
companion object {
// TODO: find a common place for storing kotlin-related extensions and reuse values from it everywhere
protected val nonScriptFilenameSuffixes = arrayOf(".kt", ".java")
protected val nonScriptFilenameSuffixes = arrayOf(".${KotlinFileType.EXTENSION}", ".${JavaFileType.DEFAULT_EXTENSION}")
}
}
private class CashingSequence<T>(from: Sequence<T>) : Sequence<T> {
private class CachingSequence<T>(from: Sequence<T>) : Sequence<T> {
private val lock = ReentrantReadWriteLock()
private val sequenceIterator = from.iterator()
private val cache = arrayListOf<T>()
private inner class CashingIterator : Iterator<T> {
private inner class CachingIterator : Iterator<T> {
private val cacheIterator: Iterator<T> = cache.iterator()
private var cacheRunOut = !cacheIterator.hasNext()
private var cacheCursor = 0
private fun cacheHasNext() = !cacheRunOut && (cacheIterator.hasNext().also { if (!it) cacheRunOut = true })
override fun hasNext(): Boolean = lock.read { cacheCursor < cache.size || sequenceIterator.hasNext() }
override fun hasNext(): Boolean = lock.read { cacheHasNext() || sequenceIterator.hasNext() }
override fun next(): T = lock.read {
if (cacheHasNext()) cacheIterator.next()
else sequenceIterator.next().also { lock.write { cache.add(it) } }
override fun next(): T = lock.write {
if (cacheCursor < cache.size) cache[cacheCursor++]
else sequenceIterator.next().also { cache.add(it) }
}
}
override fun iterator(): Iterator<T> = CashingIterator()
override fun iterator(): Iterator<T> = CachingIterator()
}
@@ -95,6 +95,7 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
}
private fun updateDefinitions() {
assert(lock.isWriteLocked) { "updateDefinitions should only be called under the write lock" }
definitions = definitionsByContributor.values.flattenTo(mutableListOf()).asSequence()
clearCache()
// TODO: clear by script type/definition
@@ -5,7 +5,7 @@
package kotlin.script.experimental.basic
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.full.createInstance
import kotlin.script.experimental.annotations.KotlinScriptDefaultCompilationConfiguration
import kotlin.script.experimental.api.*
import kotlin.script.experimental.util.TypedKey
@@ -18,15 +18,15 @@ open class AnnotationsBasedCompilationConfigurator(val environment: ScriptingEnv
override val defaultConfiguration = run {
val base = environment[ScriptingEnvironmentProperties.baseClass]
val cfg = base.annotations.filterIsInstance(KotlinScriptDefaultCompilationConfiguration::class.java).flatMap {
val cfg = base.annotations.filterIsInstance(KotlinScriptDefaultCompilationConfiguration::class.java).flatMap { ann ->
val params = try {
it.compilationConfiguration.objectInstance ?: it.compilationConfiguration.primaryConstructor!!.callBy(emptyMap())
ann.compilationConfiguration.objectInstance ?: ann.compilationConfiguration.createInstance()
} catch (e: Throwable) {
throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e)
}
params.forEach {
if (it !is Pair<*, *> || it.first !is TypedKey<*>)
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: invalid parameter $it")
params.forEach { param ->
if (param !is Pair<*, *> || param.first !is TypedKey<*>)
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: invalid parameter $param")
}
params as List<Pair<TypedKey<*>, Any?>>
}