KT-8575 Add tests and disable reflection for Java synthetic property references

This commit is contained in:
Pavel Mikhailovskii
2022-09-22 10:48:14 +02:00
committed by teamcity
parent 5116bbc440
commit f8fd23e373
12 changed files with 210 additions and 46 deletions
@@ -157,13 +157,15 @@ private fun FirBasedSymbol<*>.toSymbolForCall(
dispatchReceiver: FirExpression,
preferGetter: Boolean,
explicitReceiver: FirExpression? = null,
isDelegate: Boolean = false
isDelegate: Boolean = false,
isReference: Boolean = false
): IrSymbol? = when (this) {
is FirCallableSymbol<*> -> unwrapCallRepresentative().toSymbolForCall(
dispatchReceiver,
preferGetter,
explicitReceiver,
isDelegate
isDelegate,
isReference
)
is FirClassifierSymbol<*> -> toSymbol()
else -> error("Unknown symbol: $this")
@@ -175,7 +177,8 @@ fun FirReference.toSymbolForCall(
conversionScope: Fir2IrConversionScope,
preferGetter: Boolean = true,
explicitReceiver: FirExpression? = null, // Actual only for callable references
isDelegate: Boolean = false
isDelegate: Boolean = false,
isReference: Boolean = false
): IrSymbol? {
return when (this) {
is FirResolvedNamedReference ->
@@ -183,14 +186,16 @@ fun FirReference.toSymbolForCall(
dispatchReceiver,
preferGetter,
explicitReceiver,
isDelegate
isDelegate,
isReference
)
is FirErrorNamedReference ->
candidateSymbol?.toSymbolForCall(
dispatchReceiver,
preferGetter,
explicitReceiver,
isDelegate
isDelegate,
isReference
)
is FirThisReference -> {
when (val boundSymbol = boundSymbol) {
@@ -212,7 +217,8 @@ private fun FirCallableSymbol<*>.toSymbolForCall(
dispatchReceiver: FirExpression,
preferGetter: Boolean,
explicitReceiver: FirExpression? = null,
isDelegate: Boolean = false
isDelegate: Boolean = false,
isReference: Boolean = false
): IrSymbol? {
val dispatchReceiverLookupTag = when {
dispatchReceiver is FirNoReceiverExpression -> {
@@ -236,14 +242,18 @@ private fun FirCallableSymbol<*>.toSymbolForCall(
declarationStorage.getIrPropertySymbol(this)
} else {
(fir as? FirSyntheticProperty)?.let { syntheticProperty ->
val delegateSymbol = if (preferGetter) {
syntheticProperty.getter.delegate.symbol
if (isReference) {
declarationStorage.getIrPropertySymbol(this, dispatchReceiverLookupTag)
} else {
syntheticProperty.setter?.delegate?.symbol
?: throw AssertionError("Written synthetic property must have a setter")
val delegateSymbol = if (preferGetter) {
syntheticProperty.getter.delegate.symbol
} else {
syntheticProperty.setter?.delegate?.symbol
?: throw AssertionError("Written synthetic property must have a setter")
}
delegateSymbol.unwrapCallRepresentative()
.toSymbolForCall(dispatchReceiver, preferGetter, isDelegate = false)
}
delegateSymbol.unwrapCallRepresentative()
.toSymbolForCall(dispatchReceiver, preferGetter, isDelegate = false)
} ?: declarationStorage.getIrPropertySymbol(this)
}
}
@@ -89,7 +89,8 @@ class CallAndReferenceGenerator(
callableReferenceAccess.dispatchReceiver,
conversionScope,
explicitReceiver = callableReferenceAccess.explicitReceiver,
isDelegate = isDelegate
isDelegate = isDelegate,
isReference = true
)
// val x by y ->
// val `x$delegate` = y
@@ -44096,12 +44096,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/reflection/properties/noConflictOnKotlinGetterAndJavaField.kt");
}
@Test
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/overrideKotlinPropertyByJavaMethod.kt");
}
@Test
@TestMetadata("privateClassVal.kt")
public void testPrivateClassVal() throws Exception {
@@ -44168,6 +44162,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/reflection/properties/simpleGetProperties.kt");
}
@Test
@TestMetadata("syntheticJavaProperty.kt")
public void testSyntheticJavaProperty() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/syntheticJavaProperty.kt");
}
@Test
@TestMetadata("withLocalType.kt")
public void testWithLocalType() throws Exception {
@@ -48791,6 +48791,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/syntheticExtensions/implicitReceiver.kt");
}
@Test
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/overrideKotlinPropertyByJavaMethod.kt");
}
@Test
@TestMetadata("overrideOnlyGetter.kt")
public void testOverrideOnlyGetter() throws Exception {
@@ -48832,6 +48838,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testSetterNonVoid2() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/setterNonVoid2.kt");
}
@Test
@TestMetadata("syntheticJavaProperty.kt")
public void testSyntheticJavaProperty() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/syntheticJavaProperty.kt");
}
}
@Nested
@@ -351,7 +351,12 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
call.putValueArgument(index++, computeSignatureString(expression))
if (useOptimizedSuperClass) {
val isPackage = (container is IrClass && container.isFileClass) || container is IrPackageFragment
call.putValueArgument(index, irInt(if (isPackage) 1 else 0))
val isJavaSynthetic = (expression.symbol.owner as? IrProperty)?.let {
it.backingField == null &&
(it.origin == IrDeclarationOrigin.SYNTHETIC_JAVA_PROPERTY_DELEGATE
|| it.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB)
} ?: false
call.putValueArgument(index, irInt((if (isPackage) 1 else 0) or (if (isJavaSynthetic) 2 else 0)))
}
}
@@ -0,0 +1,34 @@
// TARGET_BACKEND: JVM_IR
// !LANGUAGE: +ReferencesToSyntheticJavaProperties
// WITH_REFLECT
// FILE: J.java
public class J {
private String stringProperty;
public String getStringProperty() {
return stringProperty;
}
public void setStringProperty(String value) {
stringProperty = value;
}
}
// FILE: main.kt
import kotlin.reflect.*
import kotlin.test.*
fun box(): String {
val stringProperty = J::stringProperty
assertEquals("property stringProperty (Kotlin reflection is not available)", stringProperty.toString())
try {
stringProperty.visibility
return "Fail"
} catch (e: UnsupportedOperationException) {
assertEquals("Kotlin reflection is not yet supported for synthetic Java properties", e.message)
return "OK"
}
}
@@ -1,6 +1,6 @@
// TARGET_BACKEND: JVM
// WITH_REFLECT
// WITH_STDLIB
// FILE: J.java
public class J implements K {
@@ -20,7 +20,6 @@ public class J implements K {
// FILE: K.kt
import kotlin.test.assertEquals
import kotlin.reflect.KParameter
interface K {
var foo: String
@@ -30,12 +29,7 @@ fun box(): String {
val p = J::foo
assertEquals("foo", p.name)
if (p.parameters.size != 1) return "Should have only 1 parameter"
if (p.parameters.single().kind != KParameter.Kind.INSTANCE) return "Should have an instance parameter"
if (J::class.members.none { it == p }) return "No foo in members"
val j = J()
p.setter.call(j, "OK")
return p.getter.call(j)
p.set(j, "OK")
return p.get(j)
}
@@ -0,0 +1,79 @@
// TARGET_BACKEND: JVM_IR
// !LANGUAGE: +ReferencesToSyntheticJavaProperties
// WITH_STDLIB
// FILE: J.java
public class J {
private String stringProperty;
private boolean myBooleanProperty;
public int numGetCalls;
public int numSetCalls;
public String getStringProperty() {
numGetCalls++;
return stringProperty;
}
public void setStringProperty(String value) {
numSetCalls++;
stringProperty = value;
}
public boolean isBooleanProperty() {
numGetCalls++;
return myBooleanProperty;
}
public void setBooleanProperty(boolean value) {
numSetCalls++;
myBooleanProperty = value;
}
}
// FILE: main.kt
import kotlin.reflect.*
import kotlin.test.*
fun box(): String {
val j = J()
val unboundStringProperty = J::stringProperty
assertNull(unboundStringProperty.get(j))
unboundStringProperty.set(j, "Hi")
assertEquals("Hi", unboundStringProperty.get(j))
assertEquals("Hi", unboundStringProperty(j))
assertEquals(3, j.numGetCalls)
assertEquals(1, j.numSetCalls)
val boundStringProperty = j::stringProperty
assertEquals("Hi", boundStringProperty.get())
boundStringProperty.set("Hello")
assertEquals("Hello", boundStringProperty.get())
assertEquals("Hello", boundStringProperty())
assertEquals(6, j.numGetCalls)
assertEquals(2, j.numSetCalls)
val unboundBooleanProperty: KMutableProperty1<J, Boolean> = J::isBooleanProperty
assertFalse(unboundBooleanProperty.get(j))
unboundBooleanProperty.set(j, true)
assertTrue(unboundBooleanProperty.get(j))
assertTrue(unboundBooleanProperty(j))
assertEquals(9, j.numGetCalls)
assertEquals(3, j.numSetCalls)
val boundBooleanProperty: KMutableProperty0<Boolean> = j::isBooleanProperty
assertTrue(boundBooleanProperty.get())
boundBooleanProperty.set(false)
assertFalse(boundBooleanProperty.get())
assertFalse(boundBooleanProperty())
assertEquals(12, j.numGetCalls)
assertEquals(4, j.numSetCalls)
return "OK"
}
@@ -42656,12 +42656,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/properties/noConflictOnKotlinGetterAndJavaField.kt");
}
@Test
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/overrideKotlinPropertyByJavaMethod.kt");
}
@Test
@TestMetadata("privateClassVal.kt")
public void testPrivateClassVal() throws Exception {
@@ -47273,6 +47267,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/syntheticExtensions/implicitReceiver.kt");
}
@Test
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/overrideKotlinPropertyByJavaMethod.kt");
}
@Test
@TestMetadata("overrideOnlyGetter.kt")
public void testOverrideOnlyGetter() throws Exception {
@@ -44096,12 +44096,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/properties/noConflictOnKotlinGetterAndJavaField.kt");
}
@Test
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/overrideKotlinPropertyByJavaMethod.kt");
}
@Test
@TestMetadata("privateClassVal.kt")
public void testPrivateClassVal() throws Exception {
@@ -44168,6 +44162,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/properties/simpleGetProperties.kt");
}
@Test
@TestMetadata("syntheticJavaProperty.kt")
public void testSyntheticJavaProperty() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/syntheticJavaProperty.kt");
}
@Test
@TestMetadata("withLocalType.kt")
public void testWithLocalType() throws Exception {
@@ -48791,6 +48791,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/syntheticExtensions/implicitReceiver.kt");
}
@Test
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/overrideKotlinPropertyByJavaMethod.kt");
}
@Test
@TestMetadata("overrideOnlyGetter.kt")
public void testOverrideOnlyGetter() throws Exception {
@@ -48832,6 +48838,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testSetterNonVoid2() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/setterNonVoid2.kt");
}
@Test
@TestMetadata("syntheticJavaProperty.kt")
public void testSyntheticJavaProperty() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/syntheticJavaProperty.kt");
}
}
@Nested
@@ -34254,11 +34254,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/properties/noConflictOnKotlinGetterAndJavaField.kt");
}
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/overrideKotlinPropertyByJavaMethod.kt");
}
@TestMetadata("privateClassVal.kt")
public void testPrivateClassVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/properties/privateClassVal.kt");
@@ -38307,6 +38302,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/syntheticExtensions/implicitReceiver.kt");
}
@TestMetadata("overrideKotlinPropertyByJavaMethod.kt")
public void testOverrideKotlinPropertyByJavaMethod() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/overrideKotlinPropertyByJavaMethod.kt");
}
@TestMetadata("overrideOnlyGetter.kt")
public void testOverrideOnlyGetter() throws Exception {
runTest("compiler/testData/codegen/box/syntheticExtensions/overrideOnlyGetter.kt");
@@ -11,26 +11,42 @@ import kotlin.reflect.KProperty;
@SuppressWarnings("rawtypes")
public abstract class PropertyReference extends CallableReference implements KProperty {
private final boolean syntheticJavaProperty;
public PropertyReference() {
super();
syntheticJavaProperty = false;
}
@SinceKotlin(version = "1.1")
public PropertyReference(Object receiver) {
super(receiver);
syntheticJavaProperty = false;
}
@SinceKotlin(version = "1.4")
public PropertyReference(Object receiver, Class owner, String name, String signature, int flags) {
super(receiver, owner, name, signature, (flags & 1) == 1);
syntheticJavaProperty = (flags & 2) == 2;
}
@Override
@SinceKotlin(version = "1.1")
protected KProperty getReflected() {
if (syntheticJavaProperty) {
throw new UnsupportedOperationException("Kotlin reflection is not yet supported for synthetic Java properties");
}
return (KProperty) super.getReflected();
}
@Override
public KCallable compute() {
return syntheticJavaProperty ? this : super.compute();
}
@Override
@SinceKotlin(version = "1.1")
public boolean isLateinit() {
@@ -4007,6 +4007,7 @@ public abstract class kotlin/jvm/internal/PropertyReference : kotlin/jvm/interna
public fun <init> ()V
public fun <init> (Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
public fun compute ()Lkotlin/reflect/KCallable;
public fun equals (Ljava/lang/Object;)Z
protected synthetic fun getReflected ()Lkotlin/reflect/KCallable;
protected fun getReflected ()Lkotlin/reflect/KProperty;