first step of refactoring code to generate 'this' expressions and receivers in ExpressionCodegen; correctly generate references to outer class properties in inner superclass constructor call

This commit is contained in:
Dmitry Jemerov
2011-05-30 20:35:58 +04:00
parent e616c38a9f
commit 15f55d852d
6 changed files with 57 additions and 29 deletions
@@ -25,9 +25,7 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.*;
/**
* @author max
@@ -66,28 +64,33 @@ public class ExpressionCodegen extends JetVisitor {
private final InstructionAdapter v;
private final FrameMap myMap;
private final JetTypeMapper typeMapper;
private final JetType receiverType;
private final Type returnType;
private final DeclarationDescriptor contextType;
private final OwnerKind contextKind;
private final BindingContext bindingContext;
private final StackValue thisExpression;
private final Map<ClassDescriptor, StackValue> outerThisExpressions = new HashMap<ClassDescriptor, StackValue>();
public ExpressionCodegen(MethodVisitor v,
BindingContext bindingContext,
FrameMap myMap,
JetTypeMapper typeMapper,
JetType receiverType,
Type returnType,
DeclarationDescriptor contextType,
OwnerKind contextKind) {
OwnerKind contextKind,
@Nullable StackValue thisExpression) {
this.myMap = myMap;
this.typeMapper = typeMapper;
this.receiverType = receiverType;
this.returnType = returnType;
this.contextType = contextType;
this.contextKind = contextKind;
this.v = new InstructionAdapter(v);
this.bindingContext = bindingContext;
this.thisExpression = thisExpression;
}
public void addOuterThis(ClassDescriptor outer, StackValue expression) {
outerThisExpressions.put(outer, expression);
}
static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) {
@@ -772,12 +775,18 @@ public class ExpressionCodegen extends JetVisitor {
}
public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
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.IMPLEMENTATION).getDescriptor());
// TODO handle more levels of class nestng
final StackValue value = outerThisExpressions.get(calleeContainingClass);
if (value != null) {
value.put(value.type, v);
}
else {
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.IMPLEMENTATION).getDescriptor());
// TODO handle more levels of class nestng
}
}
}
@@ -1418,19 +1427,16 @@ public class ExpressionCodegen extends JetVisitor {
}
private void generateThis() {
if (contextKind == OwnerKind.NAMESPACE) {
if (receiverType != null) {
myStack.push(StackValue.local(0, typeMapper.mapType(receiverType)));
}
else {
throw new UnsupportedOperationException("Cannot generate this expression in top level context");
}
if (thisExpression != null) {
myStack.push(thisExpression);
return;
}
else {
if (contextKind == OwnerKind.NAMESPACE) {
ClassDescriptor contextClass = (ClassDescriptor) contextType;
final Type thisType = typeMapper.jvmType(contextClass, contextKind);
if (contextKind == OwnerKind.IMPLEMENTATION) {
myStack.push(StackValue.local(0, thisType));
return;
}
else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) {
v.load(0, thisType);
@@ -1438,11 +1444,10 @@ public class ExpressionCodegen extends JetVisitor {
thisType.getInternalName(),
"$this",
false));
}
else {
throw new UnsupportedOperationException("Unknown kind: " + contextKind);
return;
}
}
throw new UnsupportedOperationException("'this' expression is not defined in the context");
}
@Override
@@ -77,8 +77,9 @@ public class FunctionCodegen {
frameMap.enter(parameter, argTypes[i].getSize());
}
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, receiverType,
jvmSignature.getReturnType(), contextDescriptor, kind);
StackValue thisExpression = receiverType == null ? null : StackValue.local(0, typeMapper.mapType(receiverType));
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper,
jvmSignature.getReturnType(), contextDescriptor, kind, thisExpression);
if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -87,7 +87,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
frameMap.enterTemp(); // this
final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, descriptor, kind);
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE,
descriptor, kind, StackValue.local(0, typeMapper.jvmType(descriptor, kind)));
String classname = typeMapper.jvmName(descriptor, kind);
final Type classType = Type.getType("L" + classname + ";");
@@ -108,11 +109,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
}
int index = 1; // this
int index = 1; // 0 = this
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
if (outerDescriptor instanceof ClassDescriptor) {
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
codegen.addOuterThis(outerClassDescriptor, StackValue.local(1, type));
String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0";
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
@@ -75,7 +75,7 @@ public class NamespaceCodegen {
FrameMap frameMap = new FrameMap();
JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext);
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, null, Type.VOID_TYPE, null, OwnerKind.NAMESPACE);
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, Type.VOID_TYPE, null, OwnerKind.NAMESPACE, null);
for (JetDeclaration declaration : namespace.getDeclarations()) {
if (declaration instanceof JetProperty) {
@@ -0,0 +1,16 @@
class Outer() {
public val s = "xyzzy"
class InnerBase(public val name: String) {
}
class InnerDerived(): InnerBase(s) {
}
public val x = new InnerDerived()
}
fun box() {
val o = new Outer()
return if (o.x.name != "xyzzy") "fail" else "OK"
}
@@ -87,4 +87,8 @@ public class ClassGenTest extends CodegenTestCase {
public void testInitializerBlockDImpl() throws Exception {
blackBoxFile("classes/initializerBlockDImpl.jet");
}
public void testPropertyInInitializer() throws Exception {
blackBoxFile("classes/propertyInInitializer.jet");
}
}