K2: support implicit integer to unsigned conversions...
with dedicated opt-in language feature and special annotation or module capability. Not intended for a general use, solves specific K/N scenario with interop libs. #KT-55902 fixed
This commit is contained in:
committed by
Space Team
parent
3e2f8b834c
commit
be2a85be71
@@ -18,7 +18,8 @@ class BinaryModuleData(
|
||||
fun createDependencyModuleData(
|
||||
name: Name,
|
||||
platform: TargetPlatform,
|
||||
analyzerServices: PlatformDependentAnalyzerServices
|
||||
analyzerServices: PlatformDependentAnalyzerServices,
|
||||
capabilities: FirModuleCapabilities = FirModuleCapabilities.Empty
|
||||
): FirModuleData {
|
||||
return FirModuleDataImpl(
|
||||
name,
|
||||
@@ -27,6 +28,7 @@ class BinaryModuleData(
|
||||
friendDependencies = emptyList(),
|
||||
platform,
|
||||
analyzerServices,
|
||||
capabilities
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,17 +29,24 @@ class DependencyListForCliModule(
|
||||
private val allFriendsDependencies = mutableListOf<FirModuleData>()
|
||||
private val allDependsOnDependencies = mutableListOf<FirModuleData>()
|
||||
|
||||
private val filtersMap: Map<FirModuleData, MutableSet<Path>> =
|
||||
private val filtersMap =
|
||||
listOf(
|
||||
binaryModuleData.dependsOn,
|
||||
binaryModuleData.friends,
|
||||
binaryModuleData.regular
|
||||
).associateWith { mutableSetOf() }
|
||||
).associateWithTo(mutableMapOf<FirModuleData, MutableSet<Path>>()) { mutableSetOf() }
|
||||
|
||||
fun dependency(vararg path: Path) {
|
||||
filtersMap.getValue(binaryModuleData.regular) += path
|
||||
}
|
||||
|
||||
fun dependency(moduleData: FirModuleData, vararg path: Path) {
|
||||
filtersMap.getOrPut(moduleData) {
|
||||
allRegularDependencies.add(moduleData)
|
||||
mutableSetOf()
|
||||
} += path
|
||||
}
|
||||
|
||||
fun dependency(vararg path: String) {
|
||||
path.mapTo(filtersMap.getValue(binaryModuleData.regular)) { Paths.get(it) }
|
||||
}
|
||||
@@ -49,6 +56,18 @@ class DependencyListForCliModule(
|
||||
paths.mapTo(filtersMap.getValue(binaryModuleData.regular)) { Paths.get(it) }
|
||||
}
|
||||
|
||||
@JvmName("dependenciesString")
|
||||
fun dependencies(moduleData: FirModuleData, paths: Collection<String>) {
|
||||
paths.mapTo(
|
||||
filtersMap.getOrPut(moduleData) {
|
||||
allRegularDependencies.add(moduleData)
|
||||
mutableSetOf()
|
||||
}
|
||||
) {
|
||||
Paths.get(it)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmName("friendDependenciesString")
|
||||
fun friendDependencies(paths: Collection<String>) {
|
||||
paths.mapTo(filtersMap.getValue(binaryModuleData.friends)) { Paths.get(it) }
|
||||
|
||||
+67
-5
@@ -6,6 +6,8 @@
|
||||
package org.jetbrains.kotlin.fir.backend.generators
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
@@ -14,16 +16,14 @@ import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.getContainingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.references.*
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.approximateDeclarationType
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -935,7 +935,9 @@ class CallAndReferenceGenerator(
|
||||
irArgument = irArgument.applySamConversionIfNeeded(argument, parameter, substitutor)
|
||||
}
|
||||
}
|
||||
return irArgument.applyAssigningArrayElementsToVarargInNamedForm(argument, parameter)
|
||||
return irArgument
|
||||
.applyAssigningArrayElementsToVarargInNamedForm(argument, parameter)
|
||||
.applyImplicitIntegerCoercionIfNeeded(argument, parameter)
|
||||
}
|
||||
|
||||
private fun IrExpression.applyAssigningArrayElementsToVarargInNamedForm(
|
||||
@@ -962,6 +964,66 @@ class CallAndReferenceGenerator(
|
||||
return this
|
||||
}
|
||||
|
||||
private fun IrExpression.applyImplicitIntegerCoercionIfNeeded(
|
||||
argument: FirExpression,
|
||||
parameter: FirValueParameter?
|
||||
): IrExpression {
|
||||
if (!session.languageVersionSettings.supportsFeature(LanguageFeature.ImplicitSignedToUnsignedIntegerConversion)) return this
|
||||
|
||||
if (parameter == null || !parameter.isMarkedWithImplicitIntegerCoercion) return this
|
||||
|
||||
fun IrExpression.applyToElement(argument: FirExpression, conversionFunction: IrSimpleFunctionSymbol): IrExpression =
|
||||
if (argument is FirConstExpression<*> ||
|
||||
argument.calleeReference?.toResolvedCallableSymbol()?.let {
|
||||
it.resolvedStatus.isConst && it.isMarkedWithImplicitIntegerCoercion
|
||||
} == true
|
||||
) {
|
||||
IrCallImpl(
|
||||
startOffset, endOffset,
|
||||
conversionFunction.owner.returnType,
|
||||
conversionFunction,
|
||||
typeArgumentsCount = 0,
|
||||
valueArgumentsCount = 0
|
||||
).apply {
|
||||
extensionReceiver = this@applyToElement
|
||||
}
|
||||
} else this@applyToElement
|
||||
|
||||
if (parameter.isMarkedWithImplicitIntegerCoercion) {
|
||||
if (this is IrVarargImpl && argument is FirVarargArgumentsExpression) {
|
||||
|
||||
val targetTypeFqName = varargElementType.classFqName ?: return this
|
||||
val conversionFunctions = irBuiltIns.getNonBuiltInFunctionsByExtensionReceiver(
|
||||
Name.identifier("to" + targetTypeFqName.shortName().asString()),
|
||||
StandardNames.BUILT_INS_PACKAGE_NAME.asString()
|
||||
)
|
||||
if (conversionFunctions.isNotEmpty()) {
|
||||
elements.forEachIndexed { i, irVarargElement ->
|
||||
val targetFun = argument.arguments[i].typeRef.toIrType().classifierOrNull?.let { conversionFunctions[it] }
|
||||
if (targetFun != null && irVarargElement is IrExpression) {
|
||||
elements[i] =
|
||||
irVarargElement.applyToElement(argument.arguments[i], targetFun)
|
||||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
} else {
|
||||
val targetIrType = parameter.returnTypeRef.toIrType()
|
||||
val targetTypeFqName = targetIrType.classFqName ?: return this
|
||||
val conversionFunctions = irBuiltIns.getNonBuiltInFunctionsByExtensionReceiver(
|
||||
Name.identifier("to" + targetTypeFqName.shortName().asString()),
|
||||
StandardNames.BUILT_INS_PACKAGE_NAME.asString()
|
||||
)
|
||||
val sourceTypeClassifier = argument.typeRef.toIrType().classifierOrNull ?: return this
|
||||
|
||||
val conversionFunction = conversionFunctions[sourceTypeClassifier] ?: return this
|
||||
|
||||
return this.applyToElement(argument, conversionFunction)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
internal fun IrExpression.applyTypeArguments(access: FirQualifiedAccessExpression): IrExpression {
|
||||
if (this !is IrMemberAccessExpression<*>) return this
|
||||
val argumentsCount = access.typeArguments.size
|
||||
|
||||
+6
@@ -51555,6 +51555,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/nullableUnsignedEqualsLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("signedToUnsignedConversions.kt")
|
||||
public void testSignedToUnsignedConversions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedConversions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsignedArraySize.kt")
|
||||
public void testUnsignedArraySize() throws Exception {
|
||||
|
||||
+6
@@ -51555,6 +51555,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/nullableUnsignedEqualsLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("signedToUnsignedConversions.kt")
|
||||
public void testSignedToUnsignedConversions() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedConversions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsignedArraySize.kt")
|
||||
public void testUnsignedArraySize() throws Exception {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirModuleCapability
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.resolvedAnnotationClassIds
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
object ImplicitIntegerCoercionModuleCapability : FirModuleCapability() {
|
||||
override val key: KClass<out FirModuleCapability> = ImplicitIntegerCoercionModuleCapability::class
|
||||
}
|
||||
|
||||
private val implicitIntegerCoercionAnnotationClassId =
|
||||
ClassId(StandardNames.KOTLIN_INTERNAL_FQ_NAME, Name.identifier("ImplicitIntegerCoercion"))
|
||||
|
||||
val FirCallableSymbol<*>.isMarkedWithImplicitIntegerCoercion
|
||||
get() =
|
||||
fir.moduleData.capabilities.contains(ImplicitIntegerCoercionModuleCapability) ||
|
||||
resolvedAnnotationClassIds.any { it == implicitIntegerCoercionAnnotationClassId }
|
||||
|
||||
val FirCallableDeclaration.isMarkedWithImplicitIntegerCoercion
|
||||
get() =
|
||||
moduleData.capabilities.contains(ImplicitIntegerCoercionModuleCapability) ||
|
||||
resolvedAnnotationClassIds(symbol).any { it == implicitIntegerCoercionAnnotationClassId }
|
||||
@@ -6,16 +6,16 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.isBasicFunctionOrKFunction
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.lookupTracker
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.createFunctionType
|
||||
import org.jetbrains.kotlin.fir.expressions.unwrapSmartcastExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.LambdaWithTypeVariableAsExpectedTypeAtom
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeReceiverConstraintPosition
|
||||
@@ -487,7 +487,9 @@ private fun Candidate.prepareExpectedType(
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: basicExpectedType
|
||||
}
|
||||
?: getExpectedTypeWithImplicintIntegerCoercion(session, argument, parameter, basicExpectedType)
|
||||
?: basicExpectedType
|
||||
return this.substitutor.substituteOrSelf(expectedType)
|
||||
}
|
||||
|
||||
@@ -510,6 +512,29 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getExpectedTypeWithImplicintIntegerCoercion(
|
||||
session: FirSession,
|
||||
argument: FirExpression,
|
||||
parameter: FirValueParameter,
|
||||
candidateExpectedType: ConeKotlinType
|
||||
): ConeKotlinType? {
|
||||
if (!session.languageVersionSettings.supportsFeature(LanguageFeature.ImplicitSignedToUnsignedIntegerConversion)) return null
|
||||
|
||||
if (!parameter.isMarkedWithImplicitIntegerCoercion) return null
|
||||
|
||||
val argumentType =
|
||||
if (argument.isIntegerLiteralOrOperatorCall()) argument.resultType.coneType
|
||||
else {
|
||||
argument.calleeReference?.toResolvedCallableSymbol()?.takeIf {
|
||||
it.rawStatus.isConst && it.isMarkedWithImplicitIntegerCoercion
|
||||
}?.resolvedReturnType
|
||||
}
|
||||
|
||||
// TODO: consider adding a check that argument could be converted to the parameter type (maybe difficult for platform types)
|
||||
|
||||
return argumentType?.withNullability(candidateExpectedType.nullability, session.typeContext)
|
||||
}
|
||||
|
||||
fun FirExpression.isFunctional(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.util.ConeTypeRegistry
|
||||
import org.jetbrains.kotlin.util.AttributeArrayOwner
|
||||
import org.jetbrains.kotlin.util.TypeRegistry
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
abstract class FirModuleCapability {
|
||||
abstract val key: KClass<out FirModuleCapability>
|
||||
}
|
||||
|
||||
class FirModuleCapabilities private constructor(
|
||||
capabilities: List<FirModuleCapability>
|
||||
) : AttributeArrayOwner<FirModuleCapability, FirModuleCapability>() {
|
||||
|
||||
companion object : ConeTypeRegistry<FirModuleCapability, FirModuleCapability>() {
|
||||
|
||||
val Empty: FirModuleCapabilities = FirModuleCapabilities(emptyList())
|
||||
|
||||
fun create(attributes: List<FirModuleCapability>): FirModuleCapabilities {
|
||||
return if (attributes.isEmpty()) {
|
||||
Empty
|
||||
} else {
|
||||
FirModuleCapabilities(attributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
for (capability in capabilities) {
|
||||
registerComponent(capability.key, capability)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override val typeRegistry: TypeRegistry<FirModuleCapability, FirModuleCapability>
|
||||
get() = Companion
|
||||
}
|
||||
@@ -50,6 +50,9 @@ abstract class FirModuleData : FirSessionComponent {
|
||||
// refactor them to make API clearer
|
||||
abstract val analyzerServices: PlatformDependentAnalyzerServices
|
||||
|
||||
open val capabilities: FirModuleCapabilities
|
||||
get() = FirModuleCapabilities.Empty
|
||||
|
||||
private var _session: FirSession? = null
|
||||
val session: FirSession
|
||||
get() = _session
|
||||
@@ -73,7 +76,8 @@ class FirModuleDataImpl(
|
||||
override val dependsOnDependencies: List<FirModuleData>,
|
||||
override val friendDependencies: List<FirModuleData>,
|
||||
override val platform: TargetPlatform,
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices,
|
||||
override val capabilities: FirModuleCapabilities = FirModuleCapabilities.Empty
|
||||
) : FirModuleData()
|
||||
|
||||
val FirSession.nullableModuleData: FirModuleData? by FirSession.nullableSessionComponentAccessor()
|
||||
|
||||
@@ -31,6 +31,9 @@ val FirTypeRef.coneType: ConeKotlinType
|
||||
get() = coneTypeSafe()
|
||||
?: error("Expected FirResolvedTypeRef with ConeKotlinType but was ${this::class.simpleName} ${render()}")
|
||||
|
||||
val FirTypeRef.coneTypeOrNull: ConeKotlinType?
|
||||
get() = coneTypeSafe()
|
||||
|
||||
val FirTypeRef.isAny: Boolean get() = isBuiltinType(StandardClassIds.Any, false)
|
||||
val FirTypeRef.isNullableAny: Boolean get() = isBuiltinType(StandardClassIds.Any, true)
|
||||
val FirTypeRef.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false)
|
||||
|
||||
Reference in New Issue
Block a user