From 4ea08a59db0a45ee988e158a76c6c3c1c872894b Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Thu, 2 Jun 2022 18:45:14 +0200 Subject: [PATCH] [FE 1.0] Get rid of CandidateResolver --- .../kotlin/resolve/calls/CandidateResolver.kt | 734 ------------------ .../calls/tower/NewResolutionOldInference.kt | 4 - 2 files changed, 738 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt deleted file mode 100644 index 0f6fd2336d1..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ /dev/null @@ -1,734 +0,0 @@ -/* - * 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 com.google.common.collect.Lists -import org.jetbrains.kotlin.builtins.ReflectionTypes -import org.jetbrains.kotlin.builtins.isSuspendFunctionType -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.diagnostics.Errors.EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED -import org.jetbrains.kotlin.diagnostics.Errors.SUPER_CANT_BE_EXTENSION_RECEIVER -import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke -import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker -import org.jetbrains.kotlin.resolve.calls.context.* -import org.jetbrains.kotlin.resolve.calls.inference.SubstitutionFilteringInternalResolveAnnotations -import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus -import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall -import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus -import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.* -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory -import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager -import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast -import org.jetbrains.kotlin.resolve.calls.util.* -import org.jetbrains.kotlin.resolve.calls.util.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.TypeUtils.noExpectedType -import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.error.ErrorUtils -import org.jetbrains.kotlin.types.error.ErrorTypeKind -import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver -import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments -import org.jetbrains.kotlin.types.typeUtil.makeNotNullable -import kotlin.math.min - -class CandidateResolver( - private val argumentTypeResolver: ArgumentTypeResolver, - private val genericCandidateResolver: GenericCandidateResolver, - private val reflectionTypes: ReflectionTypes, - private val additionalTypeCheckers: Iterable, - private val smartCastManager: SmartCastManager, - private val dataFlowValueFactory: DataFlowValueFactory, - private val upperBoundChecker: UpperBoundChecker -) { - fun performResolutionForCandidateCall( - context: CallCandidateResolutionContext, - checkArguments: CheckArgumentTypesMode - ): Unit = with(context) { - ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() - - if (ErrorUtils.isError(candidateDescriptor)) { - candidateCall.addStatus(SUCCESS) - return - } - - if (!checkOuterClassMemberIsAccessible(this)) { - candidateCall.addStatus(OTHER_ERROR) - return - } - - if (!context.isDebuggerContext) { - checkVisibilityWithoutReceiver() - } - - when (checkArguments) { - CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS -> - mapArguments() - CheckArgumentTypesMode.CHECK_CALLABLE_TYPE -> - checkExpectedCallableType() - } - - checkReceiverTypeError() - checkExtensionReceiver() - checkDispatchReceiver() - - processTypeArguments() - checkValueArguments() - - checkAbstractAndSuper() - checkConstructedExpandedType() - } - - private fun CallCandidateResolutionContext<*>.checkValueArguments() = checkAndReport { - if (call.typeArguments.isEmpty() - && !candidateDescriptor.typeParameters.isEmpty() - && candidateCall.knownTypeParametersSubstitutor == null - ) { - genericCandidateResolver.inferTypeArguments(this) - } else { - checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status - } - } - - private fun CallCandidateResolutionContext<*>.processTypeArguments() = check { - val ktTypeArguments = call.typeArguments - if (candidateCall.knownTypeParametersSubstitutor != null) { - candidateCall.setSubstitutor(candidateCall.knownTypeParametersSubstitutor!!) - } else if (ktTypeArguments.isNotEmpty()) { - // Explicit type arguments passed - - val typeArguments = ArrayList() - for (projection in ktTypeArguments) { - val type = projection.typeReference?.let { trace.bindingContext.get(BindingContext.TYPE, it) } - ?: ErrorUtils.createErrorType(ErrorTypeKind.STAR_PROJECTION_IN_CALL) - typeArguments.add(type) - } - - val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size - for (index in ktTypeArguments.size until expectedTypeArgumentCount) { - typeArguments.add( - ErrorUtils.createErrorType( - ErrorTypeKind.MISSED_TYPE_ARGUMENT_FOR_TYPE_PARAMETER, - candidateDescriptor.typeParameters[index].name.toString() - ) - ) - } - val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments) - val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution)) - - if (expectedTypeArgumentCount != ktTypeArguments.size) { - candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR) - tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor) - } else { - checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace) - } - - candidateCall.setSubstitutor(substitutor) - } - } - - private fun CallCandidateResolutionContext.mapArguments() = check { - val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters( - call, tracing, candidateCall, languageVersionSettings - ) - if (!argumentMappingStatus.isSuccess) { - candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR) - } - } - - private fun CallCandidateResolutionContext.checkExpectedCallableType() = check { - if (!noExpectedType(expectedType)) { - val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference( - candidateCall.candidateDescriptor, - (call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let { - trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it) - }, - reflectionTypes, scope.ownerDescriptor - ) - if (candidateKCallableType == null || - !canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) { - candidateCall.addStatus(OTHER_ERROR) - } - } - } - - private fun canBeSubtype(subType: KotlinType, superType: KotlinType, candidateTypeParameters: List): Boolean { - // Here we need to check that there exists a substitution from type parameters (used in types in candidate signature) - // to arguments such that substituted candidateKCallableType would be a subtype of expectedType. - // It looks like in general this can only be decided by constructing a constraint system and checking - // if it has a contradiction. Currently we use a heuristic that may not work ideally in all cases. - // TODO: use constraint system to check if candidateKCallableType can be a subtype of expectedType - val substituteDontCare = makeConstantSubstitutor(candidateTypeParameters, TypeUtils.DONT_CARE) - val subTypeSubstituted = substituteDontCare.substitute(subType, Variance.INVARIANT) ?: return true - return ErrorTypesAreEqualToAnything.isSubtypeOf(subTypeSubstituted, superType) - } - - private fun CallCandidateResolutionContext<*>.checkVisibilityWithoutReceiver() = checkAndReport { - checkVisibilityWithDispatchReceiver(DescriptorVisibilities.ALWAYS_SUITABLE_RECEIVER, null) - } - - private fun CallCandidateResolutionContext<*>.checkVisibilityWithDispatchReceiver( - receiverArgument: ReceiverValue?, - smartCastType: KotlinType? - ): ResolutionStatus { - val invisibleMember = DescriptorVisibilityUtils.findInvisibleMember( - getReceiverValueWithSmartCast(receiverArgument, smartCastType), - candidateDescriptor, - scope.ownerDescriptor, - languageVersionSettings - ) - return if (invisibleMember != null) { - tracing.invisibleMember(trace, invisibleMember) - INVISIBLE_MEMBER_ERROR - } else { - SUCCESS - } - } - - private fun CallCandidateResolutionContext<*>.isCandidateVisibleOrExtensionReceiver( - receiverArgument: ReceiverValue?, - smartCastType: KotlinType?, - isDispatchReceiver: Boolean - ) = !isDispatchReceiver || isCandidateVisible(receiverArgument, smartCastType) - - private fun CallCandidateResolutionContext<*>.isCandidateVisible( - receiverArgument: ReceiverValue?, - smartCastType: KotlinType? - ) = DescriptorVisibilityUtils.findInvisibleMember( - getReceiverValueWithSmartCast(receiverArgument, smartCastType), - candidateDescriptor, scope.ownerDescriptor, - languageVersionSettings - ) == null - - private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport { - val receiverParameter = candidateCall.candidateDescriptor.extensionReceiverParameter - val receiverArgument = candidateCall.extensionReceiver - if (receiverParameter != null && receiverArgument == null) { - tracing.missingReceiver(candidateCall.trace, receiverParameter) - OTHER_ERROR - } else if (receiverParameter == null && receiverArgument != null) { - tracing.noReceiverAllowed(candidateCall.trace) - if (call.calleeExpression is KtSimpleNameExpression) { - RECEIVER_PRESENCE_ERROR - } else { - OTHER_ERROR - } - } else { - SUCCESS - } - } - - private fun CallCandidateResolutionContext<*>.checkDispatchReceiver() = checkAndReport { - val candidateDescriptor = candidateDescriptor - val dispatchReceiver = candidateCall.dispatchReceiver - if (dispatchReceiver != null) { - var nestedClass: ClassDescriptor? = null - if (candidateDescriptor is ClassConstructorDescriptor - && DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration) - ) { - nestedClass = candidateDescriptor.containingDeclaration - } else if (candidateDescriptor is FakeCallableDescriptorForObject) { - nestedClass = candidateDescriptor.getReferencedObject() - } - if (nestedClass != null) { - tracing.nestedClassAccessViaInstanceReference(trace, nestedClass, candidateCall.explicitReceiverKind) - return@checkAndReport OTHER_ERROR - } - } - - assert((dispatchReceiver != null) == (candidateCall.resultingDescriptor.dispatchReceiverParameter != null)) { - "Shouldn't happen because of TaskPrioritizer: $candidateDescriptor" - } - - SUCCESS - } - - private fun checkOuterClassMemberIsAccessible(context: CallCandidateResolutionContext<*>): Boolean { - - fun KtElement.insideScript() = (containingFile as? KtFile)?.isScript() ?: false - - // context.scope doesn't contains outer class implicit receiver if we inside nested class - // Outer scope for some class in script file is scopeForInitializerResolution see: DeclarationScopeProviderImpl.getResolutionScopeForDeclaration - if (!context.call.callElement.insideScript()) return true - - // In "this@Outer.foo()" the error will be reported on "this@Outer" instead - if (context.call.explicitReceiver != null || context.call.dispatchReceiver != null) return true - - val candidateThis = getDeclaringClass(context.candidateCall.candidateDescriptor) - if (candidateThis == null || candidateThis.kind.isSingleton) return true - - return DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, context.call.callElement, candidateThis) - } - - private fun CallCandidateResolutionContext<*>.checkAbstractAndSuper() = check { - val descriptor = candidateDescriptor - val expression = candidateCall.call.calleeExpression - - if (expression is KtSimpleNameExpression) { - // 'B' in 'class A: B()' is JetConstructorCalleeExpression - if (descriptor is ConstructorDescriptor) { - val modality = descriptor.constructedClass.modality - if (modality == Modality.ABSTRACT) { - tracing.instantiationOfAbstractClass(trace) - } - } - } - - val superDispatchReceiver = getReceiverSuper(candidateCall.dispatchReceiver) - if (superDispatchReceiver != null) { - if (descriptor is MemberDescriptor && descriptor.modality == Modality.ABSTRACT) { - tracing.abstractSuperCall(trace) - candidateCall.addStatus(OTHER_ERROR) - } - } - - // 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this - // See TaskPrioritizer for more - val superExtensionReceiver = getReceiverSuper(candidateCall.extensionReceiver) - if (superExtensionReceiver != null) { - trace.report(SUPER_CANT_BE_EXTENSION_RECEIVER.on(superExtensionReceiver, superExtensionReceiver.text)) - candidateCall.addStatus(OTHER_ERROR) - } - } - - private fun CallCandidateResolutionContext<*>.checkConstructedExpandedType() = check { - val descriptor = candidateDescriptor - - if (descriptor is TypeAliasConstructorDescriptor) { - if (descriptor.returnType.containsTypeProjectionsInTopLevelArguments()) { - trace.report(EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED.on(call.callElement, descriptor.returnType)) - candidateCall.addStatus(OTHER_ERROR) - } - } - } - - private fun getReceiverSuper(receiver: Receiver?): KtSuperExpression? { - if (receiver is ExpressionReceiver) { - val expression = receiver.expression - if (expression is KtSuperExpression) { - return expression - } - } - return null - } - - private fun getDeclaringClass(candidate: CallableDescriptor): ClassDescriptor? { - val expectedThis = candidate.dispatchReceiverParameter ?: return null - val descriptor = expectedThis.containingDeclaration - return if (descriptor is ClassDescriptor) descriptor else null - } - - fun checkAllValueArguments( - context: CallCandidateResolutionContext, - resolveFunctionArgumentBodies: ResolveArgumentsMode - ): ValueArgumentsCheckingResult { - val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies) - var resultStatus = checkingResult.status - resultStatus = resultStatus.combine(checkReceivers(context)) - - return ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes) - } - - private fun > checkValueArgumentTypes( - context: CallResolutionContext, - candidateCall: MutableResolvedCall, - resolveFunctionArgumentBodies: ResolveArgumentsMode - ): ValueArgumentsCheckingResult { - var resultStatus = SUCCESS - val argumentTypes = Lists.newArrayList() - val infoForArguments = candidateCall.dataFlowInfoForArguments - for ((parameterDescriptor, resolvedArgument) in candidateCall.valueArguments) { - for (argument in resolvedArgument.arguments) { - val expression = argument.getArgumentExpression() ?: continue - - val expectedType = getEffectiveExpectedType(parameterDescriptor, argument, context) - - val newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument)).replaceExpectedType(expectedType) - val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(expression, newContext, resolveFunctionArgumentBodies, expectedType.isSuspendFunctionType) - val type = typeInfoForCall.type - infoForArguments.updateInfo(argument, typeInfoForCall.dataFlowInfo) - - var matchStatus = ArgumentMatchStatus.SUCCESS - var resultingType: KotlinType? = type - if (type == null || (type.isError && !type.isFunctionPlaceholder)) { - matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE - } else if (!noExpectedType(expectedType)) { - if (!argumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) { - val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext) - if (smartCast == null) { - resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR - matchStatus = ArgumentMatchStatus.TYPE_MISMATCH - } else { - resultingType = smartCast - } - } else if (ErrorUtils.containsUninferredTypeVariable(expectedType)) { - matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES - } - - val spreadElement = argument.getSpreadElement() - if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) { - val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, type, context) - val smartCastResult = smartCastManager.checkAndRecordPossibleCast( - dataFlowValue, expectedType, expression, context, - call = null, recordExpressionType = false - ) - if (smartCastResult == null || !smartCastResult.isCorrect) { - context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement)) - } - } - } - argumentTypes.add(resultingType) - candidateCall.recordArgumentMatchStatus(argument, matchStatus) - } - } - return ValueArgumentsCheckingResult(resultStatus, argumentTypes) - } - - private fun smartCastValueArgumentTypeIfPossible( - expression: KtExpression, - expectedType: KotlinType, - actualType: KotlinType, - context: ResolutionContext<*> - ): KotlinType? { - val receiverToCast = ExpressionReceiver.create(KtPsiUtil.safeDeparenthesize(expression), actualType, context.trace.bindingContext) - val variants = smartCastManager.getSmartCastVariantsExcludingReceiver(context, receiverToCast) - return variants.firstOrNull { possibleType -> - KotlinTypeChecker.DEFAULT.isSubtypeOf(possibleType, expectedType) - } - } - - private fun tryNotNullableArgument(argumentType: KotlinType, parameterType: KotlinType): ResolutionStatus? { - if (!argumentType.isMarkedNullable || parameterType.isMarkedNullable) return null - - val notNullableArgumentType = argumentType.makeNotNullable() - val isApplicable = argumentTypeResolver.isSubtypeOfForArgumentType(notNullableArgumentType, parameterType) - return if (isApplicable) NULLABLE_ARGUMENT_TYPE_MISMATCH else null - } - - private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(): Unit = check { - val extensionReceiver = candidateDescriptor.extensionReceiverParameter - val dispatchReceiver = candidateDescriptor.dispatchReceiverParameter - - // For the expressions like '42.(f)()' where f: String.() -> Unit we'd like to generate a type mismatch error on '1', - // not to throw away the candidate, so the following check is skipped. - if (!isInvokeCallOnExpressionWithBothReceivers(call)) { - checkReceiverTypeError(extensionReceiver, candidateCall.extensionReceiver) - } - checkReceiverTypeError(dispatchReceiver, candidateCall.dispatchReceiver) - } - - private fun CallCandidateResolutionContext<*>.checkReceiverTypeError( - receiverParameterDescriptor: ReceiverParameterDescriptor?, - receiverArgument: ReceiverValue? - ) = checkAndReport { - if (receiverParameterDescriptor == null || receiverArgument == null) return@checkAndReport SUCCESS - - val erasedReceiverType = getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor) - - if (smartCastManager.getSmartCastReceiverResult(receiverArgument, erasedReceiverType, this) == null) { - RECEIVER_TYPE_ERROR - } else { - SUCCESS - } - } - - private fun checkReceivers(context: CallCandidateResolutionContext): ResolutionStatus { - var resultStatus = SUCCESS - val candidateCall = context.candidateCall - - // Comment about a very special case. - // Call 'b.foo(1)' where class 'Foo' has an extension member 'fun B.invoke(Int)' should be checked two times for safe call (in 'checkReceiver'), because - // both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'. - // Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object. - - resultStatus = resultStatus.combine( - context.checkReceiver( - candidateCall, - candidateCall.resultingDescriptor.extensionReceiverParameter, - candidateCall.extensionReceiver, - candidateCall.explicitReceiverKind.isExtensionReceiver, - implicitInvokeCheck = false, isDispatchReceiver = false - ) - ) - - resultStatus = resultStatus.combine( - context.checkReceiver( - candidateCall, - candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver, - candidateCall.explicitReceiverKind.isDispatchReceiver, - // for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error - implicitInvokeCheck = context.call is CallForImplicitInvoke, - isDispatchReceiver = true - ) - ) - - if (!context.isDebuggerContext - && candidateCall.dispatchReceiver != null - // Do not report error if it's already reported when checked without receiver - && context.isCandidateVisible(receiverArgument = DescriptorVisibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) { - resultStatus = resultStatus.combine( - context.checkVisibilityWithDispatchReceiver( - candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType - ) - ) - } - - return resultStatus - } - - private fun CallCandidateResolutionContext.checkReceiver( - candidateCall: MutableResolvedCall, - receiverParameter: ReceiverParameterDescriptor?, - receiverArgument: ReceiverValue?, - isExplicitReceiver: Boolean, - implicitInvokeCheck: Boolean, - isDispatchReceiver: Boolean - ): ResolutionStatus { - if (receiverParameter == null || receiverArgument == null) return SUCCESS - val candidateDescriptor = candidateCall.candidateDescriptor - if (TypeUtils.dependsOnTypeParameters(receiverParameter.type, candidateDescriptor.typeParameters)) return SUCCESS - - // Here we know that receiver is OK ignoring nullability and check that nullability is OK too - // Doing it simply as full subtyping check (receiverValueType <: receiverParameterType) - val call = candidateCall.call - val safeAccess = isExplicitReceiver && !implicitInvokeCheck && call.isSemanticallyEquivalentToSafeCall - val expectedReceiverParameterType = if (safeAccess) TypeUtils.makeNullable(receiverParameter.type) else receiverParameter.type - - val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this) - if (smartCastSubtypingResult == null) { - tracing.wrongReceiverType( - trace, receiverParameter, receiverArgument, - this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall)) - ) - return OTHER_ERROR - } - - val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK - val smartCastNeeded = - notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver) - var reportUnsafeCall = false - - var nullableImplicitInvokeReceiver = false - var receiverArgumentType = receiverArgument.type - if (implicitInvokeCheck && call is CallForImplicitInvoke && call.isSafeCall()) { - val outerCallReceiver = call.outerCall.explicitReceiver - if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) { - val outerReceiverDataFlowValue = dataFlowValueFactory.createDataFlowValue(outerCallReceiver, this) - val outerReceiverNullability = dataFlowInfo.getStableNullability(outerReceiverDataFlowValue) - if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) { - nullableImplicitInvokeReceiver = true - receiverArgumentType = TypeUtils.makeNullable(receiverArgumentType) - } - } - } - - val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverArgument, this) - val nullability = dataFlowInfo.getStableNullability(dataFlowValue) - val expression = (receiverArgument as? ExpressionReceiver)?.expression - if (nullability.canBeNull() && !nullability.canBeNonNull()) { - if (!TypeUtils.isNullableType(expectedReceiverParameterType)) { - reportUnsafeCall = true - } - if (dataFlowValue.immanentNullability.canBeNonNull()) { - expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) } - } - } else if (!nullableImplicitInvokeReceiver && smartCastNeeded) { - // Look if smart cast has some useful nullability info - - val smartCastResult = smartCastManager.checkAndRecordPossibleCast( - dataFlowValue, expectedReceiverParameterType, - expression, this, candidateCall.call, recordExpressionType = true - ) { possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) } - - if (smartCastResult == null) { - if (notNullReceiverExpected) { - reportUnsafeCall = true - } - } else { - if (isDispatchReceiver) { - candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType) - } else { - candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType) - } - if (!smartCastResult.isCorrect) { - // Error about unstable smart cast reported within checkAndRecordPossibleCast - return UNSTABLE_SMARTCAST_FOR_RECEIVER_ERROR - } - } - } - - if (reportUnsafeCall || nullableImplicitInvokeReceiver) { - tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck) - return UNSAFE_CALL_ERROR - } - - additionalTypeCheckers.forEach { it.checkReceiver(receiverParameter, receiverArgument, safeAccess, this) } - - return SUCCESS - } - - inner class ValueArgumentsCheckingResult(val status: ResolutionStatus, val argumentTypes: List) - - private fun CallCandidateResolutionContext<*>.checkGenericBoundsInAFunctionCall( - ktTypeArguments: List, - typeArguments: List, - functionDescriptor: CallableDescriptor, - substitutor: TypeSubstitutor, - trace: BindingTrace - ) { - if (functionDescriptor is TypeAliasConstructorDescriptor) { - checkGenericBoundsInTypeAliasConstructorCall(ktTypeArguments, functionDescriptor, substitutor, trace) - return - } - - val typeParameters = functionDescriptor.typeParameters - for (i in 0..min(typeParameters.size, ktTypeArguments.size) - 1) { - val typeParameterDescriptor = typeParameters[i] - val typeArgument = typeArguments[i] - val typeReference = ktTypeArguments[i].typeReference - if (typeReference != null) { - upperBoundChecker.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace) - } - } - } - - private class TypeAliasSingleStepExpansionReportStrategy( - private val callElement: KtElement, - typeAlias: TypeAliasDescriptor, - ktTypeArguments: List, - private val trace: BindingTrace, - private val upperBoundChecker: UpperBoundChecker - ) : TypeAliasExpansionReportStrategy { - init { - assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" } - } - - private val argumentsMapping = typeAlias.declaredTypeParameters.zip(ktTypeArguments).toMap() - - override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) { - // can't happen in single-step expansion - } - - override fun conflictingProjection( - typeAlias: TypeAliasDescriptor, - typeParameter: TypeParameterDescriptor?, - substitutedArgument: KotlinType - ) { - // can't happen in single-step expansion - } - - override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) { - // can't happen in single-step expansion - } - - override fun repeatedAnnotation(annotation: AnnotationDescriptor) { - // can't happen in single-step expansion - } - - override fun boundsViolationInSubstitution( - substitutor: TypeSubstitutor, - unsubstitutedArgument: KotlinType, - argument: KotlinType, - typeParameter: TypeParameterDescriptor - ) { - val descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor - val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument] - val argumentTypeReferenceElement = argumentElement?.typeReference - - upperBoundChecker.checkBounds(argumentTypeReferenceElement, argument, typeParameter, substitutor, trace, callElement) - } - } - - private fun CallCandidateResolutionContext<*>.checkGenericBoundsInTypeAliasConstructorCall( - ktTypeArguments: List, - typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor, - typeAliasParametersSubstitutor: TypeSubstitutor, - trace: BindingTrace - ) { - val substitutedType = typeAliasParametersSubstitutor.substitute(typeAliasConstructorDescriptor.returnType, Variance.INVARIANT)!! - val boundsSubstitutor = TypeSubstitutor.create(substitutedType) - - val typeAliasDescriptor = typeAliasConstructorDescriptor.containingDeclaration - - val unsubstitutedType = typeAliasDescriptor.expandedType - if (unsubstitutedType.isError) return - - val reportStrategy = - TypeAliasSingleStepExpansionReportStrategy(call.callElement, typeAliasDescriptor, ktTypeArguments, trace, upperBoundChecker) - - // TODO refactor TypeResolver - // - perform full type alias expansion - // - provide type alias expansion stack in diagnostics - - checkTypeInTypeAliasSubstitutionRec(reportStrategy, unsubstitutedType, typeAliasParametersSubstitutor, boundsSubstitutor) - } - - - private fun checkTypeInTypeAliasSubstitutionRec( - reportStrategy: TypeAliasExpansionReportStrategy, - unsubstitutedType: KotlinType, - typeAliasParametersSubstitutor: TypeSubstitutor, - boundsSubstitutor: TypeSubstitutor - ) { - // TODO refactor TypeResolver - val typeParameters = unsubstitutedType.constructor.parameters - - // TODO do not perform substitution for type arguments multiple times - val substitutedTypeArguments = typeAliasParametersSubstitutor.safeSubstitute(unsubstitutedType, Variance.INVARIANT).arguments - - for (i in 0..min(typeParameters.size, substitutedTypeArguments.size) - 1) { - val substitutedTypeProjection = substitutedTypeArguments[i] - if (substitutedTypeProjection.isStarProjection) continue - - val typeParameter = typeParameters[i] - val substitutedTypeArgument = substitutedTypeProjection.type - val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].type - - reportStrategy.boundsViolationInSubstitution( - boundsSubstitutor, - unsubstitutedTypeArgument, - substitutedTypeArgument, - typeParameter - ) - - checkTypeInTypeAliasSubstitutionRec( - reportStrategy, - unsubstitutedTypeArgument, - typeAliasParametersSubstitutor, - boundsSubstitutor - ) - } - } - - private fun CallCandidateResolutionContext.shouldContinue() = - candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess() - - private inline fun CallCandidateResolutionContext.check( - crossinline checker: CallCandidateResolutionContext.() -> Unit - ) { - if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() } - } - - private inline fun CallCandidateResolutionContext.checkAndReport( - crossinline checker: CallCandidateResolutionContext.() -> ResolutionStatus - ) { - check { - candidateCall.addStatus(checker()) - } - } - - private val CallCandidateResolutionContext<*>.candidateDescriptor: CallableDescriptor - get() = candidateCall.candidateDescriptor -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index d4873124231..60dec9bb14e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.CallTransformer -import org.jetbrains.kotlin.resolve.calls.CandidateResolver import org.jetbrains.kotlin.resolve.calls.context.* import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl @@ -58,7 +57,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.compactIfPossible import org.jetbrains.kotlin.utils.sure class NewResolutionOldInference( - private val candidateResolver: CandidateResolver, private val towerResolver: TowerResolver, private val resolutionResultsHandler: ResolutionResultsHandler, private val dynamicCallableDescriptors: DynamicCallableDescriptors, @@ -231,7 +229,6 @@ class NewResolutionOldInference( resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call, CandidateResolveMode.EXIT_ON_FIRST_ERROR ) - candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status)) MyCandidate(diagnostics, resolvedCall) { @@ -478,7 +475,6 @@ class NewResolutionOldInference( candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call, CandidateResolveMode.EXIT_ON_FIRST_ERROR ) - candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo val diagnostics = createDiagnosticsForCandidate(towerCandidate, candidateCall) return MyCandidate(diagnostics, candidateCall) {