[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(
|
fun <D : CallableDescriptor> onlyTransform(
|
||||||
resolvedCallAtom: ResolvedCallAtom
|
resolvedCallAtom: ResolvedCallAtom
|
||||||
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, completed = false)
|
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, null)
|
||||||
|
|
||||||
fun <D : CallableDescriptor> transformAndReport(
|
fun <D : CallableDescriptor> transformAndReport(
|
||||||
baseResolvedCall: CallResolutionResult,
|
baseResolvedCall: CallResolutionResult,
|
||||||
@@ -103,7 +103,7 @@ class KotlinToResolvedCallTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall<D> {
|
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 psiKotlinCall = candidate.atom.psiKotlinCall
|
||||||
val tracing = psiKotlinCall.safeAs<PSIKotlinCallForInvoke>()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy
|
val tracing = psiKotlinCall.safeAs<PSIKotlinCallForInvoke>()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy
|
||||||
|
|
||||||
@@ -114,22 +114,38 @@ class KotlinToResolvedCallTransformer(
|
|||||||
|
|
||||||
fun <D : CallableDescriptor> transformToResolvedCall(
|
fun <D : CallableDescriptor> transformToResolvedCall(
|
||||||
completedCallAtom: ResolvedCallAtom,
|
completedCallAtom: ResolvedCallAtom,
|
||||||
completed: Boolean,
|
trace: BindingTrace?,
|
||||||
resultSubstitutor: NewTypeSubstitutor = FreshVariableNewTypeSubstitutor.Empty
|
resultSubstitutor: NewTypeSubstitutor? = null // if substitutor is not null, it means that this call is completed
|
||||||
): ResolvedCall<D> {
|
): ResolvedCall<D> {
|
||||||
val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
|
val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
|
||||||
return if (psiKotlinCall is PSIKotlinCallForInvoke) {
|
return if (psiKotlinCall is PSIKotlinCallForInvoke) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
NewVariableAsFunctionResolvedCallImpl(
|
NewVariableAsFunctionResolvedCallImpl(
|
||||||
NewResolvedCallImpl(psiKotlinCall.variableCall.resolvedCall, completed, resultSubstitutor),
|
createOrGet(psiKotlinCall.variableCall.resolvedCall, trace, resultSubstitutor),
|
||||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
createOrGet(completedCallAtom, trace, resultSubstitutor)
|
||||||
) as ResolvedCall<D>
|
) as ResolvedCall<D>
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
|
||||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||||
resolvedCall.variableCall.call.calleeExpression
|
resolvedCall.variableCall.call.calleeExpression
|
||||||
@@ -329,12 +345,17 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
|
|||||||
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||||
abstract val kotlinCall: KotlinCall
|
abstract val kotlinCall: KotlinCall
|
||||||
|
|
||||||
private var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
|
protected var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
|
||||||
private val _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument> by lazy { createValueArguments() }
|
protected var _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>? = null
|
||||||
|
|
||||||
override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall
|
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>? {
|
override fun getValueArgumentsByIndex(): List<ResolvedValueArgument>? {
|
||||||
val arguments = ArrayList<ResolvedValueArgument?>(candidateDescriptor.valueParameters.size)
|
val arguments = ArrayList<ResolvedValueArgument?>(candidateDescriptor.valueParameters.size)
|
||||||
@@ -412,28 +433,13 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
|
|||||||
|
|
||||||
class NewResolvedCallImpl<D : CallableDescriptor>(
|
class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||||
val resolvedCallAtom: ResolvedCallAtom,
|
val resolvedCallAtom: ResolvedCallAtom,
|
||||||
val completed: Boolean,
|
substitutor: NewTypeSubstitutor?
|
||||||
substitutor: NewTypeSubstitutor
|
|
||||||
): NewAbstractResolvedCall<D>() {
|
): NewAbstractResolvedCall<D>() {
|
||||||
private val resultingDescriptor = run {
|
var isCompleted = false
|
||||||
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
|
private set
|
||||||
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
|
private lateinit var resultingDescriptor: D
|
||||||
|
|
||||||
when {
|
private lateinit var typeArguments: List<UnwrappedType>
|
||||||
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 var extensionReceiver = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
private var extensionReceiver = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
||||||
private var smartCastDispatchReceiverType: KotlinType? = null
|
private var smartCastDispatchReceiverType: KotlinType? = null
|
||||||
@@ -446,7 +452,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
|
|||||||
get() = resolvedCallAtom.argumentMappingByOriginal
|
get() = resolvedCallAtom.argumentMappingByOriginal
|
||||||
|
|
||||||
override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
|
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 getExtensionReceiver(): ReceiverValue? = extensionReceiver
|
||||||
override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
||||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
||||||
@@ -470,6 +476,41 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
|
|||||||
fun setSmartCastDispatchReceiverType(smartCastDispatchReceiverType: KotlinType) {
|
fun setSmartCastDispatchReceiverType(smartCastDispatchReceiverType: KotlinType) {
|
||||||
this.smartCastDispatchReceiverType = smartCastDispatchReceiverType
|
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) {
|
fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) {
|
||||||
@@ -487,10 +528,10 @@ class NewVariableAsFunctionResolvedCallImpl(
|
|||||||
|
|
||||||
fun ResolvedCall<*>.isNewNotCompleted(): Boolean {
|
fun ResolvedCall<*>.isNewNotCompleted(): Boolean {
|
||||||
if (this is NewVariableAsFunctionResolvedCallImpl) {
|
if (this is NewVariableAsFunctionResolvedCallImpl) {
|
||||||
return !functionCall.completed
|
return !functionCall.isCompleted
|
||||||
}
|
}
|
||||||
if (this is NewResolvedCallImpl<*>) {
|
if (this is NewResolvedCallImpl<*>) {
|
||||||
return !completed
|
return !isCompleted
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class PSICallResolver(
|
|||||||
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
|
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
|
||||||
val resolvedCalls = result.allCandidates?.map {
|
val resolvedCalls = result.allCandidates?.map {
|
||||||
val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor()
|
val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor()
|
||||||
kotlinToResolvedCallTransformer.transformToResolvedCall<D>(it.resolvedCall, false, resultingSubstitutor)
|
kotlinToResolvedCallTransformer.transformToResolvedCall<D>(it.resolvedCall, null, resultingSubstitutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return AllCandidates(resolvedCalls ?: emptyList())
|
return AllCandidates(resolvedCalls ?: emptyList())
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ class ResolvedAtomCompleter(
|
|||||||
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? {
|
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? {
|
||||||
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
|
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.bindAndReport(topLevelCallContext, trace, resolvedCall)
|
||||||
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
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);
|
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")
|
@TestMetadata("supertypeDepth.kt")
|
||||||
public void testSupertypeDepth() throws Exception {
|
public void testSupertypeDepth() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||||
|
|||||||
@@ -17078,6 +17078,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("supertypeDepth.kt")
|
||||||
public void testSupertypeDepth() throws Exception {
|
public void testSupertypeDepth() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||||
|
|||||||
@@ -17078,6 +17078,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("supertypeDepth.kt")
|
||||||
public void testSupertypeDepth() throws Exception {
|
public void testSupertypeDepth() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
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.");
|
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")
|
@TestMetadata("supertypeDepth.kt")
|
||||||
public void testSupertypeDepth() throws Exception {
|
public void testSupertypeDepth() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/supertypeDepth.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user