initial, barely working implementation of inner classes
This commit is contained in:
@@ -42,6 +42,12 @@ public class ClassCodegen {
|
||||
generateInterface(aClass);
|
||||
generateImplementation(aClass, OwnerKind.IMPLEMENTATION);
|
||||
generateImplementation(aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
|
||||
|
||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||
if (declaration instanceof JetClass) {
|
||||
generate((JetClass) declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateInterface(JetClass aClass) {
|
||||
@@ -70,12 +76,13 @@ public class ClassCodegen {
|
||||
String superClass = getSuperClass(aClass, kind);
|
||||
|
||||
ClassVisitor v = kind == OwnerKind.IMPLEMENTATION ? factory.forClassImplementation(descriptor) : factory.forClassDelegatingImplementation(descriptor);
|
||||
final String defaultInterfaceName = JetTypeMapper.jvmNameForInterface(descriptor);
|
||||
v.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
JetTypeMapper.jetJvmName(descriptor, kind),
|
||||
null,
|
||||
superClass,
|
||||
new String[] { "jet/JetObject", JetTypeMapper.jvmNameForInterface(descriptor) }
|
||||
new String[] { "jet/JetObject", defaultInterfaceName}
|
||||
);
|
||||
|
||||
int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC;
|
||||
@@ -180,9 +187,29 @@ public class ClassCodegen {
|
||||
String classname = typeMapper.jvmName(classDescriptor, kind);
|
||||
final Type classType = Type.getType("L" + classname + ";");
|
||||
|
||||
List<JetDelegationSpecifier> specifiers = aClass.getDelegationSpecifiers();
|
||||
|
||||
if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) {
|
||||
String superClass = getSuperClass(aClass, kind);
|
||||
iv.load(0, Type.getType("L" + superClass + ";"));
|
||||
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (ClassDescriptor outerClassDescriptor : JetTypeMapper.getOuterClassDescriptors(classDescriptor)) {
|
||||
final Type type = JetTypeMapper.jetInterfaceType(outerClassDescriptor);
|
||||
String interfaceDesc = type.getDescriptor();
|
||||
final String fieldName = "this$" + index;
|
||||
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
|
||||
iv.load(0, classType);
|
||||
iv.load(index + 1, type);
|
||||
iv.putfield(classname, fieldName, interfaceDesc);
|
||||
frameMap.enterTemp();
|
||||
}
|
||||
|
||||
if (kind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||
String interfaceDesc = JetTypeMapper.jetInterfaceType(classDescriptor).getDescriptor();
|
||||
v.visitField(Opcodes.ACC_PRIVATE, "$this", interfaceDesc, /*TODO*/null, null);
|
||||
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "$this", interfaceDesc, /*TODO*/null, null);
|
||||
iv.load(1, argTypes[0]);
|
||||
iv.putfield(classname, "$this", interfaceDesc);
|
||||
frameMap.enterTemp();
|
||||
@@ -204,14 +231,6 @@ public class ClassCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
List<JetDelegationSpecifier> specifiers = aClass.getDelegationSpecifiers();
|
||||
|
||||
if (specifiers.isEmpty() || !(specifiers.get(0) instanceof JetDelegatorToSuperCall)) {
|
||||
String superClass = getSuperClass(aClass, kind);
|
||||
iv.load(0, Type.getType("L" + superClass + ";"));
|
||||
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||
}
|
||||
|
||||
HashSet<FunctionDescriptor> overriden = new HashSet<FunctionDescriptor>();
|
||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||
if (declaration instanceof JetFunction) {
|
||||
|
||||
@@ -561,7 +561,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
final Type fieldType = psiTypeToAsm(psiField.getType());
|
||||
final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
|
||||
if (!isStatic) {
|
||||
ensureReceiverOnStack(expression);
|
||||
ensureReceiverOnStack(expression, null);
|
||||
}
|
||||
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
|
||||
}
|
||||
@@ -591,7 +591,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
|
||||
if (isClass(container, "Array") && propertyDescriptor.getName().equals("size")) {
|
||||
ensureReceiverOnStack(expression);
|
||||
ensureReceiverOnStack(expression, null);
|
||||
v.arraylength();
|
||||
myStack.push(StackValue.onStack(Type.INT_TYPE));
|
||||
}
|
||||
@@ -600,7 +600,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
|
||||
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField);
|
||||
if (!isStatic) {
|
||||
ensureReceiverOnStack(expression);
|
||||
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null);
|
||||
}
|
||||
myStack.push(iValue);
|
||||
}
|
||||
@@ -709,7 +709,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC);
|
||||
|
||||
if (!isStatic) {
|
||||
ensureReceiverOnStack(expression);
|
||||
ensureReceiverOnStack(expression, null);
|
||||
if (expression.getParent() instanceof JetQualifiedExpression) {
|
||||
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
|
||||
owner = expressionType(receiver).getInternalName();
|
||||
@@ -727,14 +727,14 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
methodDescriptor = typeMapper.mapSignature(jetFunction);
|
||||
if (functionParent instanceof NamespaceDescriptorImpl) {
|
||||
if (jetFunction.getReceiverTypeRef() != null) {
|
||||
ensureReceiverOnStack(expression);
|
||||
ensureReceiverOnStack(expression, null);
|
||||
}
|
||||
pushMethodArguments(expression, methodDescriptor);
|
||||
final String owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
|
||||
v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
|
||||
}
|
||||
else if (functionParent instanceof ClassDescriptor) {
|
||||
ensureReceiverOnStack(expression);
|
||||
ensureReceiverOnStack(expression, (ClassDescriptor) functionParent);
|
||||
pushMethodArguments(expression, methodDescriptor);
|
||||
final String owner = JetTypeMapper.jvmNameForInterface((ClassDescriptor) functionParent);
|
||||
v.invokeinterface(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
|
||||
@@ -756,7 +756,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureReceiverOnStack(JetElement expression) {
|
||||
private void ensureReceiverOnStack(JetElement expression, @Nullable ClassDescriptor calleeContainingClass) {
|
||||
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
|
||||
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
||||
if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
|
||||
@@ -769,6 +769,12 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :)
|
||||
if (calleeContainingClass != null && contextType instanceof ClassDescriptor &&
|
||||
calleeContainingClass == contextType.getContainingDeclaration()) {
|
||||
v.getfield(typeMapper.jvmName((ClassDescriptor) contextType, OwnerKind.IMPLEMENTATION),
|
||||
"this$0", typeMapper.jvmType(calleeContainingClass, OwnerKind.INTERFACE).getDescriptor());
|
||||
// TODO handle more levels of class nestng
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1314,9 +1320,14 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
generateNewArray(expression, type);
|
||||
}
|
||||
else {
|
||||
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
||||
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
|
||||
// TODO typechecker must verify that we're the outer class of the instance being created
|
||||
pushOuterClassArguments(classDecl);
|
||||
|
||||
Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||
pushMethodArguments(expression, method);
|
||||
|
||||
@@ -1326,7 +1337,6 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
|
||||
}
|
||||
|
||||
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
||||
v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "<init>", method.getDescriptor());
|
||||
}
|
||||
}
|
||||
@@ -1336,6 +1346,14 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
myStack.push(StackValue.onStack(type));
|
||||
}
|
||||
|
||||
private void pushOuterClassArguments(ClassDescriptor classDecl) {
|
||||
final List<ClassDescriptor> outerClassDescriptors = JetTypeMapper.getOuterClassDescriptors(classDecl);
|
||||
if (outerClassDescriptors.size() > 0) {
|
||||
v.load(0, JetTypeMapper.jetImplementationType(classDecl));
|
||||
}
|
||||
// TODO push further outer classes
|
||||
}
|
||||
|
||||
private Type generateJavaConstructorCall(JetNewExpression expression, PsiMethod constructor) {
|
||||
PsiClass javaClass = constructor.getContainingClass();
|
||||
Type type = JetTypeMapper.psiClassType(javaClass);
|
||||
|
||||
@@ -253,6 +253,9 @@ public class JetTypeMapper {
|
||||
List<ValueParameterDescriptor> parameters = descriptor.getUnsubstitutedValueParameters();
|
||||
List<Type> parameterTypes = new ArrayList<Type>();
|
||||
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||
for (ClassDescriptor outerDescriptor : getOuterClassDescriptors(classDescriptor)) {
|
||||
parameterTypes.add(jvmType(outerDescriptor, OwnerKind.IMPLEMENTATION));
|
||||
}
|
||||
if (delegate) {
|
||||
parameterTypes.add(jetInterfaceType(classDescriptor));
|
||||
}
|
||||
@@ -268,6 +271,16 @@ public class JetTypeMapper {
|
||||
return new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
}
|
||||
|
||||
public static List<ClassDescriptor> getOuterClassDescriptors(ClassDescriptor classDescriptor) {
|
||||
List<ClassDescriptor> result = new ArrayList<ClassDescriptor>();
|
||||
DeclarationDescriptor outerClass = classDescriptor.getContainingDeclaration();
|
||||
while (outerClass instanceof ClassDescriptor) {
|
||||
result.add((ClassDescriptor) outerClass);
|
||||
outerClass = outerClass.getContainingDeclaration();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int getAccessModifiers(JetDeclaration p, int defaultFlags) {
|
||||
int flags = 0;
|
||||
if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
class Outer(val foo: StringBuilder) {
|
||||
class Inner() {
|
||||
fun len() {
|
||||
return foo.length()
|
||||
}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
return new Inner()
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val sb = new StringBuilder("xyzzy")
|
||||
val o = new Outer(sb)
|
||||
val i = o.test()
|
||||
val l = i.len()
|
||||
return if (l != 5) "fail" else "OK"
|
||||
}
|
||||
@@ -58,4 +58,8 @@ public class ClassGenTest extends CodegenTestCase {
|
||||
final Integer returnValue = (Integer) method.invoke(null);
|
||||
assertEquals(610, returnValue.intValue());
|
||||
}
|
||||
|
||||
public void testInnerClass() throws Exception {
|
||||
blackBoxFile("classes/innerClass.jet");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,14 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
protected void blackBoxFile(String filename) throws Exception {
|
||||
loadFile(filename);
|
||||
//System.out.println(generateToText());
|
||||
assertEquals("OK", blackBox());
|
||||
String actual;
|
||||
try {
|
||||
actual = blackBox();
|
||||
} catch (Exception e) {
|
||||
System.out.println(generateToText());
|
||||
throw e;
|
||||
}
|
||||
assertEquals("OK", actual);
|
||||
}
|
||||
|
||||
protected String blackBox() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user