Support calling methods annotated with PolymorphicSignature

#KT-14416 Fixed
 #KT-26165 Fixed
This commit is contained in:
Alexander Udalov
2018-11-12 17:38:42 +01:00
parent b940418604
commit a796f11934
18 changed files with 595 additions and 25 deletions
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
@@ -22,8 +24,14 @@ class CallBasedArgumentGenerator(
private val isVarargInvoke: Boolean =
JvmCodegenUtil.isDeclarationOfBigArityFunctionInvoke(valueParameters.firstOrNull()?.containingDeclaration)
private val isPolymorphicSignature: Boolean =
codegen.state.languageVersionSettings.supportsFeature(LanguageFeature.PolymorphicSignature) &&
(valueParameters.firstOrNull()?.containingDeclaration as? FunctionDescriptor)?.let { function ->
JvmCodegenUtil.isPolymorphicSignature(function)
} == true
init {
if (!isVarargInvoke) {
if (!isVarargInvoke && !isPolymorphicSignature) {
assert(valueParameters.size == valueParameterTypes.size) {
"Value parameters and their types mismatch in sizes: ${valueParameters.size} != ${valueParameterTypes.size}"
}
@@ -49,6 +57,15 @@ class CallBasedArgumentGenerator(
}
override fun generateVararg(i: Int, argument: VarargValueArgument) {
if (isPolymorphicSignature) {
for ((index, arg) in argument.arguments.withIndex()) {
val expression = arg.getArgumentExpression()!!
val type = JvmKotlinType(valueParameterTypes[index], codegen.kotlinType(expression))
callGenerator.genValueAndPut(null, expression, type, index)
}
return
}
// Upper bound for type of vararg parameter should always have a form of 'Array<out T>',
// while its lower bound may be Nothing-typed after approximation
val lazyVararg = codegen.genVarargs(argument, valueParameters[i].type.upperIfFlexible())
@@ -2401,12 +2401,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return intrinsic.toCallable(fd, superCall, resolvedCall, this);
}
return resolveToCallableMethod(fd, superCall);
}
@NotNull
private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall) {
return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), superCall);
return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), resolvedCall, superCall, null);
}
public void invokeMethodWithArguments(
@@ -4381,7 +4376,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
assert resolvedCall != null : "No resolved call for " + operationDescriptor;
Callable callable = resolveToCallable(accessibleFunctionDescriptor(resolvedCall), false, resolvedCall);
Callable callableMethod = resolveToCallableMethod(operationDescriptor, false);
Callable callableMethod = typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(operationDescriptor), false);
Type[] argumentTypes = callableMethod.getParameterTypes();
StackValue.CollectionElementReceiver collectionElementReceiver = createCollectionElementReceiver(
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt;
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.KtFile;
@@ -384,4 +385,8 @@ public class JvmCodegenUtil {
: "ClassDescriptor should not be null:" + specifier.getText();
return superClass;
}
public static boolean isPolymorphicSignature(@NotNull FunctionDescriptor descriptor) {
return descriptor.getAnnotations().hasAnnotation(new FqName("java.lang.invoke.MethodHandle.PolymorphicSignature"));
}
}
@@ -46,14 +46,13 @@ import org.jetbrains.kotlin.load.kotlin.*;
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider.IncrementalMultifileClassPackageFragment;
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmBytecodeBinaryVersion;
import org.jetbrains.kotlin.name.*;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtFunctionLiteral;
import org.jetbrains.kotlin.psi.KtLambdaExpression;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
@@ -791,7 +790,12 @@ public class KotlinTypeMapper {
}
@NotNull
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall, @Nullable OwnerKind kind) {
public CallableMethod mapToCallableMethod(
@NotNull FunctionDescriptor descriptor,
@Nullable ResolvedCall<?> resolvedCall,
boolean superCall,
@Nullable OwnerKind kind
) {
// we generate constructors of inline classes as usual functions
if (descriptor instanceof ConstructorDescriptor && kind != OwnerKind.ERASED_INLINE_CLASS) {
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal());
@@ -904,7 +908,7 @@ public class KotlinTypeMapper {
signature = toInlinedErasedClass
? mapSignatureForInlineErasedClassSkipGeneric(functionToCall)
: mapSignatureSkipGeneric(functionToCall);
: mapSignature(functionToCall, resolvedCall, OwnerKind.IMPLEMENTATION, true, false);
returnKotlinType = functionToCall.getReturnType();
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor
@@ -965,6 +969,11 @@ public class KotlinTypeMapper {
);
}
@NotNull
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall, @Nullable OwnerKind kind) {
return mapToCallableMethod(descriptor, null, superCall, kind);
}
@NotNull
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall) {
return mapToCallableMethod(descriptor, superCall, null);
@@ -1215,17 +1224,20 @@ public class KotlinTypeMapper {
}
@NotNull
public JvmMethodGenericSignature mapSignatureWithGeneric(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind, boolean hasSpecialBridge) {
return mapSignature(f, kind, false, hasSpecialBridge);
public JvmMethodGenericSignature mapSignatureWithGeneric(
@NotNull FunctionDescriptor f, @NotNull OwnerKind kind, boolean hasSpecialBridge
) {
return mapSignature(f, null, kind, false, hasSpecialBridge);
}
private JvmMethodGenericSignature mapSignature(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind, boolean skipGenericSignature) {
return mapSignature(f, kind, skipGenericSignature, false);
return mapSignature(f, null, kind, skipGenericSignature, false);
}
@NotNull
private JvmMethodGenericSignature mapSignature(
@NotNull FunctionDescriptor f,
@Nullable ResolvedCall<?> resolvedCall,
@NotNull OwnerKind kind,
boolean skipGenericSignature,
boolean hasSpecialBridge
@@ -1254,13 +1266,25 @@ public class KotlinTypeMapper {
if (isDeclarationOfBigArityFunctionInvoke(f) || isDeclarationOfBigArityCreateCoroutineMethod(f)) {
KotlinBuiltIns builtIns = DescriptorUtilsKt.getBuiltIns(f);
KotlinType arrayOfNullableAny = builtIns.getArrayType(Variance.INVARIANT, builtIns.getNullableAnyType());
return mapSignatureWithCustomParameters(f, kind, Stream.of(arrayOfNullableAny), false, false);
return mapSignatureWithCustomParameters(f, kind, Stream.of(arrayOfNullableAny), null, false, false);
}
return mapSignatureWithCustomParameters(
f, kind, f.getValueParameters().stream().map(ValueParameterDescriptor::getType),
skipGenericSignature, hasSpecialBridge
);
Stream<KotlinType> parameterTypes;
KotlinType returnType;
if (languageVersionSettings.supportsFeature(LanguageFeature.PolymorphicSignature) && JvmCodegenUtil.isPolymorphicSignature(f)) {
if (resolvedCall == null) {
throw new UnsupportedOperationException("Cannot determine polymorphic signature without a resolved call: " + f);
}
parameterTypes = extractPolymorphicParameterTypes(resolvedCall);
returnType = extractPolymorphicReturnType(resolvedCall);
}
else {
parameterTypes = f.getValueParameters().stream().map(ValueParameterDescriptor::getType);
returnType = null;
}
return mapSignatureWithCustomParameters(f, kind, parameterTypes, returnType, skipGenericSignature, hasSpecialBridge);
}
@NotNull
@@ -1271,8 +1295,7 @@ public class KotlinTypeMapper {
boolean skipGenericSignature
) {
return mapSignatureWithCustomParameters(
f, kind, valueParameters.stream().map(ValueParameterDescriptor::getType),
skipGenericSignature, false
f, kind, valueParameters.stream().map(ValueParameterDescriptor::getType), null, skipGenericSignature, false
);
}
@@ -1281,6 +1304,7 @@ public class KotlinTypeMapper {
@NotNull FunctionDescriptor f,
@NotNull OwnerKind kind,
@NotNull Stream<KotlinType> valueParameterTypes,
@Nullable KotlinType customReturnType,
boolean skipGenericSignature,
boolean hasSpecialBridge
) {
@@ -1344,7 +1368,12 @@ public class KotlinTypeMapper {
});
sw.writeReturnType();
mapReturnType(f, sw);
if (customReturnType != null) {
mapReturnType(f, sw, customReturnType);
}
else {
mapReturnType(f, sw);
}
sw.writeReturnTypeEnd();
}
@@ -1363,6 +1392,54 @@ public class KotlinTypeMapper {
return signature;
}
@NotNull
private Stream<KotlinType> extractPolymorphicParameterTypes(@NotNull ResolvedCall<?> resolvedCall) {
List<ResolvedValueArgument> valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex();
if (valueArgumentsByIndex == null ||
valueArgumentsByIndex.size() != 1 ||
!(valueArgumentsByIndex.get(0) instanceof VarargValueArgument)) {
throw new UnsupportedOperationException(
"Polymorphic signature is only supported for methods with one vararg argument: " + resolvedCall.getResultingDescriptor()
);
}
VarargValueArgument argument = (VarargValueArgument) valueArgumentsByIndex.get(0);
return argument.getArguments().stream().map(arg -> {
KtExpression expression = arg.getArgumentExpression();
if (expression == null) {
throw new UnsupportedOperationException(
"Polymorphic signature argument must be an expression: " + resolvedCall.getResultingDescriptor()
);
}
return bindingContext.getType(expression);
});
}
@Nullable
private KotlinType extractPolymorphicReturnType(@NotNull ResolvedCall<?> resolvedCall) {
// Return type is polymorphic only in case it's Object; see VarHandle.compareAndSet and similar.
KotlinType originalReturnType = resolvedCall.getResultingDescriptor().getReturnType();
if (originalReturnType != null && !KotlinBuiltIns.isAny(originalReturnType)) return null;
if (!(resolvedCall.getCall().getCallElement() instanceof KtExpression)) {
throw new UnsupportedOperationException(
"Polymorphic signature method call must be an expression: " + resolvedCall.getResultingDescriptor()
);
}
KtExpression expression = (KtExpression) resolvedCall.getCall().getCallElement();
while (true) {
KtQualifiedExpression parent = KtPsiUtilKt.getQualifiedExpressionForSelector(expression);
if (parent == null) break;
expression = parent;
}
expression = KtPsiUtilKt.getOutermostParenthesizerOrThis(expression);
return expression.getParent() instanceof KtBinaryExpressionWithTypeRHS
? bindingContext.getType((KtExpression) expression.getParent())
: null;
}
private void checkOwnerCompatibility(@NotNull FunctionDescriptor descriptor) {
KotlinJvmBinaryClass ownerClass = KotlinJvmBinaryClassUtilKt.getContainingKotlinJvmBinaryClass(descriptor);
if (ownerClass == null) return;
@@ -0,0 +1,37 @@
// !LANGUAGE: +PolymorphicSignature
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_RUNTIME
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.lang.invoke.WrongMethodTypeException
interface I {
fun get(): String
}
class C {
fun run(i: I): String = i.get()
}
fun box(): String {
val mh = MethodHandles.lookup().findVirtual(
C::class.java, "run",
MethodType.methodType(String::class.java, I::class.java)
)
try {
return mh.invokeExact(C(), object : I {
override fun get(): String = "Fail"
}) as String
} catch (e: WrongMethodTypeException) {
// OK
}
return mh.invoke(C(), object : I {
override fun get(): String = "OK"
}) as String
}
@@ -0,0 +1,47 @@
// !LANGUAGE: +PolymorphicSignature
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_RUNTIME
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
open class Base
class Derived : Base() {
override fun toString() = "!"
}
class C {
fun foo(s: String, d: Double?, x: Base): String = "$s$d$x"
}
@Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class IrrelevantAnnotation
fun box(): String {
val mh = MethodHandles.lookup().findVirtual(
C::class.java, "foo",
MethodType.methodType(String::class.java, String::class.java, Double::class.javaObjectType, Base::class.java)
)
val result1: String = mh.invoke(C(), "Hello", 0.01, Derived()) as String
if (result1 != "Hello0.01!") return "Fail 1: $result1"
// Check parenthesized/annotated expressions + invoke via "()"
val result2 = (@IrrelevantAnnotation() ((mh(C(), (("Hello")), 0.01, Derived())))) as String
if (result1 != result2) return "Fail 2: $result1 != $result2"
// Check deep qualified expressions
val o = object {
val p = object {
val handle = mh
}
}
val result3 = (o.p).handle.invoke(C(), "Hello", 0.01, Derived()) as String
if (result1 != result3) return "Fail 3: $result1 != $result3"
return "OK"
}
@@ -0,0 +1,22 @@
// !LANGUAGE: +PolymorphicSignature
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_RUNTIME
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
class C {
fun foo(s: String, d: Double, x: Int): String = "$s$d$x"
}
fun box(): String {
val mh = MethodHandles.lookup().findVirtual(
C::class.java, "foo",
MethodType.methodType(String::class.java, String::class.java, Double::class.java, Int::class.java)
)
val result: String = mh.invokeExact(C(), "Hello", 0.01, 42) as String
return if (result == "Hello0.0142") "OK" else "Fail: $result"
}
@@ -0,0 +1,23 @@
// !LANGUAGE: +PolymorphicSignature
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_REFLECT
import java.lang.invoke.MethodHandles
import kotlin.reflect.jvm.javaMethod
inline class Z(val s: String)
fun foo(z: Z): String = z.s
fun box(): String {
val mh = MethodHandles.lookup().unreflect(::foo.javaMethod!!)
// TODO: it's unclear whether this should throw or not, see KT-28214.
val r1 = mh.invokeExact(Z("OK")) as String
if (r1 != "OK") return "Fail r1: $r1"
return mh.invokeExact("OK") as String
}
@@ -0,0 +1,51 @@
// !LANGUAGE: +PolymorphicSignature
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_RUNTIME
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.lang.invoke.WrongMethodTypeException
fun foo(vararg args: Any?): Any? = args[0]
fun box(): String {
val mh = MethodHandles.lookup().findStatic(
object {}::class.java.enclosingClass, "foo",
MethodType.methodType(Any::class.java, Array<Any>::class.java)
)
val args = arrayOf("aaa", 1)
val r1 = mh.invokeExact(args)
if (r1 != "aaa") return "Fail 1: $r1"
val r2 = mh.invokeExact(*args)
if (r2 != "aaa") return "Fail 2: $r2"
val r3 = mh.invokeExact(arrayOf(args) as Array<*>)
if (r3 !is Array<*> || !r3.contentEquals(args)) return "Fail 3: $r3"
try {
mh.invokeExact(arrayOf(args))
return "Fail 4"
} catch (e: WrongMethodTypeException) {
// OK
}
val r5 = mh.invoke(args)
if (r5 != "aaa") return "Fail 5: $r5"
val r6 = mh.invoke(*args)
if (r6 != "aaa") return "Fail 6: $r6"
val r7 = mh.invoke(arrayOf(args) as Array<*>)
if (r7 !is Array<*> || !r7.contentEquals(args)) return "Fail 7: $r7"
val r8 = mh.invoke(arrayOf(args))
if (r8 !is Array<*> || !r8.contentEquals(args)) return "Fail 8: $r8"
return "OK"
}
@@ -0,0 +1,48 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_RUNTIME
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.lang.invoke.WrongMethodTypeException
fun foo(vararg args: Any?): Any? = args[0]
fun box(): String {
val mh = MethodHandles.lookup().findStatic(
object {}::class.java.enclosingClass, "foo",
MethodType.methodType(Any::class.java, Array<Any>::class.java)
)
val args = arrayOf("aaa", 1)
// Note that before PolymorphicSignature was supported in the compiler, this call (and some subsequent calls) made little sense
// because the vararg was always wrapped in another array. But it compiled and worked somehow, and this test checks its behavior.
val r1 = mh.invokeExact(args)
if (r1 !is Array<*> || !r1.contentEquals(args)) return "Fail 1: $r1"
val r2 = mh.invokeExact(*args)
if (r2 != "aaa") return "Fail 2: $r2"
val r3 = mh.invokeExact(arrayOf(args) as Array<*>)
if (r3 !is Array<*> || r3[0] !is Array<*> || !(r3[0] as Array<*>).contentEquals(args)) return "Fail 3: $r3"
val r4 = mh.invokeExact(arrayOf(args))
if (r4 !is Array<*> || r4[0] !is Array<*> || !(r4[0] as Array<*>).contentEquals(args)) return "Fail 4: $r4"
val r5 = mh.invoke(args)
if (r5 !is Array<*> || !r5.contentEquals(args)) return "Fail 5: $r5"
val r6 = mh.invoke(*args)
if (r6 != "aaa") return "Fail 6: $r6"
val r7 = mh.invoke(arrayOf(args) as Array<*>)
if (r7 !is Array<*> || r7[0] !is Array<*> || !(r7[0] as Array<*>).contentEquals(args)) return "Fail 7: $r7"
val r8 = mh.invoke(arrayOf(args))
if (r8 !is Array<*> || r8[0] !is Array<*> || !(r8[0] as Array<*>).contentEquals(args)) return "Fail 8: $r8"
return "OK"
}
+38
View File
@@ -0,0 +1,38 @@
// !LANGUAGE: +PolymorphicSignature
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// SKIP_JDK6
// WITH_RUNTIME
import java.lang.invoke.MethodHandles
import kotlin.concurrent.thread
fun box(): String {
val handle = MethodHandles.arrayElementVarHandle(ByteArray::class.java)
val array = ByteArray(10)
val index = 0
// Check that we don't consider non-Object return type of a signature-polymorphic method to be polymorphic.
handle.weakCompareAndSetPlain(array, index, 0.toByte(), 21.toByte()) as Comparable<*>
val oldValue = 42.toByte()
val newValue = (-74).toByte()
thread {
Thread.sleep(400L)
handle.setVolatile(array, index, oldValue)
}
while (!handle.compareAndSet(array, index, oldValue, newValue)) {
Thread.sleep(10L)
}
return if (handle.getVolatile(array, index) == newValue) "OK" else "Fail"
}
fun main() {
box().let { if (it != "OK") throw AssertionError(it) }
}
@@ -16773,6 +16773,49 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@TestMetadata("compiler/testData/codegen/box/polymorphicSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PolymorphicSignature extends AbstractBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInPolymorphicSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/polymorphicSignature"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("anonymousSubclass.kt")
public void testAnonymousSubclass() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/anonymousSubclass.kt");
}
@TestMetadata("invoke.kt")
public void testInvoke() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invoke.kt");
}
@TestMetadata("invokeExact.kt")
public void testInvokeExact() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invokeExact.kt");
}
@TestMetadata("invokeExactWithInlineClass.kt")
public void testInvokeExactWithInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invokeExactWithInlineClass.kt");
}
@TestMetadata("varargOfObjects_after.kt")
public void testVarargOfObjects_after() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/varargOfObjects_after.kt");
}
@TestMetadata("varargOfObjects_before.kt")
public void testVarargOfObjects_before() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/varargOfObjects_before.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/primitiveTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.codegen
import org.jetbrains.kotlin.cli.common.output.writeAll
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
import java.util.concurrent.TimeUnit
// TODO: merge into main codegen box tests somehow
class Java9CodegenTest : AbstractBlackBoxCodegenTest() {
override fun setUp() {
super.setUp()
val fileName = KotlinTestUtils.getTestDataPathBase() + "/codegen/" + getPrefix() + "/" + getTestName(true) + ".kt"
val testFile = TestFile(fileName, File(fileName).readText())
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.NO_KOTLIN_REFLECT, listOf(testFile), TestJdkKind.FULL_JDK_9)
}
override fun getPrefix(): String = "java9/box"
override fun blackBox() {
val tmpdir = KotlinTestUtils.tmpDirForTest(this)
generateClassesInFile().writeAll(tmpdir, null)
val jdk9Home = KotlinTestUtils.getJdk9Home()
val javaExe = File(jdk9Home, "bin/java.exe").takeIf(File::exists)
?: File(jdk9Home, "bin/java").takeIf(File::exists)
?: error("Can't find 'java' executable in $jdk9Home")
val command = arrayOf(
javaExe.absolutePath,
"-ea",
"-classpath",
listOf(tmpdir, ForTestCompileRuntime.runtimeJarForTests()).joinToString(File.pathSeparator, transform = File::getAbsolutePath),
PackagePartClassUtils.getFilePartShortName(getTestName(false))
)
val process = ProcessBuilder(*command).inheritIO().start()
process.waitFor(1, TimeUnit.MINUTES)
assertEquals(0, process.exitValue())
}
fun testVarHandle() {
loadFile()
blackBox()
}
}
@@ -16773,6 +16773,49 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
}
}
@TestMetadata("compiler/testData/codegen/box/polymorphicSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PolymorphicSignature extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInPolymorphicSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/polymorphicSignature"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("anonymousSubclass.kt")
public void testAnonymousSubclass() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/anonymousSubclass.kt");
}
@TestMetadata("invoke.kt")
public void testInvoke() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invoke.kt");
}
@TestMetadata("invokeExact.kt")
public void testInvokeExact() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invokeExact.kt");
}
@TestMetadata("invokeExactWithInlineClass.kt")
public void testInvokeExactWithInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invokeExactWithInlineClass.kt");
}
@TestMetadata("varargOfObjects_after.kt")
public void testVarargOfObjects_after() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/varargOfObjects_after.kt");
}
@TestMetadata("varargOfObjects_before.kt")
public void testVarargOfObjects_before() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/varargOfObjects_before.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/primitiveTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -16778,6 +16778,49 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
}
@TestMetadata("compiler/testData/codegen/box/polymorphicSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PolymorphicSignature extends AbstractIrBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInPolymorphicSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/polymorphicSignature"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("anonymousSubclass.kt")
public void testAnonymousSubclass() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/anonymousSubclass.kt");
}
@TestMetadata("invoke.kt")
public void testInvoke() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invoke.kt");
}
@TestMetadata("invokeExact.kt")
public void testInvokeExact() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invokeExact.kt");
}
@TestMetadata("invokeExactWithInlineClass.kt")
public void testInvokeExactWithInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/invokeExactWithInlineClass.kt");
}
@TestMetadata("varargOfObjects_after.kt")
public void testVarargOfObjects_after() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/varargOfObjects_after.kt");
}
@TestMetadata("varargOfObjects_before.kt")
public void testVarargOfObjects_before() throws Exception {
runTest("compiler/testData/codegen/box/polymorphicSignature/varargOfObjects_before.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/primitiveTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -92,6 +92,7 @@ enum class LanguageFeature(
RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
NoConstantValueAttributeForNonConstVals(KOTLIN_1_4, kind = BUG_FIX),
WarningOnMainUnusedParameter(KOTLIN_1_4),
PolymorphicSignature(KOTLIN_1_4),
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
// Temporarily disabled, see KT-27084/KT-22379
@@ -14318,6 +14318,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
}
}
@TestMetadata("compiler/testData/codegen/box/polymorphicSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PolymorphicSignature extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInPolymorphicSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/polymorphicSignature"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
}
}
@TestMetadata("compiler/testData/codegen/box/primitiveTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -15373,6 +15373,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
@TestMetadata("compiler/testData/codegen/box/polymorphicSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PolymorphicSignature extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInPolymorphicSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/polymorphicSignature"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
}
@TestMetadata("compiler/testData/codegen/box/primitiveTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)