KT-31908 Handle SAM conversion on vararg elements
This commit is contained in:
@@ -32,17 +32,31 @@ import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
public class SamType {
|
||||
@Nullable
|
||||
public static SamType createByValueParameter(@NotNull ValueParameterDescriptor valueParameter) {
|
||||
KotlinType singleArgumentType;
|
||||
KotlinType originalSingleArgumentType;
|
||||
KotlinType varargElementType = valueParameter.getVarargElementType();
|
||||
if (varargElementType != null) {
|
||||
singleArgumentType = varargElementType;
|
||||
originalSingleArgumentType = valueParameter.getOriginal().getVarargElementType();
|
||||
assert originalSingleArgumentType != null :
|
||||
"Value parameter and original value parameter have inconsistent varargs: " +
|
||||
valueParameter + "; " + valueParameter.getOriginal();
|
||||
} else {
|
||||
singleArgumentType = valueParameter.getType();
|
||||
originalSingleArgumentType = valueParameter.getOriginal().getType();
|
||||
}
|
||||
|
||||
KotlinType originalTypeToUse =
|
||||
// This can be true in case when the value parameter is in the method of a generic type with out-projection.
|
||||
// We approximate Inv<Captured#1> to Nothing, while Inv itself can be a SAM interface safe to call here
|
||||
// (see testData genericSamProjectedOut.kt for details)
|
||||
KotlinBuiltIns.isNothing(valueParameter.getType())
|
||||
KotlinBuiltIns.isNothing(singleArgumentType)
|
||||
// In such a case we can't have a proper supertype since wildcards are not allowed there,
|
||||
// so we use Nothing arguments instead that leads to a raw type used for a SAM wrapper.
|
||||
// See org.jetbrains.kotlin.codegen.state.KotlinTypeMapper#writeGenericType to understand how
|
||||
// raw types and Nothing arguments relate.
|
||||
? TypeUtilsKt.replaceArgumentsWithNothing(valueParameter.getOriginal().getType())
|
||||
: valueParameter.getType();
|
||||
? TypeUtilsKt.replaceArgumentsWithNothing(originalSingleArgumentType)
|
||||
: singleArgumentType;
|
||||
|
||||
return create(TypeMapperUtilsKt.removeExternalProjections(originalTypeToUse));
|
||||
}
|
||||
|
||||
+46
-28
@@ -42,10 +42,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.NewVariableAsFunctionResolvedCallImpl;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
@@ -799,12 +796,16 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
CallableDescriptor descriptor = call.getResultingDescriptor();
|
||||
if (!(descriptor instanceof FunctionDescriptor)) return;
|
||||
|
||||
recordSamValueForNewInference(call);
|
||||
recordSamValuesForNewInference(call);
|
||||
recordSamConstructorIfNeeded(expression, call);
|
||||
recordSamValuesForOldInference(call, descriptor);
|
||||
}
|
||||
|
||||
private void recordSamValuesForOldInference(ResolvedCall<?> call, CallableDescriptor descriptor) {
|
||||
FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) descriptor);
|
||||
if (original == null) return;
|
||||
|
||||
// TODO we can just record SAM_VALUE on relevant value arguments as we do in recordSamValuesForNewInference
|
||||
List<ValueParameterDescriptor> valueParametersWithSAMConversion = new SmartList<>();
|
||||
for (ValueParameterDescriptor valueParameter : original.getValueParameters()) {
|
||||
ValueParameterDescriptor adaptedParameter = descriptor.getValueParameters().get(valueParameter.getIndex());
|
||||
@@ -814,30 +815,43 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
writeSamValueForValueParameters(valueParametersWithSAMConversion, call.getValueArgumentsByIndex());
|
||||
}
|
||||
|
||||
private void recordSamValueForNewInference(@NotNull ResolvedCall<?> call) {
|
||||
NewResolvedCallImpl<?> newResolvedCall = null;
|
||||
if (call instanceof NewVariableAsFunctionResolvedCallImpl) {
|
||||
newResolvedCall = ((NewVariableAsFunctionResolvedCallImpl) call).getFunctionCall();
|
||||
}
|
||||
else if(call instanceof NewResolvedCallImpl) {
|
||||
newResolvedCall = (NewResolvedCallImpl<?>) call;
|
||||
}
|
||||
private void recordSamValuesForNewInference(@NotNull ResolvedCall<?> call) {
|
||||
NewResolvedCallImpl<?> newResolvedCall = getNewResolvedCallForCallWithPossibleSamConversions(call);
|
||||
if (newResolvedCall == null) return;
|
||||
|
||||
List<ValueParameterDescriptor> valueParametersWithSAMConversion = new SmartList<>();
|
||||
Map<ValueParameterDescriptor, ResolvedValueArgument> arguments = newResolvedCall.getValueArguments();
|
||||
for (ValueParameterDescriptor valueParameter : arguments.keySet()) {
|
||||
SamType samType = SamType.createByValueParameter(valueParameter);
|
||||
if (samType == null) continue;
|
||||
|
||||
ResolvedValueArgument argument = arguments.get(valueParameter);
|
||||
|
||||
if (!(argument instanceof ExpressionValueArgument)) continue;
|
||||
ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument();
|
||||
|
||||
if (valueArgument == null || newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) == null) continue;
|
||||
|
||||
valueParametersWithSAMConversion.add(valueParameter);
|
||||
if (argument instanceof ExpressionValueArgument) {
|
||||
ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument();
|
||||
if (valueArgument != null && newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) != null) {
|
||||
recordSamTypeOnArgumentExpression(samType, valueArgument);
|
||||
}
|
||||
} else if (argument instanceof VarargValueArgument) {
|
||||
VarargValueArgument varargValueArgument = (VarargValueArgument) argument;
|
||||
for (ValueArgument valueArgument : varargValueArgument.getArguments()) {
|
||||
if (valueArgument != null && newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) != null) {
|
||||
recordSamTypeOnArgumentExpression(samType, valueArgument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
writeSamValueForValueParameters(valueParametersWithSAMConversion, newResolvedCall.getValueArgumentsByIndex());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NewResolvedCallImpl<?> getNewResolvedCallForCallWithPossibleSamConversions(@NotNull ResolvedCall<?> call) {
|
||||
if (call instanceof NewVariableAsFunctionResolvedCallImpl) {
|
||||
return ((NewVariableAsFunctionResolvedCallImpl) call).getFunctionCall();
|
||||
}
|
||||
else if (call instanceof NewResolvedCallImpl) {
|
||||
return (NewResolvedCallImpl<?>) call;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeSamValueForValueParameters(
|
||||
@@ -854,13 +868,17 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
assert resolvedValueArgument instanceof ExpressionValueArgument : resolvedValueArgument;
|
||||
ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
|
||||
assert valueArgument != null;
|
||||
KtExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
assert argumentExpression != null : valueArgument.asElement().getText();
|
||||
|
||||
bindingTrace.record(CodegenBinding.SAM_VALUE, argumentExpression, samType);
|
||||
recordSamTypeOnArgumentExpression(samType, valueArgument);
|
||||
}
|
||||
}
|
||||
|
||||
private void recordSamTypeOnArgumentExpression(SamType samType, ValueArgument valueArgument) {
|
||||
KtExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
assert argumentExpression != null : valueArgument.asElement().getText();
|
||||
|
||||
bindingTrace.record(CodegenBinding.SAM_VALUE, argumentExpression, samType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSuperTypeCallEntry(@NotNull KtSuperTypeCallEntry call) {
|
||||
// Closures in super type constructor calls for anonymous objects are created in outer context
|
||||
@@ -942,7 +960,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
if (!(operationDescriptor instanceof FunctionDescriptor)) return;
|
||||
|
||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
|
||||
if (resolvedCall != null) recordSamValueForNewInference(resolvedCall);
|
||||
if (resolvedCall != null) recordSamValuesForNewInference(resolvedCall);
|
||||
|
||||
FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor);
|
||||
if (original == null) return;
|
||||
@@ -967,7 +985,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
if (!(operationDescriptor instanceof FunctionDescriptor)) return;
|
||||
|
||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
|
||||
if (resolvedCall != null) recordSamValueForNewInference(resolvedCall);
|
||||
if (resolvedCall != null) recordSamValuesForNewInference(resolvedCall);
|
||||
|
||||
boolean isSetter = operationDescriptor.getName().asString().equals("set");
|
||||
FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor);
|
||||
|
||||
Generated
+10
@@ -11205,6 +11205,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceInheritance.kt")
|
||||
public void testFunInterfaceInheritance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");
|
||||
@@ -28143,6 +28148,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/sam/kt24825.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt31908.kt")
|
||||
public void testKt31908() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt");
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument
|
||||
fun interface MyRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = "failed"
|
||||
val r = MyRunnable { result += "K" }
|
||||
foo({ result = "O" }, r)
|
||||
return result
|
||||
}
|
||||
|
||||
fun foo(vararg rs: MyRunnable) {
|
||||
for (r in rs) {
|
||||
r.run()
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: kt31908.kt
|
||||
fun box(): String {
|
||||
var result = "failed"
|
||||
val r = java.lang.Runnable { result += "K" }
|
||||
J().foo({ result = "O" }, r)
|
||||
return result
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
public class J {
|
||||
public void foo(Runnable... rs) {
|
||||
for (Runnable r : rs) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -12420,6 +12420,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceInheritance.kt")
|
||||
public void testFunInterfaceInheritance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");
|
||||
@@ -29729,6 +29734,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/sam/kt24825.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt31908.kt")
|
||||
public void testKt31908() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt");
|
||||
|
||||
+10
@@ -12425,6 +12425,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceWithReceiver.kt")
|
||||
public void testFunInterfaceWithReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceWithReceiver.kt");
|
||||
@@ -27363,6 +27368,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/sam/kt24825.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt31908.kt")
|
||||
public void testKt31908() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt");
|
||||
|
||||
+10
@@ -11205,6 +11205,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceInheritance.kt")
|
||||
public void testFunInterfaceInheritance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");
|
||||
@@ -28143,6 +28148,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/sam/kt24825.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt31908.kt")
|
||||
public void testKt31908() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/kt31908.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonInlinedSamWrapper.kt")
|
||||
public void testNonInlinedSamWrapper() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt");
|
||||
|
||||
Generated
+5
@@ -9605,6 +9605,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceInheritance.kt")
|
||||
public void testFunInterfaceInheritance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");
|
||||
|
||||
Generated
+5
@@ -9615,6 +9615,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceInheritance.kt")
|
||||
public void testFunInterfaceInheritance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");
|
||||
|
||||
+5
@@ -9615,6 +9615,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funConversionInVararg.kt")
|
||||
public void testFunConversionInVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funInterfaceInheritance.kt")
|
||||
public void testFunInterfaceInheritance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");
|
||||
|
||||
Reference in New Issue
Block a user