From 94fbf2bdf48e92e4147e78ff0da083562d089800 Mon Sep 17 00:00:00 2001 From: "Natalia.Ukhorskaya" Date: Fri, 9 Nov 2012 11:52:17 +0400 Subject: [PATCH] Add labels for extension properties #KT-2824 Fixed --- .../jet/codegen/context/LocalLookup.java | 4 +- .../jet/lang/resolve/BodyResolver.java | 5 +- .../jet/lang/resolve/DescriptorResolver.java | 34 ++++++++++- .../lang/types/expressions/LabelResolver.java | 9 +-- .../codegen/label/propertyAccessor.kt | 29 +++++++++ .../label/propertyAccessorFunctionLiteral.kt | 23 +++++++ .../propertyAccessorInnerExtensionFun.kt | 27 ++++++++ .../codegen/label/propertyAccessorObject.kt | 53 ++++++++++++++++ .../codegen/label/propertyInClassAccessor.kt | 17 ++++++ .../thisAndSuper/thisInPropertyInitializer.kt | 8 +++ .../labels/labelForPropertyInGetter.jet | 47 ++++++++++++++ .../labels/labelForPropertyInSetter.jet | 32 ++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++ .../codegen/labels/AbstractLabelGenTest.java | 58 ++++++++++++++++++ .../codegen/labels/LabelGenTestGenerated.java | 61 +++++++++++++++++++ 15 files changed, 401 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/label/propertyAccessor.kt create mode 100644 compiler/testData/codegen/label/propertyAccessorFunctionLiteral.kt create mode 100644 compiler/testData/codegen/label/propertyAccessorInnerExtensionFun.kt create mode 100644 compiler/testData/codegen/label/propertyAccessorObject.kt create mode 100644 compiler/testData/codegen/label/propertyInClassAccessor.kt create mode 100644 compiler/testData/diagnostics/tests/thisAndSuper/thisInPropertyInitializer.kt create mode 100644 compiler/testData/resolve/labels/labelForPropertyInGetter.jet create mode 100644 compiler/testData/resolve/labels/labelForPropertyInSetter.jet create mode 100644 compiler/tests/org/jetbrains/jet/codegen/labels/AbstractLabelGenTest.java create mode 100644 compiler/tests/org/jetbrains/jet/codegen/labels/LabelGenTestGenerated.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java index bcef4eda60e..fe4f7d33d90 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java @@ -108,7 +108,7 @@ public interface LocalLookup { RECEIVER { @Override public boolean isCase(DeclarationDescriptor d, GenerationState state) { - return d instanceof FunctionDescriptor; + return d instanceof CallableDescriptor; } @Override @@ -130,7 +130,7 @@ public interface LocalLookup { @Override public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) { - CallableDescriptor descriptor = (FunctionDescriptor) d.getDescriptor(); + CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor(); return StackValue.local(descriptor.getExpectedThisObject() != null ? 1 : 0, d.getType()); } }; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 4bff98b2c57..861506c64a0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -434,7 +434,7 @@ public class BodyResolver { JetScope declaringScope = context.getDeclaringScopes().apply(accessor); JetScope propertyDeclarationInnerScope = descriptorResolver.getPropertyDeclarationInnerScope( - declaringScope, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter(), trace); + propertyDescriptor, declaringScope, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter(), trace); WritableScope accessorScope = new WritableScopeImpl( propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(trace), "Accessor scope"); accessorScope.changeLockLevel(WritableScope.LockLevel.READING); @@ -479,7 +479,8 @@ public class BodyResolver { public void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { JetType expectedTypeForInitializer = property.getTypeRef() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE; - JetScope propertyDeclarationInnerScope = descriptorResolver.getPropertyDeclarationInnerScope(scope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace); + JetScope propertyDeclarationInnerScope = descriptorResolver.getPropertyDeclarationInnerScopeForInitializer( + scope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace); expressionTypingServices.getType(propertyDeclarationInnerScope, initializer, expectedTypeForInitializer, DataFlowInfo.EMPTY, trace); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index ad943edd9a9..4fe2f96db36 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -839,12 +839,39 @@ public class DescriptorResolver { } public JetScope getPropertyDeclarationInnerScope( - @NotNull JetScope outerScope, @NotNull List typeParameters, - @Nullable ReceiverParameterDescriptor receiver, BindingTrace trace + @NotNull PropertyDescriptor propertyDescriptor, + @NotNull JetScope outerScope, + @NotNull List typeParameters, + @Nullable ReceiverParameterDescriptor receiver, + BindingTrace trace + ) { + return getPropertyDeclarationInnerScope(propertyDescriptor, outerScope, typeParameters, receiver, trace, true); + } + + public JetScope getPropertyDeclarationInnerScopeForInitializer( + @NotNull JetScope outerScope, + @NotNull List typeParameters, + @Nullable ReceiverParameterDescriptor receiver, + BindingTrace trace + ) { + return getPropertyDeclarationInnerScope(null, outerScope, typeParameters, receiver, trace, false); + } + + private JetScope getPropertyDeclarationInnerScope( + @Nullable PropertyDescriptor propertyDescriptor, // PropertyDescriptor can be null for property scope which hasn't label to property (in this case addLabelForProperty parameter must be false + @NotNull JetScope outerScope, + @NotNull List typeParameters, + @Nullable ReceiverParameterDescriptor receiver, + BindingTrace trace, + boolean addLabelForProperty ) { WritableScopeImpl result = new WritableScopeImpl( outerScope, outerScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(trace), "Property declaration inner scope"); + if (addLabelForProperty) { + assert propertyDescriptor != null : "PropertyDescriptor can be null for property scope which hasn't label to property"; + result.addLabeledDeclaration(propertyDescriptor); + } for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { result.addTypeParameterDescriptor(typeParameterDescriptor); } @@ -909,7 +936,8 @@ public class DescriptorResolver { ReceiverParameterDescriptor receiverDescriptor = resolveReceiverParameterFor(propertyDescriptor, receiverType); - JetScope propertyScope = getPropertyDeclarationInnerScope(scope, typeParameterDescriptors, NO_RECEIVER_PARAMETER, trace); + JetScope propertyScope = getPropertyDeclarationInnerScope(propertyDescriptor, scope, typeParameterDescriptors, + NO_RECEIVER_PARAMETER, trace); JetType type = getVariableType(propertyScope, property, DataFlowInfo.EMPTY, true, trace); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java index 8b290f24eee..4b76ae933fb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/LabelResolver.java @@ -19,10 +19,7 @@ package org.jetbrains.jet.lang.types.expressions; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; @@ -140,6 +137,10 @@ public class LabelResolver { FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; thisReceiver = functionDescriptor.getReceiverParameter(); } + else if (declarationDescriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) declarationDescriptor; + thisReceiver = propertyDescriptor.getReceiverParameter(); + } else { throw new UnsupportedOperationException("Unsupported descriptor: " + declarationDescriptor); // TODO } diff --git a/compiler/testData/codegen/label/propertyAccessor.kt b/compiler/testData/codegen/label/propertyAccessor.kt new file mode 100644 index 00000000000..1a8ddf5004b --- /dev/null +++ b/compiler/testData/codegen/label/propertyAccessor.kt @@ -0,0 +1,29 @@ +val Int.getter: Int + get() { + return this@getter + } + +var Int.setter1: Int = 2 + get() { + return this@setter1 + } + set(i: Int) { + $setter1 = this@setter1 + } + +var Int.setter2: Int = 2 + set(i: Int) { + $setter2 = this@setter2 + } + +fun box(): String { + val i = 1 + if (i.getter != 1) return "getter failed" + + i.setter1 = 2 + if (i.setter1 != 1) return "setter1 failed" + i.setter2 = 2 + if (i.setter2 != 1) return "setter2 failed" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/label/propertyAccessorFunctionLiteral.kt b/compiler/testData/codegen/label/propertyAccessorFunctionLiteral.kt new file mode 100644 index 00000000000..0668187e12a --- /dev/null +++ b/compiler/testData/codegen/label/propertyAccessorFunctionLiteral.kt @@ -0,0 +1,23 @@ +val Int.getter: Int + get() { + return { + this@getter + }.invoke() + } + +var Int.setter: Int = 1 + set(i: Int) { + $setter = { + this@setter + }.invoke() + } + +fun box(): String { + val i = 1 + if (i.getter != 1) return "getter failed" + + i.setter = 2 + if (i.setter != 1) return "setter failed" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/label/propertyAccessorInnerExtensionFun.kt b/compiler/testData/codegen/label/propertyAccessorInnerExtensionFun.kt new file mode 100644 index 00000000000..90353e8af08 --- /dev/null +++ b/compiler/testData/codegen/label/propertyAccessorInnerExtensionFun.kt @@ -0,0 +1,27 @@ +val Int.getter: Int + get() { + val extFun = { Int.() -> + this@getter + } + return this@getter.extFun() + } + + +var Int.setter: Int = 1 + set(i: Int) { + val extFun = { Int.() -> + this@setter + } + this@setter.extFun() + } + + +fun box(): String { + val i = 1 + if (i.getter != 1) return "getter failed" + + i.setter = 1 + if (i.setter != 1) return "setter failed" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/label/propertyAccessorObject.kt b/compiler/testData/codegen/label/propertyAccessorObject.kt new file mode 100644 index 00000000000..633b69957be --- /dev/null +++ b/compiler/testData/codegen/label/propertyAccessorObject.kt @@ -0,0 +1,53 @@ +trait Base { + fun foo(): Int +} + +val Int.getter: Int + get() { + return object: Base { + override fun foo(): Int { + return this@getter + } + }.foo() + } + +var Int.setter1: Int = 2 + set(i: Int) { + $setter1 = object: Base { + override fun foo(): Int { + this@setter1 + return 1 + } + }.foo() + } + + +var Int.setter2: Int = 2 + get() { + return object: Base { + override fun foo(): Int { + return this@setter2 + } + }.foo() + } + set(i: Int) { + $setter2 = object: Base { + override fun foo(): Int { + this@setter2 + return 1 + } + }.foo() + } + + +fun box(): String { + val i = 1 + if (i.getter != 1) return "getter failed" + + i.setter1 = 2 + if (i.setter1 != 1) return "setter1 failed" + i.setter2 = 2 + if (i.setter2 != 1) return "setter2 failed" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/label/propertyInClassAccessor.kt b/compiler/testData/codegen/label/propertyInClassAccessor.kt new file mode 100644 index 00000000000..21cfd6428d9 --- /dev/null +++ b/compiler/testData/codegen/label/propertyInClassAccessor.kt @@ -0,0 +1,17 @@ +class Test { + val Int.innerGetter: Int + get() { + return this@innerGetter + } + + fun test(): Int { + val i = 1 + if (i.innerGetter != 1) return 0 + return 1 + } +} + +fun box(): String { + if (Test().test() != 1) return "inner getter or setter failed" + return "OK" +} diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/thisInPropertyInitializer.kt b/compiler/testData/diagnostics/tests/thisAndSuper/thisInPropertyInitializer.kt new file mode 100644 index 00000000000..7d493932b4c --- /dev/null +++ b/compiler/testData/diagnostics/tests/thisAndSuper/thisInPropertyInitializer.kt @@ -0,0 +1,8 @@ +trait Base { + fun foo() +} +val String.test: Base = object: Base { + override fun foo() { + this@test + } +} \ No newline at end of file diff --git a/compiler/testData/resolve/labels/labelForPropertyInGetter.jet b/compiler/testData/resolve/labels/labelForPropertyInGetter.jet new file mode 100644 index 00000000000..3dcae60460c --- /dev/null +++ b/compiler/testData/resolve/labels/labelForPropertyInGetter.jet @@ -0,0 +1,47 @@ +trait Base { + fun foo() +} + +val ~getter1~Int.getter1: Int + get() { + return `getter1`this@getter1 + } + +val ~getter2~Int.getter2: Base + get() { + return object: Base { + override fun foo() { + `getter2`this@getter2 + } + } + } + +val ~getter3~Int.getter3: Base + get() = object: Base { + override fun foo() { + `getter3`this@getter3 + } + } + +val ~getter4~Int.getter4: Int + get() { + return { + `getter4`this@getter4 + }.invoke() + } + +val ~getter5~Int.getter5: Int + get() { + val extFun = { Int.() -> + `getter5`this@getter5 + } + return `getter5`this@getter5.extFun() + } + + +class Test { + val ~innerGetter1~Int.innerGetter1: Int + get() { + return `innerGetter1`this@innerGetter1 + } +} \ No newline at end of file diff --git a/compiler/testData/resolve/labels/labelForPropertyInSetter.jet b/compiler/testData/resolve/labels/labelForPropertyInSetter.jet new file mode 100644 index 00000000000..c9d22a39e8a --- /dev/null +++ b/compiler/testData/resolve/labels/labelForPropertyInSetter.jet @@ -0,0 +1,32 @@ +trait Base { + fun foo() +} + +var ~setter1~Int.setter1: Int = 2 + set(i: Int) { + $setter1 = `setter1`this@setter1 + } + +var ~setter2~Int.setter2: Base? = null + set(i: Base?) { + $setter2 = object: Base { + override fun foo() { + `setter2`this@setter2 + } + } + } + +var ~setter3~Int.setter3: Int = 1 + set(i: Int) { + { + `setter3`this@setter3 + }.invoke() + } + +var ~setter4~Int.setter4: Int = 1 + set(i: Int) { + val extFun = { Int.() -> + `setter4`this@setter4 + } + `setter4`this@setter4.extFun() + } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index e32c19c88a0..28b384569f6 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3570,6 +3570,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/thisAndSuper/thisInNestedClasses.kt"); } + @TestMetadata("thisInPropertyInitializer.kt") + public void testThisInPropertyInitializer() throws Exception { + doTest("compiler/testData/diagnostics/tests/thisAndSuper/thisInPropertyInitializer.kt"); + } + @TestMetadata("thisInToplevelFunction.kt") public void testThisInToplevelFunction() throws Exception { doTest("compiler/testData/diagnostics/tests/thisAndSuper/thisInToplevelFunction.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/labels/AbstractLabelGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/labels/AbstractLabelGenTest.java new file mode 100644 index 00000000000..560c5a54544 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/labels/AbstractLabelGenTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2012 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.labels; + +import org.jetbrains.jet.ConfigurationKind; +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; +import org.jetbrains.jet.codegen.CodegenTestCase; +import org.jetbrains.jet.test.generator.SimpleTestClassModel; +import org.jetbrains.jet.test.generator.TestGenerator; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +public abstract class AbstractLabelGenTest extends CodegenTestCase { + + private static final String REDUNDANT_PATH_PREFIX = "compiler/testData/codegen"; + + @Override + public void setUp() throws Exception { + super.setUp(); + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_AND_ANNOTATIONS); + } + + protected void doTest(String path) throws IOException { + String relativePath = path.substring(REDUNDANT_PATH_PREFIX.length()); + blackBoxFile(relativePath); + } + + public static void main(String[] args) throws IOException { + String aPackage = "org.jetbrains.jet.codegen.labels"; + Class thisClass = AbstractLabelGenTest.class; + new TestGenerator( + "compiler/tests/", + aPackage, + "LabelGenTestGenerated", + thisClass, + Arrays.asList( + new SimpleTestClassModel(new File("compiler/testData/codegen/label"), true, "kt", "doTest") + ), + thisClass + ).generateAndSave(); + } +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/labels/LabelGenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/labels/LabelGenTestGenerated.java new file mode 100644 index 00000000000..3898b02ec56 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/labels/LabelGenTestGenerated.java @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2012 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.labels; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.io.File; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.test.InnerTestClasses; +import org.jetbrains.jet.test.TestMetadata; + +import org.jetbrains.jet.codegen.labels.AbstractLabelGenTest; + +/** This class is generated by {@link org.jetbrains.jet.codegen.labels.AbstractLabelGenTest}. DO NOT MODIFY MANUALLY */ +@TestMetadata("compiler/testData/codegen/label") +public class LabelGenTestGenerated extends AbstractLabelGenTest { + public void testAllFilesPresentInLabel() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.codegen.labels.AbstractLabelGenTest", new File("compiler/testData/codegen/label"), "kt", true); + } + + @TestMetadata("propertyAccessor.kt") + public void testPropertyAccessor() throws Exception { + doTest("compiler/testData/codegen/label/propertyAccessor.kt"); + } + + @TestMetadata("propertyAccessorFunctionLiteral.kt") + public void testPropertyAccessorFunctionLiteral() throws Exception { + doTest("compiler/testData/codegen/label/propertyAccessorFunctionLiteral.kt"); + } + + @TestMetadata("propertyAccessorInnerExtensionFun.kt") + public void testPropertyAccessorInnerExtensionFun() throws Exception { + doTest("compiler/testData/codegen/label/propertyAccessorInnerExtensionFun.kt"); + } + + @TestMetadata("propertyAccessorObject.kt") + public void testPropertyAccessorObject() throws Exception { + doTest("compiler/testData/codegen/label/propertyAccessorObject.kt"); + } + + @TestMetadata("propertyInClassAccessor.kt") + public void testPropertyInClassAccessor() throws Exception { + doTest("compiler/testData/codegen/label/propertyInClassAccessor.kt"); + } + +}