[NI] Use same ResolvedCall when run completion
It is necessary, because some clients store this ResolvedCall to other places, for example for get call it stored to INDEXED_LVALUE_GET
This commit is contained in:
+74
-33
@@ -73,7 +73,7 @@ class KotlinToResolvedCallTransformer(
|
||||
|
||||
fun <D : CallableDescriptor> onlyTransform(
|
||||
resolvedCallAtom: ResolvedCallAtom
|
||||
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, completed = false)
|
||||
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, null)
|
||||
|
||||
fun <D : CallableDescriptor> transformAndReport(
|
||||
baseResolvedCall: CallResolutionResult,
|
||||
@@ -103,7 +103,7 @@ class KotlinToResolvedCallTransformer(
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall<D> {
|
||||
val result = onlyTransform<D>(candidate)
|
||||
val result = transformToResolvedCall<D>(candidate, trace)
|
||||
val psiKotlinCall = candidate.atom.psiKotlinCall
|
||||
val tracing = psiKotlinCall.safeAs<PSIKotlinCallForInvoke>()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy
|
||||
|
||||
@@ -114,22 +114,38 @@ class KotlinToResolvedCallTransformer(
|
||||
|
||||
fun <D : CallableDescriptor> transformToResolvedCall(
|
||||
completedCallAtom: ResolvedCallAtom,
|
||||
completed: Boolean,
|
||||
resultSubstitutor: NewTypeSubstitutor = FreshVariableNewTypeSubstitutor.Empty
|
||||
trace: BindingTrace?,
|
||||
resultSubstitutor: NewTypeSubstitutor? = null // if substitutor is not null, it means that this call is completed
|
||||
): ResolvedCall<D> {
|
||||
val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
|
||||
return if (psiKotlinCall is PSIKotlinCallForInvoke) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
NewVariableAsFunctionResolvedCallImpl(
|
||||
NewResolvedCallImpl(psiKotlinCall.variableCall.resolvedCall, completed, resultSubstitutor),
|
||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
||||
createOrGet(psiKotlinCall.variableCall.resolvedCall, trace, resultSubstitutor),
|
||||
createOrGet(completedCallAtom, trace, resultSubstitutor)
|
||||
) as ResolvedCall<D>
|
||||
}
|
||||
else {
|
||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
||||
createOrGet(completedCallAtom, trace, resultSubstitutor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> createOrGet(
|
||||
completedSimpleAtom: ResolvedCallAtom,
|
||||
trace: BindingTrace?,
|
||||
resultSubstitutor: NewTypeSubstitutor?
|
||||
): NewResolvedCallImpl<D> {
|
||||
if (trace != null) {
|
||||
val storedResolvedCall = completedSimpleAtom.atom.psiKotlinCall.psiCall.getResolvedCall(trace.bindingContext)?.
|
||||
safeAs<NewResolvedCallImpl<D>>()
|
||||
if (storedResolvedCall != null) {
|
||||
storedResolvedCall.setResultingSubstitutor(resultSubstitutor)
|
||||
return storedResolvedCall
|
||||
}
|
||||
}
|
||||
return NewResolvedCallImpl(completedSimpleAtom, resultSubstitutor)
|
||||
}
|
||||
|
||||
fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
|
||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||
resolvedCall.variableCall.call.calleeExpression
|
||||
@@ -329,12 +345,17 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
|
||||
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
abstract val kotlinCall: KotlinCall
|
||||
|
||||
private var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
|
||||
private val _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument> by lazy { createValueArguments() }
|
||||
protected var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
|
||||
protected var _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>? = null
|
||||
|
||||
override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall
|
||||
|
||||
override fun getValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> = _valueArguments
|
||||
override fun getValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> {
|
||||
if (_valueArguments == null) {
|
||||
_valueArguments = createValueArguments()
|
||||
}
|
||||
return _valueArguments!!
|
||||
}
|
||||
|
||||
override fun getValueArgumentsByIndex(): List<ResolvedValueArgument>? {
|
||||
val arguments = ArrayList<ResolvedValueArgument?>(candidateDescriptor.valueParameters.size)
|
||||
@@ -412,28 +433,13 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
|
||||
|
||||
class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||
val resolvedCallAtom: ResolvedCallAtom,
|
||||
val completed: Boolean,
|
||||
substitutor: NewTypeSubstitutor
|
||||
substitutor: NewTypeSubstitutor?
|
||||
): NewAbstractResolvedCall<D>() {
|
||||
private val resultingDescriptor = run {
|
||||
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
|
||||
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
|
||||
var isCompleted = false
|
||||
private set
|
||||
private lateinit var resultingDescriptor: D
|
||||
|
||||
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
|
||||
}
|
||||
private lateinit var typeArguments: List<UnwrappedType>
|
||||
|
||||
private var extensionReceiver = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
||||
private var smartCastDispatchReceiverType: KotlinType? = null
|
||||
@@ -446,7 +452,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||
get() = resolvedCallAtom.argumentMappingByOriginal
|
||||
|
||||
override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = resultingDescriptor as D
|
||||
override fun getResultingDescriptor(): D = resultingDescriptor
|
||||
override fun getExtensionReceiver(): ReceiverValue? = extensionReceiver
|
||||
override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
||||
@@ -470,6 +476,41 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||
fun setSmartCastDispatchReceiverType(smartCastDispatchReceiverType: KotlinType) {
|
||||
this.smartCastDispatchReceiverType = smartCastDispatchReceiverType
|
||||
}
|
||||
|
||||
fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) {
|
||||
//clear cached values
|
||||
argumentToParameterMap = null
|
||||
_valueArguments = null
|
||||
if (substitutor != null) {
|
||||
// todo: add asset that we do not complete call many times
|
||||
isCompleted = true
|
||||
}
|
||||
|
||||
resultingDescriptor = run {
|
||||
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
|
||||
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
|
||||
|
||||
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 ?: FreshVariableNewTypeSubstitutor.Empty)
|
||||
else ->
|
||||
candidateDescriptor
|
||||
}
|
||||
} as D
|
||||
|
||||
typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
|
||||
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
|
||||
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
setResultingSubstitutor(substitutor)
|
||||
}
|
||||
}
|
||||
|
||||
fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) {
|
||||
@@ -487,10 +528,10 @@ class NewVariableAsFunctionResolvedCallImpl(
|
||||
|
||||
fun ResolvedCall<*>.isNewNotCompleted(): Boolean {
|
||||
if (this is NewVariableAsFunctionResolvedCallImpl) {
|
||||
return !functionCall.completed
|
||||
return !functionCall.isCompleted
|
||||
}
|
||||
if (this is NewResolvedCallImpl<*>) {
|
||||
return !completed
|
||||
return !isCompleted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ class PSICallResolver(
|
||||
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
|
||||
val resolvedCalls = result.allCandidates?.map {
|
||||
val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor()
|
||||
kotlinToResolvedCallTransformer.transformToResolvedCall<D>(it.resolvedCall, false, resultingSubstitutor)
|
||||
kotlinToResolvedCallTransformer.transformToResolvedCall<D>(it.resolvedCall, null, resultingSubstitutor)
|
||||
}
|
||||
|
||||
return AllCandidates(resolvedCalls ?: emptyList())
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ class ResolvedAtomCompleter(
|
||||
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? {
|
||||
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
|
||||
|
||||
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(resolvedCallAtom, true, resultSubstitutor)
|
||||
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(resolvedCallAtom, trace, resultSubstitutor)
|
||||
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall)
|
||||
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
val targetNameLists: Map<String, String> = mapOf("1" to "OK")
|
||||
|
||||
fun <T> id(t: T) = t
|
||||
fun foo(argumentName: String?): String? = id(targetNameLists[argumentName])
|
||||
|
||||
fun box() = foo("1")
|
||||
+6
@@ -17078,6 +17078,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("resolvedCallForGetOperator.kt")
|
||||
public void testResolvedCallForGetOperator() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/resolvedCallForGetOperator.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("supertypeDepth.kt")
|
||||
public void testSupertypeDepth() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||
|
||||
@@ -17078,6 +17078,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("resolvedCallForGetOperator.kt")
|
||||
public void testResolvedCallForGetOperator() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/resolvedCallForGetOperator.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("supertypeDepth.kt")
|
||||
public void testSupertypeDepth() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||
|
||||
@@ -17078,6 +17078,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("resolvedCallForGetOperator.kt")
|
||||
public void testResolvedCallForGetOperator() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/resolvedCallForGetOperator.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("supertypeDepth.kt")
|
||||
public void testSupertypeDepth() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||
|
||||
@@ -20870,6 +20870,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("resolvedCallForGetOperator.kt")
|
||||
public void testResolvedCallForGetOperator() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/resolvedCallForGetOperator.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("supertypeDepth.kt")
|
||||
public void testSupertypeDepth() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||
|
||||
Reference in New Issue
Block a user