[NI] Don't check type for constants too early to avoid mismatch
This commit is contained in:
+32
-2
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.tower
|
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.builtins.createFunctionType
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
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.psi.psiUtil.lastBlockStatementOrThis
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
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.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
|
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.ResolvedCallAtom
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
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.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
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
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class KotlinResolutionCallbacksImpl(
|
class KotlinResolutionCallbacksImpl(
|
||||||
val topLevelCallContext: BasicCallResolutionContext,
|
topLevelCallContext: BasicCallResolutionContext,
|
||||||
val expressionTypingServices: ExpressionTypingServices,
|
val expressionTypingServices: ExpressionTypingServices,
|
||||||
val typeApproximator: TypeApproximator,
|
val typeApproximator: TypeApproximator,
|
||||||
val argumentTypeResolver: ArgumentTypeResolver,
|
val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
val languageVersionSettings: LanguageVersionSettings,
|
val languageVersionSettings: LanguageVersionSettings,
|
||||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
|
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||||
|
val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||||
): KotlinResolutionCallbacks {
|
): KotlinResolutionCallbacks {
|
||||||
val trace: BindingTrace = topLevelCallContext.trace
|
val trace: BindingTrace = topLevelCallContext.trace
|
||||||
|
|
||||||
@@ -160,4 +167,27 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
languageVersionSettings
|
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.context.BasicCallResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||||
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.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class SimpleTypeArgumentImpl(
|
class SimpleTypeArgumentImpl(
|
||||||
val typeReference: KtTypeReference,
|
val typeReference: KtTypeReference,
|
||||||
@@ -61,10 +59,11 @@ val KotlinCallArgument.psiCallArgument: PSIKotlinCallArgument get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val KotlinCallArgument.psiExpression: KtExpression? get() {
|
val KotlinCallArgument.psiExpression: KtExpression? get() {
|
||||||
if (this is ReceiverExpressionKotlinCallArgument) {
|
return when (this) {
|
||||||
return (receiver.receiverValue as? ExpressionReceiver)?.expression
|
is ReceiverExpressionKotlinCallArgument -> receiver.receiverValue.safeAs<ExpressionReceiver>()?.expression
|
||||||
|
is QualifierReceiverKotlinCallArgument -> receiver.safeAs<Qualifier>()?.expression
|
||||||
|
else -> psiCallArgument.valueArgument.getArgumentExpression()
|
||||||
}
|
}
|
||||||
return psiCallArgument.valueArgument.getArgumentExpression()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParseErrorKotlinCallArgument(
|
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.ResolutionCandidate
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
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.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
@@ -69,7 +70,8 @@ class PSICallResolver(
|
|||||||
private val kotlinCallResolver: KotlinCallResolver,
|
private val kotlinCallResolver: KotlinCallResolver,
|
||||||
private val typeApproximator: TypeApproximator,
|
private val typeApproximator: TypeApproximator,
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
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>")
|
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
|
||||||
|
|
||||||
@@ -151,7 +153,8 @@ class PSICallResolver(
|
|||||||
|
|
||||||
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
||||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
|
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
|
||||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer)
|
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
||||||
|
constantExpressionEvaluator)
|
||||||
|
|
||||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||||
val expectedType = context.expectedType.unwrap()
|
val expectedType = context.expectedType.unwrap()
|
||||||
|
|||||||
+2
@@ -48,4 +48,6 @@ interface KotlinResolutionCallbacks {
|
|||||||
fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom)
|
fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom)
|
||||||
|
|
||||||
fun createReceiverWithSmartCastInfo(resolvedAtom: ResolvedCallAtom): ReceiverValueWithSmartCastInfo?
|
fun createReceiverWithSmartCastInfo(resolvedAtom: ResolvedCallAtom): ReceiverValueWithSmartCastInfo?
|
||||||
|
|
||||||
|
fun isCompileTimeConstant(resolvedAtom: ResolvedCallAtom, expectedType: UnwrappedType): Boolean
|
||||||
}
|
}
|
||||||
+1
-1
@@ -141,7 +141,7 @@ class KotlinCallCompleter(
|
|||||||
val actualType = withSmartCastInfo?.stableType ?: unsubstitutedReturnType
|
val actualType = withSmartCastInfo?.stableType ?: unsubstitutedReturnType
|
||||||
|
|
||||||
val returnType = resolvedCall.substitutor.substituteKeepAnnotations(actualType)
|
val returnType = resolvedCall.substitutor.substituteKeepAnnotations(actualType)
|
||||||
if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) {
|
if (expectedType != null && !TypeUtils.noExpectedType(expectedType) && !resolutionCallbacks.isCompileTimeConstant(resolvedCall, expectedType)) {
|
||||||
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
|
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -1,10 +1,8 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
|
||||||
|
|
||||||
var x : Int = 1 + <!UNINITIALIZED_VARIABLE!>x<!>
|
var x : Int = 1 + <!UNINITIALIZED_VARIABLE!>x<!>
|
||||||
get() : Int = 1
|
get() : Int = 1
|
||||||
set(value : <!WRONG_SETTER_PARAMETER_TYPE!>Long<!>) {
|
set(value : <!WRONG_SETTER_PARAMETER_TYPE!>Long<!>) {
|
||||||
field = value.toInt()
|
field = value.toInt()
|
||||||
field = <!TYPE_MISMATCH!>1.<!NI;TYPE_MISMATCH!>toLong()<!><!>
|
field = <!TYPE_MISMATCH!>1.toLong()<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
val xx : Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1 + x<!>
|
val xx : Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1 + x<!>
|
||||||
|
|||||||
+15
-17
@@ -1,26 +1,24 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
|
||||||
|
|
||||||
val p1: Int = 1 - 1
|
val p1: Int = 1 - 1
|
||||||
val p2: Long = <!NI;TYPE_MISMATCH!>1 - 1<!>
|
val p2: Long = 1 - 1
|
||||||
val p3: Byte = <!NI;TYPE_MISMATCH!>1 - 1<!>
|
val p3: Byte = 1 - 1
|
||||||
val p4: Short = <!NI;TYPE_MISMATCH!>1 - 1<!>
|
val p4: Short = 1 - 1
|
||||||
|
|
||||||
val l1: Long = 1 - 1.toLong()
|
val l1: Long = 1 - 1.toLong()
|
||||||
val l2: Byte = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toLong()<!>
|
val l2: Byte = <!TYPE_MISMATCH!>1 - 1.toLong()<!>
|
||||||
val l3: Int = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toLong()<!>
|
val l3: Int = <!TYPE_MISMATCH!>1 - 1.toLong()<!>
|
||||||
val l4: Short = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toLong()<!>
|
val l4: Short = <!TYPE_MISMATCH!>1 - 1.toLong()<!>
|
||||||
|
|
||||||
val b1: Byte = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toByte()<!>
|
val b1: Byte = <!TYPE_MISMATCH!>1 - 1.toByte()<!>
|
||||||
val b2: Int = 1 - 1.toByte()
|
val b2: Int = 1 - 1.toByte()
|
||||||
val b3: Long = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toByte()<!>
|
val b3: Long = <!TYPE_MISMATCH!>1 - 1.toByte()<!>
|
||||||
val b4: Short = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toByte()<!>
|
val b4: Short = <!TYPE_MISMATCH!>1 - 1.toByte()<!>
|
||||||
|
|
||||||
val i1: Byte = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toInt()<!>
|
val i1: Byte = <!TYPE_MISMATCH!>1 - 1.toInt()<!>
|
||||||
val i2: Int = 1 - 1.toInt()
|
val i2: Int = 1 - 1.toInt()
|
||||||
val i3: Long = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toInt()<!>
|
val i3: Long = <!TYPE_MISMATCH!>1 - 1.toInt()<!>
|
||||||
val i4: Short = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toInt()<!>
|
val i4: Short = <!TYPE_MISMATCH!>1 - 1.toInt()<!>
|
||||||
|
|
||||||
val s1: Byte = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toShort()<!>
|
val s1: Byte = <!TYPE_MISMATCH!>1 - 1.toShort()<!>
|
||||||
val s2: Int = 1 - 1.toShort()
|
val s2: Int = 1 - 1.toShort()
|
||||||
val s3: Long = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toShort()<!>
|
val s3: Long = <!TYPE_MISMATCH!>1 - 1.toShort()<!>
|
||||||
val s4: Short = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>1 - 1.toShort()<!>
|
val s4: Short = <!TYPE_MISMATCH!>1 - 1.toShort()<!>
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
val p1: Byte = (1 + 2) * 2
|
||||||
|
val p2: Short = (1 + 2) * 2
|
||||||
val p1: Byte = <!NI;TYPE_MISMATCH!>(1 + 2) * 2<!>
|
|
||||||
val p2: Short = <!NI;TYPE_MISMATCH!>(1 + 2) * 2<!>
|
|
||||||
val p3: Int = (1 + 2) * 2
|
val p3: Int = (1 + 2) * 2
|
||||||
val p4: Long = <!NI;TYPE_MISMATCH!>(1 + 2) * 2<!>
|
val p4: Long = (1 + 2) * 2
|
||||||
|
|
||||||
val b1: Byte = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>(1.toByte() + 2) * 2<!>
|
val b1: Byte = <!TYPE_MISMATCH!>(1.toByte() + 2) * 2<!>
|
||||||
val b2: Short = <!NI;TYPE_MISMATCH, TYPE_MISMATCH!>(1.toShort() + 2) * 2<!>
|
val b2: Short = <!TYPE_MISMATCH!>(1.toShort() + 2) * 2<!>
|
||||||
val b3: Int = (1.toInt() + 2) * 2
|
val b3: Int = (1.toInt() + 2) * 2
|
||||||
val b4: Long = (1.toLong() + 2) * 2
|
val b4: Long = (1.toLong() + 2) * 2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user