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:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user