Assorted fixes to inheritance/delegation codegen
This commit is contained in:
@@ -179,6 +179,8 @@ public class ClassCodegen {
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, classDescriptor, kind);
|
||||
|
||||
String classname = JetTypeMapper.jvmName(classDescriptor, kind);
|
||||
final Type classType = Type.getType("L" + classname + ";");
|
||||
|
||||
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||
String interfaceDesc = JetTypeMapper.jetInterfaceType(classDescriptor).getDescriptor();
|
||||
v.visitField(Opcodes.ACC_PRIVATE, "$this", interfaceDesc, /*TODO*/null, null);
|
||||
@@ -202,14 +204,62 @@ public class ClassCodegen {
|
||||
|
||||
int n = 0;
|
||||
for (JetDelegationSpecifier specifier : specifiers) {
|
||||
boolean instanceOnStack = pushDelegateInstance(specifier, kind, codegen, iv, n);
|
||||
if (instanceOnStack) {
|
||||
boolean delegateOnStack = specifier instanceof JetDelegatorToSuperCall && n > 0 ||
|
||||
specifier instanceof JetDelegatorByExpressionSpecifier ;
|
||||
|
||||
if (delegateOnStack) {
|
||||
iv.load(0, classType);
|
||||
}
|
||||
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
|
||||
ConstructorDescriptor constructorDescriptor1 = bindingContext.resolveSuperConstructor(superCall, this);
|
||||
|
||||
ClassDescriptor classDecl = constructorDescriptor1.getContainingDeclaration();
|
||||
boolean isDelegating = kind == OwnerKind.DELEGATING_IMPLEMENTATION;
|
||||
Type type = isDelegating ? JetTypeMapper.jetDelegatingImplementationType(classDecl) : JetTypeMapper.jetImplementationType(classDecl);
|
||||
|
||||
if (n > 0) {
|
||||
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||
codegen.thisToStack();
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
iv.load(0, type);
|
||||
}
|
||||
else {
|
||||
iv.anew(type);
|
||||
iv.dup();
|
||||
}
|
||||
|
||||
Method method1 = typeMapper.mapConstructorSignature(constructorDescriptor1, kind);
|
||||
final Type[] argTypes1 = method1.getArgumentTypes();
|
||||
List<JetArgument> args = superCall.getValueArguments();
|
||||
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
|
||||
JetArgument arg = args.get(i);
|
||||
codegen.gen(arg.getArgumentExpression(), argTypes1[i]);
|
||||
}
|
||||
|
||||
iv.invokespecial(type.getClassName(), "<init>", method1.getDescriptor());
|
||||
}
|
||||
else if (specifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||
codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression());
|
||||
}
|
||||
|
||||
if (delegateOnStack) {
|
||||
JetType superType = bindingContext.resolveTypeReference(specifier.getTypeReference());
|
||||
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
|
||||
String delegateField = "$delegate_" + n;
|
||||
String fieldDesc = JetTypeMapper.jetInterfaceType(superClassDescriptor).getDescriptor();
|
||||
Type fieldType = JetTypeMapper.jetInterfaceType(superClassDescriptor);
|
||||
String fieldDesc = fieldType.getDescriptor();
|
||||
v.visitField(Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null);
|
||||
iv.putfield(classname, delegateField, fieldDesc);
|
||||
|
||||
JetClass superClass = (JetClass) bindingContext.getDeclarationPsiElement(superClassDescriptor);
|
||||
generateDelegates(aClass, superClass, v,
|
||||
new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false),
|
||||
JetTypeMapper.jvmNameForInterface(superClassDescriptor)));
|
||||
}
|
||||
|
||||
n++;
|
||||
@@ -217,54 +267,24 @@ public class ClassCodegen {
|
||||
|
||||
generateInitializers(aClass, kind, codegen, iv);
|
||||
|
||||
int curParam = 0;
|
||||
List<JetParameter> constructorParameters = aClass.getPrimaryConstructorParameters();
|
||||
for (JetParameter parameter : constructorParameters) {
|
||||
if (parameter.getValOrVarNode() != null) {
|
||||
VariableDescriptor descriptor = paramDescrs.get(curParam);
|
||||
Type type = typeMapper.mapType(descriptor.getOutType());
|
||||
iv.load(0, classType);
|
||||
iv.load(frameMap.getIndex(descriptor), type);
|
||||
iv.putfield(classname, descriptor.getName(), type.getDescriptor());
|
||||
}
|
||||
curParam++;
|
||||
}
|
||||
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private boolean pushDelegateInstance(JetDelegationSpecifier specifier, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter v, int pos) {
|
||||
boolean instanceOnStack = false;
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
|
||||
ConstructorDescriptor constructorDescriptor = bindingContext.resolveSuperConstructor(superCall, this);
|
||||
|
||||
ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
|
||||
boolean isDelegating = kind == OwnerKind.DELEGATING_IMPLEMENTATION;
|
||||
Type type = isDelegating ? JetTypeMapper.jetDelegatingImplementationType(classDecl) : JetTypeMapper.jetImplementationType(classDecl);
|
||||
|
||||
if (pos > 0) {
|
||||
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||
codegen.thisToStack();
|
||||
}
|
||||
}
|
||||
|
||||
Method method = typeMapper.mapConstructorSignature(constructorDescriptor, kind);
|
||||
final Type[] argTypes = method.getArgumentTypes();
|
||||
List<JetArgument> args = superCall.getValueArguments();
|
||||
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
|
||||
JetArgument arg = args.get(i);
|
||||
codegen.gen(arg.getArgumentExpression(), argTypes[i]);
|
||||
}
|
||||
|
||||
if (pos == 0) {
|
||||
v.load(0, type);
|
||||
}
|
||||
else {
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
instanceOnStack = true;
|
||||
}
|
||||
|
||||
v.invokespecial(type.getClassName(), "<init>", method.getDescriptor());
|
||||
}
|
||||
else if (specifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||
codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression());
|
||||
instanceOnStack = true;
|
||||
}
|
||||
|
||||
return instanceOnStack;
|
||||
}
|
||||
|
||||
private void generateInitializers(JetClass aClass, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter iv) {
|
||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
@@ -295,5 +315,56 @@ public class ClassCodegen {
|
||||
functionCodegen.gen((JetFunction) declaration, kind);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetParameter p : aClass.getPrimaryConstructorParameters()) {
|
||||
if (p.getValOrVarNode() != null) {
|
||||
VariableDescriptor descriptor = bindingContext.getParameterDescriptor(p);
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
|
||||
}
|
||||
|
||||
if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && bindingContext.hasBackingField(propertyDescriptor)) {
|
||||
v.visitField(Opcodes.ACC_PRIVATE, p.getName(), typeMapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDelegates(JetClass inClass, JetClass toClass, ClassVisitor v, OwnerKind kind) {
|
||||
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
|
||||
final FunctionCodegen functionCodegen = new FunctionCodegen(toClass, v, standardLibrary, bindingContext);
|
||||
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen);
|
||||
|
||||
/* TODO
|
||||
for (JetDeclaration declaration : toClass.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
propertyCodegen.gen((JetProperty) declaration, kind);
|
||||
}
|
||||
else if (declaration instanceof JetFunction) {
|
||||
functionCodegen.gen((JetFunction) declaration, kind);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for (JetParameter p : toClass.getPrimaryConstructorParameters()) {
|
||||
if (p.getValOrVarNode() != null) {
|
||||
VariableDescriptor descriptor = bindingContext.getParameterDescriptor(p);
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
|
||||
}
|
||||
|
||||
if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && bindingContext.hasBackingField(propertyDescriptor)) {
|
||||
v.visitField(Opcodes.ACC_PRIVATE, p.getName(), typeMapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import jet.IntRange;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -448,6 +449,23 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
|
||||
//TODO: hack, will not need if resolve goes to right descriptor itself
|
||||
if (declaration instanceof JetParameter) {
|
||||
if (PsiTreeUtil.getParentOfType(expression, JetDelegationSpecifier.class) != null) {
|
||||
JetClass aClass = PsiTreeUtil.getParentOfType(expression, JetClass.class);
|
||||
ConstructorDescriptor constructorDescriptor = bindingContext.getConstructorDescriptor(aClass);
|
||||
List<ValueParameterDescriptor> parameters = constructorDescriptor.getUnsubstitutedValueParameters();
|
||||
for (ValueParameterDescriptor parameter : parameters) {
|
||||
if (parameter.getName().equals(descriptor.getName())) {
|
||||
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||
myStack.push(StackValue.local(myMap.getIndex(parameter), typeMapper.mapType(outType)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isStatic = descriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
|
||||
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
|
||||
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField);
|
||||
|
||||
@@ -32,18 +32,18 @@ public class JetTypeMapper {
|
||||
}
|
||||
|
||||
static String jvmName(ClassDescriptor jetClass, OwnerKind kind) {
|
||||
switch (kind) {
|
||||
|
||||
case INTERFACE:
|
||||
return jvmNameForInterface(jetClass);
|
||||
case IMPLEMENTATION:
|
||||
return jvmNameForImplementation(jetClass);
|
||||
case DELEGATING_IMPLEMENTATION:
|
||||
return jvmNameForDelegatingImplementation(jetClass);
|
||||
|
||||
default:
|
||||
assert false : "Unsuitable kind";
|
||||
return "java/lang/Object";
|
||||
if (kind == OwnerKind.INTERFACE) {
|
||||
return jvmNameForInterface(jetClass);
|
||||
}
|
||||
else if (kind == OwnerKind.IMPLEMENTATION) {
|
||||
return jvmNameForImplementation(jetClass);
|
||||
}
|
||||
else if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||
return jvmNameForDelegatingImplementation(jetClass);
|
||||
}
|
||||
else {
|
||||
assert false : "Unsuitable kind";
|
||||
return "java/lang/Object";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,31 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public enum OwnerKind {
|
||||
NAMESPACE,
|
||||
INTERFACE,
|
||||
IMPLEMENTATION,
|
||||
DELEGATING_IMPLEMENTATION
|
||||
public class OwnerKind {
|
||||
public static final OwnerKind NAMESPACE = new OwnerKind();
|
||||
public static final OwnerKind INTERFACE = new OwnerKind();
|
||||
public static final OwnerKind IMPLEMENTATION = new OwnerKind();
|
||||
public static final OwnerKind DELEGATING_IMPLEMENTATION = new OwnerKind();
|
||||
|
||||
public static class DelegateKind extends OwnerKind {
|
||||
private final StackValue delegate;
|
||||
private final String ownerClass;
|
||||
|
||||
public DelegateKind(StackValue delegate, String ownerClass) {
|
||||
this.delegate = delegate;
|
||||
this.ownerClass = ownerClass;
|
||||
}
|
||||
|
||||
public StackValue getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public String getOwnerClass() {
|
||||
return ownerClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,49 +122,78 @@ public class PropertyCodegen {
|
||||
private void generateDefaultGetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p);
|
||||
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
|
||||
generateDefaultGetter(propertyDescriptor, flags, kind);
|
||||
}
|
||||
|
||||
public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags, OwnerKind kind) {
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
final String signature = mapper.mapGetterSignature(propertyDescriptor).getDescriptor();
|
||||
MethodVisitor mv = v.visitMethod(flags, getterName(p.getName()), signature, null, null);
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
else if (kind == OwnerKind.INTERFACE) {
|
||||
flags |= Opcodes.ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
final String signature = mapper.mapGetterSignature(propertyDescriptor).getDescriptor();
|
||||
String getterName = getterName(propertyDescriptor.getName());
|
||||
MethodVisitor mv = v.visitMethod(flags, getterName, signature, null, null);
|
||||
if (kind != OwnerKind.INTERFACE) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
final Type type = mapper.mapType(propertyDescriptor.getOutType());
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
iv.invokeinterface(dk.getOwnerClass(), getterName, signature);
|
||||
}
|
||||
else {
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD,
|
||||
JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
}
|
||||
iv.areturn(type);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
final Type type = mapper.mapType(propertyDescriptor.getOutType());
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD,
|
||||
JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
iv.areturn(type);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateDefaultSetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p);
|
||||
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
|
||||
generateDefaultSetter(propertyDescriptor, flags, kind);
|
||||
}
|
||||
|
||||
public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags, OwnerKind kind) {
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
else if (kind == OwnerKind.INTERFACE) {
|
||||
flags |= Opcodes.ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
final String signature = mapper.mapSetterSignature(propertyDescriptor).getDescriptor();
|
||||
MethodVisitor mv = v.visitMethod(flags, setterName(p.getName()), signature, null, null);
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
final Type type = mapper.mapType(propertyDescriptor.getOutType());
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
iv.load(1, type);
|
||||
MethodVisitor mv = v.visitMethod(flags, setterName(propertyDescriptor.getName()), signature, null, null);
|
||||
if (kind != OwnerKind.INTERFACE) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
final Type type = mapper.mapType(propertyDescriptor.getOutType());
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
iv.load(1, type);
|
||||
}
|
||||
else {
|
||||
iv.load(0, type);
|
||||
}
|
||||
//TODO: kind inst Delegate
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD,
|
||||
JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
else {
|
||||
iv.load(0, type);
|
||||
}
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD,
|
||||
JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public static String getterName(String propertyName) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class X(val x : Int) {}
|
||||
class Y(val y : Int) {}
|
||||
|
||||
class Point(x : Int, y : Int) : X(x), Y(y) {}
|
||||
class Point(x : Int, y : Int) : X(x) , Y(y) {}
|
||||
|
||||
class Abstract {}
|
||||
|
||||
@@ -18,10 +18,10 @@ fun box() : String {
|
||||
if (p.x + p.y != 239) return "FAIL #3"
|
||||
|
||||
val y = new Y(-1)
|
||||
/*
|
||||
|
||||
val p1 = new P1(240, y)
|
||||
if (p1.x + p1.y != 239) return "FAIL #4"
|
||||
|
||||
val p2 = new P2(240, y)
|
||||
if (p2.x + p2.y != 239) return "FAIL #5"
|
||||
|
||||
@@ -30,6 +30,6 @@ fun box() : String {
|
||||
|
||||
val p4 = new P4(240, y)
|
||||
if (p4.x + p4.y != 239) return "FAIL #7"
|
||||
|
||||
*/
|
||||
"OK"
|
||||
}
|
||||
@@ -40,6 +40,7 @@ public class ClassGenTest extends CodegenTestCase {
|
||||
|
||||
public void testNewInstanceExplicitConstructor() throws Exception {
|
||||
loadFile("newInstanceDefaultConstructor.jet");
|
||||
System.out.println(generateToText());
|
||||
final Codegens codegens = generateClassesInFile();
|
||||
loadImplementationClass(codegens, "SimpleClass");
|
||||
Class ns = loadRootNamespaceClass(codegens);
|
||||
|
||||
Reference in New Issue
Block a user