Merge remote branch 'origin/master'
This commit is contained in:
@@ -4,8 +4,11 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
|||||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -22,6 +25,8 @@ public abstract class ClassBodyCodegen {
|
|||||||
protected final ClassVisitor v;
|
protected final ClassVisitor v;
|
||||||
protected final ClassContext context;
|
protected final ClassContext context;
|
||||||
|
|
||||||
|
protected final List<CodeChunk> staticInitializerChunks = new ArrayList<CodeChunk>();
|
||||||
|
|
||||||
public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
descriptor = state.getBindingContext().getClassDescriptor(aClass);
|
descriptor = state.getBindingContext().getClassDescriptor(aClass);
|
||||||
@@ -38,6 +43,8 @@ public abstract class ClassBodyCodegen {
|
|||||||
|
|
||||||
generateClassBody();
|
generateClassBody();
|
||||||
|
|
||||||
|
generateStaticInitializer();
|
||||||
|
|
||||||
v.visitEnd();
|
v.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,4 +102,23 @@ public abstract class ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateStaticInitializer() {
|
||||||
|
if (staticInitializerChunks.size() > 0) {
|
||||||
|
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||||
|
"<clinit>", "()V", null, null);
|
||||||
|
mv.visitCode();
|
||||||
|
|
||||||
|
InstructionAdapter v = new InstructionAdapter(mv);
|
||||||
|
|
||||||
|
for (CodeChunk chunk : staticInitializerChunks) {
|
||||||
|
chunk.generate(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,13 +25,15 @@ public class ClassCodegen {
|
|||||||
else {
|
else {
|
||||||
generateInterface(parentContext, aClass);
|
generateInterface(parentContext, aClass);
|
||||||
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
|
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
|
||||||
generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
|
if (!ImplementationBodyCodegen.isEnum(aClass)) {
|
||||||
|
generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
|
ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
|
||||||
final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION);
|
final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION);
|
||||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||||
if (declaration instanceof JetClass) {
|
if (declaration instanceof JetClass && !(declaration instanceof JetEnumEntry)) {
|
||||||
generate(contextForInners, (JetClass) declaration);
|
generate(contextForInners, (JetClass) declaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yole
|
||||||
|
*/
|
||||||
|
public interface CodeChunk {
|
||||||
|
void generate(InstructionAdapter v);
|
||||||
|
}
|
||||||
@@ -896,11 +896,11 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
return funDescriptor;
|
return funDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invokeMethodWithArguments(CallableMethod callableMethod, JetCallExpression expression) {
|
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCall expression) {
|
||||||
invokeMethodWithArguments(callableMethod, expression, false);
|
invokeMethodWithArguments(callableMethod, expression, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invokeMethodWithArguments(CallableMethod callableMethod, JetCallExpression expression, final boolean haveReceiver) {
|
private void invokeMethodWithArguments(CallableMethod callableMethod, JetCall expression, final boolean haveReceiver) {
|
||||||
if (callableMethod.isOwnerFromCall()) {
|
if (callableMethod.isOwnerFromCall()) {
|
||||||
setOwnerFromCall(callableMethod, expression);
|
setOwnerFromCall(callableMethod, expression);
|
||||||
}
|
}
|
||||||
@@ -914,7 +914,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
callableMethod.invoke(v);
|
callableMethod.invoke(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOwnerFromCall(CallableMethod callableMethod, JetCallExpression expression) {
|
private void setOwnerFromCall(CallableMethod callableMethod, JetCall expression) {
|
||||||
if (expression.getParent() instanceof JetQualifiedExpression) {
|
if (expression.getParent() instanceof JetQualifiedExpression) {
|
||||||
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
|
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
|
||||||
JetType expressionType = bindingContext.getExpressionType(receiver);
|
JetType expressionType = bindingContext.getExpressionType(receiver);
|
||||||
@@ -926,7 +926,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetExpression getReceiverForSelector(JetElement expression) {
|
private static JetExpression getReceiverForSelector(PsiElement expression) {
|
||||||
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
|
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
|
||||||
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
||||||
return parent.getReceiverExpression();
|
return parent.getReceiverExpression();
|
||||||
@@ -934,7 +934,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureReceiverOnStack(JetElement expression, @Nullable ClassDescriptor calleeContainingClass) {
|
private void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) {
|
||||||
JetExpression receiver = getReceiverForSelector(expression);
|
JetExpression receiver = getReceiverForSelector(expression);
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
if (!resolvesToClassOrPackage(receiver)) {
|
if (!resolvesToClassOrPackage(receiver)) {
|
||||||
@@ -1013,7 +1013,7 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isReceiver(JetElement expression) {
|
private static boolean isReceiver(PsiElement expression) {
|
||||||
final PsiElement parent = expression.getParent();
|
final PsiElement parent = expression.getParent();
|
||||||
if (parent instanceof JetQualifiedExpression) {
|
if (parent instanceof JetQualifiedExpression) {
|
||||||
final JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression();
|
final JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression();
|
||||||
|
|||||||
@@ -74,20 +74,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void generateSyntheticParts() {
|
protected void generateSyntheticParts() {
|
||||||
int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC;
|
generateFieldForTypeInfo();
|
||||||
v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
|
generateFieldForObjectInstance();
|
||||||
|
generateFieldForClassObject();
|
||||||
if (isNonLiteralObject()) {
|
|
||||||
Type type = JetTypeMapper.jetImplementationType(descriptor);
|
|
||||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
|
|
||||||
}
|
|
||||||
final JetClassObject classObject = getClassObject();
|
|
||||||
if (classObject != null) {
|
|
||||||
Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject));
|
|
||||||
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
generateStaticInitializer();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
generatePrimaryConstructor();
|
generatePrimaryConstructor();
|
||||||
@@ -99,13 +88,69 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
generateGetTypeInfo();
|
generateGetTypeInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateFieldForTypeInfo() {
|
||||||
|
final boolean typeInfoIsStatic = descriptor.getTypeConstructor().getParameters().size() == 0;
|
||||||
|
v.visitField(Opcodes.ACC_PRIVATE | (typeInfoIsStatic ? Opcodes.ACC_STATIC : 0), "$typeInfo",
|
||||||
|
"Ljet/typeinfo/TypeInfo;", null, null);
|
||||||
|
if (typeInfoIsStatic) {
|
||||||
|
staticInitializerChunks.add(new CodeChunk() {
|
||||||
|
@Override
|
||||||
|
public void generate(InstructionAdapter v) {
|
||||||
|
JetTypeMapper typeMapper = state.getTypeMapper();
|
||||||
|
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE));
|
||||||
|
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateFieldForObjectInstance() {
|
||||||
|
if (isNonLiteralObject()) {
|
||||||
|
Type type = JetTypeMapper.jetImplementationType(descriptor);
|
||||||
|
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
|
||||||
|
|
||||||
|
staticInitializerChunks.add(new CodeChunk() {
|
||||||
|
@Override
|
||||||
|
public void generate(InstructionAdapter v) {
|
||||||
|
String name = jvmName();
|
||||||
|
v.anew(Type.getObjectType(name));
|
||||||
|
v.dup();
|
||||||
|
v.invokespecial(name, "<init>", "()V");
|
||||||
|
v.putstatic(name, "$instance", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateFieldForClassObject() {
|
||||||
|
final JetClassObject classObject = getClassObject();
|
||||||
|
if (classObject != null) {
|
||||||
|
Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject));
|
||||||
|
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
|
||||||
|
|
||||||
|
staticInitializerChunks.add(new CodeChunk() {
|
||||||
|
@Override
|
||||||
|
public void generate(InstructionAdapter v) {
|
||||||
|
String name = state.getTypeMapper().jvmName(classObject);
|
||||||
|
final Type classObjectType = Type.getObjectType(name);
|
||||||
|
v.anew(classObjectType);
|
||||||
|
v.dup();
|
||||||
|
v.invokespecial(name, "<init>", "()V");
|
||||||
|
v.putstatic(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$classobj",
|
||||||
|
classObjectType.getDescriptor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void generatePrimaryConstructor() {
|
protected void generatePrimaryConstructor() {
|
||||||
ConstructorDescriptor constructorDescriptor = state.getBindingContext().getConstructorDescriptor((JetElement) myClass);
|
ConstructorDescriptor constructorDescriptor = state.getBindingContext().getConstructorDescriptor((JetElement) myClass);
|
||||||
if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration)) return;
|
if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return;
|
||||||
|
|
||||||
Method method;
|
Method method;
|
||||||
CallableMethod callableMethod;
|
CallableMethod callableMethod;
|
||||||
if (myClass instanceof JetObjectDeclaration) {
|
if (constructorDescriptor == null) {
|
||||||
method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
|
method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
|
||||||
callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.<Type>emptyList());
|
callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.<Type>emptyList());
|
||||||
}
|
}
|
||||||
@@ -233,6 +278,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isEnum(JetClassOrObject myClass) {
|
||||||
|
final JetModifierList modifierList = myClass.getModifierList();
|
||||||
|
return modifierList != null && modifierList.hasModifier(JetTokens.ENUM_KEYWORD);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ClassDescriptor getOuterClassDescriptor() {
|
private ClassDescriptor getOuterClassDescriptor() {
|
||||||
if (myClass.getParent() instanceof JetClassObject) {
|
if (myClass.getParent() instanceof JetClassObject) {
|
||||||
@@ -280,13 +330,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
|
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
|
||||||
List<JetArgument> args = constructorCall.getValueArguments();
|
codegen.invokeMethodWithArguments(method, constructorCall);
|
||||||
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
|
|
||||||
JetArgument arg = args.get(i);
|
|
||||||
codegen.gen(arg.getArgumentExpression(), method.getValueParameterTypes().get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
method.invoke(iv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -409,47 +453,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateStaticInitializer() {
|
|
||||||
boolean needTypeInfo = descriptor.getTypeConstructor().getParameters().size() == 0;
|
|
||||||
boolean needInstance = isNonLiteralObject();
|
|
||||||
JetClassObject classObject = getClassObject();
|
|
||||||
if (!needTypeInfo && !needInstance && classObject == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
|
||||||
"<clinit>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
|
|
||||||
InstructionAdapter v = new InstructionAdapter(mv);
|
|
||||||
|
|
||||||
if (needTypeInfo) {
|
|
||||||
JetTypeMapper typeMapper = state.getTypeMapper();
|
|
||||||
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE));
|
|
||||||
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
|
|
||||||
}
|
|
||||||
if (needInstance) {
|
|
||||||
String name = jvmName();
|
|
||||||
v.anew(Type.getObjectType(name));
|
|
||||||
v.dup();
|
|
||||||
v.invokespecial(name, "<init>", "()V");
|
|
||||||
v.putstatic(name, "$instance", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
|
|
||||||
}
|
|
||||||
if (classObject != null) {
|
|
||||||
String name = state.getTypeMapper().jvmName(classObject);
|
|
||||||
final Type classObjectType = Type.getObjectType(name);
|
|
||||||
v.anew(classObjectType);
|
|
||||||
v.dup();
|
|
||||||
v.invokespecial(name, "<init>", "()V");
|
|
||||||
v.putstatic(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$classobj",
|
|
||||||
classObjectType.getDescriptor());
|
|
||||||
}
|
|
||||||
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitMaxs(0, 0);
|
|
||||||
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private JetClassObject getClassObject() {
|
private JetClassObject getClassObject() {
|
||||||
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;
|
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ package org.jetbrains.jet.codegen;
|
|||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -18,6 +21,8 @@ import java.util.Set;
|
|||||||
* @author yole
|
* @author yole
|
||||||
*/
|
*/
|
||||||
public class InterfaceBodyCodegen extends ClassBodyCodegen {
|
public class InterfaceBodyCodegen extends ClassBodyCodegen {
|
||||||
|
private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
|
||||||
|
|
||||||
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
|
||||||
super(aClass, context, v, state);
|
super(aClass, context, v, state);
|
||||||
assert context.getContextKind() == OwnerKind.INTERFACE;
|
assert context.getContextKind() == OwnerKind.INTERFACE;
|
||||||
@@ -73,4 +78,59 @@ public class InterfaceBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
return superInterfaces;
|
return superInterfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
|
||||||
|
if (declaration instanceof JetEnumEntry && !((JetEnumEntry) declaration).hasPrimaryConstructor()) {
|
||||||
|
String name = declaration.getName();
|
||||||
|
final String desc = "L" + state.getTypeMapper().jvmName(descriptor, OwnerKind.INTERFACE) + ";";
|
||||||
|
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, desc, null, null);
|
||||||
|
if (myEnumConstants.isEmpty()) {
|
||||||
|
staticInitializerChunks.add(new CodeChunk() {
|
||||||
|
@Override
|
||||||
|
public void generate(InstructionAdapter v) {
|
||||||
|
initializeEnumConstants(v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
myEnumConstants.add((JetEnumEntry) declaration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
super.generateDeclaration(propertyCodegen, declaration, functionCodegen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeEnumConstants(InstructionAdapter v) {
|
||||||
|
ExpressionCodegen codegen = new ExpressionCodegen(v, new FrameMap(), Type.VOID_TYPE, context, state);
|
||||||
|
for (JetEnumEntry enumConstant : myEnumConstants) {
|
||||||
|
// TODO type and constructor parameters
|
||||||
|
String intfClass = state.getTypeMapper().jvmName(descriptor, OwnerKind.INTERFACE);
|
||||||
|
String implClass = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION);
|
||||||
|
|
||||||
|
final List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
|
||||||
|
if (delegationSpecifiers.size() > 1) {
|
||||||
|
throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
v.anew(Type.getObjectType(implClass));
|
||||||
|
v.dup();
|
||||||
|
|
||||||
|
if (delegationSpecifiers.size() == 1) {
|
||||||
|
final JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
|
||||||
|
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||||
|
final JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
|
||||||
|
ConstructorDescriptor constructorDescriptor = state.getBindingContext().resolveSuperConstructor(superCall);
|
||||||
|
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||||
|
codegen.invokeMethodWithArguments(method, superCall);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v.invokespecial(implClass, "<init>", "()V");
|
||||||
|
}
|
||||||
|
v.putstatic(intfClass, enumConstant.getName(), "L" + intfClass + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.jet.lang.psi;
|
package org.jetbrains.jet.lang.psi;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface JetCall {
|
public interface JetCall extends PsiElement {
|
||||||
@Nullable
|
@Nullable
|
||||||
JetArgumentList getValueArgumentList();
|
JetArgumentList getValueArgumentList();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -130,4 +131,21 @@ public class ClassGenTest extends CodegenTestCase {
|
|||||||
Object result = method.invoke(null);
|
Object result = method.invoke(null);
|
||||||
assertInstanceOf(result, Runnable.class);
|
assertInstanceOf(result, Runnable.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testEnumClass() throws Exception {
|
||||||
|
loadText("enum class Direction { NORTH; SOUTH; EAST; WEST }");
|
||||||
|
final Class direction = loadAllClasses(generateClassesInFile()).get("Direction");
|
||||||
|
final Field north = direction.getField("NORTH");
|
||||||
|
assertEquals(direction, north.getType());
|
||||||
|
assertInstanceOf(north.get(null), direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEnumConstantConstructors() throws Exception {
|
||||||
|
loadText("enum class Color(val rgb: Int) { RED: Color(0xFF0000); GREEN: Color(0x00FF00); }");
|
||||||
|
final Class colorClass = loadAllClasses(generateClassesInFile()).get("Color");
|
||||||
|
final Field redField = colorClass.getField("RED");
|
||||||
|
final Object redValue = redField.get(null);
|
||||||
|
final Method rgbMethod = colorClass.getMethod("getRgb");
|
||||||
|
assertEquals(0xFF0000, rgbMethod.invoke(redValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user