diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt index 6d8676caf8f..9f4d75b97d2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor -import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.Variance @@ -73,15 +72,18 @@ val CallableDescriptor?.isMethodWithDeclarationSiteWildcards: Boolean get() { if (this !is CallableMemberDescriptor) return false return original.firstOverridden(useOriginal = true) { - METHODS_WITH_DECLARATION_SITE_WILDCARDS.contains(it.propertyIfAccessor.fqNameOrNull()) + it.propertyIfAccessor.fqNameOrNull().isMethodWithDeclarationSiteWildcardsFqName } != null } +val FqName?.isMethodWithDeclarationSiteWildcardsFqName: Boolean + get() = this in METHODS_WITH_DECLARATION_SITE_WILDCARDS + private fun FqName.child(name: String): FqName = child(Name.identifier(name)) private val METHODS_WITH_DECLARATION_SITE_WILDCARDS = setOf( - BUILTIN_NAMES.mutableCollection.child("addAll"), - BUILTIN_NAMES.mutableList.child("addAll"), - BUILTIN_NAMES.mutableMap.child("putAll") + BUILTIN_NAMES.mutableCollection.child("addAll"), + BUILTIN_NAMES.mutableList.child("addAll"), + BUILTIN_NAMES.mutableMap.child("putAll") ) fun TypeMappingMode.updateArgumentModeFromAnnotations( @@ -108,25 +110,35 @@ fun TypeMappingMode.updateArgumentModeFromAnnotations( } internal fun extractTypeMappingModeFromAnnotation( - callableDescriptor: CallableDescriptor?, - outerType: KotlinType, - isForAnnotationParameter: Boolean + callableDescriptor: CallableDescriptor?, + outerType: KotlinType, + isForAnnotationParameter: Boolean ): TypeMappingMode? = - (outerType.suppressWildcardsMode(SimpleClassicTypeSystemContext) ?: callableDescriptor?.suppressWildcardsMode())?.let { - if (outerType.arguments.isNotEmpty()) - TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode( - skipDeclarationSiteWildcards = it, - isForAnnotationParameter = isForAnnotationParameter, - needInlineClassWrapping = !outerType.isInlineClassType() - ) - else - TypeMappingMode.DEFAULT - } + SimpleClassicTypeSystemContext.extractTypeMappingModeFromAnnotation( + callableDescriptor?.suppressWildcardsMode(), outerType, isForAnnotationParameter + ) + +fun TypeSystemCommonBackendContext.extractTypeMappingModeFromAnnotation( + callableSuppressWildcardsMode: Boolean?, + outerType: KotlinTypeMarker, + isForAnnotationParameter: Boolean +): TypeMappingMode? { + val suppressWildcards = + outerType.suppressWildcardsMode(this) ?: callableSuppressWildcardsMode ?: return null + + if (outerType.argumentsCount() == 0) return TypeMappingMode.DEFAULT + + return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode( + skipDeclarationSiteWildcards = suppressWildcards, + isForAnnotationParameter = isForAnnotationParameter, + needInlineClassWrapping = !outerType.typeConstructor().isInlineClass() + ) +} private fun DeclarationDescriptor.suppressWildcardsMode(): Boolean? = - parentsWithSelf.mapNotNull { - it.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME) - }.firstOrNull()?.suppressWildcardsMode() + parentsWithSelf.mapNotNull { + it.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME) + }.firstOrNull()?.suppressWildcardsMode() private fun KotlinTypeMarker.suppressWildcardsMode(typeSystem: TypeSystemCommonBackendContext): Boolean? = with(typeSystem) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 1cccea9c22e..5a9b0f04b40 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -5,21 +5,35 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import org.jetbrains.kotlin.backend.common.lower.allOverridden +import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault +import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.OwnerKind +import org.jetbrains.kotlin.codegen.replaceValueParametersIn +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter +import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter +import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.codegen.state.extractTypeMappingModeFromAnnotation +import org.jetbrains.kotlin.codegen.state.isMethodWithDeclarationSiteWildcardsFqName import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunctionBase import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression -import org.jetbrains.kotlin.ir.types.toKotlinType -import org.jetbrains.kotlin.ir.util.isFakeOverride -import org.jetbrains.kotlin.ir.util.isInterface -import org.jetbrains.kotlin.ir.util.parentAsClass -import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature +import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type @@ -27,31 +41,181 @@ import org.jetbrains.org.objectweb.asm.commons.Method class MethodSignatureMapper(context: JvmBackendContext) { private val typeMapper: IrTypeMapper = context.typeMapper + private val typeSystem: IrTypeSystemContext = typeMapper.typeSystem private val kotlinTypeMapper: KotlinTypeMapper = context.state.typeMapper - fun mapAsmMethod(irFunction: IrFunction): Method = - kotlinTypeMapper.mapAsmMethod(irFunction.descriptor) + fun mapAsmMethod(function: IrFunction): Method = + mapSignatureSkipGeneric(function).asmMethod - fun mapFieldSignature(irField: IrField): String? = - kotlinTypeMapper.mapFieldSignature(irField.type.toKotlinType(), irField.descriptor) + fun mapFieldSignature(field: IrField): String? { + val sw = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) + if (field.correspondingPropertySymbol?.owner?.isVar == true) { + writeParameterType(sw, field.type, field) + } else { + mapReturnType(field, field.type, sw) + } + return sw.makeJavaGenericSignature() + } fun mapFunctionName(irFunction: IrFunction): String = kotlinTypeMapper.mapFunctionName(irFunction.descriptor, OwnerKind.IMPLEMENTATION) fun mapAnnotationParameterName(field: IrField): String = - kotlinTypeMapper.mapAnnotationParameterName(field.descriptor) + mapFunctionName(field.correspondingPropertySymbol!!.owner.getter ?: error("No getter for annotation property: ${field.render()}")) - fun mapReturnType(irField: IrField): Type = - kotlinTypeMapper.mapReturnType(irField.descriptor) + fun mapReturnType(declaration: IrDeclaration, sw: JvmSignatureWriter? = null): Type { + if (declaration !is IrFunction) { + require(declaration is IrField) { "Unsupported declaration: $declaration" } + return mapReturnType(declaration, declaration.type, sw) + } - fun mapReturnType(irFunction: IrFunction): Type = - kotlinTypeMapper.mapReturnType(irFunction.descriptor) + return when { + hasVoidReturnType(declaration) -> { + sw?.writeAsmType(Type.VOID_TYPE) + Type.VOID_TYPE + } + forceBoxedReturnType(declaration) -> { + typeMapper.mapType(declaration.returnType, TypeMappingMode.RETURN_TYPE_BOXED, sw) + } + else -> mapReturnType(declaration, declaration.returnType, sw) + } + } - fun mapSignatureSkipGeneric(f: IrFunction): JvmMethodSignature = - kotlinTypeMapper.mapSignatureSkipGeneric(f.descriptor, OwnerKind.IMPLEMENTATION) + private fun mapReturnType(declaration: IrDeclaration, returnType: IrType, sw: JvmSignatureWriter?): Type { + val isAnnotationMethod = declaration.parent.let { it is IrClass && it.isAnnotationClass } + if (sw == null || sw.skipGenericSignature()) { + return typeMapper.mapType(returnType, TypeMappingMode.getModeForReturnTypeNoGeneric(isAnnotationMethod), sw) + } - fun mapSignatureWithGeneric(f: IrFunction): JvmMethodGenericSignature = - kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, OwnerKind.IMPLEMENTATION) + val typeMappingModeFromAnnotation = + typeSystem.extractTypeMappingModeFromAnnotation(declaration.suppressWildcardsMode(), returnType, isAnnotationMethod) + if (typeMappingModeFromAnnotation != null) { + return typeMapper.mapType(returnType, typeMappingModeFromAnnotation, sw) + } + + val mappingMode = TypeMappingMode.getOptimalModeForReturnType(returnType.toKotlinType(), isAnnotationMethod) + + return typeMapper.mapType(returnType, mappingMode, sw) + } + + private fun hasVoidReturnType(function: IrFunction): Boolean = + function is IrConstructor || (function.returnType.isUnit() && !function.isPropertyGetter) + + private val IrFunction.isPropertyGetter: Boolean + get() = isPropertyAccessor && valueParameters.isEmpty() + + // Copied from KotlinTypeMapper.forceBoxedReturnType. + private fun forceBoxedReturnType(function: IrFunction): Boolean { + if (isBoxMethodForInlineClass(function)) return true + + return isJvmPrimitive(function.returnType) && + function is IrSimpleFunction && function.allOverridden().any { !isJvmPrimitive(it.returnType) } + } + + private fun isBoxMethodForInlineClass(function: IrFunction): Boolean = + function.parent.let { it is IrClass && it.isInline } && + function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER && + function.name.asString() == "box-impl" + + private fun isJvmPrimitive(type: IrType): Boolean { + if (type.isPrimitiveType()) return true + return type.getClass()?.isInline == true && AsmUtil.isPrimitive(typeMapper.mapType(type)) + } + + fun mapSignatureSkipGeneric(function: IrFunction): JvmMethodSignature = + mapSignature(function, true) + + fun mapSignatureWithGeneric(function: IrFunction): JvmMethodGenericSignature = + mapSignature(function, false) + + private fun mapSignature(function: IrFunction, skipGenericSignature: Boolean): JvmMethodGenericSignature { + if (function is IrLazyFunctionBase && function.initialSignatureFunction != null) { + // Overrides of special builtin in Kotlin classes always have special signature + if (function.descriptor.getOverriddenBuiltinReflectingJvmDescriptor() == null || + function.descriptor.containingDeclaration.original is JavaClassDescriptor + ) { + return mapSignature(function.initialSignatureFunction!!, skipGenericSignature) + } + } + + val sw = if (skipGenericSignature) JvmSignatureWriter() else BothSignatureWriter(BothSignatureWriter.Mode.METHOD) + + typeMapper.writeFormalTypeParameters(function.typeParameters, sw) + + sw.writeParametersStart() + + val receiverParameter = function.extensionReceiverParameter + if (receiverParameter != null) { + writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function) + } + + for (parameter in function.valueParameters) { + val type = if (forceSingleValueParameterBoxing(function.descriptor)) parameter.type.makeNullable() else parameter.type + writeParameter(sw, JvmMethodParameterKind.VALUE, type, function) + } + + sw.writeReturnType() + mapReturnType(function, sw) + sw.writeReturnTypeEnd() + + val signature = sw.makeJvmMethodSignature(mapFunctionName(function)) + + val specialSignatureInfo = with(BuiltinMethodsWithSpecialGenericSignature) { function.descriptor.getSpecialSignatureInfo() } + + if (specialSignatureInfo != null) { + val newGenericSignature = specialSignatureInfo.replaceValueParametersIn(signature.genericsSignature) + return JvmMethodGenericSignature(signature.asmMethod, signature.valueParameters, newGenericSignature) + } + + return signature + } + + private fun writeParameter(sw: JvmSignatureWriter, kind: JvmMethodParameterKind, type: IrType, function: IrFunction) { + sw.writeParameterType(kind) + writeParameterType(sw, type, function) + sw.writeParameterTypeEnd() + } + + private fun writeParameterType(sw: JvmSignatureWriter, type: IrType, declaration: IrDeclaration) { + if (sw.skipGenericSignature()) { + typeMapper.mapType(type, TypeMappingMode.DEFAULT, sw) + return + } + + val mode = with(typeSystem) { + extractTypeMappingModeFromAnnotation(declaration.suppressWildcardsMode(), type, isForAnnotationParameter = false) + ?: if (declaration.isMethodWithDeclarationSiteWildcards && type.argumentsCount() != 0) { + TypeMappingMode.GENERIC_ARGUMENT // Render all wildcards + } else { + TypeMappingMode.getOptimalModeForValueParameter(type.toKotlinType()) + } + } + + typeMapper.mapType(type, mode, sw) + } + + private val IrDeclaration.isMethodWithDeclarationSiteWildcards: Boolean + get() = this is IrSimpleFunction && allOverridden().any { + it.fqNameWhenAvailable.isMethodWithDeclarationSiteWildcardsFqName + } + + private fun IrDeclaration.suppressWildcardsMode(): Boolean? = + parentsWithSelf.mapNotNull { declaration -> + when (declaration) { + is IrField -> { + // Annotations on properties (JvmSuppressWildcards has PROPERTY, not FIELD, in its targets) have been moved + // to the synthetic "$annotations" method, but the copy can still be found via the property symbol. + declaration.correspondingPropertySymbol?.owner?.getSuppressWildcardsAnnotationValue() + } + is IrAnnotationContainer -> declaration.getSuppressWildcardsAnnotationValue() + else -> null + } + }.firstOrNull() + + private fun IrAnnotationContainer.getSuppressWildcardsAnnotationValue(): Boolean? = + getAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)?.run { + if (valueArgumentsCount > 0) (getValueArgument(0) as? IrConst<*>)?.value as? Boolean ?: true else null + } fun mapToCallableMethod(expression: IrFunctionAccessExpression): IrCallableMethod { val callee = expression.symbol.owner diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt index 6a96b776e42..eb944546693 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt @@ -32,6 +32,10 @@ abstract class IrLazyFunctionBase( IrLazyDeclarationBase(startOffset, endOffset, origin, stubGenerator, typeTranslator), IrFunction { + val initialSignatureFunction: IrFunction? by lazyVar { + descriptor.initialSignatureDescriptor?.takeIf { it != descriptor }?.original?.let(stubGenerator::generateFunctionStub) + } + override var dispatchReceiverParameter: IrValueParameter? by lazyVar { typeTranslator.buildWithScope(this) { descriptor.dispatchReceiverParameter?.generateReceiverParameterStub()?.also { it.parent = this@IrLazyFunctionBase }