KT-4118 Closures mix makes code fail on runtime
#KT-4118 Fixed
This commit is contained in:
@@ -309,9 +309,9 @@ public class AsmUtil {
|
|||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
|
JetType captureReceiverType = closure.getCaptureReceiverType();
|
||||||
if (captureReceiver != null) {
|
if (captureReceiverType != null) {
|
||||||
v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiver).getDescriptor(),
|
v.newField(null, access, CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType).getDescriptor(),
|
||||||
null, null);
|
null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,9 +249,9 @@ public class ClosureCodegen extends ParentCodegenAwareImpl {
|
|||||||
Type type = typeMapper.mapType(captureThis);
|
Type type = typeMapper.mapType(captureThis);
|
||||||
args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
|
args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
|
||||||
}
|
}
|
||||||
ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
|
JetType captureReceiverType = closure.getCaptureReceiverType();
|
||||||
if (captureReceiver != null) {
|
if (captureReceiverType != null) {
|
||||||
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiver), CAPTURED_RECEIVER_FIELD));
|
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
|
for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
|
||||||
@@ -268,7 +268,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl {
|
|||||||
args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
|
args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof FunctionDescriptor) {
|
else if (descriptor instanceof FunctionDescriptor) {
|
||||||
assert captureReceiver != null;
|
assert captureReceiverType != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public class CodegenUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isConst(CalculatedClosure closure) {
|
public static boolean isConst(CalculatedClosure closure) {
|
||||||
return closure.getCaptureThis() == null && closure.getCaptureReceiver() == null && closure.getCaptureVariables().isEmpty();
|
return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T peekFromStack(Stack<T> stack) {
|
public static <T> T peekFromStack(Stack<T> stack) {
|
||||||
|
|||||||
@@ -1374,9 +1374,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
generateThisOrOuter(captureThis, false).put(OBJECT_TYPE, v);
|
generateThisOrOuter(captureThis, false).put(OBJECT_TYPE, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
|
JetType captureReceiver = closure.getCaptureReceiverType();
|
||||||
if (captureReceiver != null) {
|
if (captureReceiver != null) {
|
||||||
v.load(context.isStatic() ? 0 : 1, typeMapper.mapClass(captureReceiver));
|
v.load(context.isStatic() ? 0 : 1, typeMapper.mapType(captureReceiver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.asm4.Type;
|
import org.jetbrains.asm4.Type;
|
||||||
import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
|
import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
|
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -41,7 +41,7 @@ public interface CalculatedClosure {
|
|||||||
ClassDescriptor getCaptureThis();
|
ClassDescriptor getCaptureThis();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
ClassifierDescriptor getCaptureReceiver();
|
JetType getCaptureReceiverType();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables();
|
Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables();
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ import org.jetbrains.asm4.Type;
|
|||||||
import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
|
import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
|
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -72,10 +73,14 @@ public final class MutableClosure implements CalculatedClosure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassifierDescriptor getCaptureReceiver() {
|
public JetType getCaptureReceiverType() {
|
||||||
return captureReceiver
|
if (captureReceiver) {
|
||||||
? enclosingReceiverDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor()
|
ReceiverParameterDescriptor parameter = enclosingReceiverDescriptor.getReceiverParameter();
|
||||||
: null;
|
assert parameter != null : "Receiver parameter should exist in " + enclosingReceiverDescriptor;
|
||||||
|
return parameter.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCaptureReceiver() {
|
public void setCaptureReceiver() {
|
||||||
|
|||||||
@@ -812,10 +812,10 @@ public class JetTypeMapper extends BindingTraceAware {
|
|||||||
signatureWriter.writeParameterTypeEnd();
|
signatureWriter.writeParameterTypeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassifierDescriptor captureReceiver = closure != null ? closure.getCaptureReceiver() : null;
|
JetType captureReceiverType = closure != null ? closure.getCaptureReceiverType() : null;
|
||||||
if (captureReceiver != null) {
|
if (captureReceiverType != null) {
|
||||||
signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
|
signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
|
||||||
mapType(captureReceiver.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
|
mapType(captureReceiverType, signatureWriter, JetTypeMapperMode.VALUE);
|
||||||
signatureWriter.writeParameterTypeEnd();
|
signatureWriter.writeParameterTypeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
fun Array<String>.test1(): Array<String> {
|
||||||
|
val func = {(i:Int) -> this}
|
||||||
|
return func(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Array<String>.test1Nested(): Array<String> {
|
||||||
|
val func = {(i:Int) -> { this }()}
|
||||||
|
return func(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun Array<String>.test2() : Array<String> {
|
||||||
|
class Z2() {
|
||||||
|
fun run(): Array<String> {
|
||||||
|
this@test2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Z2().run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Array<String>.test2Nested() : Array<String> {
|
||||||
|
class Z2() {
|
||||||
|
fun run(): Array<String> {
|
||||||
|
class Z3 {
|
||||||
|
fun run(): Array<String> {
|
||||||
|
return this@test2Nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Z3().run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Z2().run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Array<String>.test3(): Array<String> {
|
||||||
|
fun local(): Array<String> {
|
||||||
|
this@test3
|
||||||
|
}
|
||||||
|
return local()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Array<String>.test3Nested(): Array<String> {
|
||||||
|
fun local(): Array<String> {
|
||||||
|
fun local2(): Array<String> {
|
||||||
|
this@test3Nested
|
||||||
|
}
|
||||||
|
return local2()
|
||||||
|
}
|
||||||
|
return local()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun Array<String>.test4() : Array<String> {
|
||||||
|
return object {
|
||||||
|
fun run() : Array<String> {
|
||||||
|
return this@test4
|
||||||
|
}
|
||||||
|
}.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Array<String>.test4Nested() : Array<String> {
|
||||||
|
return object {
|
||||||
|
fun run() : Array<String> {
|
||||||
|
return object {
|
||||||
|
fun run() : Array<String> {
|
||||||
|
return this@test4Nested
|
||||||
|
}
|
||||||
|
}.run()
|
||||||
|
}
|
||||||
|
}.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Array<DoubleArray>.test1(): Array<DoubleArray> {
|
||||||
|
val func = {(i:Int) -> this}
|
||||||
|
return func(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
val array = Array<String>(2, { i -> "${i}" })
|
||||||
|
if (array != array.test1()) return "fail 1"
|
||||||
|
if (array != array.test2()) return "fail 2"
|
||||||
|
if (array != array.test3()) return "fail 3"
|
||||||
|
if (array != array.test4()) return "fail 4"
|
||||||
|
|
||||||
|
if (array != array.test1Nested()) return "fail 1Nested"
|
||||||
|
if (array != array.test2Nested()) return "fail 2Nested"
|
||||||
|
if (array != array.test3Nested()) return "fail 3Nested"
|
||||||
|
if (array != array.test4Nested()) return "fail 4Nested"
|
||||||
|
|
||||||
|
val array2 = Array<DoubleArray>(2, { i -> DoubleArray(i) })
|
||||||
|
if (array2 != array2.test1()) return "fail on array of double []"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -2109,6 +2109,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest("compiler/testData/codegen/box/extensionFunctions/kt1953_class.kt");
|
doTest("compiler/testData/codegen/box/extensionFunctions/kt1953_class.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt4118.kt")
|
||||||
|
public void testKt4118() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/extensionFunctions/kt4118.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt475.kt")
|
@TestMetadata("kt475.kt")
|
||||||
public void testKt475() throws Exception {
|
public void testKt475() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/extensionFunctions/kt475.kt");
|
doTest("compiler/testData/codegen/box/extensionFunctions/kt475.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user