Implement script environment variables in backend, add simple test

This commit is contained in:
Ilya Chernikov
2018-04-25 13:06:58 +02:00
parent a9600e34bf
commit dff4be9e04
9 changed files with 158 additions and 43 deletions
@@ -32,9 +32,11 @@ import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt; import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.lazy.descriptors.ScriptEnvironmentPropertyDescriptor;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.ErrorUtils;
@@ -486,13 +488,13 @@ public class PropertyCodegen {
return false; return false;
} }
private void generateGetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) { public void generateGetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) {
generateAccessor(p, getter, descriptor.getGetter() != null generateAccessor(p, getter, descriptor.getGetter() != null
? descriptor.getGetter() ? descriptor.getGetter()
: DescriptorFactory.createDefaultGetter(descriptor, Annotations.Companion.getEMPTY())); : DescriptorFactory.createDefaultGetter(descriptor, Annotations.Companion.getEMPTY()));
} }
private void generateSetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) { public void generateSetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) {
if (!descriptor.isVar()) return; if (!descriptor.isVar()) return;
generateAccessor(p, setter, descriptor.getSetter() != null generateAccessor(p, setter, descriptor.getSetter() != null
@@ -513,7 +515,10 @@ public class PropertyCodegen {
FunctionGenerationStrategy strategy; FunctionGenerationStrategy strategy;
if (accessor == null || !accessor.hasBody()) { if (accessor == null || !accessor.hasBody()) {
if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) { if (accessorDescriptor.getCorrespondingProperty() instanceof ScriptEnvironmentPropertyDescriptor) {
strategy = new ScriptEnvPropertyAccessorStrategy(state, accessorDescriptor);
}
else if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor); strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor);
} }
else { else {
@@ -626,6 +631,42 @@ public class PropertyCodegen {
} }
} }
private static class ScriptEnvPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
public static final String MAP_IFACE_NAME = "java/util/Map";
public static final String MAP_FIELD_NAME = "environment";
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
public ScriptEnvPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
super(state);
this.propertyAccessorDescriptor = descriptor;
}
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
InstructionAdapter v = codegen.v;
String intScriptName =
state.getTypeMapper().mapClass((ClassifierDescriptor)(propertyAccessorDescriptor.getCorrespondingProperty().getContainingDeclaration())).getClassName();
v.visitVarInsn(Opcodes.ALOAD, 0);
v.visitFieldInsn(Opcodes.GETFIELD, intScriptName, MAP_FIELD_NAME, Type.getObjectType(MAP_IFACE_NAME).getDescriptor());
v.visitLdcInsn(propertyAccessorDescriptor.getCorrespondingProperty().getName().asString());
if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) {
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_NAME, "get",
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true);
}
else {
Type valueType = state.getTypeMapper().mapType(propertyAccessorDescriptor.getCorrespondingProperty());
v.load(1, valueType);
StackValue.coerce(valueType, AsmTypes.OBJECT_TYPE, v);
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_NAME, "set",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true);
}
Type returnType = state.getTypeMapper().mapReturnType(propertyAccessorDescriptor);
StackValue.coerce(AsmTypes.OBJECT_TYPE, returnType, v);
v.areturn(returnType);
}
}
public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) { public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration(); ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.ScriptDescriptor
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.*
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -53,6 +54,10 @@ class ScriptCodegen private constructor(
override fun generateSyntheticPartsBeforeBody() { override fun generateSyntheticPartsBeforeBody() {
generatePropertyMetadataArrayFieldIfNeeded(classAsmType) generatePropertyMetadataArrayFieldIfNeeded(classAsmType)
scriptContext.scriptDescriptor.scriptEnvironmentProperties.forEach {
propertyCodegen.generateGetter(null, it, null)
propertyCodegen.generateSetter(null, it, null)
}
} }
override fun generateSyntheticPartsAfterBody() {} override fun generateSyntheticPartsAfterBody() {}
@@ -68,7 +73,12 @@ class ScriptCodegen private constructor(
) { ) {
val scriptDefinition = scriptContext.script.kotlinScriptDefinition.value val scriptDefinition = scriptContext.script.kotlinScriptDefinition.value
val jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, scriptContext.earlierScripts, scriptDefinition.implicitReceivers) val jvmSignature = typeMapper.mapScriptSignature(
scriptDescriptor,
scriptContext.earlierScripts,
scriptDefinition.implicitReceivers,
scriptDefinition.environmentVariables
)
if (state.replSpecific.shouldGenerateScriptResultValue) { if (state.replSpecific.shouldGenerateScriptResultValue) {
val resultFieldInfo = scriptContext.resultFieldInfo val resultFieldInfo = scriptContext.resultFieldInfo
@@ -108,6 +118,7 @@ class ScriptCodegen private constructor(
val valueParamStart = 1 val valueParamStart = 1
.incrementIf(scriptContext.earlierScripts.isNotEmpty()) .incrementIf(scriptContext.earlierScripts.isNotEmpty())
.incrementIf(scriptDefinition.implicitReceivers.isNotEmpty()) .incrementIf(scriptDefinition.implicitReceivers.isNotEmpty())
.incrementIf(scriptDefinition.environmentVariables.isNotEmpty())
val valueParameters = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters val valueParameters = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters
for (superclassParam in ctorDesc.valueParameters) { for (superclassParam in ctorDesc.valueParameters) {
@@ -155,6 +166,14 @@ class ScriptCodegen private constructor(
} }
} }
if (scriptDefinition.environmentVariables.isNotEmpty()) {
val envParamIndex = frameMap.enterTemp(AsmTypes.OBJECT_TYPE)
val mapType = Type.getObjectType("java/util/Map")
iv.load(0, classType)
iv.load(envParamIndex, mapType)
iv.putfield(classType.internalName, "environment", mapType.descriptor)
}
val codegen = ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this) val codegen = ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this)
generateInitializers { codegen } generateInitializers { codegen }
@@ -187,6 +206,16 @@ class ScriptCodegen private constructor(
null null
) )
} }
if (scriptContext.scriptDescriptor.scriptEnvironmentProperties.isNotEmpty()) {
classBuilder.newField(
NO_ORIGIN,
ACC_PUBLIC or ACC_FINAL,
"environment",
Type.getObjectType("java/util/Map").descriptor,
null,
null
)
}
} }
private fun genMembers() { private fun genMembers() {
@@ -23,7 +23,6 @@ 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.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -32,9 +31,8 @@ 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.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.kotlin.resolve.lazy.descriptors.ScriptEnvironmentDescriptor
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import kotlin.reflect.KClass import kotlin.reflect.KClass
@@ -75,6 +73,9 @@ class ScriptContext(
} }
fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue { fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue {
if (thisOrOuterClass is ScriptEnvironmentDescriptor) {
return prefix ?: StackValue.LOCAL_0
}
receiverDescriptors.forEachIndexed { index, outerReceiver -> receiverDescriptors.forEachIndexed { index, outerReceiver ->
if (outerReceiver == thisOrOuterClass) { if (outerReceiver == thisOrOuterClass) {
return getImplicitReceiverType(index)?.let { type -> return getImplicitReceiverType(index)?.let { type ->
@@ -1586,7 +1586,8 @@ public class KotlinTypeMapper {
public JvmMethodSignature mapScriptSignature( public JvmMethodSignature mapScriptSignature(
@NotNull ScriptDescriptor script, @NotNull ScriptDescriptor script,
@NotNull List<ScriptDescriptor> importedScripts, @NotNull List<ScriptDescriptor> importedScripts,
List<? extends KType> implicitReceivers List<? extends KType> implicitReceivers,
List<? extends Pair<String, ? extends KType>> environmentVariables
) { ) {
JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD); JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
@@ -1600,6 +1601,10 @@ public class KotlinTypeMapper {
writeParameter(sw, DescriptorUtilsKt.getModule(script).getBuiltIns().getArray().getDefaultType(), null); writeParameter(sw, DescriptorUtilsKt.getModule(script).getBuiltIns().getArray().getDefaultType(), null);
} }
if (environmentVariables.size() > 0) {
writeParameter(sw, DescriptorUtilsKt.getModule(script).getBuiltIns().getMap().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);
} }
@@ -102,7 +102,7 @@ class LazyScriptDescriptor(
} }
} }
private fun findTypeDescriptor(type: KType, errorDiagnostic: DiagnosticFactory1<PsiElement, FqName>): ClassDescriptor? { internal fun findTypeDescriptor(type: KType, errorDiagnostic: DiagnosticFactory1<PsiElement, FqName>): ClassDescriptor? {
val receiverClassId = type.classifier?.let { it as? KClass<*> }?.classId val receiverClassId = type.classifier?.let { it as? KClass<*> }?.classId
return receiverClassId?.let { return receiverClassId?.let {
module.findClassAcrossModuleDependencies(it) module.findClassAcrossModuleDependencies(it)
@@ -119,15 +119,11 @@ class LazyScriptDescriptor(
override fun getImplicitReceivers(): List<ClassDescriptor> = scriptImplicitReceivers() override fun getImplicitReceivers(): List<ClassDescriptor> = scriptImplicitReceivers()
private val scriptEnvironmentProperties: () -> List<Pair<String, ClassDescriptor>> = resolveSession.storageManager.createLazyValue { private val scriptEnvironment: () -> ScriptEnvironmentDescriptor = resolveSession.storageManager.createLazyValue {
scriptDefinition.environmentVariables.mapNotNull { (name, type) -> ScriptEnvironmentDescriptor(this)
findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
name to it
}
}
} }
fun getScriptEnvironmentProperties(): List<Pair<String, ClassDescriptor>> = scriptEnvironmentProperties() override fun getScriptEnvironmentProperties(): List<PropertyDescriptor> = scriptEnvironment().properties
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue { private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
var outerScope = super.getOuterScope() var outerScope = super.getOuterScope()
@@ -160,7 +156,7 @@ private val KClass<*>.classId: ClassId
private val KType.classId: ClassId? private val KType.classId: ClassId?
get() = classifier?.let { it as? KClass<*> }?.classId get() = classifier?.let { it as? KClass<*> }?.classId
private class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) : class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
MutableClassDescriptor( MutableClassDescriptor(
script, ClassKind.CLASS, false, false, script, ClassKind.CLASS, false, false,
Name.special("<synthetic script environment for ${script.name}>"), SourceElement.NO_SOURCE, LockBasedStorageManager.NO_LOCKS Name.special("<synthetic script environment for ${script.name}>"), SourceElement.NO_SOURCE, LockBasedStorageManager.NO_LOCKS
@@ -176,23 +172,32 @@ private class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
private val memberScope by lazy { private val memberScope by lazy {
ScriptEnvironmentMemberScope( ScriptEnvironmentMemberScope(
script.name.identifier, script.name.identifier,
script.getScriptEnvironmentProperties().map { properties
makeEnvironmentPropertyDescriptor(
Name.identifier(it.first),
it.second,
true,
script
)
}
) )
} }
override fun getUnsubstitutedMemberScope(): MemberScope = memberScope override fun getUnsubstitutedMemberScope(): MemberScope = memberScope
val properties by lazy {
script.scriptDefinition.environmentVariables.mapNotNull { (name, type) ->
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
name to it
}
}.map { (key, value) ->
ScriptEnvironmentPropertyDescriptor(
Name.identifier(key),
value,
thisAsReceiverParameter,
true,
script
)
}
}
} }
private class ScriptEnvironmentMemberScope( private class ScriptEnvironmentMemberScope(
private val scriptId: String, private val scriptId: String,
private val environmentProperties: List<PropertyDescriptorImpl> private val environmentProperties: List<PropertyDescriptor>
) : MemberScopeImpl() { ) : MemberScopeImpl() {
override fun getContributedDescriptors( override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter, kindFilter: DescriptorKindFilter,
@@ -208,27 +213,35 @@ private class ScriptEnvironmentMemberScope(
} }
} }
private fun ScriptEnvironmentDescriptor.makeEnvironmentPropertyDescriptor(name: Name, typeDescriptor: ClassDescriptor, isVar: Boolean, script: LazyScriptDescriptor) = class ScriptEnvironmentPropertyDescriptor(
PropertyDescriptorImpl.create( name: Name,
script.containingDeclaration, typeDescriptor: ClassDescriptor,
Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, receiver: ReceiverParameterDescriptor?,
isVar, isVar: Boolean,
name, script: LazyScriptDescriptor
CallableMemberDescriptor.Kind.SYNTHESIZED, ) : PropertyDescriptorImpl(
SourceElement.NO_SOURCE, script,
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false, null,
/* isDelegated = */ true Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
).also { isVar,
it.setType(typeDescriptor.defaultType, emptyList<TypeParameterDescriptorImpl>(), thisAsReceiverParameter, null as KotlinType?) name,
it.initialize( CallableMemberDescriptor.Kind.SYNTHESIZED,
it.makePropertyGetterDescriptor(), SourceElement.NO_SOURCE,
if (!isVar) null else it.makePropertySetterDescriptor() /* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
/* isDelegated = */ true
) {
init {
setType(typeDescriptor.defaultType, emptyList<TypeParameterDescriptorImpl>(), receiver, null as KotlinType?)
initialize(
makePropertyGetterDescriptor(),
if (!isVar) null else makePropertySetterDescriptor()
) )
} }
}
private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() = private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() =
PropertyGetterDescriptorImpl( PropertyGetterDescriptorImpl(
this, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, this, Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
/* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false, /* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE
).also { ).also {
@@ -237,7 +250,7 @@ private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() =
private fun PropertyDescriptorImpl.makePropertySetterDescriptor() = private fun PropertyDescriptorImpl.makePropertySetterDescriptor() =
PropertySetterDescriptorImpl( PropertySetterDescriptorImpl(
this, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, this, Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
/* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false, /* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false,
CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE
).also { ).also {
@@ -0,0 +1,8 @@
// KOTLIN_SCRIPT_DEFINITION: org.jetbrains.kotlin.codegen.TestScriptWithSimpleEnvVars
// envVar: stringVar1 = abracadabra
val res = stringVar1.drop(4)
// expected: res = cadabra
@@ -212,3 +212,13 @@ object TestScriptWithReceiversConfiguration : ArrayList<Pair<TypedKey<*>, Any?>>
@KotlinScriptDefaultCompilationConfiguration(TestScriptWithReceiversConfiguration::class) @KotlinScriptDefaultCompilationConfiguration(TestScriptWithReceiversConfiguration::class)
abstract class TestScriptWithReceivers abstract class TestScriptWithReceivers
object TestScriptWithSimpleEnvVarsConfiguration : ArrayList<Pair<TypedKey<*>, Any?>>(
listOf(
ScriptCompileConfigurationProperties.contextVariables("stringVar1" to String::class.starProjectedType)
)
)
@Suppress("unused")
@KotlinScript
@KotlinScriptDefaultCompilationConfiguration(TestScriptWithSimpleEnvVarsConfiguration::class)
abstract class TestScriptWithSimpleEnvVars
@@ -29,6 +29,11 @@ public class CustomScriptCodegenTestGenerated extends AbstractCustomScriptCodege
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/customScript"), Pattern.compile("^(.+)\\.kts$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/customScript"), Pattern.compile("^(.+)\\.kts$"), TargetBackend.ANY, true);
} }
@TestMetadata("simpleEnvVars.kts")
public void testSimpleEnvVars() throws Exception {
runTest("compiler/testData/codegen/customScript/simpleEnvVars.kts");
}
@TestMetadata("stringReceiver.kts") @TestMetadata("stringReceiver.kts")
public void testStringReceiver() throws Exception { public void testStringReceiver() throws Exception {
runTest("compiler/testData/codegen/customScript/stringReceiver.kts"); runTest("compiler/testData/codegen/customScript/stringReceiver.kts");
@@ -29,4 +29,7 @@ public interface ScriptDescriptor extends ClassDescriptor {
@NotNull @NotNull
List<ClassDescriptor> getImplicitReceivers(); List<ClassDescriptor> getImplicitReceivers();
@NotNull
List<PropertyDescriptor> getScriptEnvironmentProperties();
} }