From 0d310c0fa453a25ad18758c7bf7113a38c84b02a Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 11 Feb 2020 08:17:50 +0300 Subject: [PATCH] [NI] Support signed-unsigned conversions for K/Native #KT-34545 Fixed --- .../tower/KotlinResolutionCallbacksImpl.kt | 21 ++++ .../KotlinResolutionStatelessCallbacksImpl.kt | 12 +- .../tower/KotlinToResolvedCallTransformer.kt | 110 ++++++++++++------ .../calls/tower/ResolvedAtomCompleter.kt | 6 +- .../calls/components/ExternalComponents.kt | 3 + .../components/PostponeArgumentsChecks.kt | 5 +- .../components/PostponedArgumentsAnalyzer.kt | 2 +- .../calls/components/ResolutionParts.kt | 37 +++++- .../calls/components/SimpleArgumentsChecks.kt | 10 +- .../calls/model/KotlinResolverContext.kt | 3 +- .../resolve/calls/model/ResolutionAtoms.kt | 2 + .../calls/model/ResolutionCandidate.kt | 15 +++ .../inferenceForSignedAndUnsignedTypes.kt | 7 +- ...nedToUnsignedConversionWithExpectedType.kt | 3 +- 14 files changed, 179 insertions(+), 57 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt index f79bc9eb46d..1edbe3df730 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt @@ -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 + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt index 4f97e885b86..328ba48dc5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt @@ -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) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index 47e788c84ec..2bd536fc4d3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -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 onlyTransform( resolvedCallAtom: ResolvedCallAtom, - diagnostics: Collection + diagnostics: Collection, ): ResolvedCall = transformToResolvedCall(resolvedCallAtom, null, null, diagnostics) fun transformAndReport( baseResolvedCall: CallResolutionResult, context: BasicCallResolutionContext, - tracingStrategy: TracingStrategy + tracingStrategy: TracingStrategy, ): ResolvedCall { 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 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, - substitutor: NewTypeSubstitutor? + substitutor: NewTypeSubstitutor?, ): ResolvedCall { val result = transformToResolvedCall(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 + diagnostics: Collection, ): ResolvedCall { 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 } else { createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics) @@ -212,7 +215,7 @@ class KotlinToResolvedCallTransformer( completedSimpleAtom: ResolvedCallAtom, trace: BindingTrace?, resultSubstitutor: NewTypeSubstitutor?, - diagnostics: Collection + diagnostics: Collection, ): NewResolvedCallImpl { if (trace != null) { val storedResolvedCall = completedSimpleAtom.atom.psiKotlinCall.getResolvedPsiKotlinCall(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 + diagnostics: Collection, ) { when (resolvedCall) { is NewResolvedCallImpl -> @@ -471,7 +490,7 @@ class KotlinToResolvedCallTransformer( trace: BindingTrace, completedCallAtom: ResolvedCallAtom, resultingDescriptor: CallableDescriptor, - diagnostics: Collection + diagnostics: Collection, ) { 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() : ResolvedCall protected abstract fun argumentToParameterMap( resultingDescriptor: CallableDescriptor, - valueArguments: Map + valueArguments: Map, ): Map private fun createValueArguments(): Map = @@ -623,7 +642,7 @@ class NewResolvedCallImpl( val resolvedCallAtom: ResolvedCallAtom, substitutor: NewTypeSubstitutor?, private var diagnostics: Collection, - private val typeApproximator: TypeApproximator + private val typeApproximator: TypeApproximator, ) : NewAbstractResolvedCall() { var isCompleted = false private set @@ -635,6 +654,7 @@ class NewResolvedCallImpl( private var dispatchReceiver = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue private var smartCastDispatchReceiverType: KotlinType? = null private var expedtedTypeForSamConvertedArgumentMap: MutableMap? = null + private var argumentTypeForConstantConvertedMap: MutableMap? = null override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom @@ -662,7 +682,7 @@ class NewResolvedCallImpl( if (extensionReceiver is ImplicitClassReceiver) { extensionReceiver = CastImplicitClassReceiver( (extensionReceiver as ImplicitClassReceiver).classDescriptor, - smartCastExtensionReceiverType + smartCastExtensionReceiverType, ) } } @@ -715,6 +735,7 @@ class NewResolvedCallImpl( } calculateExpectedTypeForSamConvertedArgumentMap(substitutor) + calculateExpectedTypeForConstantConvertedArgumentMap() } private fun KotlinType.withNullabilityFromExplicitTypeArgument(typeArgument: SimpleTypeArgument) = @@ -722,7 +743,7 @@ class NewResolvedCallImpl( private fun getSubstitutorWithoutFlexibleTypes( currentSubstitutor: NewTypeSubstitutor?, - explicitTypeArguments: List + explicitTypeArguments: List, ): NewTypeSubstitutor? { if (currentSubstitutor !is NewTypeSubstitutorByConstructorMap || explicitTypeArguments.isEmpty()) return currentSubstitutor if (!currentSubstitutor.map.any { (_, value) -> value.isFlexible() }) return currentSubstitutor @@ -747,7 +768,7 @@ class NewResolvedCallImpl( val explicitTypeArguments = resolvedCallAtom.atom.typeArguments.filterIsInstance() candidateDescriptor.substituteInferredVariablesAndApproximate( - getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments) + getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments), ) } is FunctionDescriptor -> candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor) @@ -774,9 +795,24 @@ class NewResolvedCallImpl( .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( override fun argumentToParameterMap( resultingDescriptor: CallableDescriptor, - valueArguments: Map + valueArguments: Map, ): Map { val argumentErrors = collectErrorPositions() @@ -846,7 +882,7 @@ fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = wh class NewVariableAsFunctionResolvedCallImpl( override val variableCall: NewResolvedCallImpl, - override val functionCall: NewResolvedCallImpl + override val functionCall: NewResolvedCallImpl, ) : VariableAsFunctionResolvedCall, ResolvedCall by functionCall { val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast().baseCall } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt index 30baaf98a78..5f9104010f2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt @@ -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 ) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt index 0f66758a7a0..35704ec4d88 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt @@ -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? } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index e1296e108ed..14a760d49e3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt @@ -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) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 12e5fbc810a..e4e3586e267 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -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 ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index e9f49673a4a..a1c94b0e8c3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -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( diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt index 4ebb45d9385..b5a48b48ba3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt @@ -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 diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt index e35c7bdc1f4..1593b16c59b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt @@ -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) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index 5412e11ab12..05bb4b62793 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -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 + abstract val argumentsWithConstantConversion: Map } class SamConversionDescription( diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt index c558ae66c1d..f47bb6a172c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt @@ -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 private var samAdapterMap: HashMap? = null + private var signedUnsignedConstantConversions: HashMap? = null val hasSamConversion: Boolean get() = samAdapterMap != null @@ -189,6 +193,9 @@ class MutableResolvedCallAtom( override val argumentsWithConversion: Map get() = samAdapterMap ?: emptyMap() + override val argumentsWithConstantConversion: Map + 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) { super.setAnalyzedResults(subResolvedAtoms) } diff --git a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt index 6608e406537..14a18f20ef5 100644 --- a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt +++ b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt @@ -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 select(x: K, y: K): K = TODO() fun takeUByte(u: UByte) {} fun foo() { - select(1, 1u) checkType { _>() } - takeUByte(id(1)) + select(1, 1u) checkType { _>() } + takeUByte(id(1)) 1 + 1u (1u + 1) checkType { _() } + + id(1) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt index de61b569c7d..33c0b292a39 100644 --- a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt +++ b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt @@ -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(1) takeULong(1) - takeULong(18446744073709551615) + takeULong(18446744073709551615) takeULong(1844674407370955161) takeULong(18446744073709551615u)