Implement support for additional receivers in the backend

This commit is contained in:
Ilya Chernikov
2018-03-13 11:07:16 +01:00
parent 611aff6b61
commit 00320bad8d
10 changed files with 138 additions and 37 deletions
@@ -98,6 +98,7 @@ 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, String> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
@@ -363,6 +363,7 @@ public class DefaultErrorMessages {
MAP.put(API_NOT_AVAILABLE, "This declaration is only available since Kotlin {0} and cannot be used with the specified API version {1}", STRING, STRING);
MAP.put(MISSING_DEPENDENCY_CLASS, "Cannot access class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
MAP.put(MISSING_SCRIPT_RECEIVER_CLASS, "Cannot access implicit script receiver class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
MAP.put(PRE_RELEASE_CLASS, "{0} is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler", TO_STRING);
MAP.put(INCOMPATIBLE_CLASS,
"{0} was compiled with an incompatible version of Kotlin. {1}",
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.resolve.lazy.descriptors
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorVisitor
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -92,16 +89,26 @@ class LazyScriptDescriptor(
override fun computeSupertypes() =
listOf(ScriptHelper.getInstance().getKotlinType(this, scriptDefinition.template)).ifEmpty { listOf(builtIns.anyType) }
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
val receivers = scriptDefinition.implicitReceivers
var outerScope = super.getOuterScope()
for (receiver in receivers.asReversed()) {
private val scriptImplicitReceivers: () -> List<ClassDescriptor> = resolveSession.storageManager.createLazyValue {
scriptDefinition.implicitReceivers.mapNotNull { receiver ->
val receiverClassId = receiver.classifier?.let { it as? KClass<*> }?.java?.classId
val receiverClassDescriptor = receiverClassId?.let { module.findClassAcrossModuleDependencies(it) }
if (receiverClassDescriptor == null) {
resolveSession.trace.report(Errors.MISSING_DEPENDENCY_CLASS.on(scriptInfo.script, receiverClassId?.asSingleFqName() ?: FqName(receiver.toString())))
break
receiverClassId?.let {
module.findClassAcrossModuleDependencies(it)
?: also {
// TODO: use PositioningStrategies to highlight some specific place in case of error, instead of treating the whole file as invalid
resolveSession.trace.report(
Errors.MISSING_SCRIPT_RECEIVER_CLASS.on(scriptInfo.script, receiverClassId.asSingleFqName())
)
}
}
}
}
override fun getImplicitReceivers(): List<ClassDescriptor> = scriptImplicitReceivers()
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
var outerScope = super.getOuterScope()
for (receiverClassDescriptor in implicitReceivers.asReversed()) {
outerScope = LexicalScopeImpl(
outerScope,
receiverClassDescriptor,