diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 714ca13f5f1..42082eaf848 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -29,8 +29,8 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter; +import org.jetbrains.kotlin.resolve.calls.model.CallResolutionResult; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; @@ -122,7 +122,7 @@ public interface BindingContext { new BasicWritableSlice<>(DO_NOTHING); WritableSlice> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING); - WritableSlice ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING); + WritableSlice ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING); WritableSlice DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL = new BasicWritableSlice<>(DO_NOTHING); WritableSlice TAIL_RECURSION_CALL = Slices.createSimpleSlice(); WritableSlice CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java index 61643f98ea1..7b04a546c49 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/OverloadResolutionResultsUtil.java @@ -24,8 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.KotlinResolutionConfigurationKt; import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyResolvedCall; -import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyVariableAsFunctionCall; +import org.jetbrains.kotlin.resolve.calls.tower.KotlinToResolvedCallTransformerKt; import org.jetbrains.kotlin.types.KotlinType; import java.util.Collection; @@ -61,7 +60,7 @@ public class OverloadResolutionResultsUtil { } } else { - if (resultingCall instanceof StubOnlyResolvedCall || resultingCall instanceof StubOnlyVariableAsFunctionCall) { + if (KotlinToResolvedCallTransformerKt.isNewNotCompleted(resultingCall)) { return null; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt index 2fd5855f2f5..1c991973aa4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt @@ -19,8 +19,6 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPsiUtil @@ -28,22 +26,22 @@ import org.jetbrains.kotlin.psi.KtReturnExpression import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ContextDependency -import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom +import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind -import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver +import org.jetbrains.kotlin.types.TypeApproximator +import org.jetbrains.kotlin.types.TypeApproximatorConfiguration +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo -import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.addIfNotNull @@ -51,10 +49,9 @@ class KotlinResolutionCallbacksImpl( val topLevelCallContext: BasicCallResolutionContext, val expressionTypingServices: ExpressionTypingServices, val typeApproximator: TypeApproximator, - val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, val argumentTypeResolver: ArgumentTypeResolver, - val doubleColonExpressionResolver: DoubleColonExpressionResolver, - val languageVersionSettings: LanguageVersionSettings + val languageVersionSettings: LanguageVersionSettings, + val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer ): KotlinResolutionCallbacks { val trace: BindingTrace = topLevelCallContext.trace @@ -143,72 +140,8 @@ class KotlinResolutionCallbacksImpl( return KtPsiUtil.deparenthesize(lastExpression) } - override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) { + override fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) { kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace(candidate, trace) } - override fun completeCallableReference( - callableReferenceArgument: PostponedCallableReferenceArgument, - resultTypeParameters: List - ) { - val callableCandidate = callableReferenceArgument.callableResolutionCandidate - val psiCallArgument = callableReferenceArgument.argument.psiCallArgument as CallableReferenceKotlinCallArgumentImpl - val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression - val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor() - - - // write down type for callable reference expression - val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT) - argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter, - resultType, - callableReferenceExpression) - val reference = callableReferenceExpression.callableReference - - val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) { - ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver - ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver - else -> null - } - - val explicitReceiver = explicitCallableReceiver?.receiver - val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList()) - - val tracing = TracingStrategyImpl.create(reference, psiCall) - val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call") - - val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue, - callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind, - null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)) - resolvedCall.setResultingSubstitutor(resultSubstitutor) - - tracing.bindCall(trace, psiCall) - tracing.bindReference(trace, resolvedCall) - tracing.bindResolvedCall(trace, resolvedCall) - - resolvedCall.setStatusToSuccess() - resolvedCall.markCallAsCompleted() - - when (callableCandidate.candidate) { - is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext) - is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext) - } - - // TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo - trace.recordType(callableReferenceExpression, resultType) - trace.record(BindingContext.PROCESSED, callableReferenceExpression) - - doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression) - } - - override fun completeCollectionLiteralCalls(collectionLiteralArgument: PostponedCollectionLiteralArgument) { - val psiCallArgument = collectionLiteralArgument.argument.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl - val context = psiCallArgument.outerCallContext - - val actualContext = context - .replaceBindingTrace(trace) - .replaceExpectedType(collectionLiteralArgument.expectedType) - .replaceContextDependency(ContextDependency.INDEPENDENT) - - expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext) - } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt index 997d4d4e019..cda4f375e1c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgum import org.jetbrains.kotlin.resolve.calls.model.KotlinCall import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.resolve.isHiddenInResolution +import org.jetbrains.kotlin.utils.addToStdlib.safeAs class KotlinResolutionStatelessCallbacksImpl( private val languageVersionSettings: LanguageVersionSettings @@ -54,4 +55,7 @@ class KotlinResolutionStatelessCallbacksImpl( override fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower = (argument as CallableReferenceKotlinCallArgumentImpl).scopeTowerForResolution + + override fun getVariableCandidateIfInvoke(functionCall: KotlinCall) = + functionCall.safeAs()?.variableCall } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index 43946a02027..8def8d09504 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -16,10 +16,8 @@ package org.jetbrains.kotlin.resolve.calls.tower -import org.jetbrains.kotlin.builtins.replaceReturnType import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.* @@ -32,9 +30,15 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.isFakeElement import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.components.AdditionalDiagnosticReporter import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.CallPosition +import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.substitute +import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus @@ -42,12 +46,15 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.types.ErrorUtils -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.NewCapturedType import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer +import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver +import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils +import org.jetbrains.kotlin.types.typeUtil.contains +import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.util.* @@ -56,91 +63,71 @@ class KotlinToResolvedCallTransformer( private val languageFeatureSettings: LanguageVersionSettings, private val dataFlowAnalyzer: DataFlowAnalyzer, private val argumentTypeResolver: ArgumentTypeResolver, - private val constantExpressionEvaluator: ConstantExpressionEvaluator -) { + private val constantExpressionEvaluator: ConstantExpressionEvaluator, + private val expressionTypingServices: ExpressionTypingServices, + private val doubleColonExpressionResolver: DoubleColonExpressionResolver, + private val additionalDiagnosticReporter: AdditionalDiagnosticReporter + ) { + + fun onlyTransform( + resolvedCallAtom: ResolvedCallAtom + ): ResolvedCall = transformToResolvedCall(resolvedCallAtom, completed = false) fun transformAndReport( - baseResolvedCall: ResolvedKotlinCall, - context: BasicCallResolutionContext, - trace: BindingTrace? // if trace is not null then all information will be reported to this trace + baseResolvedCall: CallResolutionResult, + context: BasicCallResolutionContext ): ResolvedCall { - if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) { - val allResolvedCalls = baseResolvedCall.allInnerCalls.mapTo(ArrayList>()) { transformAndReportCompletedCall(it, context, trace) } - val result = transformAndReportCompletedCall(baseResolvedCall.completedCall, context, trace) - allResolvedCalls.add(result) + val candidate = baseResolvedCall.resultCallAtom!! + when (baseResolvedCall.type) { + CallResolutionResult.Type.PARTIAL -> { + context.trace.record(BindingContext.ONLY_RESOLVED_CALL, candidate.atom.psiKotlinCall.psiCall, baseResolvedCall) - if (trace != null) { - // todo: check checkers order - val callCheckerContext = CallCheckerContext(context.replaceBindingTrace(trace), languageFeatureSettings) - for (resolvedCall in allResolvedCalls) { - runCallCheckers(resolvedCall, callCheckerContext) - } - runLambdaArgumentsChecks(context, trace, baseResolvedCall.lambdaArguments) - allResolvedCalls.map { - if (it is VariableAsFunctionResolvedCall) it.functionCall else it - }.forEach { - runArgumentsChecks(context, trace, it as NewResolvedCallImpl<*>) - } + return createStubResolvedCallAndWriteItToTrace(candidate, context.trace) } + CallResolutionResult.Type.ERROR, CallResolutionResult.Type.COMPLETED -> { + val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor() + val ktPrimitiveCompleter = ResolvedAtomCompleter(resultSubstitutor, context.trace, context, this, + expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, + languageFeatureSettings) - return result + for (subKtPrimitive in candidate.subResolvedAtoms) { + ktPrimitiveCompleter.completeAll(subKtPrimitive) + } + + return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall + } } - - val onlyResolvedCall = (baseResolvedCall as ResolvedKotlinCall.OnlyResolvedKotlinCall) - trace?.record(BindingContext.ONLY_RESOLVED_CALL, onlyResolvedCall.candidate.kotlinCall.psiKotlinCall.psiCall, onlyResolvedCall) - - return createStubResolvedCallAndWriteItToTrace(onlyResolvedCall.candidate, trace) } - fun createStubResolvedCallAndWriteItToTrace(candidate: KotlinResolutionCandidate, trace: BindingTrace?): ResolvedCall { - val result = when (candidate) { - is VariableAsFunctionKotlinResolutionCandidate -> { - val variableStub = StubOnlyResolvedCall(candidate.resolvedVariable) - val invokeStub = StubOnlyResolvedCall(candidate.invokeCandidate) - StubOnlyVariableAsFunctionCall(variableStub, invokeStub) as ResolvedCall - } - is SimpleKotlinResolutionCandidate -> { - StubOnlyResolvedCall(candidate) - } - } - if (trace != null) { - val tracing = candidate.kotlinCall.psiKotlinCall.tracingStrategy + fun createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall { + val result = onlyTransform(candidate) + val psiKotlinCall = candidate.atom.psiKotlinCall + val tracing = psiKotlinCall.safeAs()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy - tracing.bindReference(trace, result) - tracing.bindResolvedCall(trace, result) - } + tracing.bindReference(trace, result) + tracing.bindResolvedCall(trace, result) return result } - - private fun transformAndReportCompletedCall( - completedCall: CompletedKotlinCall, - context: BasicCallResolutionContext, - trace: BindingTrace? + fun transformToResolvedCall( + completedCallAtom: ResolvedCallAtom, + completed: Boolean, + resultSubstitutor: NewTypeSubstitutor = FreshVariableNewTypeSubstitutor.Empty ): ResolvedCall { - fun C.runIfTraceNotNull(action: (BasicCallResolutionContext, BindingTrace, C) -> Unit): C { - if (trace != null) action(context, trace, this) - return this + val psiKotlinCall = completedCallAtom.atom.psiKotlinCall + return if (psiKotlinCall is PSIKotlinCallForInvoke) { + @Suppress("UNCHECKED_CAST") + NewVariableAsFunctionResolvedCallImpl( + NewResolvedCallImpl(psiKotlinCall.variableCall.resolvedCall, completed, resultSubstitutor), + NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor) + ) as ResolvedCall } - - return when (completedCall) { - is CompletedKotlinCall.Simple -> { - NewResolvedCallImpl(completedCall).runIfTraceNotNull(this::bindResolvedCall) - } - is CompletedKotlinCall.VariableAsFunction -> { - val resolvedCall = NewVariableAsFunctionResolvedCallImpl( - completedCall, - NewResolvedCallImpl(completedCall.variableCall), - NewResolvedCallImpl(completedCall.invokeCall) - ).runIfTraceNotNull(this::bindResolvedCall) - - @Suppress("UNCHECKED_CAST") - (resolvedCall as ResolvedCall) - } + else { + NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor) } } - private fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) { + fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) { val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.variableCall.call.calleeExpression else @@ -158,57 +145,8 @@ class KotlinToResolvedCallTransformer( } } - - private fun runLambdaArgumentsChecks( - context: BasicCallResolutionContext, - trace: BindingTrace, - lambdaArguments: List - ) { - for (lambdaArgument in lambdaArguments) { - val returnType = lambdaArgument.finalReturnType - - updateTraceForLambdaReturnType(lambdaArgument, trace, returnType) - - for (lambdaResult in lambdaArgument.resultArguments) { - val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue - val newContext = - context.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument) - .replaceExpectedType(returnType) - .replaceBindingTrace(trace) - - val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue - updateRecordedType(argumentExpression, newContext) - } - } - } - - private fun updateTraceForLambdaReturnType(lambdaArgument: PostponedLambdaArgument, trace: BindingTrace, returnType: UnwrappedType) { - val psiCallArgument = lambdaArgument.argument.psiCallArgument - - val ktArgumentExpression: KtExpression - val ktFunction: KtElement - when (psiCallArgument) { - is LambdaKotlinCallArgumentImpl -> { - ktArgumentExpression = psiCallArgument.ktLambdaExpression - ktFunction = ktArgumentExpression.functionLiteral - } - is FunctionExpressionImpl -> { - ktArgumentExpression = psiCallArgument.ktFunction - ktFunction = ktArgumentExpression - } - else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument") - } - - val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?: - throw AssertionError("No function descriptor for resolved lambda argument") - functionDescriptor.setReturnType(returnType) - - val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument") - trace.recordType(ktArgumentExpression, existingLambdaType.replaceReturnType(returnType)) - } - // todo very beginning code - private fun runArgumentsChecks( + fun runArgumentsChecks( context: BasicCallResolutionContext, trace: BindingTrace, resolvedCall: NewResolvedCallImpl<*> @@ -320,19 +258,24 @@ class KotlinToResolvedCallTransformer( return expressionType != null && TypeUtils.isNullableType(expressionType) } - private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) { - reportCallDiagnostic(context, trace, simpleResolvedCall.completedCall) - val tracing = simpleResolvedCall.completedCall.kotlinCall.psiKotlinCall.tracingStrategy + internal fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, resolvedCall: ResolvedCall<*>) { + resolvedCall.safeAs>()?.let { bindAndReport(context, trace, it) } + resolvedCall.safeAs()?.let { bindAndReport(context, trace, it) } + } + + private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) { + reportCallDiagnostic(context, trace, simpleResolvedCall.resolvedCallAtom, simpleResolvedCall.resultingDescriptor) + val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy tracing.bindReference(trace, simpleResolvedCall) tracing.bindResolvedCall(trace, simpleResolvedCall) } - private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) { - reportCallDiagnostic(context, trace, variableAsFunction.variableCall.completedCall) - reportCallDiagnostic(context, trace, variableAsFunction.functionCall.completedCall) + private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) { + reportCallDiagnostic(context, trace, variableAsFunction.variableCall.resolvedCallAtom, variableAsFunction.variableCall.resultingDescriptor) + reportCallDiagnostic(context, trace, variableAsFunction.functionCall.resolvedCallAtom, variableAsFunction.functionCall.resultingDescriptor) - val outerTracingStrategy = variableAsFunction.completedCall.kotlinCall.psiKotlinCall.tracingStrategy + val outerTracingStrategy = variableAsFunction.baseCall.tracingStrategy outerTracingStrategy.bindReference(trace, variableAsFunction.variableCall) outerTracingStrategy.bindResolvedCall(trace, variableAsFunction) variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall) @@ -341,13 +284,17 @@ class KotlinToResolvedCallTransformer( private fun reportCallDiagnostic( context: BasicCallResolutionContext, trace: BindingTrace, - completedCall: CompletedKotlinCall.Simple + completedCallAtom: ResolvedCallAtom, + resultingDescriptor: CallableDescriptor ) { val trackingTrace = TrackingBindingTrace(trace) val newContext = context.replaceBindingTrace(trackingTrace) - val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCall.kotlinCall.psiKotlinCall) + val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall) - for (diagnostic in completedCall.diagnostics) { + val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() + additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder) + + for (diagnostic in completedCallAtom.diagnostics + diagnosticHolder.getDiagnostics()) { trackingTrace.reported = false diagnostic.report(diagnosticReporter) @@ -460,24 +407,46 @@ sealed class NewAbstractResolvedCall(): ResolvedCall } class NewResolvedCallImpl( - val completedCall: CompletedKotlinCall.Simple + val resolvedCallAtom: ResolvedCallAtom, + val completed: Boolean, + substitutor: NewTypeSubstitutor ): NewAbstractResolvedCall() { - override val kotlinCall: KotlinCall get() = completedCall.kotlinCall + private val resultingDescriptor = run { + val candidateDescriptor = resolvedCallAtom.candidateDescriptor + val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false - override fun getStatus(): ResolutionStatus = completedCall.resultingApplicability.toResolutionStatus() + when { + candidateDescriptor is FunctionDescriptor || + (candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes)) -> + // this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types, + // but it seems like temporary solution. + candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes(substitutor) + else -> + candidateDescriptor + } + } + + val typeArguments = resolvedCallAtom.substitutor.freshVariables.map { + val substituted = substitutor.safeSubstitute(it.defaultType) + TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted + } + + override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom + + override fun getStatus(): ResolutionStatus = getResultApplicability(resolvedCallAtom.diagnostics).toResolutionStatus() override val argumentMappingByOriginal: Map - get() = completedCall.argumentMappingByOriginal + get() = resolvedCallAtom.argumentMappingByOriginal - override fun getCandidateDescriptor(): D = completedCall.candidateDescriptor as D - override fun getResultingDescriptor(): D = completedCall.resultingDescriptor as D - override fun getExtensionReceiver(): ReceiverValue? = completedCall.extensionReceiver?.receiverValue - override fun getDispatchReceiver(): ReceiverValue? = completedCall.dispatchReceiver?.receiverValue - override fun getExplicitReceiverKind(): ExplicitReceiverKind = completedCall.explicitReceiverKind + override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D + override fun getResultingDescriptor(): D = resultingDescriptor as D + override fun getExtensionReceiver(): ReceiverValue? = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue + override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue + override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind override fun getTypeArguments(): Map { val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap() - return typeParameters.zip(completedCall.typeArguments).toMap() + return typeParameters.zip(typeArguments).toMap() } override fun getSmartCastDispatchReceiverType(): KotlinType? = null // todo @@ -490,30 +459,18 @@ fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = wh } class NewVariableAsFunctionResolvedCallImpl( - val completedCall: CompletedKotlinCall.VariableAsFunction, override val variableCall: NewResolvedCallImpl, override val functionCall: NewResolvedCallImpl -): VariableAsFunctionResolvedCall, ResolvedCall by functionCall - -class StubOnlyResolvedCall(val candidate: SimpleKotlinResolutionCandidate): NewAbstractResolvedCall() { - override fun getStatus() = candidate.resultingApplicability.toResolutionStatus() - - override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D - override fun getResultingDescriptor(): D = candidate.descriptorWithFreshTypes as D - override fun getExtensionReceiver() = candidate.extensionReceiver?.receiver?.receiverValue - override fun getDispatchReceiver() = candidate.dispatchReceiverArgument?.receiver?.receiverValue - override fun getExplicitReceiverKind() = candidate.explicitReceiverKind - - override fun getTypeArguments(): Map = emptyMap() - - override fun getSmartCastDispatchReceiverType(): KotlinType? = null - - override val argumentMappingByOriginal: Map - get() = candidate.argumentMappingByOriginal - override val kotlinCall: KotlinCall get() = candidate.kotlinCall +): VariableAsFunctionResolvedCall, ResolvedCall by functionCall { + val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast().baseCall } -class StubOnlyVariableAsFunctionCall( - override val variableCall: StubOnlyResolvedCall, - override val functionCall: StubOnlyResolvedCall -) : VariableAsFunctionResolvedCall, ResolvedCall by functionCall +fun ResolvedCall<*>.isNewNotCompleted(): Boolean { + if (this is NewVariableAsFunctionResolvedCallImpl) { + return !functionCall.completed + } + if (this is NewResolvedCallImpl<*>) { + return !completed + } + return false +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt index 4e2c3c6d26e..74572bb6b1a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt @@ -147,7 +147,7 @@ class SubKotlinCallArgumentImpl( override val dataFlowInfoBeforeThisArgument: DataFlowInfo, override val dataFlowInfoAfterThisArgument: DataFlowInfo, override val receiver: ReceiverValueWithSmartCastInfo, - override val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall + override val callResult: CallResolutionResult ): SimplePSIKotlinCallArgument(), SubKotlinCallArgument { override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName @@ -216,7 +216,7 @@ internal fun createSimplePSICallArgument( } // todo hack for if expression: sometimes we not write properly type information for branches val baseType = typeInfoForArgument.type?.unwrap() ?: - onlyResolvedCall?.candidate?.lastCall?.descriptorWithFreshTypes?.returnType?.unwrap() ?: + onlyResolvedCall?.resultCallAtom?.freshReturnType ?: return null // we should use DFI after this argument, because there can be some useful smartcast. Popular case: if branches. @@ -232,5 +232,4 @@ internal fun createSimplePSICallArgument( else { SubKotlinCallArgumentImpl(valueArgument, dataFlowInfoBeforeThisArgument, typeInfoForArgument.dataFlowInfo, receiverToCast, onlyResolvedCall) } - -} \ No newline at end of file +} 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 8514c3e824a..3d3a5002edb 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 @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.results.* +import org.jetbrains.kotlin.resolve.calls.results.ManyCandidates import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors @@ -56,6 +57,7 @@ import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.expressions.* +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import java.util.* @@ -93,7 +95,7 @@ class PSICallResolver( var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke) val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) - if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllCompletedAndInapplicable())) { + if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) { result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, scopeTower, resolutionCallbacks, expectedType) } @@ -117,12 +119,12 @@ class PSICallResolver( val resolutionCallbacks = createResolutionCallbacks(context) val givenCandidates = resolutionCandidates.map { - GivenCandidate(scopeTower, it.descriptor as FunctionDescriptor, + GivenCandidate(it.descriptor as FunctionDescriptor, it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) }, it.knownTypeParametersResultingSubstitutor) } - val result = kotlinCallResolver.resolveGivenCandidates(resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates) + val result = kotlinCallResolver.resolveGivenCandidates(scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates) return convertToOverloadResolutionResults(context, result, tracingStrategy) } @@ -135,7 +137,7 @@ class PSICallResolver( scopeTower: ImplicitScopeTower, resolutionCallbacks: KotlinResolutionCallbacksImpl, expectedType: UnwrappedType? - ): Collection { + ): CallResolutionResult { val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy) val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName) @@ -148,8 +150,8 @@ class PSICallResolver( } private fun createResolutionCallbacks(context: BasicCallResolutionContext) = - KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, kotlinToResolvedCallTransformer, - argumentTypeResolver, doubleColonExpressionResolver, languageVersionSettings) + KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, + argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer) private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? { val expectedType = context.expectedType.unwrap() @@ -167,60 +169,67 @@ class PSICallResolver( private fun convertToOverloadResolutionResults( context: BasicCallResolutionContext, - result: Collection, + result: CallResolutionResult, tracingStrategy: TracingStrategy ): OverloadResolutionResults { val trace = context.trace - when (result.size) { - 0 -> { - tracingStrategy.unresolvedReference(trace) - return OverloadResolutionResultsImpl.nameNotFound() + + result.diagnostics.firstIsInstanceOrNull()?.let { + tracingStrategy.unresolvedReference(trace) + return OverloadResolutionResultsImpl.nameNotFound() + } + + result.diagnostics.firstIsInstanceOrNull()?.let { + val resolvedCalls = it.candidates.map { kotlinToResolvedCallTransformer.onlyTransform(it.resolvedCall) } + if (it.candidates.areAllFailed()) { + tracingStrategy.noneApplicable(trace, resolvedCalls) + tracingStrategy.recordAmbiguity(trace, resolvedCalls) } - 1 -> { - val singleCandidate = result.single() - - val isInapplicableReceiver = singleCandidate.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER - - val resolvedCall = kotlinToResolvedCallTransformer.transformAndReport(singleCandidate, context, trace.takeUnless { isInapplicableReceiver }) - - if (isInapplicableReceiver) { - tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(resolvedCall)) - } - return SingleOverloadResolutionResult(resolvedCall) - } - else -> { - val resolvedCalls = result.map { kotlinToResolvedCallTransformer.transformAndReport(it, context, trace = null) } - if (result.areAllCompletedAndFailed()) { - tracingStrategy.noneApplicable(trace, resolvedCalls) - tracingStrategy.recordAmbiguity(trace, resolvedCalls) + else { + tracingStrategy.recordAmbiguity(trace, resolvedCalls) + if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) { + tracingStrategy.cannotCompleteResolve(trace, resolvedCalls) } else { - tracingStrategy.recordAmbiguity(trace, resolvedCalls) - if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) { - tracingStrategy.cannotCompleteResolve(trace, resolvedCalls) - } - else { - tracingStrategy.ambiguity(trace, resolvedCalls) - } + tracingStrategy.ambiguity(trace, resolvedCalls) } - return ManyCandidates(resolvedCalls) + } + return ManyCandidates(resolvedCalls) + } + + val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result") + val isInapplicableReceiver = getResultApplicability(singleCandidate.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER + + val resolvedCall = if (isInapplicableReceiver) { + kotlinToResolvedCallTransformer.onlyTransform(singleCandidate).also { + tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it)) } } + else { + kotlinToResolvedCallTransformer.transformAndReport(result, context) + } + return SingleOverloadResolutionResult(resolvedCall) } - private fun Collection.areAllCompletedAndFailed() = + private fun CallResolutionResult.isEmpty(): Boolean = + diagnostics.firstIsInstanceOrNull() != null + + private fun Collection.areAllFailed() = all { - it is ResolvedKotlinCall.CompletedResolvedKotlinCall && - !it.completedCall.resultingApplicability.isSuccess + !it.resultingApplicability.isSuccess } - private fun Collection.areAllCompletedAndInapplicable() = - all { - val applicability = it.resultingApplicability - applicability == ResolutionCandidateApplicability.INAPPLICABLE || - applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER || - applicability == ResolutionCandidateApplicability.HIDDEN - } + private fun CallResolutionResult.areAllInapplicable(): Boolean { + val candidates = diagnostics.firstIsInstanceOrNull()?.candidates?.map { it.resolvedCall } + ?: listOfNotNull(resultCallAtom) + + return candidates.all { + val applicability = getResultApplicability(it.diagnostics) + applicability == ResolutionCandidateApplicability.INAPPLICABLE || + applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER || + applicability == ResolutionCandidateApplicability.HIDDEN + } + } // true if we found something private fun reportAdditionalDiagnosticIfNoCandidates( @@ -285,18 +294,9 @@ class PSICallResolver( override fun transformCandidate( variable: KotlinResolutionCandidate, invoke: KotlinResolutionCandidate - ): VariableAsFunctionKotlinResolutionCandidate { - assert(variable is SimpleKotlinResolutionCandidate) { - "VariableAsFunction variable is not allowed here: $variable" - } - assert(invoke is SimpleKotlinResolutionCandidate) { - "VariableAsFunction candidate is not allowed here: $invoke" - } + ) = invoke - return VariableAsFunctionKotlinResolutionCandidate(kotlinCall, variable as SimpleKotlinResolutionCandidate, invoke as SimpleKotlinResolutionCandidate) - } - - override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory { + override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory { val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name) return SimpleCandidateFactory(callComponents, scopeTower, variableCall) @@ -304,58 +304,59 @@ class PSICallResolver( override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean): Pair>? { - assert(variable is SimpleKotlinResolutionCandidate) { - "VariableAsFunction variable is not allowed here: $variable" - } - if (isRecursiveVariableResolution(variable as SimpleKotlinResolutionCandidate)) return null + if (isRecursiveVariableResolution(variable)) return null assert(variable.isSuccessful) { "Variable call should be successful: $variable " + - "Descriptor: ${variable.descriptorWithFreshTypes}" + "Descriptor: ${variable.resolvedCall.candidateDescriptor}" } val variableCallArgument = createReceiverCallArgument(variable) val explicitReceiver = kotlinCall.explicitReceiver val callForInvoke = if (useExplicitReceiver && explicitReceiver is SimpleKotlinCallArgument) { - PSIKotlinCallForInvoke(kotlinCall, explicitReceiver, variableCallArgument) + PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument) } else { - PSIKotlinCallForInvoke(kotlinCall, variableCallArgument, null) + PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null) } return variableCallArgument.receiver to SimpleCandidateFactory(callComponents, scopeTower, callForInvoke) } // todo: create special check that there is no invoke on variable - private fun isRecursiveVariableResolution(variable: SimpleKotlinResolutionCandidate): Boolean { - val variableType = variable.candidateDescriptor.returnType + private fun isRecursiveVariableResolution(variable: KotlinResolutionCandidate): Boolean { + val variableType = variable.resolvedCall.candidateDescriptor.returnType return variableType is DeferredType && variableType.isComputing } // todo: review - private fun createReceiverCallArgument(variable: SimpleKotlinResolutionCandidate): SimpleKotlinCallArgument { + private fun createReceiverCallArgument(variable: KotlinResolutionCandidate): SimpleKotlinCallArgument { + variable.forceResolution() val variableReceiver = createReceiverValueWithSmartCastInfo(variable) if (variableReceiver.possibleTypes.isNotEmpty()) { return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true) } - val psiKotlinCall = variable.kotlinCall.psiKotlinCall + val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall + + val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage()) return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression), psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver, - ResolvedKotlinCall.OnlyResolvedKotlinCall(variable)) + variableResult) } // todo: decrease hacks count - private fun createReceiverValueWithSmartCastInfo(variable: SimpleKotlinResolutionCandidate): ReceiverValueWithSmartCastInfo { - val callForVariable = variable.kotlinCall as PSIKotlinCallForVariable + private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo { + val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?: error("Unexpected call : ${callForVariable.baseCall.psiCall}") val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate") - val type = variable.descriptorWithFreshTypes.returnType!!.unwrap() + + val type = variable.resolvedCall.freshReturnType!! val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext) - temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.descriptorWithFreshTypes) + temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor) val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor) return ReceiverValueWithSmartCastInfo(variableReceiver, context.dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt index c14b5fb69c6..b462afabd2f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSIKotlinCalls.kt @@ -79,6 +79,7 @@ class PSIKotlinCallForVariable( class PSIKotlinCallForInvoke( val baseCall: PSIKotlinCallImpl, + val variableCall: KotlinResolutionCandidate, override val explicitReceiver: SimpleKotlinCallArgument, override val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument? ) : PSIKotlinCall() { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt new file mode 100644 index 00000000000..d93077482a6 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.builtins.replaceReturnType +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.TemporaryBindingTrace +import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.ContextDependency +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl +import org.jetbrains.kotlin.resolve.calls.util.CallMaker +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver +import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection + +class ResolvedAtomCompleter( + private val resultSubstitutor: NewTypeSubstitutor, + private val trace: BindingTrace, + private val topLevelCallContext: BasicCallResolutionContext, + + private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, + private val expressionTypingServices: ExpressionTypingServices, + private val argumentTypeResolver: ArgumentTypeResolver, + private val doubleColonExpressionResolver: DoubleColonExpressionResolver, + languageVersionSettings: LanguageVersionSettings +) { + private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings) + + fun completeAndReport(resolvedAtom: ResolvedAtom) { + when (resolvedAtom) { + is ResolvedCollectionLiteralAtom -> completeCollectionLiteralCalls(resolvedAtom) + is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom) + is ResolvedLambdaAtom -> completeLambda(resolvedAtom) + is ResolvedCallAtom -> completeResolvedCall(resolvedAtom) + } + } + + fun completeAll(resolvedAtom: ResolvedAtom) { + for (subKtPrimitive in resolvedAtom.subResolvedAtoms) { + completeAll(subKtPrimitive) + } + completeAndReport(resolvedAtom) + } + + fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? { + if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null + + val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall(resolvedCallAtom, true, resultSubstitutor) + kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall) + kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext) + + val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall + kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, trace, lastCall as NewResolvedCallImpl<*>) + + return resolvedCall + } + + private fun completeLambda(lambda: ResolvedLambdaAtom) { + val returnType = resultSubstitutor.safeSubstitute(lambda.returnType) + + updateTraceForLambdaReturnType(lambda, trace, returnType) + + for (lambdaResult in lambda.resultArguments) { + val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue + val newContext = + topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument) + .replaceExpectedType(returnType) + .replaceBindingTrace(trace) + + val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue + kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext) + } + } + + private fun updateTraceForLambdaReturnType(lambda: ResolvedLambdaAtom, trace: BindingTrace, returnType: UnwrappedType) { + val psiCallArgument = lambda.atom.psiCallArgument + + val ktArgumentExpression: KtExpression + val ktFunction: KtElement + when (psiCallArgument) { + is LambdaKotlinCallArgumentImpl -> { + ktArgumentExpression = psiCallArgument.ktLambdaExpression + ktFunction = ktArgumentExpression.functionLiteral + } + is FunctionExpressionImpl -> { + ktArgumentExpression = psiCallArgument.ktFunction + ktFunction = ktArgumentExpression + } + else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument") + } + + val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?: + throw AssertionError("No function descriptor for resolved lambda argument") + functionDescriptor.setReturnType(returnType) + + val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument") + trace.recordType(ktArgumentExpression, existingLambdaType.replaceReturnType(returnType)) + } + + private fun completeCallableReference( + resolvedAtom: ResolvedCallableReferenceAtom + ) { + val callableCandidate = resolvedAtom.candidate + if (callableCandidate == null) { + // todo report meanfull diagnostic here + return + } + val resultTypeParameters = callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) } + + + val psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl + val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression + val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor() + + + // write down type for callable reference expression + val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT) + argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter, + resultType, + callableReferenceExpression) + val reference = callableReferenceExpression.callableReference + + val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) { + ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver + ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver + else -> null + } + + val explicitReceiver = explicitCallableReceiver?.receiver + val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList()) + + val tracing = TracingStrategyImpl.create(reference, psiCall) + val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call") + + val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue, + callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind, + null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)) + resolvedCall.setResultingSubstitutor(resultSubstitutor) + + tracing.bindCall(trace, psiCall) + tracing.bindReference(trace, resolvedCall) + tracing.bindResolvedCall(trace, resolvedCall) + + resolvedCall.setStatusToSuccess() + resolvedCall.markCallAsCompleted() + + when (callableCandidate.candidate) { + is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext) + is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext) + } + + // TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo + trace.recordType(callableReferenceExpression, resultType) + trace.record(BindingContext.PROCESSED, callableReferenceExpression) + + doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression) + } + + private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) { + val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl + val context = psiCallArgument.outerCallContext + + val expectedType = collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE + + val actualContext = context + .replaceBindingTrace(trace) + .replaceExpectedType(expectedType) + .replaceContextDependency(ContextDependency.INDEPENDENT) + + expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext) + } +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt index a50373e241f..b5cd5998e42 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/KotlinCallResolver.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResolver import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.model.* -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.types.UnwrappedType import java.lang.UnsupportedOperationException @@ -40,7 +39,7 @@ class KotlinCallResolver( kotlinCall: KotlinCall, expectedType: UnwrappedType?, factoryProviderForInvoke: CandidateFactoryProviderForInvoke - ): Collection { + ): CallResolutionResult { kotlinCall.checkCallInvariants() val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) @@ -56,43 +55,33 @@ class KotlinCallResolver( val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED) - return choseMostSpecific(resolutionCallbacks, expectedType, candidates) + return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) } fun resolveGivenCandidates( + scopeTower: ImplicitScopeTower, resolutionCallbacks: KotlinResolutionCallbacks, kotlinCall: KotlinCall, expectedType: UnwrappedType?, givenCandidates: Collection - ): Collection { + ): CallResolutionResult { kotlinCall.checkCallInvariants() + val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) - val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false - - val resolutionCandidates = givenCandidates.map { - SimpleKotlinResolutionCandidate(callComponents, - it.scopeTower, - kotlinCall, - if (it.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER, - it.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) }, - null, - it.descriptor, - it.knownTypeParametersResultingSubstitutor, - listOf() - ) - } + val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() } val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), TowerResolver.SuccessfulResultCollector(), useOrder = true) - return choseMostSpecific(resolutionCallbacks, expectedType, candidates) + return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) } private fun choseMostSpecific( + candidateFactory: SimpleCandidateFactory, resolutionCallbacks: KotlinResolutionCallbacks, expectedType: UnwrappedType?, candidates: Collection - ): Collection { - val isDebuggerContext = (candidates.firstOrNull() ?: return emptyList()).lastCall.scopeTower.isDebuggerContext + ): CallResolutionResult { + val isDebuggerContext = candidateFactory.scopeTower.isDebuggerContext val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates( candidates, @@ -100,16 +89,7 @@ class KotlinCallResolver( discriminateGenerics = true, // todo isDebuggerContext = isDebuggerContext) - val singleResult = maximallySpecificCandidates.singleOrNull()?.let { - kotlinCallCompleter.completeCallIfNecessary(it, expectedType, resolutionCallbacks) - } - if (singleResult != null) { - return listOf(singleResult) - } - - return maximallySpecificCandidates.map { - kotlinCallCompleter.transformWhenAmbiguity(it, resolutionCallbacks) - } + return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt index ec147ffc18d..29759994a95 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt @@ -21,17 +21,19 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.utils.SmartList -import org.jetbrains.kotlin.utils.addIfNotNull // very initial state of component // todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy +// move it to frontend module class AdditionalDiagnosticReporter { - fun createAdditionalDiagnostics( - candidate: SimpleKotlinResolutionCandidate, - resultingDescriptor: CallableDescriptor - ): List = reportSmartCasts(candidate, resultingDescriptor) + fun reportAdditionalDiagnostics( + candidate: ResolvedCallAtom, + resultingDescriptor: CallableDescriptor, + kotlinDiagnosticsHolder: KotlinDiagnosticsHolder + ) { + reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder) + } private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? { if (argument !is ExpressionKotlinCallArgument) return null @@ -42,7 +44,7 @@ class AdditionalDiagnosticReporter { } private fun reportSmartCastOnReceiver( - candidate: SimpleKotlinResolutionCandidate, + candidate: ResolvedCallAtom, receiver: SimpleKotlinCallArgument?, parameter: ReceiverParameterDescriptor? ): SmartCastDiagnostic? { @@ -53,33 +55,36 @@ class AdditionalDiagnosticReporter { // todo may be we have smart cast to Int? return smartCastDiagnostic.takeIf { - candidate.getCandidateDiagnostics().filterIsInstance().none { + candidate.diagnostics.filterIsInstance().none { it.receiver == receiver } && - candidate.getCandidateDiagnostics().filterIsInstance().none { + candidate.diagnostics.filterIsInstance().none { it.argument == receiver } } } - private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor) = - SmartList().apply { - addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter)) - addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter)) + private fun reportSmartCasts( + candidate: ResolvedCallAtom, + resultingDescriptor: CallableDescriptor, + kotlinDiagnosticsHolder: KotlinDiagnosticsHolder + ) { + kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiverArgument, resultingDescriptor.extensionReceiverParameter)) + kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter)) - for (parameter in resultingDescriptor.valueParameters) { - for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { - val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue + for (parameter in resultingDescriptor.valueParameters) { + for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { + val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue - val thereIsUnstableSmartCastError = candidate.getCandidateDiagnostics().filterIsInstance().any { - it.argument == argument - } + val thereIsUnstableSmartCastError = candidate.diagnostics.filterIsInstance().any { + it.argument == argument + } - if (!thereIsUnstableSmartCastError) { - add(smartCastDiagnostic) - } - } + if (!thereIsUnstableSmartCastError) { + kotlinDiagnosticsHolder.addDiagnostic(smartCastDiagnostic) } } + } + } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt index fb3f05d11fb..7be95c2bf9c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.resolve.calls.components +import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.checker.intersectWrappedTypes +import org.jetbrains.kotlin.utils.addToStdlib.safeAs internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing = @@ -40,12 +42,12 @@ internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType return intersectWrappedTypes(possibleTypes + receiverValue.type) } -internal fun KotlinCallArgument.getExpectedType(parameter: ValueParameterDescriptor) = +internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor) = if (this.isSpread) { parameter.type.unwrap() } else { - parameter.varargElementType?.unwrap() ?: parameter.type.unwrap() + parameter.safeAs()?.varargElementType?.unwrap() ?: parameter.type.unwrap() } val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null 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 0f041f673d8..d8b756a9a9c 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 @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.resolve.calls.components.CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints +import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition @@ -72,6 +72,9 @@ class CallableReferenceCandidate( ) : Candidate { override val resultingApplicability = getResultApplicability(diagnostics) override val isSuccessful get() = resultingApplicability.isSuccess + + var freshSubstitutor: FreshVariableNewTypeSubstitutor? = null + internal set } /** diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt index f62e68064bb..c53ca974002 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector -import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.results.FlatSignature @@ -30,20 +29,20 @@ import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver import org.jetbrains.kotlin.types.UnwrappedType -import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addIfNotNull class CallableReferenceOverloadConflictResolver( builtIns: KotlinBuiltIns, specificityComparator: TypeSpecificityComparator, statelessCallbacks: KotlinResolutionStatelessCallbacks, - constraintInjector: ConstraintInjector, - typeResolver: ResultTypeResolver + constraintInjector: ConstraintInjector ) : OverloadingConflictResolver( builtIns, specificityComparator, { it.candidate }, - { SimpleConstraintSystemImpl(constraintInjector, typeResolver) }, + { SimpleConstraintSystemImpl(constraintInjector, builtIns) }, Companion::createFlatSignature, { null }, { statelessCallbacks.isDescriptorFromSource(it) } @@ -63,39 +62,50 @@ class CallableReferenceResolver( fun processCallableReferenceArgument( csBuilder: ConstraintSystemBuilder, - postponedArgument: PostponedCallableReferenceArgument - ): KotlinCallDiagnostic? { - postponedArgument.analyzed = true - - val argument = postponedArgument.argument - val expectedType = csBuilder.buildCurrentSubstitutor().safeSubstitute(postponedArgument.expectedType) - - val subLHSCall = argument.lhsResult.safeAs()?.lshCallArgument.safeAs() - if (subLHSCall != null) { - csBuilder.addInnerCall(subLHSCall.resolvedCall) - } + resolvedAtom: ResolvedCallableReferenceAtom + ) { + val argument = resolvedAtom.atom + val expectedType = resolvedAtom.expectedType?.let { csBuilder.buildCurrentSubstitutor().safeSubstitute(it) } val scopeTower = callComponents.statelessCallbacks.getScopeTowerForCallableReferenceArgument(argument) val candidates = runRHSResolution(scopeTower, argument, expectedType) { checkCallableReference -> csBuilder.runTransaction { checkCallableReference(this); false } } - val chosenCandidate = when (candidates.size) { - 0 -> return NoneCallableReferenceCandidates(argument) - 1 -> candidates.single() - else -> return CallableReferenceCandidatesAmbiguity(argument, candidates) + val diagnostics = SmartList() + + val chosenCandidate = candidates.singleOrNull() + if (chosenCandidate != null) { + val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) { + csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate, + reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor) + } + diagnostics.addIfNotNull(diagnostic) + chosenCandidate.freshSubstitutor = toFreshSubstitutor } - val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) { - csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate, - reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor) + else { + if (candidates.isEmpty()) { + diagnostics.add(NoneCallableReferenceCandidates(argument)) + } + else { + diagnostics.add(CallableReferenceCandidatesAmbiguity(argument, candidates)) + } } - postponedArgument.analyzedAndThereIsResult = true - postponedArgument.myTypeVariables = toFreshSubstitutor.freshVariables - postponedArgument.callableResolutionCandidate = chosenCandidate + // todo -- create this inside CallableReferencesCandidateFactory + val subKtArguments = listOfNotNull(buildResolvedKtArgument(argument.lhsResult)) - return diagnostic + resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments, diagnostics) } + private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? { + if (lhsResult !is LHSResult.Expression) return null + val lshCallArgument = lhsResult.lshCallArgument + return when(lshCallArgument) { + is SubKotlinCallArgument -> lshCallArgument.callResult + is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument) + else -> unexpectedArgument(lshCallArgument) + } + } private fun runRHSResolution( scopeTower: ImplicitScopeTower, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt index 4715be10424..e087ddb8994 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt @@ -31,6 +31,7 @@ interface KotlinResolutionStatelessCallbacks { fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall): Boolean fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower + fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate? } // This components hold state (trace). Work with this carefully. @@ -43,11 +44,5 @@ interface KotlinResolutionCallbacks { expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables ): List - // todo this is hack for some client which try to read ResolvedCall from trace before all calls completed - fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) - - fun completeCallableReference(callableReferenceArgument: PostponedCallableReferenceArgument, - resultTypeParameters: List) - - fun completeCollectionLiteralCalls(collectionLiteralArgument: PostponedCollectionLiteralArgument) + fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index cdba4680662..a14eea94883 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -16,152 +16,82 @@ package org.jetbrains.kotlin.resolve.calls.components -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition -import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing -import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes import org.jetbrains.kotlin.resolve.calls.model.* -import org.jetbrains.kotlin.types.TypeApproximator -import org.jetbrains.kotlin.types.TypeApproximatorConfiguration +import org.jetbrains.kotlin.resolve.calls.tower.forceResolution import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.UnwrappedType -import org.jetbrains.kotlin.types.checker.NewCapturedType -import org.jetbrains.kotlin.types.typeUtil.contains class KotlinCallCompleter( - private val additionalDiagnosticReporter: AdditionalDiagnosticReporter, private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter ) { - interface Context { - val innerCalls: List - fun buildResultingSubstitutor(): NewTypeSubstitutor - val postponedArguments: List - val lambdaArguments: List - } - - fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate, resolutionCallbacks: KotlinResolutionCallbacks): ResolvedKotlinCall = - toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate, resolutionCallbacks) - - // todo investigate variable+function calls - fun completeCallIfNecessary( - candidate: KotlinResolutionCandidate, + fun runCompletion( + factory: SimpleCandidateFactory, + candidates: Collection, expectedType: UnwrappedType?, resolutionCallbacks: KotlinResolutionCallbacks - ): ResolvedKotlinCall { - resolutionCallbacks.bindStubResolvedCallForCandidate(candidate) - val topLevelCall = - when (candidate) { - is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate - else -> candidate as SimpleKotlinResolutionCandidate - } + ): CallResolutionResult { + val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() + if (candidates.isEmpty()) { + diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic(factory.kotlinCall)) + } + if (candidates.size > 1) { + diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(factory.kotlinCall, candidates)) + } + val candidate = candidates.singleOrNull() - var completionType = topLevelCall.prepareForCompletion(expectedType) - val lastCall = candidate.lastCall - lastCall.runCompletion(completionType, resolutionCallbacks) + // this is needed at least for non-local return checker, because when we analyze lambda we should already bind descriptor for outer call + candidate?.resolvedCall?.let { resolutionCallbacks.bindStubResolvedCallForCandidate(it) } - if (lastCall.constraintSystem.asConstraintSystemCompleterContext().canBeProper(lastCall.descriptorWithFreshTypes.returnTypeOrNothing)) { - completionType = ConstraintSystemCompletionMode.FULL - lastCall.runCompletion(completionType, resolutionCallbacks) + if (candidate == null || candidate.csBuilder.hasContradiction) { + val candidateForCompletion = candidate ?: factory.createErrorCandidate().forceResolution() + candidateForCompletion.prepareForCompletion(expectedType) + runCompletion(candidateForCompletion.resolvedCall, ConstraintSystemCompletionMode.FULL, diagnosticHolder, candidateForCompletion.getSystem(), resolutionCallbacks) + + return CallResolutionResult(CallResolutionResult.Type.ERROR, candidate?.resolvedCall, diagnosticHolder.getDiagnostics(), ConstraintStorage.Empty) } - return when (completionType) { - ConstraintSystemCompletionMode.FULL -> toCompletedBaseResolvedCall(lastCall.constraintSystem.asCallCompleterContext(), candidate, resolutionCallbacks) - ConstraintSystemCompletionMode.PARTIAL -> ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate) + val completionType = candidate.prepareForCompletion(expectedType) + val constraintSystem = candidate.getSystem() + runCompletion(candidate.resolvedCall, completionType, diagnosticHolder, constraintSystem, resolutionCallbacks) + + return if (completionType == ConstraintSystemCompletionMode.FULL) { + CallResolutionResult(CallResolutionResult.Type.COMPLETED, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage()) } + else { + CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage()) + } + } - private fun SimpleKotlinResolutionCandidate.runCompletion(completionMode: ConstraintSystemCompletionMode, resolutionCallbacks: KotlinResolutionCallbacks) { - kotlinConstraintSystemCompleter.runCompletion( - constraintSystem.asConstraintSystemCompleterContext(), completionMode, descriptorWithFreshTypes.returnTypeOrNothing - ) { + private fun runCompletion( + resolvedCallAtom: ResolvedCallAtom, + completionMode: ConstraintSystemCompletionMode, + diagnosticsHolder: KotlinDiagnosticsHolder, + constraintSystem: NewConstraintSystem, + resolutionCallbacks: KotlinResolutionCallbacks + ) { + val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType + kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) { postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it) } + + constraintSystem.diagnostics.forEach(diagnosticsHolder::addDiagnostic) } - private fun toCompletedBaseResolvedCall( - c: Context, - candidate: KotlinResolutionCandidate, - resolutionCallbacks: KotlinResolutionCallbacks - ): ResolvedKotlinCall.CompletedResolvedKotlinCall { - val currentSubstitutor = c.buildResultingSubstitutor() - val completedCall = candidate.toCompletedCall(currentSubstitutor, isTopLevel = true) - val competedCalls = c.innerCalls.map { - it.candidate.toCompletedCall(currentSubstitutor, isTopLevel = false) - } - for (postponedArgument in c.postponedArguments) { - when (postponedArgument) { - is PostponedLambdaArgument -> { - postponedArgument.finalReturnType = currentSubstitutor.safeSubstitute(postponedArgument.returnType) - } - is PostponedCallableReferenceArgument -> { - val resultTypeParameters = postponedArgument.myTypeVariables.map { currentSubstitutor.safeSubstitute(it.defaultType) } - resolutionCallbacks.completeCallableReference(postponedArgument, resultTypeParameters) - } - is PostponedCollectionLiteralArgument -> { - resolutionCallbacks.completeCollectionLiteralCalls(postponedArgument) - } - } - } - return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls, c.lambdaArguments) - } - - private fun KotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor, isTopLevel: Boolean): CompletedKotlinCall { - if (this is VariableAsFunctionKotlinResolutionCandidate) { - val variable = resolvedVariable.toCompletedCall(substitutor, isTopLevel = false) - val invoke = invokeCandidate.toCompletedCall(substitutor, isTopLevel) - - return CompletedKotlinCall.VariableAsFunction(kotlinCall, variable, invoke) - } - return (this as SimpleKotlinResolutionCandidate).toCompletedCall(substitutor, isTopLevel) - } - - private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor, isTopLevel: Boolean): CompletedKotlinCall.Simple { - val containsCapturedTypes = descriptorWithFreshTypes.returnType?.contains { it is NewCapturedType } ?: false - val resultingDescriptor = when { - descriptorWithFreshTypes is FunctionDescriptor || - (descriptorWithFreshTypes is PropertyDescriptor && (descriptorWithFreshTypes.typeParameters.isNotEmpty() || containsCapturedTypes)) -> - // this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types, - // but it seems like temporary solution. - descriptorWithFreshTypes.substituteAndApproximateCapturedTypes(substitutor) - else -> - descriptorWithFreshTypes - } - - val typeArguments = descriptorWithFreshTypes.typeParameters.map { - val substituted = substitutor.safeSubstitute(typeVariablesForFreshTypeParameters[it.index].defaultType) - TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted - } - - val diagnostics = computeDiagnostics(this, resultingDescriptor, isTopLevel) - return CompletedKotlinCall.Simple(kotlinCall, candidateDescriptor, resultingDescriptor, diagnostics, explicitReceiverKind, - dispatchReceiverArgument?.receiver, extensionReceiver?.receiver, typeArguments, argumentMappingByOriginal) - } - - private fun computeDiagnostics( - candidate: SimpleKotlinResolutionCandidate, - resultingDescriptor: CallableDescriptor, - isTopLevel: Boolean - ): List { - var diagnostics = candidate.getCandidateDiagnostics() - if (isTopLevel) { - diagnostics += candidate.constraintSystem.diagnostics - } - diagnostics += additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor) - return diagnostics - } // true if we should complete this call - private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): ConstraintSystemCompletionMode { - val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL + private fun KotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): ConstraintSystemCompletionMode { + val unsubstitutedReturnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL + val returnType = resolvedCall.substitutor.safeSubstitute(unsubstitutedReturnType) if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) { - csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(kotlinCall)) + csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom)) } return if (expectedType != null || csBuilder.isProperType(returnType)) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/NewOverloadingConflictResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/NewOverloadingConflictResolver.kt index f5e80cdd781..67d57d5522c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/NewOverloadingConflictResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/NewOverloadingConflictResolver.kt @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector -import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.results.FlatSignature @@ -32,32 +31,30 @@ class NewOverloadingConflictResolver( builtIns: KotlinBuiltIns, specificityComparator: TypeSpecificityComparator, statelessCallbacks: KotlinResolutionStatelessCallbacks, - constraintInjector: ConstraintInjector, - typeResolver: ResultTypeResolver + constraintInjector: ConstraintInjector ) : OverloadingConflictResolver( builtIns, specificityComparator, { // todo investigate - (it as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate?.candidateDescriptor ?: - (it as SimpleKotlinResolutionCandidate).candidateDescriptor + it.resolvedCall.candidateDescriptor }, - { SimpleConstraintSystemImpl(constraintInjector, typeResolver) }, + { SimpleConstraintSystemImpl(constraintInjector, builtIns) }, Companion::createFlatSignature, - { (it as? VariableAsFunctionKotlinResolutionCandidate)?.resolvedVariable }, + { it.variableCandidateIfInvoke }, { statelessCallbacks.isDescriptorFromSource(it) } ) { companion object { private fun createFlatSignature(candidate: KotlinResolutionCandidate): FlatSignature { - val simpleCandidate = (candidate as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate ?: (candidate as SimpleKotlinResolutionCandidate) - val originalDescriptor = simpleCandidate.descriptorWithFreshTypes.original + val resolvedCall = candidate.resolvedCall + val originalDescriptor = resolvedCall.candidateDescriptor.original val originalValueParameters = originalDescriptor.valueParameters var numDefaults = 0 val valueArgumentToParameterType = HashMap() - for ((valueParameter, resolvedValueArgument) in simpleCandidate.argumentMappingByOriginal) { + for ((valueParameter, resolvedValueArgument) in resolvedCall.argumentMappingByOriginal) { if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) { numDefaults++ } @@ -73,8 +70,8 @@ class NewOverloadingConflictResolver( return FlatSignature.create(candidate, originalDescriptor, numDefaults, - simpleCandidate.kotlinCall.argumentsInParenthesis.map { valueArgumentToParameterType[it] } + - listOfNotNull(simpleCandidate.kotlinCall.externalArgument?.let { valueArgumentToParameterType[it] }) + resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } + + listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] }) ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index 1c9a0d2c997..0240a0e0778 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.builtins.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType @@ -25,94 +26,93 @@ import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.utils.addToStdlib.safeAs -fun createPostponedArgumentAndPerformInitialChecks( +fun resolveKtPrimitive( csBuilder: ConstraintSystemBuilder, - argument: PostponableKotlinCallArgument, - expectedType: UnwrappedType -): KotlinCallDiagnostic? { - val (postponedArgument, diagnostic) = when (argument) { - is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType) - is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType) - is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(csBuilder, argument, expectedType) - else -> unexpectedArgument(argument) - } - csBuilder.addPostponedArgument(postponedArgument) - - return diagnostic + argument: KotlinCallArgument, + expectedType: UnwrappedType?, + diagnosticsHolder: KotlinDiagnosticsHolder, + isReceiver: Boolean +): ResolvedAtom = when (argument) { + is SimpleKotlinCallArgument -> checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) + is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType) + is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType, diagnosticsHolder) + is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(argument, expectedType) + else -> unexpectedArgument(argument) } + // if expected type isn't function type, then may be it is Function, Any or just `T` private fun preprocessLambdaArgument( csBuilder: ConstraintSystemBuilder, argument: LambdaKotlinCallArgument, - expectedType: UnwrappedType -): Pair { - val builtIns = expectedType.builtIns - val isSuspend = expectedType.isSuspendFunctionType + expectedType: UnwrappedType? +): ResolvedAtom { + val builtIns = csBuilder.builtIns + val isSuspend = expectedType?.isSuspendFunctionType ?: false val receiverType: UnwrappedType? // null means that there is no receiver val parameters: List val returnType: UnwrappedType + val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L") - if (expectedType.isBuiltinFunctionalType) { + if (expectedType?.isBuiltinFunctionalType == true) { receiverType = if (argument is FunctionExpression) argument.receiverType else expectedType.getReceiverTypeFromFunctionType()?.unwrap() val expectedParameters = expectedType.getValueParameterTypesFromFunctionType() - if (argument.parametersTypes != null) { - parameters = argument.parametersTypes!!.mapIndexed { + parameters = if (argument.parametersTypes != null) { + argument.parametersTypes!!.mapIndexed { index, type -> type ?: expectedParameters.getOrNull(index)?.type?.unwrap() ?: builtIns.nullableAnyType } } else { // lambda without explicit parameters: { } - parameters = expectedParameters.map { it.type.unwrap() } + expectedParameters.map { it.type.unwrap() } } returnType = argument.safeAs()?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap() } else { - val isFunctionSupertype = KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType) + val isFunctionSupertype = expectedType != null && KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType) receiverType = argument.safeAs()?.receiverType parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList() returnType = argument.safeAs()?.returnType ?: - expectedType.arguments.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?: - createFreshTypeVariableForLambdaReturnType(csBuilder, argument, builtIns) + expectedType?.arguments?.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?: + typeVariable.defaultType // what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design } - val resolvedArgument = PostponedLambdaArgument(argument, isSuspend, receiverType, parameters, returnType) + val newTypeVariableUsed = returnType == typeVariable.defaultType + if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable) - csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument)) + if (expectedType != null) { + val lambdaType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiverType, parameters, null, returnType, isSuspend) + csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPosition(argument)) + } - return resolvedArgument to null -} - -private fun createFreshTypeVariableForLambdaReturnType( - csBuilder: ConstraintSystemBuilder, - argument: LambdaKotlinCallArgument, - builtIns: KotlinBuiltIns -): UnwrappedType { - val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L") - csBuilder.registerVariable(typeVariable) - return typeVariable.defaultType + return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed }) } private fun preprocessCallableReference( csBuilder: ConstraintSystemBuilder, argument: CallableReferenceKotlinCallArgument, - expectedType: UnwrappedType -): Pair { + expectedType: UnwrappedType?, + diagnosticsHolder: KotlinDiagnosticsHolder +): ResolvedAtom { + val result = ResolvedCallableReferenceAtom(argument, expectedType) + if (expectedType == null) return result + val notCallableTypeConstructor = csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) } - val diagnostic = notCallableTypeConstructor?.let { NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor) } - return PostponedCallableReferenceArgument(argument, expectedType) to diagnostic + if (notCallableTypeConstructor != null) { + diagnosticsHolder.addDiagnostic(NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor)) + } + return result } private fun preprocessCollectionLiteralArgument( - csBuilder: ConstraintSystemBuilder, collectionLiteralArgument: CollectionLiteralKotlinCallArgument, - expectedType: UnwrappedType -): Pair { + expectedType: UnwrappedType? +): ResolvedAtom { // todo add some checks about expected type - return PostponedCollectionLiteralArgument(collectionLiteralArgument, expectedType) to null + return ResolvedCollectionLiteralAtom(collectionLiteralArgument, expectedType) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 2746f628dec..027a0b6ae5f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -17,12 +17,11 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder +import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemForArgument import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition -import org.jetbrains.kotlin.resolve.calls.model.PostponedCallableReferenceArgument -import org.jetbrains.kotlin.resolve.calls.model.PostponedCollectionLiteralArgument -import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument -import org.jetbrains.kotlin.resolve.calls.model.PostponedLambdaArgument +import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.typeUtil.builtIns @@ -36,34 +35,42 @@ class PostponedArgumentsAnalyzer( fun canBeProper(type: UnwrappedType): Boolean // mutable operations + fun addOtherSystem(otherSystem: ConstraintStorage) fun getBuilder(): ConstraintSystemBuilder } - fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: PostponedKotlinCallArgument) { + fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: ResolvedAtom) { when (argument) { - is PostponedLambdaArgument -> analyzeLambda(c, resolutionCallbacks, argument) - is PostponedCallableReferenceArgument -> callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument) - is PostponedCollectionLiteralArgument -> TODO("Not supported") + is ResolvedLambdaAtom -> analyzeLambda(c, resolutionCallbacks, argument) + is ResolvedCallableReferenceAtom -> callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument) + is ResolvedCollectionLiteralAtom -> TODO("Not supported") + else -> error("Unexpected resolved primitive: ${argument.javaClass.canonicalName}") } } - private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: PostponedLambdaArgument) { + private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: ResolvedLambdaAtom) { val currentSubstitutor = c.buildCurrentSubstitutor() fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type) val receiver = lambda.receiver?.let(::substitute) val parameters = lambda.parameters.map(::substitute) val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute) - lambda.analyzed = true - lambda.resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.argument, lambda.isSuspend, receiver, parameters, expectedType) - for (resultLambdaArgument in lambda.resultArguments) { - checkSimpleArgument(c.getBuilder(), resultLambdaArgument, lambda.returnType.let(::substitute)) + val resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.atom, lambda.isSuspend, receiver, parameters, expectedType) + + resultArguments.forEach { c.addSubsystemForArgument(it) } + + val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() + + val subResolvedKtPrimitives = resultArguments.map { + checkSimpleArgument(c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false) } - if (lambda.resultArguments.isEmpty()) { + if (resultArguments.isEmpty()) { val unitType = lambda.returnType.builtIns.unitType c.getBuilder().addSubtypeConstraint(lambda.returnType.let(::substitute), unitType, LambdaArgumentConstraintPosition(lambda)) } + + lambda.setAnalyzedResults(resultArguments, subResolvedKtPrimitives, diagnosticHolder.getDiagnostics()) } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 3c839e0390b..42c3ae68d28 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -31,114 +31,127 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError -import org.jetbrains.kotlin.resolve.calls.tower.isSuccess -import org.jetbrains.kotlin.utils.SmartList -import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.utils.addToStdlib.safeAs -internal object CheckInstantiationOfAbstractClass : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { - if (candidateDescriptor is ConstructorDescriptor && !callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(kotlinCall)) { +internal object CheckInstantiationOfAbstractClass : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val candidateDescriptor = resolvedCall.candidateDescriptor + + if (candidateDescriptor is ConstructorDescriptor && + !callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(resolvedCall.atom)) { if (candidateDescriptor.constructedClass.modality == Modality.ABSTRACT) { - return listOf(InstantiationOfAbstractClass) + addDiagnostic(InstantiationOfAbstractClass) } } - - return emptyList() } } -internal object CheckVisibility : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { +internal object CheckVisibility : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val containingDescriptor = scopeTower.lexicalScope.ownerDescriptor + val dispatchReceiverArgument = resolvedCall.dispatchReceiverArgument + val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER - val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList() + val invisibleMember = Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return if (dispatchReceiverArgument is ExpressionKotlinCallArgument) { val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType) if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) { - return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType)) + addDiagnostic(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType)) + return } } - return listOf(VisibilityError(invisibleMember)) - } - - private val SimpleKotlinResolutionCandidate.containingDescriptor: DeclarationDescriptor get() = scopeTower.lexicalScope.ownerDescriptor -} - -internal object MapTypeArguments : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { - typeArgumentMappingByOriginal = callComponents.typeArgumentsToParametersMapper.mapTypeArguments(kotlinCall, candidateDescriptor.original) - return typeArgumentMappingByOriginal.diagnostics + addDiagnostic(VisibilityError(invisibleMember)) } } -internal object NoTypeArguments : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { +internal object MapTypeArguments : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + resolvedCall.typeArgumentMappingByOriginal = + callComponents.typeArgumentsToParametersMapper.mapTypeArguments(kotlinCall, candidateDescriptor.original).also { + it.diagnostics.forEach(this@process::addDiagnostic) + } + } +} + +internal object NoTypeArguments : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { assert(kotlinCall.typeArguments.isEmpty()) { "Variable call cannot has explicit type arguments: ${kotlinCall.typeArguments}. Call: $kotlinCall" } - typeArgumentMappingByOriginal = NoExplicitArguments - return typeArgumentMappingByOriginal.diagnostics + resolvedCall.typeArgumentMappingByOriginal = NoExplicitArguments } } -internal object MapArguments : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { +internal object MapArguments : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { val mapping = callComponents.argumentsToParametersMapper.mapArguments(kotlinCall, candidateDescriptor) - argumentMappingByOriginal = mapping.parameterToCallArgumentMap - return mapping.diagnostics + mapping.diagnostics.forEach(this::addDiagnostic) + + resolvedCall.argumentMappingByOriginal = mapping.parameterToCallArgumentMap } } -internal object NoArguments : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { +internal object ArgumentsToCandidateParameterDescriptor : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val map = hashMapOf() + for ((originalValueParameter, resolvedCallArgument) in resolvedCall.argumentMappingByOriginal) { + val valueParameter = candidateDescriptor.valueParameters.getOrNull(originalValueParameter.index) ?: continue + for (argument in resolvedCallArgument.arguments) { + map[argument] = valueParameter + } + } + resolvedCall.argumentToCandidateParameter = map + } +} + +internal object NoArguments : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { assert(kotlinCall.argumentsInParenthesis.isEmpty()) { "Variable call cannot has arguments: ${kotlinCall.argumentsInParenthesis}. Call: $kotlinCall" } assert(kotlinCall.externalArgument == null) { "Variable call cannot has external argument: ${kotlinCall.externalArgument}. Call: $kotlinCall" } - argumentMappingByOriginal = emptyMap() - return emptyList() + resolvedCall.argumentMappingByOriginal = emptyMap() + resolvedCall.argumentToCandidateParameter = emptyMap() } } -internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { + +internal object CreateFreshVariablesSubstitutor : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { if (candidateDescriptor.typeParameters.isEmpty()) { - descriptorWithFreshTypes = candidateDescriptor - return emptyList() + resolvedCall.substitutor = FreshVariableNewTypeSubstitutor.Empty + return } val toFreshVariables = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder) - typeVariablesForFreshTypeParameters = toFreshVariables.freshVariables + resolvedCall.substitutor = toFreshVariables // bad function -- error on declaration side - if (csBuilder.hasContradiction) { - descriptorWithFreshTypes = candidateDescriptor - return emptyList() - } + if (csBuilder.hasContradiction) return // optimization - if (typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) { - descriptorWithFreshTypes = candidateDescriptor.substitute(toFreshVariables) - csBuilder.simplify().let { assert(it.isEmpty) { "Substitutor should be empty: $it, call: $kotlinCall" } } - return emptyList() + if (resolvedCall.typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) { + return } val typeParameters = candidateDescriptor.typeParameters for (index in typeParameters.indices) { val typeParameter = typeParameters[index] + val freshVariable = toFreshVariables.freshVariables[index] + val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType) if (knownTypeArgument != null) { - val freshVariable = toFreshVariables.freshVariables[index] csBuilder.addEqualityConstraint(freshVariable.defaultType, knownTypeArgument.unwrap(), KnownTypeParameterConstraintPosition(knownTypeArgument)) continue } - val typeArgument = typeArgumentMappingByOriginal.getTypeArgument(typeParameter) + val typeArgument = resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter) if (typeArgument is SimpleTypeArgument) { - val freshVariable = toFreshVariables.freshVariables[index] csBuilder.addEqualityConstraint(freshVariable.defaultType, typeArgument.type, ExplicitTypeParameterConstraintPosition(typeArgument)) } else { @@ -147,19 +160,6 @@ internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart { } } } - - /** - * Note: here we can fix also placeholders arguments. - * Example: - * fun , Y> foo() - * - * foo, *>() - */ - val toFixedTypeParameters = csBuilder.simplify() - // todo optimize -- composite substitutions before run safeSubstitute - descriptorWithFreshTypes = candidateDescriptor.substitute(toFreshVariables).substitute(toFixedTypeParameters) - - return emptyList() } fun createToFreshVariableSubstitutorAndAddInitialConstraints( @@ -189,98 +189,124 @@ internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart { } } -internal object CheckExplicitReceiverKindConsistency : ResolutionPart { - private fun SimpleKotlinResolutionCandidate.hasError(): Nothing = +internal object CheckExplicitReceiverKindConsistency : ResolutionPart() { + private fun KotlinResolutionCandidate.hasError(): Nothing = error("Inconsistent call: $kotlinCall. \n" + - "Candidate: $candidateDescriptor, explicitReceiverKind: $explicitReceiverKind.\n" + + "Candidate: $candidateDescriptor, explicitReceiverKind: ${resolvedCall.explicitReceiverKind}.\n" + "Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}") - override fun SimpleKotlinResolutionCandidate.process(): List { - when (explicitReceiverKind) { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + when (resolvedCall.explicitReceiverKind) { NO_EXPLICIT_RECEIVER -> if (kotlinCall.explicitReceiver is SimpleKotlinCallArgument || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError() DISPATCH_RECEIVER, EXTENSION_RECEIVER -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError() BOTH_RECEIVERS -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension == null) hasError() } - return emptyList() } } -internal object CheckReceivers : ResolutionPart { - private fun SimpleKotlinResolutionCandidate.checkReceiver( +private fun KotlinResolutionCandidate.resolveKotlinArgument( + argument: KotlinCallArgument, + candidateParameter: ParameterDescriptor?, + isReceiver: Boolean +) { + val expectedType = candidateParameter?.let { + resolvedCall.substitutor.safeSubstitute(argument.getExpectedType(candidateParameter)) + } + addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver)) +} + +internal object CheckReceivers : ResolutionPart() { + private fun KotlinResolutionCandidate.checkReceiver( receiverArgument: SimpleKotlinCallArgument?, receiverParameter: ReceiverParameterDescriptor? - ): KotlinCallDiagnostic? { + ) { if ((receiverArgument == null) != (receiverParameter == null)) { error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor") } - if (receiverArgument == null || receiverParameter == null) return null + if (receiverArgument == null || receiverParameter == null) return - val expectedType = receiverParameter.type.unwrap() - - return checkSimpleArgument(csBuilder, receiverArgument, expectedType, isReceiver = true) + resolveKotlinArgument(receiverArgument, receiverParameter, isReceiver = true) } - override fun SimpleKotlinResolutionCandidate.process() = - listOfNotNull(checkReceiver(dispatchReceiverArgument, descriptorWithFreshTypes.dispatchReceiverParameter), - checkReceiver(extensionReceiver, descriptorWithFreshTypes.extensionReceiverParameter)) -} - -internal object CheckArguments : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { - val diagnostics = SmartList() - for (parameterDescriptor in descriptorWithFreshTypes.valueParameters) { - // error was reported in ArgumentsToParametersMapper - val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue - for (argument in resolvedCallArgument.arguments) { - - val expectedType = argument.getExpectedType(parameterDescriptor) - val diagnostic = when (argument) { - is SimpleKotlinCallArgument -> - checkSimpleArgument(csBuilder, argument, expectedType) - is PostponableKotlinCallArgument -> - createPostponedArgumentAndPerformInitialChecks(csBuilder, argument, expectedType) - else -> unexpectedArgument(argument) - } - diagnostics.addIfNotNull(diagnostic) - - if (diagnostic != null && !diagnostic.candidateApplicability.isSuccess) break - } + override fun KotlinResolutionCandidate.process(workIndex: Int) { + if (workIndex == 0) { + checkReceiver(resolvedCall.dispatchReceiverArgument, candidateDescriptor.dispatchReceiverParameter) + } else { + checkReceiver(resolvedCall.extensionReceiverArgument, candidateDescriptor.extensionReceiverParameter) } - return diagnostics + } + + override fun KotlinResolutionCandidate.workCount() = 2 +} + +internal object CheckArguments : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val argument = kotlinCall.argumentsInParenthesis[workIndex] + resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false) + } + + override fun KotlinResolutionCandidate.workCount() = kotlinCall.argumentsInParenthesis.size +} + +internal object CheckExternalArgument : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val argument = kotlinCall.externalArgument ?: return + + resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false) } } -internal object CheckInfixResolutionPart : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { +internal object CheckInfixResolutionPart : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val candidateDescriptor = resolvedCall.candidateDescriptor if (callComponents.statelessCallbacks.isInfixCall(kotlinCall) && (candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isInfix)) { - return listOf(InfixCallNoInfixModifier) + addDiagnostic(InfixCallNoInfixModifier) } - - return emptyList() } } -internal object CheckOperatorResolutionPart : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { +internal object CheckOperatorResolutionPart : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val candidateDescriptor = resolvedCall.candidateDescriptor if (callComponents.statelessCallbacks.isOperatorCall(kotlinCall) && (candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isOperator)) { - return listOf(InvokeConventionCallNoOperatorModifier) + addDiagnostic(InvokeConventionCallNoOperatorModifier) } - - return emptyList() } } -internal object CheckAbstractSuperCallPart : ResolutionPart { - override fun SimpleKotlinResolutionCandidate.process(): List { - if (callComponents.statelessCallbacks.isSuperExpression(dispatchReceiverArgument)) { +internal object CheckAbstractSuperCallPart : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + val candidateDescriptor = resolvedCall.candidateDescriptor + + if (callComponents.statelessCallbacks.isSuperExpression(resolvedCall.dispatchReceiverArgument)) { if (candidateDescriptor is MemberDescriptor && candidateDescriptor.modality == Modality.ABSTRACT) { - return listOf(AbstractSuperCall) + addDiagnostic(AbstractSuperCall) } } - - return emptyList() } +} +internal object ErrorDescriptorResolutionPart : ResolutionPart() { + override fun KotlinResolutionCandidate.process(workIndex: Int) { + assert(ErrorUtils.isError(candidateDescriptor)) { + "Should be error descriptor: $candidateDescriptor" + } + resolvedCall.typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments + resolvedCall.argumentMappingByOriginal = emptyMap() + resolvedCall.substitutor = FreshVariableNewTypeSubstitutor.Empty + resolvedCall.argumentToCandidateParameter = emptyMap() + + kotlinCall.explicitReceiver?.safeAs()?.let { + resolveKotlinArgument(it, null, isReceiver = true) + } + for (argument in kotlinCall.argumentsInParenthesis) { + resolveKotlinArgument(argument, null, isReceiver = true) + } + + kotlinCall.externalArgument?.let { + resolveKotlinArgument(it, null, isReceiver = true) + } + } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt index 5de6297407f..ed11eca0a42 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt @@ -35,22 +35,25 @@ import org.jetbrains.kotlin.types.upperIfFlexible fun checkSimpleArgument( csBuilder: ConstraintSystemBuilder, argument: SimpleKotlinCallArgument, - expectedType: UnwrappedType, - isReceiver: Boolean = false -): KotlinCallDiagnostic? { - return when (argument) { - is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, isReceiver) - is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, isReceiver) - else -> unexpectedArgument(argument) - } + expectedType: UnwrappedType?, + diagnosticsHolder: KotlinDiagnosticsHolder, + isReceiver: Boolean +): ResolvedAtom = when (argument) { + is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) + is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) + else -> unexpectedArgument(argument) } private fun checkExpressionArgument( csBuilder: ConstraintSystemBuilder, expressionArgument: ExpressionKotlinCallArgument, - expectedType: UnwrappedType, + expectedType: UnwrappedType?, + diagnosticsHolder: KotlinDiagnosticsHolder, isReceiver: Boolean -): KotlinCallDiagnostic? { +): ResolvedAtom { + val resolvedKtExpression = ResolvedExpressionAtom(expressionArgument) + if (expectedType == null) return resolvedKtExpression + // todo run this approximation only once for call val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType) @@ -70,30 +73,31 @@ private fun checkExpressionArgument( val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument) if (expressionArgument.isSafeCall) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) { - return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)?.let { return it } + diagnosticsHolder.addDiagnosticIfNotNull( + unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)) } - return null + return resolvedKtExpression } if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { if (!isReceiver) { - return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position)?.let { return it } + diagnosticsHolder.addDiagnosticIfNotNull(unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position)) + return resolvedKtExpression } val unstableType = expressionArgument.receiver.unstableType if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) { - return UnstableSmartCast(expressionArgument, unstableType) + diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType)) } else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) { - return UnsafeCallError(expressionArgument) + diagnosticsHolder.addDiagnostic(UnsafeCallError(expressionArgument)) } else { csBuilder.addSubtypeConstraint(argumentType, expectedType, position) - return null } } - return null + return resolvedKtExpression } /** @@ -131,30 +135,33 @@ private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedTy private fun checkSubCallArgument( csBuilder: ConstraintSystemBuilder, subCallArgument: SubKotlinCallArgument, - expectedType: UnwrappedType, + expectedType: UnwrappedType?, + diagnosticsHolder: KotlinDiagnosticsHolder, isReceiver: Boolean -): KotlinCallDiagnostic? { - val resolvedCall = subCallArgument.resolvedCall - val expectedNullableType = expectedType.makeNullableAsSpecified(true) - val position = ArgumentConstraintPosition(subCallArgument) +): ResolvedAtom { + val subCallResult = subCallArgument.callResult - csBuilder.addInnerCall(resolvedCall) + if (expectedType == null) return subCallResult + + val expectedNullableType = expectedType.makeNullableAsSpecified(true) + val position = if (isReceiver) ReceiverConstraintPosition(subCallArgument) else ArgumentConstraintPosition(subCallArgument) // subArgument cannot has stable smartcast // return type can contains fixed type variables val currentReturnType = csBuilder.buildCurrentSubstitutor().safeSubstitute(subCallArgument.receiver.receiverValue.type.unwrap()) if (subCallArgument.isSafeCall) { csBuilder.addSubtypeConstraint(currentReturnType, expectedNullableType, position) - return null + return subCallResult } if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) && csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position) ) { - return UnsafeCallError(subCallArgument) + diagnosticsHolder.addDiagnostic(UnsafeCallError(subCallArgument)) + return subCallResult } csBuilder.addSubtypeConstraint(currentReturnType, expectedType, position) - return null + return subCallResult } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt index 12cd7fa2b8a..bfea007cbde 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt @@ -16,12 +16,18 @@ package org.jetbrains.kotlin.resolve.calls.inference +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable -import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.LHSResult +import org.jetbrains.kotlin.resolve.calls.model.SubKotlinCallArgument import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.utils.addToStdlib.safeAs interface ConstraintSystemOperation { val hasContradiction: Boolean @@ -36,23 +42,25 @@ interface ConstraintSystemOperation { } interface ConstraintSystemBuilder : ConstraintSystemOperation { - fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) - fun addPostponedArgument(postponedArgument: PostponedKotlinCallArgument) - + val builtIns: KotlinBuiltIns // if runOperations return true, then this operation will be applied, and function return true fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean fun buildCurrentSubstitutor(): NewTypeSubstitutor - - /** - * This function removes variables for which we know exact type. - * @return substitutor from typeVariable to result - */ - fun simplify(): NewTypeSubstitutor } fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) = runTransaction { if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position) !hasContradiction - } \ No newline at end of file + } + + +fun PostponedArgumentsAnalyzer.Context.addSubsystemForArgument(argument: KotlinCallArgument?) { + when (argument) { + is SubKotlinCallArgument -> addOtherSystem(argument.callResult.constraintSystem) + is CallableReferenceKotlinCallArgument -> { + addSubsystemForArgument(argument.lhsResult.safeAs()?.lshCallArgument) + } + } +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt index 6d1415d61fa..229cbd048b9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage +import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.types.* @@ -27,6 +28,17 @@ fun ConstraintStorage.buildCurrentSubstitutor() = NewTypeSubstitutorByConstructo it.key to it.value }) +fun ConstraintStorage.buildResultingSubstitutor(): NewTypeSubstitutor { + val currentSubstitutorMap = fixedTypeVariables.entries.associate { + it.key to it.value + } + val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) -> + freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor) + } + + return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap) +} + val CallableDescriptor.returnTypeOrNothing: UnwrappedType get() { returnType?.let { return it.unwrap() } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt index fef4a6e8ed6..7d6f4ccd2e5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/NewConstraintSystem.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.resolve.calls.inference +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter @@ -23,13 +24,14 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic interface NewConstraintSystem { + val builtIns: KotlinBuiltIns + val hasContradiction: Boolean val diagnostics: List fun getBuilder(): ConstraintSystemBuilder // after this method we shouldn't mutate system via ConstraintSystemBuilder fun asReadOnlyStorage(): ConstraintStorage - fun asCallCompleterContext(): KotlinCallCompleter.Context fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompleterImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt similarity index 55% rename from compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompleterImpl.kt rename to compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt index a2f57b1fe1b..05f61bf878b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompleterImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt @@ -22,7 +22,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraint import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs class KotlinConstraintSystemCompleter( private val resultTypeResolver: ResultTypeResolver, @@ -34,7 +36,6 @@ class KotlinConstraintSystemCompleter( } interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context { - override val postponedArguments: List override val notFixedTypeVariables: Map // type can be proper if it not contains not fixed type variables @@ -48,23 +49,27 @@ class KotlinConstraintSystemCompleter( fun runCompletion( c: Context, completionMode: ConstraintSystemCompletionMode, + topLevelPrimitive: ResolvedAtom, topLevelType: UnwrappedType, - analyze: (PostponedKotlinCallArgument) -> Unit + analyze: (PostponedResolvedAtom) -> Unit ) { while (true) { - if (analyzePostponeArgumentIfPossible(c, analyze)) continue + if (analyzePostponeArgumentIfPossible(c, topLevelPrimitive, analyze)) continue - val variableForFixation = variableFixationFinder.findFirstVariableForFixation(c, completionMode, topLevelType) + val allTypeVariables = getOrderedAllTypeVariables(c, topLevelPrimitive) + val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive) + val variableForFixation = variableFixationFinder.findFirstVariableForFixation( + c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType) if (shouldWeForceCallableReferenceResolution(completionMode, variableForFixation)) { - if (forceCallableReferenceResolution(c, analyze)) continue + if (forceCallableReferenceResolution(topLevelPrimitive, analyze)) continue } if (variableForFixation != null) { if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) { val variableWithConstraints = c.notFixedTypeVariables[variableForFixation.variable]!! - fixVariable(c, topLevelType, variableWithConstraints) + fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives) if (!variableForFixation.hasProperConstraint) { c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable)) @@ -77,7 +82,7 @@ class KotlinConstraintSystemCompleter( if (completionMode == ConstraintSystemCompletionMode.FULL) { // force resolution for all not-analyzed argument's - c.postponedArguments.filterNot { it.analyzed }.forEach(analyze) + getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).forEach(analyze) } } @@ -92,8 +97,8 @@ class KotlinConstraintSystemCompleter( } // true if we do analyze - private fun analyzePostponeArgumentIfPossible(c: Context, analyze: (PostponedKotlinCallArgument) -> Unit): Boolean { - for (argument in getOrderedNotAnalyzedPostponedArguments(c)) { + private fun analyzePostponeArgumentIfPossible(c: Context, topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean { + for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)) { if (canWeAnalyzeIt(c, argument)) { analyze(argument) return true @@ -103,24 +108,55 @@ class KotlinConstraintSystemCompleter( } // true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful - private fun forceCallableReferenceResolution(c: Context, analyze: (PostponedKotlinCallArgument) -> Unit): Boolean { - val callableReferenceArgument = getOrderedNotAnalyzedPostponedArguments(c). - firstIsInstanceOrNull() ?: return false + private fun forceCallableReferenceResolution(topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean { + val callableReferenceArgument = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive). + firstIsInstanceOrNull() ?: return false analyze(callableReferenceArgument) return true } - private fun getOrderedNotAnalyzedPostponedArguments(c: Context): List { - val notAnalyzedArguments = c.postponedArguments.filterNot { it.analyzed } + private fun getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive: ResolvedAtom): List { + fun ResolvedAtom.process(to: MutableList) { + to.addIfNotNull(this.safeAs()?.takeUnless { it.analyzed }) - // todo insert logic here - return notAnalyzedArguments + if (analyzed) { + subResolvedAtoms.forEach { it.process(to) } + } + } + return arrayListOf().apply { topLevelPrimitive.process(this) } + } + + private fun getOrderedAllTypeVariables(c: Context, topLevelPrimitive: ResolvedAtom) : List { + fun ResolvedAtom.process(to: MutableList) { + val typeVariables = when (this) { + is ResolvedCallAtom -> substitutor.freshVariables + is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables.orEmpty() + is ResolvedLambdaAtom -> listOfNotNull(typeVariableForLambdaReturnType) + else -> emptyList() + } + typeVariables.mapNotNullTo(to) { + val typeConstructor = it.freshTypeConstructor + typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) } + } + + if (analyzed) { + subResolvedAtoms.forEach { it.process(to) } + } + } + val result = arrayListOf().apply { topLevelPrimitive.process(this) } + + assert(result.size == c.notFixedTypeVariables.size) { + val notFoundTypeVariables = c.notFixedTypeVariables.keys.toMutableSet().removeAll(result) + "Not all type variables found: $notFoundTypeVariables" + } + + return result } - private fun canWeAnalyzeIt(c: Context, argument: PostponedKotlinCallArgument): Boolean { - if (argument is PostponedCollectionLiteralArgument || argument.analyzed) return false + private fun canWeAnalyzeIt(c: Context, argument: PostponedResolvedAtom): Boolean { + if (argument.analyzed) return false return argument.inputTypes.all { c.canBeProper(it) } } @@ -128,9 +164,10 @@ class KotlinConstraintSystemCompleter( private fun fixVariable( c: Context, topLevelType: UnwrappedType, - variableWithConstraints: VariableWithConstraints + variableWithConstraints: VariableWithConstraints, + postponedResolveKtPrimitives: List ) { - val direction = TypeVariableDirectionCalculator(c, topLevelType).getDirection(variableWithConstraints) + val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints) val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt index 5f23c8b1088..6d4d21a7d1c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt @@ -150,4 +150,8 @@ class FreshVariableNewTypeSubstitutor(val freshVariables: List): TypeSubstitutor { val substitutionMap = typeParameters.associate { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt index 4710a7129db..d0c8fe24bb3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDependencyInformationProvider.kt @@ -17,7 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints -import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.typeUtil.contains @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.utils.SmartSet class TypeVariableDependencyInformationProvider( private val notFixedTypeVariables: Map, - private val postponedArguments: List, + private val postponedKtPrimitives: List, private val topLevelType: UnwrappedType? ) { // not oriented edges @@ -71,7 +71,7 @@ class TypeVariableDependencyInformationProvider( postponeArgumentsEdges.getOrPut(from) { hashSetOf() }.add(to) } - for (argument in postponedArguments) { + for (argument in postponedKtPrimitives) { if (argument.analyzed) continue val typeVariablesInOutputType = SmartSet.create() @@ -89,7 +89,7 @@ class TypeVariableDependencyInformationProvider( } private fun computeRelatedToAllOutputTypes() { - for (argument in postponedArguments) { + for (argument in postponedKtPrimitives) { if (argument.analyzed) continue (argument.outputType ?: continue).forAllMyTypeVariables { addAllRelatedNodes(relatedToAllOutputTypes, it, includePostponedEdges = false) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDirectionCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDirectionCalculator.kt index c73fe05b8b9..20fe372fbcc 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDirectionCalculator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeVariableDirectionCalculator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints +import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom import org.jetbrains.kotlin.types.FlexibleType import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.UnwrappedType @@ -31,7 +32,8 @@ import org.jetbrains.kotlin.utils.SmartList private typealias Variable = VariableWithConstraints class TypeVariableDirectionCalculator( - val c: VariableFixationFinder.Context, + private val c: VariableFixationFinder.Context, + private val postponedKtPrimitives: List, topLevelType: UnwrappedType ) { enum class ResolveDirection { @@ -57,7 +59,7 @@ class TypeVariableDirectionCalculator( topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction -> enterToNode(variableWithConstraints, direction) } - for (postponedArgument in c.postponedArguments) { + for (postponedArgument in postponedKtPrimitives) { for (inputType in postponedArgument.inputTypes) { inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction -> enterToNode(variableWithConstraints, direction) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt index b6c6e4d29c2..676bec8c262 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt @@ -17,11 +17,11 @@ package org.jetbrains.kotlin.resolve.calls.inference.components import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.* +import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints -import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.typeUtil.contains @@ -29,16 +29,17 @@ import org.jetbrains.kotlin.types.typeUtil.contains class VariableFixationFinder { interface Context { val notFixedTypeVariables: Map - val postponedArguments: List } data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean) fun findFirstVariableForFixation( c: Context, + allTypeVariables: List, + postponedKtPrimitives: List, completionMode: ConstraintSystemCompletionMode, topLevelType: UnwrappedType - ): VariableForFixation? = c.findTypeVariableForFixation(completionMode, topLevelType) + ): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType) private enum class TypeVariableFixationReadiness { FORBIDDEN, @@ -52,6 +53,7 @@ class VariableFixationFinder { variable: TypeConstructor, dependencyProvider: TypeVariableDependencyInformationProvider ): TypeVariableFixationReadiness = when { + !notFixedTypeVariables.contains(variable) || dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN !variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE @@ -60,14 +62,15 @@ class VariableFixationFinder { } private fun Context.findTypeVariableForFixation( + allTypeVariables: List, + postponedKtPrimitives: List, completionMode: ConstraintSystemCompletionMode, topLevelType: UnwrappedType ): VariableForFixation? { - val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, + val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedKtPrimitives, topLevelType.takeIf { completionMode == PARTIAL }) - val initialOrder = notFixedTypeVariables.keys.sortByInitialOrder() - val candidate = initialOrder.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null + val candidate = allTypeVariables.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null val candidateReadiness = getTypeVariableReadiness(candidate, dependencyProvider) return when (candidateReadiness) { TypeVariableFixationReadiness.FORBIDDEN -> null @@ -94,7 +97,4 @@ class VariableFixationFinder { private fun Context.isProperType(type: UnwrappedType): Boolean = !type.contains { notFixedTypeVariables.containsKey(it.constructor) } - private fun Collection.sortByInitialOrder(): List = - sortedBy { toString() } // todo - } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt index 1868290d790..b8447ab638b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt @@ -50,9 +50,9 @@ class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintP class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : ConstraintPosition() { override fun toString() = "TypeArgument $typeArgument" } -class LambdaArgumentConstraintPosition(val lambdaArgument: PostponedLambdaArgument) : ConstraintPosition() { +class LambdaArgumentConstraintPosition(val lambda: ResolvedLambdaAtom) : ConstraintPosition() { override fun toString(): String { - return "LambdaArgument $lambdaArgument" + return "LambdaArgument $lambda" } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt index 35bee549b5e..e80787733b6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt @@ -52,8 +52,6 @@ interface ConstraintStorage { val maxTypeDepthFromInitialConstraints: Int val errors: List val fixedTypeVariables: Map - val postponedArguments: List - val innerCalls: List object Empty : ConstraintStorage { override val allTypeVariables: Map get() = emptyMap() @@ -62,8 +60,6 @@ interface ConstraintStorage { override val maxTypeDepthFromInitialConstraints: Int get() = 1 override val errors: List get() = emptyList() override val fixedTypeVariables: Map get() = emptyMap() - override val postponedArguments: List get() = emptyList() - override val innerCalls: List get() = emptyList() } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt index 26af94a4f17..3f84245ccbf 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt @@ -18,8 +18,6 @@ package org.jetbrains.kotlin.resolve.calls.inference.model import org.jetbrains.kotlin.resolve.calls.inference.trimToSize import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic -import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument -import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType import java.util.* @@ -105,6 +103,4 @@ internal class MutableConstraintStorage : ConstraintStorage { override var maxTypeDepthFromInitialConstraints: Int = 1 override val errors: MutableList = ArrayList() override val fixedTypeVariables: MutableMap = LinkedHashMap() - override val postponedArguments: MutableList = ArrayList() - override val innerCalls: MutableList = ArrayList() } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index 9710861a8e8..a6debcb0d93 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -16,28 +16,28 @@ package org.jetbrains.kotlin.resolve.calls.inference.model -import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.inference.* -import org.jetbrains.kotlin.resolve.calls.inference.components.* +import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector +import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic -import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument -import org.jetbrains.kotlin.resolve.calls.model.PostponedLambdaArgument -import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall import org.jetbrains.kotlin.resolve.calls.tower.isSuccess -import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.utils.SmartList -import java.util.* -class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val resultTypeResolver: ResultTypeResolver): +class NewConstraintSystemImpl( + private val constraintInjector: ConstraintInjector, + override val builtIns: KotlinBuiltIns +): NewConstraintSystem, ConstraintSystemBuilder, ConstraintInjector.Context, ResultTypeResolver.Context, - KotlinCallCompleter.Context, KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context { @@ -69,12 +69,6 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re return storage } - override fun asCallCompleterContext(): KotlinCallCompleter.Context { - checkState(State.BUILDING, State.COMPLETION) - state = State.COMPLETION - return this - } - override fun asConstraintSystemCompleterContext() = apply { checkState(State.BUILDING) } override fun asPostponedArgumentsAnalyzerContext() = apply { checkState(State.BUILDING) } @@ -150,51 +144,11 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re return false } - override fun addPostponedArgument(postponedArgument: PostponedKotlinCallArgument) { - checkState(State.BUILDING, State.COMPLETION) - storage.postponedArguments.add(postponedArgument) - } - - private fun getVariablesForFixation(): Map { - val fixedVariables = LinkedHashMap() - - for (variableWithConstrains in storage.notFixedTypeVariables.values) { - val resultType = resultTypeResolver.findResultIfThereIsEqualsConstraint( - apply { checkState(State.BUILDING) }, - variableWithConstrains, - allowedFixToNotProperType = false - ) - if (resultType != null) { - fixedVariables[variableWithConstrains.typeVariable] = resultType - } - } - return fixedVariables - } - - override fun simplify(): NewTypeSubstitutor { - checkState(State.BUILDING) - - var fixedVariables = getVariablesForFixation() - while (fixedVariables.isNotEmpty()) { - for ((variable, resultType) in fixedVariables) { - fixVariable(variable, resultType) - } - fixedVariables = getVariablesForFixation() - } - - return storage.buildCurrentSubstitutor() - } - // ConstraintSystemBuilder, KotlinConstraintSystemCompleter.Context override val hasContradiction: Boolean - get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) } + get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.FREEZED, State.BUILDING, State.COMPLETION, State.TRANSACTION) } - // ConstraintSystemBuilder - override fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) { - checkState(State.BUILDING, State.COMPLETION) - storage.innerCalls.add(innerCall) - - val otherSystem = innerCall.candidate.lastCall.constraintSystem.asReadOnlyStorage() + override fun addOtherSystem(otherSystem: ConstraintStorage) { storage.allTypeVariables.putAll(otherSystem.allTypeVariables) for ((variable, constraints) in otherSystem.notFixedTypeVariables) { notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints) @@ -203,11 +157,8 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re storage.maxTypeDepthFromInitialConstraints = Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints) storage.errors.addAll(otherSystem.errors) storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables) - storage.postponedArguments.addAll(otherSystem.postponedArguments) - storage.innerCalls.addAll(otherSystem.innerCalls) } - // ResultTypeResolver.Context, ConstraintSystemBuilder override fun isProperType(type: UnwrappedType): Boolean { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) @@ -246,16 +197,6 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re storage.errors.add(error) } - // KotlinCallCompleter.Context, FixationOrderCalculator.Context - override val lambdaArguments: List get() { - checkState(State.BUILDING, State.COMPLETION) - return storage.postponedArguments.filterIsInstance() - } - - // FixationOrderCalculator.Context, KotlinCallCompleter.Context, KotlinConstraintSystemCompleter.Context - override val postponedArguments: List - get() = storage.postponedArguments.apply { checkState(State.BUILDING, State.COMPLETION) } - // KotlinConstraintSystemCompleter.Context override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) { checkState(State.BUILDING, State.COMPLETION) @@ -272,12 +213,6 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType } - // KotlinCallCompleter.Context - override val innerCalls: List get() { - checkState(State.COMPLETION) - return storage.innerCalls - } - // KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context override fun canBeProper(type: UnwrappedType): Boolean { checkState(State.BUILDING, State.COMPLETION) @@ -289,17 +224,4 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re checkState(State.BUILDING, State.COMPLETION) return storage.buildCurrentSubstitutor() } - - // KotlinCallCompleter.Context - override fun buildResultingSubstitutor(): NewTypeSubstitutor { - checkState(State.COMPLETION) - val currentSubstitutorMap = storage.fixedTypeVariables.entries.associate { - it.key to it.value - } - val uninferredSubstitutorMap = storage.notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) -> - freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor) - } - - return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap) - } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt index 98bf6e2b115..ea537253d01 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCall.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.model import org.jetbrains.kotlin.name.Name -interface KotlinCall { +interface KotlinCall : ResolutionAtom { val callKind: KotlinCallKind val explicitReceiver: ReceiverKotlinCallArgument? @@ -43,6 +43,18 @@ private fun SimpleKotlinCallArgument.checkReceiverInvariants() { assert(argumentName == null) { "Argument name should be null for receiver: $this, but it is $argumentName" } + checkArgumentInvariants() +} + +private fun KotlinCallArgument.checkArgumentInvariants() { + if (this is SubKotlinCallArgument) { + assert(callResult.type == CallResolutionResult.Type.PARTIAL) { + "SubCall should has type PARTIAL: $callResult" + } + assert(callResult.resultCallAtom != null) { + "SubCall should has resultCallAtom: $callResult" + } + } } fun KotlinCall.checkCallInvariants() { @@ -52,6 +64,8 @@ fun KotlinCall.checkCallInvariants() { (explicitReceiver as? SimpleKotlinCallArgument)?.checkReceiverInvariants() dispatchReceiverForInvokeExtension?.checkReceiverInvariants() + argumentsInParenthesis.forEach(KotlinCallArgument::checkArgumentInvariants) + externalArgument?.checkArgumentInvariants() if (callKind != KotlinCallKind.FUNCTION) { assert(externalArgument == null) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt index 5fdaf63588d..600678a0239 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt @@ -26,12 +26,15 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver import org.jetbrains.kotlin.types.UnwrappedType -interface ReceiverKotlinCallArgument { +interface ReceiverKotlinCallArgument : KotlinCallArgument { val receiver: DetailedReceiver } class QualifierReceiverKotlinCallArgument(override val receiver: QualifierReceiver) : ReceiverKotlinCallArgument { override fun toString() = "$receiver" + + override val isSpread get() = false + override val argumentName: Name? get() = null } interface KotlinCallArgument { @@ -39,7 +42,7 @@ interface KotlinCallArgument { val argumentName: Name? } -interface PostponableKotlinCallArgument : KotlinCallArgument +interface PostponableKotlinCallArgument : KotlinCallArgument, ResolutionAtom interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgument { override val receiver: ReceiverValueWithSmartCastInfo @@ -47,10 +50,10 @@ interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgum val isSafeCall: Boolean } -interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument +interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument, ResolutionAtom interface SubKotlinCallArgument : SimpleKotlinCallArgument { - val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall + val callResult: CallResolutionResult } interface LambdaKotlinCallArgument : PostponableKotlinCallArgument { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnistics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnistics.kt index fbb7d4a5f63..ef340822de4 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnistics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnistics.kt @@ -154,3 +154,19 @@ object AbstractSuperCall : KotlinCallDiagnostic(RUNTIME_ERROR) { reporter.onCall(this) } } + +// candidates result +class NoneCandidatesCallDiagnostic(val kotlinCall: KotlinCall) : KotlinCallDiagnostic(INAPPLICABLE) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCall(this) + } +} + +class ManyCandidatesCallDiagnostic( + val kotlinCall: KotlinCall, + val candidates: Collection +) : KotlinCallDiagnostic(INAPPLICABLE) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCall(this) + } +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt index 2c46352028b..ba481b4cca7 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt @@ -16,11 +16,15 @@ package org.jetbrains.kotlin.resolve.calls.model +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.resolve.calls.components.* +import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemForArgument import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector -import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage +import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation @@ -34,16 +38,29 @@ class KotlinCallComponents( val statelessCallbacks: KotlinResolutionStatelessCallbacks, val argumentsToParametersMapper: ArgumentsToParametersMapper, val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper, - val resultTypeResolver: ResultTypeResolver, val constraintInjector: ConstraintInjector, - val reflectionTypes: ReflectionTypes + val reflectionTypes: ReflectionTypes, + val builtIns: KotlinBuiltIns ) class SimpleCandidateFactory( val callComponents: KotlinCallComponents, val scopeTower: ImplicitScopeTower, val kotlinCall: KotlinCall -): CandidateFactory { +): CandidateFactory { + val baseSystem: ConstraintStorage + + init { + val baseSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns) + baseSystem.addSubsystemForArgument(kotlinCall.explicitReceiver) + baseSystem.addSubsystemForArgument(kotlinCall.dispatchReceiverForInvokeExtension) + for (argument in kotlinCall.argumentsInParenthesis) { + baseSystem.addSubsystemForArgument(argument) + } + baseSystem.addSubsystemForArgument(kotlinCall.externalArgument) + + this.baseSystem = baseSystem.asReadOnlyStorage() + } // todo: try something else, because current method is ugly and unstable private fun createReceiverArgument( @@ -64,37 +81,80 @@ class SimpleCandidateFactory( else -> null } + fun createCandidate(givenCandidate: GivenCandidate): KotlinResolutionCandidate { + val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false + + val explicitReceiverKind = if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER + val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) } + return createCandidate(givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null, + listOf(), givenCandidate.knownTypeParametersResultingSubstitutor) + } + override fun createCandidate( towerCandidate: CandidateWithBoundDispatchReceiver, explicitReceiverKind: ExplicitReceiverKind, extensionReceiver: ReceiverValueWithSmartCastInfo? - ): SimpleKotlinResolutionCandidate { + ): KotlinResolutionCandidate { val dispatchArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind), towerCandidate.dispatchReceiver) val extensionArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), extensionReceiver) - if (ErrorUtils.isError(towerCandidate.descriptor)) { - return ErrorKotlinResolutionCandidate(callComponents, scopeTower, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver, towerCandidate.descriptor) + return createCandidate(towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, + extensionArgumentReceiver, towerCandidate.diagnostics, knownSubstitutor = null) + } + + private fun createCandidate( + descriptor: CallableDescriptor, + explicitReceiverKind: ExplicitReceiverKind, + dispatchArgumentReceiver: SimpleKotlinCallArgument?, + extensionArgumentReceiver: SimpleKotlinCallArgument?, + initialDiagnostics: Collection, + knownSubstitutor: TypeSubstitutor? + ): KotlinResolutionCandidate { + val resolvedKtCall = MutableResolvedCallAtom(kotlinCall, descriptor, explicitReceiverKind, + dispatchArgumentReceiver, extensionArgumentReceiver) + + if (ErrorUtils.isError(descriptor)) { + return KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor, listOf(ErrorDescriptorResolutionPart)) } - val candidateDiagnostics = towerCandidate.diagnostics.toMutableList() - if (callComponents.statelessCallbacks.isHiddenInResolution(towerCandidate.descriptor, kotlinCall)) { - candidateDiagnostics.add(HiddenDescriptor) + val candidate = KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor) + + initialDiagnostics.forEach(candidate::addDiagnostic) + + if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall)) { + candidate.addDiagnostic(HiddenDescriptor) } - if (extensionReceiver != null) { - val parameterIsDynamic = towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic() - val argumentIsDynamic = extensionReceiver.receiverValue.type.isDynamic() + if (extensionArgumentReceiver != null) { + val parameterIsDynamic = descriptor.extensionReceiverParameter!!.value.type.isDynamic() + val argumentIsDynamic = extensionArgumentReceiver.receiver.receiverValue.type.isDynamic() if (parameterIsDynamic != argumentIsDynamic || - (parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())) { - candidateDiagnostics.add(HiddenExtensionRelatedToDynamicTypes) + (parameterIsDynamic && !descriptor.hasDynamicExtensionAnnotation())) { + candidate.addDiagnostic(HiddenExtensionRelatedToDynamicTypes) } } - return SimpleKotlinResolutionCandidate(callComponents, scopeTower, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver, - towerCandidate.descriptor, null, candidateDiagnostics) + return candidate } + + fun createErrorCandidate(): KotlinResolutionCandidate { + val errorScope = ErrorUtils.createErrorScope("Error resolution candidate for call $kotlinCall") + val errorDescriptor = if (kotlinCall.callKind == KotlinCallKind.VARIABLE) { + errorScope.getContributedVariables(kotlinCall.name, scopeTower.location) + } + else { + errorScope.getContributedFunctions(kotlinCall.name, scopeTower.location) + }.first() + + val dispatchReceiver = createReceiverArgument(kotlinCall.explicitReceiver, fromResolution = null) + val explicitReceiverKind = if (dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER + + return createCandidate(errorDescriptor, explicitReceiverKind, dispatchReceiver, extensionArgumentReceiver = null, + initialDiagnostics = listOf(), knownSubstitutor = null) + } + } enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) { @@ -105,7 +165,7 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) { CheckAbstractSuperCallPart, NoTypeArguments, NoArguments, - CreateDescriptorWithFreshTypeVariables, + CreateFreshVariablesSubstitutor, CheckExplicitReceiverKindConsistency, CheckReceivers ), @@ -116,10 +176,12 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) { CheckAbstractSuperCallPart, MapTypeArguments, MapArguments, - CreateDescriptorWithFreshTypeVariables, + ArgumentsToCandidateParameterDescriptor, + CreateFreshVariablesSubstitutor, CheckExplicitReceiverKindConsistency, CheckReceivers, - CheckArguments + CheckArguments, + CheckExternalArgument ), UNSUPPORTED(); @@ -127,7 +189,6 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) { } class GivenCandidate( - val scopeTower: ImplicitScopeTower, val descriptor: FunctionDescriptor, val dispatchReceiver: ReceiverValueWithSmartCastInfo?, val knownTypeParametersResultingSubstitutor: TypeSubstitutor? diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/PostponedKotlinCallArguments.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/PostponedKotlinCallArguments.kt deleted file mode 100644 index 25d9d668451..00000000000 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/PostponedKotlinCallArguments.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.resolve.calls.model - -import org.jetbrains.kotlin.builtins.createFunctionType -import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType -import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType -import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate -import org.jetbrains.kotlin.resolve.calls.components.getFunctionTypeFromCallableReferenceExpectedType -import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable -import org.jetbrains.kotlin.types.SimpleType -import org.jetbrains.kotlin.types.UnwrappedType -import org.jetbrains.kotlin.types.typeUtil.builtIns - - -sealed class PostponedKotlinCallArgument { - abstract val argument: PostponableKotlinCallArgument - - abstract val analyzed: Boolean - - abstract val inputTypes: Collection - abstract val outputType: UnwrappedType? -} - -class PostponedLambdaArgument( - override val argument: LambdaKotlinCallArgument, - val isSuspend: Boolean, - val receiver: UnwrappedType?, - val parameters: List, - val returnType: UnwrappedType -) : PostponedKotlinCallArgument() { - override var analyzed: Boolean = false - - val type: SimpleType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiver, parameters, null, returnType, isSuspend) // todo support annotations - - override val inputTypes: Collection get() = receiver?.let { parameters + it } ?: parameters - override val outputType: UnwrappedType get() = returnType - - lateinit var resultArguments: List - lateinit var finalReturnType: UnwrappedType -} - -class PostponedCallableReferenceArgument( - override val argument: CallableReferenceKotlinCallArgument, - val expectedType: UnwrappedType -) : PostponedKotlinCallArgument() { - override var analyzed: Boolean = false - - override val inputTypes: Collection - get() { - val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return emptyList() - val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() } - val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap() - return receiver?.let { parameters + it } ?: parameters - } - - override val outputType: UnwrappedType? - get() { - val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null - return functionType.getReturnTypeFromFunctionType().unwrap() - } - - var analyzedAndThereIsResult: Boolean = false - - lateinit var myTypeVariables: List - lateinit var callableResolutionCandidate: CallableReferenceCandidate -} - -class PostponedCollectionLiteralArgument( - override val argument: CollectionLiteralKotlinCallArgument, - val expectedType: UnwrappedType -) : PostponedKotlinCallArgument() { - // for now we consider all such arguments as analyzed because they processed via special logic anyway - override val analyzed get() = true - - override val inputTypes: Collection - get() = emptyList() - override val outputType: UnwrappedType? - get() = null -} \ No newline at end of file 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 new file mode 100644 index 00000000000..f3551632b09 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -0,0 +1,173 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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.inference.components.FreshVariableNewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage +import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.types.UnwrappedType + +/** + * Call, Callable reference, lambda & function expression, collection literal. + * In future we should add literals here, because they have similar lifecycle. + * + * Expression with type is also primitive. This is done for simplification. todo + */ +interface ResolutionAtom + +sealed class ResolvedAtom { + abstract val atom: ResolutionAtom? // CallResolutionResult has no ResolutionAtom + + var analyzed: Boolean = false + private set + + lateinit var subResolvedAtoms: List + private set + lateinit var diagnostics: Collection + private set + + protected open fun setAnalyzedResults(subResolvedAtoms: List, diagnostics: Collection) { + assert(!analyzed) { + "Already analyzed: $this" + } + + analyzed = true + + this.subResolvedAtoms = subResolvedAtoms + this.diagnostics = diagnostics + } +} + +abstract class ResolvedCallAtom : ResolvedAtom() { + abstract override val atom: KotlinCall + abstract val candidateDescriptor: CallableDescriptor + abstract val explicitReceiverKind: ExplicitReceiverKind + abstract val dispatchReceiverArgument: SimpleKotlinCallArgument? + abstract val extensionReceiverArgument: SimpleKotlinCallArgument? + abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping + abstract val argumentMappingByOriginal: Map + abstract val substitutor: FreshVariableNewTypeSubstitutor +} + +class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : ResolvedAtom() { + init { + setAnalyzedResults(listOf(), listOf()) + } +} +sealed class PostponedResolvedAtom : ResolvedAtom() { + abstract val inputTypes: Collection + abstract val outputType: UnwrappedType? +} + +class ResolvedLambdaAtom( + override val atom: LambdaKotlinCallArgument, + val isSuspend: Boolean, + val receiver: UnwrappedType?, + val parameters: List, + val returnType: UnwrappedType, + val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType? +) : PostponedResolvedAtom() { + lateinit var resultArguments: List + private set + + fun setAnalyzedResults( + resultArguments: List, + subResolvedAtoms: List, + diagnostics: Collection + ) { + this.resultArguments = resultArguments + setAnalyzedResults(subResolvedAtoms, diagnostics) + } + + override val inputTypes: Collection get() = receiver?.let { parameters + it } ?: parameters + override val outputType: UnwrappedType get() = returnType +} + +class ResolvedCallableReferenceAtom( + override val atom: CallableReferenceKotlinCallArgument, + val expectedType: UnwrappedType? +) : PostponedResolvedAtom() { + var candidate: CallableReferenceCandidate? = null + private set + + fun setAnalyzedResults( + candidate: CallableReferenceCandidate?, + subResolvedAtoms: List, + diagnostics: Collection + ) { + this.candidate = candidate + setAnalyzedResults(subResolvedAtoms, diagnostics) + } + + override val inputTypes: Collection + get() { + val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return emptyList() + val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() } + val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap() + return receiver?.let { parameters + it } ?: parameters + } + + override val outputType: UnwrappedType? + get() { + val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null + return functionType.getReturnTypeFromFunctionType().unwrap() + } +} + +class ResolvedCollectionLiteralAtom( + override val atom: CollectionLiteralKotlinCallArgument, + val expectedType: UnwrappedType? +) : ResolvedAtom() { + init { + setAnalyzedResults(listOf(), listOf()) + } +} + +class CallResolutionResult( + val type: Type, + val resultCallAtom: ResolvedCallAtom?, + diagnostics: List, + val constraintSystem: ConstraintStorage +) : ResolvedAtom() { + override val atom: ResolutionAtom? get() = null + + enum class Type { + COMPLETED, // resultSubstitutor possible create use constraintSystem + PARTIAL, + ERROR // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates + } + + init { + setAnalyzedResults(listOfNotNull(resultCallAtom), diagnostics) + } + + override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})" +} + +val ResolvedCallAtom.freshReturnType: UnwrappedType? get() { + val returnType = candidateDescriptor.returnType ?: return null + return substitutor.safeSubstitute(returnType.unwrap()) +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt index 3a8336f0a58..fb0d781341e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt @@ -20,127 +20,163 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem +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.NewConstraintSystemImpl -import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.types.TypeSubstitutor -import java.util.* -interface ResolutionPart { - fun SimpleKotlinResolutionCandidate.process(): List +abstract class ResolutionPart { + abstract fun KotlinResolutionCandidate.process(workIndex: Int) + + open fun KotlinResolutionCandidate.workCount(): Int = 1 + + // helper functions + protected inline val KotlinResolutionCandidate.candidateDescriptor get() = resolvedCall.candidateDescriptor + protected inline val KotlinResolutionCandidate.kotlinCall get() = resolvedCall.atom } -sealed class KotlinResolutionCandidate : Candidate { - abstract val kotlinCall: KotlinCall +interface KotlinDiagnosticsHolder { + fun addDiagnostic(diagnostic: KotlinCallDiagnostic) - abstract val lastCall: SimpleKotlinResolutionCandidate -} + class SimpleHolder : KotlinDiagnosticsHolder { + private val diagnostics = arrayListOf() -class VariableAsFunctionKotlinResolutionCandidate( - override val kotlinCall: KotlinCall, - val resolvedVariable: SimpleKotlinResolutionCandidate, - val invokeCandidate: SimpleKotlinResolutionCandidate -) : KotlinResolutionCandidate() { - override val isSuccessful: Boolean get() = resolvedVariable.isSuccessful && invokeCandidate.isSuccessful - override val resultingApplicability: ResolutionCandidateApplicability - get() = maxOf(resolvedVariable.resultingApplicability, invokeCandidate.resultingApplicability) - - override val lastCall: SimpleKotlinResolutionCandidate get() = invokeCandidate -} - -sealed class AbstractSimpleKotlinResolutionCandidate( - val constraintSystem: NewConstraintSystem, - initialDiagnostics: Collection = emptyList() -) : KotlinResolutionCandidate() { - override val isSuccessful: Boolean - get() { - process(stopOnFirstError = true) - return !hasErrors + override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) { + diagnostics.add(diagnostic) } - override val resultingApplicability: ResolutionCandidateApplicability - get() { - process(stopOnFirstError = false) - return getResultApplicability(diagnostics + constraintSystem.diagnostics) - } - - private val diagnostics = ArrayList() - protected var step = 0 - private set - - protected var hasErrors = false - private set - - private fun process(stopOnFirstError: Boolean) { - while (step < resolutionSequence.size && (!stopOnFirstError || !hasErrors)) { - addDiagnostics(resolutionSequence[step].run { lastCall.process() }) - step++ - } + fun getDiagnostics(): List = diagnostics } - - private fun addDiagnostics(diagnostics: Collection) { - hasErrors = hasErrors || diagnostics.any { !it.candidateApplicability.isSuccess } || - constraintSystem.diagnostics.any { !it.candidateApplicability.isSuccess } - this.diagnostics.addAll(diagnostics) - } - - init { - addDiagnostics(initialDiagnostics) - } - - fun getCandidateDiagnostics(): List = diagnostics - - abstract val resolutionSequence: List } -open class SimpleKotlinResolutionCandidate( +fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnostic?) { + diagnostic?.let { addDiagnostic(it) } +} +/** + * baseSystem contains all information from arguments, i.e. it is union of all system of arguments + * Also by convention we suppose that baseSystem has no contradiction + */ +class KotlinResolutionCandidate( val callComponents: KotlinCallComponents, val scopeTower: ImplicitScopeTower, - override val kotlinCall: KotlinCall, - val explicitReceiverKind: ExplicitReceiverKind, - val dispatchReceiverArgument: SimpleKotlinCallArgument?, - val extensionReceiver: SimpleKotlinCallArgument?, - val candidateDescriptor: CallableDescriptor, - val knownTypeParametersResultingSubstitutor: TypeSubstitutor?, - initialDiagnostics: Collection -) : AbstractSimpleKotlinResolutionCandidate(NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.resultTypeResolver), initialDiagnostics) { - val csBuilder: ConstraintSystemBuilder get() = constraintSystem.getBuilder() + private val baseSystem: ConstraintStorage, + val resolvedCall: MutableResolvedCallAtom, + val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null, + private val resolutionSequence: List = resolvedCall.atom.callKind.resolutionSequence +) : Candidate, KotlinDiagnosticsHolder { + private var newSystem: NewConstraintSystemImpl? = null + private val diagnostics = arrayListOf() + private var currentApplicability = ResolutionCandidateApplicability.RESOLVED + private var subResolvedAtoms: MutableList = arrayListOf() - lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping - lateinit var argumentMappingByOriginal: Map - lateinit var descriptorWithFreshTypes: CallableDescriptor - lateinit var typeVariablesForFreshTypeParameters: List + private val stepCount = resolutionSequence.sumBy { it.run { workCount() } } + private var step = 0 - override val lastCall: SimpleKotlinResolutionCandidate get() = this - override val resolutionSequence: List get() = kotlinCall.callKind.resolutionSequence + fun getSystem(): NewConstraintSystem { + if (newSystem == null) { + newSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns) + newSystem!!.addOtherSystem(baseSystem) + } + return newSystem!! + } + + internal val csBuilder get() = getSystem().getBuilder() + + override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) { + diagnostics.add(diagnostic) + currentApplicability = maxOf(diagnostic.candidateApplicability, currentApplicability) + } + + fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom) { + subResolvedAtoms.add(resolvedAtom) + } + + private fun processParts(stopOnFirstError: Boolean) { + if (stopOnFirstError && step > 0) return // error already happened + if (step == stepCount) return + + var partIndex = 0 + var workStep = step + while (workStep > 0) { + val workCount = resolutionSequence[partIndex].run { workCount() } + if (workStep >= workCount) { + partIndex++ + workStep -= workCount + } + } + if (partIndex < resolutionSequence.size) { + if (processPart(resolutionSequence[partIndex], stopOnFirstError, workStep)) return + partIndex++ + } + + while (partIndex < resolutionSequence.size) { + if (processPart(resolutionSequence[partIndex], stopOnFirstError)) return + partIndex++ + } + if (step == stepCount) { + resolvedCall.setAnalyzedResults(subResolvedAtoms, diagnostics + getSystem().diagnostics) + } + } + + // true if part was interrupted + private fun processPart(part: ResolutionPart, stopOnFirstError: Boolean, startWorkIndex: Int = 0): Boolean { + for (workIndex in startWorkIndex until (part.run { workCount() })) { + if (stopOnFirstError && !currentApplicability.isSuccess) return true + + part.run { process(workIndex) } + step++ + } + return false + } + + val variableCandidateIfInvoke: KotlinResolutionCandidate? + get() = callComponents.statelessCallbacks.getVariableCandidateIfInvoke(resolvedCall.atom) + + private val variableApplicability + get() = variableCandidateIfInvoke?.resultingApplicability ?: ResolutionCandidateApplicability.RESOLVED + + override val isSuccessful: Boolean + get() { + processParts(stopOnFirstError = true) + return currentApplicability.isSuccess && variableApplicability.isSuccess + } + + override val resultingApplicability: ResolutionCandidateApplicability + get() { + processParts(stopOnFirstError = false) + + val systemApplicability = getResultApplicability(getSystem().diagnostics) + return maxOf(currentApplicability, systemApplicability, variableApplicability) + } override fun toString(): String { - val descriptor = DescriptorRenderer.COMPACT.render(candidateDescriptor) - val okOrFail = if (hasErrors) "FAIL" else "OK" - val step = "$step/${resolutionSequence.size}" + val descriptor = DescriptorRenderer.COMPACT.render(resolvedCall.candidateDescriptor) + val okOrFail = if (currentApplicability.isSuccess) "OK" else "FAIL" + val step = "$step/$stepCount" return "$okOrFail($step): $descriptor" } } -class ErrorKotlinResolutionCandidate( - callComponents: KotlinCallComponents, - scopeTower: ImplicitScopeTower, - kotlinCall: KotlinCall, - explicitReceiverKind: ExplicitReceiverKind, - dispatchReceiverArgument: SimpleKotlinCallArgument?, - extensionReceiver: SimpleKotlinCallArgument?, - candidateDescriptor: CallableDescriptor -) : SimpleKotlinResolutionCandidate(callComponents, scopeTower, kotlinCall, explicitReceiverKind, dispatchReceiverArgument, - extensionReceiver, candidateDescriptor, null, listOf()) { - override val resolutionSequence: List get() = emptyList() +class MutableResolvedCallAtom( + override val atom: KotlinCall, + override val candidateDescriptor: CallableDescriptor, // original candidate descriptor + override val explicitReceiverKind: ExplicitReceiverKind, + override val dispatchReceiverArgument: SimpleKotlinCallArgument?, + override val extensionReceiverArgument: SimpleKotlinCallArgument? +) : ResolvedCallAtom() { + override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping + override lateinit var argumentMappingByOriginal: Map + override lateinit var substitutor: FreshVariableNewTypeSubstitutor + lateinit var argumentToCandidateParameter: Map - init { - typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments - argumentMappingByOriginal = emptyMap() - descriptorWithFreshTypes = candidateDescriptor + override public fun setAnalyzedResults(subResolvedAtoms: List, diagnostics: Collection) { + super.setAnalyzedResults(subResolvedAtoms, diagnostics) } + + override fun toString(): String = "$atom, candidate = $candidateDescriptor" } + diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedKotlinCall.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedKotlinCall.kt index eab32d32381..99080fa93a0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedKotlinCall.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedKotlinCall.kt @@ -16,55 +16,6 @@ package org.jetbrains.kotlin.resolve.calls.model -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind -import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability -import org.jetbrains.kotlin.resolve.calls.tower.getResultApplicability -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo -import org.jetbrains.kotlin.types.UnwrappedType - -sealed class ResolvedKotlinCall { - abstract val resultingApplicability: ResolutionCandidateApplicability - - class CompletedResolvedKotlinCall( - val completedCall: CompletedKotlinCall, - val allInnerCalls: Collection, - val lambdaArguments: List - ): ResolvedKotlinCall() { - override val resultingApplicability get() = completedCall.resultingApplicability - } - - class OnlyResolvedKotlinCall(val candidate: KotlinResolutionCandidate) : ResolvedKotlinCall() { - override val resultingApplicability get() = candidate.resultingApplicability - } -} - -sealed class CompletedKotlinCall { - abstract val resultingApplicability: ResolutionCandidateApplicability - - class Simple( - val kotlinCall: KotlinCall, - val candidateDescriptor: CallableDescriptor, - val resultingDescriptor: CallableDescriptor, - val diagnostics: List, - val explicitReceiverKind: ExplicitReceiverKind, - val dispatchReceiver: ReceiverValueWithSmartCastInfo?, - val extensionReceiver: ReceiverValueWithSmartCastInfo?, - val typeArguments: List, - val argumentMappingByOriginal: Map - ): CompletedKotlinCall() { - override val resultingApplicability = getResultApplicability(diagnostics) - } - - class VariableAsFunction( - val kotlinCall: KotlinCall, - val variableCall: Simple, - val invokeCall: Simple - ): CompletedKotlinCall() { - override val resultingApplicability get() = maxOf(variableCall.resultingApplicability, invokeCall.resultingApplicability) - } -} sealed class ResolvedCallArgument { abstract val arguments: List diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt index 950ccd535c5..7f0d0baa6c9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt @@ -60,7 +60,7 @@ interface CandidateWithBoundDispatchReceiver { val dispatchReceiver: ReceiverValueWithSmartCastInfo? } -fun getResultApplicability(diagnostics: List) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability +fun getResultApplicability(diagnostics: Collection) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability ?: RESOLVED enum class ResolutionCandidateApplicability { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt index a33fca34153..f7b83e6f5b6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt @@ -41,4 +41,9 @@ internal class CandidateWithBoundDispatchReceiverImpl( override val dispatchReceiver: ReceiverValueWithSmartCastInfo?, override val descriptor: CallableDescriptor, override val diagnostics: List -) : CandidateWithBoundDispatchReceiver \ No newline at end of file +) : CandidateWithBoundDispatchReceiver + +fun C.forceResolution(): C { + resultingApplicability + return this +} \ No newline at end of file