Implement support for additional receivers in the backend
This commit is contained in:
@@ -2749,7 +2749,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cur = getNotNullParentContextForMethod(cur);
|
cur = getNotNullParentContextForMethod(cur);
|
||||||
result = cur.getOuterExpression(result, false);
|
// for now the script codegen only passes this branch, since the method context for script constructor is defined using function context
|
||||||
|
if (cur instanceof ScriptContext && !(thisOrOuterClass instanceof ScriptDescriptor)) {
|
||||||
|
return ((ScriptContext) cur).getOuterReceiverExpression(result, thisOrOuterClass);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = cur.getOuterExpression(result, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = cur.getEnclosingClassContext();
|
cur = cur.getEnclosingClassContext();
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import org.jetbrains.kotlin.codegen.context.CodegenContext
|
|||||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||||
import org.jetbrains.kotlin.codegen.context.ScriptContext
|
import org.jetbrains.kotlin.codegen.context.ScriptContext
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||||
@@ -66,7 +66,9 @@ class ScriptCodegen private constructor(
|
|||||||
classBuilder: ClassBuilder,
|
classBuilder: ClassBuilder,
|
||||||
methodContext: MethodContext
|
methodContext: MethodContext
|
||||||
) {
|
) {
|
||||||
val jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, scriptContext.earlierScripts)
|
val scriptDefinition = scriptContext.script.kotlinScriptDefinition.value
|
||||||
|
|
||||||
|
val jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, scriptContext.earlierScripts, scriptDefinition.implicitReceivers)
|
||||||
|
|
||||||
if (state.replSpecific.shouldGenerateScriptResultValue) {
|
if (state.replSpecific.shouldGenerateScriptResultValue) {
|
||||||
val resultFieldInfo = scriptContext.resultFieldInfo
|
val resultFieldInfo = scriptContext.resultFieldInfo
|
||||||
@@ -102,7 +104,10 @@ class ScriptCodegen private constructor(
|
|||||||
|
|
||||||
iv.load(0, classType)
|
iv.load(0, classType)
|
||||||
|
|
||||||
val valueParamStart = if (scriptContext.earlierScripts.isEmpty()) 1 else 2 // this + array of earlier scripts if not empty
|
fun Int.incrementIf(cond: Boolean): Int = if (cond) plus(1) else this
|
||||||
|
val valueParamStart = 1
|
||||||
|
.incrementIf(scriptContext.earlierScripts.isNotEmpty())
|
||||||
|
.incrementIf(scriptDefinition.implicitReceivers.isNotEmpty())
|
||||||
|
|
||||||
val valueParameters = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters
|
val valueParameters = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters
|
||||||
for (superclassParam in ctorDesc.valueParameters) {
|
for (superclassParam in ctorDesc.valueParameters) {
|
||||||
@@ -122,19 +127,31 @@ class ScriptCodegen private constructor(
|
|||||||
val frameMap = FrameMap()
|
val frameMap = FrameMap()
|
||||||
frameMap.enterTemp(OBJECT_TYPE)
|
frameMap.enterTemp(OBJECT_TYPE)
|
||||||
|
|
||||||
|
fun genFieldFromArrayElement(descriptor: ClassDescriptor, paramIndex: Int, elementIndex: Int, name: String) {
|
||||||
|
val elementClassType = typeMapper.mapClass(descriptor)
|
||||||
|
iv.load(0, classType)
|
||||||
|
iv.load(paramIndex, elementClassType)
|
||||||
|
iv.aconst(elementIndex)
|
||||||
|
iv.aload(OBJECT_TYPE)
|
||||||
|
iv.checkcast(elementClassType)
|
||||||
|
iv.putfield(classType.internalName, name, elementClassType.descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
if (!scriptContext.earlierScripts.isEmpty()) {
|
if (!scriptContext.earlierScripts.isEmpty()) {
|
||||||
val scriptsParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE))
|
val scriptsParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE))
|
||||||
|
|
||||||
var earlierScriptIndex = 0
|
scriptContext.earlierScripts.forEachIndexed { earlierScriptIndex, earlierScript ->
|
||||||
for (earlierScript in scriptContext.earlierScripts) {
|
val name = scriptContext.getScriptFieldName(earlierScript)
|
||||||
val earlierClassType = typeMapper.mapClass(earlierScript)
|
genFieldFromArrayElement(earlierScript, scriptsParamIndex, earlierScriptIndex, name)
|
||||||
iv.load(0, classType)
|
}
|
||||||
iv.load(scriptsParamIndex, earlierClassType)
|
}
|
||||||
iv.aconst(earlierScriptIndex++)
|
|
||||||
iv.aload(OBJECT_TYPE)
|
if (scriptDefinition.implicitReceivers.isNotEmpty()) {
|
||||||
iv.checkcast(earlierClassType)
|
val receiversParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE))
|
||||||
iv.putfield(classType.internalName, scriptContext.getScriptFieldName(earlierScript), earlierClassType.descriptor)
|
|
||||||
|
scriptContext.receiverDescriptors.forEachIndexed { receiverIndex, receiver ->
|
||||||
|
val name = scriptContext.getImplicitReceiverName(receiverIndex)
|
||||||
|
genFieldFromArrayElement(receiver, receiversParamIndex, receiverIndex, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,9 +168,24 @@ class ScriptCodegen private constructor(
|
|||||||
|
|
||||||
private fun genFieldsForParameters(classBuilder: ClassBuilder) {
|
private fun genFieldsForParameters(classBuilder: ClassBuilder) {
|
||||||
for (earlierScript in scriptContext.earlierScripts) {
|
for (earlierScript in scriptContext.earlierScripts) {
|
||||||
val earlierClassName = typeMapper.mapType(earlierScript)
|
classBuilder.newField(
|
||||||
val access = ACC_PUBLIC or ACC_FINAL
|
NO_ORIGIN,
|
||||||
classBuilder.newField(NO_ORIGIN, access, scriptContext.getScriptFieldName(earlierScript), earlierClassName.descriptor, null, null)
|
ACC_PUBLIC or ACC_FINAL,
|
||||||
|
scriptContext.getScriptFieldName(earlierScript),
|
||||||
|
typeMapper.mapType(earlierScript).descriptor,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (receiverIndex in scriptContext.receiverDescriptors.indices) {
|
||||||
|
classBuilder.newField(
|
||||||
|
NO_ORIGIN,
|
||||||
|
ACC_PUBLIC or ACC_FINAL,
|
||||||
|
scriptContext.getImplicitReceiverName(receiverIndex),
|
||||||
|
scriptContext.getImplicitReceiverType(receiverIndex)!!.descriptor,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,21 +16,30 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.context
|
package org.jetbrains.kotlin.codegen.context
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.FieldInfo
|
import org.jetbrains.kotlin.codegen.FieldInfo
|
||||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
|
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.KtScript
|
import org.jetbrains.kotlin.psi.KtScript
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class ScriptContext(
|
class ScriptContext(
|
||||||
typeMapper: KotlinTypeMapper,
|
val typeMapper: KotlinTypeMapper,
|
||||||
val scriptDescriptor: ScriptDescriptor,
|
val scriptDescriptor: ScriptDescriptor,
|
||||||
val earlierScripts: List<ScriptDescriptor>,
|
val earlierScripts: List<ScriptDescriptor>,
|
||||||
contextDescriptor: ClassDescriptor,
|
contextDescriptor: ClassDescriptor,
|
||||||
@@ -41,14 +50,14 @@ class ScriptContext(
|
|||||||
val resultFieldInfo: FieldInfo
|
val resultFieldInfo: FieldInfo
|
||||||
get() {
|
get() {
|
||||||
assert(state.replSpecific.shouldGenerateScriptResultValue) { "Should not be called unless 'scriptResultFieldName' is set" }
|
assert(state.replSpecific.shouldGenerateScriptResultValue) { "Should not be called unless 'scriptResultFieldName' is set" }
|
||||||
val state = state
|
|
||||||
val scriptResultFieldName = state.replSpecific.scriptResultFieldName!!
|
val scriptResultFieldName = state.replSpecific.scriptResultFieldName!!
|
||||||
return FieldInfo.createForHiddenField(state.typeMapper.mapClass(scriptDescriptor), AsmTypes.OBJECT_TYPE, scriptResultFieldName)
|
return FieldInfo.createForHiddenField(state.typeMapper.mapClass(scriptDescriptor), AsmTypes.OBJECT_TYPE, scriptResultFieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val script = DescriptorToSourceUtils.getSourceFromDescriptor(scriptDescriptor) as KtScript?
|
||||||
|
?: error("Declaration should be present for script: $scriptDescriptor")
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val script = DescriptorToSourceUtils.getSourceFromDescriptor(scriptDescriptor) as KtScript?
|
|
||||||
?: error("Declaration should be present for script: $scriptDescriptor")
|
|
||||||
val lastDeclaration = script.declarations.lastOrNull()
|
val lastDeclaration = script.declarations.lastOrNull()
|
||||||
if (lastDeclaration is KtAnonymousInitializer) {
|
if (lastDeclaration is KtAnonymousInitializer) {
|
||||||
this.lastStatement = lastDeclaration.body
|
this.lastStatement = lastDeclaration.body
|
||||||
@@ -57,6 +66,29 @@ class ScriptContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getImplicitReceiverName(index: Int): String = "\$\$implicitReceiver$index"
|
||||||
|
|
||||||
|
fun getImplicitReceiverType(index: Int): Type? {
|
||||||
|
val receivers = script.kotlinScriptDefinition.value.implicitReceivers
|
||||||
|
val kClass = receivers.getOrNull(index)?.classifier as? KClass<*>
|
||||||
|
return kClass?.java?.classId?.let(AsmUtil::asmTypeByClassId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue {
|
||||||
|
receiverDescriptors.forEachIndexed { index, outerReceiver ->
|
||||||
|
if (outerReceiver == thisOrOuterClass) {
|
||||||
|
return getImplicitReceiverType(index)?.let { type ->
|
||||||
|
val owner = typeMapper.mapType(scriptDescriptor)
|
||||||
|
StackValue.field(type, owner, getImplicitReceiverName(index), false, prefix ?: StackValue.LOCAL_0)
|
||||||
|
} ?: error("Invalid script receiver: ${thisOrOuterClass.fqNameSafe}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Script receiver not found: ${thisOrOuterClass.fqNameSafe}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverDescriptors: List<ClassDescriptor>
|
||||||
|
get() = scriptDescriptor.implicitReceivers
|
||||||
|
|
||||||
fun getScriptFieldName(scriptDescriptor: ScriptDescriptor): String {
|
fun getScriptFieldName(scriptDescriptor: ScriptDescriptor): String {
|
||||||
val index = earlierScripts.indexOf(scriptDescriptor)
|
val index = earlierScripts.indexOf(scriptDescriptor)
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
@@ -69,3 +101,6 @@ class ScriptContext(
|
|||||||
return "Script: " + contextDescriptor.name.asString()
|
return "Script: " + contextDescriptor.name.asString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val Class<*>.classId: ClassId
|
||||||
|
get() = enclosingClass?.classId?.createNestedClassId(Name.identifier(simpleName)) ?: ClassId.topLevel(FqName(name))
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement;
|
|||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
|
import kotlin.reflect.KType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
||||||
@@ -1563,7 +1564,11 @@ public class KotlinTypeMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List<ScriptDescriptor> importedScripts) {
|
public JvmMethodSignature mapScriptSignature(
|
||||||
|
@NotNull ScriptDescriptor script,
|
||||||
|
@NotNull List<ScriptDescriptor> importedScripts,
|
||||||
|
List<? extends KType> implicitReceivers
|
||||||
|
) {
|
||||||
JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
|
JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
|
||||||
|
|
||||||
sw.writeParametersStart();
|
sw.writeParametersStart();
|
||||||
@@ -1572,6 +1577,10 @@ public class KotlinTypeMapper {
|
|||||||
writeParameter(sw, DescriptorUtilsKt.getModule(script).getBuiltIns().getArray().getDefaultType(), null);
|
writeParameter(sw, DescriptorUtilsKt.getModule(script).getBuiltIns().getArray().getDefaultType(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (implicitReceivers.size() > 0) {
|
||||||
|
writeParameter(sw, DescriptorUtilsKt.getModule(script).getBuiltIns().getArray().getDefaultType(), null);
|
||||||
|
}
|
||||||
|
|
||||||
for (ValueParameterDescriptor valueParameter : script.getUnsubstitutedPrimaryConstructor().getValueParameters()) {
|
for (ValueParameterDescriptor valueParameter : script.getUnsubstitutedPrimaryConstructor().getValueParameters()) {
|
||||||
writeParameter(sw, valueParameter.getType(), /* callableDescriptor = */ null);
|
writeParameter(sw, valueParameter.getType(), /* callableDescriptor = */ null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory2<PsiElement, String, String> API_NOT_AVAILABLE = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<PsiElement, String, String> API_NOT_AVAILABLE = DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
DiagnosticFactory1<PsiElement, FqName> MISSING_DEPENDENCY_CLASS = DiagnosticFactory1.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);
|
DiagnosticFactory1<PsiElement, String> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
|
||||||
|
|
||||||
|
|||||||
+1
@@ -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(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_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(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,
|
MAP.put(INCOMPATIBLE_CLASS,
|
||||||
"{0} was compiled with an incompatible version of Kotlin. {1}",
|
"{0} was compiled with an incompatible version of Kotlin. {1}",
|
||||||
|
|||||||
+19
-12
@@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.lazy.descriptors
|
package org.jetbrains.kotlin.resolve.lazy.descriptors
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorVisitor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -92,16 +89,26 @@ class LazyScriptDescriptor(
|
|||||||
override fun computeSupertypes() =
|
override fun computeSupertypes() =
|
||||||
listOf(ScriptHelper.getInstance().getKotlinType(this, scriptDefinition.template)).ifEmpty { listOf(builtIns.anyType) }
|
listOf(ScriptHelper.getInstance().getKotlinType(this, scriptDefinition.template)).ifEmpty { listOf(builtIns.anyType) }
|
||||||
|
|
||||||
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
|
private val scriptImplicitReceivers: () -> List<ClassDescriptor> = resolveSession.storageManager.createLazyValue {
|
||||||
val receivers = scriptDefinition.implicitReceivers
|
scriptDefinition.implicitReceivers.mapNotNull { receiver ->
|
||||||
var outerScope = super.getOuterScope()
|
|
||||||
for (receiver in receivers.asReversed()) {
|
|
||||||
val receiverClassId = receiver.classifier?.let { it as? KClass<*> }?.java?.classId
|
val receiverClassId = receiver.classifier?.let { it as? KClass<*> }?.java?.classId
|
||||||
val receiverClassDescriptor = receiverClassId?.let { module.findClassAcrossModuleDependencies(it) }
|
receiverClassId?.let {
|
||||||
if (receiverClassDescriptor == null) {
|
module.findClassAcrossModuleDependencies(it)
|
||||||
resolveSession.trace.report(Errors.MISSING_DEPENDENCY_CLASS.on(scriptInfo.script, receiverClassId?.asSingleFqName() ?: FqName(receiver.toString())))
|
?: also {
|
||||||
break
|
// 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 = LexicalScopeImpl(
|
||||||
outerScope,
|
outerScope,
|
||||||
receiverClassDescriptor,
|
receiverClassDescriptor,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import java.util.Objects;
|
|||||||
import static kotlin.LazyThreadSafetyMode.PUBLICATION;
|
import static kotlin.LazyThreadSafetyMode.PUBLICATION;
|
||||||
|
|
||||||
public class KtScript extends KtNamedDeclarationStub<KotlinScriptStub> implements KtDeclarationContainer {
|
public class KtScript extends KtNamedDeclarationStub<KotlinScriptStub> implements KtDeclarationContainer {
|
||||||
private final Lazy<KotlinScriptDefinition> kotlinScriptDefinition = LazyKt.lazy(PUBLICATION, () -> Objects.requireNonNull(
|
public final Lazy<KotlinScriptDefinition> kotlinScriptDefinition = LazyKt.lazy(PUBLICATION, () -> Objects.requireNonNull(
|
||||||
KotlinScriptDefinitionProviderKt.getScriptDefinition(getContainingKtFile()),
|
KotlinScriptDefinitionProviderKt.getScriptDefinition(getContainingKtFile()),
|
||||||
() -> "Should not parse a script without definition: " + getContainingKtFile().getVirtualFile().getPath()
|
() -> "Should not parse a script without definition: " + getContainingKtFile().getVirtualFile().getPath()
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -18,10 +18,15 @@ package org.jetbrains.kotlin.descriptors;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface ScriptDescriptor extends ClassDescriptor {
|
public interface ScriptDescriptor extends ClassDescriptor {
|
||||||
int getPriority();
|
int getPriority();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
ClassConstructorDescriptor getUnsubstitutedPrimaryConstructor();
|
ClassConstructorDescriptor getUnsubstitutedPrimaryConstructor();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
List<ClassDescriptor> getImplicitReceivers();
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -26,7 +26,12 @@ open class BasicJvmScriptRunner<ScriptBase : Any>(val baseClass: KClass<ScriptBa
|
|||||||
if (scriptObject !is Class<*>)
|
if (scriptObject !is Class<*>)
|
||||||
ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}"))
|
ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}"))
|
||||||
else {
|
else {
|
||||||
scriptObject.getConstructor().newInstance()
|
val receivers = scriptEvaluationEnvironment.getOrNull(ScriptEvaluationEnvironmentParams.implicitReceivers)
|
||||||
|
if (receivers == null) {
|
||||||
|
scriptObject.getConstructor().newInstance()
|
||||||
|
} else {
|
||||||
|
scriptObject.getConstructor(Array<Any>::class.java).newInstance(receivers.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
ResultWithDiagnostics.Success(EvaluationResult(null, scriptEvaluationEnvironment))
|
ResultWithDiagnostics.Success(EvaluationResult(null, scriptEvaluationEnvironment))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user