Skip to content

Commit 6fb83c2

Browse files
committed
Force wrapping java classes from annotation methods into KClasses
Before this change such wrapping happened only during coercion, i.e. when a call-site expected a KClass instance. But when call-site expects Any, for example, no wrapping happened, and raw j.l.Class instance was left on stack. The solution is to put wrapping code closer to generation of annotation's method call itself to guarantee that necessary wrapping will happen. #KT-9453 Fixed
1 parent 415c3d5 commit 6fb83c2

File tree

8 files changed

+157
-14
lines changed

8 files changed

+157
-14
lines changed

compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -372,23 +372,12 @@ else if (!fromType.equals(getType(Void.class))) {
372372
}
373373
}
374374
else if (toType.getSort() == Type.ARRAY) {
375-
if (fromType.getSort() == Type.ARRAY &&
376-
fromType.getElementType().equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(K_CLASS_ARRAY_TYPE)) {
377-
wrapJavaClassesIntoKClasses(v);
378-
}
379-
else {
380-
v.checkcast(toType);
381-
}
375+
v.checkcast(toType);
382376
}
383377
else if (toType.getSort() == Type.OBJECT) {
384378
if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) {
385379
if (!toType.equals(OBJECT_TYPE)) {
386-
if (fromType.equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(AsmTypes.K_CLASS_TYPE)) {
387-
wrapJavaClassIntoKClass(v);
388-
}
389-
else {
390-
v.checkcast(toType);
391-
}
380+
v.checkcast(toType);
392381
}
393382
}
394383
else {
@@ -1211,7 +1200,20 @@ public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
12111200
else {
12121201
getter.genInvokeInstruction(v);
12131202
}
1214-
coerce(getter.getReturnType(), type, v);
1203+
1204+
Type typeOfValueOnStack = getter.getReturnType();
1205+
if (DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
1206+
if (this.type.equals(K_CLASS_TYPE)) {
1207+
wrapJavaClassIntoKClass(v);
1208+
typeOfValueOnStack = K_CLASS_TYPE;
1209+
}
1210+
else if (this.type.equals(K_CLASS_ARRAY_TYPE)) {
1211+
wrapJavaClassesIntoKClasses(v);
1212+
typeOfValueOnStack = K_CLASS_ARRAY_TYPE;
1213+
}
1214+
}
1215+
1216+
coerce(typeOfValueOnStack, type, v);
12151217

12161218
KotlinType returnType = descriptor.getReturnType();
12171219
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// IGNORE_BACKEND: JS
2+
// WITH_REFLECT
3+
4+
import kotlin.reflect.KClass
5+
import kotlin.test.assertEquals
6+
7+
annotation class Anno(
8+
val klass: KClass<*>,
9+
val kClasses: Array<KClass<*>>,
10+
vararg val kClassesVararg: KClass<*>
11+
)
12+
13+
@Anno(String::class, arrayOf(Int::class), Double::class)
14+
fun foo() {}
15+
16+
fun box(): String {
17+
val k = ::foo.annotations.single() as Anno
18+
assertEquals(String::class, k.klass)
19+
assertEquals(Int::class, k.kClasses[0])
20+
assertEquals(Double::class, k.kClassesVararg[0])
21+
return "OK"
22+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// IGNORE_BACKEND: JS
2+
// WITH_REFLECT
3+
import kotlin.reflect.KClass
4+
import kotlin.test.assertEquals
5+
6+
annotation class Anno(
7+
val klass: KClass<*>,
8+
val kClasses: Array<KClass<*>>,
9+
vararg val kClassesVararg: KClass<*>
10+
)
11+
12+
@Anno(String::class, arrayOf(Int::class), Double::class)
13+
fun foo() {}
14+
15+
fun Anno.checkReference(expected: Any?, x: Anno.() -> Any?) {
16+
assertEquals(expected, x())
17+
}
18+
19+
fun Anno.checkReferenceArray(expected: Any?, x: Anno.() -> Array<out Any?>) {
20+
assertEquals(expected, x()[0])
21+
}
22+
23+
fun checkBoundReference(expected: Any?, x: () -> Any?) {
24+
assertEquals(expected, x())
25+
}
26+
27+
fun checkBoundReferenceArray(expected: Any?, x: () -> Array<out Any?>) {
28+
assertEquals(expected, x()[0])
29+
}
30+
31+
fun box(): String {
32+
val k = ::foo.annotations.single() as Anno
33+
k.checkReference(String::class, Anno::klass)
34+
k.checkReferenceArray(Int::class, Anno::kClasses)
35+
k.checkReferenceArray(Double::class, Anno::kClassesVararg)
36+
37+
checkBoundReference(String::class, k::klass)
38+
checkBoundReferenceArray(Int::class, k::kClasses)
39+
checkBoundReferenceArray(Double::class, k::kClassesVararg)
40+
return "OK"
41+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@java.lang.annotation.Retention
2+
@kotlin.Metadata
3+
public annotation class Anno {
4+
public abstract method kClasses(): java.lang.Class[]
5+
public abstract method kClassesVararg(): java.lang.Class[]
6+
public abstract method klass(): java.lang.Class
7+
}
8+
9+
@kotlin.Metadata
10+
public final class ForceWrappingKt {
11+
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
12+
public final static @Anno method foo(): void
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@java.lang.annotation.Retention
2+
@kotlin.Metadata
3+
public annotation class Anno {
4+
public abstract method kClasses(): java.lang.Class[]
5+
public abstract method kClassesVararg(): java.lang.Class[]
6+
public abstract method klass(): java.lang.Class
7+
}
8+
9+
@kotlin.Metadata
10+
public final class WrappingForCallableReferencesKt {
11+
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
12+
public final static method checkBoundReference(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): void
13+
public final static method checkBoundReferenceArray(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): void
14+
public final static method checkReference(@org.jetbrains.annotations.NotNull p0: Anno, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: kotlin.jvm.functions.Function1): void
15+
public final static method checkReferenceArray(@org.jetbrains.annotations.NotNull p0: Anno, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: kotlin.jvm.functions.Function1): void
16+
public final static @Anno method foo(): void
17+
}

compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14209,6 +14209,12 @@ public void testCheckcast() throws Exception {
1420914209
doTest(fileName);
1421014210
}
1421114211

14212+
@TestMetadata("forceWrapping.kt")
14213+
public void testForceWrapping() throws Exception {
14214+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/forceWrapping.kt");
14215+
doTest(fileName);
14216+
}
14217+
1421214218
@TestMetadata("vararg.kt")
1421314219
public void testVararg() throws Exception {
1421414220
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/vararg.kt");
@@ -14220,6 +14226,12 @@ public void testVarargInJava() throws Exception {
1422014226
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/varargInJava.kt");
1422114227
doTest(fileName);
1422214228
}
14229+
14230+
@TestMetadata("wrappingForCallableReferences.kt")
14231+
public void testWrappingForCallableReferences() throws Exception {
14232+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/wrappingForCallableReferences.kt");
14233+
doTest(fileName);
14234+
}
1422314235
}
1422414236

1422514237
@TestMetadata("compiler/testData/codegen/box/reflection/lambdaClasses")

compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14209,6 +14209,12 @@ public void testCheckcast() throws Exception {
1420914209
doTest(fileName);
1421014210
}
1421114211

14212+
@TestMetadata("forceWrapping.kt")
14213+
public void testForceWrapping() throws Exception {
14214+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/forceWrapping.kt");
14215+
doTest(fileName);
14216+
}
14217+
1421214218
@TestMetadata("vararg.kt")
1421314219
public void testVararg() throws Exception {
1421414220
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/vararg.kt");
@@ -14220,6 +14226,12 @@ public void testVarargInJava() throws Exception {
1422014226
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/varargInJava.kt");
1422114227
doTest(fileName);
1422214228
}
14229+
14230+
@TestMetadata("wrappingForCallableReferences.kt")
14231+
public void testWrappingForCallableReferences() throws Exception {
14232+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/wrappingForCallableReferences.kt");
14233+
doTest(fileName);
14234+
}
1422314235
}
1422414236

1422514237
@TestMetadata("compiler/testData/codegen/box/reflection/lambdaClasses")

js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17276,6 +17276,18 @@ public void testCheckcast() throws Exception {
1727617276
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
1727717277
}
1727817278

17279+
@TestMetadata("forceWrapping.kt")
17280+
public void testForceWrapping() throws Exception {
17281+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/forceWrapping.kt");
17282+
try {
17283+
doTest(fileName);
17284+
}
17285+
catch (Throwable ignore) {
17286+
return;
17287+
}
17288+
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
17289+
}
17290+
1727917291
@TestMetadata("vararg.kt")
1728017292
public void testVararg() throws Exception {
1728117293
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/vararg.kt");
@@ -17299,6 +17311,18 @@ public void testVarargInJava() throws Exception {
1729917311
}
1730017312
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
1730117313
}
17314+
17315+
@TestMetadata("wrappingForCallableReferences.kt")
17316+
public void testWrappingForCallableReferences() throws Exception {
17317+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/kClassInAnnotation/wrappingForCallableReferences.kt");
17318+
try {
17319+
doTest(fileName);
17320+
}
17321+
catch (Throwable ignore) {
17322+
return;
17323+
}
17324+
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
17325+
}
1730217326
}
1730317327

1730417328
@TestMetadata("compiler/testData/codegen/box/reflection/lambdaClasses")

0 commit comments

Comments
 (0)