Make @JvmOverloads work with JVM_IR
This commit is contained in:
@@ -31,6 +31,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR")
|
||||
object TO_ARRAY : IrDeclarationOriginImpl("TO_ARRAY")
|
||||
object JVM_STATIC_WRAPPER : IrDeclarationOriginImpl("JVM_STATIC_WRAPPER")
|
||||
object JVM_OVERLOADS_WRAPPER : IrDeclarationOriginImpl("JVM_OVERLOADS_WRAPPER")
|
||||
}
|
||||
|
||||
interface JvmLoweredStatementOrigin : IrStatementOrigin {
|
||||
|
||||
@@ -62,6 +62,7 @@ class JvmLower(val context: JvmBackendContext) {
|
||||
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
||||
SyntheticAccessorLowering(context).lower(irFile)
|
||||
BridgeLowering(context).runOnFilePostfix(irFile)
|
||||
JvmOverloadsAnnotationLowering(context).runOnFilePostfix(irFile)
|
||||
JvmStaticAnnotationLowering(context).lower(irFile)
|
||||
StaticDefaultFunctionLowering(context.state).runOnFilePostfix(irFile)
|
||||
|
||||
@@ -70,4 +71,4 @@ class JvmLower(val context: JvmBackendContext) {
|
||||
|
||||
irFile.acceptVoid(PatchDeclarationParentsVisitor())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -251,8 +251,13 @@ class ExpressionCodegen(
|
||||
|
||||
callGenerator.beforeValueParametersStart()
|
||||
val defaultMask = DefaultCallArgs(callable.valueParameterTypes.size)
|
||||
val enumConstructorDefaultArgsShift =
|
||||
if (expression.descriptor is ConstructorDescriptor && isEnumClass(expression.descriptor.containingDeclaration)) 2 else 0
|
||||
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
|
||||
else -> 0
|
||||
}
|
||||
expression.descriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
|
||||
val arg = expression.getValueArgument(i)
|
||||
val parameterType = callable.valueParameterTypes[i]
|
||||
@@ -268,7 +273,7 @@ class ExpressionCodegen(
|
||||
i,
|
||||
this@ExpressionCodegen
|
||||
)
|
||||
defaultMask.mark(i - enumConstructorDefaultArgsShift/*TODO switch to separate lower*/)
|
||||
defaultMask.mark(i - extraArgsShift/*TODO switch to separate lower*/)
|
||||
}
|
||||
else -> {
|
||||
assert(parameterDescriptor.varargElementType != null)
|
||||
@@ -1123,4 +1128,4 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo
|
||||
)
|
||||
}
|
||||
return toInts.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -92,8 +92,16 @@ class JvmDescriptorsFactory(
|
||||
val newValueParameters =
|
||||
listOf(outerThisValueParameter) +
|
||||
oldDescriptor.valueParameters.map { it.copy(newDescriptor, it.name, it.index + 1) }
|
||||
newDescriptor.initialize(newValueParameters, oldDescriptor.visibility)
|
||||
newDescriptor.returnType = oldDescriptor.returnType
|
||||
// Call the long version of `initialize()`, because otherwise default implementation inserts
|
||||
// an unwanted `dispatchReceiverParameter`
|
||||
newDescriptor.initialize(
|
||||
oldDescriptor.extensionReceiverParameter?.type,
|
||||
null,
|
||||
oldDescriptor.typeParameters,
|
||||
newValueParameters,
|
||||
oldDescriptor.returnType,
|
||||
oldDescriptor.modality,
|
||||
oldDescriptor.visibility)
|
||||
return IrConstructorSymbolImpl(newDescriptor)
|
||||
}
|
||||
|
||||
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
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.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
||||
|
||||
|
||||
class JvmOverloadsAnnotationLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
val functions = irClass.declarations.filterIsInstance<IrFunction>().filter {
|
||||
it.descriptor.findJvmOverloadsAnnotation() != null
|
||||
}
|
||||
|
||||
functions.forEach {
|
||||
generateWrappers(it, irClass)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateWrappers(target: IrFunction, irClass: IrClass) {
|
||||
val numDefaultParameters = target.symbol.descriptor.valueParameters.count { it.hasDefaultValue() }
|
||||
for (i in 0 until numDefaultParameters) {
|
||||
val wrapper = generateWrapper(target, i)
|
||||
irClass.addMember(wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateWrapper(target: IrFunction, numDefaultParametersToExpect: Int): IrFunction {
|
||||
val wrapperSymbol = generateWrapperSymbol(target.symbol, numDefaultParametersToExpect)
|
||||
val wrapperIrFunction = when (wrapperSymbol) {
|
||||
is IrConstructorSymbol -> IrConstructorImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.JVM_OVERLOADS_WRAPPER,
|
||||
wrapperSymbol
|
||||
)
|
||||
is IrSimpleFunctionSymbol -> IrFunctionImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.JVM_OVERLOADS_WRAPPER,
|
||||
wrapperSymbol
|
||||
)
|
||||
else -> error("expected IrConstructorSymbol or IrSimpleFunctionSymbol")
|
||||
}
|
||||
|
||||
wrapperIrFunction.returnType = target.returnType
|
||||
wrapperIrFunction.createParameterDeclarations()
|
||||
|
||||
val call = if (target is IrConstructor)
|
||||
IrDelegatingConstructorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target.returnType, target.symbol, target.descriptor)
|
||||
else
|
||||
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target.returnType, target.symbol)
|
||||
call.dispatchReceiver = wrapperIrFunction.dispatchReceiverParameter?.let { dispatchReceiver ->
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
dispatchReceiver.symbol
|
||||
)
|
||||
}
|
||||
call.extensionReceiver = wrapperIrFunction.extensionReceiverParameter?.let { extensionReceiver ->
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
extensionReceiver.symbol
|
||||
)
|
||||
}
|
||||
|
||||
var parametersCopied = 0
|
||||
var defaultParametersCopied = 0
|
||||
for ((i, valueParameter) in target.valueParameters.withIndex()) {
|
||||
if ((valueParameter.descriptor as ValueParameterDescriptor).hasDefaultValue()) {
|
||||
if (defaultParametersCopied < numDefaultParametersToExpect) {
|
||||
defaultParametersCopied++
|
||||
call.putValueArgument(
|
||||
i,
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
wrapperIrFunction.valueParameters[parametersCopied++].symbol
|
||||
)
|
||||
)
|
||||
} else {
|
||||
call.putValueArgument(i, null)
|
||||
}
|
||||
} else {
|
||||
call.putValueArgument(
|
||||
i,
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
wrapperIrFunction.valueParameters[parametersCopied++].symbol
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wrapperIrFunction.body = IrExpressionBodyImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, call
|
||||
)
|
||||
|
||||
target.annotations.mapTo(wrapperIrFunction.annotations) { it.deepCopyWithSymbols() }
|
||||
|
||||
return wrapperIrFunction
|
||||
}
|
||||
|
||||
private fun generateWrapperSymbol(oldSymbol: IrFunctionSymbol, numDefaultParametersToExpect: Int): IrFunctionSymbol {
|
||||
val oldDescriptor = oldSymbol.descriptor
|
||||
val newDescriptor = if (oldDescriptor is ClassConstructorDescriptor) {
|
||||
oldDescriptor.copyWithModifiedParameters(numDefaultParametersToExpect)
|
||||
} else {
|
||||
val newParameters = generateNewValueParameters(oldDescriptor, numDefaultParametersToExpect)
|
||||
oldDescriptor.newCopyBuilder()
|
||||
.setValueParameters(newParameters)
|
||||
.setOriginal(null)
|
||||
.setKind(CallableMemberDescriptor.Kind.SYNTHESIZED)
|
||||
.build()!!
|
||||
}
|
||||
|
||||
return createFunctionSymbol(newDescriptor)
|
||||
}
|
||||
|
||||
private fun ClassConstructorDescriptor.copyWithModifiedParameters(numDefaultParametersToExpect: Int): ClassConstructorDescriptor {
|
||||
val result = ClassConstructorDescriptorImpl.createSynthesized(
|
||||
this.containingDeclaration,
|
||||
annotations,
|
||||
/* isPrimary = */ false,
|
||||
source
|
||||
)
|
||||
// Call the long version of `initialize()`, because otherwise default implementation inserts
|
||||
// an unwanted `dispatchReceiverParameter`.
|
||||
result.initialize(
|
||||
extensionReceiverParameter?.type,
|
||||
dispatchReceiverParameter,
|
||||
typeParameters,
|
||||
generateNewValueParameters(this, numDefaultParametersToExpect),
|
||||
returnType,
|
||||
modality,
|
||||
visibility
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun generateNewValueParameters(
|
||||
oldDescriptor: FunctionDescriptor,
|
||||
numDefaultParametersToExpect: Int
|
||||
): List<ValueParameterDescriptor> {
|
||||
var parametersCopied = 0
|
||||
var defaultParametersCopied = 0
|
||||
val result = mutableListOf<ValueParameterDescriptor>()
|
||||
for (oldValueParameter in oldDescriptor.valueParameters) {
|
||||
if (oldValueParameter.hasDefaultValue() &&
|
||||
defaultParametersCopied < numDefaultParametersToExpect
|
||||
) {
|
||||
defaultParametersCopied++
|
||||
result.add(
|
||||
ValueParameterDescriptorImpl(
|
||||
oldDescriptor, // to be substituted with newDescriptor
|
||||
null,
|
||||
parametersCopied++,
|
||||
oldValueParameter.annotations,
|
||||
oldValueParameter.name,
|
||||
oldValueParameter.type,
|
||||
declaresDefaultValue = false,
|
||||
isCrossinline = false,
|
||||
isNoinline = false,
|
||||
varargElementType = oldValueParameter.varargElementType,
|
||||
source = oldValueParameter.source
|
||||
)
|
||||
)
|
||||
} else if (!oldValueParameter.hasDefaultValue()) {
|
||||
result.add(oldValueParameter.copy(oldDescriptor, oldValueParameter.name, parametersCopied++))
|
||||
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
+1
@@ -99,6 +99,7 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
|
||||
proxyIrFunction.createParameterDeclarations()
|
||||
|
||||
proxyIrFunction.body = createProxyBody(target, proxyIrFunction, companion)
|
||||
target.annotations.mapTo(proxyIrFunction.annotations) { it.deepCopyWithSymbols() }
|
||||
return proxyIrFunction
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
|
||||
Reference in New Issue
Block a user