Expose script parameters from descriptor explicitly...

and universally as ValueParameterDescriptors;
update implementation accordingly
This commit is contained in:
Ilya Chernikov
2020-10-22 20:50:24 +02:00
parent 4cb0437145
commit 7572b50385
5 changed files with 118 additions and 156 deletions
@@ -724,7 +724,7 @@ open class WrappedScriptDescriptor : ScriptDescriptor, WrappedDeclarationDescrip
}
override fun getDefaultFunctionTypeForSamInterface(): SimpleType? {
TODO("not implemented")
TODO("not yet implemented")
}
override fun isDefinitelyNotSamInterface(): Boolean {
@@ -735,6 +735,18 @@ open class WrappedScriptDescriptor : ScriptDescriptor, WrappedDeclarationDescrip
TODO("Not yet implemented")
}
override fun getExplicitConstructorParameters(): MutableList<ValueParameterDescriptor> {
TODO("Not yet implemented")
}
override fun getImplicitReceiversParameters(): MutableList<ValueParameterDescriptor> {
TODO("Not yet implemented")
}
override fun getScriptProvidedPropertiesParameters(): MutableList<ValueParameterDescriptor> {
TODO("Not yet implemented")
}
override fun getImplicitReceivers(): MutableList<ClassDescriptor> {
TODO("Not yet implemented")
}
@@ -36,4 +36,13 @@ public interface ScriptDescriptor extends ClassDescriptor {
@Nullable
PropertyDescriptor getResultValue();
@NotNull
List<ValueParameterDescriptor> getExplicitConstructorParameters();
@NotNull
List<ValueParameterDescriptor> getImplicitReceiversParameters();
@NotNull
List<ValueParameterDescriptor> getScriptProvidedPropertiesParameters();
}
@@ -5,18 +5,13 @@
package org.jetbrains.kotlin.scripting.resolve
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassMemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
class LazyScriptClassMemberScope(
resolveSession: ResolveSession,
@@ -28,65 +23,17 @@ class LazyScriptClassMemberScope(
private val _variableNames: MutableSet<Name>
by lazy(LazyThreadSafetyMode.PUBLICATION) {
super.getVariableNames().apply {
scriptDescriptor.scriptProvidedProperties.forEach {
add(it.name)
}
scriptDescriptor.resultFieldName()?.let {
add(it)
}
}
}
private val scriptPrimaryConstructor: () -> ClassConstructorDescriptorImpl? = resolveSession.storageManager.createNullableLazyValue {
val baseClass = scriptDescriptor.baseClassDescriptor()
val baseConstructorDescriptor = baseClass?.unsubstitutedPrimaryConstructor
if (baseConstructorDescriptor != null) {
val implicitReceiversParamTypes =
scriptDescriptor.implicitReceivers.mapIndexed { idx, receiver ->
val name =
if (receiver is ScriptDescriptor) "$IMPORTED_SCRIPT_PARAM_NAME_PREFIX${receiver.name}"
else "$IMPLICIT_RECEIVER_PARAM_NAME_PREFIX$idx"
name to receiver.defaultType
}
val providedPropertiesParamTypes =
scriptDescriptor.scriptProvidedProperties.map {
it.name.identifier to it.type
}
val annotations = baseConstructorDescriptor.annotations
val constructorDescriptor = ClassConstructorDescriptorImpl.create(
scriptDescriptor, annotations, baseConstructorDescriptor.isPrimary, scriptDescriptor.source
)
var paramsIndexBase = baseConstructorDescriptor.valueParameters.lastIndex + 1
val syntheticParameters =
(implicitReceiversParamTypes + providedPropertiesParamTypes).map { param: Pair<String, KotlinType> ->
ValueParameterDescriptorImpl(
constructorDescriptor,
null,
paramsIndexBase++,
Annotations.EMPTY,
Name.identifier(param.first),
param.second,
false, false, false, null, SourceElement.NO_SOURCE
)
}
val parameters = baseConstructorDescriptor.valueParameters.map { it.copy(constructorDescriptor, it.name, it.index) } +
syntheticParameters
constructorDescriptor.initialize(parameters, baseConstructorDescriptor.visibility)
constructorDescriptor.returnType = scriptDescriptor.defaultType
constructorDescriptor
} else {
null
}
}
override fun resolvePrimaryConstructor(): ClassConstructorDescriptor? {
val constructor = scriptPrimaryConstructor()
?: ClassConstructorDescriptorImpl.create(
scriptDescriptor,
Annotations.EMPTY,
true,
SourceElement.NO_SOURCE
).initialize(
emptyList(),
DescriptorVisibilities.PUBLIC
)
override fun resolvePrimaryConstructor(): ClassConstructorDescriptor {
val constructor = scriptDescriptor.scriptPrimaryConstructorWithParams().constructor
setDeferredReturnType(constructor)
return constructor
}
@@ -100,6 +47,7 @@ class LazyScriptClassMemberScope(
result.add(it)
}
}
scriptDescriptor.scriptProvidedProperties.forEach { if (it.name == name) result.add(it) }
}
override fun createPropertiesFromPrimaryConstructorParameters(name: Name, result: MutableSet<PropertyDescriptor>) {
@@ -111,5 +59,3 @@ class LazyScriptClassMemberScope(
}
}
private fun ClassDescriptor.substitute(vararg types: KotlinType): KotlinType? =
KotlinTypeFactory.simpleType(this.defaultType, arguments = types.map { it.asTypeProjection() })
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.scripting.resolve
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.VirtualFileSystem
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Errors.MISSING_IMPORTED_SCRIPT_FILE
@@ -53,6 +56,7 @@ import kotlin.script.experimental.host.GetScriptingClass
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.host.getScriptingClass
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import kotlin.script.experimental.jvm.util.toValidJvmIdentifier
class LazyScriptDescriptor(
@@ -179,11 +183,11 @@ class LazyScriptDescriptor(
private inner class ImportedScriptDescriptorsFinder {
val localFS by lazy {
val localFS: VirtualFileSystem by lazy(LazyThreadSafetyMode.PUBLICATION) {
val fileManager = VirtualFileManager.getInstance()
fileManager.getFileSystem(StandardFileSystems.FILE_PROTOCOL)
}
val psiManager by lazy { PsiManager.getInstance(scriptInfo.script.project) }
val psiManager by lazy(LazyThreadSafetyMode.PUBLICATION) { PsiManager.getInstance(scriptInfo.script.project) }
operator fun invoke(importedScript: SourceCode): ScriptDescriptor? {
// Note: is not an error now - if import references other valid source file, it is simply compiled along with script
@@ -264,22 +268,93 @@ class LazyScriptDescriptor(
override fun getImplicitReceivers(): List<ClassDescriptor> = scriptImplicitReceivers()
private val scriptProvidedProperties: () -> ScriptProvidedPropertiesDescriptor = resolveSession.storageManager.createLazyValue {
ScriptProvidedPropertiesDescriptor(this)
private val scriptProvidedProperties: () -> List<ScriptProvidedPropertyDescriptor> = resolveSession.storageManager.createLazyValue {
scriptCompilationConfiguration()[ScriptCompilationConfiguration.providedProperties].orEmpty()
.mapNotNull { (name, type) ->
findTypeDescriptor(getScriptingClass(type), Errors.MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS)
?.let { name.toValidJvmIdentifier() to it }
}.map { (name, classDescriptor) ->
ScriptProvidedPropertyDescriptor(
Name.identifier(name),
classDescriptor,
thisAsReceiverParameter,
true,
this
)
}
}
override fun getScriptProvidedProperties(): List<PropertyDescriptor> = scriptProvidedProperties().properties()
override fun getScriptProvidedProperties(): List<PropertyDescriptor> = scriptProvidedProperties()
internal class ConstructorWithParams(
val constructor: ClassConstructorDescriptorImpl,
val explicitConstructorParameters: List<ValueParameterDescriptor>,
val implicitReceiversParameters: List<ValueParameterDescriptor>,
val scriptProvidedPropertiesParameters: List<ValueParameterDescriptor>
)
internal val scriptPrimaryConstructorWithParams: () -> ConstructorWithParams = resolveSession.storageManager.createLazyValue {
val baseConstructorDescriptor = baseClassDescriptor()?.unsubstitutedPrimaryConstructor
val inheritedAnnotations = baseConstructorDescriptor?.annotations ?: Annotations.EMPTY
val baseExplicitParameters = baseConstructorDescriptor?.valueParameters ?: emptyList()
val implicitReceiversParamTypes =
implicitReceivers.mapIndexed { idx, receiver ->
val receiverName =
if (receiver is ScriptDescriptor) "${LazyScriptClassMemberScope.IMPORTED_SCRIPT_PARAM_NAME_PREFIX}${receiver.name}"
else "${LazyScriptClassMemberScope.IMPLICIT_RECEIVER_PARAM_NAME_PREFIX}$idx"
receiverName to receiver.defaultType
}
val providedPropertiesParamTypes =
scriptProvidedProperties().map {
it.name.identifier to it.type
}
val constructorDescriptor = ClassConstructorDescriptorImpl.create(this, inheritedAnnotations, true, source)
var paramsIndexBase = baseExplicitParameters.lastIndex + 1
fun createValueParameter(param: Pair<String, org.jetbrains.kotlin.types.KotlinType>) =
ValueParameterDescriptorImpl(
constructorDescriptor,
null,
paramsIndexBase++,
Annotations.EMPTY,
Name.identifier(param.first),
param.second,
declaresDefaultValue = false, isCrossinline = false, isNoinline = false, varargElementType = null,
source = SourceElement.NO_SOURCE
)
val explicitParameters = baseExplicitParameters.map { it.copy(constructorDescriptor, it.name, it.index) }
val implicitReceiversParameters = implicitReceiversParamTypes.map(::createValueParameter)
val providedPropertiesParameters = providedPropertiesParamTypes.map(::createValueParameter)
constructorDescriptor.initialize(
explicitParameters + implicitReceiversParameters + providedPropertiesParameters, DescriptorVisibilities.PUBLIC
)
constructorDescriptor.returnType = defaultType()
ConstructorWithParams(
constructorDescriptor,
explicitConstructorParameters = explicitParameters,
implicitReceiversParameters = implicitReceiversParameters,
scriptProvidedPropertiesParameters = providedPropertiesParameters
)
}
override fun getExplicitConstructorParameters(): List<ValueParameterDescriptor> =
scriptPrimaryConstructorWithParams().explicitConstructorParameters
override fun getImplicitReceiversParameters(): List<ValueParameterDescriptor> =
scriptPrimaryConstructorWithParams().implicitReceiversParameters
override fun getScriptProvidedPropertiesParameters(): List<ValueParameterDescriptor> =
scriptPrimaryConstructorWithParams().scriptProvidedPropertiesParameters
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
var outerScope = super.getOuterScope()
val outerScopeReceivers = implicitReceivers.let {
if (scriptCompilationConfiguration()[ScriptCompilationConfiguration.providedProperties]?.isNotEmpty() == true) {
it + ScriptProvidedPropertiesDescriptor(this)
} else {
it
}
}
for (receiverClassDescriptor in outerScopeReceivers.asReversed()) {
for (receiverClassDescriptor in implicitReceivers.asReversed()) {
outerScope = LexicalScopeImpl(
outerScope,
receiverClassDescriptor,
@@ -1,80 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.scripting.resolve
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.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.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.utils.Printer
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.providedProperties
import kotlin.script.experimental.jvm.util.toValidJvmIdentifier
class ScriptProvidedPropertiesDescriptor(script: LazyScriptDescriptor) :
MutableClassDescriptor(
script,
ClassKind.CLASS, false, false,
Name.special("<synthetic script provided properties for ${script.name}>"),
SourceElement.NO_SOURCE,
LockBasedStorageManager.NO_LOCKS
) {
init {
modality = Modality.FINAL
visibility = DescriptorVisibilities.PUBLIC
setTypeParameterDescriptors(emptyList())
createTypeConstructor()
}
private val memberScope: () -> ScriptProvidedPropertiesMemberScope = script.resolveSession.storageManager.createLazyValue {
ScriptProvidedPropertiesMemberScope(
script.name.identifier,
properties()
)
}
override fun getUnsubstitutedMemberScope(kotlinTypeRefiner: KotlinTypeRefiner): MemberScope = memberScope()
val properties: () -> List<ScriptProvidedPropertyDescriptor> = script.resolveSession.storageManager.createLazyValue {
script.scriptCompilationConfiguration()[ScriptCompilationConfiguration.providedProperties].orEmpty().mapNotNull { (name, type) ->
script.findTypeDescriptor(script.getScriptingClass(type), Errors.MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS)
?.let { name.toValidJvmIdentifier() to it }
}.map { (name, classDescriptor) ->
ScriptProvidedPropertyDescriptor(
Name.identifier(name),
classDescriptor,
thisAsReceiverParameter,
true,
script
)
}
}
private class ScriptProvidedPropertiesMemberScope(
private val scriptId: String,
private val providedProperties: List<PropertyDescriptor>
) : MemberScopeImpl() {
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> =
providedProperties
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
providedProperties.filter { it.name == name }
override fun printScopeStructure(p: Printer) {
p.println("Scope of script provided properties: $scriptId")
}
}
}