From f35ced366610d81c2be1fdb185644d2034c589ff Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 12 Sep 2022 11:25:20 +0200 Subject: [PATCH] Revert "[FE 1.0] Get rid of GenericCandidateResolver" This reverts commit 941a33a1841270e2f6e73273936e40ba2cd311c7. --- .../resolve/calls/GenericCandidateResolver.kt | 529 ++++++++++++++++++ ...plicitNothingAsTypeParameterCallChecker.kt | 2 +- ...rscoreNamedParameterOfCatchBlockChecker.kt | 1 + .../resolve/calls/tower/PSICallResolver.kt | 1 + .../kotlin/resolve/calls/util/callUtil.kt | 3 - 5 files changed, 532 insertions(+), 4 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt new file mode 100644 index 00000000000..15b503981c3 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -0,0 +1,529 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls + +import org.jetbrains.kotlin.builtins.* +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getBinaryWithTypeParent +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil +import org.jetbrains.kotlin.resolve.TemporaryBindingTrace +import org.jetbrains.kotlin.resolve.calls.util.* +import org.jetbrains.kotlin.resolve.calls.util.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS +import org.jetbrains.kotlin.resolve.calls.util.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS +import org.jetbrains.kotlin.resolve.calls.util.getCall +import org.jetbrains.kotlin.resolve.calls.util.isSafeCall +import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT +import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache +import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache +import org.jetbrains.kotlin.resolve.calls.inference.* +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ValidityConstraintForConstituentType +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall +import org.jetbrains.kotlin.resolve.calls.util.makeNullableTypeIfSafeReceiver +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory +import org.jetbrains.kotlin.resolve.isFunctionForExpectTypeFromCastFeature +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE +import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct +import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils +import org.jetbrains.kotlin.types.typeUtil.makeNullable +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialFunctionName }.toSet() + +class GenericCandidateResolver( + private val argumentTypeResolver: ArgumentTypeResolver, + private val languageVersionSettings: LanguageVersionSettings, + private val dataFlowValueFactory: DataFlowValueFactory +) { + fun inferTypeArguments(context: CallCandidateResolutionContext): ResolutionStatus { + val candidateCall = context.candidateCall + val candidate = candidateCall.candidateDescriptor + + val builder = ConstraintSystemBuilderImpl() + builder.registerTypeVariables(candidateCall.call.toHandle(), candidate.typeParameters) + + val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE) + + // Value parameters + for ((candidateParameter, resolvedValueArgument) in candidateCall.valueArguments) { + val valueParameterDescriptor = candidate.valueParameters[candidateParameter.index] + + for (valueArgument in resolvedValueArgument.arguments) { + // TODO : more attempts, with different expected types + + // Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare) + // and throw the results away + // We'll type check the arguments later, with the inferred types expected + addConstraintForValueArgument( + valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS + ) + } + } + + if (candidate is TypeAliasConstructorDescriptor) { + val substitutedReturnType = builder.compositeSubstitutor().safeSubstitute(candidate.returnType, Variance.INVARIANT) + addValidityConstraintsForConstituentTypes(builder, substitutedReturnType) + } + + // Receiver + // Error is already reported if something is missing + val receiverArgument = candidateCall.extensionReceiver + val receiverParameter = candidate.extensionReceiverParameter + if (receiverArgument != null && receiverParameter != null) { + val receiverArgumentType = receiverArgument.type + var receiverType: KotlinType? = if (context.candidateCall.call.isSafeCall()) + TypeUtils.makeNotNullable(receiverArgumentType) + else + receiverArgumentType + if (receiverArgument is ExpressionReceiver) { + receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context) + } + builder.addSubtypeConstraint( + receiverType, + builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT), + RECEIVER_POSITION.position() + ) + } + + val constraintSystem = builder.build() + candidateCall.setConstraintSystem(constraintSystem) + + // Solution + val hasContradiction = constraintSystem.status.hasContradiction() + if (!hasContradiction) { + addExpectedTypeForExplicitCast(context, builder) + return INCOMPLETE_TYPE_INFERENCE + } + return OTHER_ERROR + } + + private fun ConstraintSystem.Builder.typeInSystem(call: Call, type: KotlinType?): KotlinType? = + type?.let { + typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT) + } + + private fun addExpectedTypeForExplicitCast( + context: CallCandidateResolutionContext<*>, + builder: ConstraintSystem.Builder + ) { + if (!languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return + + if (context.candidateCall is VariableAsFunctionResolvedCall) return + + val candidateDescriptor = context.candidateCall.candidateDescriptor.safeAs() ?: return + + val binaryParent = context.call.calleeExpression?.getBinaryWithTypeParent() ?: return + val operationType = binaryParent.operationReference.getReferencedNameElementType().takeIf { + it == KtTokens.AS_KEYWORD || it == KtTokens.AS_SAFE + } ?: return + + val leftType = context.trace.get(BindingContext.TYPE, binaryParent.right ?: return) ?: return + val expectedType = if (operationType == KtTokens.AS_SAFE) leftType.makeNullable() else leftType + + if (context.candidateCall.call.typeArgumentList != null || !candidateDescriptor.isFunctionForExpectTypeFromCastFeature()) return + + val typeInSystem = builder.typeInSystem(context.call, candidateDescriptor.returnType ?: return) ?: return + + context.trace.record(BindingContext.CAST_TYPE_USED_AS_EXPECTED_TYPE, binaryParent) + builder.addSubtypeConstraint(typeInSystem, expectedType, ConstraintPositionKind.SPECIAL.position()) + } + + private fun addValidityConstraintsForConstituentTypes(builder: ConstraintSystem.Builder, type: KotlinType) { + val typeConstructor = type.constructor + if (typeConstructor.declarationDescriptor is TypeParameterDescriptor) return + + val boundsSubstitutor = TypeSubstitutor.create(type) + + type.arguments.forEachIndexed forEachArgument@ { i, typeProjection -> + if (typeProjection.isStarProjection) return@forEachArgument // continue + + val typeParameter = typeConstructor.parameters[i] + addValidityConstraintsForTypeArgument(builder, typeProjection, typeParameter, boundsSubstitutor) + + addValidityConstraintsForConstituentTypes(builder, typeProjection.type) + } + } + + private fun addValidityConstraintsForTypeArgument( + builder: ConstraintSystem.Builder, + substitutedArgument: TypeProjection, + typeParameter: TypeParameterDescriptor, + boundsSubstitutor: TypeSubstitutor + ) { + val substitutedType = substitutedArgument.type + for (upperBound in typeParameter.upperBounds) { + val substitutedUpperBound = boundsSubstitutor.safeSubstitute(upperBound, Variance.INVARIANT).upperIfFlexible() + val constraintPosition = ValidityConstraintForConstituentType(substitutedType, typeParameter, substitutedUpperBound) + + // Do not add extra constraints if upper bound is 'Any?'; + // otherwise it will be treated incorrectly in nested calls processing. + if (KotlinBuiltIns.isNullableAny(substitutedUpperBound)) continue + + builder.addSubtypeConstraint(substitutedType, substitutedUpperBound, constraintPosition) + } + } + + // Creates a substitutor which maps types to their representation in the constraint system. + // In case when some type parameter descriptor is represented by more than one variable in the system, the behavior is undefined. + private fun ConstraintSystem.Builder.compositeSubstitutor(): TypeSubstitutor { + return TypeSubstitutor.create(object : TypeSubstitution() { + override fun get(key: KotlinType): TypeProjection? { + return typeVariableSubstitutors.values.reversed().asSequence().mapNotNull { it.substitution.get(key) }.firstOrNull() + } + }) + } + + private fun addConstraintForValueArgument( + valueArgument: ValueArgument, + valueParameterDescriptor: ValueParameterDescriptor, + substitutor: TypeSubstitutor, + builder: ConstraintSystem.Builder, + context: CallCandidateResolutionContext<*>, + resolveFunctionArgumentBodies: ResolveArgumentsMode + ) { + val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context) + val argumentExpression = valueArgument.getArgumentExpression() + + val expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT) + val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument) + val newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument) + + val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo( + argumentExpression, + newContext, + resolveFunctionArgumentBodies, + expectedType?.isSuspendFunctionType == true + ) + context.candidateCall.dataFlowInfoForArguments.updateInfo(valueArgument, typeInfoForCall.dataFlowInfo) + + val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) + + if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return + + val type = + updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument)) + + if (argumentExpression is KtCallableReferenceExpression && type == null) return + + builder.addSubtypeConstraint( + type, + builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT), + constraintPosition + ) + } + + private fun addConstraintForNestedCall( + argumentExpression: KtExpression?, + constraintPosition: ConstraintPosition, + builder: ConstraintSystem.Builder, + context: CallCandidateResolutionContext<*>, + effectiveExpectedType: KotlinType + ): Boolean { + val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults + if (resolutionResults == null || !resolutionResults.isSingleResult) return false + + val nestedCall = resolutionResults.resultingCall + if (nestedCall.isCompleted) return false + + val nestedConstraintSystem = nestedCall.constraintSystem ?: return false + + val candidateDescriptor = nestedCall.candidateDescriptor + val returnType = candidateDescriptor.returnType ?: return false + + val nestedTypeVariables = nestedConstraintSystem.getNestedTypeVariables(returnType) + + // we add an additional type variable only if no information is inferred for it. + // otherwise we add currently inferred return type as before + if (nestedTypeVariables.any { nestedConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false + + val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor) + val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap() + + val freshVariables = returnType.getNestedTypeParameters().mapNotNull { conversion[it] } + builder.registerTypeVariables(nestedCall.call.toHandle(), freshVariables, external = true) + // Safe call result must be nullable if receiver is nullable + val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context) + + builder.addSubtypeConstraint( + argumentExpressionType, + builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT), + constraintPosition + ) + + return true + } + + private fun updateResultTypeForSmartCasts( + type: KotlinType?, + argumentExpression: KtExpression?, + context: ResolutionContext<*> + ): KotlinType? { + val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter) + if (deparenthesizedArgument == null || type == null) return type + + val dataFlowValue = dataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context) + if (!dataFlowValue.isStable) return type + + val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings) + if (possibleTypes.isEmpty()) return type + + return TypeIntersector.intersectTypes(possibleTypes + type) + } + + fun completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext) { + val resolvedCall = context.candidateCall + val constraintSystem = resolvedCall.constraintSystem?.toBuilder() ?: return + + // `resolvedCall` can contain wrapped call (e.g. CallForImplicitInvoke). Meanwhile, `context` contains simple call which leads + // to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument` + val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) { + CallCandidateResolutionContext.create( + resolvedCall, context, context.trace, context.tracing, resolvedCall.functionCall.call, context.candidateResolveMode + ) + } else { + context + } + + // constraints for function literals + // Value parameters + for ((valueParameterDescriptor, resolvedValueArgument) in resolvedCall.valueArguments) { + for (valueArgument in resolvedValueArgument.arguments) { + valueArgument.getArgumentExpression()?.let { argumentExpression -> + ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral -> + addConstraintForFunctionLiteralArgument( + functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext, + resolvedCall.candidateDescriptor.returnType + ) + } + + // as inference for callable references depends on expected type, + // we should postpone reporting errors on them until all types will be inferred + + // We do not replace trace for special calls (e.g. if-expressions) because of their specific analysis + // For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression) + val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) { + newContext + } else { + val temporaryBindingTrace = TemporaryBindingTrace.create( + newContext.trace, "Trace to complete argument for call that might be not resulting call" + ) + newContext.replaceBindingTrace(temporaryBindingTrace) + } + + ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference -> + addConstraintForCallableReference( + callableReference, + valueArgument, + valueParameterDescriptor, + constraintSystem, + temporaryContextForCall + ) + } + } + } + } + val resultingSystem = constraintSystem.build() + resolvedCall.setConstraintSystem(resultingSystem) + + val isNewInferenceEnabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference) + val resultingSubstitutor = if (isNewInferenceEnabled) { + resultingSystem.resultingSubstitutor.replaceWithContravariantApproximatingSubstitution() + } else resultingSystem.resultingSubstitutor + + resolvedCall.setSubstitutor(resultingSubstitutor) + } + + // See KT-5385 + // When literal returns T, and it's an argument of a function that also returns T, + // and we have some expected type Type, we can expected from literal to return Type + // Otherwise we do not care about literal's exact return type + private fun estimateLiteralReturnType( + context: CallCandidateResolutionContext<*>, + literalExpectedType: KotlinType, + ownerReturnType: KotlinType? + ) = if (!TypeUtils.noExpectedType(context.expectedType) && + ownerReturnType != null && + TypeUtils.isTypeParameter(ownerReturnType) && + literalExpectedType.isFunctionTypeOrSubtype && + getReturnTypeForCallable(literalExpectedType) == ownerReturnType) + context.expectedType + else DONT_CARE + + private fun addConstraintForFunctionLiteralArgument( + functionLiteral: KtFunction, + valueArgument: ValueArgument, + valueParameterDescriptor: ValueParameterDescriptor, + constraintSystem: ConstraintSystem.Builder, + context: CallCandidateResolutionContext, + argumentOwnerReturnType: KotlinType? + ) { + val argumentExpression = valueArgument.getArgumentExpression() ?: return + + val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context) + + val currentSubstitutor = constraintSystem.build().currentSubstitutor + val newSubstitution = object : DelegatedTypeSubstitution(currentSubstitutor.substitution) { + override fun approximateContravariantCapturedTypes() = true + } + + var expectedType = newSubstitution.buildSubstitutor().substitute(effectiveExpectedType, Variance.IN_VARIANCE) + + if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) { + expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral( + functionLiteral, + context.scope, + context.trace, + false, + expectedType?.isSuspendFunctionType == true + ) + } + if (expectedType == null || !expectedType.isBuiltinFunctionalType || hasUnknownFunctionParameter(expectedType)) { + return + } + val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments + val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument) + + val effectiveExpectedTypeInSystem = + constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT) + + //todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type + val hasExpectedReturnType = !hasUnknownReturnType(expectedType) + val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) + if (hasExpectedReturnType) { + val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create( + context, "trace to resolve function literal with expected return type", argumentExpression + ) + + val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return + val mismatch = BooleanArray(1) + val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch( + temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch + ) + val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType) + .replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache) + .replaceContextDependency(INDEPENDENT) + val type = argumentTypeResolver.getFunctionLiteralTypeInfo( + argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS, + expectedType.isSuspendFunctionType + ).type + if (!mismatch[0]) { + constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position) + temporaryToResolveFunctionLiteral.commit() + return + } + } + val estimatedReturnType = estimateLiteralReturnType(context, effectiveExpectedType, argumentOwnerReturnType) + val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType) + val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument) + .replaceContextDependency(INDEPENDENT) + val type = + argumentTypeResolver.getFunctionLiteralTypeInfo( + argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS, + expectedType.isSuspendFunctionType + ).type + constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position) + } + + private fun addConstraintForCallableReference( + callableReference: KtCallableReferenceExpression, + valueArgument: ValueArgument, + valueParameterDescriptor: ValueParameterDescriptor, + constraintSystem: ConstraintSystem.Builder, + context: CallCandidateResolutionContext + ) { + val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context) + val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType) + ?: return + if (!expectedType.isApplicableExpectedTypeForCallableReference()) return + val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return + val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) + constraintSystem.addSubtypeConstraint( + resolvedType, + constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT), + position + ) + } + + private fun getExpectedTypeForCallableReference( + callableReference: KtCallableReferenceExpression, + constraintSystem: ConstraintSystem.Builder, + context: CallCandidateResolutionContext, + effectiveExpectedType: KotlinType + ): KotlinType? { + val substitutedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT) + if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType)) + return substitutedType + + val shapeType = argumentTypeResolver.getShapeTypeOfCallableReference(callableReference, context, false) + if (shapeType != null && shapeType.isFunctionTypeOrSubtype && !hasUnknownFunctionParameter(shapeType)) + return shapeType + + return null + } + + private fun getResolvedTypeForCallableReference( + callableReference: KtCallableReferenceExpression, + context: CallCandidateResolutionContext, + expectedType: KotlinType, + valueArgument: ValueArgument + ): KotlinType? { + val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument) + val expectedTypeWithoutReturnType = + if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType + val newContext = context + .replaceExpectedType(expectedTypeWithoutReturnType) + .replaceDataFlowInfo(dataFlowInfoForArgument) + .replaceContextDependency(INDEPENDENT) + return argumentTypeResolver.getCallableReferenceTypeInfo( + callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS + ).type + } +} + +fun getResolutionResultsCachedData(expression: KtExpression?, context: ResolutionContext<*>): ResolutionResultsCache.CachedData? { + if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null + val argumentCall = expression?.getCall(context.trace.bindingContext) ?: return null + + return context.resolutionResultsCache[argumentCall] +} + +fun makeConstantSubstitutor(typeParameterDescriptors: Collection, type: KotlinType): TypeSubstitutor { + val constructors = typeParameterDescriptors.map { it.typeConstructor }.toSet() + val projection = TypeProjectionImpl(type) + + return TypeSubstitutor.create(object : TypeConstructorSubstitution() { + override operator fun get(key: TypeConstructor) = + if (key in constructors) projection else null + + override fun isEmpty() = false + }) +} + +private fun KotlinType.isApplicableExpectedTypeForCallableReference(): Boolean { + return this.isFunctionType || + ReflectionTypes.isBaseTypeForNumberedReferenceTypes(this) || + ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(this) || + ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(this) +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt index f821902381b..30716dc300d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactoryList import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall import org.jetbrains.kotlin.resolve.calls.components.stableType @@ -20,7 +21,6 @@ import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.tower.psiExpression import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall -import org.jetbrains.kotlin.resolve.calls.util.SPECIAL_FUNCTION_NAMES import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.types.DeferredType import org.jetbrains.kotlin.types.KotlinType diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReferencingToUnderscoreNamedParameterOfCatchBlockChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReferencingToUnderscoreNamedParameterOfCatchBlockChecker.kt index 0161a562656..d2c934195d5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReferencingToUnderscoreNamedParameterOfCatchBlockChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReferencingToUnderscoreNamedParameterOfCatchBlockChecker.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactory import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.* diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 016a71e1a0b..800ce144fe8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.BindingContext.NEW_INFERENCE_CATCH_EXCEPTION import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver +import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES import org.jetbrains.kotlin.resolve.calls.components.InferenceSession import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt index f782224c12e..6d6c061c50d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt @@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -331,5 +330,3 @@ fun KotlinCall.extractCallableReferenceExpression(): KtCallableReferenceExpressi psiKotlinCall.psiCall.extractCallableReferenceExpression() fun Call.extractCallableReferenceExpression(): KtCallableReferenceExpression? = callElement.asCallableReferenceExpression() - -val SPECIAL_FUNCTION_NAMES = ControlStructureTypingUtils.ResolveConstruct.values().map { it.specialFunctionName }.toSet()