From bfe148efd588c01b82fdbdf4c0c935e536923297 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Mon, 15 Apr 2019 01:29:55 +0300 Subject: [PATCH] IR: mostly remove descriptors from codegen --- .../org/jetbrains/kotlin/codegen/asm7Util.kt | 2 +- .../jetbrains/kotlin/codegen/asm7Util.kt.182 | 2 +- .../lower/DefaultArgumentStubGenerator.kt | 3 +- .../jetbrains/kotlin/ir/util/IrTypeUtils.kt | 30 ++ .../kotlin/backend/jvm/JvmSymbols.kt | 50 --- .../backend/jvm/codegen/AnnotationCodegen.kt | 4 +- .../backend/jvm/codegen/ClassCodegen.kt | 91 ++-- .../backend/jvm/codegen/ExpressionCodegen.kt | 380 ++++++++++------ .../backend/jvm/codegen/FunctionCodegen.kt | 140 ++++-- .../backend/jvm/codegen/IrCallGenerator.kt | 8 +- .../backend/jvm/codegen/IrInlineCodegen.kt | 34 +- .../backend/jvm/codegen/IrTypeMapper.kt | 65 +++ .../backend/jvm/codegen/irCodegenUtils.kt | 404 +++++++++++++++++- .../backend/jvm/intrinsics/ArrayIterator.kt | 18 +- .../backend/jvm/intrinsics/CompareTo.kt | 2 +- .../backend/jvm/intrinsics/IntrinsicMethod.kt | 2 +- .../backend/jvm/intrinsics/IrEnumValueOf.kt | 14 +- .../jvm/intrinsics/IrIntrinsicFunction.kt | 21 +- .../jvm/intrinsics/IrIntrinsicMethods.kt | 69 ++- .../kotlin/backend/jvm/intrinsics/NewArray.kt | 5 +- .../jvm/lower/CallableReferenceLowering.kt | 26 +- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 8 + .../functionExpressionWithThisReference.kt | 2 + .../functionExpressionWithThisReferenceNI.kt | 36 ++ .../codegen/box/reflection/typeOf/classes.kt | 2 +- .../box/reflection/typeOf/classesIR.kt | 41 ++ .../reflection/typeOf/noReflect/classes.kt | 1 + .../reflection/typeOf/noReflect/classesIR.kt | 42 ++ .../noReflect/typeReferenceEqualsHashCode.kt | 1 + .../typeReferenceEqualsHashCodeIR.kt | 55 +++ ...peParameterReplacedWithIntersectionType.kt | 1 - .../codegen/BlackBoxCodegenTestGenerated.java | 5 + .../LightAnalysisModeTestGenerated.java | 5 + .../ir/IrBlackBoxCodegenTestGenerated.java | 20 + .../IrJsCodegenBoxTestGenerated.java | 5 + .../semantics/JsCodegenBoxTestGenerated.java | 5 + 36 files changed, 1224 insertions(+), 375 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt create mode 100644 compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/classesIR.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/noReflect/classesIR.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCodeIR.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt index 3709cccd386..05ce1062c37 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.org.objectweb.asm.MethodVisitor -internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) { +fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) { mv.visitAnnotableParameterCount(paramCount, true) mv.visitAnnotableParameterCount(paramCount, false) } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt.182 b/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt.182 index eaf8aa8c897..6a54f9bdd92 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt.182 +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/asm7Util.kt.182 @@ -7,4 +7,4 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.org.objectweb.asm.MethodVisitor -internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {} \ No newline at end of file +fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt index b4a5ee64f3a..4d806273c58 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -160,7 +159,7 @@ open class DefaultArgumentStubGenerator( newIrFunction: IrFunction, params: MutableList ): IrExpression { - val dispatchCall = irCall(irFunction).apply { + val dispatchCall = irCall(irFunction.symbol).apply { passTypeArgumentsFrom(newIrFunction) dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) } extensionReceiver = newIrFunction.extensionReceiverParameter?.let { irGet(it) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt index da5df603e11..20cafbd60ae 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt @@ -11,9 +11,12 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrPackageFragment +import org.jetbrains.kotlin.ir.declarations.IrTypeParameter import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.DFS @@ -89,3 +92,30 @@ fun IrType.getPrimitiveArrayElementType() = (this as? IrSimpleType)?.let { fun IrType.isNonPrimitiveArray() = (this.isArray() || this.isNullableArray()) && !this.isPrimitiveArray() + + +fun IrType.substitute(params: List, arguments: List): IrType = + substitute(params.map { it.symbol }.zip(arguments).toMap()) + + +fun IrType.substitute(substitutionMap: Map): IrType { + if (this !is IrSimpleType) return this + + substitutionMap[classifier]?.let { return it } + + val newArguments = arguments.map { + if (it is IrTypeProjection) { + makeTypeProjection(it.type.substitute(substitutionMap), it.variance) + } else { + it + } + } + + val newAnnotations = annotations.map { it.deepCopyWithSymbols() } + return IrSimpleTypeImpl( + classifier, + hasQuestionMark, + newArguments, + newAnnotations + ) +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 99e79390145..03a244de5a0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -6,27 +6,23 @@ package org.jetbrains.kotlin.backend.jvm import org.jetbrains.kotlin.backend.common.ir.Symbols -import org.jetbrains.kotlin.backend.common.ir.addChild import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable -import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -53,10 +49,7 @@ class JvmSymbols( private fun createPackage(fqName: FqName): IrPackageFragment = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName))) - private val kotlinPackage: IrPackageFragment = createPackage(FqName("kotlin")) - private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm")) private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal")) - private val kotlinJvmInternalUnsafePackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal.unsafe")) private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions")) private fun createClass(fqName: FqName, classKind: ClassKind = ClassKind.CLASS, block: (IrClass) -> Unit): IrClass = @@ -261,47 +254,4 @@ class JvmSymbols( val getOrCreateKotlinClasses: IrSimpleFunctionSymbol = reflection.functions.single { it.owner.name.asString() == "getOrCreateKotlinClasses" } - - val javaClassProperty: IrPropertySymbol = kotlinJvmPackage.addProperty { - name = Name.identifier("javaClass") - }.apply { - addGetter().apply { - val typeParameter = addTypeParameter { - name = Name.identifier("T") - }.apply { - superTypes.add(irBuiltIns.anyType) - } - addExtensionReceiver(typeParameter.defaultType) - returnType = javaLangClass.typeWith(typeParameter.defaultType) - } - }.symbol - - val kClassJavaProperty: IrPropertySymbol = kotlinJvmPackage.addProperty { - name = Name.identifier("java") - }.apply { - addGetter().apply { - val extensionReceiverType = irBuiltIns.kClassClass.typeWith() - addExtensionReceiver(extensionReceiverType) - returnType = javaLangClass.typeWith(extensionReceiverType) - } - }.symbol - - val monitorEnter = kotlinJvmInternalUnsafePackage.addFunction("monitorEnter", irBuiltIns.unitType, isStatic = true).apply { - addValueParameter("monitor", irBuiltIns.anyType) - }.symbol - - val monitorExit = kotlinJvmInternalUnsafePackage.addFunction("monitorExit", irBuiltIns.unitType, isStatic = true).apply { - addValueParameter("monitor", irBuiltIns.anyType) - }.symbol - - val isArrayOf = kotlinJvmPackage.addFunction("isArrayOf", irBuiltIns.booleanType, isStatic = true).apply { - addExtensionReceiver(irBuiltIns.arrayClass.owner.defaultType) - addTypeParameter("T", irBuiltIns.anyNType) - }.symbol - - // We cannot create Cloneable reference out of thin air, since we have to preserve the information that it is a Java interface and - // it has no DefaultImpls counterpart. - val cloneable = symbolTable.referenceClass( - builtInsPackage("kotlin").getContributedClassifier(Name.identifier("Cloneable"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor - ) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt index ed466b9df64..a9fb21e401b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt @@ -107,7 +107,7 @@ class AnnotationCodegen( if (declaration is IrValueParameter && isInvisibleFromTheOutside(declaration.parent as? IrDeclaration)) return // No need to annotate annotation methods since they're always non-null - if (declaration is IrSimpleFunction && declaration.correspondingProperty != null && + if (declaration is IrSimpleFunction && declaration.correspondingPropertySymbol != null && declaration.parentAsClass.isAnnotationClass ) { return @@ -276,7 +276,7 @@ class AnnotationCodegen( } interface InnerClassConsumer { - fun addInnerClassInfoFromAnnotation(irClass: IrClass) + fun addInnerClassInfoFromAnnotation(innerClass: IrClass) } private fun isBareTypeParameterWithNullableUpperBound(type: IrType): Boolean { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index fb713f38d7b..ef5f383460e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -20,28 +20,27 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.lower.constantValue import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.codegen.binding.CodegenBinding.ASM_TYPE import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper import org.jetbrains.kotlin.codegen.inline.SourceMapper import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.SpecialNames -import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin -import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.serialization.DescriptorSerializer -import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import java.io.File @@ -52,20 +51,19 @@ open class ClassCodegen protected constructor( private val parentClassCodegen: ClassCodegen? = null ) : InnerClassConsumer { - private val innerClasses = mutableListOf() + private val innerClasses = mutableListOf() val state = context.state - val typeMapper = context.state.typeMapper + val typeMapper = IrTypeMapper(context.state.typeMapper) val descriptor = irClass.descriptor - private val isAnonymous = DescriptorUtils.isAnonymousObject(irClass.descriptor) + private val isAnonymous = irClass.isAnonymousObject - val type: Type = if (isAnonymous) CodegenBinding.asmTypeForAnonymousClass( - state.bindingContext, - descriptor.source.getPsi() as KtElement - ) else typeMapper.mapType(descriptor) + val type: Type = if (isAnonymous) + state.bindingContext.get(ASM_TYPE, descriptor)!! + else typeMapper.mapType(irClass) private val sourceManager = context.psiSourceManager @@ -78,7 +76,7 @@ open class ClassCodegen protected constructor( open fun createClassBuilder() = state.factory.newVisitor( OtherOrigin(psiElement, descriptor), type, - psiElement?.containingFile?.let { setOf(it) } ?: emptySet() + listOf(File(fileEntry.name)) ) private var sourceMapper: DefaultSourceMapper? = null @@ -92,8 +90,8 @@ open class ClassCodegen protected constructor( } fun generate() { - val superClassInfo = SuperClassInfo.getSuperClassInfo(descriptor, typeMapper) - val signature = ImplementationBodyCodegen.signature(descriptor, type, superClassInfo, typeMapper) + val superClassInfo = irClass.getSuperClassInfo(typeMapper) + val signature = getSignature(irClass, type, superClassInfo, typeMapper) visitor.defineClass( psiElement, @@ -170,22 +168,16 @@ open class ClassCodegen protected constructor( companion object { fun generate(irClass: IrClass, context: JvmBackendContext) { - val descriptor = irClass.descriptor val state = context.state - if (ErrorUtils.isError(descriptor)) { - badDescriptor(irClass, state.classBuilderMode) - return - } - if (irClass.name == SpecialNames.NO_NAME_PROVIDED) { - badDescriptor(irClass, state.classBuilderMode) + badClass(irClass, state.classBuilderMode) } ClassCodegen(irClass, context).generate() } - private fun badDescriptor(irClass: IrClass, mode: ClassBuilderMode) { + private fun badClass(irClass: IrClass, mode: ClassBuilderMode) { if (mode.generateBodies) { throw IllegalStateException("Generating bad class in ClassBuilderMode = $mode: ${irClass.dump()}") } @@ -216,9 +208,9 @@ open class ClassCodegen protected constructor( private fun generateField(field: IrField, companionObjectCodegen: ClassCodegen?) { if (field.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return - val fieldType = typeMapper.mapType(field.descriptor) - val fieldSignature = typeMapper.mapFieldSignature(field.descriptor.type, field.descriptor) - val fieldName = field.descriptor.name.asString() + val fieldType = typeMapper.mapType(field) + val fieldSignature = typeMapper.mapFieldSignature(field.type, field) + val fieldName = field.name.asString() // The ConstantValue attribute makes the initializer part of the ABI, which is why since 1.4 // it is no longer set unless the property is explicitly `const`. val implicitConst = !state.languageVersionSettings.supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals) && @@ -274,13 +266,13 @@ open class ClassCodegen protected constructor( private fun writeInnerClasses() { // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information // for each enclosing class and for each immediate member - val classDescriptor = classForInnerClassRecord() - if (classDescriptor != null) { - parentClassCodegen?.innerClasses?.add(classDescriptor) + val classForInnerClassRecord = getClassForInnerClassRecord() + if (classForInnerClassRecord != null) { + parentClassCodegen?.innerClasses?.add(classForInnerClassRecord) var codegen: ClassCodegen? = this while (codegen != null) { - val outerClass = codegen.classForInnerClassRecord() + val outerClass = codegen.getClassForInnerClassRecord() if (outerClass != null) { innerClasses.add(outerClass) } @@ -289,23 +281,23 @@ open class ClassCodegen protected constructor( } for (innerClass in innerClasses) { - MemberCodegen.writeInnerClass(innerClass, typeMapper, visitor) + writeInnerClass(innerClass, typeMapper, context, visitor) } } - private fun classForInnerClassRecord(): ClassDescriptor? { - return if (parentClassCodegen != null) descriptor else null + private fun getClassForInnerClassRecord(): IrClass? { + return if (parentClassCodegen != null) irClass else null } // It's necessary for proper recovering of classId by plain string JVM descriptor when loading annotations // See FileBasedKotlinClass.convertAnnotationVisitor - override fun addInnerClassInfoFromAnnotation(irClass: IrClass) { - var current: DeclarationDescriptor? = irClass.descriptor - while (current != null && !isTopLevelDeclaration(current)) { - if (current is ClassDescriptor) { + override fun addInnerClassInfoFromAnnotation(innerClass: IrClass) { + var current: IrDeclaration? = innerClass + while (current != null) { + if (current is IrClass) { innerClasses.add(current) } - current = current.containingDeclaration + current = current.parent as? IrDeclaration } } @@ -323,7 +315,7 @@ open class ClassCodegen protected constructor( // in the source. val containingDeclaration = irClass.symbol.owner.parent if (containingDeclaration is IrFunction) { - val method = typeMapper.mapAsmMethod(containingDeclaration.descriptor) + val method = typeMapper.mapAsmMethod(containingDeclaration) visitor.visitOuterClass(outerClassName, method.name, method.descriptor) } else { visitor.visitOuterClass(outerClassName, null, null) @@ -340,7 +332,7 @@ open class ClassCodegen protected constructor( } private val IrClass.flags: Int - get() = origin.flags or AsmUtil.getVisibilityAccessFlagForClass(descriptor) or when { + get() = origin.flags or getVisibilityAccessFlagForClass() or when { isAnnotationClass -> Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT isInterface -> Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT isEnumClass -> Opcodes.ACC_ENUM or Opcodes.ACC_SUPER or modality.flags @@ -372,3 +364,18 @@ private val IrField.OtherOrigin: JvmDeclarationOrigin internal val IrFunction.OtherOrigin: JvmDeclarationOrigin get() = OtherOrigin(descriptor.psiElement, this.descriptor) + +private fun IrClass.getSuperClassInfo(typeMapper: IrTypeMapper): IrSuperClassInfo { + if (isInterface) { + return IrSuperClassInfo(AsmTypes.OBJECT_TYPE, null) + } + + for (superType in superTypes) { + val superClass = superType.safeAs()?.classifier?.safeAs()?.owner + if (superClass != null && !superClass.isJvmInterface) { + return IrSuperClassInfo(typeMapper.mapClass(superClass), superType) + } + } + + return IrSuperClassInfo(AsmTypes.OBJECT_TYPE, null) +} \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 6877b595ce5..abe72cde9e1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -5,17 +5,14 @@ package org.jetbrains.kotlin.backend.jvm.codegen -import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin -import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethods +import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty import org.jetbrains.kotlin.backend.jvm.intrinsics.Not import org.jetbrains.kotlin.backend.jvm.lower.CrIrType import org.jetbrains.kotlin.backend.jvm.lower.constantValue -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.* -import org.jetbrains.kotlin.codegen.ExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameter import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.AS import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE_AS @@ -25,27 +22,22 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.visitors.IrElementVisitor -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass -import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue -import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE -import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.typeUtil.isNothing -import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes -import org.jetbrains.kotlin.types.upperIfFlexible import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type @@ -125,18 +117,15 @@ class ExpressionCodegen( override var lastLineNumber: Int = -1 - private val KotlinType.asmType: Type - get() = typeMapper.mapType(this) - private val IrType.asmType: Type - get() = toKotlinType().asmType - - private val CallableDescriptor.asmType: Type get() = typeMapper.mapType(this) val IrExpression.asmType: Type get() = type.asmType + val IrVariable.asmType: Type + get() = type.asmType + // Assume this expression's result has already been materialized on the stack // with the correct type. val IrExpression.onStack: MaterialValue @@ -178,7 +167,7 @@ class ExpressionCodegen( if (irFunction.origin != JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER) { irFunction.markLineNumber(startOffset = irFunction is IrConstructor && irFunction.isPrimary) } - val returnType = typeMapper.mapReturnType(irFunction.descriptor) + val returnType = typeMapper.mapReturnType(irFunction) result.coerce(returnType).materialize() mv.areturn(returnType) } @@ -201,18 +190,15 @@ class ExpressionCodegen( } private fun writeValueParameterInLocalVariableTable(param: IrValueParameter, startLabel: Label) { - val descriptor = param.descriptor - val nameForDestructuredParameter = if (descriptor is ValueParameterDescriptor) { - getNameForDestructuredParameterOrNull(descriptor) - } else { - null - } + // TODO: old code has a special treatment for destructuring lambda parameters. + // There is no (easy) way to reproduce it with IR structures. + // Does not show up in tests, but might come to bite us at some point. + val name = param.name.asString() - val type = typeMapper.mapType(descriptor) + val type = typeMapper.mapType(param) // NOTE: we expect all value parameters to be present in the frame. mv.visitLocalVariable( - nameForDestructuredParameter ?: param.name.asString(), - type.descriptor, null, startLabel, markNewLabel(), findLocalIndex(param.symbol) + name, type.descriptor, null, startLabel, markNewLabel(), findLocalIndex(param.symbol) ) } @@ -268,10 +254,10 @@ class ExpressionCodegen( override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue { expression.markLineNumber(startOffset = true) - if (expression.descriptor is ConstructorDescriptor) { + if (expression.symbol.owner is IrConstructor) { throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}") } - return generateCall(expression, expression.superQualifier, data) + return generateCall(expression, expression.superQualifierSymbol, data) } override fun visitConstructorCall(expression: IrConstructorCall, data: BlockInfo): PromisedValue { @@ -287,35 +273,36 @@ class ExpressionCodegen( return expression.onStack } - fun generateNewArray(expression: IrConstructorCall, data: BlockInfo): PromisedValue { - val args = expression.descriptor.valueParameters + private fun generateNewArray(expression: IrConstructorCall, data: BlockInfo): PromisedValue { + val args = expression.symbol.owner.valueParameters assert(args.size == 1 || args.size == 2) { "Unknown constructor called: " + args.size + " arguments" } if (args.size == 1) { // TODO move to the intrinsic expression.getValueArgument(0)!!.accept(this, data).coerce(Type.INT_TYPE).materialize() - newArrayInstruction(expression.type.toKotlinType()) + newArrayInstruction(expression.type) return expression.onStack } return generateCall(expression, null, data) } - private fun generateCall(expression: IrFunctionAccessExpression, superQualifier: ClassDescriptor?, data: BlockInfo): PromisedValue { + private fun generateCall(expression: IrFunctionAccessExpression, superQualifierSymbol: IrClassSymbol?, data: BlockInfo): PromisedValue { classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol) ?.invoke(expression, this, data)?.let { return it.coerce(expression.asmType) } - val isSuperCall = superQualifier != null + val isSuperCall = superQualifierSymbol != null val callable = resolveToCallable(expression, isSuperCall) return generateCall(expression, callable, data, isSuperCall) } fun generateCall( - expression: IrMemberAccessExpression, + expression: IrFunctionAccessExpression, callable: Callable, data: BlockInfo, isSuperCall: Boolean = false ): PromisedValue { - val callGenerator = getOrCreateCallGenerator(expression, expression.descriptor, data) + val callee = expression.symbol.owner + val callGenerator = getOrCreateCallGenerator(expression, data) val receiver = expression.dispatchReceiver receiver?.apply { @@ -335,19 +322,24 @@ class ExpressionCodegen( val defaultMask = DefaultCallArgs(callable.valueParameterTypes.size) val extraArgsShift = when { - expression.descriptor is ConstructorDescriptor && isEnumClass(expression.descriptor.containingDeclaration) -> 2 - expression.descriptor is ConstructorDescriptor && - (expression.descriptor.containingDeclaration as ClassDescriptor).isInner -> 1 // skip the `$outer` parameter + callee is IrConstructor && callee.parentAsClass.isEnumClass -> 2 + callee is IrConstructor && callee.parentAsClass.isInner -> 1 // skip the `$outer` parameter else -> 0 } - expression.descriptor.valueParameters.forEachIndexed { i, parameterDescriptor -> + val typeParameters = if (callee is IrConstructor) + callee.parentAsClass.typeParameters + callee.typeParameters + else + callee.typeParameters + val typeArguments = (0 until typeParameters.size).map { expression.getTypeArgument(it)!! } + val typeSubstitutionMap = typeParameters.map { it.symbol }.zip(typeArguments).toMap() + expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter -> val arg = expression.getValueArgument(i) val parameterType = callable.valueParameterTypes[i] when { arg != null -> { - callGenerator.genValueAndPut(parameterDescriptor, arg, parameterType, i, this@ExpressionCodegen, data) + callGenerator.genValueAndPut(irParameter, arg, parameterType, i, this@ExpressionCodegen, data) } - parameterDescriptor.hasDefaultValue() -> { + irParameter.hasDefaultValue() -> { callGenerator.putValueIfNeeded( parameterType, StackValue.createDefaultValue(parameterType), @@ -358,12 +350,10 @@ class ExpressionCodegen( defaultMask.mark(i - extraArgsShift/*TODO switch to separate lower*/) } else -> { - assert(parameterDescriptor.varargElementType != null) - //empty vararg - - // Upper bound for type of vararg parameter should always have a form of 'Array', - // while its lower bound may be Nothing-typed after approximation - val type = typeMapper.mapType(parameterDescriptor.type.upperIfFlexible()) + assert(irParameter.varargElementType != null) + val type = typeMapper.mapType( + irParameter.type.substitute(typeSubstitutionMap) + ) callGenerator.putValueIfNeeded( parameterType, StackValue.operation(type) { @@ -378,17 +368,17 @@ class ExpressionCodegen( callGenerator.genCall( callable, - defaultMask.generateOnStackIfNeeded(callGenerator, expression.descriptor is ConstructorDescriptor, this), + defaultMask.generateOnStackIfNeeded(callGenerator, callee is IrConstructor, this), this, expression ) - val returnType = expression.descriptor.returnType - if (returnType != null && returnType.isNothing()) { + val returnType = callee.returnType.substitute(typeSubstitutionMap) + if (returnType.isNothing()) { mv.aconst(null) mv.athrow() return voidValue - } else if (expression.descriptor is ConstructorDescriptor) { + } else if (callee is IrConstructor) { return voidValue } else if (expression.type.isUnit()) { // NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail. @@ -398,7 +388,7 @@ class ExpressionCodegen( } override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue { - val varType = typeMapper.mapType(declaration.descriptor) + val varType = typeMapper.mapType(declaration) val index = frameMap.enter(declaration.symbol, varType) declaration.markLineNumber(startOffset = true) @@ -431,10 +421,10 @@ class ExpressionCodegen( return voidValue.coerce(expression.asmType) } - val realDescriptor = DescriptorUtils.unwrapFakeOverride(expression.descriptor) - val fieldType = typeMapper.mapType(realDescriptor.original.type) - val ownerType = typeMapper.mapImplementationOwner(expression.descriptor).internalName - val fieldName = expression.descriptor.name.asString() + val realField = expression.symbol.owner.resolveFakeOverride()!! + val fieldType = typeMapper.mapType(realField.type) + val ownerType = typeMapper.mapImplementationOwner(expression.symbol.owner).internalName + val fieldName = realField.name.asString() val isStatic = expression.receiver == null expression.markLineNumber(startOffset = true) expression.receiver?.accept(this, data)?.materialize() @@ -497,8 +487,8 @@ class ExpressionCodegen( override fun visitSetVariable(expression: IrSetVariable, data: BlockInfo): PromisedValue { expression.markLineNumber(startOffset = true) expression.value.markLineNumber(startOffset = true) - expression.value.accept(this, data).coerce(expression.descriptor.asmType).materialize() - mv.store(findLocalIndex(expression.symbol), expression.descriptor.asmType) + expression.value.accept(this, data).coerce(expression.symbol.owner.asmType).materialize() + mv.store(findLocalIndex(expression.symbol), expression.symbol.owner.asmType) return voidValue.coerce(expression.asmType) } @@ -547,7 +537,7 @@ class ExpressionCodegen( val hasSpread = arguments.firstIsInstanceOrNull() != null if (hasSpread) { - val arrayOfReferences = KotlinBuiltIns.isArray(outType.toKotlinType()) + val arrayOfReferences = outType.makeNotNull().isArray() if (size == 1) { // Arrays.copyOf(receiverValue, newLength) val argument = (arguments[0] as IrSpreadElement).expression @@ -595,7 +585,7 @@ class ExpressionCodegen( if (arrayOfReferences) { mv.dup() mv.invokevirtual(owner, "size", "()I", false) - newArrayInstruction(outType.toKotlinType()) + newArrayInstruction(outType) mv.invokevirtual(owner, "toArray", toArrayDescriptor, false) mv.checkcast(type) } else { @@ -604,7 +594,7 @@ class ExpressionCodegen( } } else { mv.iconst(size) - newArrayInstruction(expression.type.toKotlinType()) + newArrayInstruction(expression.type) for ((i, element) in expression.elements.withIndex()) { mv.dup() mv.iconst(i) @@ -615,16 +605,16 @@ class ExpressionCodegen( return expression.onStack } - fun newArrayInstruction(arrayType: KotlinType) { - if (KotlinBuiltIns.isArray(arrayType)) { - val elementKotlinType = arrayType.arguments[0].type + fun newArrayInstruction(arrayType: IrType) { + if (arrayType.isArray()) { + val elementIrType = arrayType.safeAs()!!.arguments[0].safeAs()!!.type putReifiedOperationMarkerIfTypeIsReifiedParameter( - elementKotlinType, + elementIrType, ReifiedTypeInliner.OperationKind.NEW_ARRAY, mv, this ) - mv.newarray(boxType(elementKotlinType.asmType)) + mv.newarray(boxType(elementIrType.asmType)) } else { val type = typeMapper.mapType(arrayType) mv.newarray(correctElementType(type)) @@ -634,10 +624,8 @@ class ExpressionCodegen( override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue { val owner = expression.returnTargetSymbol.owner //TODO: should be owner != irFunction - val isNonLocalReturn = state.typeMapper.mapFunctionName( - owner.descriptor, - OwnerKind.IMPLEMENTATION - ) != state.typeMapper.mapFunctionName(irFunction.descriptor, OwnerKind.IMPLEMENTATION) + val isNonLocalReturn = + typeMapper.mapFunctionName(owner, OwnerKind.IMPLEMENTATION) != typeMapper.mapFunctionName(irFunction, OwnerKind.IMPLEMENTATION) if (isNonLocalReturn && state.isInlineDisabled) { //TODO: state.diagnostics.report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression)) genThrow( @@ -647,7 +635,7 @@ class ExpressionCodegen( return voidValue } - val returnType = typeMapper.mapReturnType(owner.descriptor) + val returnType = typeMapper.mapReturnType(owner) val afterReturnLabel = Label() expression.value.accept(this, data).coerce(returnType).materialize() generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) @@ -697,8 +685,9 @@ class ExpressionCodegen( } override fun visitTypeOperator(expression: IrTypeOperatorCall, data: BlockInfo): PromisedValue { - val kotlinType = expression.typeOperand.toKotlinType() - val asmType = kotlinType.asmType + val typeOperand = expression.typeOperand + val asmType = typeOperand.asmType + val kotlinType = typeOperand.toKotlinType() return when (expression.operator) { IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { expression.argument.accept(this, data).discard() @@ -714,9 +703,9 @@ class ExpressionCodegen( expression.argument.accept(this, data).coerce(AsmTypes.OBJECT_TYPE).materialize() val boxedType = boxType(asmType) - if (TypeUtils.isReifiedTypeParameter(kotlinType)) { + if (typeOperand.isReifiedTypeParameter) { putReifiedOperationMarkerIfTypeIsReifiedParameter( - kotlinType, if (IrTypeOperator.SAFE_CAST == expression.operator) SAFE_AS else AS, mv, this + typeOperand, if (IrTypeOperator.SAFE_CAST == expression.operator) SAFE_AS else AS, mv, this ) v.checkcast(boxedType) } else { @@ -731,8 +720,8 @@ class ExpressionCodegen( IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> { expression.argument.accept(this, data).coerce(AsmTypes.OBJECT_TYPE).materialize() val type = boxType(asmType) - if (TypeUtils.isReifiedTypeParameter(kotlinType)) { - putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS, mv, this) + if (typeOperand.isReifiedTypeParameter) { + putReifiedOperationMarkerIfTypeIsReifiedParameter(typeOperand, ReifiedTypeInliner.OperationKind.IS, mv, this) v.instanceOf(type) } else { generateIsCheck(mv, kotlinType, type, state.languageVersionSettings.isReleaseCoroutines()) @@ -782,17 +771,17 @@ class ExpressionCodegen( // Convert single arg to string. val type = expression.arguments[0].accept(this, data).materialized.type if (!expression.arguments[0].type.isString()) - AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv) + AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper.kotlinTypeMapper).put(expression.asmType, mv) } arity == 2 && expression.arguments[0].type.isStringClassType() -> { // Call the stringPlus intrinsic expression.arguments.forEach { val type = it.accept(this, data).materialized.type if (type.sort != Type.OBJECT) - AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv) + AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper.kotlinTypeMapper).put(expression.asmType, mv) } mv.invokestatic( - IntrinsicMethods.INTRINSICS_CLASS_NAME, + IrIntrinsicMethods.INTRINSICS_CLASS_NAME, "stringPlus", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;", false @@ -897,8 +886,8 @@ class ExpressionCodegen( val catches = aTry.catches for (clause in catches) { val clauseStart = markNewLabel() - val descriptor = clause.parameter - val descriptorType = descriptor.asmType + val parameter = clause.catchParameter + val descriptorType = parameter.asmType val index = frameMap.enter(clause.catchParameter, descriptorType) mv.store(index, descriptorType) @@ -917,7 +906,7 @@ class ExpressionCodegen( val clauseEnd = markNewLabel() mv.visitLocalVariable( - descriptor.name.asString(), descriptorType.descriptor, null, clauseStart, clauseEnd, + parameter.name.asString(), descriptorType.descriptor, null, clauseStart, clauseEnd, index ) @@ -1025,16 +1014,17 @@ class ExpressionCodegen( } else if (classReference is IrClassReference) { val classType = classReference.classType if (classType is CrIrType) { - putJavaLangClassInstance(mv, classType.type, null, typeMapper) + putJavaLangClassInstance(mv, classType.type, null, typeMapper.kotlinTypeMapper) return classReference.onStack } else { val kotlinType = classType.toKotlinType() - if (TypeUtils.isTypeParameter(kotlinType)) { - assert(TypeUtils.isReifiedTypeParameter(kotlinType)) { "Non-reified type parameter under ::class should be rejected by type checker: " + kotlinType } - putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this) + val classifier = classType.classifierOrNull + if (classifier is IrTypeParameterSymbol) { + assert(classifier.owner.isReified) { "Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}" } + putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this) } - putJavaLangClassInstance(mv, typeMapper.mapType(kotlinType), kotlinType, typeMapper) + putJavaLangClassInstance(mv, typeMapper.mapType(classType), kotlinType, typeMapper.kotlinTypeMapper) } } else { throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}") @@ -1046,29 +1036,14 @@ class ExpressionCodegen( return classReference.onStack } - private fun resolveToCallable(irCall: IrMemberAccessExpression, isSuper: Boolean): Callable { - var descriptor = irCall.descriptor - if (descriptor is TypeAliasConstructorDescriptor) { - throw AssertionError("TypeAliasConstructorDescriptor should be unwrapped in psi2ir: $descriptor") - } - if (descriptor is PropertyDescriptor) { - descriptor = descriptor.getter!! - } - if (descriptor is CallableMemberDescriptor && JvmCodegenUtil.getDirectMember(descriptor) is SyntheticJavaPropertyDescriptor) { - val propertyDescriptor = JvmCodegenUtil.getDirectMember(descriptor) as SyntheticJavaPropertyDescriptor - descriptor = if (descriptor is PropertyGetterDescriptor) { - propertyDescriptor.getMethod - } else { - propertyDescriptor.setMethod!! - } - } - return typeMapper.mapToCallableMethod(descriptor as FunctionDescriptor, isSuper) + private fun resolveToCallable(irCall: IrFunctionAccessExpression, isSuper: Boolean): Callable { + return typeMapper.mapToCallableMethod(irCall.symbol.owner, isSuper) } private fun getOrCreateCallGenerator( - descriptor: CallableDescriptor, + irFunction: IrFunction, element: IrMemberAccessExpression?, - typeParameterMappings: TypeParameterMappings?, + typeParameterMappings: IrTypeParameterMappings?, isDefaultCompilation: Boolean, data: BlockInfo ): IrCallGenerator { @@ -1076,56 +1051,56 @@ class ExpressionCodegen( // We should inline callable containing reified type parameters even if inline is disabled // because they may contain something to reify and straight call will probably fail at runtime - val isInline = descriptor.isInlineCall(state) + val isInline = irFunction.isInlineCall(state) if (!isInline) return IrCallGenerator.DefaultCallGenerator - val original = unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride(descriptor.original as FunctionDescriptor)) + val original = (irFunction as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction return if (isDefaultCompilation) { TODO() } else { - IrInlineCodegen(this, state, original, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this, data)) + IrInlineCodegen(this, state, original.descriptor, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this, data)) } } private fun getOrCreateCallGenerator( - memberAccessExpression: IrMemberAccessExpression, - descriptor: CallableDescriptor, + functionAccessExpression: IrFunctionAccessExpression, data: BlockInfo ): IrCallGenerator { + val callee = functionAccessExpression.symbol.owner + val typeArgumentContainer = if (callee is IrConstructor) callee.parentAsClass else callee val typeArguments = - if (memberAccessExpression.typeArgumentsCount == 0) { + if (functionAccessExpression.typeArgumentsCount == 0) { //avoid ambiguity with type constructor type parameters emptyMap() - } else (descriptor.propertyIfAccessor as? CallableDescriptor)?.original?.typeParameters?.keysToMap { - memberAccessExpression.getTypeArgumentOrDefault(it) - } ?: emptyMap() + } else typeArgumentContainer.typeParameters.keysToMap { + functionAccessExpression.getTypeArgumentOrDefault(it) + } - val mappings = TypeParameterMappings() + val mappings = IrTypeParameterMappings() for (entry in typeArguments.entries) { val key = entry.key val type = entry.value - val isReified = key.isReified || InlineUtil.isArrayConstructorWithLambda(descriptor) + val isReified = key.isReified || callee.isArrayConstructorWithLambda() - val typeParameterAndReificationArgument = extractReificationArgument(type) - if (typeParameterAndReificationArgument == null) { - val approximatedType = approximateCapturedTypes(entry.value).upper + val reificationArgument = extractReificationArgument(type) + if (reificationArgument == null) { // type is not generic val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) - val asmType = typeMapper.mapTypeParameter(approximatedType, signatureWriter) + val asmType = typeMapper.mapTypeParameter(type, signatureWriter) mappings.addParameterMappingToType( - key.name.identifier, approximatedType, asmType, signatureWriter.toString(), isReified + key.name.identifier, type, asmType, signatureWriter.toString(), isReified ) } else { mappings.addParameterMappingForFurtherReification( - key.name.identifier, type, typeParameterAndReificationArgument.second, isReified + key.name.identifier, type, reificationArgument, isReified ) } } - return getOrCreateCallGenerator(descriptor, memberAccessExpression, mappings, false, data) + return getOrCreateCallGenerator(callee, functionAccessExpression, mappings, false, data) } override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) { @@ -1152,6 +1127,71 @@ class ExpressionCodegen( fun isFinallyMarkerRequired(): Boolean { return irFunction.isInline || isInlineLambda } + + /* Borrowed and modified from compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt */ + + private fun extractReificationArgumentWithParameter(initialType: IrType): Pair? { + var type = initialType + var arrayDepth = 0 + val isNullable = type.isMarkedNullable() + while (type.isArray() || type.isNullableArray()) { + arrayDepth++ + type = (type as IrSimpleType).arguments[0].safeAs()?.type ?: classCodegen.context.irBuiltIns.anyNType + } + + val parameter = type.getTypeParameterOrNull() ?: return null + + return Pair(parameter, IrReificationArgument(parameter.name.asString(), isNullable, arrayDepth)) + } + + private fun extractReificationArgument(initialType: IrType): IrReificationArgument? = extractReificationArgumentWithParameter(initialType)?.second + + /* From ReifiedTypeInliner.kt */ + inner class IrReificationArgument( + val parameterName: String, val nullable: Boolean, private val arrayDepth: Int + ) { + fun asString() = "[".repeat(arrayDepth) + parameterName + (if (nullable) "?" else "") + fun combine(replacement: IrReificationArgument) = + IrReificationArgument( + replacement.parameterName, + this.nullable || (replacement.nullable && this.arrayDepth == 0), + this.arrayDepth + replacement.arrayDepth + ) + + fun reify(replacementAsmType: Type, irType: IrType) = + Pair( + Type.getType("[".repeat(arrayDepth) + replacementAsmType), + irType.arrayOf(arrayDepth).withHasQuestionMark(nullable) + ) + + private fun IrType.arrayOf(arrayDepth: Int): IrType { + val builtins = classCodegen.context.irBuiltIns + var currentType = this + + repeat(arrayDepth) { + currentType = builtins.arrayClass.typeWith(currentType) + } + + return currentType + } + + fun toReificationArgument() = ReificationArgument(parameterName, nullable, arrayDepth) + } + + /* From ExpressionCodegen.java */ + private fun putReifiedOperationMarkerIfTypeIsReifiedParameter( + type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter, + codegen: BaseExpressionCodegen? + ) { + val typeParameterAndReificationArgument = extractReificationArgumentWithParameter(type) + if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.first.isReified) { + val irTypeParameter = typeParameterAndReificationArgument.first + codegen?.consumeReifiedOperationMarker(irTypeParameter.descriptor) + ReifiedTypeInliner.putReifiedOperationMarker( + operationKind, typeParameterAndReificationArgument.second.toReificationArgument(), v + ) + } + } } fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isConstructor: Boolean, codegen: ExpressionCodegen): Boolean { @@ -1173,6 +1213,80 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo return toInts.isNotEmpty() } -internal fun CallableDescriptor.isInlineCall(state: GenerationState) = - (!state.isInlineDisabled || InlineUtil.containsReifiedTypeParameters(this)) && - (InlineUtil.isInline(this) || InlineUtil.isArrayConstructorWithLambda(this)) +internal fun IrFunction.isInlineCall(state: GenerationState) = + (!state.isInlineDisabled || containsReifiedTypeParameters()) && + (isInline || isArrayConstructorWithLambda()) + +val IrType.isReifiedTypeParameter: Boolean + get() = this.classifierOrNull?.safeAs()?.owner?.isReified == true + +/* Copied and modified from InlineUtil.java */ +fun isInline(declaration: IrDeclaration?): Boolean = declaration is IrSimpleFunction && declaration.isInline + +fun IrFunction.containsReifiedTypeParameters(): Boolean = + typeParameters.any { it.isReified } + +fun IrClass.isArrayOrPrimitiveArray() = this.defaultType.let { it.isArray() || it.isPrimitiveArray() } + +/* From typeUtil.java */ +fun IrType.getTypeParameterOrNull() = classifierOrNull?.owner?.safeAs() + +/* From ReifiedTypeInliner.kt */ +class IrTypeParameterMappings { + private val mappingsByName = hashMapOf() + + fun addParameterMappingToType(name: String, type: IrType, asmType: Type, signature: String, isReified: Boolean) { + mappingsByName[name] = IrTypeParameterMapping( + name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified + ) + } + + fun addParameterMappingForFurtherReification( + name: String, + type: IrType, + reificationArgument: ExpressionCodegen.IrReificationArgument, + isReified: Boolean + ) { + mappingsByName[name] = IrTypeParameterMapping( + name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified + ) + } + + operator fun get(name: String): IrTypeParameterMapping? = mappingsByName[name] + + fun hasReifiedParameters() = mappingsByName.values.any { it.isReified } + + internal inline fun forEach(l: (IrTypeParameterMapping) -> Unit) { + mappingsByName.values.forEach(l) + } + + fun toTypeParameterMappings() = TypeParameterMappings().also { result -> + mappingsByName.forEach { (_, value) -> + if (value.asmType == null) { + result.addParameterMappingForFurtherReification( + value.name, + value.type.toKotlinType(), + value.reificationArgument!!.toReificationArgument(), + value.isReified + ) + } else { + result.addParameterMappingToType( + value.name, + value.type.toKotlinType(), + value.asmType, + value.signature!!, + value.isReified + ) + } + } + } +} + +class IrTypeParameterMapping( + val name: String, + val type: IrType, + val asmType: Type?, + val reificationArgument: ExpressionCodegen.IrReificationArgument?, + val signature: String?, + val isReified: Boolean +) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index cafca049605..d88ee5dc518 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -7,14 +7,14 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.FunctionCodegen import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.types.toKotlinType -import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.util.getAnnotation +import org.jetbrains.kotlin.ir.util.hasAnnotation +import org.jetbrains.kotlin.ir.util.isAnnotationClass import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature @@ -33,8 +33,6 @@ open class FunctionCodegen( val state = classCodegen.state - val descriptor = irFunction.descriptor - fun generate(): JvmMethodGenericSignature = try { doGenerate() @@ -43,23 +41,26 @@ open class FunctionCodegen( } private fun doGenerate(): JvmMethodGenericSignature { - val signature = classCodegen.typeMapper.mapSignatureWithGeneric(descriptor, OwnerKind.IMPLEMENTATION) + val signature = classCodegen.typeMapper.mapSignatureWithGeneric(irFunction, OwnerKind.IMPLEMENTATION) val flags = calculateMethodFlags(irFunction.isStatic) val methodVisitor = createMethod(flags, signature) - generateParameterNames(descriptor, methodVisitor, signature, state, flags.and(Opcodes.ACC_SYNTHETIC) != 0) + generateParameterNames(irFunction.descriptor, methodVisitor, signature, state, flags.and(Opcodes.ACC_SYNTHETIC) != 0) if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) { - AnnotationCodegen(classCodegen, state, methodVisitor::visitAnnotation).genAnnotations(irFunction, signature.asmMethod.returnType) - FunctionCodegen.generateParameterAnnotations(descriptor, methodVisitor, signature, DummyOldInnerClassConsumer(), state) + AnnotationCodegen(classCodegen, state, methodVisitor::visitAnnotation).genAnnotations( + irFunction, + signature.asmMethod.returnType + ) + generateParameterAnnotations(irFunction, methodVisitor, signature, classCodegen, state) } if (!state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) { generateAnnotationDefaultValueIfNeeded(methodVisitor) methodVisitor.visitEnd() } else { - val frameMap = createFrameMapWithReceivers(classCodegen.state, irFunction, signature) + val frameMap = createFrameMapWithReceivers(signature) ExpressionCodegen(irFunction, frameMap, InstructionAdapter(methodVisitor), classCodegen, isInlineLambda).generate() } @@ -102,7 +103,7 @@ open class FunctionCodegen( // @Throws(vararg exceptionClasses: KClass) val exceptions = irFunction.getAnnotation(FqName("kotlin.jvm.Throws"))?.getValueArgument(0)?.let { (it as IrVararg).elements.map { exceptionClass -> - classCodegen.typeMapper.mapType((exceptionClass as IrClassReference).classType.toKotlinType()).internalName + classCodegen.typeMapper.mapType((exceptionClass as IrClassReference).classType).internalName }.toTypedArray() } @@ -127,7 +128,7 @@ open class FunctionCodegen( // TODO: any simpler way to get to the value expression? // Are there other valid IR structures that represent the default value? return irFunction.safeAs() - ?.correspondingProperty + ?.correspondingPropertySymbol?.owner ?.backingField ?.initializer.safeAs() ?.expression?.safeAs() @@ -135,46 +136,95 @@ open class FunctionCodegen( ?.defaultValue?.safeAs() ?.expression } -} -private fun createFrameMapWithReceivers( - state: GenerationState, - irFunction: IrFunction, - signature: JvmMethodSignature -): IrFrameMap { - val frameMap = IrFrameMap() - if (irFunction is IrConstructor) { - frameMap.enter((irFunction.parent as IrClass).thisReceiver!!, AsmTypes.OBJECT_TYPE) - } else if (irFunction.dispatchReceiverParameter != null) { - frameMap.enter(irFunction.dispatchReceiverParameter!!, AsmTypes.OBJECT_TYPE) - } + private fun createFrameMapWithReceivers(signature: JvmMethodSignature): IrFrameMap { + val frameMap = IrFrameMap() + if (irFunction is IrConstructor) { + frameMap.enter((irFunction.parent as IrClass).thisReceiver!!, AsmTypes.OBJECT_TYPE) + } else if (irFunction.dispatchReceiverParameter != null) { + frameMap.enter(irFunction.dispatchReceiverParameter!!, AsmTypes.OBJECT_TYPE) + } - for (parameter in signature.valueParameters) { - if (parameter.kind == JvmMethodParameterKind.RECEIVER) { - val receiverParameter = irFunction.extensionReceiverParameter - if (receiverParameter?.descriptor != null) { - frameMap.enter(receiverParameter, state.typeMapper.mapType(receiverParameter.descriptor)) - } else { + for (parameter in signature.valueParameters) { + if (parameter.kind == JvmMethodParameterKind.RECEIVER) { + val receiverParameter = irFunction.extensionReceiverParameter + if (receiverParameter != null) { + frameMap.enter(receiverParameter, classCodegen.typeMapper.mapType(receiverParameter)) + } else { + frameMap.enterTemp(parameter.asmType) + } + } else if (parameter.kind != JvmMethodParameterKind.VALUE) { frameMap.enterTemp(parameter.asmType) } - } else if (parameter.kind != JvmMethodParameterKind.VALUE) { - frameMap.enterTemp(parameter.asmType) } - } - for (parameter in irFunction.valueParameters) { - frameMap.enter(parameter, state.typeMapper.mapType(parameter.type.toKotlinType())) - } + for (parameter in irFunction.valueParameters) { + frameMap.enter(parameter, classCodegen.typeMapper.mapType(parameter.type)) + } - return frameMap + return frameMap + } } -/**/// TODO: temporary, to allow calling the old FunctionCodegen.generateParameterAnnotations -private class DummyOldInnerClassConsumer() - : org.jetbrains.kotlin.codegen.InnerClassConsumer { - - override fun addInnerClassInfoFromAnnotation(classDescriptor: ClassDescriptor) { - +// Borrowed from org.jetbrains.kotlin.codegen.FunctionCodegen.java +fun generateParameterAnnotations( + irFunction: IrFunction, + mv: MethodVisitor, + jvmSignature: JvmMethodSignature, + innerClassConsumer: InnerClassConsumer, + state: GenerationState +) { + val iterator = irFunction.valueParameters.iterator() + val kotlinParameterTypes = jvmSignature.valueParameters + var syntheticParameterCount = 0 + kotlinParameterTypes.forEachIndexed { i, parameterSignature -> + val kind = parameterSignature.kind + if (kind.isSkippedInGenericSignature) { + if (AsmUtil.IS_BUILT_WITH_ASM6) { + markEnumOrInnerConstructorParameterAsSynthetic(mv, i, state.classBuilderMode) + } else { + syntheticParameterCount++ + } + } + } + if (!AsmUtil.IS_BUILT_WITH_ASM6) { + visitAnnotableParameterCount(mv, kotlinParameterTypes.size - syntheticParameterCount) } -} \ No newline at end of file + kotlinParameterTypes.forEachIndexed { i, parameterSignature -> + val kind = parameterSignature.kind + if (kind.isSkippedInGenericSignature) return@forEachIndexed + + val annotated = when (kind) { + JvmMethodParameterKind.VALUE -> iterator.next() + JvmMethodParameterKind.RECEIVER -> irFunction.extensionReceiverParameter + else -> null + } + + if (annotated != null) { + + AnnotationCodegen( + innerClassConsumer, + state + ) { descriptor, visible -> + mv.visitParameterAnnotation( + if (AsmUtil.IS_BUILT_WITH_ASM6) i else i - syntheticParameterCount, + descriptor, + visible + ) + } + .genAnnotations(annotated, parameterSignature.asmType) + } + } +} + +private fun markEnumOrInnerConstructorParameterAsSynthetic(mv: MethodVisitor, i: Int, mode: ClassBuilderMode) { + // IDEA's ClsPsi builder fails to annotate synthetic parameters + if (mode === ClassBuilderMode.LIGHT_CLASSES) return + + // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac: + // see MethodWriter.visitParameterAnnotation() + + val av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true) + av?.visitEnd() +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt index 39657003d3d..501e3a0682f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt @@ -20,14 +20,14 @@ import org.jetbrains.kotlin.codegen.Callable import org.jetbrains.kotlin.codegen.CallableMethod import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.ValueKind -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.org.objectweb.asm.Type interface IrCallGenerator { - fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen, expression: IrMemberAccessExpression) { + fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen, expression: IrFunctionAccessExpression) { if (!callDefault) { callableMethod.genInvokeInstruction(codegen.mv) } else { @@ -40,7 +40,7 @@ interface IrCallGenerator { } fun genValueAndPut( - valueParameterDescriptor: ValueParameterDescriptor?, + irValueParameter: IrValueParameter?, argumentExpression: IrExpression, parameterType: Type, parameterIndex: Int, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 4458ebfcdef..7b0caa71e36 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -6,19 +6,15 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlineParameter import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.Method @@ -27,9 +23,10 @@ class IrInlineCodegen( codegen: ExpressionCodegen, state: GenerationState, function: FunctionDescriptor, - typeParameterMappings: TypeParameterMappings, + typeParameterMappings: IrTypeParameterMappings, sourceCompiler: SourceCompilerForInline -) : InlineCodegen(codegen, state, function, typeParameterMappings, sourceCompiler), IrCallGenerator { +) : InlineCodegen(codegen, state, function, typeParameterMappings.toTypeParameterMappings(), sourceCompiler), + IrCallGenerator { override fun generateAssertFieldIfNeeded(info: RootInliningContext) { // TODO: JVM assertions are not implemented yet in IR backend } @@ -45,19 +42,19 @@ class IrInlineCodegen( } override fun genValueAndPut( - valueParameterDescriptor: ValueParameterDescriptor?, + irValueParameter: IrValueParameter?, argumentExpression: IrExpression, parameterType: Type, parameterIndex: Int, codegen: ExpressionCodegen, blockInfo: BlockInfo ) { - if (valueParameterDescriptor?.let { isInlineParameter(it) } == true && isInlineIrExpression(argumentExpression)) { + if (irValueParameter?.isInlineParameter() == true && isInlineIrExpression(argumentExpression)) { val irReference: IrFunctionReference = (argumentExpression as IrBlock).statements.filterIsInstance().single() - rememberClosure(irReference, parameterType, valueParameterDescriptor) as IrExpressionLambdaImpl + rememberClosure(irReference, parameterType, irValueParameter) as IrExpressionLambdaImpl } else { - putValueOnStack(argumentExpression, parameterType, valueParameterDescriptor?.index ?: -1) + putValueOnStack(argumentExpression, parameterType, irValueParameter?.index ?: -1) } } @@ -89,12 +86,17 @@ class IrInlineCodegen( invocationParamBuilder.markValueParametersStart() } - override fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen, expression: IrMemberAccessExpression) { + override fun genCall( + callableMethod: Callable, + callDefault: Boolean, + codegen: ExpressionCodegen, + expression: IrFunctionAccessExpression + ) { val typeArguments = expression.descriptor.typeParameters.keysToMap { expression.getTypeArgumentOrDefault(it) } performInline(typeArguments, callDefault, codegen) } - private fun rememberClosure(irReference: IrFunctionReference, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { + private fun rememberClosure(irReference: IrFunctionReference, type: Type, parameter: IrValueParameter): LambdaInfo { //assert(InlineUtil.isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } val expression = irReference.symbol.owner return IrExpressionLambdaImpl( @@ -160,13 +162,5 @@ fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) = (!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && (isInline || isArrayConstructorWithLambda()) -private fun IrFunction.isArrayConstructorWithLambda() = - valueParameters.size == 2 && - this is IrConstructor && - parentAsClass.let { - it.getPackageFragment()?.fqName?.asString() == "kotlin" && - it.name.asString().endsWith("Array") - } - fun IrValueParameter.isInlineParameter() = !isNoinline && !type.isNullable() && type.isFunctionOrKFunction() \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt new file mode 100644 index 00000000000..784e5a25052 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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.backend.jvm.codegen + +import org.jetbrains.kotlin.codegen.OwnerKind +import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall + +class IrTypeMapper(val kotlinTypeMapper: KotlinTypeMapper) { + + val classBuilderMode get() = kotlinTypeMapper.classBuilderMode + + fun classInternalName(irClass: IrClass) = kotlinTypeMapper.classInternalName(irClass.descriptor) + + fun mapAsmMethod(irFunction: IrFunction) = kotlinTypeMapper.mapAsmMethod(irFunction.descriptor) + + fun mapClass(irClass: IrClass) = kotlinTypeMapper.mapClass(irClass.descriptor) + + fun mapFieldSignature(irType: IrType, irFrield: IrField) = + kotlinTypeMapper.mapFieldSignature(irType.toKotlinType(), irFrield.descriptor) + + fun mapFunctionName(irReturnTarget: IrReturnTarget, ownerKind: OwnerKind) = + kotlinTypeMapper.mapFunctionName(irReturnTarget.descriptor, ownerKind) + + fun mapImplementationOwner(irDeclaration: IrDeclaration) = kotlinTypeMapper.mapImplementationOwner(irDeclaration.descriptor) + + fun mapReturnType(irReturnTarget: IrReturnTarget) = kotlinTypeMapper.mapReturnType(irReturnTarget.descriptor) + + fun mapSignatureSkipGeneric(f: IrFunction, kind: OwnerKind = OwnerKind.IMPLEMENTATION) = + kotlinTypeMapper.mapSignatureSkipGeneric(f.descriptor, kind) + + fun mapSignatureWithGeneric(f: IrFunction, kind: OwnerKind) = kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, kind) + + fun mapSupertype(irType: IrType, sw: JvmSignatureWriter) = kotlinTypeMapper.mapSupertype(irType.toKotlinType(), sw) + + fun mapToCallableMethod(f: IrFunction, superCall: Boolean, kind: OwnerKind? = null, resolvedCall: ResolvedCall<*>? = null) = + kotlinTypeMapper.mapToCallableMethod(f.descriptor, superCall, kind, resolvedCall) + + fun mapType(irType: IrType) = kotlinTypeMapper.mapType(irType.toKotlinType()) + + fun mapType(irClass: IrClass) = kotlinTypeMapper.mapType(irClass.descriptor) + + fun mapType(irField: IrField) = kotlinTypeMapper.mapType(irField.descriptor) + + fun mapType(irValueParameter: IrValueParameter) = kotlinTypeMapper.mapType(irValueParameter.descriptor) + + fun mapType(irVariable: IrVariable) = kotlinTypeMapper.mapType(irVariable.descriptor) + + fun mapType(irType: IrType, sw: JvmSignatureWriter, mode: TypeMappingMode) = + kotlinTypeMapper.mapType(irType.toKotlinType(), sw, mode) + + fun mapTypeParameter(irType: IrType, signatureWriter: JvmSignatureWriter) = + kotlinTypeMapper.mapTypeParameter(irType.toKotlinType(), signatureWriter) + + fun writeFormalTypeParameters(irParameters: List, sw: JvmSignatureWriter) = + kotlinTypeMapper.writeFormalTypeParameters(irParameters.map { it.descriptor }, sw) +} \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index 76a5953512f..a09f7f6c551 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -6,18 +6,42 @@ package org.jetbrains.kotlin.backend.jvm.codegen import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.codegen.FrameMapBase -import org.jetbrains.kotlin.codegen.SourceInfo +import org.jetbrains.kotlin.backend.jvm.lower.allOverridden +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap +import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.AsmUtil.LABELED_THIS_PARAMETER +import org.jetbrains.kotlin.codegen.AsmUtil.RECEIVER_PARAMETER_NAME import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.util.isAnnotationClass -import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.load.java.JavaVisibilities +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.source.PsiSourceElement +import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.org.objectweb.asm.MethodVisitor +import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type -import java.io.File +import java.util.ArrayList +import java.util.LinkedHashSet class IrFrameMap : FrameMapBase() @@ -61,3 +85,371 @@ fun JvmBackendContext.getSourceMapper(declaration: IrClass): DefaultSourceMapper ) ) } + +val IrType.isExtensionFunctionType: Boolean + get() = isFunctionTypeOrSubtype() && hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) + +/** + * @return true if the function is a constructor of one of 9 array classes (Array<T>, IntArray, FloatArray, ...) + * which takes the size and an initializer lambda as parameters. Such constructors are marked as 'inline' but they are not loaded + * as such because the 'inline' flag is not stored for constructors in the binary metadata. Therefore we pretend that they are inline + */ +fun IrFunction.isArrayConstructorWithLambda(): Boolean = this is IrConstructor && + valueParameters.size == 2 && + parentAsClass.isArrayOrPrimitiveArray() + + +/* Borrowed from MemberCodegen.java */ + +fun writeInnerClass(innerClass: IrClass, typeMapper: IrTypeMapper, context: JvmBackendContext, v: ClassBuilder) { + val outerClassInternalName = innerClass.parent.safeAs()?.let { typeMapper.classInternalName(it) } + /* TODO: So long as the type mapper works by descriptors, the internal name should be consistent with it. */ + val outerClassInternalNameByDescriptor = innerClass.descriptor.containingDeclaration.safeAs()?.let { + typeMapper.kotlinTypeMapper.classInternalName(it) + } + val innerName = innerClass.name.takeUnless { it.isSpecial }?.asString() + val innerClassInternalName = typeMapper.classInternalName(innerClass) + v.visitInnerClass(innerClassInternalName, outerClassInternalNameByDescriptor, innerName, innerClass.calculateInnerClassAccessFlags(context)) +} + +/* Borrowed with modifications from AsmUtil.java */ + +private val NO_FLAG_LOCAL = 0 + +private val visibilityToAccessFlag = mapOf( + Visibilities.PRIVATE to Opcodes.ACC_PRIVATE, + Visibilities.PRIVATE_TO_THIS to Opcodes.ACC_PRIVATE, + Visibilities.PROTECTED to Opcodes.ACC_PROTECTED, + JavaVisibilities.PROTECTED_STATIC_VISIBILITY to Opcodes.ACC_PROTECTED, + JavaVisibilities.PROTECTED_AND_PACKAGE to Opcodes.ACC_PROTECTED, + Visibilities.PUBLIC to Opcodes.ACC_PUBLIC, + Visibilities.INTERNAL to Opcodes.ACC_PUBLIC, + Visibilities.LOCAL to NO_FLAG_LOCAL, + JavaVisibilities.PACKAGE_VISIBILITY to AsmUtil.NO_FLAG_PACKAGE_PRIVATE +) + +private fun IrDeclaration.getVisibilityAccessFlagForAnonymous(): Int = + if (isInlineOrContainedInInline(parent as? IrDeclaration)) Opcodes.ACC_PUBLIC else AsmUtil.NO_FLAG_PACKAGE_PRIVATE + +fun IrClass.calculateInnerClassAccessFlags(context: JvmBackendContext): Int { + val isLambda = superTypes.any { it.safeAs()?.classifier === context.ir.symbols.lambdaClass } + val visibility = when { + isLambda -> getVisibilityAccessFlagForAnonymous() + visibility === Visibilities.LOCAL -> Opcodes.ACC_PUBLIC + else -> getVisibilityAccessFlag() + } + return visibility or + if (origin.isSynthetic) Opcodes.ACC_SYNTHETIC else 0 or + innerAccessFlagsForModalityAndKind() or + if (isInner) 0 else Opcodes.ACC_STATIC +} + +private fun IrClass.innerAccessFlagsForModalityAndKind(): Int { + when (kind) { + ClassKind.INTERFACE -> return Opcodes.ACC_ABSTRACT or Opcodes.ACC_INTERFACE + ClassKind.ENUM_CLASS -> return Opcodes.ACC_FINAL or Opcodes.ACC_ENUM + ClassKind.ANNOTATION_CLASS -> return Opcodes.ACC_ABSTRACT or Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE + else -> { + if (modality === Modality.FINAL) { + return Opcodes.ACC_FINAL + } else if (modality === Modality.ABSTRACT || modality === Modality.SEALED) { + return Opcodes.ACC_ABSTRACT + } + } + } + return 0 +} + +private fun IrDeclarationWithVisibility.getVisibilityAccessFlag(kind: OwnerKind? = null): Int = + specialCaseVisibility(kind) + ?: visibilityToAccessFlag[visibility] + ?: throw IllegalStateException("$visibility is not a valid visibility in backend for ${ir2string(this)}") + + +private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?): Int? { +// if (JvmCodegenUtil.isNonIntrinsicPrivateCompanionObjectInInterface(memberDescriptor)) { +// return ACC_PUBLIC +// } + if (this is IrClass && Visibilities.isPrivate(visibility) && + parent.safeAs()?.isInterface ?: false) { // TODO: non-intrinsic + return Opcodes.ACC_PUBLIC + } + +// if (memberDescriptor is FunctionDescriptor && isInlineClassWrapperConstructor(memberDescriptor, kind)) + if (this is IrConstructor && parentAsClass.isInline && kind === OwnerKind.IMPLEMENTATION) { + return Opcodes.ACC_PRIVATE + } + +// if (kind !== OwnerKind.ERASED_INLINE_CLASS && +// memberDescriptor is ConstructorDescriptor && +// memberDescriptor !is AccessorForConstructorDescriptor && +// shouldHideConstructorDueToInlineClassTypeValueParameters(memberDescriptor) +// ) { + if (kind !== OwnerKind.ERASED_INLINE_CLASS && + this is IrConstructor && + shouldHideDueToInlineClassTypeValueParameters() + ) { + return Opcodes.ACC_PRIVATE + } + +// if (memberDescriptor.isEffectivelyInlineOnly()) { + if (isEffectivelyInlineOnly()) { + return Opcodes.ACC_PRIVATE + } + +// if (memberVisibility === Visibilities.LOCAL && memberDescriptor is CallableMemberDescriptor) { + if (visibility === Visibilities.LOCAL && this is IrFunction) { + return Opcodes.ACC_PUBLIC + } + +// if (isEnumEntry(memberDescriptor)) { + if (this is IrClass && this.kind === ClassKind.ENUM_ENTRY) { + return AsmUtil.NO_FLAG_PACKAGE_PRIVATE + } + +// These ones should be public anyway after ToArrayLowering. +// if (memberDescriptor.isToArrayFromCollection()) { +// return ACC_PUBLIC +// } + +// if (memberDescriptor is ConstructorDescriptor && isAnonymousObject(memberDescriptor.containingDeclaration)) { +// return getVisibilityAccessFlagForAnonymous(memberDescriptor.containingDeclaration as ClassDescriptor) +// } + if (this is IrConstructor && parentAsClass.isAnonymousObject) { + return parentAsClass.getVisibilityAccessFlagForAnonymous() + } + +// TODO: when is this applicable? +// if (memberDescriptor is SyntheticJavaPropertyDescriptor) { +// return getVisibilityAccessFlag((memberDescriptor as SyntheticJavaPropertyDescriptor).getMethod) +// } + + +// if (memberDescriptor is PropertyAccessorDescriptor) { +// val property = memberDescriptor.correspondingProperty +// if (property is SyntheticJavaPropertyDescriptor) { +// val method = (if (memberDescriptor === property.getGetter()) +// (property as SyntheticJavaPropertyDescriptor).getMethod +// else +// (property as SyntheticJavaPropertyDescriptor).setMethod) +// ?: error("No get/set method in SyntheticJavaPropertyDescriptor: $property") +// return getVisibilityAccessFlag(method) +// } +// } + if (this is IrField && correspondingPropertySymbol?.owner?.isExternal == true) { + val method = correspondingPropertySymbol?.owner?.getter ?: correspondingPropertySymbol?.owner?.setter + ?: error("No get/set method in SyntheticJavaPropertyDescriptor: ${ir2string(correspondingPropertySymbol?.owner)}") + return method.getVisibilityAccessFlag() + } + +// if (memberDescriptor is CallableDescriptor && memberVisibility === Visibilities.PROTECTED) { +// for (overridden in DescriptorUtils.getAllOverriddenDescriptors(memberDescriptor as CallableDescriptor)) { +// if (isJvmInterface(overridden.containingDeclaration)) { +// return ACC_PUBLIC +// } +// } +// } + if (this is IrSimpleFunction && visibility === Visibilities.PROTECTED && + allOverridden().any { it.parentAsClass.isJvmInterface } + ) { + return Opcodes.ACC_PUBLIC + } + + if (!Visibilities.isPrivate(visibility)) { + return null + } + + if (this is IrSimpleFunction && isSuspend) { + return AsmUtil.NO_FLAG_PACKAGE_PRIVATE + } + +// Should be taken care of in IR +// if (memberDescriptor is AccessorForCompanionObjectInstanceFieldDescriptor) { +// return NO_FLAG_PACKAGE_PRIVATE +// } + +// return if (memberDescriptor is ConstructorDescriptor && isEnumEntry(containingDeclaration)) { +// NO_FLAG_PACKAGE_PRIVATE +// } else null + if (this is IrConstructor && parentAsClass.kind === ClassKind.ENUM_ENTRY) { + return AsmUtil.NO_FLAG_PACKAGE_PRIVATE + } + + return null +} + +/* From inlineClassManglingRules.kt */ +fun IrConstructor.shouldHideDueToInlineClassTypeValueParameters() = + !Visibilities.isPrivate(visibility) && + !parentAsClass.isInline && + parentAsClass.modality !== Modality.SEALED && + valueParameters.any { it.type.requiresFunctionNameMangling() } + +fun IrType.requiresFunctionNameMangling(): Boolean = + isInlineClassThatRequiresMangling() || isTypeParameterWithUpperBoundThatRequiresMangling() + +fun IrType.isInlineClassThatRequiresMangling() = + safeAs()?.classifier?.owner?.safeAs()?.let { + it.isInline && !it.isDontMangleClass() + } ?: false + +fun IrClass.isDontMangleClass() = + fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME + +fun IrType.isTypeParameterWithUpperBoundThatRequiresMangling() = + safeAs()?.classifier?.owner.safeAs()?.let { param -> + param.superTypes.any { it.requiresFunctionNameMangling() } + } ?: false + + +/* Borrowed from InlineUtil. */ +private tailrec fun isInlineOrContainedInInline(declaration: IrDeclaration?): Boolean = when { + declaration === null -> false + declaration is IrFunction && declaration.isInline -> true + else -> isInlineOrContainedInInline(declaration.parent as? IrDeclaration) +} + +/* Borrowed from inlineOnly.kt */ + +private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly") + +fun IrDeclarationWithVisibility.isInlineOnlyOrReifiable(): Boolean = + this is IrFunction && (isReifiable() || isInlineOnly()) + +fun IrDeclarationWithVisibility.isEffectivelyInlineOnly(): Boolean = + isInlineOnlyOrReifiable() || + (this is IrSimpleFunction && isSuspend && isInline && + (valueParameters.any { it.isCrossinline } || visibility === Visibilities.PRIVATE)) + +private fun IrFunction.isInlineOnly() = + isInline && hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME) + +private fun IrFunction.isReifiable() = typeParameters.any { it.isReified } + + +// Borrowed with modifications from ImplementationBodyCodegen.java + +private val KOTLIN_MARKER_INTERFACES: Map = run { + val kotlinMarkerInterfaces = mutableMapOf() + for (platformMutabilityMapping in JavaToKotlinClassMap.mutabilityMappings) { + kotlinMarkerInterfaces[platformMutabilityMapping.kotlinReadOnly.asSingleFqName()] = "kotlin/jvm/internal/markers/KMappedMarker" + + val mutableClassId = platformMutabilityMapping.kotlinMutable + kotlinMarkerInterfaces[mutableClassId.asSingleFqName()] = + "kotlin/jvm/internal/markers/K" + mutableClassId.relativeClassName.asString() + .replace("MutableEntry", "Entry") // kotlin.jvm.internal.markers.KMutableMap.Entry for some reason + .replace(".", "$") + } + kotlinMarkerInterfaces +} + +internal class IrSuperClassInfo(val type: Type, val irType: IrType?) + +internal fun getSignature( + irClass: IrClass, + classAsmType: Type, + superClassInfo: IrSuperClassInfo, + typeMapper: IrTypeMapper +): JvmClassSignature { + val sw = BothSignatureWriter(BothSignatureWriter.Mode.CLASS) + + typeMapper.writeFormalTypeParameters(irClass.typeParameters, sw) + + sw.writeSuperclass() + val irType = superClassInfo.irType + if (irType == null) { + sw.writeClassBegin(superClassInfo.type) + sw.writeClassEnd() + } else { + typeMapper.mapSupertype(irType, sw) + } + sw.writeSuperclassEnd() + + val superInterfaces = LinkedHashSet() + val kotlinMarkerInterfaces = LinkedHashSet() + + for (superType in irClass.superTypes) { + val superClass = superType.safeAs()?.classifier?.safeAs()?.owner ?: continue + if (superClass.isJvmInterface) { + val kotlinInterfaceName = superClass.fqNameWhenAvailable!! + + sw.writeInterface() + val jvmInterfaceType = typeMapper.mapSupertype(superType, sw) + sw.writeInterfaceEnd() + val jvmInterfaceInternalName = jvmInterfaceType.internalName + + superInterfaces.add(jvmInterfaceInternalName) + + val kotlinMarkerInterfaceInternalName = KOTLIN_MARKER_INTERFACES.get(kotlinInterfaceName) + if (kotlinMarkerInterfaceInternalName != null) { + if (typeMapper.classBuilderMode === ClassBuilderMode.LIGHT_CLASSES) { + sw.writeInterface() + val kotlinCollectionType = + typeMapper.mapType(superClass.defaultType, sw, TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS) + sw.writeInterfaceEnd() + superInterfaces.add(kotlinCollectionType.internalName) + } + + kotlinMarkerInterfaces.add(kotlinMarkerInterfaceInternalName) + } + } + } + + for (kotlinMarkerInterface in kotlinMarkerInterfaces) { + sw.writeInterface() + sw.writeAsmType(Type.getObjectType(kotlinMarkerInterface)) + sw.writeInterfaceEnd() + } + + superInterfaces.addAll(kotlinMarkerInterfaces) + + return JvmClassSignature( + classAsmType.internalName, superClassInfo.type.internalName, + ArrayList(superInterfaces), sw.makeJavaGenericSignature() + ) +} + +/* Copied with modifications from AsmUtil.getVisibilityAccessFlagForClass */ +/* + Use this method to get visibility flag for class to define it in byte code (v.defineClass method). + For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor) + Classes in byte code should be public or package private +*/ +fun IrClass.getVisibilityAccessFlagForClass(): Int { + /* Original had a check for SyntheticClassDescriptorForJava, never invoked in th IR backend. */ + if (isOptionalAnnotationClass()) { + return AsmUtil.NO_FLAG_PACKAGE_PRIVATE + } + if (kind == ClassKind.ENUM_ENTRY) { + return AsmUtil.NO_FLAG_PACKAGE_PRIVATE + } + return if (visibility === Visibilities.PUBLIC || + visibility === Visibilities.PROTECTED || + // TODO: should be package private, but for now Kotlin's reflection can't access members of such classes + visibility === Visibilities.LOCAL || + visibility === Visibilities.INTERNAL + ) { + Opcodes.ACC_PUBLIC + } else AsmUtil.NO_FLAG_PACKAGE_PRIVATE +} + +/* Borrowed and translated from ExpectedActualDeclarationChecker */ +// TODO: Descriptor-based code also checks for `descriptor.isExpect`; we don't represent expect/actual distinction in IR thus far. +fun IrClass.isOptionalAnnotationClass(): Boolean = + isAnnotationClass && + hasAnnotation(ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME) + +//@JvmOverloads +//fun OtherOriginForIr(element: PsiElement?, descriptor: DeclarationDescriptor? = null) = +// if (element == null && descriptor == null) +// JvmDeclarationOrigin.NO_ORIGIN +// else +// object : JvmDeclarationOrigin(JvmDeclarationOriginKind.OTHER, element, descriptor) { +// override val element get() = +// error("Access to PsiElement") +// override val descriptor get() = +// error("Access to descriptor") +// } + +// JvmDeclarationOrigin(OTHER, element, descriptor) + diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/ArrayIterator.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/ArrayIterator.kt index b144fa40329..7ef48314d01 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/ArrayIterator.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/ArrayIterator.kt @@ -18,21 +18,23 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.codegen.AsmUtil -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature object ArrayIterator : IntrinsicMethod() { - override fun toCallable(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction { - val method = context.state.typeMapper.mapToCallableMethod(expression.descriptor as FunctionDescriptor, false) + override fun toCallable( + expression: IrFunctionAccessExpression, + signature: JvmMethodSignature, + context: JvmBackendContext + ): IrIntrinsicFunction { + val method = context.state.typeMapper.mapToCallableMethod(expression.descriptor, false) return IrIntrinsicFunction.create(expression, signature, context, method.owner) { val methodSignature = "(${method.owner.descriptor})${method.returnType.descriptor}" val intrinsicOwner = - if (AsmUtil.isPrimitive(method.owner.elementType)) - "kotlin/jvm/internal/ArrayIteratorsKt" - else - "kotlin/jvm/internal/ArrayIteratorKt" + if (AsmUtil.isPrimitive(method.owner.elementType)) + "kotlin/jvm/internal/ArrayIteratorsKt" + else + "kotlin/jvm/internal/ArrayIteratorKt" it.invokestatic(intrinsicOwner, "iterator", methodSignature, false) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt index 48670ac2a32..224b9043a1f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt @@ -88,7 +88,7 @@ class PrimitiveComparison( private val operatorToken: KtSingleValueToken ) : IntrinsicMethod() { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { - val parameterType = codegen.typeMapper.mapType(primitiveNumberType) + val parameterType = codegen.typeMapper.kotlinTypeMapper.mapType(primitiveNumberType) val (left, right) = expression.receiverAndArgs() val a = left.accept(codegen, data).coerce(parameterType).materialized val b = right.accept(codegen, data).coerce(parameterType).materialized diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicMethod.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicMethod.kt index 3ad7c30a5b9..060ac3fa3ed 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicMethod.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IntrinsicMethod.kt @@ -26,7 +26,7 @@ abstract class IntrinsicMethod { open fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? = with(codegen) { - val descriptor = typeMapper.mapSignatureSkipGeneric(expression.descriptor) + val descriptor = typeMapper.mapSignatureSkipGeneric(expression.symbol.owner) val stackValue = toCallable(expression, descriptor, context).invoke(mv, codegen, data) return object : PromisedValue(mv, stackValue.type) { override fun materialize() = stackValue.put(mv) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrEnumValueOf.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrEnumValueOf.kt index 97e9438b66f..3e7f6a669f1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrEnumValueOf.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrEnumValueOf.kt @@ -21,24 +21,26 @@ import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.StackValue -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter object IrEnumValueOf : IntrinsicMethod() { - override fun toCallable(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction { + override fun toCallable( + expression: IrFunctionAccessExpression, + signature: JvmMethodSignature, + context: JvmBackendContext + ): IrIntrinsicFunction { val enumType = context.state.typeMapper.mapType(expression.descriptor.returnType!!) - val newSignature = context.state.typeMapper.mapSignatureSkipGeneric(expression.descriptor as FunctionDescriptor, OwnerKind.IMPLEMENTATION) - val stringType = AsmTypes.JAVA_STRING_TYPE; + val newSignature = context.state.typeMapper.mapSignatureSkipGeneric(expression.descriptor, OwnerKind.IMPLEMENTATION) + val stringType = AsmTypes.JAVA_STRING_TYPE return object : IrIntrinsicFunction(expression, newSignature, context, listOf(stringType)) { override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue { v.tconst(enumType) codegen.gen(expression.getValueArgument(0)!!, stringType, data) - v.invokestatic("java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;", false); + v.invokestatic("java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;", false) v.checkcast(enumType) return StackValue.onStack(enumType) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt index 236b0146b52..e5761cf3f98 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicFunction.kt @@ -11,9 +11,8 @@ import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.Callable import org.jetbrains.kotlin.codegen.StackValue -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -23,7 +22,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import java.util.* open class IrIntrinsicFunction( - val expression: IrMemberAccessExpression, + val expression: IrFunctionAccessExpression, val signature: JvmMethodSignature, val context: JvmBackendContext, val argsTypes: List = expression.argTypes(context) @@ -80,7 +79,7 @@ open class IrIntrinsicFunction( argument != null -> genArg(argument, codegen, i + offset, data) descriptor.isVararg -> { - val parameterType = codegen.typeMapper.mapType(descriptor.type) + val parameterType = codegen.typeMapper.kotlinTypeMapper.mapType(descriptor.type) StackValue.operation(parameterType) { it.aconst(0) it.newarray(AsmUtil.correctElementType(parameterType)) @@ -98,7 +97,7 @@ open class IrIntrinsicFunction( companion object { fun create( - expression: IrMemberAccessExpression, + expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext, argsTypes: List = expression.argTypes(context), @@ -111,7 +110,7 @@ open class IrIntrinsicFunction( } fun createWithResult( - expression: IrMemberAccessExpression, signature: JvmMethodSignature, + expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext, argsTypes: List = expression.argTypes(context), invokeInstruction: IrIntrinsicFunction.(InstructionAdapter) -> Type @@ -123,7 +122,7 @@ open class IrIntrinsicFunction( } fun create( - expression: IrMemberAccessExpression, + expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext, type: Type, @@ -134,17 +133,17 @@ open class IrIntrinsicFunction( } } -fun IrMemberAccessExpression.argTypes(context: JvmBackendContext): ArrayList { - val callableMethod = context.state.typeMapper.mapToCallableMethod(descriptor as FunctionDescriptor, false) +fun IrFunctionAccessExpression.argTypes(context: JvmBackendContext): ArrayList { + val callableMethod = context.state.typeMapper.mapToCallableMethod(descriptor, false) return arrayListOf().apply { callableMethod.dispatchReceiverType?.let { add(it) } addAll(callableMethod.getAsmMethod().argumentTypes) } } -fun IrMemberAccessExpression.receiverAndArgs(): List { +fun IrFunctionAccessExpression.receiverAndArgs(): List { return (arrayListOf(this.dispatchReceiver, this.extensionReceiver) + - descriptor.valueParameters.mapIndexed { i, _ -> getValueArgument(i) }).filterNotNull() + symbol.owner.valueParameters.mapIndexed { i, _ -> getValueArgument(i) }).filterNotNull() } fun List.asmTypes(context: JvmBackendContext): List { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt index a51db9b41b6..17e317e1855 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.JvmSymbols +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrPackageFragment @@ -26,8 +27,8 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.functions @@ -43,18 +44,64 @@ import org.jetbrains.org.objectweb.asm.Type class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { + private val KOTLIN_INTERNAL_IR = FqName("kotlin.internal.ir") + private val KOTLIN_JVM = FqName("kotlin.jvm") + private val KOTLIN_JVM_INTERNAL_UNSAFE = FqName("kotlin.jvm.internal.unsafe") + val andandSymbol = irBuiltIns.run { defineOperator(OperatorNames.ANDAND, bool, listOf(bool, bool)) } private val intrinsicsMap = ( listOf( - symbols.javaClassProperty.owner.getter!!.symbol.toKey() to JavaClassProperty, - symbols.kClassJavaProperty.owner.getter!!.symbol.toKey() to KClassJavaProperty, - symbols.monitorEnter.toKey() to MonitorInstruction.MONITOR_ENTER, - symbols.monitorExit.toKey() to MonitorInstruction.MONITOR_EXIT, - symbols.isArrayOf.toKey() to IsArrayOf, + Key(KOTLIN_JVM, FqName("T"),"", emptyList()) to JavaClassProperty, + Key( + KOTLIN_JVM, + KotlinBuiltIns.FQ_NAMES.kClass.toSafe(), + "", + emptyList() + ) to KClassJavaProperty, + Key( + KOTLIN_JVM_INTERNAL_UNSAFE, + null, + "monitorEnter", + listOf(KotlinBuiltIns.FQ_NAMES.any.toSafe()) + ) to MonitorInstruction.MONITOR_ENTER, + Key( + KOTLIN_JVM_INTERNAL_UNSAFE, + null, + "monitorExit", + listOf(KotlinBuiltIns.FQ_NAMES.any.toSafe()) + ) to MonitorInstruction.MONITOR_EXIT, + Key( + KOTLIN_JVM, + KotlinBuiltIns.FQ_NAMES.array.toSafe(), + "isArrayOf", + emptyList() + ) to IsArrayOf, symbols.arrayOf.toKey() to ArrayOf, - symbols.extensionToString.toKey() to ToString, - symbols.arrayOfNulls.toKey() to NewArray, + Key( + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, + KotlinBuiltIns.FQ_NAMES.any.toSafe(), + "toString", + emptyList() + ) to ToString, + Key( + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, + null, + "arrayOfNulls", + listOf(KotlinBuiltIns.FQ_NAMES._int.toSafe()) + ) to NewArray, + Key( + KotlinBuiltIns.FQ_NAMES.cloneable.toSafe(), + null, + "clone", + emptyList() + ) to Clone, + Key( + KOTLIN_INTERNAL_IR, + null, + OperatorNames.ANDAND, + listOf(KotlinBuiltIns.FQ_NAMES._boolean.toSafe(), KotlinBuiltIns.FQ_NAMES._boolean.toSafe()) + ) to AndAnd, irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ), irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ), irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.float]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE), @@ -63,8 +110,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { irBuiltIns.enumValueOfSymbol.toKey()!! to IrEnumValueOf, irBuiltIns.noWhenBranchMatchedExceptionSymbol.toKey()!! to IrNoWhenBranchMatchedException, irBuiltIns.illegalArgumentExceptionSymbol.toKey()!! to IrIllegalArgumentException, - irBuiltIns.throwNpeSymbol.toKey()!! to ThrowNPE, - andandSymbol.toKey() to AndAnd + irBuiltIns.throwNpeSymbol.toKey()!! to ThrowNPE ) + numberConversionMethods() + unaryFunForPrimitives("plus", UnaryPlus) + @@ -94,7 +140,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { binaryFunForPrimitives("compareTo", CompareTo) + methodWithArity(irBuiltIns.booleanClass, "not", 0, Not) + methodWithArity(irBuiltIns.stringClass, "get", 1, StringGetChar) + - methodWithArity(symbols.cloneable, "clone", 0, Clone) + symbols.primitiveIteratorsByType.values.flatMap { iteratorClass -> methodWithArity(iteratorClass, "next", 0, IteratorNext) } + @@ -147,7 +192,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { } private fun getParameterFqName(parameter: IrValueParameter?): FqName? = - parameter?.type?.safeAs()?.classifier?.owner?.let { + parameter?.type?.classifierOrNull?.owner?.let { when (it) { is IrClass -> it.fqNameWhenAvailable is IrTypeParameter -> FqName(it.name.asString()) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt index 21c46bab763..e67e953740c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression -import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -21,11 +20,11 @@ object NewArray : IntrinsicMethod() { signature: JvmMethodSignature, context: JvmBackendContext ): IrIntrinsicFunction { - val ktType = expression.type + val irType = expression.type return object : IrIntrinsicFunction(expression, signature, context) { override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue { super.invoke(v, codegen, data) - codegen.newArrayInstruction(ktType.toKotlinType()) + codegen.newArrayInstruction(irType) return StackValue.onStack(returnType) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index 507c954817f..5c2468baee5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -44,7 +44,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl @@ -109,7 +108,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL val vararg = IrVarargImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType), - context.irBuiltIns.anyClass.typeWith(), + context.irBuiltIns.anyNType, (0 until argumentsCount).map { i -> expression.getValueArgument(i)!! } ) val invokeFun = context.ir.symbols.functionN.owner.declarations.single { @@ -596,26 +595,3 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL const val MAX_ARGCOUNT_WITHOUT_VARARG = 22 } } - -// TODO: Move to IrUtils -private fun IrType.substitute(substitutionMap: Map): IrType { - if (this !is IrSimpleType) return this - - substitutionMap[classifier]?.let { return it } - - val newArguments = arguments.map { - if (it is IrTypeProjection) { - makeTypeProjection(it.type.substitute(substitutionMap), it.variance) - } else { - it - } - } - - val newAnnotations = annotations.map { it.deepCopyWithSymbols() } - return IrSimpleTypeImpl( - classifier, - hasQuestionMark, - newArguments, - newAnnotations - ) -} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index e6c4a6cd31f..d334de0c97f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.utils.DFS /** * Binds the arguments explicitly represented in the IR to the parameters of the accessed function. @@ -281,6 +282,7 @@ val IrClass.isEnumEntry get() = kind == ClassKind.ENUM_ENTRY val IrClass.isInterface get() = kind == ClassKind.INTERFACE val IrClass.isClass get() = kind == ClassKind.CLASS val IrClass.isObject get() = kind == ClassKind.OBJECT +val IrClass.isAnonymousObject get() = isClass && name == SpecialNames.NO_NAME_PROVIDED val IrDeclarationWithName.fqNameWhenAvailable: FqName? get() = when (val parent = parent) { is IrDeclarationWithName -> parent.fqNameWhenAvailable?.child(name) @@ -352,6 +354,12 @@ inline fun IrDeclarationContainer.findDeclaration(pr inline fun IrDeclarationContainer.filterDeclarations(predicate: (T) -> Boolean): List = declarations.filter { it is T && predicate(it) } as List +fun IrValueParameter.hasDefaultValue(): Boolean = DFS.ifAny( + listOf(this), + { current -> (current.parent as? IrSimpleFunction)?.overriddenSymbols?.map { it.owner.valueParameters[current.index] } ?: listOf() }, + { current -> current.defaultValue != null } +) + fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { assert(this.descriptor.type == newDescriptor.type) diff --git a/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt b/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt index a9e1d43173e..0009d12c7d4 100644 --- a/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt +++ b/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt @@ -1,3 +1,5 @@ +// IGNORE_BACKEND: JVM_IR +// For JVM_IR, NewInference is needed because of KT-26531. See functionExpressionWithThisReferenceNI.kt fun Int.thisRef1() = fun () = this fun Int.thisRef2() = fun (): Int {return this} diff --git a/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt b/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt new file mode 100644 index 00000000000..f44e247af37 --- /dev/null +++ b/compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt @@ -0,0 +1,36 @@ +// !LANGUAGE: +NewInference +// NewInference needed because of KT-26531 + +fun Int.thisRef1() = fun () = this +fun Int.thisRef2() = fun (): Int {return this} + +fun T.genericThisRef1() = fun () = this +fun T.genericThisRef2() = fun (): T {return this} + +val Int.valThisRef1: () -> Int get() = fun () = this +val Int.valThisRef2: () -> Int get() = fun (): Int {return this} + +val T.valGenericThisRef1: ()->T get() = fun () = this +val T.valGenericThisRef2: ()->T get() = fun (): T {return this} + +val T.withLabel1: ()->T get() = fun () = this@withLabel1 +val T.withLabel2: ()->T get() = fun (): T {return this@withLabel2} + +fun box(): String { + if (1.thisRef1()() != 1) return "Test 1 failed" + if (2.thisRef2()() != 2) return "Test 2 failed" + + if (3.genericThisRef1()() != 3) return "Test 3 failed" + if (4.genericThisRef2()() != 4) return "Test 4 failed" + + if (5.valThisRef1() != 5) return "Test 5 failed" + if (6.valThisRef2() != 6) return "Test 6 failed" + + if (7.valGenericThisRef1() != 7) return "Test 7 failed" + if (8.valGenericThisRef2() != 8) return "Test 8 failed" + + if ("bar".withLabel1() != "bar") return "Test 9 failed" + if ("bar".withLabel2() != "bar") return "Test 10 failed" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/typeOf/classes.kt b/compiler/testData/codegen/box/reflection/typeOf/classes.kt index 7c6d05ea9a6..27f90a0738d 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/classes.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/classes.kt @@ -1,5 +1,5 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi -// IGNORE_BACKEND: JS, JS_IR, NATIVE +// IGNORE_BACKEND: JS, JS_IR, NATIVE, JVM_IR // WITH_REFLECT package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/classesIR.kt b/compiler/testData/codegen/box/reflection/typeOf/classesIR.kt new file mode 100644 index 00000000000..71c884e4b4e --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/classesIR.kt @@ -0,0 +1,41 @@ +// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TARGET_BACKEND: JVM_IR +// WITH_REFLECT + +package test + +import kotlin.reflect.KType +import kotlin.reflect.typeOf +import kotlin.test.assertEquals + +class C + +fun check(expected: String, actual: KType) { + assertEquals(expected, actual.toString()) +} + +fun box(): String { + check("kotlin.Any", typeOf()) + check("kotlin.String", typeOf()) + check("kotlin.String?", typeOf()) + check("kotlin.Unit", typeOf()) + + check("test.C", typeOf()) + check("test.C?", typeOf()) + + check("kotlin.collections.List", typeOf>()) + check("kotlin.collections.Map?", typeOf?>()) + check("kotlin.Enum<*>", typeOf>()) + check("kotlin.Enum", typeOf>()) + + check("kotlin.Array", typeOf>()) + check("kotlin.Array<*>", typeOf>()) + check("kotlin.Array", typeOf>()) + check("kotlin.Array?>", typeOf?>>()) + + check("kotlin.Int", typeOf()) + check("kotlin.Int?", typeOf()) + check("kotlin.Boolean", typeOf()) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt index 622c654204e..33b7f77598c 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt @@ -1,5 +1,6 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/classesIR.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/classesIR.kt new file mode 100644 index 00000000000..9cd6449b55a --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/classesIR.kt @@ -0,0 +1,42 @@ +// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +// Separate test is needed for IR because type arguments of typeOf are computed differently. + +package test + +import kotlin.reflect.KType +import kotlin.reflect.typeOf +import kotlin.test.assertEquals + +class C + +fun check(expected: String, actual: KType) { + assertEquals(expected + " (Kotlin reflection is not available)", actual.toString()) +} + +fun box(): String { + check("java.lang.Object", typeOf()) + check("java.lang.String", typeOf()) + check("java.lang.String?", typeOf()) + check("kotlin.Unit", typeOf()) + + check("test.C", typeOf()) + check("test.C?", typeOf()) + + check("java.util.List", typeOf>()) + check("java.util.Map?", typeOf?>()) + check("java.lang.Enum<*>", typeOf>()) + check("java.lang.Enum", typeOf>()) + + check("kotlin.Array", typeOf>()) + check("kotlin.Array<*>", typeOf>()) + check("kotlin.Array", typeOf>()) + check("kotlin.Array?>", typeOf?>>()) + + check("int", typeOf()) + check("java.lang.Integer?", typeOf()) + check("boolean", typeOf()) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt index 768bb5cab9f..a0b0747ce77 100644 --- a/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt +++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt @@ -1,5 +1,6 @@ // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCodeIR.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCodeIR.kt new file mode 100644 index 00000000000..2d90c632067 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCodeIR.kt @@ -0,0 +1,55 @@ +// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +// Separate test is needed for IR because of different ways type arguments of typeOf are calculated. + +package test + +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +class C + +fun assertEqual(a: KType, b: KType) { + if (a != b || b != a) throw AssertionError("Fail equals: $a != $b") + if (a.hashCode() != b.hashCode()) throw AssertionError("Fail hashCode: $a != $b") +} + +fun assertNotEqual(a: KType, b: KType) { + if (a == b || b == a) throw AssertionError("Fail equals: $a == $b") +} + +inline fun equal() { + assertEqual(typeOf(), typeOf()) +} + +inline fun notEqual() { + assertNotEqual(typeOf(), typeOf()) +} + +fun box(): String { + equal() + equal() + equal() + + equal() + equal() + + equal, List>() + equal, Enum>() + + equal, Array>() + equal, Array>() + equal, Array<*>>() + + equal() + equal() + + notEqual() + notEqual() + notEqual, List>() + notEqual, Map>() + notEqual, Array>>() + + return "OK" +} diff --git a/compiler/testData/codegen/box/regressions/noAssertionsWhenNullableTypeParameterReplacedWithIntersectionType.kt b/compiler/testData/codegen/box/regressions/noAssertionsWhenNullableTypeParameterReplacedWithIntersectionType.kt index cdc8fb844eb..925ff26edd9 100644 --- a/compiler/testData/codegen/box/regressions/noAssertionsWhenNullableTypeParameterReplacedWithIntersectionType.kt +++ b/compiler/testData/codegen/box/regressions/noAssertionsWhenNullableTypeParameterReplacedWithIntersectionType.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +NewInference -// IGNORE_BACKEND: JVM_IR class Recursive> : Generic>, MainSupertype open class Simple : Generic, MainSupertype diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index cc3cb4e629e..b0f66d3b28c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11261,6 +11261,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); } + @TestMetadata("functionExpressionWithThisReferenceNI.kt") + public void testFunctionExpressionWithThisReferenceNI() throws Exception { + runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt"); + } + @TestMetadata("functionLiteralExpression.kt") public void testFunctionLiteralExpression() throws Exception { runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e1d093c180a..851419cda00 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -11261,6 +11261,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); } + @TestMetadata("functionExpressionWithThisReferenceNI.kt") + public void testFunctionExpressionWithThisReferenceNI() throws Exception { + runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt"); + } + @TestMetadata("functionLiteralExpression.kt") public void testFunctionLiteralExpression() throws Exception { runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index ceb7fb57f46..6943b942064 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -11266,6 +11266,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); } + @TestMetadata("functionExpressionWithThisReferenceNI.kt") + public void testFunctionExpressionWithThisReferenceNI() throws Exception { + runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt"); + } + @TestMetadata("functionLiteralExpression.kt") public void testFunctionLiteralExpression() throws Exception { runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); @@ -21724,6 +21729,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt"); } + @TestMetadata("classesIR.kt") + public void testClassesIR() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/classesIR.kt"); + } + @TestMetadata("inlineClasses.kt") public void testInlineClasses() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt"); @@ -21756,6 +21766,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt"); } + @TestMetadata("classesIR.kt") + public void testClassesIR() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classesIR.kt"); + } + @TestMetadata("inlineClasses.kt") public void testInlineClasses() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt"); @@ -21765,6 +21780,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testTypeReferenceEqualsHashCode() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt"); } + + @TestMetadata("typeReferenceEqualsHashCodeIR.kt") + public void testTypeReferenceEqualsHashCodeIR() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCodeIR.kt"); + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 2c16aadc58e..f28e96ce5cb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -8816,6 +8816,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); } + @TestMetadata("functionExpressionWithThisReferenceNI.kt") + public void testFunctionExpressionWithThisReferenceNI() throws Exception { + runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt"); + } + @TestMetadata("functionLiteralExpression.kt") public void testFunctionLiteralExpression() throws Exception { runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index d7bb42f85d1..a661af5a5fe 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -9891,6 +9891,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); } + @TestMetadata("functionExpressionWithThisReferenceNI.kt") + public void testFunctionExpressionWithThisReferenceNI() throws Exception { + runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt"); + } + @TestMetadata("functionLiteralExpression.kt") public void testFunctionLiteralExpression() throws Exception { runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt");