[NI] Fix input/output types for callable reference atom
Input and output types are crucial for type variable fixation order and analysis of postponed arguments (callable references, lambdas). Specifically, if there is non-fixed type variable inside input types of a callable reference, then we'll postpone resolution for such callable reference. Initial example with the expected type `KMutableProperty1<*, F>` caused problems because input types were computed incorrectly (while there aren't input types here) #KT-25431 Fixed
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
+42
-14
@@ -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<Array<KotlinType>, 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<UnwrappedType>, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
+3
-16
@@ -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<UnwrappedType>
|
||||
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(
|
||||
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
interface Parent
|
||||
class Child : Parent
|
||||
|
||||
class ChildHolder(var child: Child)
|
||||
|
||||
interface Inv<T>
|
||||
|
||||
class Form {
|
||||
fun <F> get0(field: KMutableProperty<F>): Inv<F> = TODO()
|
||||
fun <F> get1(field: KProperty<F>): Inv<F> = TODO()
|
||||
fun <F> get2(field: KCallable<F>): Inv<F> = TODO()
|
||||
fun <F> get3(field: KMutableProperty1<*, F>): Inv<F> = TODO()
|
||||
}
|
||||
|
||||
fun <T : Parent> radio(field: Inv<T>) {}
|
||||
|
||||
fun test(form: Form) {
|
||||
radio(form.get0(ChildHolder::child))
|
||||
radio(form.get1(ChildHolder::child))
|
||||
radio(form.get2(ChildHolder::child))
|
||||
radio(form.get3(ChildHolder::child))
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : Parent> radio(/*0*/ field: Inv<T>): 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 </*0*/ F> get0(/*0*/ field: kotlin.reflect.KMutableProperty<F>): Inv<F>
|
||||
public final fun </*0*/ F> get1(/*0*/ field: kotlin.reflect.KProperty<F>): Inv<F>
|
||||
public final fun </*0*/ F> get2(/*0*/ field: kotlin.reflect.KCallable<F>): Inv<F>
|
||||
public final fun </*0*/ F> get3(/*0*/ field: kotlin.reflect.KMutableProperty1<*, F>): Inv<F>
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Inv</*0*/ T> {
|
||||
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
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) ||
|
||||
|
||||
Reference in New Issue
Block a user