[FIR & IR] Support of default values for arguments in expect functions
Add FirActualDeclarationChecker that checks expect/actual return types ^KT-56331 Fixed, ^KT-56334 Fixed
This commit is contained in:
committed by
Space Team
parent
a54b56d74e
commit
d87619e06e
+6
-6
@@ -173,13 +173,13 @@ private class CallablesLinkCollector(
|
||||
|
||||
private fun addLink(declaration: IrDeclarationBase) {
|
||||
if (!declaration.isExpect) return
|
||||
val member = actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)]
|
||||
if (member != null) {
|
||||
expectActualMap[declaration.symbol] = member.symbol
|
||||
val actualMember = actualMembers[generateIrElementFullName(declaration, expectActualMap, typeAliasMap)]
|
||||
if (actualMember != null) {
|
||||
expectActualMap[declaration.symbol] = actualMember.symbol
|
||||
if (declaration is IrProperty) {
|
||||
member as IrProperty
|
||||
declaration.getter?.symbol?.let { expectActualMap[it] = member.getter!!.symbol }
|
||||
declaration.setter?.symbol?.let { expectActualMap[it] = member.setter!!.symbol }
|
||||
val actualProperty = actualMember as IrProperty
|
||||
declaration.getter?.symbol?.let { expectActualMap[it] = actualProperty.getter!!.symbol }
|
||||
declaration.setter?.symbol?.let { expectActualMap[it] = actualProperty.setter!!.symbol }
|
||||
}
|
||||
} else {
|
||||
reportMissingActual(declaration)
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.actualizer
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.copyAndActualizeDefaultValue
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
|
||||
class FunctionDefaultParametersActualizer(private val expectActualMap: Map<IrSymbol, IrSymbol>) {
|
||||
fun actualize() {
|
||||
for ((expect, actual) in expectActualMap) {
|
||||
if (expect is IrFunctionSymbol) {
|
||||
actualize(expect.owner, (actual as IrFunctionSymbol).owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun actualize(expectFunction: IrFunction, actualFunction: IrFunction) {
|
||||
expectFunction.valueParameters.zip(actualFunction.valueParameters).forEach { (expectParameter, actualParameter) ->
|
||||
val expectDefaultValue = expectParameter.defaultValue
|
||||
if (actualParameter.defaultValue == null && expectDefaultValue != null) {
|
||||
actualParameter.defaultValue = expectDefaultValue.copyAndActualizeDefaultValue(
|
||||
actualFunction,
|
||||
actualParameter,
|
||||
mapOf(),
|
||||
classActualizer = { (expectActualMap[it.symbol] as IrClassSymbol).owner },
|
||||
functionActualizer = { (expectActualMap[it.symbol] as IrFunctionSymbol).owner }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -6,20 +6,21 @@
|
||||
package org.jetbrains.kotlin.backend.common.actualizer
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isProperExpect
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object IrActualizer {
|
||||
fun actualize(mainFragment: IrModuleFragment, dependentFragments: List<IrModuleFragment>) {
|
||||
val (expectActualMap, typeAliasMap) = ExpectActualCollector(mainFragment, dependentFragments).collect()
|
||||
removeExpectDeclaration(dependentFragments) // TODO: consider removing this call. See ExpectDeclarationRemover.kt
|
||||
FunctionDefaultParametersActualizer(expectActualMap).actualize()
|
||||
removeExpectDeclarations(dependentFragments)
|
||||
addMissingFakeOverrides(expectActualMap, dependentFragments, typeAliasMap)
|
||||
linkExpectToActual(expectActualMap, dependentFragments)
|
||||
mergeIrFragments(mainFragment, dependentFragments)
|
||||
}
|
||||
|
||||
private fun removeExpectDeclaration(dependentFragments: List<IrModuleFragment>) {
|
||||
private fun removeExpectDeclarations(dependentFragments: List<IrModuleFragment>) {
|
||||
for (fragment in dependentFragments) {
|
||||
for (file in fragment.files) {
|
||||
file.declarations.removeAll { it.isProperExpect }
|
||||
|
||||
+7
-65
@@ -12,13 +12,9 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.extractTypeParameters
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.findCompatibleActualsForExpected
|
||||
@@ -153,16 +149,13 @@ open class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, priva
|
||||
}
|
||||
|
||||
defaultValue.let { originalDefault ->
|
||||
declaration.defaultValue = declaration.factory.createExpressionBody(originalDefault.startOffset, originalDefault.endOffset) {
|
||||
expression = originalDefault.expression
|
||||
.deepCopyWithSymbols(function) { symbolRemapper, _ ->
|
||||
DeepCopyIrTreeWithSymbols(
|
||||
symbolRemapper,
|
||||
IrTypeParameterRemapper(typeParameterSubstitutionMap.getValue(expectToActual))
|
||||
)
|
||||
}
|
||||
.remapExpectValueSymbols()
|
||||
}
|
||||
declaration.defaultValue = originalDefault.copyAndActualizeDefaultValue(
|
||||
function,
|
||||
declaration,
|
||||
typeParameterSubstitutionMap.getValue(expectToActual),
|
||||
classActualizer = { symbolTable.referenceClass(it.descriptor.findActualForExpect() as ClassDescriptor).owner },
|
||||
functionActualizer = { symbolTable.referenceFunction(it.descriptor.findActualForExpect() as FunctionDescriptor).owner }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,55 +163,4 @@ open class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, priva
|
||||
if (!isActual) error(this)
|
||||
return findCompatibleExpectsForActual().singleOrNull()
|
||||
}
|
||||
|
||||
private fun IrExpression.remapExpectValueSymbols(): IrExpression {
|
||||
return this.transform(object : IrElementTransformerVoid() {
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
val newValue = remapExpectValue(expression.symbol)
|
||||
?: return expression
|
||||
|
||||
return IrGetValueImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
newValue.type,
|
||||
newValue.symbol,
|
||||
expression.origin
|
||||
)
|
||||
}
|
||||
}, data = null)
|
||||
}
|
||||
|
||||
private fun remapExpectValue(symbol: IrValueSymbol): IrValueParameter? {
|
||||
if (symbol !is IrValueParameterSymbol) {
|
||||
return null
|
||||
}
|
||||
|
||||
val parameter = symbol.owner
|
||||
|
||||
return when (val parent = parameter.parent) {
|
||||
is IrClass -> {
|
||||
assert(parameter == parent.thisReceiver)
|
||||
symbolTable.referenceClass(parent.descriptor.findActualForExpect() as ClassDescriptor).owner.thisReceiver!!
|
||||
}
|
||||
|
||||
is IrFunction -> {
|
||||
val actualFunction =
|
||||
symbolTable.referenceFunction(parent.descriptor.findActualForExpect() as FunctionDescriptor).owner
|
||||
when (parameter) {
|
||||
parent.dispatchReceiverParameter ->
|
||||
actualFunction.dispatchReceiverParameter!!
|
||||
parent.extensionReceiverParameter ->
|
||||
actualFunction.extensionReceiverParameter!!
|
||||
else -> {
|
||||
assert(parent.valueParameters[parameter.index] == parameter)
|
||||
actualFunction.valueParameters[parameter.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> error(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
@@ -17,9 +17,14 @@ 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.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.IrTypeParameterRemapper
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -215,3 +220,61 @@ fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index
|
||||
)
|
||||
else -> throw Error("Unexpected parameter descriptor: $this")
|
||||
}
|
||||
|
||||
fun IrExpressionBody.copyAndActualizeDefaultValue(
|
||||
actualFunction: IrFunction,
|
||||
actualValueParameter: IrValueParameter,
|
||||
expectActualTypeParametersMap: Map<IrTypeParameter, IrTypeParameter>,
|
||||
classActualizer: (IrClass) -> IrClass,
|
||||
functionActualizer: (IrFunction) -> IrFunction
|
||||
) = actualValueParameter.factory.createExpressionBody(startOffset, endOffset) {
|
||||
expression = this@copyAndActualizeDefaultValue.expression
|
||||
.deepCopyWithSymbols(actualFunction) { symbolRemapper, _ ->
|
||||
DeepCopyIrTreeWithSymbols(symbolRemapper, IrTypeParameterRemapper(expectActualTypeParametersMap))
|
||||
}
|
||||
.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
val newValue = remapExpectValue(expression.symbol) ?: return expression
|
||||
|
||||
return IrGetValueImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
newValue.type,
|
||||
newValue.symbol,
|
||||
expression.origin
|
||||
)
|
||||
}
|
||||
|
||||
private fun remapExpectValue(symbol: IrValueSymbol): IrValueParameter? {
|
||||
if (symbol !is IrValueParameterSymbol) {
|
||||
return null
|
||||
}
|
||||
|
||||
val parameter = symbol.owner
|
||||
|
||||
return when (val parent = parameter.parent) {
|
||||
is IrClass -> {
|
||||
assert(parameter == parent.thisReceiver)
|
||||
classActualizer(parent).thisReceiver!!
|
||||
}
|
||||
|
||||
is IrFunction -> {
|
||||
val function = functionActualizer(parent)
|
||||
when (parameter) {
|
||||
parent.dispatchReceiverParameter -> function.dispatchReceiverParameter!!
|
||||
parent.extensionReceiverParameter -> function.extensionReceiverParameter!!
|
||||
else -> {
|
||||
assert(parent.valueParameters[parameter.index] == parameter)
|
||||
function.valueParameters[parameter.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> error(parent)
|
||||
}
|
||||
}
|
||||
}, data = null)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user