[NI] Support ad-hoc implicit integer coercion for Kotlin/Native
This commit is contained in:
+12
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls
|
package org.jetbrains.kotlin.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
|||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker
|
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
@@ -227,6 +229,16 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
val expression = it.psiExpression ?: return
|
val expression = it.psiExpression ?: return
|
||||||
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
|
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
|
||||||
if (reportConstantTypeMismatch(constraintError, deparenthesized)) return
|
if (reportConstantTypeMismatch(constraintError, deparenthesized)) return
|
||||||
|
|
||||||
|
val compileTimeConstant = trace[BindingContext.COMPILE_TIME_VALUE, deparenthesized] as? TypedCompileTimeConstant
|
||||||
|
if (compileTimeConstant != null) {
|
||||||
|
val expressionType = trace[BindingContext.EXPRESSION_TYPE_INFO, expression]?.type
|
||||||
|
if (expressionType != null &&
|
||||||
|
!UnsignedTypes.isUnsignedType(compileTimeConstant.type) && UnsignedTypes.isUnsignedType(expressionType)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
trace.report(
|
trace.report(
|
||||||
Errors.TYPE_MISMATCH.on(
|
Errors.TYPE_MISMATCH.on(
|
||||||
deparenthesized,
|
deparenthesized,
|
||||||
|
|||||||
+60
-25
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.tower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -35,7 +36,9 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
|||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
|
||||||
@@ -264,16 +267,22 @@ class KotlinToResolvedCallTransformer(
|
|||||||
|
|
||||||
for (valueArgument in resolvedCall.call.valueArguments) {
|
for (valueArgument in resolvedCall.call.valueArguments) {
|
||||||
val argumentMapping = resolvedCall.getArgumentMapping(valueArgument!!)
|
val argumentMapping = resolvedCall.getArgumentMapping(valueArgument!!)
|
||||||
|
val parameter: ValueParameterDescriptor?
|
||||||
val (expectedType, callPosition) = when (argumentMapping) {
|
val (expectedType, callPosition) = when (argumentMapping) {
|
||||||
is ArgumentMatch -> {
|
is ArgumentMatch -> {
|
||||||
|
parameter = argumentMapping.valueParameter
|
||||||
|
|
||||||
val expectedType = resolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument)
|
val expectedType = resolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument)
|
||||||
?: getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context)
|
?: getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context)
|
||||||
Pair(
|
Pair(
|
||||||
expectedType,
|
expectedType,
|
||||||
CallPosition.ValueArgumentPosition(resolvedCall, argumentMapping.valueParameter, valueArgument)
|
CallPosition.ValueArgumentPosition(resolvedCall, argumentMapping.valueParameter, valueArgument)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
|
else -> {
|
||||||
|
parameter = null
|
||||||
|
Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val newContext =
|
val newContext =
|
||||||
context.replaceDataFlowInfo(resolvedCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
context.replaceDataFlowInfo(resolvedCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
||||||
@@ -284,13 +293,13 @@ class KotlinToResolvedCallTransformer(
|
|||||||
// todo external argument
|
// todo external argument
|
||||||
|
|
||||||
val argumentExpression = valueArgument.getArgumentExpression() ?: continue
|
val argumentExpression = valueArgument.getArgumentExpression() ?: continue
|
||||||
updateRecordedType(argumentExpression, newContext, resolvedCall.isReallySuccess())
|
updateRecordedType(argumentExpression, parameter, newContext, resolvedCall.isReallySuccess())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateRecordedType(
|
fun updateRecordedType(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
|
parameter: ValueParameterDescriptor?,
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
reportErrorForTypeMismatch: Boolean
|
reportErrorForTypeMismatch: Boolean
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
@@ -309,13 +318,39 @@ class KotlinToResolvedCallTransformer(
|
|||||||
updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, deparenthesized) ?: updatedType
|
updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, deparenthesized) ?: updatedType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var reportErrorDuringTypeCheck = reportErrorForTypeMismatch
|
||||||
|
|
||||||
|
if (parameter != null && ImplicitIntegerCoercion.isEnabledForParameter(parameter)) {
|
||||||
|
val argumentCompileTimeValue = context.trace[BindingContext.COMPILE_TIME_VALUE, deparenthesized]
|
||||||
|
if (argumentCompileTimeValue != null && argumentCompileTimeValue.parameters.isConvertableConstVal) {
|
||||||
|
val generalNumberType = createTypeForConvertableConstant(argumentCompileTimeValue)
|
||||||
|
if (generalNumberType != null) {
|
||||||
|
updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
|
||||||
|
context.trace, context.statementFilter, context.expectedType, generalNumberType, expression
|
||||||
|
)
|
||||||
|
reportErrorDuringTypeCheck = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context)
|
updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context)
|
||||||
|
|
||||||
dataFlowAnalyzer.checkType(updatedType, deparenthesized, context, reportErrorForTypeMismatch)
|
dataFlowAnalyzer.checkType(updatedType, deparenthesized, context, reportErrorDuringTypeCheck)
|
||||||
|
|
||||||
return updatedType
|
return updatedType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createTypeForConvertableConstant(constant: CompileTimeConstant<*>): SimpleType? {
|
||||||
|
val value = constant.getValue(TypeUtils.NO_EXPECTED_TYPE).safeAs<Number>()?.toLong() ?: return null
|
||||||
|
val typeConstructor = IntegerLiteralTypeConstructor(value, moduleDescriptor, constant.parameters)
|
||||||
|
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||||
|
Annotations.EMPTY, typeConstructor, emptyList(), false,
|
||||||
|
ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getResolvedCallForArgumentExpression(expression: KtExpression, context: BasicCallResolutionContext) =
|
private fun getResolvedCallForArgumentExpression(expression: KtExpression, context: BasicCallResolutionContext) =
|
||||||
if (!ExpressionTypingUtils.dependsOnExpectedType(expression))
|
if (!ExpressionTypingUtils.dependsOnExpectedType(expression))
|
||||||
null
|
null
|
||||||
@@ -374,36 +409,39 @@ class KotlinToResolvedCallTransformer(
|
|||||||
return expressionType != null && TypeUtils.isNullableType(expressionType)
|
return expressionType != null && TypeUtils.isNullableType(expressionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun bindAndReport(
|
internal fun bind(trace: BindingTrace, resolvedCall: ResolvedCall<*>) {
|
||||||
|
resolvedCall.safeAs<NewResolvedCallImpl<*>>()?.let { bind(trace, it) }
|
||||||
|
resolvedCall.safeAs<NewVariableAsFunctionResolvedCallImpl>()?.let { bind(trace, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reportDiagnostics(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
diagnostics: Collection<KotlinCallDiagnostic>
|
diagnostics: Collection<KotlinCallDiagnostic>
|
||||||
) {
|
) {
|
||||||
resolvedCall.safeAs<NewResolvedCallImpl<*>>()?.let { bindAndReport(context, trace, it, diagnostics) }
|
when (resolvedCall) {
|
||||||
resolvedCall.safeAs<NewVariableAsFunctionResolvedCallImpl>()?.let { bindAndReport(context, trace, it, diagnostics) }
|
is NewResolvedCallImpl ->
|
||||||
|
reportCallDiagnostic(context, trace, resolvedCall.resolvedCallAtom, resolvedCall.resultingDescriptor, diagnostics)
|
||||||
|
|
||||||
|
is NewVariableAsFunctionResolvedCallImpl -> {
|
||||||
|
val variableCall = resolvedCall.variableCall
|
||||||
|
val functionCall = resolvedCall.functionCall
|
||||||
|
|
||||||
|
reportCallDiagnostic(context, trace, variableCall.resolvedCallAtom, variableCall.resultingDescriptor, diagnostics)
|
||||||
|
reportCallDiagnostic(context, trace, functionCall.resolvedCallAtom, functionCall.resultingDescriptor, emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindAndReport(
|
private fun bind(trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) {
|
||||||
context: BasicCallResolutionContext,
|
|
||||||
trace: BindingTrace,
|
|
||||||
simpleResolvedCall: NewResolvedCallImpl<*>,
|
|
||||||
diagnostics: Collection<KotlinCallDiagnostic>
|
|
||||||
) {
|
|
||||||
val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy
|
val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy
|
||||||
|
|
||||||
tracing.bindReference(trace, simpleResolvedCall)
|
tracing.bindReference(trace, simpleResolvedCall)
|
||||||
tracing.bindResolvedCall(trace, simpleResolvedCall)
|
tracing.bindResolvedCall(trace, simpleResolvedCall)
|
||||||
|
|
||||||
reportCallDiagnostic(context, trace, simpleResolvedCall.resolvedCallAtom, simpleResolvedCall.resultingDescriptor, diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindAndReport(
|
private fun bind(trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) {
|
||||||
context: BasicCallResolutionContext,
|
|
||||||
trace: BindingTrace,
|
|
||||||
variableAsFunction: NewVariableAsFunctionResolvedCallImpl,
|
|
||||||
diagnostics: Collection<KotlinCallDiagnostic>
|
|
||||||
) {
|
|
||||||
val outerTracingStrategy = variableAsFunction.baseCall.tracingStrategy
|
val outerTracingStrategy = variableAsFunction.baseCall.tracingStrategy
|
||||||
val variableCall = variableAsFunction.variableCall
|
val variableCall = variableAsFunction.variableCall
|
||||||
val functionCall = variableAsFunction.functionCall
|
val functionCall = variableAsFunction.functionCall
|
||||||
@@ -411,9 +449,6 @@ class KotlinToResolvedCallTransformer(
|
|||||||
outerTracingStrategy.bindReference(trace, variableCall)
|
outerTracingStrategy.bindReference(trace, variableCall)
|
||||||
outerTracingStrategy.bindResolvedCall(trace, variableAsFunction)
|
outerTracingStrategy.bindResolvedCall(trace, variableAsFunction)
|
||||||
functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, functionCall)
|
functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, functionCall)
|
||||||
|
|
||||||
reportCallDiagnostic(context, trace, variableCall.resolvedCallAtom, variableCall.resultingDescriptor, diagnostics)
|
|
||||||
reportCallDiagnostic(context, trace, functionCall.resolvedCallAtom, functionCall.resultingDescriptor, emptyList())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reportCallDiagnostic(
|
fun reportCallDiagnostic(
|
||||||
|
|||||||
+6
-2
@@ -102,12 +102,14 @@ class ResolvedAtomCompleter(
|
|||||||
else
|
else
|
||||||
topLevelCallCheckerContext
|
topLevelCallCheckerContext
|
||||||
|
|
||||||
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, topLevelTrace, resolvedCall, diagnostics)
|
kotlinToResolvedCallTransformer.bind(topLevelTrace, resolvedCall)
|
||||||
|
|
||||||
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>)
|
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>)
|
||||||
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
||||||
kotlinToResolvedCallTransformer.runAdditionalReceiversCheckers(resolvedCall, topLevelCallContext)
|
kotlinToResolvedCallTransformer.runAdditionalReceiversCheckers(resolvedCall, topLevelCallContext)
|
||||||
|
|
||||||
|
kotlinToResolvedCallTransformer.reportDiagnostics(topLevelCallContext, topLevelTrace, resolvedCall, diagnostics)
|
||||||
|
|
||||||
return resolvedCall
|
return resolvedCall
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +155,9 @@ class ResolvedAtomCompleter(
|
|||||||
.replaceBindingTrace(topLevelTrace)
|
.replaceBindingTrace(topLevelTrace)
|
||||||
|
|
||||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||||
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
kotlinToResolvedCallTransformer.updateRecordedType(
|
||||||
|
argumentExpression, parameter = null, context = newContext, reportErrorForTypeMismatch = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
-2
@@ -1,4 +1,5 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// !WITH_NEW_INFERENCE
|
||||||
|
|
||||||
// FILE: annotation.kt
|
// FILE: annotation.kt
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ fun test() {
|
|||||||
|
|
||||||
takeUBytes(IMPLICIT_INT, EXPLICIT_INT, 42u)
|
takeUBytes(IMPLICIT_INT, EXPLICIT_INT, 42u)
|
||||||
|
|
||||||
takeLong(IMPLICIT_INT)
|
takeLong(<!NI;TYPE_MISMATCH!>IMPLICIT_INT<!>)
|
||||||
|
|
||||||
takeIntWithoutAnnotation(IMPLICIT_INT)
|
takeIntWithoutAnnotation(IMPLICIT_INT)
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ fun test() {
|
|||||||
|
|
||||||
takeUByte(<!TYPE_MISMATCH!>LONG_CONST<!>)
|
takeUByte(<!TYPE_MISMATCH!>LONG_CONST<!>)
|
||||||
takeUByte(<!TYPE_MISMATCH!>NON_CONST<!>)
|
takeUByte(<!TYPE_MISMATCH!>NON_CONST<!>)
|
||||||
takeUByte(<!TYPE_MISMATCH!>BIGGER_THAN_UBYTE<!>)
|
takeUByte(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>BIGGER_THAN_UBYTE<!>)
|
||||||
takeUByte(<!TYPE_MISMATCH!>UINT_CONST<!>)
|
takeUByte(<!TYPE_MISMATCH!>UINT_CONST<!>)
|
||||||
takeUIntWithoutAnnotaion(<!TYPE_MISMATCH!>IMPLICIT_INT<!>)
|
takeUIntWithoutAnnotaion(<!TYPE_MISMATCH!>IMPLICIT_INT<!>)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user