Correctly apply SAM conversions in superclass constructor calls

#KT-5452 Fixed
This commit is contained in:
Dmitry Jemerov
2015-03-25 15:13:47 +01:00
parent da9fe7d9a9
commit 827d9d48c1
16 changed files with 117 additions and 11 deletions
@@ -1446,9 +1446,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (superCall != null) {
// For an anonymous object, we should also generate all non-default arguments that it captures for its super call
ConstructorDescriptor superConstructor = superCall.getResultingDescriptor();
ConstructorDescriptor constructorToCall = SamCodegenUtil.resolveSamAdapter(superConstructor);
List<ValueParameterDescriptor> superValueParameters = superConstructor.getValueParameters();
int params = superValueParameters.size();
List<Type> superMappedTypes = typeMapper.mapToCallableMethod(superConstructor).getValueParameterTypes();
List<Type> superMappedTypes = typeMapper.mapToCallableMethod(constructorToCall).getValueParameterTypes();
assert superMappedTypes.size() >= params : String
.format("Incorrect number of mapped parameters vs arguments: %d < %d for %s",
superMappedTypes.size(), params, classDescriptor);
@@ -1474,7 +1475,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
assert constructors.size() == 1 : "Unexpected number of constructors for class: " + classDescriptor + " " + constructors;
ConstructorDescriptor constructorDescriptor = KotlinPackage.single(constructors);
JvmMethodSignature constructor = typeMapper.mapSignature(constructorDescriptor);
JvmMethodSignature constructor = typeMapper.mapSignature(SamCodegenUtil.resolveSamAdapter(constructorDescriptor));
v.invokespecial(type.getInternalName(), "<init>", constructor.getAsmMethod().getDescriptor(), false);
return Unit.INSTANCE$;
}
@@ -2313,8 +2314,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull
private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull CodegenContext context) {
SimpleFunctionDescriptor originalOfSamAdapter = (SimpleFunctionDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(fd);
return typeMapper.mapToCallableMethod(originalOfSamAdapter != null ? originalOfSamAdapter : fd, superCall, context);
return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), superCall, context);
}
public void invokeMethodWithArguments(
@@ -3593,8 +3593,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
// See StackValue.receiver for more info
pushClosureOnStack(constructor.getContainingDeclaration(), dispatchReceiver == null, defaultCallGenerator);
ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructor);
CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructor : originalOfSamAdapter);
constructor = SamCodegenUtil.resolveSamAdapter(constructor);
CallableMethod method = typeMapper.mapToCallableMethod(constructor);
invokeMethodWithArguments(method, resolvedCall, StackValue.none());
return Unit.INSTANCE$;
@@ -1466,7 +1466,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return;
}
iv.load(0, OBJECT_TYPE);
ConstructorDescriptor delegateConstructor = delegationConstructorCall.getResultingDescriptor();
ConstructorDescriptor delegateConstructor = SamCodegenUtil.resolveSamAdapter(delegationConstructorCall.getResultingDescriptor());
CallableMethod delegateConstructorCallable = typeMapper.mapToCallableMethod(delegateConstructor);
CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor);
@@ -42,6 +42,11 @@ public class SamCodegenUtil {
return null;
}
public static <T extends FunctionDescriptor> T resolveSamAdapter(@NotNull T descriptor) {
FunctionDescriptor original = getOriginalIfSamAdapter(descriptor);
return original != null ? (T) original : descriptor;
}
private SamCodegenUtil() {
}
}
@@ -386,6 +386,10 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
@Override
public void visitCallExpression(@NotNull JetCallExpression expression) {
super.visitCallExpression(expression);
checkSamCall(expression);
}
private void checkSamCall(@NotNull JetCallElement expression) {
ResolvedCall<?> call = CallUtilPackage.getResolvedCall(expression, bindingContext);
if (call == null) return;
@@ -416,7 +420,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
}
}
private void recordSamConstructorIfNeeded(@NotNull JetCallExpression expression, @NotNull ResolvedCall<?> call) {
@Override
public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) {
super.visitDelegationToSuperCallSpecifier(call);
checkSamCall(call);
}
private void recordSamConstructorIfNeeded(@NotNull JetCallElement expression, @NotNull ResolvedCall<?> call) {
CallableDescriptor callableDescriptor = call.getResultingDescriptor();
if (!(callableDescriptor.getOriginal() instanceof SamConstructorDescriptor)) return;
@@ -62,7 +62,7 @@ public class CodegenBinding {
public static final WritableSlice<JetExpression, SamType> SAM_VALUE = Slices.createSimpleSlice();
public static final WritableSlice<JetCallExpression, JetExpression> SAM_CONSTRUCTOR_TO_ARGUMENT = Slices.createSimpleSlice();
public static final WritableSlice<JetCallElement, JetExpression> SAM_CONSTRUCTOR_TO_ARGUMENT = Slices.createSimpleSlice();
public static final WritableSlice<JetWhenExpression, WhenByEnumsMapping> MAPPING_FOR_WHEN_BY_ENUM =
Slices.<JetWhenExpression, WhenByEnumsMapping>sliceBuilder().build();
@@ -924,7 +924,7 @@ public class JetTypeMapper {
@NotNull ResolvedCall<ConstructorDescriptor> superCall,
boolean hasOuter
) {
ConstructorDescriptor superDescriptor = superCall.getResultingDescriptor();
ConstructorDescriptor superDescriptor = SamCodegenUtil.resolveSamAdapter(superCall.getResultingDescriptor());
List<ResolvedValueArgument> valueArguments = superCall.getValueArgumentsByIndex();
assert valueArguments != null : "Failed to arrange value arguments by index: " + superDescriptor;
@@ -0,0 +1,11 @@
class JavaClass {
private Runnable r;
public JavaClass(Runnable r) {
this.r = r;
}
public void run() {
r.run();
}
}
@@ -0,0 +1,8 @@
var status: String = "fail" // global property to avoid issues with accessing closure from local class (KT-4174)
fun box(): String {
class C() : JavaClass({status = "OK"}) {}
C().run()
return status
}
@@ -0,0 +1,11 @@
class JavaClass {
private Runnable r;
public JavaClass(Runnable r) {
this.r = r;
}
public void run() {
r.run();
}
}
@@ -0,0 +1,6 @@
fun box(): String {
var v = "FAIL"
val x = object : JavaClass({-> v = "OK"}) {}
x.run()
return v
}
@@ -0,0 +1,11 @@
class JavaClass {
private Runnable r;
public JavaClass(Runnable r) {
this.r = r;
}
public void run() {
r.run();
}
}
@@ -0,0 +1,7 @@
fun box(): String {
var v = "FAIL"
val f = {-> v = "OK"}
val x = object : JavaClass(f) {}
x.run()
return v
}
@@ -0,0 +1,5 @@
class JavaClass {
JavaClass(Runnable r) {
if (r != null) r.run();
}
}
@@ -0,0 +1,9 @@
var status: String = "fail" // global property to avoid issues with accessing closure from local class (KT-4174)
class KotlinClass(): JavaClass({status="OK"}) {
}
fun box(): String {
KotlinClass()
return status
}
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.kotlin.codegen.CodegenTestCase;
import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.InlineTestUtil;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.test.ConfigurationKind;
@@ -499,6 +499,24 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
doTestAgainstJava(fileName);
}
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/sam/adapters/localClass.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("localObjectConstructor.kt")
public void testLocalObjectConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/sam/adapters/localObjectConstructor.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("localObjectConstructorWithFnValue.kt")
public void testLocalObjectConstructorWithFnValue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/sam/adapters/localObjectConstructorWithFnValue.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("nonLiteralAndLiteralRunnable.kt")
public void testNonLiteralAndLiteralRunnable() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/sam/adapters/nonLiteralAndLiteralRunnable.kt");
@@ -547,6 +565,12 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
doTestAgainstJava(fileName);
}
@TestMetadata("superconstructorWithClosure.kt")
public void testSuperconstructorWithClosure() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/sam/adapters/superconstructorWithClosure.kt");
doTestAgainstJava(fileName);
}
@TestMetadata("typeParameterOfClass.kt")
public void testTypeParameterOfClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/sam/adapters/typeParameterOfClass.kt");