[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
@@ -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)
}