Fix propagation of dependency resolution failure reports during script compilation

This commit is contained in:
Anatoly Nikitin
2019-10-17 19:54:36 +03:00
committed by Ilya Chernikov
parent 744dfc6bf9
commit 81e2e119e2
4 changed files with 51 additions and 36 deletions
@@ -274,13 +274,15 @@ fun ScriptCompilationConfiguration.refineOnAnnotations(
val foundAnnotationNames = collectedData[ScriptCollectedData.foundAnnotations]?.mapTo(HashSet()) { it.annotationClass.java.name } val foundAnnotationNames = collectedData[ScriptCollectedData.foundAnnotations]?.mapTo(HashSet()) { it.annotationClass.java.name }
if (foundAnnotationNames.isNullOrEmpty()) return this.asSuccess() if (foundAnnotationNames.isNullOrEmpty()) return this.asSuccess()
val refinedConfig = this[ScriptCompilationConfiguration.refineConfigurationOnAnnotations] val thisResult: ResultWithDiagnostics<ScriptCompilationConfiguration> = this.asSuccess()
?.fold(this) { config, (annotations, handler) -> return this[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]
// checking that the collected data contains expected annotations ?.fold(thisResult) { config, (annotations, handler) ->
if (annotations.none { foundAnnotationNames.contains(it.typeName) }) config config.onSuccess {
else handler.invoke(ScriptConfigurationRefinementContext(script, config, collectedData)).valueOr { return it } // checking that the collected data contains expected annotations
} if (annotations.none { foundAnnotationNames.contains(it.typeName) }) it.asSuccess()
return (refinedConfig ?: this).asSuccess() else handler.invoke(ScriptConfigurationRefinementContext(script, it, collectedData))
}
} ?: thisResult
} }
fun ScriptCompilationConfiguration.refineBeforeCompiling( fun ScriptCompilationConfiguration.refineBeforeCompiling(
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
import java.io.File import java.io.File
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.asSuccess
import kotlin.script.experimental.host.FileBasedScriptSource import kotlin.script.experimental.host.FileBasedScriptSource
data class ScriptsCompilationDependencies( data class ScriptsCompilationDependencies(
@@ -22,7 +24,7 @@ data class ScriptsCompilationDependencies(
) { ) {
data class SourceDependencies( data class SourceDependencies(
val scriptFile: KtFile, val scriptFile: KtFile,
val sourceDependencies: List<KtFile> val sourceDependencies: ResultWithDiagnostics<List<KtFile>>
) )
} }
@@ -42,34 +44,39 @@ fun collectScriptsCompilationDependencies(
while (true) { while (true) {
val newRemainingSources = ArrayList<KtFile>() val newRemainingSources = ArrayList<KtFile>()
for (source in remainingSources) { for (source in remainingSources) {
val refinedConfiguration = importsProvider.getScriptConfiguration(source) when (val refinedConfiguration = importsProvider.getScriptConfigurationResult(source)) {
if (refinedConfiguration != null) { null -> {}
collectedClassPath.addAll(refinedConfiguration.dependenciesClassPath) is ResultWithDiagnostics.Failure -> {
collectedSourceDependencies.add(ScriptsCompilationDependencies.SourceDependencies(source, refinedConfiguration))
val sourceDependenciesRoots = refinedConfiguration.importedScripts.mapNotNull {
// TODO: support any kind of ScriptSource.
val path = (it as? FileBasedScriptSource)?.file?.path ?: return@mapNotNull null
KotlinSourceRoot(path, false)
} }
val sourceDependencies = is ResultWithDiagnostics.Success -> {
createSourceFilesFromSourceRoots( collectedClassPath.addAll(refinedConfiguration.value.dependenciesClassPath)
configuration, project, sourceDependenciesRoots,
// TODO: consider receiving and using precise location from the resolver in the future
source.virtualFile?.path?.let { CompilerMessageLocation.create(it) }
)
if (sourceDependencies.isNotEmpty()) {
collectedSourceDependencies.add(
ScriptsCompilationDependencies.SourceDependencies(
source,
sourceDependencies
)
)
val newSources = sourceDependencies.filterNot { knownSourcePaths.contains(it.virtualFile.path) } val sourceDependenciesRoots = refinedConfiguration.value.importedScripts.mapNotNull {
for (newSource in newSources) { // TODO: support any kind of ScriptSource.
collectedSources.add(newSource) val path = (it as? FileBasedScriptSource)?.file?.path ?: return@mapNotNull null
newRemainingSources.add(newSource) KotlinSourceRoot(path, false)
knownSourcePaths.add(newSource.virtualFile.path) }
val sourceDependencies =
createSourceFilesFromSourceRoots(
configuration, project, sourceDependenciesRoots,
// TODO: consider receiving and using precise location from the resolver in the future
source.virtualFile?.path?.let { CompilerMessageLocation.create(it) }
)
if (sourceDependencies.isNotEmpty()) {
collectedSourceDependencies.add(
ScriptsCompilationDependencies.SourceDependencies(
source,
sourceDependencies.asSuccess(refinedConfiguration.reports)
)
)
val newSources = sourceDependencies.filterNot { knownSourcePaths.contains(it.virtualFile.path) }
for (newSource in newSources) {
collectedSources.add(newSource)
newRemainingSources.add(newSource)
knownSourcePaths.add(newSource.virtualFile.path)
}
} }
} }
} }
@@ -103,6 +103,12 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
messageCollector messageCollector
) )
val firstFailure = sourceDependencies.firstOrNull { it.sourceDependencies is ResultWithDiagnostics.Failure }
?.let { it.sourceDependencies as ResultWithDiagnostics.Failure }
if (firstFailure != null)
return firstFailure
if (history.isEmpty()) { if (history.isEmpty()) {
val updatedConfiguration = ScriptDependenciesProvider.getInstance(context.environment.project) val updatedConfiguration = ScriptDependenciesProvider.getInstance(context.environment.project)
?.getScriptConfiguration(snippetKtFile)?.configuration ?.getScriptConfiguration(snippetKtFile)?.configuration
@@ -165,7 +171,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
?: context.baseScriptCompilationConfiguration ?: context.baseScriptCompilationConfiguration
} }
ResultWithDiagnostics.Success(compiledScript, messageCollector.diagnostics) compiledScript.asSuccess(messageCollector.diagnostics)
} }
} }
@@ -119,7 +119,7 @@ internal fun makeCompiledScript(
val containingKtFile = script.containingKtFile val containingKtFile = script.containingKtFile
val otherScripts: List<KJvmCompiledScript<*>> = val otherScripts: List<KJvmCompiledScript<*>> =
sourceDependencies.find { it.scriptFile == containingKtFile }?.sourceDependencies?.mapNotNull { sourceFile -> sourceDependencies.find { it.scriptFile == containingKtFile }?.sourceDependencies?.valueOrThrow()?.mapNotNull { sourceFile ->
sourceFile.declarations.firstIsInstanceOrNull<KtScript>()?.let { sourceFile.declarations.firstIsInstanceOrNull<KtScript>()?.let {
KJvmCompiledScript<Any>( KJvmCompiledScript<Any>(
containingKtFile.virtualFile?.path, containingKtFile.virtualFile?.path,