diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 16a0bc3cd19..3c580c3c5ed 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -1600,30 +1600,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { JetTypeMapper typeMapper = state.getTypeMapper(); for (JetDeclaration declaration : declarations) { if (declaration instanceof JetProperty) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, declaration); - assert propertyDescriptor != null; - if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) { - JetExpression initializer = ((JetProperty) declaration).getInitializer(); - if (initializer != null) { - CompileTimeConstant compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer); - JetType jetType = propertyDescriptor.getType(); - if (compileTimeValue != null) { - Object value = compileTimeValue.getValue(); - Type type = typeMapper.mapType(jetType); - if (skipDefaultValue(propertyDescriptor, value, type)) continue; - } - iv.load(0, OBJECT_TYPE); - Type type = codegen.expressionType(initializer); - if (jetType.isNullable()) { - type = boxType(type); - } - codegen.gen(initializer, type); - // @todo write directly to the field. Fix test excloset.jet::test6 - JvmClassName owner = typeMapper.getOwner(propertyDescriptor, OwnerKind.IMPLEMENTATION, isCallInsideSameModuleAsDeclared(propertyDescriptor, codegen.context)); - Type propType = typeMapper.mapType(jetType); - StackValue.property(propertyDescriptor, owner, - propType, false, null, null, state).store(propType, iv); - } + if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) { + initializeProperty(codegen, bindingContext, iv, (JetProperty) declaration, false); } } else if (declaration instanceof JetClassInitializer) { @@ -1632,6 +1610,52 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + public static void initializeProperty( + @NotNull ExpressionCodegen codegen, + @NotNull BindingContext bindingContext, + @NotNull InstructionAdapter iv, + @NotNull JetProperty property, + boolean isStatic + ) { + if (!isStatic) { + iv.load(0, OBJECT_TYPE); + } + + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property); + assert propertyDescriptor != null; + + JetExpression initializer = property.getInitializer(); + assert initializer != null : "shouldInitializeProperty must return false if initializer is null"; + + JetType jetType = propertyDescriptor.getType(); + Type type = codegen.expressionType(initializer); + if (jetType.isNullable()) { + type = boxType(type); + } + codegen.gen(initializer, type); + + StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null); + propValue.store(propValue.type, iv); + } + + public static boolean shouldInitializeProperty( + @NotNull JetProperty property, + @NotNull JetTypeMapper typeMapper + ) { + JetExpression initializer = property.getInitializer(); + if (initializer == null) return false; + + CompileTimeConstant compileTimeValue = typeMapper.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer); + if (compileTimeValue == null) return true; + + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) typeMapper.getBindingContext().get(BindingContext.VARIABLE, property); + assert propertyDescriptor != null; + + Object value = compileTimeValue.getValue(); + Type type = typeMapper.mapType(propertyDescriptor.getType()); + return !skipDefaultValue(propertyDescriptor, value, type); + } + private static boolean skipDefaultValue(PropertyDescriptor propertyDescriptor, Object value, Type type) { if (isPrimitive(type)) { if (!propertyDescriptor.getType().isNullable() && value instanceof Number) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 0de2b2af293..7c3e2e34336 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.codegen; +import com.google.common.collect.Lists; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.io.FileUtil; @@ -26,7 +27,6 @@ import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; -import org.jetbrains.jet.codegen.binding.CodegenBinding; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; @@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.resolve.name.Name; import java.io.File; import java.util.Collection; +import java.util.List; import static org.jetbrains.asm4.Opcodes.*; @@ -160,9 +161,7 @@ public class NamespaceCodegen extends MemberCodegen { } } - if (hasNonConstantPropertyInitializers()) { - generateStaticInitializers(builder, file); - } + generateStaticInitializers(builder, file); builder.done(); } @@ -207,6 +206,9 @@ public class NamespaceCodegen extends MemberCodegen { } private void generateStaticInitializers(@NotNull ClassBuilder builder, @NotNull JetFile file) { + List properties = collectPropertiesToInitialize(file); + if (properties.isEmpty()) return; + MethodVisitor mv = builder.newMethod(file, ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { mv.visitCode(); @@ -214,18 +216,9 @@ public class NamespaceCodegen extends MemberCodegen { FrameMap frameMap = new FrameMap(); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state); - for (JetDeclaration declaration : file.getDeclarations()) { - if (declaration instanceof JetProperty) { - JetExpression initializer = ((JetProperty) declaration).getInitializer(); - if (initializer != null && !(initializer instanceof JetConstantExpression)) { - PropertyDescriptor descriptor = - (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration); - assert descriptor != null; - codegen.genToJVMStack(initializer); - StackValue.Property propValue = codegen.intermediateValueForProperty(descriptor, true, null); - propValue.store(propValue.type, new InstructionAdapter(mv)); - } - } + for (JetDeclaration declaration : properties) { + ImplementationBodyCodegen. + initializeProperty(codegen, state.getBindingContext(), new InstructionAdapter(mv), (JetProperty) declaration, true); } mv.visitInsn(RETURN); @@ -234,18 +227,16 @@ public class NamespaceCodegen extends MemberCodegen { } } - private boolean hasNonConstantPropertyInitializers() { - for (JetFile file : files) { - for (JetDeclaration declaration : file.getDeclarations()) { - if (declaration instanceof JetProperty) { - JetExpression initializer = ((JetProperty) declaration).getInitializer(); - if (initializer != null && !(initializer instanceof JetConstantExpression)) { - return true; - } - } + @NotNull + private List collectPropertiesToInitialize(@NotNull JetFile file) { + List result = Lists.newArrayList(); + for (JetDeclaration declaration : file.getDeclarations()) { + if (declaration instanceof JetProperty && + ImplementationBodyCodegen.shouldInitializeProperty((JetProperty) declaration, typeMapper)) { + result.add((JetProperty) declaration); } } - return false; + return result; } public void done() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 4bcd2b04912..b4ebeeb434a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -97,7 +97,7 @@ public class PropertyCodegen extends GenerationStateAware { Object value = null; JetExpression initializer = p instanceof JetProperty ? ((JetProperty) p).getInitializer() : null; if (initializer != null) { - if (initializer instanceof JetConstantExpression) { + if (initializer instanceof JetConstantExpression && !propertyDescriptor.getType().isNullable()) { CompileTimeConstant compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer); value = compileTimeValue != null ? compileTimeValue.getValue() : null; } diff --git a/compiler/testData/codegen/box/classes/boxPrimitiveTypeInClinitOfClassObject.kt b/compiler/testData/codegen/box/classes/boxPrimitiveTypeInClinitOfClassObject.kt new file mode 100644 index 00000000000..e309d418a48 --- /dev/null +++ b/compiler/testData/codegen/box/classes/boxPrimitiveTypeInClinitOfClassObject.kt @@ -0,0 +1,31 @@ +class A { + class object { + var xi = 0 + var xin : Int? = 0 + var xinn : Int? = null + + var xl = 0.toLong() + var xln : Long? = 0.toLong() + var xlnn : Long? = null + + var xb = 0.toByte() + var xbn : Byte? = 0.toByte() + var xbnn : Byte? = null + + var xf = 0.toFloat() + var xfn : Float? = 0.toFloat() + var xfnn : Float? = null + + var xd = 0.toDouble() + var xdn : Double? = 0.toDouble() + var xdnn : Double? = null + + var xs = 0.toShort() + var xsn : Short? = 0.toShort() + var xsnn : Short? = null + } +} + +fun box() : String { + return "OK" +} diff --git a/compiler/testData/codegen/box/namespace/boxPrimitiveTypeInClinit.kt b/compiler/testData/codegen/box/namespace/boxPrimitiveTypeInClinit.kt new file mode 100644 index 00000000000..8b8377d314b --- /dev/null +++ b/compiler/testData/codegen/box/namespace/boxPrimitiveTypeInClinit.kt @@ -0,0 +1,27 @@ +var xi = 0 +var xin : Int? = 0 +var xinn : Int? = null + +var xl = 0.toLong() +var xln : Long? = 0.toLong() +var xlnn : Long? = null + +var xb = 0.toByte() +var xbn : Byte? = 0.toByte() +var xbnn : Byte? = null + +var xf = 0.toFloat() +var xfn : Float? = 0.toFloat() +var xfnn : Float? = null + +var xd = 0.toDouble() +var xdn : Double? = 0.toDouble() +var xdnn : Double? = null + +var xs = 0.toShort() +var xsn : Short? = 0.toShort() +var xsnn : Short? = null + +fun box() : String { + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 0cb760e0543..e65f2913ee5 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -457,6 +457,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/classes"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("boxPrimitiveTypeInClinitOfClassObject.kt") + public void testBoxPrimitiveTypeInClinitOfClassObject() throws Exception { + doTest("compiler/testData/codegen/box/classes/boxPrimitiveTypeInClinitOfClassObject.kt"); + } + @TestMetadata("classObject.kt") public void testClassObject() throws Exception { doTest("compiler/testData/codegen/box/classes/classObject.kt"); @@ -2621,6 +2626,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/namespace"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("boxPrimitiveTypeInClinit.kt") + public void testBoxPrimitiveTypeInClinit() throws Exception { + doTest("compiler/testData/codegen/box/namespace/boxPrimitiveTypeInClinit.kt"); + } + @TestMetadata("checkCast.kt") public void testCheckCast() throws Exception { doTest("compiler/testData/codegen/box/namespace/checkCast.kt");