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.InstructionAdapter;
|
||||||
import org.objectweb.asm.commons.Method;
|
import org.objectweb.asm.commons.Method;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
@@ -66,28 +64,33 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
private final InstructionAdapter v;
|
private final InstructionAdapter v;
|
||||||
private final FrameMap myMap;
|
private final FrameMap myMap;
|
||||||
private final JetTypeMapper typeMapper;
|
private final JetTypeMapper typeMapper;
|
||||||
private final JetType receiverType;
|
|
||||||
private final Type returnType;
|
private final Type returnType;
|
||||||
private final DeclarationDescriptor contextType;
|
private final DeclarationDescriptor contextType;
|
||||||
private final OwnerKind contextKind;
|
private final OwnerKind contextKind;
|
||||||
private final BindingContext bindingContext;
|
private final BindingContext bindingContext;
|
||||||
|
private final StackValue thisExpression;
|
||||||
|
private final Map<ClassDescriptor, StackValue> outerThisExpressions = new HashMap<ClassDescriptor, StackValue>();
|
||||||
|
|
||||||
public ExpressionCodegen(MethodVisitor v,
|
public ExpressionCodegen(MethodVisitor v,
|
||||||
BindingContext bindingContext,
|
BindingContext bindingContext,
|
||||||
FrameMap myMap,
|
FrameMap myMap,
|
||||||
JetTypeMapper typeMapper,
|
JetTypeMapper typeMapper,
|
||||||
JetType receiverType,
|
|
||||||
Type returnType,
|
Type returnType,
|
||||||
DeclarationDescriptor contextType,
|
DeclarationDescriptor contextType,
|
||||||
OwnerKind contextKind) {
|
OwnerKind contextKind,
|
||||||
|
@Nullable StackValue thisExpression) {
|
||||||
this.myMap = myMap;
|
this.myMap = myMap;
|
||||||
this.typeMapper = typeMapper;
|
this.typeMapper = typeMapper;
|
||||||
this.receiverType = receiverType;
|
|
||||||
this.returnType = returnType;
|
this.returnType = returnType;
|
||||||
this.contextType = contextType;
|
this.contextType = contextType;
|
||||||
this.contextKind = contextKind;
|
this.contextKind = contextKind;
|
||||||
this.v = new InstructionAdapter(v);
|
this.v = new InstructionAdapter(v);
|
||||||
this.bindingContext = bindingContext;
|
this.bindingContext = bindingContext;
|
||||||
|
this.thisExpression = thisExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addOuterThis(ClassDescriptor outer, StackValue expression) {
|
||||||
|
outerThisExpressions.put(outer, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) {
|
static void loadTypeInfo(ClassDescriptor descriptor, InstructionAdapter v) {
|
||||||
@@ -772,12 +775,18 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
|
public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
|
||||||
v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :)
|
final StackValue value = outerThisExpressions.get(calleeContainingClass);
|
||||||
if (calleeContainingClass != null && contextType instanceof ClassDescriptor &&
|
if (value != null) {
|
||||||
calleeContainingClass == contextType.getContainingDeclaration()) {
|
value.put(value.type, v);
|
||||||
v.getfield(typeMapper.jvmName((ClassDescriptor) contextType, OwnerKind.IMPLEMENTATION),
|
}
|
||||||
"this$0", typeMapper.jvmType(calleeContainingClass, OwnerKind.IMPLEMENTATION).getDescriptor());
|
else {
|
||||||
// TODO handle more levels of class nestng
|
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() {
|
private void generateThis() {
|
||||||
if (contextKind == OwnerKind.NAMESPACE) {
|
if (thisExpression != null) {
|
||||||
if (receiverType != null) {
|
myStack.push(thisExpression);
|
||||||
myStack.push(StackValue.local(0, typeMapper.mapType(receiverType)));
|
return;
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new UnsupportedOperationException("Cannot generate this expression in top level context");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
if (contextKind == OwnerKind.NAMESPACE) {
|
||||||
ClassDescriptor contextClass = (ClassDescriptor) contextType;
|
ClassDescriptor contextClass = (ClassDescriptor) contextType;
|
||||||
final Type thisType = typeMapper.jvmType(contextClass, contextKind);
|
final Type thisType = typeMapper.jvmType(contextClass, contextKind);
|
||||||
if (contextKind == OwnerKind.IMPLEMENTATION) {
|
if (contextKind == OwnerKind.IMPLEMENTATION) {
|
||||||
myStack.push(StackValue.local(0, thisType));
|
myStack.push(StackValue.local(0, thisType));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
else if (contextKind == OwnerKind.DELEGATING_IMPLEMENTATION) {
|
||||||
v.load(0, thisType);
|
v.load(0, thisType);
|
||||||
@@ -1438,11 +1444,10 @@ public class ExpressionCodegen extends JetVisitor {
|
|||||||
thisType.getInternalName(),
|
thisType.getInternalName(),
|
||||||
"$this",
|
"$this",
|
||||||
false));
|
false));
|
||||||
}
|
return;
|
||||||
else {
|
|
||||||
throw new UnsupportedOperationException("Unknown kind: " + contextKind);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new UnsupportedOperationException("'this' expression is not defined in the context");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -77,8 +77,9 @@ public class FunctionCodegen {
|
|||||||
frameMap.enter(parameter, argTypes[i].getSize());
|
frameMap.enter(parameter, argTypes[i].getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, receiverType,
|
StackValue thisExpression = receiverType == null ? null : StackValue.local(0, typeMapper.mapType(receiverType));
|
||||||
jvmSignature.getReturnType(), contextDescriptor, kind);
|
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper,
|
||||||
|
jvmSignature.getReturnType(), contextDescriptor, kind, thisExpression);
|
||||||
if (kind instanceof OwnerKind.DelegateKind) {
|
if (kind instanceof OwnerKind.DelegateKind) {
|
||||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
frameMap.enterTemp(); // this
|
frameMap.enterTemp(); // this
|
||||||
|
|
||||||
final InstructionAdapter iv = new InstructionAdapter(mv);
|
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);
|
String classname = typeMapper.jvmName(descriptor, kind);
|
||||||
final Type classType = Type.getType("L" + classname + ";");
|
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");
|
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 1; // this
|
int index = 1; // 0 = this
|
||||||
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
|
final DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
|
||||||
if (outerDescriptor instanceof ClassDescriptor) {
|
if (outerDescriptor instanceof ClassDescriptor) {
|
||||||
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
|
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
|
||||||
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
|
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
|
||||||
|
codegen.addOuterThis(outerClassDescriptor, StackValue.local(1, type));
|
||||||
String interfaceDesc = type.getDescriptor();
|
String interfaceDesc = type.getDescriptor();
|
||||||
final String fieldName = "this$0";
|
final String fieldName = "this$0";
|
||||||
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
|
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public class NamespaceCodegen {
|
|||||||
|
|
||||||
FrameMap frameMap = new FrameMap();
|
FrameMap frameMap = new FrameMap();
|
||||||
JetTypeMapper typeMapper = new JetTypeMapper(JetStandardLibrary.getJetStandardLibrary(namespace.getProject()), bindingContext);
|
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()) {
|
for (JetDeclaration declaration : namespace.getDeclarations()) {
|
||||||
if (declaration instanceof JetProperty) {
|
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 {
|
public void testInitializerBlockDImpl() throws Exception {
|
||||||
blackBoxFile("classes/initializerBlockDImpl.jet");
|
blackBoxFile("classes/initializerBlockDImpl.jet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPropertyInInitializer() throws Exception {
|
||||||
|
blackBoxFile("classes/propertyInInitializer.jet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user