Support for synthetic extensions in codegen

This commit is contained in:
Valentin Kipyatkov
2015-07-08 15:07:16 +03:00
parent 2e351f3e4d
commit 08754b9fc0
11 changed files with 120 additions and 9 deletions
@@ -76,6 +76,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
import org.jetbrains.kotlin.synthetic.SyntheticExtensionPropertyDescriptor;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeProjection;
import org.jetbrains.kotlin.types.TypeUtils;
@@ -2144,6 +2145,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull MethodKind methodKind,
StackValue receiver
) {
if (propertyDescriptor instanceof SyntheticExtensionPropertyDescriptor) {
return intermediateValueForSyntheticExtensionProperty((SyntheticExtensionPropertyDescriptor) propertyDescriptor, receiver);
}
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
@@ -2166,10 +2171,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (isBackingFieldInAnotherClass && forceField) {
backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
skipPropertyAccessors =
(flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
if (!skipPropertyAccessors) {
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType);
changeOwnerOnTypeMapping = changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
changeOwnerOnTypeMapping =
changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
}
}
@@ -2191,7 +2198,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
if (getter != null) {
callableGetter = typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
callableGetter =
typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
}
}
@@ -2202,14 +2210,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
callableSetter = null;
}
else {
callableSetter = typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
callableSetter =
typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
}
}
}
}
propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
Type backingFieldOwner = typeMapper.mapOwner(changeOwnerOnTypeMapping ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
Type backingFieldOwner =
typeMapper.mapOwner(changeOwnerOnTypeMapping ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory()));
String fieldName;
@@ -2226,9 +2236,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
return StackValue.property(propertyDescriptor, backingFieldOwner,
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver);
typeMapper.mapType(
isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver);
}
@NotNull
private StackValue.Property intermediateValueForSyntheticExtensionProperty(@NotNull SyntheticExtensionPropertyDescriptor propertyDescriptor, StackValue receiver) {
Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType());
CallableMethod callableGetter = typeMapper.mapToCallableMethod(propertyDescriptor.getGetMethod(), false, context);
FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
CallableMethod callableSetter = setMethod != null ? typeMapper.mapToCallableMethod(setMethod, false, context) : null;
return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, state, receiver);
}
@Override
@@ -248,7 +248,7 @@ public abstract class StackValue {
@NotNull
public static Property property(
@NotNull PropertyDescriptor descriptor,
@NotNull Type backingFieldOwner,
@Nullable Type backingFieldOwner,
@NotNull Type type,
boolean isStaticBackingField,
@Nullable String fieldName,
@@ -989,7 +989,7 @@ public abstract class StackValue {
private final String fieldName;
public Property(
@NotNull PropertyDescriptor descriptor, @NotNull Type backingFieldOwner,
@NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner,
@Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
@Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state,
@NotNull StackValue receiver
@@ -1007,6 +1007,7 @@ public abstract class StackValue {
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
if (getter == null) {
assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
assert backingFieldOwner != null : "Property should have either a getter or a backingFieldOwner: " + descriptor;
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
genNotNullAssertionForField(v, state, descriptor);
coerceTo(type, v);
@@ -1022,6 +1023,7 @@ public abstract class StackValue {
coerceFrom(topOfStackType, v);
if (setter == null) {
assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
assert backingFieldOwner != null : "Property should have either a setter or a backingFieldOwner: " + descriptor;
v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
}
else {
@@ -0,0 +1,3 @@
class JavaClass {
public String getOk() { return "OK"; }
}
@@ -0,0 +1,3 @@
fun box(): String {
return JavaClass().ok
}
@@ -0,0 +1,11 @@
class JavaClass {
private String myX;
public String getX() {
return myX;
}
public void setX(String x) {
myX = x;
}
}
@@ -0,0 +1,8 @@
fun box(): String {
return JavaClass().doIt()
}
fun JavaClass.doIt(): String {
x = "OK"
return x
}
@@ -0,0 +1,11 @@
class JavaClass {
private int myX = 0;
public int getX() {
return myX;
}
public void setX(int x) {
myX = x;
}
}
@@ -0,0 +1,5 @@
fun box(): String {
val javaClass = JavaClass()
javaClass.x++
return if (javaClass.x == 1) "OK" else "ERROR"
}
@@ -0,0 +1,11 @@
class JavaClass {
private String myX;
public String getX() {
return myX;
}
public void setX(String x) {
myX = x;
}
}
@@ -0,0 +1,5 @@
fun box(): String {
val javaClass = JavaClass()
javaClass.x = "OK"
return javaClass.x
}
@@ -827,6 +827,39 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SyntheticExtensions extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInSyntheticExtensions() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/syntheticExtensions"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("getter.kt")
public void testGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions/getter.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("implicitReceiver.kt")
public void testImplicitReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions/implicitReceiver.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("plusPlus.kt")
public void testPlusPlus() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions/plusPlus.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("setter.kt")
public void testSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions/setter.kt");
doTestAgainstJava(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/visibility")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)