From 2c84389a451516e7ee6e60fd4f6d34df065803c5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 28 Aug 2012 21:53:01 +0400 Subject: [PATCH] Codegen for "componentN" functions for data classes --- .../codegen/ImplementationBodyCodegen.java | 38 +++++++++ .../codegen/dataClasses/arrayParams.kt | 10 +++ .../codegen/dataClasses/changingVarParam.kt | 8 ++ .../codegen/dataClasses/genericParam.kt | 12 +++ .../codegen/dataClasses/mixedParams.kt | 8 ++ .../codegen/dataClasses/multiDeclaration.kt | 7 ++ .../dataClasses/multiDeclarationFor.kt | 17 ++++ .../codegen/dataClasses/overriddenProperty.kt | 11 +++ .../codegen/dataClasses/twoValParams.kt | 6 ++ .../codegen/dataClasses/twoVarParams.kt | 9 ++ .../codegen/dataClasses/unitComponent.kt | 6 ++ .../codegen/AbstractDataClassCodegenTest.java | 51 +++++++++++ .../DataClassCodegenTestGenerated.java | 85 +++++++++++++++++++ 13 files changed, 268 insertions(+) create mode 100644 compiler/testData/codegen/dataClasses/arrayParams.kt create mode 100644 compiler/testData/codegen/dataClasses/changingVarParam.kt create mode 100644 compiler/testData/codegen/dataClasses/genericParam.kt create mode 100644 compiler/testData/codegen/dataClasses/mixedParams.kt create mode 100644 compiler/testData/codegen/dataClasses/multiDeclaration.kt create mode 100644 compiler/testData/codegen/dataClasses/multiDeclarationFor.kt create mode 100644 compiler/testData/codegen/dataClasses/overriddenProperty.kt create mode 100644 compiler/testData/codegen/dataClasses/twoValParams.kt create mode 100644 compiler/testData/codegen/dataClasses/twoVarParams.kt create mode 100644 compiler/testData/codegen/dataClasses/unitComponent.kt create mode 100644 compiler/tests/org/jetbrains/jet/codegen/AbstractDataClassCodegenTest.java create mode 100644 compiler/tests/org/jetbrains/jet/codegen/DataClassCodegenTestGenerated.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index ce53c70e069..b8a13a5840f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -349,9 +349,47 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateEnumMethods(); + generateComponentFunctionsForDataClasses(); + generateClosureFields(context.closure, v, state.getTypeMapper()); } + private void generateComponentFunctionsForDataClasses() { + if (!myClass.hasPrimaryConstructor() || !JetStandardLibrary.isData(descriptor)) return; + + ConstructorDescriptor constructor = descriptor.getConstructors().iterator().next(); + + for (ValueParameterDescriptor parameter : constructor.getValueParameters()) { + FunctionDescriptor function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter); + if (function != null) { + generateComponentFunction(function, parameter); + } + } + } + + private void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull ValueParameterDescriptor parameter) { + JetType returnType = function.getReturnType(); + assert returnType != null : "Return type of component function should not be null: " + function; + Type componentType = typeMapper.mapReturnType(returnType); + + MethodVisitor mv = v.newMethod(myClass, + ACC_FINAL | getVisibilityAccessFlag(function), + function.getName().getName(), + "()" + componentType.getDescriptor(), + null, null); + + mv.visitCode(); + InstructionAdapter iv = new InstructionAdapter(mv); + if (!componentType.equals(Type.VOID_TYPE)) { + Type classType = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL); + iv.load(0, classType); + iv.getfield(classType.getInternalName(), parameter.getName().getName(), componentType.getDescriptor()); + } + iv.areturn(componentType); + + FunctionCodegen.endVisit(mv, function.getName().getName(), myClass); + } + private void generateEnumMethods() { if (myEnumConstants.size() > 0) { { diff --git a/compiler/testData/codegen/dataClasses/arrayParams.kt b/compiler/testData/codegen/dataClasses/arrayParams.kt new file mode 100644 index 00000000000..3c55fb1a0dd --- /dev/null +++ b/compiler/testData/codegen/dataClasses/arrayParams.kt @@ -0,0 +1,10 @@ +data class A(val x: Array, val y: IntArray) + +fun foo(x: Array, y: IntArray) = A(x, y) + +fun box(): String { + val a = Array(0, {0}) + val b = IntArray(0) + val (x, y) = foo(a, b) + return if (a == x && b == y) "OK" else "Fail" +} diff --git a/compiler/testData/codegen/dataClasses/changingVarParam.kt b/compiler/testData/codegen/dataClasses/changingVarParam.kt new file mode 100644 index 00000000000..56f9c63561f --- /dev/null +++ b/compiler/testData/codegen/dataClasses/changingVarParam.kt @@ -0,0 +1,8 @@ +data class A(var string: String) + +fun box(): String { + val a = A("Fail") + a.string = "OK" + val (result) = a + return result +} diff --git a/compiler/testData/codegen/dataClasses/genericParam.kt b/compiler/testData/codegen/dataClasses/genericParam.kt new file mode 100644 index 00000000000..5bf58f528f7 --- /dev/null +++ b/compiler/testData/codegen/dataClasses/genericParam.kt @@ -0,0 +1,12 @@ +data class A(val x: T) + +fun box(): String { + val a = A(42) + if (a.component1() != 42) return "Fail a: ${a.component1()}" + + val b = A(239.toLong()) + if (b.component1() != 239.toLong()) return "Fail b: ${b.component1()}" + + val c = A("OK") + return c.component1() +} diff --git a/compiler/testData/codegen/dataClasses/mixedParams.kt b/compiler/testData/codegen/dataClasses/mixedParams.kt new file mode 100644 index 00000000000..ea3e99a6ffb --- /dev/null +++ b/compiler/testData/codegen/dataClasses/mixedParams.kt @@ -0,0 +1,8 @@ +data class A(var x: Int, y: Int, val z: Int) + +fun box(): String { + val a = A(1, 2, 3) + if (a.component1() != 1) return "Fail: ${a.component1()}" + if (a.component2() != 3) return "Fail: ${a.component2()}" + return "OK" +} diff --git a/compiler/testData/codegen/dataClasses/multiDeclaration.kt b/compiler/testData/codegen/dataClasses/multiDeclaration.kt new file mode 100644 index 00000000000..c74ea42a4a3 --- /dev/null +++ b/compiler/testData/codegen/dataClasses/multiDeclaration.kt @@ -0,0 +1,7 @@ +data class A(val x: Int, val y: Any?, val z: String) + +fun box(): String { + val a = A(42, null, "OK") + val (x, y, z) = a + return if (x == 42 && y == null) z else "Fail" +} diff --git a/compiler/testData/codegen/dataClasses/multiDeclarationFor.kt b/compiler/testData/codegen/dataClasses/multiDeclarationFor.kt new file mode 100644 index 00000000000..b7756b0c036 --- /dev/null +++ b/compiler/testData/codegen/dataClasses/multiDeclarationFor.kt @@ -0,0 +1,17 @@ +data class A(val x: Int, val y: String) + +fun box(): String { + val arr = Array(5) { + i -> A(i, i.toString()) + } + + var sum = 0 + var str = "" + + for ((x, y) in arr) { + sum += x + str += y + } + + return if (sum == 0+1+2+3+4 && str == "01234") "OK" else "Fail ${sum} ${str}" +} diff --git a/compiler/testData/codegen/dataClasses/overriddenProperty.kt b/compiler/testData/codegen/dataClasses/overriddenProperty.kt new file mode 100644 index 00000000000..113a2b176c1 --- /dev/null +++ b/compiler/testData/codegen/dataClasses/overriddenProperty.kt @@ -0,0 +1,11 @@ +open data class A(open val x: String) + +class B : A("OK") { + override val x: String = "Fail" +} + +fun foo(a: A) = a.component1() + +fun box(): String { + return foo(B()) +} diff --git a/compiler/testData/codegen/dataClasses/twoValParams.kt b/compiler/testData/codegen/dataClasses/twoValParams.kt new file mode 100644 index 00000000000..91b918b1a8c --- /dev/null +++ b/compiler/testData/codegen/dataClasses/twoValParams.kt @@ -0,0 +1,6 @@ +data class A(val x: Int, val y: String) + +fun box(): String { + val a = A(42, "OK") + return if (a.component1() == 42) a.component2() else a.component1().toString() +} diff --git a/compiler/testData/codegen/dataClasses/twoVarParams.kt b/compiler/testData/codegen/dataClasses/twoVarParams.kt new file mode 100644 index 00000000000..053cfe55892 --- /dev/null +++ b/compiler/testData/codegen/dataClasses/twoVarParams.kt @@ -0,0 +1,9 @@ +data class A(var x: Int, var y: String) + +fun box(): String { + val a = A(21, "K") + if (a.component1() != 21 || a.component2() != "K") return "Fail" + a.x *= 2 + a.y = "O" + a.component2() + return if (a.component1() == 42) a.component2() else a.component1().toString() +} diff --git a/compiler/testData/codegen/dataClasses/unitComponent.kt b/compiler/testData/codegen/dataClasses/unitComponent.kt new file mode 100644 index 00000000000..49046f4240e --- /dev/null +++ b/compiler/testData/codegen/dataClasses/unitComponent.kt @@ -0,0 +1,6 @@ +data class A(val x: Unit) + +fun box(): String { + val a = A(#()) + return if (a.component1() is Unit) "OK" else "Fail ${a.component1()}" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/AbstractDataClassCodegenTest.java b/compiler/tests/org/jetbrains/jet/codegen/AbstractDataClassCodegenTest.java new file mode 100644 index 00000000000..a3c7448ac8c --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/AbstractDataClassCodegenTest.java @@ -0,0 +1,51 @@ +/* + * 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; + +import org.jetbrains.jet.ConfigurationKind; +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; + +/** + * @author udalov + */ +public abstract class AbstractDataClassCodegenTest extends CodegenTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + } + + public static void main(String[] args) throws IOException { + Class thisClass = AbstractDataClassCodegenTest.class; + String aPackage = thisClass.getPackage().getName(); + new TestGenerator( + "compiler/tests/", + aPackage, + "DataClassCodegenTestGenerated", + thisClass, + Arrays.asList( + new SimpleTestClassModel(new File("compiler/testData/codegen/dataClasses"), true, "kt", "blackBoxFileByFullPath") + ), + thisClass + ).generateAndSave(); + } +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/DataClassCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/DataClassCodegenTestGenerated.java new file mode 100644 index 00000000000..cc710df6e8e --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/DataClassCodegenTestGenerated.java @@ -0,0 +1,85 @@ +/* + * 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; + +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.TestMetadata; + +import org.jetbrains.jet.codegen.AbstractDataClassCodegenTest; + +/** This class is generated by {@link org.jetbrains.jet.codegen.AbstractDataClassCodegenTest}. DO NOT MODIFY MANUALLY */ +@TestMetadata("compiler/testData/codegen/dataClasses") +public class DataClassCodegenTestGenerated extends AbstractDataClassCodegenTest { + public void testAllFilesPresentInDataClasses() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.codegen.AbstractDataClassCodegenTest", new File("compiler/testData/codegen/dataClasses"), "kt", false); + } + + @TestMetadata("arrayParams.kt") + public void testArrayParams() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/arrayParams.kt"); + } + + @TestMetadata("changingVarParam.kt") + public void testChangingVarParam() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/changingVarParam.kt"); + } + + @TestMetadata("genericParam.kt") + public void testGenericParam() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/genericParam.kt"); + } + + @TestMetadata("mixedParams.kt") + public void testMixedParams() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/mixedParams.kt"); + } + + @TestMetadata("multiDeclaration.kt") + public void testMultiDeclaration() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/multiDeclaration.kt"); + } + + @TestMetadata("multiDeclarationFor.kt") + public void testMultiDeclarationFor() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/multiDeclarationFor.kt"); + } + + @TestMetadata("overriddenProperty.kt") + public void testOverriddenProperty() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/overriddenProperty.kt"); + } + + @TestMetadata("twoValParams.kt") + public void testTwoValParams() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/twoValParams.kt"); + } + + @TestMetadata("twoVarParams.kt") + public void testTwoVarParams() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/twoVarParams.kt"); + } + + @TestMetadata("unitComponent.kt") + public void testUnitComponent() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/dataClasses/unitComponent.kt"); + } + +}