[NI] Handle vararg parameter in reflection type wrt array types
Vararg parameter in reflection type is interpreted as covariant
array type against array in expected functional type and as
vararg element type otherwise. For instance having function
fun foo(vararg args: Int): Unit { /*...*/ }
reference ::foo can be passed against expected
(Int) -> Unit,
(Int, Int) -> Unit, etc.
In none of such cases type for parameter in foo's reflection type
should be changed to array.
However, against expected type (IntArray) -> Unit args' type
must become IntArray.
^KT-25514 Fixed
This commit is contained in:
+5
@@ -23463,6 +23463,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargOfNothing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsArray.kt")
|
||||
public void testVarargViewedAsArray() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargsAndFunctionLiterals.kt")
|
||||
public void testVarargsAndFunctionLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargsAndFunctionLiterals.kt");
|
||||
|
||||
+61
-6
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastI
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.captureFromExpression
|
||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
@@ -178,7 +179,8 @@ class CallableReferencesCandidateFactory(
|
||||
candidateDescriptor,
|
||||
dispatchCallableReceiver,
|
||||
extensionCallableReceiver,
|
||||
expectedType
|
||||
expectedType,
|
||||
callComponents.builtIns
|
||||
)
|
||||
|
||||
if (defaults != 0 &&
|
||||
@@ -224,10 +226,15 @@ class CallableReferencesCandidateFactory(
|
||||
)
|
||||
}
|
||||
|
||||
private enum class VarargMappingState {
|
||||
UNMAPPED, MAPPED_WITH_PLAIN_ARGS, MAPPED_WITH_ARRAY
|
||||
}
|
||||
|
||||
private fun getArgumentAndReturnTypeUseMappingByExpectedType(
|
||||
descriptor: FunctionDescriptor,
|
||||
expectedType: UnwrappedType?,
|
||||
unboundReceiverCount: Int
|
||||
unboundReceiverCount: Int,
|
||||
builtins: KotlinBuiltIns
|
||||
): Triple<Array<KotlinType>, CoercionStrategy, Int>? {
|
||||
val inputOutputTypes = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType) ?: return null
|
||||
|
||||
@@ -244,13 +251,29 @@ class CallableReferencesCandidateFactory(
|
||||
* fun foo(a: A, b: B = B(), vararg c: C)
|
||||
*/
|
||||
var defaults = 0
|
||||
var varargMappingState = VarargMappingState.UNMAPPED
|
||||
val mappedArguments = arrayOfNulls<KotlinType?>(fakeArguments.size)
|
||||
|
||||
for ((valueParameter, resolvedArgument) in argumentMapping.parameterToCallArgumentMap) {
|
||||
for (fakeArgument in resolvedArgument.arguments) {
|
||||
val index = (fakeArgument as FakeKotlinCallArgumentForCallableReference).index
|
||||
val substitutedParameter = descriptor.valueParameters.getOrNull(valueParameter.index) ?: continue
|
||||
|
||||
mappedArguments[index] = substitutedParameter.varargElementType ?: substitutedParameter.type
|
||||
val mappedArgument: KotlinType?
|
||||
if (substitutedParameter.isVararg) {
|
||||
val (varargType, newVarargMappingState) = varargParameterTypeByExpectedParameter(
|
||||
inputOutputTypes.inputTypes[index],
|
||||
substitutedParameter,
|
||||
varargMappingState,
|
||||
builtins
|
||||
)
|
||||
varargMappingState = newVarargMappingState
|
||||
mappedArgument = varargType
|
||||
} else {
|
||||
mappedArgument = substitutedParameter.type
|
||||
}
|
||||
|
||||
mappedArguments[index] = mappedArgument
|
||||
}
|
||||
if (resolvedArgument == ResolvedCallArgument.DefaultArgument) defaults++
|
||||
}
|
||||
@@ -265,11 +288,42 @@ class CallableReferencesCandidateFactory(
|
||||
return Triple(mappedArguments as Array<KotlinType>, coercion, defaults)
|
||||
}
|
||||
|
||||
private fun varargParameterTypeByExpectedParameter(
|
||||
expectedParameterType: KotlinType,
|
||||
substitutedParameter: ValueParameterDescriptor,
|
||||
varargMappingState: VarargMappingState,
|
||||
builtins: KotlinBuiltIns
|
||||
): Pair<KotlinType?, VarargMappingState> {
|
||||
val elementType = substitutedParameter.varargElementType
|
||||
?: error("Vararg parameter $substitutedParameter does not have vararg type")
|
||||
|
||||
return when (varargMappingState) {
|
||||
VarargMappingState.UNMAPPED -> {
|
||||
if (KotlinBuiltIns.isArrayOrPrimitiveArray(expectedParameterType)) {
|
||||
val arrayType = builtins.getPrimitiveArrayKotlinTypeByPrimitiveKotlinType(elementType)
|
||||
?: builtins.getArrayType(Variance.OUT_VARIANCE, elementType)
|
||||
arrayType to VarargMappingState.MAPPED_WITH_ARRAY
|
||||
} else {
|
||||
elementType to VarargMappingState.MAPPED_WITH_PLAIN_ARGS
|
||||
}
|
||||
}
|
||||
VarargMappingState.MAPPED_WITH_PLAIN_ARGS -> {
|
||||
if (KotlinBuiltIns.isArrayOrPrimitiveArray(expectedParameterType))
|
||||
null to VarargMappingState.MAPPED_WITH_PLAIN_ARGS
|
||||
else
|
||||
elementType to VarargMappingState.MAPPED_WITH_PLAIN_ARGS
|
||||
}
|
||||
VarargMappingState.MAPPED_WITH_ARRAY ->
|
||||
null to VarargMappingState.MAPPED_WITH_ARRAY
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildReflectionType(
|
||||
descriptor: CallableDescriptor,
|
||||
dispatchReceiver: CallableReceiver?,
|
||||
extensionReceiver: CallableReceiver?,
|
||||
expectedType: UnwrappedType?
|
||||
expectedType: UnwrappedType?,
|
||||
builtins: KotlinBuiltIns
|
||||
): Pair<UnwrappedType, /*defaults*/ Int> {
|
||||
val argumentsAndReceivers = ArrayList<KotlinType>(descriptor.valueParameters.size + 2)
|
||||
|
||||
@@ -281,7 +335,7 @@ class CallableReferencesCandidateFactory(
|
||||
}
|
||||
|
||||
val descriptorReturnType = descriptor.returnType
|
||||
?: ErrorUtils.createErrorType("Error return type for descriptor: $descriptor")
|
||||
?: ErrorUtils.createErrorType("Error return type for descriptor: $descriptor")
|
||||
|
||||
when (descriptor) {
|
||||
is PropertyDescriptor -> {
|
||||
@@ -305,7 +359,8 @@ class CallableReferencesCandidateFactory(
|
||||
val defaults: Int
|
||||
val argumentsAndExpectedTypeCoercion = getArgumentAndReturnTypeUseMappingByExpectedType(
|
||||
descriptor, expectedType,
|
||||
unboundReceiverCount = argumentsAndReceivers.size
|
||||
unboundReceiverCount = argumentsAndReceivers.size,
|
||||
builtins = builtins
|
||||
)
|
||||
|
||||
if (argumentsAndExpectedTypeCoercion == null) {
|
||||
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
|
||||
fun sum(vararg args: Int): Int {
|
||||
var result = 0
|
||||
for (arg in args)
|
||||
result += arg
|
||||
return result
|
||||
}
|
||||
|
||||
fun nsum(vararg args: Number) = sum(*IntArray(args.size) { args[it].toInt() })
|
||||
|
||||
fun usePlainArgs(fn: (Int, Int) -> Int) = fn(1, 1)
|
||||
fun usePrimitiveArray(fn: (IntArray) -> Int) = fn(intArrayOf(1, 1, 1))
|
||||
fun useArray(fn: (Array<Int>) -> Int) = fn(arrayOf(1, 1, 1, 1))
|
||||
|
||||
fun box(): String {
|
||||
var result = usePlainArgs(::sum)
|
||||
if (result != 2)
|
||||
return "Fail: plain args $result != 2"
|
||||
result = usePrimitiveArray(::sum)
|
||||
if (result != 3)
|
||||
return "Fail: primitive array $result != 3"
|
||||
result = useArray(::nsum)
|
||||
if (result != 4)
|
||||
return "Fail: reference array $result != 4"
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+1
-2
@@ -1,4 +1,3 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@@ -10,7 +9,7 @@ expect fun foo(): String
|
||||
fun g(f: () -> String): String = f()
|
||||
|
||||
fun test() {
|
||||
g(::<!OI;JVM:DEPRECATION!>foo<!>)
|
||||
g(::<!JVM:DEPRECATION!>foo<!>)
|
||||
}
|
||||
|
||||
// MODULE: m2-jvm(m1-common)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun stringVararg(vararg args: String) {}
|
||||
fun intVararg(vararg args: Int) {}
|
||||
fun numberVararg(vararg args: Number) {}
|
||||
|
||||
fun useStrings(fn: (String, String, String) -> Unit) = fn("foo", "bar", "boo")
|
||||
fun useStringArray(fn: (Array<String>) -> Unit) = fn(arrayOf("foo", "bar", "boo"))
|
||||
|
||||
fun useIntArray(fn: (Array<Int>) -> Unit) = fn(arrayOf(1, 2, 3))
|
||||
fun usePrimitiveIntArray(fn: (IntArray) -> Unit) = fn(intArrayOf(4, 5, 6))
|
||||
|
||||
fun useMixedStringArgs1(fn: (String, Array<String>) -> Unit) = fn("foo", arrayOf("bar", "baz"))
|
||||
fun useMixedStringArgs2(fn: (Array<String>, String) -> Unit) = fn(arrayOf("foo", "bar"), "baz")
|
||||
fun useMixedStringArgs3(fn: (String, Array<String>, String) -> Unit) = fn("foo", arrayOf("bar", "baz"), "boo")
|
||||
fun useTwoStringArrays(fn: (Array<String>, Array<String>) -> Unit) = fn(arrayOf("foo", "bar"), arrayOf("baz", "boo"))
|
||||
|
||||
fun test() {
|
||||
useStrings(::stringVararg)
|
||||
useStringArray(::stringVararg)
|
||||
useIntArray(::numberVararg)
|
||||
usePrimitiveIntArray(::intVararg)
|
||||
useIntArray(<!TYPE_MISMATCH("(Array<Int>) -> Unit", "KFunction1<IntArray, Unit>")!>::intVararg<!>)
|
||||
useMixedStringArgs1(<!TYPE_MISMATCH("(String, Array<String>) -> Unit", "KFunction1<Array<out String>, Unit>")!>::stringVararg<!>)
|
||||
useMixedStringArgs2(<!TYPE_MISMATCH("(Array<String>, String) -> Unit", "KFunction1<Array<out String>, Unit>")!>::stringVararg<!>)
|
||||
useMixedStringArgs3(<!TYPE_MISMATCH("(String, Array<String>, String) -> Unit", "KFunction1<Array<out String>, Unit>")!>::stringVararg<!>)
|
||||
useTwoStringArrays(<!TYPE_MISMATCH("(Array<String>, Array<String>) -> Unit", "KFunction1<Array<out String>, Unit>")!>::stringVararg<!>)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public fun intVararg(/*0*/ vararg args: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit
|
||||
public fun numberVararg(/*0*/ vararg args: kotlin.Number /*kotlin.Array<out kotlin.Number>*/): kotlin.Unit
|
||||
public fun stringVararg(/*0*/ vararg args: kotlin.String /*kotlin.Array<out kotlin.String>*/): kotlin.Unit
|
||||
public fun test(): kotlin.Unit
|
||||
public fun useIntArray(/*0*/ fn: (kotlin.Array<kotlin.Int>) -> kotlin.Unit): kotlin.Unit
|
||||
public fun useMixedStringArgs1(/*0*/ fn: (kotlin.String, kotlin.Array<kotlin.String>) -> kotlin.Unit): kotlin.Unit
|
||||
public fun useMixedStringArgs2(/*0*/ fn: (kotlin.Array<kotlin.String>, kotlin.String) -> kotlin.Unit): kotlin.Unit
|
||||
public fun useMixedStringArgs3(/*0*/ fn: (kotlin.String, kotlin.Array<kotlin.String>, kotlin.String) -> kotlin.Unit): kotlin.Unit
|
||||
public fun usePrimitiveIntArray(/*0*/ fn: (kotlin.IntArray) -> kotlin.Unit): kotlin.Unit
|
||||
public fun useStringArray(/*0*/ fn: (kotlin.Array<kotlin.String>) -> kotlin.Unit): kotlin.Unit
|
||||
public fun useStrings(/*0*/ fn: (kotlin.String, kotlin.String, kotlin.String) -> kotlin.Unit): kotlin.Unit
|
||||
public fun useTwoStringArrays(/*0*/ fn: (kotlin.Array<kotlin.String>, kotlin.Array<kotlin.String>) -> kotlin.Unit): kotlin.Unit
|
||||
@@ -23545,6 +23545,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargOfNothing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsArray.kt")
|
||||
public void testVarargViewedAsArray() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargsAndFunctionLiterals.kt")
|
||||
public void testVarargsAndFunctionLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargsAndFunctionLiterals.kt");
|
||||
|
||||
Generated
+5
@@ -23465,6 +23465,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargOfNothing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsArray.kt")
|
||||
public void testVarargViewedAsArray() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargsAndFunctionLiterals.kt")
|
||||
public void testVarargsAndFunctionLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/varargs/varargsAndFunctionLiterals.kt");
|
||||
|
||||
+5
@@ -2697,6 +2697,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsPrimitiveArray.kt")
|
||||
public void testVarargViewedAsPrimitiveArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsPrimitiveArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargWithDefaultValue.kt")
|
||||
public void testVarargWithDefaultValue() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargWithDefaultValue.kt");
|
||||
|
||||
+5
@@ -2697,6 +2697,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsPrimitiveArray.kt")
|
||||
public void testVarargViewedAsPrimitiveArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsPrimitiveArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargWithDefaultValue.kt")
|
||||
public void testVarargWithDefaultValue() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargWithDefaultValue.kt");
|
||||
|
||||
+5
@@ -2677,6 +2677,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsPrimitiveArray.kt")
|
||||
public void testVarargViewedAsPrimitiveArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsPrimitiveArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargWithDefaultValue.kt")
|
||||
public void testVarargWithDefaultValue() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargWithDefaultValue.kt");
|
||||
|
||||
Generated
+5
@@ -2127,6 +2127,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsPrimitiveArray.kt")
|
||||
public void testVarargViewedAsPrimitiveArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsPrimitiveArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargWithDefaultValue.kt")
|
||||
public void testVarargWithDefaultValue() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargWithDefaultValue.kt");
|
||||
|
||||
+5
@@ -2127,6 +2127,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargViewedAsPrimitiveArray.kt")
|
||||
public void testVarargViewedAsPrimitiveArray() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargViewedAsPrimitiveArray.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varargWithDefaultValue.kt")
|
||||
public void testVarargWithDefaultValue() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/varargWithDefaultValue.kt");
|
||||
|
||||
Reference in New Issue
Block a user