Add annotation for default parameter value

This commit is contained in:
Leonid Stashevsky
2017-10-04 14:03:23 +03:00
parent 62e87c873c
commit 0348561cd2
48 changed files with 1827 additions and 39 deletions
@@ -17,10 +17,12 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.mapToIndex
class ArgumentAndDeclIndex(val arg: ResolvedValueArgument, val declIndex: Int)
@@ -66,8 +68,13 @@ abstract class ArgumentGenerator {
generateExpression(declIndex, argument)
}
is DefaultValueArgument -> {
defaultArgs.mark(declIndex)
generateDefault(declIndex, argument)
if (calleeDescriptor?.defaultValueFromJava(declIndex) == true) {
generateDefaultJava(declIndex, argument)
}
else {
defaultArgs.mark(declIndex)
generateDefault(declIndex, argument)
}
}
is VarargValueArgument -> {
generateVararg(declIndex, argument)
@@ -95,6 +102,10 @@ abstract class ArgumentGenerator {
throw UnsupportedOperationException("Unsupported vararg value argument #$i: $argument")
}
protected open fun generateDefaultJava(i: Int, argument: DefaultValueArgument) {
throw UnsupportedOperationException("Unsupported default java argument #$i: $argument")
}
protected open fun generateOther(i: Int, argument: ResolvedValueArgument) {
throw UnsupportedOperationException("Unsupported value argument #$i: $argument")
}
@@ -103,3 +114,13 @@ abstract class ArgumentGenerator {
throw UnsupportedOperationException("Unsupported operation")
}
}
private fun CallableDescriptor.defaultValueFromJava(index: Int): Boolean = DFS.ifAny(
listOf(this),
{ current -> current.original.overriddenDescriptors.map { it.original } },
{ descriptor ->
descriptor.original.overriddenDescriptors.isEmpty() &&
descriptor is JavaCallableMemberDescriptor &&
descriptor.valueParameters[index].declaresDefaultValue()
}
)
@@ -28,7 +28,7 @@ import org.jetbrains.org.objectweb.asm.Type;
import java.util.List;
import static org.jetbrains.kotlin.codegen.StackValue.createDefaultValue;
import static org.jetbrains.kotlin.codegen.StackValue.*;
public class CallBasedArgumentGenerator extends ArgumentGenerator {
private final ExpressionCodegen codegen;
@@ -76,6 +76,17 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
callGenerator.putValueIfNeeded(valueParameterTypes.get(i), lazyVararg, ValueKind.GENERAL_VARARG, i);
}
@Override
protected void generateDefaultJava(int i, @NotNull DefaultValueArgument argument) {
StackValue argumentValue = StackValueKt.findJavaDefaultArgumentValue(
valueParameters.get(i),
valueParameterTypes.get(i),
codegen.typeMapper
);
callGenerator.putValueIfNeeded(valueParameterTypes.get(i), argumentValue);
}
@Override
protected void reorderArgumentsIfNeeded(@NotNull List<ArgumentAndDeclIndex> actualArgsWithDeclIndex) {
callGenerator.reorderArgumentsIfNeeded(actualArgsWithDeclIndex, valueParameterTypes);
@@ -1467,7 +1467,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (isAnonymousObject(descriptor)) {
List<JvmMethodParameterSignature> superValues = superParameters.subList(superIndex, superParameters.size());
return new ObjectSuperCallArgumentGenerator(superValues, iv, offset, superConstructorCall);
return new ObjectSuperCallArgumentGenerator(
superValues, iv,
superConstructor.getValueParameters(), codegen.typeMapper,
offset, superConstructorCall
);
}
else {
return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, superConstructor.getValueParameters(),
@@ -17,15 +17,20 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.AsmUtil.pushDefaultValueOnStack
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
internal class ObjectSuperCallArgumentGenerator(
private val parameters: List<JvmMethodParameterSignature>,
private val iv: InstructionAdapter,
private val superValueParameters: List<ValueParameterDescriptor>,
private val typeMapper: KotlinTypeMapper,
offset: Int,
superConstructorCall: ResolvedCall<ConstructorDescriptor>
) : ArgumentGenerator() {
@@ -59,6 +64,12 @@ internal class ObjectSuperCallArgumentGenerator(
pushDefaultValueOnStack(type, iv)
}
public override fun generateDefaultJava(i: Int, argument: DefaultValueArgument) {
val type = parameters[i].asmType
val value = superValueParameters[i].findJavaDefaultArgumentValue(type, typeMapper)
value.put(type, iv)
}
public override fun generateVararg(i: Int, argument: VarargValueArgument) {
generateSuperCallArgument(i)
}
@@ -16,6 +16,16 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.AsmUtil.unboxPrimitiveTypeOrNull
import org.jetbrains.kotlin.codegen.StackValue.*
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.load.java.*
import org.jetbrains.kotlin.load.java.Constant
import org.jetbrains.kotlin.load.java.descriptors.NullDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.StringDefaultValue
import org.jetbrains.kotlin.load.java.descriptors.getDefaultValueFromAnnotation
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -68,3 +78,40 @@ open class OperationStackValue(resultType: Type, val lambda: (v: InstructionAdap
}
class FunctionCallStackValue(resultType: Type, lambda: (v: InstructionAdapter) -> Unit) : OperationStackValue(resultType, lambda)
fun ValueParameterDescriptor.findJavaDefaultArgumentValue(targetType: Type, typeMapper: KotlinTypeMapper): StackValue {
val descriptorWithDefaultValue = DFS.dfs(
listOf(this.original),
{ it.original.overriddenDescriptors.map(ValueParameterDescriptor::getOriginal) },
object : DFS.AbstractNodeHandler<ValueParameterDescriptor, ValueParameterDescriptor?>() {
var result: ValueParameterDescriptor? = null
override fun beforeChildren(current: ValueParameterDescriptor?): Boolean {
if (current?.declaresDefaultValue() == true && current.getDefaultValueFromAnnotation() != null) {
result = current
return false
}
return true
}
override fun result(): ValueParameterDescriptor? = result
}
) ?: error("Should be at least one descriptor with default value: $this")
val defaultValue = descriptorWithDefaultValue.getDefaultValueFromAnnotation()
if (defaultValue is NullDefaultValue) {
return constant(null, targetType)
}
val value = (defaultValue as StringDefaultValue).value
val castResult = type.lexicalCastFrom(value) ?: error("Should be checked in frontend")
return when (castResult) {
is EnumEntry -> enumEntry(castResult.descriptor, typeMapper)
is Constant -> {
val unboxedType = unboxPrimitiveTypeOrNull(targetType) ?: targetType
return coercion(constant(castResult.value, unboxedType), targetType)
}
}
}