Unify properties initialization for init and clinit
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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<JetProperty> properties = collectPropertiesToInitialize(file);
|
||||
if (properties.isEmpty()) return;
|
||||
|
||||
MethodVisitor mv = builder.newMethod(file, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()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<JetProperty> collectPropertiesToInitialize(@NotNull JetFile file) {
|
||||
List<JetProperty> 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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user