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();
|
JetTypeMapper typeMapper = state.getTypeMapper();
|
||||||
for (JetDeclaration declaration : declarations) {
|
for (JetDeclaration declaration : declarations) {
|
||||||
if (declaration instanceof JetProperty) {
|
if (declaration instanceof JetProperty) {
|
||||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, declaration);
|
if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
|
||||||
assert propertyDescriptor != null;
|
initializeProperty(codegen, bindingContext, iv, (JetProperty) declaration, false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (declaration instanceof JetClassInitializer) {
|
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) {
|
private static boolean skipDefaultValue(PropertyDescriptor propertyDescriptor, Object value, Type type) {
|
||||||
if (isPrimitive(type)) {
|
if (isPrimitive(type)) {
|
||||||
if (!propertyDescriptor.getType().isNullable() && value instanceof Number) {
|
if (!propertyDescriptor.getType().isNullable() && value instanceof Number) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
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.MethodVisitor;
|
||||||
import org.jetbrains.asm4.Type;
|
import org.jetbrains.asm4.Type;
|
||||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
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.context.CodegenContext;
|
||||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
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.io.File;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.asm4.Opcodes.*;
|
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();
|
builder.done();
|
||||||
}
|
}
|
||||||
@@ -207,6 +206,9 @@ public class NamespaceCodegen extends MemberCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateStaticInitializers(@NotNull ClassBuilder builder, @NotNull JetFile file) {
|
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);
|
MethodVisitor mv = builder.newMethod(file, ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
@@ -214,18 +216,9 @@ public class NamespaceCodegen extends MemberCodegen {
|
|||||||
FrameMap frameMap = new FrameMap();
|
FrameMap frameMap = new FrameMap();
|
||||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state);
|
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state);
|
||||||
|
|
||||||
for (JetDeclaration declaration : file.getDeclarations()) {
|
for (JetDeclaration declaration : properties) {
|
||||||
if (declaration instanceof JetProperty) {
|
ImplementationBodyCodegen.
|
||||||
JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
initializeProperty(codegen, state.getBindingContext(), new InstructionAdapter(mv), (JetProperty) declaration, true);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mv.visitInsn(RETURN);
|
mv.visitInsn(RETURN);
|
||||||
@@ -234,18 +227,16 @@ public class NamespaceCodegen extends MemberCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNonConstantPropertyInitializers() {
|
@NotNull
|
||||||
for (JetFile file : files) {
|
private List<JetProperty> collectPropertiesToInitialize(@NotNull JetFile file) {
|
||||||
for (JetDeclaration declaration : file.getDeclarations()) {
|
List<JetProperty> result = Lists.newArrayList();
|
||||||
if (declaration instanceof JetProperty) {
|
for (JetDeclaration declaration : file.getDeclarations()) {
|
||||||
JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
if (declaration instanceof JetProperty &&
|
||||||
if (initializer != null && !(initializer instanceof JetConstantExpression)) {
|
ImplementationBodyCodegen.shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
|
||||||
return true;
|
result.add((JetProperty) declaration);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void done() {
|
public void done() {
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class PropertyCodegen extends GenerationStateAware {
|
|||||||
Object value = null;
|
Object value = null;
|
||||||
JetExpression initializer = p instanceof JetProperty ? ((JetProperty) p).getInitializer() : null;
|
JetExpression initializer = p instanceof JetProperty ? ((JetProperty) p).getInitializer() : null;
|
||||||
if (initializer != null) {
|
if (initializer != null) {
|
||||||
if (initializer instanceof JetConstantExpression) {
|
if (initializer instanceof JetConstantExpression && !propertyDescriptor.getType().isNullable()) {
|
||||||
CompileTimeConstant<?> compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer);
|
CompileTimeConstant<?> compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer);
|
||||||
value = compileTimeValue != null ? compileTimeValue.getValue() : null;
|
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);
|
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")
|
@TestMetadata("classObject.kt")
|
||||||
public void testClassObject() throws Exception {
|
public void testClassObject() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/classes/classObject.kt");
|
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);
|
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")
|
@TestMetadata("checkCast.kt")
|
||||||
public void testCheckCast() throws Exception {
|
public void testCheckCast() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/namespace/checkCast.kt");
|
doTest("compiler/testData/codegen/box/namespace/checkCast.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user