Support JvmSuppressWildcards and JvmWildcard annotations

#KT-9898 Fixed
This commit is contained in:
Denis Zharkov
2015-11-27 11:49:36 +03:00
parent 6292833a69
commit ddb67d6c9c
14 changed files with 279 additions and 5 deletions
@@ -326,9 +326,16 @@ public class JetTypeMapper {
return mapType(descriptor.getReturnType(), sw, TypeMappingMode.GENERIC_TYPE);
}
else {
boolean isAnnotationMethod = DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration());
TypeMappingMode typeMappingModeFromAnnotation =
TypeMappingUtil.extractTypeMappingModeFromAnnotation(descriptor, returnType, isAnnotationMethod);
if (typeMappingModeFromAnnotation != null) {
return mapType(returnType, sw, typeMappingModeFromAnnotation);
}
TypeMappingMode mappingMode = TypeMappingMode.getOptimalModeForReturnType(
returnType,
/* isAnnotationMethod = */ DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration()));
/* isAnnotationMethod = */ isAnnotationMethod);
return mapType(returnType, sw, mappingMode);
}
@@ -631,11 +638,13 @@ public class JetTypeMapper {
signatureVisitor.writeUnboundedWildcard();
}
else {
Variance projectionKind = getVarianceForWildcard(parameter, argument, mode);
TypeMappingMode argumentMode = TypeMappingUtil.updateArgumentModeFromAnnotations(mode, argument.getType());
Variance projectionKind = getVarianceForWildcard(parameter, argument, argumentMode);
signatureVisitor.writeTypeArgument(projectionKind);
mapType(argument.getType(), signatureVisitor,
mode.toGenericArgumentMode(
argumentMode.toGenericArgumentMode(
TypeMappingUtil.getEffectiveVariance(parameter.getVariance(), argument.getProjectionKind())));
signatureVisitor.writeTypeArgumentEnd();
@@ -1204,7 +1213,13 @@ public class JetTypeMapper {
TypeMappingMode typeMappingMode;
if (TypeMappingUtil.isMethodWithDeclarationSiteWildcards(callableDescriptor) && !type.getArguments().isEmpty()) {
TypeMappingMode typeMappingModeFromAnnotation =
TypeMappingUtil.extractTypeMappingModeFromAnnotation(callableDescriptor, type, /* isForAnnotationParameter = */ false);
if (typeMappingModeFromAnnotation != null) {
typeMappingMode = typeMappingModeFromAnnotation;
}
else if (TypeMappingUtil.isMethodWithDeclarationSiteWildcards(callableDescriptor) && !type.getArguments().isEmpty()) {
typeMappingMode = TypeMappingMode.GENERIC_TYPE; // Render all wildcards
}
else {
@@ -93,6 +93,16 @@ internal class TypeMappingMode private constructor(
skipDeclarationSiteWildcardsIfPossible = true,
genericContravariantArgumentMode = contravariantArgumentMode)
}
@JvmStatic
fun createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards: Boolean,
isForAnnotationParameter: Boolean,
fallbackMode: TypeMappingMode? = null
) = TypeMappingMode(
isForAnnotationParameter = isForAnnotationParameter,
skipDeclarationSiteWildcards = skipDeclarationSiteWildcards,
genericArgumentMode = fallbackMode)
}
fun toGenericArgumentMode(effectiveVariance: Variance): TypeMappingMode =
@@ -19,9 +19,11 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
@@ -83,3 +85,45 @@ private val METHODS_WITH_DECLARATION_SITE_WILDCARDS = setOf(
FqName("kotlin.MutableList.addAll"),
FqName("kotlin.MutableMap.putAll")
)
internal fun TypeMappingMode.updateArgumentModeFromAnnotations(type: KotlinType): TypeMappingMode {
type.suppressWildcardsMode()?.let {
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = it, isForAnnotationParameter = isForAnnotationParameter)
}
if (type.annotations.hasAnnotation(JVM_WILDCARD_ANNOTATION_FQ_NAME)) {
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = false, isForAnnotationParameter = isForAnnotationParameter, fallbackMode = this)
}
return this
}
internal fun extractTypeMappingModeFromAnnotation(
callableDescriptor: CallableDescriptor,
outerType: KotlinType,
isForAnnotationParameter: Boolean
): TypeMappingMode? =
(outerType.suppressWildcardsMode() ?: callableDescriptor.suppressWildcardsMode())?.let {
if (outerType.arguments.isNotEmpty())
TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = it, isForAnnotationParameter = isForAnnotationParameter)
else
TypeMappingMode.DEFAULT
}
private fun DeclarationDescriptor.suppressWildcardsMode(): Boolean? =
parentsWithSelf.mapNotNull {
it.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)
}.firstOrNull().suppressWildcardsMode()
private fun KotlinType.suppressWildcardsMode(): Boolean? =
annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME).suppressWildcardsMode()
private fun AnnotationDescriptor?.suppressWildcardsMode(): Boolean? {
return (this ?: return null).allValueArguments.values.firstOrNull()?.value as? Boolean ?: true
}
private val JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSuppressWildcards")
private val JVM_WILDCARD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmWildcard")