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 6d2a8f09959..c4d8e6dade6 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 @@ -35,13 +35,13 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.TRANSIENT_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Opcodes @@ -110,6 +110,13 @@ open class ClassCodegen protected constructor( val superClassInfo = irClass.getSuperClassInfo(typeMapper) val signature = getSignature(irClass, type, superClassInfo, typeMapper) + // Ensure that the backend only produces class names that would be valid in the frontend for JVM. + // hasInvalidName() uses a set copied from JvmSimpleNameBacktickChecker, which in turn references JVMS 4.7.9.1: + // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9.1. + if (context.state.classBuilderMode.generateBodies && signature.hasInvalidName()) { + throw IllegalStateException("Generating class with invalid name '${type.className}': ${irClass.dump()}") + } + visitor.defineClass( irClass.descriptor.psiElement, state.classFileVersion, @@ -281,20 +288,14 @@ open class ClassCodegen protected constructor( companion object { fun generate(irClass: IrClass, context: JvmBackendContext) { - val state = context.state - - if (irClass.name == SpecialNames.NO_NAME_PROVIDED) { - badClass(irClass, state.classBuilderMode) - } - ClassCodegen(irClass, context).generate() } - private fun badClass(irClass: IrClass, mode: ClassBuilderMode) { - if (mode.generateBodies) { - throw IllegalStateException("Generating bad class in ClassBuilderMode = $mode: ${irClass.dump()}") - } - } + // Note: This is copied from JvmSimpleNameBacktickChecker. + private val INVALID_CHARS = setOf('.', ';', '[', ']', '/', '<', '>', ':', '\\') + + private fun JvmClassSignature.hasInvalidName() = + name.splitToSequence('/').any { identifier -> identifier.any { it in INVALID_CHARS } } } private fun generateDeclaration(declaration: IrDeclaration) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt index 92126bb5437..eccf77f616c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.util.isAnonymousObject import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.org.objectweb.asm.Type @@ -102,10 +103,11 @@ class InventNamesForLocalClasses(private val context: JvmBackendContext) : FileL val simpleName = declaration.name.asString() val internalName = when { - declaration.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA -> { + declaration is IrFunction && !NameUtils.hasName(declaration.name) -> { + // Replace "unnamed" function names with indices. inventName(null, data).also { name -> - // We save the name of the lambda to reuse it in the reference to it (produced by the closure conversion) later. - localFunctionNames[(declaration as IrFunction).symbol] = name + // We save the name of the function to reuse it in the reference to it (produced by the closure conversion) later. + localFunctionNames[declaration.symbol] = name } } enclosingName != null -> "$enclosingName$$simpleName"