KT-8575 Add tests and disable reflection for Java synthetic property references
This commit is contained in:
committed by
teamcity
parent
5116bbc440
commit
f8fd23e373
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+18
-6
@@ -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
|
||||
|
||||
+6
-1
@@ -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"
|
||||
}
|
||||
}
|
||||
+3
-9
@@ -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"
|
||||
}
|
||||
+6
-6
@@ -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 {
|
||||
|
||||
+18
-6
@@ -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
|
||||
|
||||
+5
-5
@@ -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() {
|
||||
|
||||
+1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user