Fixed bug in default args lowering + test
Made proper overridden descriptor selection.
This commit is contained in:
+2
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.validateIrFile
|
||||
import org.jetbrains.kotlin.backend.common.validateIrModule
|
||||
import org.jetbrains.kotlin.backend.konan.lower.*
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DefaultArgumentStubGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DefaultParameterInjector
|
||||
import org.jetbrains.kotlin.backend.konan.lower.LocalDeclarationsLowering
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
|
||||
+464
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.common.ir.ir2string
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
open class DefaultArgumentStubGenerator constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
||||
if (memberDeclaration is IrFunction)
|
||||
lower(memberDeclaration)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val symbols = context.ir.symbols
|
||||
|
||||
private fun lower(irFunction: IrFunction): List<IrFunction> {
|
||||
val functionDescriptor = irFunction.descriptor
|
||||
|
||||
if (!functionDescriptor.needsDefaultArgumentsLowering)
|
||||
return listOf(irFunction)
|
||||
|
||||
val bodies = functionDescriptor.valueParameters
|
||||
.mapNotNull{irFunction.getDefault(it)}
|
||||
|
||||
|
||||
log { "detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions" }
|
||||
functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} }
|
||||
if (bodies.isNotEmpty()) {
|
||||
val newIrFunction = functionDescriptor.generateDefaultsFunction(context)
|
||||
val descriptor = newIrFunction.descriptor
|
||||
log { "$functionDescriptor -> $descriptor" }
|
||||
val builder = context.createIrBuilder(newIrFunction.symbol)
|
||||
val body = builder.irBlockBody(irFunction) {
|
||||
val params = mutableListOf<IrVariableSymbol>()
|
||||
val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>()
|
||||
if (descriptor.extensionReceiverParameter != null) {
|
||||
variables[functionDescriptor.extensionReceiverParameter!!] =
|
||||
newIrFunction.extensionReceiverParameter!!.symbol
|
||||
}
|
||||
|
||||
for (valueParameter in functionDescriptor.valueParameters) {
|
||||
val parameterSymbol = newIrFunction.valueParameters[valueParameter.index].symbol
|
||||
val temporaryVariableSymbol =
|
||||
IrVariableSymbolImpl(scope.createTemporaryVariableDescriptor(parameterSymbol.descriptor))
|
||||
params.add(temporaryVariableSymbol)
|
||||
variables.put(valueParameter, temporaryVariableSymbol)
|
||||
if (valueParameter.hasDefaultValue()) {
|
||||
val kIntAnd = symbols.intAnd
|
||||
val condition = irNotEquals(irCall(kIntAnd).apply {
|
||||
dispatchReceiver = irGet(maskParameterSymbol(newIrFunction, valueParameter.index / 32))
|
||||
putValueArgument(0, irInt(1 shl (valueParameter.index % 32)))
|
||||
}, irInt(0))
|
||||
val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter)
|
||||
|
||||
/* Use previously calculated values in next expression. */
|
||||
expressionBody.transformChildrenVoid(object: IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
log { "GetValue: ${expression.descriptor}" }
|
||||
val valueSymbol = variables[expression.descriptor] ?: return expression
|
||||
return irGet(valueSymbol)
|
||||
}
|
||||
})
|
||||
val variableInitialization = irIfThenElse(
|
||||
type = temporaryVariableSymbol.descriptor.type,
|
||||
condition = condition,
|
||||
thenPart = expressionBody.expression,
|
||||
elsePart = irGet(parameterSymbol))
|
||||
+ scope.createTemporaryVariable(
|
||||
symbol = temporaryVariableSymbol,
|
||||
initializer = variableInitialization)
|
||||
/* Mapping calculated values with its origin variables. */
|
||||
} else {
|
||||
+ scope.createTemporaryVariable(
|
||||
symbol = temporaryVariableSymbol,
|
||||
initializer = irGet(parameterSymbol))
|
||||
}
|
||||
}
|
||||
if (irFunction is IrConstructor) {
|
||||
+ IrDelegatingConstructorCallImpl(
|
||||
startOffset = irFunction.startOffset,
|
||||
endOffset = irFunction.endOffset,
|
||||
symbol = irFunction.symbol, descriptor = irFunction.symbol.descriptor
|
||||
).apply {
|
||||
params.forEachIndexed { i, variable ->
|
||||
putValueArgument(i, irGet(variable))
|
||||
}
|
||||
if (functionDescriptor.dispatchReceiverParameter != null) {
|
||||
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
+irReturn(irCall(irFunction.symbol).apply {
|
||||
if (functionDescriptor.dispatchReceiverParameter != null) {
|
||||
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
|
||||
}
|
||||
if (functionDescriptor.extensionReceiverParameter != null) {
|
||||
extensionReceiver = irGet(variables[functionDescriptor.extensionReceiverParameter!!]!!)
|
||||
}
|
||||
params.forEachIndexed { i, variable ->
|
||||
putValueArgument(i, irGet(variable))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// Remove default argument initializers.
|
||||
irFunction.valueParameters.forEach {
|
||||
it.defaultValue = null
|
||||
}
|
||||
return if (functionDescriptor is ClassConstructorDescriptor)
|
||||
listOf(irFunction, IrConstructorImpl(
|
||||
startOffset = irFunction.startOffset,
|
||||
endOffset = irFunction.endOffset,
|
||||
descriptor = descriptor as ClassConstructorDescriptor,
|
||||
origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||
body = body).apply { createParameterDeclarations() })
|
||||
else
|
||||
listOf(irFunction, IrFunctionImpl(
|
||||
startOffset = irFunction.startOffset,
|
||||
endOffset = irFunction.endOffset,
|
||||
descriptor = descriptor,
|
||||
origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||
body = body).apply { createParameterDeclarations() })
|
||||
}
|
||||
return listOf(irFunction)
|
||||
}
|
||||
|
||||
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
|
||||
}
|
||||
|
||||
private fun Scope.createTemporaryVariableDescriptor(parameterDescriptor: ParameterDescriptor?): VariableDescriptor =
|
||||
IrTemporaryVariableDescriptorImpl(
|
||||
containingDeclaration = this.scopeOwner,
|
||||
name = parameterDescriptor!!.name.asString().synthesizedName,
|
||||
outType = parameterDescriptor.type,
|
||||
isMutable = false)
|
||||
|
||||
private fun Scope.createTemporaryVariable(symbol: IrVariableSymbol, initializer: IrExpression) =
|
||||
IrVariableImpl(
|
||||
startOffset = initializer.startOffset,
|
||||
endOffset = initializer.endOffset,
|
||||
origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
||||
symbol = symbol).apply {
|
||||
|
||||
this.initializer = initializer
|
||||
}
|
||||
|
||||
private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor): IrExpressionBody {
|
||||
return irFunction.getDefault(valueParameter) ?: TODO("FIXME!!!")
|
||||
}
|
||||
|
||||
private fun maskParameterDescriptor(function: IrFunction, number: Int) =
|
||||
maskParameterSymbol(function, number).descriptor as ValueParameterDescriptor
|
||||
private fun maskParameterSymbol(function: IrFunction, number: Int) =
|
||||
function.valueParameters.single { it.descriptor.name == parameterMaskName(number) }.symbol
|
||||
|
||||
private fun markerParameterDescriptor(descriptor: FunctionDescriptor) = descriptor.valueParameters.single { it.name == kConstructorMarkerName }
|
||||
|
||||
private fun nullConst(expression: IrElement, type: KotlinType): IrExpression? {
|
||||
when {
|
||||
KotlinBuiltIns.isFloat(type) -> return IrConstImpl.float (expression.startOffset, expression.endOffset, type, 0.0F)
|
||||
KotlinBuiltIns.isDouble(type) -> return IrConstImpl.double (expression.startOffset, expression.endOffset, type, 0.0)
|
||||
KotlinBuiltIns.isBoolean(type) -> return IrConstImpl.boolean (expression.startOffset, expression.endOffset, type, false)
|
||||
KotlinBuiltIns.isByte(type) -> return IrConstImpl.byte (expression.startOffset, expression.endOffset, type, 0)
|
||||
KotlinBuiltIns.isChar(type) -> return IrConstImpl.char (expression.startOffset, expression.endOffset, type, 0.toChar())
|
||||
KotlinBuiltIns.isShort(type) -> return IrConstImpl.short (expression.startOffset, expression.endOffset, type, 0)
|
||||
KotlinBuiltIns.isInt(type) -> return IrConstImpl.int (expression.startOffset, expression.endOffset, type, 0)
|
||||
KotlinBuiltIns.isLong(type) -> return IrConstImpl.long (expression.startOffset, expression.endOffset, type, 0)
|
||||
else -> return IrConstImpl.constNull (expression.startOffset, expression.endOffset, type.builtIns.nullableNothingType)
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultParameterInjector constructor(val context: CommonBackendContext): BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody) {
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
super.visitDelegatingConstructorCall(expression)
|
||||
val descriptor = expression.descriptor
|
||||
if (!descriptor.needsDefaultArgumentsLowering)
|
||||
return expression
|
||||
val argumentsCount = argumentCount(expression)
|
||||
if (argumentsCount == descriptor.valueParameters.size)
|
||||
return expression
|
||||
val (symbolForCall, params) = parametersForCall(expression)
|
||||
return IrDelegatingConstructorCallImpl(
|
||||
startOffset = expression.startOffset,
|
||||
endOffset = expression.endOffset,
|
||||
symbol = symbolForCall as IrConstructorSymbol,
|
||||
descriptor = symbolForCall.descriptor)
|
||||
.apply {
|
||||
params.forEach {
|
||||
log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" }
|
||||
putValueArgument(it.first.index, it.second)
|
||||
}
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
super.visitCall(expression)
|
||||
val functionDescriptor = expression.descriptor
|
||||
|
||||
if (!functionDescriptor.needsDefaultArgumentsLowering)
|
||||
return expression
|
||||
|
||||
val argumentsCount = argumentCount(expression)
|
||||
if (argumentsCount == functionDescriptor.valueParameters.size)
|
||||
return expression
|
||||
val (symbol, params) = parametersForCall(expression)
|
||||
val descriptor = symbol.descriptor
|
||||
descriptor.typeParameters.forEach { log { "$descriptor [${it.index}]: $it" } }
|
||||
descriptor.original.typeParameters.forEach { log { "${descriptor.original}[${it.index}] : $it" } }
|
||||
return IrCallImpl(
|
||||
startOffset = expression.startOffset,
|
||||
endOffset = expression.endOffset,
|
||||
symbol = symbol,
|
||||
descriptor = descriptor,
|
||||
typeArguments = expression.descriptor.typeParameters.map{it to (expression.getTypeArgument(it) ?: it.defaultType) }.toMap())
|
||||
.apply {
|
||||
params.forEach {
|
||||
log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" }
|
||||
putValueArgument(it.first.index, it.second)
|
||||
}
|
||||
expression.extensionReceiver?.apply{
|
||||
extensionReceiver = expression.extensionReceiver
|
||||
}
|
||||
expression.dispatchReceiver?.apply {
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
}
|
||||
log { "call::extension@: ${ir2string(expression.extensionReceiver)}" }
|
||||
log { "call::dispatch@: ${ir2string(expression.dispatchReceiver)}" }
|
||||
}
|
||||
}
|
||||
|
||||
private fun parametersForCall(expression: IrMemberAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> {
|
||||
val descriptor = expression.descriptor as FunctionDescriptor
|
||||
val keyDescriptor = if (DescriptorUtils.isOverride(descriptor))
|
||||
DescriptorUtils.getAllOverriddenDescriptors(descriptor).first { it.needsDefaultArgumentsLowering }
|
||||
else
|
||||
descriptor.original
|
||||
val realFunction = keyDescriptor.generateDefaultsFunction(context)
|
||||
val realDescriptor = realFunction.descriptor
|
||||
|
||||
log { "$descriptor -> $realDescriptor" }
|
||||
val maskValues = Array((descriptor.valueParameters.size + 31) / 32, { 0 })
|
||||
val params = mutableListOf<Pair<ValueParameterDescriptor, IrExpression?>>()
|
||||
params.addAll(descriptor.valueParameters.mapIndexed { i, _ ->
|
||||
val valueArgument = expression.getValueArgument(i)
|
||||
if (valueArgument == null) {
|
||||
val maskIndex = i / 32
|
||||
maskValues[maskIndex] = maskValues[maskIndex] or (1 shl (i % 32))
|
||||
}
|
||||
val valueParameterDescriptor = realDescriptor.valueParameters[i]
|
||||
val pair = valueParameterDescriptor to (valueArgument ?: nullConst(expression, valueParameterDescriptor.type))
|
||||
return@mapIndexed pair
|
||||
})
|
||||
maskValues.forEachIndexed { i, maskValue ->
|
||||
params += maskParameterDescriptor(realFunction, i) to IrConstImpl.int(
|
||||
startOffset = irBody.startOffset,
|
||||
endOffset = irBody.endOffset,
|
||||
type = descriptor.builtIns.intType,
|
||||
value = maskValue)
|
||||
}
|
||||
if (expression.descriptor is ClassConstructorDescriptor) {
|
||||
val defaultArgumentMarker = context.ir.symbols.defaultConstructorMarker
|
||||
params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl(
|
||||
startOffset = irBody.startOffset,
|
||||
endOffset = irBody.endOffset,
|
||||
type = defaultArgumentMarker.owner.defaultType,
|
||||
symbol = defaultArgumentMarker)
|
||||
}
|
||||
else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||
params += realDescriptor.valueParameters.last() to
|
||||
IrConstImpl.constNull(irBody.startOffset, irBody.endOffset, context.builtIns.any.defaultType)
|
||||
}
|
||||
params.forEach {
|
||||
log { "descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}" }
|
||||
}
|
||||
return Pair(realFunction.symbol, params)
|
||||
}
|
||||
|
||||
private fun argumentCount(expression: IrMemberAccessExpression) =
|
||||
expression.descriptor.valueParameters.count { expression.getValueArgument(it) != null }
|
||||
})
|
||||
}
|
||||
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" }
|
||||
}
|
||||
|
||||
private val CallableMemberDescriptor.needsDefaultArgumentsLowering
|
||||
get() = valueParameters.any { it.hasDefaultValue() } && !(this is FunctionDescriptor && isInline)
|
||||
|
||||
private fun FunctionDescriptor.generateDefaultsFunction(context: CommonBackendContext): IrFunction {
|
||||
return context.ir.defaultParameterDeclarationsCache.getOrPut(this) {
|
||||
val descriptor = when (this) {
|
||||
is ClassConstructorDescriptor ->
|
||||
ClassConstructorDescriptorImpl.create(
|
||||
/* containingDeclaration = */ containingDeclaration,
|
||||
/* annotations = */ annotations,
|
||||
/* isPrimary = */ false,
|
||||
/* source = */ source)
|
||||
else -> {
|
||||
val name = Name.identifier("$name\$default")
|
||||
|
||||
SimpleFunctionDescriptorImpl.create(
|
||||
/* containingDeclaration = */ containingDeclaration,
|
||||
/* annotations = */ annotations,
|
||||
/* name = */ name,
|
||||
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
/* source = */ source)
|
||||
}
|
||||
}
|
||||
|
||||
val syntheticParameters = MutableList((valueParameters.size + 31) / 32) { i ->
|
||||
valueParameter(descriptor, valueParameters.size + i, parameterMaskName(i), descriptor.builtIns.intType)
|
||||
}
|
||||
if (this is ClassConstructorDescriptor) {
|
||||
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
|
||||
kConstructorMarkerName,
|
||||
context.ir.symbols.defaultConstructorMarker.owner.defaultType)
|
||||
}
|
||||
else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
|
||||
"handler".synthesizedName,
|
||||
context.ir.symbols.any.owner.defaultType)
|
||||
}
|
||||
|
||||
descriptor.initialize(
|
||||
/* receiverParameterType = */ extensionReceiverParameter?.type,
|
||||
/* dispatchReceiverParameter = */ dispatchReceiverParameter,
|
||||
/* typeParameters = */ typeParameters.map {
|
||||
TypeParameterDescriptorImpl.createForFurtherModification(
|
||||
/* containingDeclaration = */ descriptor,
|
||||
/* annotations = */ it.annotations,
|
||||
/* reified = */ it.isReified,
|
||||
/* variance = */ it.variance,
|
||||
/* name = */ it.name,
|
||||
/* index = */ it.index,
|
||||
/* source = */ it.source,
|
||||
/* reportCycleError = */ null,
|
||||
/* supertypeLoopsChecker = */ SupertypeLoopChecker.EMPTY
|
||||
).apply {
|
||||
it.upperBounds.forEach { addUpperBound(it) }
|
||||
setInitialized()
|
||||
}
|
||||
},
|
||||
/* unsubstitutedValueParameters = */ valueParameters.map {
|
||||
ValueParameterDescriptorImpl(
|
||||
containingDeclaration = descriptor,
|
||||
original = null, /* ValueParameterDescriptorImpl::copy do not save original. */
|
||||
index = it.index,
|
||||
annotations = it.annotations,
|
||||
name = it.name,
|
||||
outType = it.type,
|
||||
declaresDefaultValue = false,
|
||||
isCrossinline = it.isCrossinline,
|
||||
isNoinline = it.isNoinline,
|
||||
varargElementType = it.varargElementType,
|
||||
source = it.source)
|
||||
} + syntheticParameters,
|
||||
/* unsubstitutedReturnType = */ returnType,
|
||||
/* modality = */ Modality.FINAL,
|
||||
/* visibility = */ this.visibility)
|
||||
descriptor.isSuspend = this.isSuspend
|
||||
context.log{"adds to cache[$this] = $descriptor"}
|
||||
|
||||
val startOffset = this.startOffsetOrUndefined
|
||||
val endOffset = this.endOffsetOrUndefined
|
||||
|
||||
val result: IrFunction = when (descriptor) {
|
||||
is ClassConstructorDescriptor -> IrConstructorImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||
descriptor
|
||||
)
|
||||
|
||||
else -> IrFunctionImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
|
||||
descriptor
|
||||
)
|
||||
}
|
||||
|
||||
result.createParameterDeclarations()
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER :
|
||||
IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT")
|
||||
|
||||
private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: Name, type: KotlinType): ValueParameterDescriptor {
|
||||
return ValueParameterDescriptorImpl(
|
||||
containingDeclaration = descriptor,
|
||||
original = null,
|
||||
index = index,
|
||||
annotations = Annotations.EMPTY,
|
||||
name = name,
|
||||
outType = type,
|
||||
declaresDefaultValue = false,
|
||||
isCrossinline = false,
|
||||
isNoinline = false,
|
||||
varargElementType = null,
|
||||
source = SourceElement.NO_SOURCE
|
||||
)
|
||||
}
|
||||
|
||||
internal val kConstructorMarkerName = "marker".synthesizedName
|
||||
|
||||
private fun parameterMaskName(number: Int) = "mask$number".synthesizedName
|
||||
@@ -349,6 +349,11 @@ task function_defaults10(type: RunKonanTest) {
|
||||
source = "codegen/function/defaults10.kt"
|
||||
}
|
||||
|
||||
task function_defaults_from_fake_override(type: RunKonanTest) {
|
||||
goldValue = "42\n"
|
||||
source = "codegen/function/defaultsFromFakeOverride.kt"
|
||||
}
|
||||
|
||||
task sum_3const(type: RunKonanTest) {
|
||||
source = "codegen/function/sum_3const.kt"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package codegen.function.defaultsFromFakeOverride
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
interface I<T> {
|
||||
fun f(x: String = "42"): String
|
||||
}
|
||||
|
||||
open class A<T> {
|
||||
open fun f(x: String) = x
|
||||
}
|
||||
|
||||
class B : A<String>(), I<String>
|
||||
|
||||
@Test fun runTest() {
|
||||
val b = B()
|
||||
println(b.f())
|
||||
}
|
||||
Reference in New Issue
Block a user