From 3696bebb4871888681492790c0fce694aa2ed0fb Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Mon, 20 Sep 2021 15:51:18 +0300 Subject: [PATCH] Introduce `NewCallableReferenceResolvedCall` and commonize other logic under `NewAbstractResolvedCall` --- .../binding/CodegenAnnotatingVisitor.java | 11 +- .../kotlin/diagnostics/diagnosticUtils.kt | 1 - .../inference/BuilderInferenceSession.kt | 6 +- .../OverloadResolutionResultsUtil.java | 10 +- .../tower/KotlinToResolvedCallTransformer.kt | 77 +++--- .../calls/tower/ManyCandidatesResolver.kt | 2 +- .../calls/tower/NewAbstractResolvedCall.kt | 18 +- .../tower/NewCallableReferenceResolvedCall.kt | 257 ++++++++++++++++++ .../calls/tower/NewResolvedCallImpl.kt | 17 +- .../NewVariableAsFunctionResolvedCallImpl.kt | 28 +- 10 files changed, 362 insertions(+), 65 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallableReferenceResolvedCall.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index 7e697f9e420..97e40739c7c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.util.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.*; +import org.jetbrains.kotlin.resolve.calls.tower.NewAbstractResolvedCall; import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl; import org.jetbrains.kotlin.resolve.calls.tower.NewVariableAsFunctionResolvedCallImpl; import org.jetbrains.kotlin.resolve.constants.ConstantValue; @@ -776,21 +777,21 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { } private void recordSamValuesForNewInference(@NotNull ResolvedCall call) { - NewResolvedCallImpl newResolvedCall = getNewResolvedCallForCallWithPossibleSamConversions(call); - if (newResolvedCall == null) return; + NewAbstractResolvedCall newResolvedCall = getNewResolvedCallForCallWithPossibleSamConversions(call); + if (!(newResolvedCall instanceof NewResolvedCallImpl)) return; Map arguments = newResolvedCall.getValueArguments(); for (ValueParameterDescriptor valueParameter : arguments.keySet()) { ResolvedValueArgument argument = arguments.get(valueParameter); if (argument instanceof ExpressionValueArgument) { ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument(); - if (valueArgument != null && newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) != null) { + if (valueArgument != null && ((NewResolvedCallImpl)newResolvedCall).getExpectedTypeForSamConvertedArgument(valueArgument) != null) { recordSamTypeOnArgumentExpression(valueParameter, valueArgument); } } else if (argument instanceof VarargValueArgument) { VarargValueArgument varargValueArgument = (VarargValueArgument) argument; for (ValueArgument valueArgument : varargValueArgument.getArguments()) { - if (valueArgument != null && newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) != null) { + if (valueArgument != null && ((NewResolvedCallImpl)newResolvedCall).getExpectedTypeForSamConvertedArgument(valueArgument) != null) { recordSamTypeOnArgumentExpression(valueParameter, valueArgument); } } @@ -799,7 +800,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { } @Nullable - private static NewResolvedCallImpl getNewResolvedCallForCallWithPossibleSamConversions(@NotNull ResolvedCall call) { + private static NewAbstractResolvedCall getNewResolvedCallForCallWithPossibleSamConversions(@NotNull ResolvedCall call) { if (call instanceof NewVariableAsFunctionResolvedCallImpl) { return ((NewVariableAsFunctionResolvedCallImpl) call).getFunctionCall(); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt index 6229bc33ded..e6a86f1ef40 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt @@ -35,7 +35,6 @@ import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.inference.isCaptured import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeConstructorSubstitution diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt index dfab56a5f2e..cd2fc988f58 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt @@ -447,11 +447,11 @@ class BuilderInferenceSession( return commonSystem.notFixedTypeVariables.all { it.value.constraints.isEmpty() } } - private fun reportErrors(completedCall: CallInfo, resolvedCall: ResolvedCall<*>, errors: List) { + private fun reportErrors(completedCall: CallInfo, resolvedCall: NewAbstractResolvedCall<*>, errors: List) { kotlinToResolvedCallTransformer.reportCallDiagnostic( completedCall.context, trace, - completedCall.callResolutionResult.resultCallAtom, + resolvedCall, resolvedCall.resultingDescriptor, errors.asDiagnostics() ) @@ -528,7 +528,7 @@ class BuilderInferenceSession( private fun completeCall( callInfo: CallInfo, atomCompleter: ResolvedAtomCompleter - ): ResolvedCall<*>? { + ): NewAbstractResolvedCall<*>? { val resultCallAtom = callInfo.callResolutionResult.resultCallAtom resultCallAtom.subResolvedAtoms?.forEach { subResolvedAtom -> atomCompleter.completeAll(subResolvedAtom) 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 2f4dbd20523..db11c26d0bf 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,9 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.tower.KotlinToResolvedCallTransformerKt; -import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl; -import org.jetbrains.kotlin.resolve.calls.tower.NewVariableAsFunctionResolvedCallImpl; +import org.jetbrains.kotlin.resolve.calls.tower.*; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.resolve.calls.util.ResolvedCallUtilKt; @@ -58,12 +56,12 @@ public class OverloadResolutionResultsUtil { ) { if (results.isSingleResult() && context.contextDependency == ContextDependency.INDEPENDENT) { ResolvedCall resultingCall = results.getResultingCall(); - NewResolvedCallImpl newResolvedCall; + NewAbstractResolvedCall newResolvedCall; if (resultingCall instanceof NewVariableAsFunctionResolvedCallImpl) { newResolvedCall = ((NewVariableAsFunctionResolvedCallImpl) resultingCall).getFunctionCall(); } - else if (resultingCall instanceof NewResolvedCallImpl) { - newResolvedCall = (NewResolvedCallImpl) resultingCall; + else if (resultingCall instanceof NewAbstractResolvedCall) { + newResolvedCall = (NewAbstractResolvedCall) resultingCall; } else { newResolvedCall = null; } 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 636837cf17f..f4ee5b87faf 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 @@ -101,13 +101,13 @@ class KotlinToResolvedCallTransformer( fun onlyTransform( resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection, - ): ResolvedCall = transformToResolvedCall(resolvedCallAtom, null, null, diagnostics) + ): NewAbstractResolvedCall = transformToResolvedCall(resolvedCallAtom, null, null, diagnostics) fun transformAndReport( baseResolvedCall: CallResolutionResult, context: BasicCallResolutionContext, tracingStrategy: TracingStrategy, - ): ResolvedCall { + ): NewAbstractResolvedCall { return when (baseResolvedCall) { is PartialCallResolutionResult -> { val candidate = baseResolvedCall.resultCallAtom @@ -123,7 +123,7 @@ class KotlinToResolvedCallTransformer( ) } - createStubResolvedCallAndWriteItToTrace(candidate, context.trace, baseResolvedCall.diagnostics, substitutor = null) + createStubResolvedCallAndWriteItToTrace(candidate, context.trace, baseResolvedCall.diagnostics, substitutor = null) } is CompletedCallResolutionResult, is ErrorCallResolutionResult -> { @@ -141,7 +141,7 @@ class KotlinToResolvedCallTransformer( forwardCallToInferenceSession(baseResolvedCall, context, stub, tracingStrategy) @Suppress("UNCHECKED_CAST") - return stub as ResolvedCall + return stub as NewAbstractResolvedCall } val ktPrimitiveCompleter = ResolvedAtomCompleter( @@ -159,7 +159,7 @@ class KotlinToResolvedCallTransformer( @Suppress("UNCHECKED_CAST") val resolvedCall = ktPrimitiveCompleter.completeResolvedCall( candidate, baseResolvedCall.completedDiagnostic(resultSubstitutor), - ) as ResolvedCall + ) as NewAbstractResolvedCall forwardCallToInferenceSession(baseResolvedCall, context, resolvedCall, tracingStrategy) @@ -174,7 +174,7 @@ class KotlinToResolvedCallTransformer( private fun forwardCallToInferenceSession( baseResolvedCall: CallResolutionResult, context: BasicCallResolutionContext, - resolvedCall: ResolvedCall<*>, + resolvedCall: NewAbstractResolvedCall<*>, tracingStrategy: TracingStrategy, ) { if (baseResolvedCall is CompletedCallResolutionResult) { @@ -187,7 +187,7 @@ class KotlinToResolvedCallTransformer( trace: BindingTrace, diagnostics: Collection, substitutor: NewTypeSubstitutor?, - ): ResolvedCall { + ): NewAbstractResolvedCall { val result = transformToResolvedCall(candidate, trace, substitutor, diagnostics) val psiKotlinCall = candidate.atom.psiKotlinCall val tracing = psiKotlinCall.safeAs()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy @@ -202,7 +202,7 @@ class KotlinToResolvedCallTransformer( trace: BindingTrace?, resultSubstitutor: NewTypeSubstitutor? = null, // if substitutor is not null, it means that this call is completed diagnostics: Collection, - ): ResolvedCall { + ): NewAbstractResolvedCall { val psiKotlinCall = completedCallAtom.atom.psiKotlinCall return if (psiKotlinCall is PSIKotlinCallForInvoke) { val diagnosticsForVariableCall = if (completedCallAtom.candidateDescriptor is FunctionDescriptor) emptyList() else diagnostics @@ -211,7 +211,7 @@ class KotlinToResolvedCallTransformer( NewVariableAsFunctionResolvedCallImpl( createOrGet(psiKotlinCall.variableCall.resolvedCall, trace, resultSubstitutor, diagnosticsForVariableCall), createOrGet(completedCallAtom, trace, resultSubstitutor, diagnosticsForFunctionCall), - ) as ResolvedCall + ) as NewAbstractResolvedCall } else { createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics) } @@ -222,7 +222,7 @@ class KotlinToResolvedCallTransformer( trace: BindingTrace?, resultSubstitutor: NewTypeSubstitutor?, diagnostics: Collection, - ): NewResolvedCallImpl { + ): NewAbstractResolvedCall { if (trace != null) { val storedResolvedCall = completedSimpleAtom.atom.psiKotlinCall.getResolvedPsiKotlinCall(trace) if (storedResolvedCall != null) { @@ -231,13 +231,16 @@ class KotlinToResolvedCallTransformer( return storedResolvedCall } } - return NewResolvedCallImpl( - completedSimpleAtom, - resultSubstitutor, - diagnostics, - typeApproximator, - expressionTypingServices.languageVersionSettings - ) + + return if (completedSimpleAtom.atom.callKind == KotlinCallKind.CALLABLE_REFERENCE) { + NewCallableReferenceResolvedCall( + completedSimpleAtom as ResolvedCallableReferenceCallAtom, typeApproximator, resultSubstitutor + ) + } else { + NewResolvedCallImpl( + completedSimpleAtom, resultSubstitutor, diagnostics, typeApproximator, expressionTypingServices.languageVersionSettings + ) + } } fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) { @@ -289,7 +292,9 @@ class KotlinToResolvedCallTransformer( } // todo very beginning code - fun runArgumentsChecks(context: BasicCallResolutionContext, resolvedCall: NewResolvedCallImpl<*>) { + fun runArgumentsChecks(context: BasicCallResolutionContext, resolvedCall: NewAbstractResolvedCall<*>) { + if (resolvedCall !is NewResolvedCallImpl<*>) return + for (valueArgument in resolvedCall.call.valueArguments) { val argumentMapping = resolvedCall.getArgumentMapping(valueArgument!!) val parameter: ValueParameterDescriptor? @@ -404,7 +409,7 @@ class KotlinToResolvedCallTransformer( if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) null else - expression.getResolvedCall(context.trace.bindingContext) + expression.getResolvedCall(context.trace.bindingContext) as? NewAbstractResolvedCall<*> // See CallCompleter#updateRecordedTypeForArgument private fun updateRecordedTypeForArgument( @@ -461,32 +466,35 @@ class KotlinToResolvedCallTransformer( } internal fun bind(trace: BindingTrace, resolvedCall: ResolvedCall<*>) { - resolvedCall.safeAs>()?.let { bind(trace, it) } + resolvedCall.safeAs>()?.let { bind(trace, it) } resolvedCall.safeAs()?.let { bind(trace, it) } } fun reportDiagnostics( context: BasicCallResolutionContext, trace: BindingTrace, - resolvedCall: ResolvedCall<*>, + resolvedCall: NewAbstractResolvedCall<*>, diagnostics: Collection, ) { when (resolvedCall) { - is NewResolvedCallImpl -> - reportCallDiagnostic(context, trace, resolvedCall.resolvedCallAtom, resolvedCall.resultingDescriptor, diagnostics) - is NewVariableAsFunctionResolvedCallImpl -> { val variableCall = resolvedCall.variableCall val functionCall = resolvedCall.functionCall - reportCallDiagnostic(context, trace, variableCall.resolvedCallAtom, variableCall.resultingDescriptor, diagnostics) - reportCallDiagnostic(context, trace, functionCall.resolvedCallAtom, functionCall.resultingDescriptor, emptyList()) + reportCallDiagnostic(context, trace, variableCall, variableCall.resultingDescriptor, diagnostics) + reportCallDiagnostic(context, trace, functionCall, functionCall.resultingDescriptor, emptyList()) + } + else -> { + val resolvedCallAtom = resolvedCall.resolvedCallAtom + if (resolvedCallAtom != null) { + reportCallDiagnostic(context, trace, resolvedCall, resolvedCall.resultingDescriptor, diagnostics) + } } } } - private fun bind(trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) { - val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy + private fun bind(trace: BindingTrace, simpleResolvedCall: NewAbstractResolvedCall<*>) { + val tracing = simpleResolvedCall.psiKotlinCall.tracingStrategy tracing.bindReference(trace, simpleResolvedCall) tracing.bindResolvedCall(trace, simpleResolvedCall) @@ -505,7 +513,7 @@ class KotlinToResolvedCallTransformer( fun reportCallDiagnostic( context: BasicCallResolutionContext, trace: BindingTrace, - completedCallAtom: ResolvedCallAtom, + resolvedCall: NewAbstractResolvedCall<*>, resultingDescriptor: CallableDescriptor, diagnostics: Collection, ) { @@ -513,14 +521,18 @@ class KotlinToResolvedCallTransformer( val newContext = context.replaceBindingTrace(trackingTrace) val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() - additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics) + val resolvedCallAtom = resolvedCall.resolvedCallAtom + + if (resolvedCallAtom != null) { + additionalDiagnosticReporter.reportAdditionalDiagnostics(resolvedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics) + } val allDiagnostics = diagnostics + diagnosticHolder.getDiagnostics() val diagnosticReporter = DiagnosticReporterByTrackingStrategy( constantExpressionEvaluator, newContext, - completedCallAtom.atom.psiKotlinCall, + resolvedCall.psiKotlinCall, context.dataFlowValueFactory, allDiagnostics, smartCastManager, @@ -533,8 +545,7 @@ class KotlinToResolvedCallTransformer( if (diagnostic is ResolvedUsingDeprecatedVisibility) { reportResolvedUsingDeprecatedVisibility( - completedCallAtom.atom.psiKotlinCall.psiCall, completedCallAtom.candidateDescriptor, - resultingDescriptor, diagnostic, trace, + resolvedCall.psiKotlinCall.psiCall, resolvedCall.candidateDescriptor, resultingDescriptor, diagnostic, trace, ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt index dd91baac8ec..7e5ffd0897d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt @@ -202,7 +202,7 @@ class PSIPartialCallInfo( class PSICompletedCallInfo( override val callResolutionResult: CompletedCallResolutionResult, context: BasicCallResolutionContext, - val resolvedCall: ResolvedCall<*>, + val resolvedCall: NewAbstractResolvedCall<*>, tracingStrategy: TracingStrategy ) : CallInfo(callResolutionResult, context, tracingStrategy), CompletedCallInfo diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewAbstractResolvedCall.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewAbstractResolvedCall.kt index d1f92686734..a7498af50ec 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewAbstractResolvedCall.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewAbstractResolvedCall.kt @@ -18,10 +18,13 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addToStdlib.compactIfPossible -sealed class NewAbstractResolvedCall() : ResolvedCall { +sealed class NewAbstractResolvedCall : ResolvedCall { abstract val argumentMappingByOriginal: Map abstract val kotlinCall: KotlinCall - protected abstract val languageVersionSettings: LanguageVersionSettings + abstract val languageVersionSettings: LanguageVersionSettings + abstract val resolvedCallAtom: ResolvedCallAtom? + abstract val psiKotlinCall: PSIKotlinCall + abstract val isCompleted: Boolean protected var argumentToParameterMap: Map? = null protected var _valueArguments: Map? = null @@ -39,9 +42,15 @@ sealed class NewAbstractResolvedCall() : ResolvedCall return _valueArguments!! } + fun setValueArguments(m: Map) { + _valueArguments = m + } + + open fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) {} + override fun getValueArgumentsByIndex(): List? { val arguments = ArrayList(candidateDescriptor.valueParameters.size) - for (i in 0..candidateDescriptor.valueParameters.size - 1) { + for (i in 0 until candidateDescriptor.valueParameters.size) { arguments.add(null) } @@ -86,7 +95,7 @@ sealed class NewAbstractResolvedCall() : ResolvedCall nonTrivialUpdatedResultInfo = dataFlowInfo.and(kotlinCall.psiKotlinCall.resultDataFlowInfo) } - protected abstract fun argumentToParameterMap( + abstract fun argumentToParameterMap( resultingDescriptor: CallableDescriptor, valueArguments: Map, ): Map @@ -130,5 +139,4 @@ sealed class NewAbstractResolvedCall() : ResolvedCall } } }.compactIfPossible() - } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallableReferenceResolvedCall.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallableReferenceResolvedCall.kt new file mode 100644 index 00000000000..1fdf4f494f3 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallableReferenceResolvedCall.kt @@ -0,0 +1,257 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor +import org.jetbrains.kotlin.psi.ValueArgument +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.components.NewTypeSubstitutorByConstructorMap +import org.jetbrains.kotlin.resolve.calls.inference.substitute +import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateTypes +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.util.isNotSimpleCall +import org.jetbrains.kotlin.resolve.calls.util.toResolutionStatus +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable +import org.jetbrains.kotlin.types.typeUtil.makeNullable + +class NewCallableReferenceResolvedCall( + val resolvedAtom: ResolvedCallableReferenceAtom, + val typeApproximator: TypeApproximator, + substitutor: NewTypeSubstitutor?, +) : NewAbstractResolvedCall() { + override var isCompleted = false + private set + + override val resolvedCallAtom: MutableResolvedCallAtom? = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate?.resolvedCall + } + + override val psiKotlinCall: PSIKotlinCall = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.atom.psiKotlinCall + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.atom.call.psiKotlinCall + } + + init { + setResultingSubstitutor(substitutor) + } + + var diagnostics: Collection = mutableListOf() + private lateinit var resultingDescriptor: D + + override fun getStatus(): ResolutionStatus { + return getResultApplicability(diagnostics).toResolutionStatus() + } + + override fun getCandidateDescriptor(): D = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.candidateDescriptor as D + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate?.candidate as D + } + + override fun getResultingDescriptor(): D = resultingDescriptor + + private var extensionReceiver = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.extensionReceiverArgument?.receiverValue + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate?.extensionReceiver?.receiver?.receiverValue + } + + private var dispatchReceiver = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.dispatchReceiverArgument?.receiverValue + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate?.dispatchReceiver?.receiver?.receiverValue + } + + override fun getExtensionReceiver(): ReceiverValue? = extensionReceiver + + override fun getDispatchReceiver(): ReceiverValue? = dispatchReceiver + + override fun getExplicitReceiverKind(): ExplicitReceiverKind = when (resolvedAtom) { + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate!!.explicitReceiverKind + is ResolvedCallableReferenceCallAtom -> resolvedAtom.explicitReceiverKind + } + + override fun getValueArguments(): Map = _valueArguments ?: emptyMap() + + override fun getValueArgumentsByIndex(): List? { + val arguments = ArrayList(candidateDescriptor.valueParameters.size) + for (i in 0 until candidateDescriptor.valueParameters.size) { + arguments.add(null) + } + + for ((parameterDescriptor, value) in valueArguments) { + val oldValue = arguments.set(parameterDescriptor.index, value) + if (oldValue != null) { + return null + } + } + + if (arguments.any { it == null }) return null + + @Suppress("UNCHECKED_CAST") + return arguments as List + } + + override fun getArgumentMapping(valueArgument: ValueArgument): ArgumentMapping = ArgumentUnmapped + + override fun getTypeArguments(): Map { + val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap() + return typeParameters.zip(typeArguments).toMap() + } + + private lateinit var typeArguments: List + + override fun getDataFlowInfoForArguments(): DataFlowInfoForArguments = + MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY) + + override fun getSmartCastDispatchReceiverType(): KotlinType? = null + + + private fun updateDispatchReceiverType(newType: KotlinType) { + if (dispatchReceiver?.type == newType) return + dispatchReceiver = dispatchReceiver?.replaceType(newType) + } + + private fun updateExtensionReceiverType(newType: KotlinType) { + if (extensionReceiver?.type == newType) return + extensionReceiver = extensionReceiver?.replaceType(newType) + } + + override fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) { + //clear cached values + if (substitutor != null) { + isCompleted = true + dispatchReceiver?.type?.let { + val newType = substitutor.safeSubstitute(it.unwrap()) + updateDispatchReceiverType(newType) + } + + extensionReceiver?.type?.let { + val newType = substitutor.safeSubstitute(it.unwrap()) + updateExtensionReceiverType(newType) + } + } + + @Suppress("UNCHECKED_CAST") + resultingDescriptor = substitutedResultingDescriptor(substitutor) as D + + val sub = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.freshVariablesSubstitutor + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate!!.freshVariablesSubstitutor!! + } + + typeArguments = sub.freshVariables.map { + val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType) + typeApproximator + .approximateToSuperType(substituted, TypeApproximatorConfiguration.IntegerLiteralsTypesApproximation) + ?: substituted + } + } + + private fun getSubstitutorWithoutFlexibleTypes( + currentSubstitutor: NewTypeSubstitutor?, + explicitTypeArguments: List, + ): NewTypeSubstitutor? { + if (currentSubstitutor !is NewTypeSubstitutorByConstructorMap || explicitTypeArguments.isEmpty()) return currentSubstitutor + if (!currentSubstitutor.map.any { (_, value) -> value.isFlexible() }) return currentSubstitutor + + val sub = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.freshVariablesSubstitutor + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate!!.freshVariablesSubstitutor!! + } + + val typeVariables = sub.freshVariables + val newSubstitutorMap = currentSubstitutor.map.toMutableMap() + + explicitTypeArguments.forEachIndexed { index, typeArgument -> + val typeVariableConstructor = typeVariables.getOrNull(index)?.freshTypeConstructor ?: return@forEachIndexed + + newSubstitutorMap[typeVariableConstructor] = + newSubstitutorMap[typeVariableConstructor]?.withNullabilityFromExplicitTypeArgument(typeArgument) + ?: return@forEachIndexed + } + + return NewTypeSubstitutorByConstructorMap(newSubstitutorMap) + } + + private fun KotlinType.withNullabilityFromExplicitTypeArgument(typeArgument: SimpleTypeArgument) = + (if (typeArgument.type.isMarkedNullable) makeNullable() else makeNotNullable()).unwrap() + + private fun substitutedResultingDescriptor(substitutor: NewTypeSubstitutor?): CallableDescriptor { + val candidateDescriptor = when (resolvedAtom) { + is ResolvedCallableReferenceCallAtom -> resolvedAtom.candidateDescriptor + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate!!.candidate + } + + return when (candidateDescriptor) { + is ClassConstructorDescriptor, is SyntheticMemberDescriptor<*> -> { + val explicitTypeArguments = emptyList() + + candidateDescriptor.substituteInferredVariablesAndApproximate( + getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments), + ) + } + is FunctionDescriptor -> { + candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor, candidateDescriptor.isNotSimpleCall()) + } + is PropertyDescriptor -> { + if (candidateDescriptor.isNotSimpleCall()) { + candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor) + } else { + candidateDescriptor + } + } + else -> candidateDescriptor + } + } + + private fun CallableDescriptor.substituteInferredVariablesAndApproximate( + substitutor: NewTypeSubstitutor?, + shouldApproximate: Boolean = true + ): CallableDescriptor { + val sub = when (resolvedAtom) { + is ResolvedCallableReferenceArgumentAtom -> resolvedAtom.candidate!!.freshVariablesSubstitutor!! + is ResolvedCallableReferenceCallAtom -> resolvedAtom.freshVariablesSubstitutor + } + + val inferredTypeVariablesSubstitutor = substitutor ?: FreshVariableNewTypeSubstitutor.Empty + + return substitute(sub).substituteAndApproximateTypes( + inferredTypeVariablesSubstitutor, + typeApproximator = if (shouldApproximate) typeApproximator else null, + positionDependentApproximation = true + ) + } + + override val argumentMappingByOriginal: Map + get() = TODO("Not yet implemented") + + override val kotlinCall: KotlinCall + get() = when (resolvedAtom) { + is ResolvedCallableReferenceArgumentAtom -> + (resolvedAtom.candidate?.kotlinCall as CallableReferenceKotlinCallArgument).call + is ResolvedCallableReferenceCallAtom -> resolvedAtom.atom + } + override val languageVersionSettings: LanguageVersionSettings + get() = TODO("Not yet implemented") + + override fun containsOnlyOnlyInputTypesErrors(): Boolean { + TODO("Not yet implemented") + } + + override fun argumentToParameterMap( + resultingDescriptor: CallableDescriptor, + valueArguments: Map + ): Map { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolvedCallImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolvedCallImpl.kt index 0c34acfcda1..7bb521c05d2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolvedCallImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolvedCallImpl.kt @@ -30,15 +30,16 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.utils.addToStdlib.safeAs - class NewResolvedCallImpl( - val resolvedCallAtom: ResolvedCallAtom, + override val resolvedCallAtom: ResolvedCallAtom, substitutor: NewTypeSubstitutor?, private var diagnostics: Collection, private val typeApproximator: TypeApproximator, override val languageVersionSettings: LanguageVersionSettings, ) : NewAbstractResolvedCall() { - var isCompleted = false + override val psiKotlinCall: PSIKotlinCall = resolvedCallAtom.atom.psiKotlinCall + + override var isCompleted = false private set private lateinit var resultingDescriptor: D @@ -104,7 +105,7 @@ class NewResolvedCallImpl( dispatchReceiver = dispatchReceiver?.replaceType(newType) } - fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) { + override fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) { //clear cached values argumentToParameterMap = null _valueArguments = null @@ -192,8 +193,12 @@ class NewResolvedCallImpl( val inferredTypeVariablesSubstitutor = substitutor ?: FreshVariableNewTypeSubstitutor.Empty // TODO: merge last two substitutors to avoid redundant descriptor substitutions - return substitute(resolvedCallAtom.freshVariablesSubstitutor).substitute(resolvedCallAtom.knownParametersSubstitutor) - .substituteAndApproximateTypes(inferredTypeVariablesSubstitutor, if (shouldApproximate) typeApproximator else null) + return substitute(resolvedCallAtom.freshVariablesSubstitutor) + .substitute(resolvedCallAtom.knownParametersSubstitutor) + .substituteAndApproximateTypes( + inferredTypeVariablesSubstitutor, + typeApproximator.takeIf { shouldApproximate } + ) } fun getArgumentTypeForConstantConvertedArgument(valueArgument: ValueArgument): IntegerValueTypeConstant? { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewVariableAsFunctionResolvedCallImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewVariableAsFunctionResolvedCallImpl.kt index 9c7ba38807d..3b5bbd88df8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewVariableAsFunctionResolvedCallImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewVariableAsFunctionResolvedCallImpl.kt @@ -9,14 +9,32 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.utils.addToStdlib.cast class NewVariableAsFunctionResolvedCallImpl( - override val variableCall: NewResolvedCallImpl, - override val functionCall: NewResolvedCallImpl, -) : VariableAsFunctionResolvedCall, ResolvedCall by functionCall { - val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast().baseCall + override val variableCall: NewAbstractResolvedCall, + override val functionCall: NewAbstractResolvedCall, +) : VariableAsFunctionResolvedCall, NewAbstractResolvedCall() { + override val resolvedCallAtom = functionCall.resolvedCallAtom + override val psiKotlinCall: PSIKotlinCall = functionCall.psiKotlinCall + val baseCall get() = functionCall.psiKotlinCall.cast().baseCall + override fun getStatus() = functionCall.status + override fun getCandidateDescriptor() = functionCall.candidateDescriptor + override fun getResultingDescriptor() = functionCall.resultingDescriptor + override fun getExtensionReceiver() = functionCall.extensionReceiver + override fun getDispatchReceiver() = functionCall.dispatchReceiver + override fun getExplicitReceiverKind() = functionCall.explicitReceiverKind + override fun getTypeArguments() = functionCall.typeArguments + override fun getSmartCastDispatchReceiverType() = functionCall.smartCastDispatchReceiverType + override val argumentMappingByOriginal = functionCall.argumentMappingByOriginal + override val kotlinCall = functionCall.kotlinCall + override val languageVersionSettings = functionCall.languageVersionSettings + override fun containsOnlyOnlyInputTypesErrors() = functionCall.containsOnlyOnlyInputTypesErrors() + override fun argumentToParameterMap( + resultingDescriptor: CallableDescriptor, + valueArguments: Map + ) = functionCall.argumentToParameterMap(resultingDescriptor, valueArguments) + override val isCompleted: Boolean = functionCall.isCompleted } \ No newline at end of file