diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt index 1d79f0bfb84..a88c77a57f9 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.idea.core.script.scriptCompilationConfiguration import org.jetbrains.kotlin.idea.core.script.scriptDependencies +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource import kotlin.script.experimental.api.asSuccess @@ -26,7 +27,7 @@ class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDepend debug(file) { "refined configuration from fileAttributes = $it" } } } ?: file.scriptDependencies?.let { - ScriptCompilationConfigurationWrapper.FromLegacy(VirtualFileScriptSource(file), it).apply { + ScriptCompilationConfigurationWrapper.FromLegacy(VirtualFileScriptSource(file), it, file.findScriptDefinition(project)).apply { debug(file) { "dependencies from fileAttributes = $it" } } }?.let { diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/BridgeScriptDefinition.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/BridgeScriptDefinition.kt deleted file mode 100644 index 953fb64e733..00000000000 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/BridgeScriptDefinition.kt +++ /dev/null @@ -1,145 +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 kotlin.script.experimental.jvmhost.impl - -import com.intellij.openapi.fileTypes.LanguageFileType -import org.jetbrains.kotlin.idea.KotlinFileType -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.NameUtils -import org.jetbrains.kotlin.psi.KtScript -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import kotlin.reflect.KClass -import kotlin.reflect.KType -import kotlin.reflect.full.starProjectedType -import kotlin.script.dependencies.ScriptContents -import kotlin.script.experimental.api.* -import kotlin.script.experimental.dependencies.DependenciesResolver -import kotlin.script.experimental.host.ScriptingHostConfiguration -import kotlin.script.experimental.host.getScriptingClass -import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver -import kotlin.script.experimental.util.getOrError - -// A bridge to the current scripting -// mostly copies functionality from KotlinScriptDefinitionAdapterFromNewAPI[Base] -// reusing it requires structural changes that doesn't seem justified now, since the internals of the scripting should be reworked soon anyway -// TODO: either finish refactoring of the scripting internals or reuse KotlinScriptDefinitionAdapterFromNewAPI[Base] here -// NOTE: since KotlinScriptDefinition is not designed to separate static (script definition related) and dynamic (actual script compilation -// configuration) parameters, the implementation is quite hacky, especially for cases as REPL -// TODO: finish refactoring and replace KotlinScriptDefinition with right abstractions -internal class BridgeScriptDefinition( - val scriptCompilationConfiguration: ScriptCompilationConfiguration, - val hostConfiguration: ScriptingHostConfiguration, - dynamicState: BridgeScriptDefinitionDynamicState -) : KotlinScriptDefinition(Any::class) { - - val baseClass: KClass<*> by lazy(LazyThreadSafetyMode.PUBLICATION) { - getScriptingClass(scriptCompilationConfiguration.getOrError(ScriptCompilationConfiguration.baseClass)) - } - - override val template: KClass<*> get() = baseClass - - override val name: String - get() = scriptCompilationConfiguration[ScriptCompilationConfiguration.displayName] ?: "Kotlin Script" - - override val fileType: LanguageFileType = KotlinFileType.INSTANCE - - override fun isScript(fileName: String): Boolean = - fileName.endsWith(".$fileExtension") - - override fun getScriptName(script: KtScript): Name { - val fileBasedName = NameUtils.getScriptNameForFile(script.containingKtFile.name) - return Name.identifier(fileBasedName.identifier.removeSuffix(".$fileExtension")) - } - - override val fileExtension: String - get() = scriptCompilationConfiguration[ScriptCompilationConfiguration.fileExtension] ?: super.fileExtension - - override val acceptedAnnotations = run { - val cl = this::class.java.classLoader - scriptCompilationConfiguration[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]?.annotations - ?.map { (cl.loadClass(it.typeName) as Class).kotlin } - ?: emptyList() - } - - override val implicitReceivers: List by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptCompilationConfiguration[ScriptCompilationConfiguration.implicitReceivers] - .orEmpty() - .map { getScriptingClass(it).starProjectedType } - } - - override val providedProperties: List> by lazy(LazyThreadSafetyMode.PUBLICATION) { - scriptCompilationConfiguration[ScriptCompilationConfiguration.providedProperties] - ?.map { (k, v) -> k to getScriptingClass(v).starProjectedType }.orEmpty() - } - - override val additionalCompilerArguments: List - get() = scriptCompilationConfiguration[ScriptCompilationConfiguration.compilerOptions] - .orEmpty() - - override val dependencyResolver: DependenciesResolver = - BridgeDependenciesResolver( - scriptCompilationConfiguration, - dynamicState::updateConfiguration, - dynamicState::getScriptSource - ) - - private val scriptingClassGetter by lazy(LazyThreadSafetyMode.PUBLICATION) { - hostConfiguration[ScriptingHostConfiguration.getScriptingClass] - ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting environment") - } - - private fun getScriptingClass(type: KotlinType) = - scriptingClassGetter( - type, - KotlinScriptDefinition::class, // Assuming that the KotlinScriptDefinition class is loaded in the proper classloader - hostConfiguration - ) -} - -// TODO: consider synchronization, since it is mutable (or finish the refactoring after all) -internal class BridgeScriptDefinitionDynamicState { - - private val _sources = linkedSetOf() - private val _configurations = hashMapOf() - private var _baseScriptCompilationConfiguration: ScriptCompilationConfiguration? = null - - val sources: Set get() = _sources - - val configurations: Map get() = _configurations - - val baseScriptCompilationConfiguration: ScriptCompilationConfiguration get() = _baseScriptCompilationConfiguration!! - - val mainScript: SourceCode get() = sources.first() - - val mainScriptCompilationConfiguration: ScriptCompilationConfiguration - get() = configurations[mainScript] ?: baseScriptCompilationConfiguration - - fun configureFor(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration) { - _sources.clear() - _sources.add(script) - _configurations.clear() - _baseScriptCompilationConfiguration = scriptCompilationConfiguration - } - - fun updateConfiguration(script: SourceCode, updatedConfiguration: ScriptCompilationConfiguration) { - _configurations[script] = updatedConfiguration - updatedConfiguration[ScriptCompilationConfiguration.importScripts]?.let { - _sources.addAll(it) - } - } - - fun getScriptSource(scriptContents: ScriptContents): SourceCode? { - val name = scriptContents.file?.name - return sources.find { - // TODO: consider using merged text (likely should be cached) - // on the other hand it may become obsolete when scripting internals will be redesigned properly - (name != null && name == it.scriptFileName( - sources.first(), - mainScriptCompilationConfiguration - )) || it.text == scriptContents.text - } - } -} \ No newline at end of file diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt index 577fd5e5292..664bea96ae9 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import kotlin.script.experimental.api.* import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.jvmhost.KJvmCompilerProxy @@ -35,10 +36,9 @@ class KJvmCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvm getScriptKtFile(script, context.baseScriptCompilationConfiguration, context.environment.project, messageCollector) .valueOr { return it } - context.scriptCompilationState.configureFor(script, context.baseScriptCompilationConfiguration) - val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment(context, mainKtFile, messageCollector) + val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project) val analysisResult = analyze(sourceFiles, context.environment) if (!analysisResult.shouldGenerateCode) return failure(script, messageCollector, "no code to generate") @@ -48,7 +48,7 @@ class KJvmCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvm val compiledScript = makeCompiledScript(generationState, script, sourceFiles.first(), sourceDependencies) { ktFile -> - context.scriptCompilationState.configurations.entries.find { ktFile.name == it.key.name }?.value + dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration ?: context.baseScriptCompilationConfiguration } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt index 6bb7bf9d79f..d239cdc4a3d 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.CompilationErrorHandler import org.jetbrains.kotlin.codegen.KotlinCodegenFacade import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.repl.ReplCodeAnalyzer import kotlin.script.experimental.api.* import kotlin.script.experimental.host.ScriptingHostConfiguration @@ -118,9 +119,10 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : history.push(LineId(codeLine), scriptDescriptor) + val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project) val compiledScript = makeCompiledScript(generationState, snippet, sourceFiles.first(), sourceDependencies) { ktFile -> - context.scriptCompilationState.configurations.entries.find { ktFile.name == it.key.name }?.value + dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration ?: context.baseScriptCompilationConfiguration } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt index 787fd6701aa..f63cc339bee 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt @@ -27,12 +27,13 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.dependencies.ScriptsCompilationDependencies import org.jetbrains.kotlin.scripting.dependencies.collectScriptsCompilationDependencies import kotlin.script.experimental.api.ScriptCompilationConfiguration -import kotlin.script.experimental.api.SourceCode import kotlin.script.experimental.api.compilerOptions import kotlin.script.experimental.api.dependencies +import kotlin.script.experimental.api.valueOrNull import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.jdkHome @@ -44,8 +45,7 @@ internal class SharedScriptCompilationContext( val disposable: Disposable, val baseScriptCompilationConfiguration: ScriptCompilationConfiguration, val environment: KotlinCoreEnvironment, - val ignoredOptionsReportingState: IgnoredOptionsReportingState, - val scriptCompilationState: BridgeScriptDefinitionDynamicState + val ignoredOptionsReportingState: IgnoredOptionsReportingState ) internal fun createSharedCompilationContext( @@ -56,11 +56,9 @@ internal fun createSharedCompilationContext( ): SharedScriptCompilationContext { val ignoredOptionsReportingState = IgnoredOptionsReportingState() - val scriptCompilationState = BridgeScriptDefinitionDynamicState() - val (initialScriptCompilationConfiguration, kotlinCompilerConfiguration) = createInitialConfigurations( - scriptCompilationConfiguration, hostConfiguration, scriptCompilationState, messageCollector, ignoredOptionsReportingState + scriptCompilationConfiguration, hostConfiguration, messageCollector, ignoredOptionsReportingState ) val environment = KotlinCoreEnvironment.createForProduction( @@ -68,14 +66,13 @@ internal fun createSharedCompilationContext( ) return SharedScriptCompilationContext( - disposable, initialScriptCompilationConfiguration, environment, ignoredOptionsReportingState, scriptCompilationState + disposable, initialScriptCompilationConfiguration, environment, ignoredOptionsReportingState ) } internal fun createInitialConfigurations( scriptCompilationConfiguration: ScriptCompilationConfiguration, hostConfiguration: ScriptingHostConfiguration, - scriptCompilationState: BridgeScriptDefinitionDynamicState, messageCollector: ScriptDiagnosticsMessageCollector, ignoredOptionsReportingState: IgnoredOptionsReportingState ): Pair { @@ -89,14 +86,7 @@ internal fun createInitialConfigurations( kotlinCompilerConfiguration.add( ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, - ScriptDefinition.FromLegacy( - hostConfiguration, - BridgeScriptDefinition( - scriptCompilationConfiguration, - hostConfiguration, - scriptCompilationState - ) - ) + ScriptDefinition.FromConfigurations(hostConfiguration, scriptCompilationConfiguration, null) ) initialScriptCompilationConfiguration[ScriptCompilationConfiguration.compilerOptions]?.let { compilerOptions -> @@ -217,26 +207,25 @@ internal fun collectRefinedSourcesAndUpdateEnvironment( sourceFiles.addAll(newSources) - // collectScriptsCompilationDependencies calls resolver for every file, so at this point all updated configurations are collected - context.environment.configuration.updateWithRefinedConfigurations( - context.baseScriptCompilationConfiguration, context.scriptCompilationState.configurations, - messageCollector, context.ignoredOptionsReportingState - ) + // collectScriptsCompilationDependencies calls resolver for every file, so at this point all updated configurations are collected in the ScriptDependenciesProvider + context.environment.configuration.updateWithRefinedConfigurations(context, sourceFiles, messageCollector) return sourceFiles to sourceDependencies } private fun CompilerConfiguration.updateWithRefinedConfigurations( - initialScriptCompilationConfiguration: ScriptCompilationConfiguration, - refinedScriptCompilationConfigurations: Map, - messageCollector: ScriptDiagnosticsMessageCollector, - reportingState: IgnoredOptionsReportingState + context: SharedScriptCompilationContext, + sourceFiles: List, + messageCollector: ScriptDiagnosticsMessageCollector ) { - val updatedCompilerOptions = refinedScriptCompilationConfigurations.flatMap { - it.value[ScriptCompilationConfiguration.compilerOptions] ?: emptyList() + val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project) + val updatedCompilerOptions = sourceFiles.flatMap { + dependenciesProvider?.getScriptConfigurationResult(it)?.valueOrNull()?.configuration?.get( + ScriptCompilationConfiguration.compilerOptions + ) ?: emptyList() } if (updatedCompilerOptions.isNotEmpty() && - updatedCompilerOptions != initialScriptCompilationConfiguration[ScriptCompilationConfiguration.compilerOptions] + updatedCompilerOptions != context.baseScriptCompilationConfiguration[ScriptCompilationConfiguration.compilerOptions] ) { - updateWithCompilerOptions(updatedCompilerOptions, messageCollector, reportingState, true) + updateWithCompilerOptions(updatedCompilerOptions, messageCollector, context.ignoredOptionsReportingState, true) } } \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt index 990f1d74ccb..e43aaf1bafd 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt @@ -21,10 +21,11 @@ import kotlin.script.experimental.jvm.jvm // TODO: name could be confused with KotlinScriptDefinition, discuss naming abstract class ScriptDefinition : UserDataHolderBase() { + @Deprecated("Use configurations instead") abstract val legacyDefinition: KotlinScriptDefinition abstract val hostConfiguration: ScriptingHostConfiguration abstract val compilationConfiguration: ScriptCompilationConfiguration - abstract val evaluationConfiguration: ScriptEvaluationConfiguration + abstract val evaluationConfiguration: ScriptEvaluationConfiguration? abstract fun isScript(fileName: String): Boolean abstract val fileExtension: String @@ -43,9 +44,11 @@ abstract class ScriptDefinition : UserDataHolderBase() { abstract val baseClassType: KotlinType abstract val compilerOptions: Iterable + @Suppress("DEPRECATION") inline fun asLegacyOrNull(): T? = if (this is FromLegacy) legacyDefinition as? T else null + @Suppress("OverridingDeprecatedMember", "DEPRECATION") open class FromLegacy( override val hostConfiguration: ScriptingHostConfiguration, override val legacyDefinition: KotlinScriptDefinition @@ -105,6 +108,7 @@ abstract class ScriptDefinition : UserDataHolderBase() { abstract class FromConfigurationsBase : ScriptDefinition() { + @Suppress("OverridingDeprecatedMember", "DEPRECATION") override val legacyDefinition by lazy { KotlinScriptDefinitionAdapterFromNewAPI( compilationConfiguration, @@ -136,13 +140,13 @@ abstract class ScriptDefinition : UserDataHolderBase() { compilationConfiguration == it.compilationConfiguration && evaluationConfiguration == it.evaluationConfiguration } == true - override fun hashCode(): Int = compilationConfiguration.hashCode() + 37 * evaluationConfiguration.hashCode() + override fun hashCode(): Int = compilationConfiguration.hashCode() + 37 * (evaluationConfiguration?.hashCode() ?: 0) } open class FromConfigurations( override val hostConfiguration: ScriptingHostConfiguration, override val compilationConfiguration: ScriptCompilationConfiguration, - override val evaluationConfiguration: ScriptEvaluationConfiguration + override val evaluationConfiguration: ScriptEvaluationConfiguration? ) : FromConfigurationsBase() open class FromTemplate( diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt index 931a545d274..0c48623827b 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt @@ -47,7 +47,7 @@ fun findScriptDefinitionByFileName(project: Project, fileName: String): ScriptDe return scriptDefinitionProvider.findDefinition(fileName) ?: scriptDefinitionProvider.getDefaultDefinition() } -private fun VirtualFile.isNonScript(): Boolean = +internal fun VirtualFile.isNonScript(): Boolean = isDirectory || extension == KotlinFileType.EXTENSION || extension == JavaClassFileType.INSTANCE.defaultExtension || diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/dynamicConfigurations.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/dynamicConfigurations.kt new file mode 100644 index 00000000000..5a827025cf0 --- /dev/null +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/dynamicConfigurations.kt @@ -0,0 +1,42 @@ +/* + * 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.definitions + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult +import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.valueOr + +fun PsiFile.findScriptCompilationConfiguration(): ScriptCompilationConfiguration? { + // Do not use psiFile.script, see comments in findScriptDefinition + if (this !is KtFile/* || this.script == null*/) return null + val file = virtualFile ?: originalFile.virtualFile ?: return null + if (file.isNonScript()) return null + + val provider = ScriptDependenciesProvider.getInstance(project) + return provider?.getScriptConfigurationResult(this)?.valueOrError()?.configuration + ?: findScriptDefinition()?.compilationConfiguration +} + +fun VirtualFile.findScriptCompilationConfiguration(project: Project): ScriptCompilationConfiguration? { + if (!isValid || isNonScript()) return null + // see comments in findScriptDefinition + // we do not need expensive check as in findScriptDefinition here, since it is assumed that this function is called only for known scripts + + val provider = ScriptDependenciesProvider.getInstance(project) + return provider?.getScriptConfigurationResult(this)?.valueOrError()?.configuration + ?: findScriptDefinition(project)?.compilationConfiguration +} + +private fun ScriptCompilationConfigurationResult.valueOrError() = valueOr { failure -> + throw IllegalArgumentException( + "Error retrieving script compilation configuration: ${failure.reports.joinToString { it.message }}", + failure.reports.find { it.exception != null }?.exception + ) +} diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt index 148c651800e..98fb3e598f4 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.definitions.ScriptPriorities -import org.jetbrains.kotlin.scripting.definitions.findScriptDefinitionByFileName +import org.jetbrains.kotlin.scripting.definitions.findScriptCompilationConfiguration import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isUnit @@ -44,7 +44,10 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.File import kotlin.reflect.KClass import kotlin.reflect.KType -import kotlin.script.experimental.api.valueOrNull +import kotlin.script.experimental.api.* +import kotlin.script.experimental.host.GetScriptingClass +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.host.getScriptingClass class LazyScriptDescriptor( @@ -105,14 +108,28 @@ class LazyScriptDescriptor( override fun getPriority() = priority - // rewrite without using legacyDefinition below - val scriptDefinition: () -> ScriptDefinition = resolveSession.storageManager.createLazyValue { - findScriptDefinitionByFileName( - resolveSession.project, - scriptInfo.script.containingKtFile.name - ) + val scriptCompilationConfiguration: () -> ScriptCompilationConfiguration = resolveSession.storageManager.createLazyValue { + scriptInfo.script.containingKtFile.findScriptCompilationConfiguration() + ?: throw IllegalArgumentException("Unable to find script compilation configuration for the script ${scriptInfo.script.containingFile}") } + private val scriptingHostConfiguration: () -> ScriptingHostConfiguration = resolveSession.storageManager.createLazyValue { + scriptCompilationConfiguration()[ScriptCompilationConfiguration.hostConfiguration] + ?: throw IllegalArgumentException("Expecting 'hostConfiguration' property in the script compilation configuration for the script ${scriptInfo.script.containingFile}") + } + + private val scriptingClassGetter: () -> GetScriptingClass = resolveSession.storageManager.createLazyValue { + scriptingHostConfiguration()[ScriptingHostConfiguration.getScriptingClass] + ?: throw IllegalArgumentException("Expecting 'getScriptingClass' property in the scripting host configuration for the script ${scriptInfo.script.containingFile}") + } + + fun getScriptingClass(type: KotlinType): KClass<*> = + scriptingClassGetter()( + type, + ScriptDefinition::class, // Assuming that the ScriptDefinition class is loaded in the proper classloader, TODO: consider more reliable way to load or cache classes + scriptingHostConfiguration() + ) + override fun substitute(substitutor: TypeSubstitutor) = this override fun accept(visitor: DeclarationDescriptorVisitor, data: D): R = @@ -130,16 +147,20 @@ class LazyScriptDescriptor( override fun getUnsubstitutedPrimaryConstructor() = super.getUnsubstitutedPrimaryConstructor()!! internal val baseClassDescriptor: () -> ClassDescriptor? = resolveSession.storageManager.createNullableLazyValue { - val template = scriptDefinition().legacyDefinition.template + val baseClass = getScriptingClass( + scriptCompilationConfiguration()[ScriptCompilationConfiguration.baseClass] + ?: throw IllegalStateException("Base class is not configured for the script ${scriptInfo.script.containingFile}") + ) findTypeDescriptor( - template, - if (template.qualifiedName?.startsWith("kotlin.script.templates.standard") == true) Errors.MISSING_SCRIPT_STANDARD_TEMPLATE + baseClass, + if (baseClass.qualifiedName?.startsWith("kotlin.script.templates.standard") == true) Errors.MISSING_SCRIPT_STANDARD_TEMPLATE else Errors.MISSING_SCRIPT_BASE_CLASS ) } override fun computeSupertypes() = listOf(baseClassDescriptor()?.defaultType ?: builtIns.anyType) + // TODO: consider passing ScriptSource to avoid psi file fsearching private inner class ImportedScriptDescriptorsFinder { val fileManager = VirtualFileManager.getInstance() @@ -153,7 +174,7 @@ class LazyScriptDescriptor( return null } - val vfile = localFS.findFileByPath(importedScriptFile.path) + val vfile = localFS.findFileByPath(importedScriptFile.absolutePath) ?: return errorDescriptor(MISSING_IMPORTED_SCRIPT_FILE) val psiFile = psiManager.findFile(vfile) ?: return errorDescriptor(MISSING_IMPORTED_SCRIPT_PSI) @@ -177,8 +198,8 @@ class LazyScriptDescriptor( } } - scriptDefinition().legacyDefinition.implicitReceivers.mapNotNullTo(res) { receiver -> - findTypeDescriptor(receiver, Errors.MISSING_SCRIPT_RECEIVER_CLASS) + scriptCompilationConfiguration()[ScriptCompilationConfiguration.implicitReceivers]?.mapNotNullTo(res) { receiver -> + findTypeDescriptor(getScriptingClass(receiver), Errors.MISSING_SCRIPT_RECEIVER_CLASS) } res @@ -224,10 +245,10 @@ class LazyScriptDescriptor( private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue { var outerScope = super.getOuterScope() val outerScopeReceivers = implicitReceivers.let { - if (scriptDefinition().legacyDefinition.providedProperties.isEmpty()) { - it - } else { + if (scriptCompilationConfiguration()[ScriptCompilationConfiguration.providedProperties]?.isNotEmpty() == true) { it + ScriptProvidedPropertiesDescriptor(this) + } else { + it } } for (receiverClassDescriptor in outerScopeReceivers.asReversed()) { diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt index f17e7dea96f..a3fbe8f7ecd 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt @@ -15,6 +15,9 @@ 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 +import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.providedProperties +import kotlin.script.experimental.jvm.util.toValidJvmIdentifier class ScriptProvidedPropertiesDescriptor(script: LazyScriptDescriptor) : MutableClassDescriptor( @@ -42,10 +45,9 @@ class ScriptProvidedPropertiesDescriptor(script: LazyScriptDescriptor) : override fun getUnsubstitutedMemberScope(): MemberScope = memberScope() val properties: () -> List = script.resolveSession.storageManager.createLazyValue { - script.scriptDefinition().legacyDefinition.providedProperties.mapNotNull { (name, type) -> - script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS)?.let { - name to it - } + 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), diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt index 5d8475458ed..9e128cd68c3 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt @@ -28,14 +28,11 @@ import kotlin.script.experimental.dependencies.AsyncDependenciesResolver import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.host.* -import kotlin.script.experimental.jvm.JvmGetScriptingClass +import kotlin.script.experimental.jvm.* import kotlin.script.experimental.jvm.compat.mapToDiagnostics -import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.impl.refineWith import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty import kotlin.script.experimental.jvm.impl.toDependencies -import kotlin.script.experimental.jvm.jdkHome -import kotlin.script.experimental.jvm.jvm internal fun VirtualFile.loadAnnotations( acceptedAnnotations: List>, @@ -147,6 +144,7 @@ abstract class ScriptCompilationConfigurationWrapper(val script: SourceCode) { get() = configuration?.get(ScriptCompilationConfiguration.importScripts) ?.mapNotNull { (it as? FileBasedScriptSource)?.file }.orEmpty() + @Suppress("OverridingDeprecatedMember") override val legacyDependencies: ScriptDependencies? get() = configuration?.toDependencies(dependenciesClassPath) @@ -156,9 +154,11 @@ abstract class ScriptCompilationConfigurationWrapper(val script: SourceCode) { override fun hashCode(): Int = super.hashCode() + 23 * (configuration?.hashCode() ?: 1) } + @Suppress("OverridingDeprecatedMember", "DEPRECATION") class FromLegacy( script: SourceCode, - override val legacyDependencies: ScriptDependencies? + override val legacyDependencies: ScriptDependencies?, + val definition: ScriptDefinition? ) : ScriptCompilationConfigurationWrapper(script) { override val dependenciesClassPath: List @@ -177,8 +177,23 @@ abstract class ScriptCompilationConfigurationWrapper(val script: SourceCode) { get() = legacyDependencies?.scripts.orEmpty() override val configuration: ScriptCompilationConfiguration? - get() = legacyDependencies?.let { - TODO("drop or implement") + get() { + val legacy = legacyDependencies ?: return null + return definition?.compilationConfiguration?.let { + ScriptCompilationConfiguration(it) { + updateClasspath(legacy.classpath) + defaultImports.append(legacy.imports) + importScripts.append(legacy.scripts.map { FileScriptSource(it) }) + jvm { + jdkHome.putIfNotNull(legacy.javaHome) // TODO: check if it is correct to supply javaHome as jdkHome + } + if (legacy.sources.isNotEmpty()) { + ide { + dependenciesSources.append(JvmDependency(legacy.sources)) + } + } + } + } } override fun equals(other: Any?): Boolean = @@ -190,6 +205,7 @@ abstract class ScriptCompilationConfigurationWrapper(val script: SourceCode) { typealias ScriptCompilationConfigurationResult = ResultWithDiagnostics +@Suppress("DEPRECATION") fun refineScriptCompilationConfiguration( script: SourceCode, definition: ScriptDefinition, @@ -240,7 +256,8 @@ fun refineScriptCompilationConfiguration( else ScriptCompilationConfigurationWrapper.FromLegacy( ktFileSource, - result.dependencies?.adjustByDefinition(definition.legacyDefinition) + result.dependencies?.adjustByDefinition(definition.legacyDefinition), + definition ).asSuccess(result.reports.mapToDiagnostics()) } }