[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:
Stanislav Erokhin
2017-08-22 15:59:54 +03:00
parent 98eae4e7ee
commit 2ceb8cef36
8 changed files with 108 additions and 35 deletions
@@ -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())
@@ -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")
@@ -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");