[NI] Add pre-resolution callable reference argument check.
If expected type for callable reference argument isn't callable type then make such candidate unsuccessful. Sometimes expected type is just `T`, where `T` is type variable. To support such case we take all supertypes and check them instead.
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
55dc2c11f7
commit
ee16a79612
+11
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
@@ -77,7 +78,7 @@ internal object CheckArguments : ResolutionPart {
|
||||
else {
|
||||
// callable reference resolution will be run after choosing single descriptor
|
||||
postponeCallableReferenceArguments.add(PostponeCallableReferenceArgument(argument, expectedType))
|
||||
null
|
||||
checkCallableExpectedType(csBuilder, argument, expectedType)
|
||||
}
|
||||
}
|
||||
else -> error("Incorrect argument type: $argument, ${argument.javaClass.canonicalName}.")
|
||||
@@ -163,6 +164,15 @@ internal object CheckArguments : ResolutionPart {
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkCallableExpectedType(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: CallableReferenceKotlinCallArgument,
|
||||
expectedType: UnwrappedType
|
||||
): KotlinCallDiagnostic? {
|
||||
val notCallableTypeConstructor = csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) }
|
||||
return notCallableTypeConstructor?.let { NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor) }
|
||||
}
|
||||
|
||||
fun processCallableReferenceArgument(
|
||||
callContext: KotlinCallContext,
|
||||
kotlinCall: KotlinCall,
|
||||
|
||||
+15
-7
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.RUNTIME_ERROR
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -250,25 +250,33 @@ class ExpectedLambdaParametersCountMismatch(
|
||||
val lambdaArgument: LambdaKotlinCallArgument,
|
||||
val expected: Int,
|
||||
val actual: Int
|
||||
) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(lambdaArgument, this)
|
||||
}
|
||||
|
||||
class UnexpectedReceiver(val functionExpression: FunctionExpression) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
class UnexpectedReceiver(val functionExpression: FunctionExpression) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionExpression, this)
|
||||
}
|
||||
|
||||
class MissingReceiver(val functionExpression: FunctionExpression) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
class MissingReceiver(val functionExpression: FunctionExpression) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionExpression, this)
|
||||
}
|
||||
|
||||
class NoneCallableReferenceCandidates(val argument: CallableReferenceKotlinCallArgument) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
class NoneCallableReferenceCandidates(val argument: CallableReferenceKotlinCallArgument) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
|
||||
class CallableReferenceCandidatesAmbiguity(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val candidates: Collection<CallableReferenceCandidate>
|
||||
) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
|
||||
class NotCallableExpectedType(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val expectedType: UnwrappedType,
|
||||
val notCallableTypeConstructor: TypeConstructor
|
||||
) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
+3
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
interface ConstraintSystemOperation {
|
||||
@@ -32,6 +33,8 @@ interface ConstraintSystemOperation {
|
||||
fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition)
|
||||
|
||||
fun isProperType(type: UnwrappedType): Boolean
|
||||
|
||||
fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor>
|
||||
}
|
||||
|
||||
interface ConstraintSystemBuilder : ConstraintSystemOperation {
|
||||
|
||||
+10
@@ -90,6 +90,16 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
override fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) =
|
||||
constraintInjector.addInitialEqualityConstraint(apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }, a, b, position)
|
||||
|
||||
override fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor> {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
val variableWithConstraints = notFixedTypeVariables[type.constructor] ?: return listOf(type.constructor)
|
||||
|
||||
return variableWithConstraints.constraints.mapNotNull {
|
||||
if (it.kind == ConstraintKind.LOWER) return@mapNotNull null
|
||||
it.type.constructor.takeUnless { allTypeVariables.containsKey(it) }
|
||||
}
|
||||
}
|
||||
|
||||
// ConstraintSystemBuilder
|
||||
private fun transactionRegisterVariable(variable: NewTypeVariable) {
|
||||
if (state != State.TRANSACTION) return
|
||||
|
||||
@@ -149,5 +149,26 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not
|
||||
return KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kPropertyClass,
|
||||
listOf(StarProjectionImpl(kPropertyClass.typeConstructor.parameters.single())))
|
||||
}
|
||||
|
||||
fun isPossibleExpectedCallableType(typeConstructor: TypeConstructor): Boolean {
|
||||
val descriptor = typeConstructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
if (KotlinBuiltIns.isAny(descriptor)) return true
|
||||
|
||||
val shortName = descriptor.name.asString()
|
||||
|
||||
val packageName = DescriptorUtils.getFqName(descriptor).parent().toSafe()
|
||||
if (packageName == KOTLIN_REFLECT_FQ_NAME) {
|
||||
return shortName.startsWith("KFunction") // KFunctionN, KFunction
|
||||
|| shortName.startsWith("KProperty") // KPropertyN, KProperty
|
||||
|| shortName.startsWith("KMutableProperty") // KMutablePropertyN, KMutableProperty
|
||||
|| shortName == "KCallable" || shortName == "KAnnotatedElement"
|
||||
|
||||
}
|
||||
if (packageName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) {
|
||||
return shortName.startsWith("Function") // FunctionN, Function
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user