[NI] Support signed-unsigned conversions for K/Native

#KT-34545 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2020-02-11 08:17:50 +03:00
parent e14e58c121
commit 0d310c0fa4
14 changed files with 179 additions and 57 deletions
@@ -8,6 +8,7 @@ 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.UnsignedTypes
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -33,6 +34,8 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
@@ -287,4 +290,22 @@ class KotlinResolutionCallbacksImpl(
val context = topLevelCallContext ?: return
disableContractsInsideContractsBlock(atom.psiCall, resolvedAtom.candidateDescriptor, context.scope, trace)
}
override fun convertSignedConstantToUnsigned(argument: KotlinCallArgument): IntegerValueTypeConstant? {
val argumentExpression = argument.psiExpression ?: return null
return convertSignedConstantToUnsigned(argumentExpression)
}
private fun convertSignedConstantToUnsigned(expression: KtExpression): IntegerValueTypeConstant? {
val constant = trace[BindingContext.COMPILE_TIME_VALUE, expression]
if (constant !is IntegerValueTypeConstant || !constantCanBeConvertedToUnsigned(constant)) return null
return with(IntegerValueTypeConstant) {
constant.convertToUnsignedConstant(moduleDescriptor)
}
}
private fun constantCanBeConvertedToUnsigned(constant: CompileTimeConstant<*>): Boolean {
return !constant.isError && constant.parameters.isPure
}
}
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
@@ -40,12 +39,11 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinResolutionStatelessCallbacksImpl(
private val deprecationResolver: DeprecationResolver,
private val languageVersionSettings: LanguageVersionSettings
private val languageVersionSettings: LanguageVersionSettings,
) : KotlinResolutionStatelessCallbacks {
override fun isDescriptorFromSource(descriptor: CallableDescriptor) =
DescriptorToSourceUtils.descriptorToDeclaration(descriptor) != null
@@ -61,13 +59,13 @@ class KotlinResolutionStatelessCallbacksImpl(
kotlinCall is PSIKotlinCallImpl && isSuperOrDelegatingConstructorCall(kotlinCall.psiCall)
override fun isHiddenInResolution(
descriptor: DeclarationDescriptor, kotlinCall: KotlinCall, resolutionCallbacks: KotlinResolutionCallbacks
descriptor: DeclarationDescriptor, kotlinCall: KotlinCall, resolutionCallbacks: KotlinResolutionCallbacks,
) =
deprecationResolver.isHiddenInResolution(
descriptor,
(kotlinCall as? PSIKotlinCall)?.psiCall,
(resolutionCallbacks as? KotlinResolutionCallbacksImpl)?.trace?.bindingContext,
isSuperOrDelegatingConstructorCall(kotlinCall)
isSuperOrDelegatingConstructorCall(kotlinCall),
)
override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean =
@@ -84,13 +82,13 @@ class KotlinResolutionStatelessCallbacksImpl(
override fun isApplicableCallForBuilderInference(
descriptor: CallableDescriptor,
languageVersionSettings: LanguageVersionSettings
languageVersionSettings: LanguageVersionSettings,
): Boolean {
return org.jetbrains.kotlin.resolve.calls.inference.isApplicableCallForBuilderInference(descriptor, languageVersionSettings)
}
override fun createConstraintSystemForOverloadResolution(
constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns
constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns,
): SimpleConstraintSystem {
return if (languageVersionSettings.getFlag(AnalysisFlags.constraintSystemForOverloadResolution).forNewInference())
SimpleConstraintSystemImpl(constraintInjector, builtIns)
@@ -13,7 +13,9 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.*
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.DiagnosticReporterByTrackingStrategy
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.isFakeElement
@@ -42,6 +44,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
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.IntegerValueTypeConstant
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
@@ -77,7 +80,7 @@ class KotlinToResolvedCallTransformer(
private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate,
private val smartCastManager: SmartCastManager,
private val typeApproximator: TypeApproximator,
private val missingSupertypesResolver: MissingSupertypesResolver
private val missingSupertypesResolver: MissingSupertypesResolver,
) {
companion object {
private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
@@ -94,13 +97,13 @@ class KotlinToResolvedCallTransformer(
fun <D : CallableDescriptor> onlyTransform(
resolvedCallAtom: ResolvedCallAtom,
diagnostics: Collection<KotlinCallDiagnostic>
diagnostics: Collection<KotlinCallDiagnostic>,
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, null, null, diagnostics)
fun <D : CallableDescriptor> transformAndReport(
baseResolvedCall: CallResolutionResult,
context: BasicCallResolutionContext,
tracingStrategy: TracingStrategy
tracingStrategy: TracingStrategy,
): ResolvedCall<D> {
return when (baseResolvedCall) {
is PartialCallResolutionResult -> {
@@ -129,7 +132,7 @@ class KotlinToResolvedCallTransformer(
candidate,
context.trace,
baseResolvedCall.diagnostics,
substitutor = resultSubstitutor
substitutor = resultSubstitutor,
)
forwardCallToInferenceSession(baseResolvedCall, context, stub, tracingStrategy)
@@ -141,7 +144,7 @@ class KotlinToResolvedCallTransformer(
val ktPrimitiveCompleter = ResolvedAtomCompleter(
resultSubstitutor, context, this, expressionTypingServices, argumentTypeResolver,
doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory,
typeApproximator, missingSupertypesResolver
typeApproximator, missingSupertypesResolver,
)
if (context.inferenceSession.shouldCompleteResolvedSubAtomsOf(candidate)) {
@@ -151,7 +154,7 @@ class KotlinToResolvedCallTransformer(
}
val resolvedCall = ktPrimitiveCompleter.completeResolvedCall(
candidate, baseResolvedCall.completedDiagnostic(resultSubstitutor)
candidate, baseResolvedCall.completedDiagnostic(resultSubstitutor),
) as ResolvedCall<D>
forwardCallToInferenceSession(baseResolvedCall, context, resolvedCall, tracingStrategy)
@@ -168,7 +171,7 @@ class KotlinToResolvedCallTransformer(
baseResolvedCall: CallResolutionResult,
context: BasicCallResolutionContext,
resolvedCall: ResolvedCall<*>,
tracingStrategy: TracingStrategy
tracingStrategy: TracingStrategy,
) {
if (baseResolvedCall is CompletedCallResolutionResult) {
context.inferenceSession.addCompletedCallInfo(PSICompletedCallInfo(baseResolvedCall, context, resolvedCall, tracingStrategy))
@@ -179,7 +182,7 @@ class KotlinToResolvedCallTransformer(
candidate: ResolvedCallAtom,
trace: BindingTrace,
diagnostics: Collection<KotlinCallDiagnostic>,
substitutor: NewTypeSubstitutor?
substitutor: NewTypeSubstitutor?,
): ResolvedCall<D> {
val result = transformToResolvedCall<D>(candidate, trace, substitutor, diagnostics)
val psiKotlinCall = candidate.atom.psiKotlinCall
@@ -194,14 +197,14 @@ class KotlinToResolvedCallTransformer(
completedCallAtom: ResolvedCallAtom,
trace: BindingTrace?,
resultSubstitutor: NewTypeSubstitutor? = null, // if substitutor is not null, it means that this call is completed
diagnostics: Collection<KotlinCallDiagnostic>
diagnostics: Collection<KotlinCallDiagnostic>,
): ResolvedCall<D> {
val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
return if (psiKotlinCall is PSIKotlinCallForInvoke) {
@Suppress("UNCHECKED_CAST")
NewVariableAsFunctionResolvedCallImpl(
createOrGet(psiKotlinCall.variableCall.resolvedCall, trace, resultSubstitutor, diagnostics),
createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics)
createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics),
) as ResolvedCall<D>
} else {
createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics)
@@ -212,7 +215,7 @@ class KotlinToResolvedCallTransformer(
completedSimpleAtom: ResolvedCallAtom,
trace: BindingTrace?,
resultSubstitutor: NewTypeSubstitutor?,
diagnostics: Collection<KotlinCallDiagnostic>
diagnostics: Collection<KotlinCallDiagnostic>,
): NewResolvedCallImpl<D> {
if (trace != null) {
val storedResolvedCall = completedSimpleAtom.atom.psiKotlinCall.getResolvedPsiKotlinCall<D>(trace)
@@ -249,14 +252,14 @@ class KotlinToResolvedCallTransformer(
resolvedCall.resultingDescriptor.extensionReceiverParameter,
resolvedCall.extensionReceiver,
resolvedCall.explicitReceiverKind.isExtensionReceiver,
implicitInvokeCheck = false
implicitInvokeCheck = false,
)
context.checkReceiver(
resolvedCall,
resolvedCall.resultingDescriptor.dispatchReceiverParameter,
resolvedCall.dispatchReceiver,
resolvedCall.explicitReceiverKind.isDispatchReceiver,
implicitInvokeCheck = context.call is CallTransformer.CallForImplicitInvoke
implicitInvokeCheck = context.call is CallTransformer.CallForImplicitInvoke,
)
}
@@ -266,7 +269,7 @@ class KotlinToResolvedCallTransformer(
receiverParameter: ReceiverParameterDescriptor?,
receiverArgument: ReceiverValue?,
isExplicitReceiver: Boolean,
implicitInvokeCheck: Boolean
implicitInvokeCheck: Boolean,
) {
if (receiverParameter == null || receiverArgument == null) return
val safeAccess = isExplicitReceiver && !implicitInvokeCheck && resolvedCall.call.isSemanticallyEquivalentToSafeCall
@@ -277,7 +280,7 @@ class KotlinToResolvedCallTransformer(
fun runArgumentsChecks(
context: BasicCallResolutionContext,
trace: BindingTrace,
resolvedCall: NewResolvedCallImpl<*>
resolvedCall: NewResolvedCallImpl<*>,
) {
for (valueArgument in resolvedCall.call.valueArguments) {
@@ -291,7 +294,7 @@ class KotlinToResolvedCallTransformer(
?: getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context)
Pair(
expectedType,
CallPosition.ValueArgumentPosition(resolvedCall, argumentMapping.valueParameter, valueArgument)
CallPosition.ValueArgumentPosition(resolvedCall, argumentMapping.valueParameter, valueArgument),
)
}
else -> {
@@ -303,12 +306,25 @@ class KotlinToResolvedCallTransformer(
context.replaceDataFlowInfo(resolvedCall.dataFlowInfoForArguments.getInfo(valueArgument))
.replaceExpectedType(expectedType)
.replaceCallPosition(callPosition)
.replaceBindingTrace(trace)
// todo external argument
val constantConvertedArgument = resolvedCall.getArgumentTypeForConstantConvertedArgument(valueArgument)
val argumentExpression = valueArgument.getArgumentExpression() ?: continue
updateRecordedType(argumentExpression, parameter, newContext, resolvedCall.isReallySuccess())
if (constantConvertedArgument != null) {
context.trace.record(BindingContext.COMPILE_TIME_VALUE, argumentExpression, constantConvertedArgument)
BindingContextUtils.updateRecordedType(
constantConvertedArgument.unknownIntegerType, argumentExpression, context.trace, false
)
}
updateRecordedType(
argumentExpression,
parameter,
newContext,
constantConvertedArgument?.unknownIntegerType?.unwrap(),
resolvedCall.isReallySuccess()
)
}
}
@@ -316,14 +332,16 @@ class KotlinToResolvedCallTransformer(
expression: KtExpression,
parameter: ValueParameterDescriptor?,
context: BasicCallResolutionContext,
reportErrorForTypeMismatch: Boolean
convertedArgumentType: UnwrappedType?,
reportErrorForTypeMismatch: Boolean,
): KotlinType? {
val deparenthesized = expression.let {
KtPsiUtil.getLastElementDeparenthesized(it, context.statementFilter)
} ?: return null
val recordedType = context.trace.getType(deparenthesized)
var updatedType = getResolvedCallForArgumentExpression(deparenthesized, context)?.run {
var updatedType = convertedArgumentType ?: getResolvedCallForArgumentExpression(deparenthesized, context)?.run {
makeNullableTypeIfSafeReceiver(resultingDescriptor.returnType, context)
} ?: recordedType
@@ -333,7 +351,6 @@ class KotlinToResolvedCallTransformer(
updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(context, deparenthesized) ?: updatedType
}
var reportErrorDuringTypeCheck = reportErrorForTypeMismatch
if (parameter != null && ImplicitIntegerCoercion.isEnabledForParameter(parameter)) {
@@ -342,12 +359,14 @@ class KotlinToResolvedCallTransformer(
val generalNumberType = createTypeForConvertableConstant(argumentCompileTimeValue)
if (generalNumberType != null) {
updatedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
context.trace, context.statementFilter, context.expectedType, generalNumberType, expression
context.trace, context.statementFilter, context.expectedType, generalNumberType, expression,
)
reportErrorDuringTypeCheck = true
}
}
} else if (convertedArgumentType != null) {
context.trace.report(Errors.SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED.on(deparenthesized))
}
updatedType = updateRecordedTypeForArgument(updatedType, recordedType, expression, context)
@@ -362,7 +381,7 @@ class KotlinToResolvedCallTransformer(
val typeConstructor = IntegerLiteralTypeConstructor(value, moduleDescriptor, constant.parameters)
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
Annotations.EMPTY, typeConstructor, emptyList(), false,
ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true)
ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true),
)
}
@@ -377,7 +396,7 @@ class KotlinToResolvedCallTransformer(
updatedType: KotlinType?,
recordedType: KotlinType?,
argumentExpression: KtExpression,
context: BasicCallResolutionContext
context: BasicCallResolutionContext,
): KotlinType? {
if ((!ErrorUtils.containsErrorType(recordedType) && recordedType == updatedType) || updatedType == null) return updatedType
@@ -433,7 +452,7 @@ class KotlinToResolvedCallTransformer(
context: BasicCallResolutionContext,
trace: BindingTrace,
resolvedCall: ResolvedCall<*>,
diagnostics: Collection<KotlinCallDiagnostic>
diagnostics: Collection<KotlinCallDiagnostic>,
) {
when (resolvedCall) {
is NewResolvedCallImpl ->
@@ -471,7 +490,7 @@ class KotlinToResolvedCallTransformer(
trace: BindingTrace,
completedCallAtom: ResolvedCallAtom,
resultingDescriptor: CallableDescriptor,
diagnostics: Collection<KotlinCallDiagnostic>
diagnostics: Collection<KotlinCallDiagnostic>,
) {
val trackingTrace = TrackingBindingTrace(trace)
val newContext = context.replaceBindingTrace(trackingTrace)
@@ -487,7 +506,7 @@ class KotlinToResolvedCallTransformer(
completedCallAtom.atom.psiKotlinCall,
context.dataFlowValueFactory,
allDiagnostics,
smartCastManager
smartCastManager,
)
for (diagnostic in allDiagnostics) {
@@ -497,7 +516,7 @@ class KotlinToResolvedCallTransformer(
if (diagnostic is ResolvedUsingDeprecatedVisibility) {
reportResolvedUsingDeprecatedVisibility(
completedCallAtom.atom.psiKotlinCall.psiCall, completedCallAtom.candidateDescriptor,
resultingDescriptor, diagnostic, trace
resultingDescriptor, diagnostic, trace,
)
}
@@ -592,7 +611,7 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>() : ResolvedCall<D>
protected abstract fun argumentToParameterMap(
resultingDescriptor: CallableDescriptor,
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>,
): Map<ValueArgument, ArgumentMatchImpl>
private fun createValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> =
@@ -623,7 +642,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
val resolvedCallAtom: ResolvedCallAtom,
substitutor: NewTypeSubstitutor?,
private var diagnostics: Collection<KotlinCallDiagnostic>,
private val typeApproximator: TypeApproximator
private val typeApproximator: TypeApproximator,
) : NewAbstractResolvedCall<D>() {
var isCompleted = false
private set
@@ -635,6 +654,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
private var dispatchReceiver = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
private var smartCastDispatchReceiverType: KotlinType? = null
private var expedtedTypeForSamConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
private var argumentTypeForConstantConvertedMap: MutableMap<KtExpression, IntegerValueTypeConstant>? = null
override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom
@@ -662,7 +682,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
if (extensionReceiver is ImplicitClassReceiver) {
extensionReceiver = CastImplicitClassReceiver(
(extensionReceiver as ImplicitClassReceiver).classDescriptor,
smartCastExtensionReceiverType
smartCastExtensionReceiverType,
)
}
}
@@ -715,6 +735,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
}
calculateExpectedTypeForSamConvertedArgumentMap(substitutor)
calculateExpectedTypeForConstantConvertedArgumentMap()
}
private fun KotlinType.withNullabilityFromExplicitTypeArgument(typeArgument: SimpleTypeArgument) =
@@ -722,7 +743,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
private fun getSubstitutorWithoutFlexibleTypes(
currentSubstitutor: NewTypeSubstitutor?,
explicitTypeArguments: List<SimpleTypeArgument>
explicitTypeArguments: List<SimpleTypeArgument>,
): NewTypeSubstitutor? {
if (currentSubstitutor !is NewTypeSubstitutorByConstructorMap || explicitTypeArguments.isEmpty()) return currentSubstitutor
if (!currentSubstitutor.map.any { (_, value) -> value.isFlexible() }) return currentSubstitutor
@@ -747,7 +768,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
val explicitTypeArguments = resolvedCallAtom.atom.typeArguments.filterIsInstance<SimpleTypeArgument>()
candidateDescriptor.substituteInferredVariablesAndApproximate(
getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments)
getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments),
)
}
is FunctionDescriptor -> candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor)
@@ -774,9 +795,24 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
.substituteAndApproximateTypes(compositeSubstitutor, typeApproximator)
}
fun getArgumentTypeForConstantConvertedArgument(valueArgument: ValueArgument): IntegerValueTypeConstant? {
val expression = valueArgument.getArgumentExpression() ?: return null
return argumentTypeForConstantConvertedMap?.get(expression)
}
fun getExpectedTypeForSamConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
expedtedTypeForSamConvertedArgumentMap?.get(valueArgument)
private fun calculateExpectedTypeForConstantConvertedArgumentMap() {
if (resolvedCallAtom.argumentsWithConstantConversion.isEmpty()) return
argumentTypeForConstantConvertedMap = hashMapOf()
for ((argument, convertedConstant) in resolvedCallAtom.argumentsWithConstantConversion) {
val expression = argument.psiExpression ?: continue
argumentTypeForConstantConvertedMap!![expression] = convertedConstant
}
}
private fun calculateExpectedTypeForSamConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
if (resolvedCallAtom.argumentsWithConversion.isEmpty()) return
@@ -791,7 +827,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
override fun argumentToParameterMap(
resultingDescriptor: CallableDescriptor,
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>,
): Map<ValueArgument, ArgumentMatchImpl> {
val argumentErrors = collectErrorPositions()
@@ -846,7 +882,7 @@ fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = wh
class NewVariableAsFunctionResolvedCallImpl(
override val variableCall: NewResolvedCallImpl<VariableDescriptor>,
override val functionCall: NewResolvedCallImpl<FunctionDescriptor>
override val functionCall: NewResolvedCallImpl<FunctionDescriptor>,
) : VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall {
val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast<PSIKotlinCallForInvoke>().baseCall
}
@@ -201,7 +201,11 @@ class ResolvedAtomCompleter(
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
kotlinToResolvedCallTransformer.updateRecordedType(
argumentExpression, parameter = null, context = newContext, reportErrorForTypeMismatch = true
argumentExpression,
parameter = null,
context = newContext,
reportErrorForTypeMismatch = true,
convertedArgumentType = null
)
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.UnwrappedType
@@ -75,4 +76,6 @@ interface KotlinResolutionCallbacks {
fun getExpectedTypeFromAsExpressionAndRecordItInTrace(resolvedAtom: ResolvedCallAtom): UnwrappedType?
fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom)
fun convertSignedConstantToUnsigned(argument: KotlinCallArgument): IntegerValueTypeConstant?
}
@@ -35,10 +35,11 @@ fun resolveKtPrimitive(
argument: KotlinCallArgument,
expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean
isReceiver: Boolean,
convertedType: UnwrappedType?
): ResolvedAtom = when (argument) {
is SimpleKotlinCallArgument ->
checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver, convertedType)
is LambdaKotlinCallArgument ->
preprocessLambdaArgument(csBuilder, argument, expectedType, diagnosticsHolder)
@@ -132,7 +132,7 @@ class PostponedArgumentsAnalyzer(
val subResolvedKtPrimitives = returnArgumentsInfo.nonErrorArguments.map {
resolveKtPrimitive(
c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false
c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false, convertedType = null
)
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal object CheckInstantiationOfAbstractClass : ResolutionPart() {
@@ -288,7 +290,40 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument(
isReceiver: Boolean
) {
val expectedType = candidateParameter?.let { prepareExpectedType(argument, candidateParameter) }
addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver))
val convertedArgument = if (expectedType != null && shouldRunConversionForConstants(expectedType)) {
val convertedConstant = resolutionCallbacks.convertSignedConstantToUnsigned(argument)
if (convertedConstant != null) {
resolvedCall.registerArgumentWithConstantConversion(argument, convertedConstant)
}
convertedConstant
} else null
addResolvedKtPrimitive(
resolveKtPrimitive(
csBuilder,
argument,
expectedType,
this,
isReceiver,
convertedArgument?.unknownIntegerType?.unwrap()
)
)
}
private fun KotlinResolutionCandidate.shouldRunConversionForConstants(expectedType: UnwrappedType): Boolean {
if (UnsignedTypes.isUnsignedType(expectedType)) return true
if (csBuilder.isTypeVariable(expectedType)) {
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[expectedType.constructor] ?: return false
return variableWithConstraints.constraints.any {
it.kind == ConstraintKind.EQUALITY &&
it.position.from is ExplicitTypeParameterConstraintPosition &&
UnsignedTypes.isUnsignedType(it.type as UnwrappedType)
}
}
return false
}
private fun KotlinResolutionCandidate.prepareExpectedType(
@@ -37,9 +37,10 @@ fun checkSimpleArgument(
argument: SimpleKotlinCallArgument,
expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean
isReceiver: Boolean,
convertedType: UnwrappedType?
): ResolvedAtom = when (argument) {
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver, convertedType)
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
else -> unexpectedArgument(argument)
}
@@ -49,13 +50,14 @@ private fun checkExpressionArgument(
expressionArgument: ExpressionKotlinCallArgument,
expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean
isReceiver: Boolean,
convertedType: UnwrappedType?
): ResolvedAtom {
val resolvedExpression = ResolvedExpressionAtom(expressionArgument)
if (expectedType == null) return resolvedExpression
// todo run this approximation only once for call
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
val argumentType = convertedType ?: captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
fun unstableSmartCastOrSubtypeError(
unstableType: UnwrappedType?, actualExpectedType: UnwrappedType, position: ConstraintPosition
@@ -144,6 +144,7 @@ class SimpleCandidateFactory(
if (ErrorUtils.isError(descriptor)) {
return KotlinResolutionCandidate(
callComponents,
resolutionCallbacks,
callableReferenceResolver,
scopeTower,
baseSystem,
@@ -154,7 +155,7 @@ class SimpleCandidateFactory(
}
val candidate = KotlinResolutionCandidate(
callComponents, callableReferenceResolver, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor
callComponents, resolutionCallbacks, callableReferenceResolver, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor
)
initialDiagnostics.forEach(candidate::addDiagnostic)
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintError
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForCallableReferenceReturnType
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeSubstitutor
@@ -70,6 +71,7 @@ abstract class ResolvedCallAtom : ResolvedAtom() {
abstract val freshVariablesSubstitutor: FreshVariableNewTypeSubstitutor
abstract val knownParametersSubstitutor: TypeSubstitutor
abstract val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription>
abstract val argumentsWithConstantConversion: Map<KotlinCallArgument, IntegerValueTypeConstant>
}
class SamConversionDescription(
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
import org.jetbrains.kotlin.resolve.calls.components.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.types.TypeSubstitutor
@@ -65,6 +67,7 @@ fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnos
*/
class KotlinResolutionCandidate(
val callComponents: KotlinCallComponents,
val resolutionCallbacks: KotlinResolutionCallbacks,
val callableReferenceResolver: CallableReferenceResolver,
val scopeTower: ImplicitScopeTower,
private val baseSystem: ConstraintStorage,
@@ -182,6 +185,7 @@ class MutableResolvedCallAtom(
override lateinit var knownParametersSubstitutor: TypeSubstitutor
lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor>
private var samAdapterMap: HashMap<KotlinCallArgument, SamConversionDescription>? = null
private var signedUnsignedConstantConversions: HashMap<KotlinCallArgument, IntegerValueTypeConstant>? = null
val hasSamConversion: Boolean
get() = samAdapterMap != null
@@ -189,6 +193,9 @@ class MutableResolvedCallAtom(
override val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription>
get() = samAdapterMap ?: emptyMap()
override val argumentsWithConstantConversion: Map<KotlinCallArgument, IntegerValueTypeConstant>
get() = signedUnsignedConstantConversions ?: emptyMap()
fun registerArgumentWithSamConversion(argument: KotlinCallArgument, samConversionDescription: SamConversionDescription) {
if (samAdapterMap == null)
samAdapterMap = hashMapOf()
@@ -196,6 +203,14 @@ class MutableResolvedCallAtom(
samAdapterMap!![argument] = samConversionDescription
}
fun registerArgumentWithConstantConversion(argument: KotlinCallArgument, convertedConstant: IntegerValueTypeConstant) {
if (signedUnsignedConstantConversions == null)
signedUnsignedConstantConversions = hashMapOf()
signedUnsignedConstantConversions!![argument] = convertedConstant
}
override public fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>) {
super.setAnalyzedResults(subResolvedAtoms)
}
@@ -1,5 +1,6 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNUSED_VARIABLE
// !CHECK_TYPE
// !WITH_NEW_INFERENCE
// Here we mostly trying to fix behaviour in order to track changes in inference rules for unsigned types later
@@ -9,9 +10,11 @@ fun <K> select(x: K, y: K): K = TODO()
fun takeUByte(u: UByte) {}
fun foo() {
select(1, 1u) checkType { _<Comparable<*>>() }
takeUByte(<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>id(1)<!>)
<!NI;TYPE_MISMATCH!>select<!>(1, 1u) checkType { <!NI;UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Comparable<*>>() }
takeUByte(<!NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>id(1)<!>)
1 <!NONE_APPLICABLE!>+<!> 1u
(1u + <!SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED!>1<!>) checkType { _<UInt>() }
id<UInt>(<!SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED!>1<!>)
}
@@ -1,4 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// !WITH_NEW_INFERENCE
fun takeUByte(u: UByte) {}
fun takeUShort(u: UShort) {}
@@ -26,7 +27,7 @@ fun test() {
takeUInt(<!SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED!>1<!>)
takeULong(<!SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED!>1<!>)
takeULong(<!INT_LITERAL_OUT_OF_RANGE!>18446744073709551615<!>)
takeULong(<!INT_LITERAL_OUT_OF_RANGE, NI;TYPE_MISMATCH!>18446744073709551615<!>)
takeULong(<!SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED!>1844674407370955161<!>)
takeULong(18446744073709551615u)