From b7c894a6d3ca0aec749ebd2924dd1ecc72005fec Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Tue, 6 Jun 2017 15:43:49 +0300 Subject: [PATCH] [NI] Capture types from smart-cast types. Sometimes we have something like if (a is Foo<*>) a.bar() where bar declared: fun Foo.bar(). For such case we should create receiver with possible types Capture(*). --- .../kotlin/resolve/calls/tower/NewCallArguments.kt | 8 ++------ .../kotlin/resolve/calls/model/ArgumentsImpl.kt | 11 ++--------- .../resolve/scopes/receivers/QualifierReceiver.kt | 11 +++++++++++ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt index 01be6dfda76..7823fa0d993 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt @@ -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) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt index 927d4e91a80..3316cce9804 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt @@ -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) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/receivers/QualifierReceiver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/receivers/QualifierReceiver.kt index 595bb67abac..5fee630579a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/receivers/QualifierReceiver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/receivers/QualifierReceiver.kt @@ -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()) { prepareArgumentTypeRegardingCaptureTypes(it.unwrap()) ?: it } + val newReceiver = if (preparedBaseType != null) receiverValue.replaceType(preparedBaseType) else receiverValue + + return ReceiverValueWithSmartCastInfo(newReceiver, newPossibleTypes, isStable) } \ No newline at end of file