diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyBackingFieldInOuterClass.java b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyBackingFieldInOuterClass.java new file mode 100644 index 00000000000..fe44fd86677 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyBackingFieldInOuterClass.java @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.types.JetType; + +public class AccessorForPropertyBackingFieldInOuterClass extends AccessorForPropertyDescriptor { + + public AccessorForPropertyBackingFieldInOuterClass( + @NotNull PropertyDescriptor pd, + @NotNull DeclarationDescriptor containingDeclaration, + int index, + @Nullable JetType delegationType + ) { + super(pd, delegationType != null ? delegationType : pd.getType(), null, null, containingDeclaration, index); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java index 35a9193ff75..a215d32a759 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AccessorForPropertyDescriptor.java @@ -16,6 +16,8 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.impl.PropertyDescriptorImpl; @@ -29,17 +31,23 @@ import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl { - public AccessorForPropertyDescriptor(PropertyDescriptor pd, DeclarationDescriptor containingDeclaration, int index) { + public AccessorForPropertyDescriptor(@NotNull PropertyDescriptor pd, @NotNull DeclarationDescriptor containingDeclaration, int index) { + this(pd, pd.getType(), DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter()), pd.getExpectedThisObject(), containingDeclaration, index); + } + + protected AccessorForPropertyDescriptor( + @NotNull PropertyDescriptor original, + @NotNull JetType propertyType, + @Nullable JetType receiverType, + @Nullable ReceiverParameterDescriptor expectedThisObject, + @NotNull DeclarationDescriptor containingDeclaration, + int index + ) { super(containingDeclaration, Collections.emptyList(), Modality.FINAL, Visibilities.LOCAL, - pd.isVar(), Name.identifier(pd.getName() + "$b$" + index), + original.isVar(), Name.identifier(original.getName() + "$b$" + index), Kind.DECLARATION); - boolean isStaticProperty = AsmUtil.isPropertyWithBackingFieldInOuterClass(pd) - && !AsmUtil.isClassObjectWithBackingFieldsInOuter(containingDeclaration); - JetType receiverType = !isStaticProperty ? DescriptorUtils.getReceiverParameterType(pd.getReceiverParameter()) : null; - - setType(pd.getType(), Collections.emptyList(), isStaticProperty ? null : pd.getExpectedThisObject(), - receiverType); + setType(propertyType, Collections.emptyList(), expectedThisObject, receiverType); initialize(new Getter(this), new Setter(this)); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 51b3ffac2d3..d41548bb0c5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1811,7 +1811,7 @@ public class ExpressionCodegen extends JetVisitor implem 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); + propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java index 34129231522..760bf3a7c9d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java @@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; import java.util.HashMap; @@ -247,21 +248,35 @@ public abstract class CodegenContext { return c; } - public DeclarationDescriptor getAccessor(DeclarationDescriptor descriptor) { + @NotNull + public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor) { + return getAccessor(descriptor, false, null); + } + + @NotNull + public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType) { if (accessors == null) { accessors = new HashMap(); } descriptor = descriptor.getOriginal(); DeclarationDescriptor accessor = accessors.get(descriptor); if (accessor != null) { + assert !isForBackingFieldInOuterClass || + accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context"; return accessor; } + int accessorIndex = accessors.size(); if (descriptor instanceof SimpleFunctionDescriptor || descriptor instanceof ConstructorDescriptor) { - accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessors.size()); + accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex); } else if (descriptor instanceof PropertyDescriptor) { - accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessors.size()); + if (isForBackingFieldInOuterClass) { + accessor = new AccessorForPropertyBackingFieldInOuterClass((PropertyDescriptor) descriptor, contextDescriptor, + accessorIndex, delegateType); + } else { + accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex); + } } else { throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor); diff --git a/compiler/testData/codegen/box/delegatedProperty/kt4138.kt b/compiler/testData/codegen/box/delegatedProperty/kt4138.kt new file mode 100644 index 00000000000..b3af82a8213 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/kt4138.kt @@ -0,0 +1,35 @@ +class Delegate(var inner: T) { + fun get(t: Any?, p: PropertyMetadata): T = inner + fun set(t: Any?, p: PropertyMetadata, i: T) { inner = i } +} + + +class Foo (val f: Int) { + class object { + val A: Foo by Delegate(Foo(11)) + var B: Foo by Delegate(Foo(11)) + } +} + +trait FooTrait { + class object { + val A: Foo by Delegate(Foo(11)) + var B: Foo by Delegate(Foo(11)) + } +} + +fun box() : String { + if (Foo.A.f != 11) return "fail 1" + if (Foo.B.f != 11) return "fail 2" + + Foo.B = Foo(12) + if (Foo.B.f != 12) return "fail 3" + + if (FooTrait.A.f != 11) return "fail 4" + if (FooTrait.B.f != 11) return "fail 5" + + FooTrait.B = Foo(12) + if (FooTrait.B.f != 12) return "fail 6" + + return "OK" +} \ 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 98b1a5c9212..7b066a985d0 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1877,6 +1877,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/delegatedProperty/inferredPropertyType.kt"); } + @TestMetadata("kt4138.kt") + public void testKt4138() throws Exception { + doTest("compiler/testData/codegen/box/delegatedProperty/kt4138.kt"); + } + @TestMetadata("privateVar.kt") public void testPrivateVar() throws Exception { doTest("compiler/testData/codegen/box/delegatedProperty/privateVar.kt");