[NI] Don't check type for constants too early to avoid mismatch

This commit is contained in:
Mikhail Zarechenskiy
2017-12-06 20:38:58 +03:00
parent 6c27a49114
commit d47130eff8
8 changed files with 67 additions and 39 deletions
@@ -16,6 +16,9 @@
package org.jetbrains.kotlin.resolve.calls.tower
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isUnderKotlinPackage
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -26,15 +29,18 @@ import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.ReceiverKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
@@ -49,12 +55,13 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinResolutionCallbacksImpl(
val topLevelCallContext: BasicCallResolutionContext,
topLevelCallContext: BasicCallResolutionContext,
val expressionTypingServices: ExpressionTypingServices,
val typeApproximator: TypeApproximator,
val argumentTypeResolver: ArgumentTypeResolver,
val languageVersionSettings: LanguageVersionSettings,
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
val constantExpressionEvaluator: ConstantExpressionEvaluator
): KotlinResolutionCallbacks {
val trace: BindingTrace = topLevelCallContext.trace
@@ -160,4 +167,27 @@ class KotlinResolutionCallbacksImpl(
languageVersionSettings
)
}
override fun isCompileTimeConstant(resolvedAtom: ResolvedCallAtom, expectedType: UnwrappedType): Boolean {
val descriptor = resolvedAtom.candidateDescriptor
if (!isUnderKotlinPackage(descriptor)) return false
val returnType = descriptor.returnType ?: return false
if (!isPrimitiveTypeOrNullablePrimitiveType(returnType) || !isPrimitiveTypeOrNullablePrimitiveType(expectedType)) return false
val callElement = resolvedAtom.atom.psiKotlinCall.psiCall.callElement.safeAs<KtExpression>() ?: return false
val expression = findCommonParent(callElement, resolvedAtom.atom.psiKotlinCall.explicitReceiver)
val temporaryBindingTrace = TemporaryBindingTrace.create(
trace,
"Trace to check if some expression is constant, we have to avoid writing probably wrong COMPILE_TIME_VALUE slice"
)
return constantExpressionEvaluator.evaluateExpression(expression, temporaryBindingTrace, expectedType) != null
}
private fun findCommonParent(callElement: KtExpression, receiver: ReceiverKotlinCallArgument?): KtExpression {
if (receiver == null) return callElement
return PsiTreeUtil.findCommonParent(callElement, receiver.psiExpression)?.safeAs() ?: callElement
}
}
@@ -28,13 +28,11 @@ 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.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.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class SimpleTypeArgumentImpl(
val typeReference: KtTypeReference,
@@ -61,10 +59,11 @@ val KotlinCallArgument.psiCallArgument: PSIKotlinCallArgument get() {
}
val KotlinCallArgument.psiExpression: KtExpression? get() {
if (this is ReceiverExpressionKotlinCallArgument) {
return (receiver.receiverValue as? ExpressionReceiver)?.expression
return when (this) {
is ReceiverExpressionKotlinCallArgument -> receiver.receiverValue.safeAs<ExpressionReceiver>()?.expression
is QualifierReceiverKotlinCallArgument -> receiver.safeAs<Qualifier>()?.expression
else -> psiCallArgument.valueArgument.getArgumentExpression()
}
return psiCallArgument.valueArgument.getArgumentExpression()
}
class ParseErrorKotlinCallArgument(
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -69,7 +70,8 @@ class PSICallResolver(
private val kotlinCallResolver: KotlinCallResolver,
private val typeApproximator: TypeApproximator,
private val argumentTypeResolver: ArgumentTypeResolver,
private val effectSystem: EffectSystem
private val effectSystem: EffectSystem,
private val constantExpressionEvaluator: ConstantExpressionEvaluator
) {
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
@@ -151,7 +153,8 @@ class PSICallResolver(
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer)
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
constantExpressionEvaluator)
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
val expectedType = context.expectedType.unwrap()