Merge pull request #95 from udalov/kt2224

object literals now capture expressions from 'by' delegate specifier
This commit is contained in:
Alex Tkachman
2012-07-09 04:19:38 -07:00
4 changed files with 97 additions and 28 deletions
@@ -493,6 +493,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
constructorMethod = callableMethod.getSignature();
}
if (context.closure != null) {
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
if (specifier != superCall && specifier instanceof JetDelegatorByExpressionSpecifier) {
JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
delegateExpression.accept(new JetVisitorVoid() {
@Override
public void visitJetElement(JetElement e) {
e.acceptChildren(this);
}
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expr) {
context.closure.lookupInContext(bindingContext.get(BindingContext.REFERENCE_TARGET, expr), null);
}
});
}
}
}
ObjectOrClosureCodegen closure = context.closure;
int firstSuperArgument = -1;
final LinkedList<JvmMethodParameterSignature> consArgTypes = new LinkedList<JvmMethodParameterSignature>(constructorMethod.getKotlinParameterTypes());
@@ -638,33 +657,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateDelegatorToConstructorCall(iv, codegen, (JetDelegatorToSuperCall) superCall, constructorDescriptor1, frameMap, firstSuperArgument);
}
int n = 0;
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
if (specifier == superCall)
continue;
if (specifier instanceof JetDelegatorByExpressionSpecifier) {
iv.load(0, classType);
codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression());
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
String delegateField = "$delegate_" + (n++);
Type fieldType = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.VALUE);
String fieldDesc = fieldType.getDescriptor();
v.newField(specifier, ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null);
StackValue field = StackValue.field(fieldType, classname, delegateField, false);
field.store(fieldType, iv);
JetClass superClass = (JetClass) BindingContextUtils.classDescriptorToDeclaration(bindingContext, superClassDescriptor);
final CodegenContext delegateContext = context.intoClass(superClassDescriptor,
new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false),
typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName()), state.getInjector().getJetTypeMapper());
generateDelegates(superClass, delegateContext, field);
}
}
final ClassDescriptor outerDescriptor = typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor);
final boolean hasOuterThis = typeMapper.hasThis0(descriptor) && outerDescriptor != null;
if (hasOuterThis) {
@@ -702,6 +694,33 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
int n = 0;
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
if (specifier == superCall)
continue;
if (specifier instanceof JetDelegatorByExpressionSpecifier) {
iv.load(0, classType);
codegen.genToJVMStack(((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression());
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
String delegateField = "$delegate_" + (n++);
Type fieldType = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.VALUE);
String fieldDesc = fieldType.getDescriptor();
v.newField(specifier, ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null);
StackValue field = StackValue.field(fieldType, classname, delegateField, false);
field.store(fieldType, iv);
JetClass superClass = (JetClass) BindingContextUtils.classDescriptorToDeclaration(bindingContext, superClassDescriptor);
final CodegenContext delegateContext = context.intoClass(superClassDescriptor,
new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false),
typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName()), state.getInjector().getJetTypeMapper());
generateDelegates(superClass, delegateContext, field);
}
}
int curParam = 0;
List<JetParameter> constructorParameters = getPrimaryConstructorParameters();
for (JetParameter parameter : constructorParameters) {
@@ -16,6 +16,7 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
import org.jetbrains.jet.lang.psi.JetElement;
@@ -48,7 +49,7 @@ public class ObjectOrClosureCodegen {
this.state = state;
}
public StackValue lookupInContext(DeclarationDescriptor d, StackValue result) {
public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result) {
EnclosedValueDescriptor answer = closure.get(d);
if (answer != null) {
StackValue innerValue = answer.getInnerValue();
@@ -0,0 +1,44 @@
trait A {
fun foo(): Int
}
class B1 : A {
override fun foo() = 10
}
class B2(val z: Int) : A {
override fun foo() = z
}
fun f1(b: B1): Int {
val o = object : A by b { }
return o.foo()
}
fun f2(b: B2): Int {
val o = object : A by B2(b.z) { }
return o.foo()
}
fun f3(b: B2, mult: Int): Int {
val o = object : A by B2(mult * b.z) { }
return o.foo()
}
fun f4(b: B1, x: Int, y: Int, z: Int): Int {
val o = object : A by b {
fun bar() = x + y + z
}
return o.foo()
}
fun box(): String {
if (f1(B1()) != 10) return "fail #1"
if (f2(B2(239)) != 239) return "fail #2"
if (f3(B2(239), 2) != 239*2) return "fail #3"
if (f4(B1(), 1, 2, 3) != 10) return "fail #4"
return "OK"
}
@@ -446,4 +446,9 @@ public class ClassGenTest extends CodegenTestCase {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
blackBoxFile("regressions/kt1891.kt");
}
public void testKt2224() {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
blackBoxFile("regressions/kt2224.kt");
}
}