Fix for KT-4206: NoSuchFieldError with class objects

#KT-4206 Fixed
This commit is contained in:
Michael Bogdanov
2014-11-10 14:05:38 +03:00
parent 7d1fd47569
commit af998101b3
4 changed files with 35 additions and 24 deletions
@@ -1956,7 +1956,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor); boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
boolean isStatic = DescriptorUtils.isStaticDeclaration(propertyDescriptor); boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) || isBackingFieldInAnotherClass;
boolean isSuper = superExpression != null; boolean isSuper = superExpression != null;
boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
@@ -1969,16 +1969,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass; boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass;
CodegenContext backingFieldContext = context.getParentContext(); CodegenContext backingFieldContext = context.getParentContext();
boolean changeOwnerOnTypeMap = isBackingFieldInAnotherClass;
if (isBackingFieldInAnotherClass && forceField) { if (isBackingFieldInAnotherClass && forceField) {
//delegate call to classObject owner : OWNER //delegate call to classObject backingFieldOwner : OWNER
backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration()); backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty); 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) { if (!skipPropertyAccessors) {
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType); propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType);
changeOwnerOnTypeMap = changeOwnerOnTypeMap && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
} }
isStatic = true;
} }
if (!skipPropertyAccessors) { if (!skipPropertyAccessors) {
@@ -2016,17 +2017,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
} }
} }
Type owner;
CallableMethod callableMethod = callableGetter != null ? callableGetter : callableSetter;
propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor); propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
if (callableMethod == null) { Type backingFieldOwner = typeMapper.mapOwner(changeOwnerOnTypeMap ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
owner = typeMapper.mapOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory()));
isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory()));
}
else {
owner = callableMethod.getOwner();
}
String fieldName; String fieldName;
if (isExtensionProperty && !isDelegatedProperty) { if (isExtensionProperty && !isDelegatedProperty) {
@@ -2041,9 +2034,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
fieldName = JvmAbi.getDefaultFieldNameForProperty(propertyDescriptor.getName(), isDelegatedProperty); fieldName = JvmAbi.getDefaultFieldNameForProperty(propertyDescriptor.getName(), isDelegatedProperty);
} }
return StackValue.property(propertyDescriptor, owner, return StackValue.property(propertyDescriptor, backingFieldOwner,
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()), typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
isStatic, fieldName, callableGetter, callableSetter, state, receiver); isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver);
} }
@@ -18,7 +18,6 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import kotlin.Function1; import kotlin.Function1;
import kotlin.Function2;
import kotlin.Unit; import kotlin.Unit;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -199,16 +198,16 @@ public abstract class StackValue implements StackValueI {
@NotNull @NotNull
public static Property property( public static Property property(
@NotNull PropertyDescriptor descriptor, @NotNull PropertyDescriptor descriptor,
@NotNull Type methodOwner, @NotNull Type backingFieldOwner,
@NotNull Type type, @NotNull Type type,
boolean isStatic, boolean isStaticBackingField,
@Nullable String fieldName, @Nullable String fieldName,
@Nullable CallableMethod getter, @Nullable CallableMethod getter,
@Nullable CallableMethod setter, @Nullable CallableMethod setter,
GenerationState state, GenerationState state,
@NotNull StackValue receiver @NotNull StackValue receiver
) { ) {
return new Property(descriptor, methodOwner, getter, setter, isStatic, fieldName, type, state, receiver); return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, state, receiver);
} }
@NotNull @NotNull
@@ -1028,7 +1027,7 @@ public abstract class StackValue implements StackValueI {
static class Property extends StackValueWithSimpleReceiver { static class Property extends StackValueWithSimpleReceiver {
private final CallableMethod getter; private final CallableMethod getter;
private final CallableMethod setter; private final CallableMethod setter;
private final Type methodOwner; private final Type backingFieldOwner;
private final PropertyDescriptor descriptor; private final PropertyDescriptor descriptor;
private final GenerationState state; private final GenerationState state;
@@ -1036,13 +1035,13 @@ public abstract class StackValue implements StackValueI {
private final String fieldName; private final String fieldName;
public Property( public Property(
@NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner, @NotNull PropertyDescriptor descriptor, @NotNull Type backingFieldOwner,
@Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField, @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
@Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state, @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state,
@NotNull StackValue receiver @NotNull StackValue receiver
) { ) {
super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver); super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver);
this.methodOwner = methodOwner; this.backingFieldOwner = backingFieldOwner;
this.getter = getter; this.getter = getter;
this.setter = setter; this.setter = setter;
this.descriptor = descriptor; this.descriptor = descriptor;
@@ -1054,7 +1053,7 @@ public abstract class StackValue implements StackValueI {
public void putNoReceiver(@NotNull Type type, @NotNull InstructionAdapter v) { public void putNoReceiver(@NotNull Type type, @NotNull InstructionAdapter v) {
if (getter == null) { if (getter == null) {
assert fieldName != null : "Property should have either a getter or a field name: " + descriptor; assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor()); v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
genNotNullAssertionForField(v, state, descriptor); genNotNullAssertionForField(v, state, descriptor);
coerceTo(type, v); coerceTo(type, v);
} }
@@ -1069,7 +1068,7 @@ public abstract class StackValue implements StackValueI {
coerceFrom(topOfStackType, v); coerceFrom(topOfStackType, v);
if (setter == null) { if (setter == null) {
assert fieldName != null : "Property should have either a setter or a field name: " + descriptor; assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor()); v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
} }
else { else {
setter.invokeWithoutAssertions(v); setter.invokeWithoutAssertions(v);
@@ -0,0 +1,13 @@
class Foo {
class object {
val bar: String
{
bar = "OK"
}
}
}
fun box(): String {
return Foo.bar
}
@@ -6173,6 +6173,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/staticFields"), Pattern.compile("^(.+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/staticFields"), Pattern.compile("^(.+)\\.kt$"), true);
} }
@TestMetadata("classObjectAnonymousInitializer.kt")
public void testClassObjectAnonymousInitializer() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/staticFields/classObjectAnonymousInitializer.kt");
doTest(fileName);
}
@TestMetadata("classObjectInc.kt") @TestMetadata("classObjectInc.kt")
public void testClassObjectInc() throws Exception { public void testClassObjectInc() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/staticFields/classObjectInc.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/staticFields/classObjectInc.kt");