[NI] Capture types from smart-cast types.

Sometimes we have something like if (a is Foo<*>) a.bar()
where bar declared: fun <T> Foo<T>.bar().
For such case we should create receiver with possible types Capture(*).
This commit is contained in:
Stanislav Erokhin
2017-06-06 15:43:49 +03:00
committed by Mikhail Zarechenskiy
parent b6bb171b67
commit b7c894a6d3
3 changed files with 15 additions and 15 deletions
@@ -26,13 +26,12 @@ import org.jetbrains.kotlin.resolve.StatementFilter
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.prepareReceiverRegardingCaptureTypes
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
class SimpleTypeArgumentImpl(
@@ -172,16 +171,13 @@ internal fun createSimplePSICallArgument(
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
}
val baseType = onlyResolvedCall?.currentReturnType ?: typeInfoForArgument.type?.unwrap() ?: return null
val preparedType = prepareArgumentTypeRegardingCaptureTypes(baseType) ?: baseType
// we should use DFI after this argument, because there can be some useful smartcast. Popular case: if branches.
val receiverToCast = transformToReceiverWithSmartCastInfo(
ownerDescriptor, bindingContext,
typeInfoForArgument.dataFlowInfo,
ExpressionReceiver.create(ktExpression, baseType, bindingContext)
).let {
ReceiverValueWithSmartCastInfo(it.receiverValue.replaceType(preparedType), it.possibleTypes, it.isStable)
}
).prepareReceiverRegardingCaptureTypes()
return if (onlyResolvedCall == null) {
ExpressionKotlinCallArgumentImpl(valueArgument, dataFlowInfoBeforeThisArgument, typeInfoForArgument.dataFlowInfo, receiverToCast)
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes
import org.jetbrains.kotlin.resolve.scopes.receivers.prepareReceiverRegardingCaptureTypes
class FakeKotlinCallArgumentForCallableReference(
@@ -45,14 +45,7 @@ class ReceiverExpressionKotlinCallArgument private constructor(
receiver: ReceiverValueWithSmartCastInfo,
isSafeCall: Boolean = false,
isVariableReceiverForInvoke: Boolean = false
): ReceiverExpressionKotlinCallArgument {
val newType = prepareArgumentTypeRegardingCaptureTypes(receiver.receiverValue.type.unwrap())
val newReceiver = if (newType != null) {
ReceiverValueWithSmartCastInfo(receiver.receiverValue.replaceType(newType), receiver.possibleTypes, receiver.isStable)
} else receiver
return ReceiverExpressionKotlinCallArgument(newReceiver, isSafeCall, isVariableReceiverForInvoke)
}
) = ReceiverExpressionKotlinCallArgument(receiver.prepareReceiverRegardingCaptureTypes(), isSafeCall, isVariableReceiverForInvoke)
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.scopes.receivers
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes
// this receiver used only for resolution. see subtypes
interface DetailedReceiver
@@ -41,4 +42,14 @@ interface QualifierReceiver : Receiver, DetailedReceiver {
// for qualifiers smart cast is impossible
val classValueReceiverWithSmartCastInfo: ReceiverValueWithSmartCastInfo?
get() = classValueReceiver?.let { ReceiverValueWithSmartCastInfo(it, emptySet(), true) }
}
fun ReceiverValueWithSmartCastInfo.prepareReceiverRegardingCaptureTypes(): ReceiverValueWithSmartCastInfo {
val preparedBaseType = prepareArgumentTypeRegardingCaptureTypes(receiverValue.type.unwrap())
if (preparedBaseType == null && possibleTypes.isEmpty()) return this
val newPossibleTypes = possibleTypes.mapTo(HashSet<KotlinType>()) { prepareArgumentTypeRegardingCaptureTypes(it.unwrap()) ?: it }
val newReceiver = if (preparedBaseType != null) receiverValue.replaceType(preparedBaseType) else receiverValue
return ReceiverValueWithSmartCastInfo(newReceiver, newPossibleTypes, isStable)
}