wip
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDelegatingConstructorCallImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDelegatingConstructorCallImpl.kt
index c61c9f1..6792621 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDelegatingConstructorCallImpl.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDelegatingConstructorCallImpl.kt
@@ -32,9 +32,8 @@
override val symbol: IrConstructorSymbol,
typeArgumentsCount: Int,
valueArgumentsCount: Int,
+ override val origin: IrStatementOrigin? = null
) : IrDelegatingConstructorCall() {
- override val origin: IrStatementOrigin?
- get() = null
override val typeArgumentsByIndex: Array<IrType?> = arrayOfNulls(typeArgumentsCount)
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/ClassifierExplorer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/ClassifierExplorer.kt
index 07d46b3..02ba03b 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/ClassifierExplorer.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/ClassifierExplorer.kt
@@ -8,8 +8,6 @@
import org.jetbrains.kotlin.backend.common.serialization.unlinked.ExploredClassifier.Unusable
import org.jetbrains.kotlin.backend.common.serialization.unlinked.ExploredClassifier.Unusable.*
import org.jetbrains.kotlin.backend.common.serialization.unlinked.ExploredClassifier.Usable
-import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageUtils.DeclarationId
-import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageUtils.DeclarationId.Companion.declarationId
import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageUtils.isEffectivelyMissingLazyIrDeclaration
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAME
@@ -24,7 +22,6 @@
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
-import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
@@ -231,62 +228,8 @@
return InvalidInheritance(symbol, superClassSymbols) // Invalid inheritance.
}
- // Check delegating constructor calls.
- val ownConstructors: Map<IrConstructorSymbol, IrConstructor> = declarations
- .filterIsInstance<IrConstructor>()
- .associateBy { it.symbol }
-
- ownConstructors.forEach { (_, constructor) ->
- var unexpectedSuperClassConstructorSymbol: IrConstructorSymbol? = null
-
- constructor.acceptChildrenVoid(object : IrElementVisitorVoid {
- override fun visitElement(element: IrElement) {
- if (unexpectedSuperClassConstructorSymbol != null)
- return // Break.
-
- element.acceptChildrenVoid(this)
- }
-
- override fun visitClass(declaration: IrClass) {
- // Skip nested
- }
-
- override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
- if (unexpectedSuperClassConstructorSymbol != null)
- return // Break.
-
- val calledConstructorSymbol = expression.symbol
- if (calledConstructorSymbol in ownConstructors) return // OK, just calling another constructor of the same class
-
- if (calledConstructorSymbol.isBound) {
- val calledConstructor = calledConstructorSymbol.owner
- if (calledConstructor.origin != PartiallyLinkedDeclarationOrigin.MISSING_DECLARATION) {
- val constructedSuperClassSymbol = calledConstructor.parentAsClass.symbol
- if (constructedSuperClassSymbol != superClassSymbol) {
- // Wrong delegating constructor call.
- unexpectedSuperClassConstructorSymbol = calledConstructorSymbol
- }
- }
- } else {
- // Fallback to signatures.
- (calledConstructorSymbol.signature as? IdSignature.CommonSignature)?.let { constructorSignature ->
- val constructedSuperClassId = DeclarationId(
- constructorSignature.packageFqName,
- constructorSignature.declarationFqName.substringBeforeLast('.')
- )
-
- if (superClassSymbol.owner.declarationId != constructedSuperClassId) {
- // Wrong delegating constructor call.
- unexpectedSuperClassConstructorSymbol = calledConstructorSymbol
- }
- }
- }
- }
- })
-
- if (unexpectedSuperClassConstructorSymbol != null)
- return InvalidInheritance(symbol, superClassSymbol, unexpectedSuperClassConstructorSymbol!!)
- }
+ // IMPORTANT: Constructor delegation is intentionally not performed here.
+ // For details see [InvalidInheritance].
}
return null
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedIrTreePatcher.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedIrTreePatcher.kt
index 81db6d1..7540f4d 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedIrTreePatcher.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedIrTreePatcher.kt
@@ -6,7 +6,10 @@
package org.jetbrains.kotlin.backend.common.serialization.unlinked
import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageCase.*
+import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageUtils.DeclarationId
+import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageUtils.DeclarationId.Companion.declarationId
import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageUtils.isEffectivelyMissingLazyIrDeclaration
+import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartiallyLinkedStatementOrigin.FIXED_CONSTRUCTOR_DELEGATION
import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartiallyLinkedStatementOrigin.PARTIAL_LINKAGE_RUNTIME_ERROR
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -14,12 +17,11 @@
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase
import org.jetbrains.kotlin.ir.expressions.*
-import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
-import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
-import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
+import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.overrides.isEffectivelyPrivate
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
+import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.IrMessageLogger.Severity
@@ -203,8 +205,38 @@
return declaration.transformChildrenWithRemoval()
}
- override fun visitFunction(declaration: IrFunction): IrStatement {
- (declaration as? IrOverridableDeclaration<*>)?.filterOverriddenSymbols()
+ override fun visitConstructor(declaration: IrConstructor): IrStatement {
+ // IMPORTANT: It's necessary to overwrite types. Please don't remove this statement or move it somewhere else.
+ val unusableClassifierInSignature = declaration.rewriteTypesInFunction()
+
+ // IMPORTANT: It's necessary to fix constructor delegation. Please don't remove this statement or move it somewhere else.
+ val inheritanceIssue = declaration.fixConstructorDelegation()
+
+ // Compute the linkage case.
+ val partialLinkageCase = if (declaration.origin == PartiallyLinkedDeclarationOrigin.MISSING_DECLARATION)
+ MissingDeclaration(declaration.symbol)
+ else
+ (unusableClassifierInSignature ?: inheritanceIssue)?.let { DeclarationWithUnusableClassifier(declaration.symbol, it) }
+
+ if (partialLinkageCase != null) {
+ // Note: Block body is missing for MISSING_DECLARATION.
+ val blockBody = declaration.body as? IrBlockBody
+ ?: builtIns.irFactory.createBlockBody(declaration.startOffset, declaration.endOffset).apply { declaration.body = this }
+
+ // IMPORTANT: Unlike it's done for IrSimpleFunction don't clean-up statements. Insert PL linkage as the first one.
+ blockBody.statements.add(
+ 0, partialLinkageCase.throwLinkageError(
+ declaration,
+ suppressWarningInCompilerOutput = declaration.isDirectMemberOf(unusableClassifierInSignature)
+ )
+ )
+ }
+
+ return declaration.transformChildren()
+ }
+
+ override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement {
+ declaration.filterOverriddenSymbols()
// IMPORTANT: It's necessary to overwrite types. Please don't move the statement below.
val unusableClassifierInSignature = declaration.rewriteTypesInFunction()
@@ -217,6 +249,7 @@
}
if (partialLinkageCase != null) {
+ // Note: Block body is missing for UNIMPLEMENTED_ABSTRACT_CALLABLE_MEMBER and MISSING_DECLARATION.
val blockBody = declaration.body as? IrBlockBody
?: builtIns.irFactory.createBlockBody(declaration.startOffset, declaration.endOffset).apply { declaration.body = this }
@@ -234,7 +267,7 @@
if (declaration.isTopLevelDeclaration) {
// Optimization: Remove unlinked top-level functions.
declaration.scheduleForRemoval()
- } else if (declaration is IrSimpleFunction) {
+ } else {
// Optimization: Remove unlinked top-level properties.
val property = declaration.correspondingPropertySymbol?.owner
if (property?.isTopLevelDeclaration == true)
@@ -285,6 +318,106 @@
return result
}
+ /**
+ * Check and fix constructor delegation. Note: This particular case of class exploration is intentionally performed
+ * outside of [ClassifierExplorer]. For details see [ExploredClassifier.Unusable.InvalidInheritance].
+ */
+ private fun IrConstructor.fixConstructorDelegation(): ExploredClassifier.Unusable.InvalidInheritance? {
+ if (origin == PartiallyLinkedDeclarationOrigin.MISSING_DECLARATION)
+ return null
+
+ val blockBody = body as? IrBlockBody
+ if (blockBody == null || blockBody.statements.isEmpty())
+ return null
+
+ val constructedClass = parentAsClass
+ val constructedClassSymbol = constructedClass.symbol
+
+ val actualSuperClassSymbol = constructedClass.superTypes
+ .firstNotNullOfOrNull { (it as? IrSimpleType)?.classifier as? IrClassSymbol }
+ ?: builtIns.anyClass
+ val actualSuperClass = actualSuperClassSymbol.owner
+
+ var inheritanceIssue: ExploredClassifier.Unusable.InvalidInheritance? = null
+
+ blockBody.statements.transformInPlace { statement ->
+ if (statement !is IrDelegatingConstructorCall)
+ return@transformInPlace statement
+
+ val calledConstructorSymbol = statement.symbol
+ val calledConstructor = calledConstructorSymbol.owner
+
+ val invalidConstructorDelegationFound =
+ if (calledConstructor.origin != PartiallyLinkedDeclarationOrigin.MISSING_DECLARATION) {
+ val constructedSuperClassSymbol = calledConstructor.parentAsClass.symbol
+ constructedSuperClassSymbol != constructedClassSymbol && constructedSuperClassSymbol != actualSuperClassSymbol
+ } else {
+ // Fallback to signatures.
+ (calledConstructorSymbol.signature as? IdSignature.CommonSignature)?.let { constructorSignature ->
+ val constructedSuperClassId = DeclarationId(
+ constructorSignature.packageFqName,
+ constructorSignature.declarationFqName.substringBeforeLast('.')
+ )
+
+ actualSuperClass.declarationId != constructedSuperClassId
+ } ?: false
+ }
+
+ if (!invalidConstructorDelegationFound)
+ return@transformInPlace statement
+
+ inheritanceIssue = ExploredClassifier.Unusable.InvalidInheritance(
+ symbol = constructedClassSymbol,
+ superClassSymbol = actualSuperClassSymbol,
+ unexpectedSuperClassConstructorSymbol = calledConstructorSymbol
+ )
+
+ val actualSuperClassConstructors = actualSuperClass.constructors.toMutableList()
+ val actualSuperClassConstructor = when (actualSuperClassConstructors.size) {
+ 0 -> error("Class without constructors: $actualSuperClass") // Normally, should not happen.
+ 1 -> actualSuperClassConstructors.first()
+ else -> {
+ // Try to find the best match.
+ actualSuperClassConstructors.sortWith(Comparator<IrConstructor> { a, b ->
+ val visibilitiesDiff = a.visibility.compareTo(b.visibility) ?: 0
+ if (visibilitiesDiff != 0) visibilitiesDiff else a.isPrimary.compareTo(b.isPrimary)
+ }.reversed())
+ actualSuperClassConstructors.first()
+ }
+ }
+
+ // An attempt to restore constructor delegation to avoid errors in subsequent lowerings and codegenerator phases.
+ IrDelegatingConstructorCallImpl(
+ statement.startOffset,
+ statement.endOffset,
+ actualSuperClass.defaultType,
+ actualSuperClassConstructor.symbol,
+ actualSuperClassConstructor.allTypeParameters.size,
+ actualSuperClassConstructor.valueParameters.size,
+ origin = FIXED_CONSTRUCTOR_DELEGATION
+ ).apply {
+ // Supply fake arguments. Anyway the super class constructor will never be called from here.
+ for (i in 0 until typeArgumentsCount) {
+ putTypeArgument(i, builtIns.anyNType)
+ }
+ for (i in 0 until valueArgumentsCount) {
+ putValueArgument(
+ i,
+ throwThrowable(
+ statement.startOffset,
+ statement.endOffset,
+ builtIns.throwIseSymbol,
+ FIXED_CONSTRUCTOR_DELEGATION,
+ "Not expected to be executed during the runtime"
+ )
+ )
+ }
+ }
+ }
+
+ return inheritanceIssue
+ }
+
override fun visitProperty(declaration: IrProperty): IrStatement {
declaration.filterOverriddenSymbols()
return declaration.transformChildren()
@@ -660,16 +793,33 @@
else
renderAndLogLinkageError(element, file)
+ return throwThrowable(
+ element.startOffset,
+ element.endOffset,
+ builtIns.linkageErrorSymbol,
+ PARTIAL_LINKAGE_RUNTIME_ERROR,
+ errorMessage
+ )
+ }
+
+ // Just a shortcut.
+ private fun throwThrowable(
+ startOffset: Int,
+ endOffset: Int,
+ throwingFunctionSymbol: IrSimpleFunctionSymbol,
+ origin: PartiallyLinkedStatementOrigin,
+ message: String
+ ): IrCall {
return IrCallImpl(
- startOffset = element.startOffset,
- endOffset = element.endOffset,
+ startOffset = startOffset,
+ endOffset = endOffset,
type = builtIns.nothingType,
- symbol = builtIns.linkageErrorSymbol,
+ symbol = throwingFunctionSymbol,
typeArgumentsCount = 0,
valueArgumentsCount = 1,
- origin = PARTIAL_LINKAGE_RUNTIME_ERROR
+ origin = origin
).apply {
- putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, errorMessage))
+ putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, message))
}
}
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedStatementOrigin.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedStatementOrigin.kt
index 99347e8..249dc21 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedStatementOrigin.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/PartiallyLinkedStatementOrigin.kt
@@ -6,7 +6,13 @@
package org.jetbrains.kotlin.backend.common.serialization.unlinked
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
+import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
+import org.jetbrains.kotlin.ir.expressions.IrExpression
internal enum class PartiallyLinkedStatementOrigin : IrStatementOrigin {
- PARTIAL_LINKAGE_RUNTIME_ERROR
+ /** An [IrExpression] that represents an PL runtime error. */
+ PARTIAL_LINKAGE_RUNTIME_ERROR,
+
+ /** An [IrDelegatingConstructorCall] that restores the correct constructor delegation. */
+ FIXED_CONSTRUCTOR_DELEGATION
}