From af998101b3dab2be812854c2a36fde6c39d6e616 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Mon, 10 Nov 2014 14:05:38 +0300 Subject: [PATCH] Fix for KT-4206: NoSuchFieldError with class objects #KT-4206 Fixed --- .../jet/codegen/ExpressionCodegen.java | 23 +++++++------------ .../org/jetbrains/jet/codegen/StackValue.java | 17 +++++++------- .../classObjectAnonymousInitializer.kt | 13 +++++++++++ .../BlackBoxCodegenTestGenerated.java | 6 +++++ 4 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 compiler/testData/codegen/box/staticFields/classObjectAnonymousInitializer.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 507f18818ca..bf1872bc10d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1956,7 +1956,7 @@ public class ExpressionCodegen extends JetVisitor implem DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor); - boolean isStatic = DescriptorUtils.isStaticDeclaration(propertyDescriptor); + boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) || isBackingFieldInAnotherClass; boolean isSuper = superExpression != null; boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; @@ -1969,16 +1969,17 @@ public class ExpressionCodegen extends JetVisitor implem boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass; CodegenContext backingFieldContext = context.getParentContext(); + boolean changeOwnerOnTypeMap = isBackingFieldInAnotherClass; if (isBackingFieldInAnotherClass && forceField) { - //delegate call to classObject owner : OWNER + //delegate call to classObject backingFieldOwner : OWNER backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration()); int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty); skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER; if (!skipPropertyAccessors) { propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType); + changeOwnerOnTypeMap = changeOwnerOnTypeMap && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass); } - isStatic = true; } if (!skipPropertyAccessors) { @@ -2016,17 +2017,9 @@ public class ExpressionCodegen extends JetVisitor implem } } - Type owner; - CallableMethod callableMethod = callableGetter != null ? callableGetter : callableSetter; - propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor); - if (callableMethod == null) { - owner = typeMapper.mapOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, - isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory())); - } - else { - owner = callableMethod.getOwner(); - } + Type backingFieldOwner = typeMapper.mapOwner(changeOwnerOnTypeMap ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, + isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory())); String fieldName; if (isExtensionProperty && !isDelegatedProperty) { @@ -2041,9 +2034,9 @@ public class ExpressionCodegen extends JetVisitor implem fieldName = JvmAbi.getDefaultFieldNameForProperty(propertyDescriptor.getName(), isDelegatedProperty); } - return StackValue.property(propertyDescriptor, owner, + return StackValue.property(propertyDescriptor, backingFieldOwner, typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()), - isStatic, fieldName, callableGetter, callableSetter, state, receiver); + isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index f6aec9f772b..2759d474030 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -18,7 +18,6 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.tree.IElementType; import kotlin.Function1; -import kotlin.Function2; import kotlin.Unit; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -199,16 +198,16 @@ public abstract class StackValue implements StackValueI { @NotNull public static Property property( @NotNull PropertyDescriptor descriptor, - @NotNull Type methodOwner, + @NotNull Type backingFieldOwner, @NotNull Type type, - boolean isStatic, + boolean isStaticBackingField, @Nullable String fieldName, @Nullable CallableMethod getter, @Nullable CallableMethod setter, GenerationState state, @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 @@ -1028,7 +1027,7 @@ public abstract class StackValue implements StackValueI { static class Property extends StackValueWithSimpleReceiver { private final CallableMethod getter; private final CallableMethod setter; - private final Type methodOwner; + private final Type backingFieldOwner; private final PropertyDescriptor descriptor; private final GenerationState state; @@ -1036,13 +1035,13 @@ public abstract class StackValue implements StackValueI { private final String fieldName; public Property( - @NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner, + @NotNull PropertyDescriptor descriptor, @NotNull Type backingFieldOwner, @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField, @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state, @NotNull StackValue receiver ) { super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver); - this.methodOwner = methodOwner; + this.backingFieldOwner = backingFieldOwner; this.getter = getter; this.setter = setter; this.descriptor = descriptor; @@ -1054,7 +1053,7 @@ public abstract class StackValue implements StackValueI { public void putNoReceiver(@NotNull Type type, @NotNull InstructionAdapter v) { if (getter == null) { 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); coerceTo(type, v); } @@ -1069,7 +1068,7 @@ public abstract class StackValue implements StackValueI { coerceFrom(topOfStackType, v); if (setter == null) { 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 { setter.invokeWithoutAssertions(v); diff --git a/compiler/testData/codegen/box/staticFields/classObjectAnonymousInitializer.kt b/compiler/testData/codegen/box/staticFields/classObjectAnonymousInitializer.kt new file mode 100644 index 00000000000..39951a9e226 --- /dev/null +++ b/compiler/testData/codegen/box/staticFields/classObjectAnonymousInitializer.kt @@ -0,0 +1,13 @@ +class Foo { + class object { + val bar: String + + { + bar = "OK" + } + } +} + +fun box(): String { + return Foo.bar +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 21ae10a8988..464bbc105f7 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -6173,6 +6173,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { 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") public void testClassObjectInc() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/staticFields/classObjectInc.kt");