diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt index df4c5676109..09991039a85 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt @@ -169,7 +169,7 @@ class DelegatedPropertyResolver( } private fun KtPsiFactory.createExpressionForProperty(): KtExpression { - return createExpression("null as ${KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString()}<*>") + return createExpression("null as ${KotlinBuiltIns.FQ_NAMES.kPropertyFqName.asString()}<*>") } /* Resolve getValue() or setValue() methods from delegate */ diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt index 5668661e2de..5bc98b18ac5 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt @@ -134,7 +134,7 @@ class IrBuiltIns( val throwableClass = builtIns.throwable.toIrSymbol() val kCallableClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe()).toIrSymbol() - val kPropertyClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName()).toIrSymbol() + val kPropertyClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kPropertyFqName.toSafe()).toIrSymbol() // TODO switch to IrType val primitiveTypes = listOf(bool, char, byte, short, int, long, float, double) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt index cd3c737edd4..2ea38392422 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.resolve.calls.components -import org.jetbrains.kotlin.builtins.ReflectionTypes -import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType -import org.jetbrains.kotlin.builtins.isFunctionType +import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints @@ -28,6 +26,7 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.expressions.CoercionStrategy import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.isUnit +import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addIfNotNull @@ -223,9 +222,9 @@ class CallableReferencesCandidateFactory( expectedType: UnwrappedType?, unboundReceiverCount: Int ): Triple, CoercionStrategy, Int>? { - val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null + val inputOutputTypes = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType) ?: return null - val expectedArgumentCount = functionType.arguments.size - unboundReceiverCount - 1 // 1 -- return type + val expectedArgumentCount = inputOutputTypes.inputTypes.size - unboundReceiverCount if (expectedArgumentCount < 0) return null val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) } @@ -251,7 +250,7 @@ class CallableReferencesCandidateFactory( if (mappedArguments.any { it == null }) return null // lower(Unit!) = Unit - val returnExpectedType = functionType.getReturnTypeFromFunctionType().lowerIfFlexible() + val returnExpectedType = inputOutputTypes.outputType val coercion = if (returnExpectedType.isUnit()) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION @@ -342,14 +341,43 @@ class CallableReferencesCandidateFactory( } } -fun getFunctionTypeFromCallableReferenceExpectedType(expectedType: UnwrappedType?): UnwrappedType? { +data class InputOutputTypes(val inputTypes: List, val outputType: UnwrappedType) + +fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: UnwrappedType?): InputOutputTypes? { if (expectedType == null) return null - return if (expectedType.isFunctionType) { - expectedType - } else if (ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(expectedType)) { - expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap() - } else { - null + return when { + expectedType.isFunctionType -> + extractInputOutputTypesFromFunctionType(expectedType) + + expectedType.isBaseTypeForNumberedReferenceTypes() -> + InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap()) + + ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(expectedType) -> { + val functionFromSupertype = expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap() + extractInputOutputTypesFromFunctionType(functionFromSupertype) + } + + ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(expectedType) -> { + val functionFromSupertype = expectedType.supertypes().first { it.isFunctionType }.unwrap() + extractInputOutputTypesFromFunctionType(functionFromSupertype) + } + + else -> null } -} \ No newline at end of file +} + +private fun UnwrappedType.isBaseTypeForNumberedReferenceTypes(): Boolean = + ReflectionTypes.hasKPropertyTypeFqName(this) || + ReflectionTypes.hasKMutablePropertyTypeFqName(this) || + ReflectionTypes.hasKCallableTypeFqName(this) + +private fun extractInputOutputTypesFromFunctionType(functionType: UnwrappedType): InputOutputTypes { + val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap() + val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() } + + val inputTypes = listOfNotNull(receiver) + parameters + val outputType = functionType.getReturnTypeFromFunctionType().unwrap() + + return InputOutputTypes(inputTypes, outputType) +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index f682006a0a0..693146103a6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -5,14 +5,9 @@ package org.jetbrains.kotlin.resolve.calls.model -import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType -import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType -import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate -import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper -import org.jetbrains.kotlin.resolve.calls.components.getFunctionTypeFromCallableReferenceExpectedType +import org.jetbrains.kotlin.resolve.calls.components.* import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType @@ -132,18 +127,10 @@ class ResolvedCallableReferenceAtom( } override val inputTypes: Collection - get() { - val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return listOfNotNull(expectedType) - val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() } - val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap() - return receiver?.let { parameters + it } ?: parameters - } + get() = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.inputTypes ?: listOfNotNull(expectedType) override val outputType: UnwrappedType? - get() { - val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null - return functionType.getReturnTypeFromFunctionType().unwrap() - } + get() = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.outputType } class ResolvedCollectionLiteralAtom( diff --git a/compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.kt b/compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.kt new file mode 100644 index 00000000000..e6d7d426df4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.kt @@ -0,0 +1,27 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +import kotlin.reflect.* + +interface Parent +class Child : Parent + +class ChildHolder(var child: Child) + +interface Inv + +class Form { + fun get0(field: KMutableProperty): Inv = TODO() + fun get1(field: KProperty): Inv = TODO() + fun get2(field: KCallable): Inv = TODO() + fun get3(field: KMutableProperty1<*, F>): Inv = TODO() +} + +fun radio(field: Inv) {} + +fun test(form: Form) { + radio(form.get0(ChildHolder::child)) + radio(form.get1(ChildHolder::child)) + radio(form.get2(ChildHolder::child)) + radio(form.get3(ChildHolder::child)) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.txt b/compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.txt new file mode 100644 index 00000000000..e4ee55ece5e --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.txt @@ -0,0 +1,42 @@ +package + +public fun radio(/*0*/ field: Inv): kotlin.Unit +public fun test(/*0*/ form: Form): kotlin.Unit + +public final class Child : Parent { + public constructor Child() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ChildHolder { + public constructor ChildHolder(/*0*/ child: Child) + public final var child: Child + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Form { + public constructor Form() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun get0(/*0*/ field: kotlin.reflect.KMutableProperty): Inv + public final fun get1(/*0*/ field: kotlin.reflect.KProperty): Inv + public final fun get2(/*0*/ field: kotlin.reflect.KCallable): Inv + public final fun get3(/*0*/ field: kotlin.reflect.KMutableProperty1<*, F>): Inv + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Inv { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Parent { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 7c7aa194ceb..31d7bdb27e6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -1681,6 +1681,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/callableReference/sam.kt"); } + @TestMetadata("subtypeArgumentFromRHSForReference.kt") + public void testSubtypeArgumentFromRHSForReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.kt"); + } + @TestMetadata("unused.kt") public void testUnused() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/unused.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 1e8c0a07846..3186664f1ea 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -1681,6 +1681,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/callableReference/sam.kt"); } + @TestMetadata("subtypeArgumentFromRHSForReference.kt") + public void testSubtypeArgumentFromRHSForReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/subtypeArgumentFromRHSForReference.kt"); + } + @TestMetadata("unused.kt") public void testUnused() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/unused.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index eb62082ec15..82e012bbbf3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -322,7 +322,9 @@ public abstract class KotlinBuiltIns { public final FqNameUnsafe kMutableProperty0 = reflect("KMutableProperty0"); public final FqNameUnsafe kMutableProperty1 = reflect("KMutableProperty1"); public final FqNameUnsafe kMutableProperty2 = reflect("KMutableProperty2"); - public final ClassId kProperty = ClassId.topLevel(reflect("KProperty").toSafe()); + public final FqNameUnsafe kPropertyFqName = reflect("KProperty"); + public final FqNameUnsafe kMutablePropertyFqName = reflect("KMutableProperty"); + public final ClassId kProperty = ClassId.topLevel(kPropertyFqName.toSafe()); public final FqName uByteFqName = fqName("UByte"); public final FqName uShortFqName = fqName("UShort"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt index 368a0e5a6b2..239ab4a3059 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt @@ -102,8 +102,13 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not isNumberedKPropertyType(type) || isNumberedKMutablePropertyType(type) private fun isKCallableType(type: KotlinType): Boolean = - hasFqName(type.constructor, KotlinBuiltIns.FQ_NAMES.kCallable) || - type.constructor.supertypes.any { isKCallableType(it) } + hasKCallableTypeFqName(type) || type.constructor.supertypes.any { isKCallableType(it) } + + fun hasKCallableTypeFqName(type: KotlinType): Boolean = + hasFqName(type.constructor, KotlinBuiltIns.FQ_NAMES.kCallable) + + fun hasKMutablePropertyTypeFqName(type: KotlinType): Boolean = + hasFqName(type.constructor, KotlinBuiltIns.FQ_NAMES.kMutablePropertyFqName) fun isNumberedKMutablePropertyType(type: KotlinType): Boolean { val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return false @@ -112,6 +117,9 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not hasFqName(descriptor, KotlinBuiltIns.FQ_NAMES.kMutableProperty2) } + fun hasKPropertyTypeFqName(type: KotlinType): Boolean = + hasFqName(type.constructor, KotlinBuiltIns.FQ_NAMES.kPropertyFqName) + fun isNumberedKPropertyType(type: KotlinType): Boolean { val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return false return hasFqName(descriptor, KotlinBuiltIns.FQ_NAMES.kProperty0) ||