Fix for KT-3584: Wrong bytecode generated for local class with default parameters and captured local val

#KT-3584 Fixed
This commit is contained in:
Michael Bogdanov
2014-10-06 17:09:45 +04:00
parent 989cae9f1f
commit d0d207f387
4 changed files with 33 additions and 5 deletions
@@ -25,6 +25,7 @@ import com.intellij.util.containers.ContainerUtil;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.bridges.Bridge;
import org.jetbrains.jet.codegen.bridges.BridgesPackage;
@@ -36,6 +37,7 @@ import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
@@ -514,9 +516,10 @@ public class FunctionCodegen extends ParentCodegenAware {
@NotNull GenerationState state,
@NotNull CallableMethod method,
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull ClassBuilder classBuilder
@NotNull ClassBuilder classBuilder,
@NotNull JetClassOrObject classOrObject
) {
if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
if (!isEmptyConstructorNeeded(state.getBindingContext(), constructorDescriptor, classOrObject)) {
return;
}
int flags = getVisibilityAccessFlag(constructorDescriptor);
@@ -550,7 +553,7 @@ public class FunctionCodegen extends ParentCodegenAware {
String desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false);
v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false);
v.areturn(Type.VOID_TYPE);
endVisit(mv, "default constructor for " + methodOwner.getInternalName(), null);
endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject);
}
void generateDefaultIfNeeded(
@@ -739,9 +742,15 @@ public class FunctionCodegen extends ParentCodegenAware {
return needed;
}
private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
private static boolean isEmptyConstructorNeeded(
@NotNull BindingContext context,
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull JetClassOrObject classOrObject
) {
ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
if (classOrObject.isLocal()) return false;
if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
@@ -1151,7 +1151,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
DefaultParameterValueLoader.DEFAULT, null);
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor);
FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v);
FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v, myClass);
if (isClassObject(descriptor)) {
context.recordSyntheticAccessorIfNeeded(constructorDescriptor, bindingContext);
@@ -0,0 +1,13 @@
fun box(): String {
val s = "captured";
class A(val param: String = "OK") {
val s2 = s + param
}
if (A().s2 != "capturedOK") return "fail 1: ${A().s2}"
if (A("Test").s2 != "capturedTest") return "fail 1: ${A("Test").s2}"
return "OK"
}
@@ -4151,6 +4151,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt3584.kt")
public void testKt3584() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/kt3584.kt");
doTest(fileName);
}
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/localClass.kt");