Use TypeSystemCommonBackendContext in KotlinTypeMapper.writeGenericArguments

This commit is contained in:
Alexander Udalov
2019-06-21 13:41:43 +02:00
parent 2585ce0aa7
commit c27d9c4546
5 changed files with 81 additions and 35 deletions
@@ -352,26 +352,9 @@ class KotlinTypeMapper @JvmOverloads constructor(
parameters: List<TypeParameterDescriptor>,
mode: TypeMappingMode
) {
for ((parameter, argument) in parameters.zip(arguments)) {
if (argument.isStarProjection ||
// In<Nothing, Foo> == In<*, Foo> -> In<?, Foo>
KotlinBuiltIns.isNothing(argument.type) && parameter.variance === Variance.IN_VARIANCE
) {
signatureVisitor.writeUnboundedWildcard()
} else {
val argumentMode = mode.updateArgumentModeFromAnnotations(argument.type)
val projectionKind = getVarianceForWildcard(parameter, argument, argumentMode)
signatureVisitor.writeTypeArgument(projectionKind)
mapType(
argument.type, signatureVisitor,
argumentMode.toGenericArgumentMode(
getEffectiveVariance(parameter.variance, argument.projectionKind)
)
)
signatureVisitor.writeTypeArgumentEnd()
with(SimpleClassicTypeSystemContext) {
writeGenericArguments(signatureVisitor, arguments, parameters, mode) { type, sw, mode ->
mapType(type as KotlinType, sw, mode)
}
}
}
@@ -1502,6 +1485,37 @@ class KotlinTypeMapper @JvmOverloads constructor(
return Variance.OUT_VARIANCE
}
fun TypeSystemCommonBackendContext.writeGenericArguments(
signatureVisitor: JvmSignatureWriter,
arguments: List<TypeArgumentMarker>,
parameters: List<TypeParameterMarker>,
mode: TypeMappingMode,
mapType: (KotlinTypeMarker, JvmSignatureWriter, TypeMappingMode) -> Type
) {
for ((parameter, argument) in parameters.zip(arguments)) {
if (argument.isStarProjection() ||
// In<Nothing, Foo> == In<*, Foo> -> In<?, Foo>
argument.getType().isNothing() && parameter.getVariance() == TypeVariance.IN
) {
signatureVisitor.writeUnboundedWildcard()
} else {
val argumentMode = mode.updateArgumentModeFromAnnotations(argument.getType(), this)
val projectionKind = getVarianceForWildcard(parameter, argument, argumentMode)
signatureVisitor.writeTypeArgument(projectionKind)
mapType(
argument.getType(), signatureVisitor,
argumentMode.toGenericArgumentMode(
getEffectiveVariance(parameter.getVariance().convertVariance(), argument.getVariance().convertVariance())
)
)
signatureVisitor.writeTypeArgumentEnd()
}
}
}
//NB: similar platform agnostic code in DescriptorUtils.unwrapFakeOverride
private fun findSuperDeclaration(descriptor: FunctionDescriptor, isSuperCall: Boolean): FunctionDescriptor {
var current = descriptor
@@ -15,6 +15,7 @@
*/
@file:JvmName("TypeMappingUtil")
package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.convertVariance
import org.jetbrains.kotlin.types.getEffectiveVariance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
@@ -82,8 +84,10 @@ private val METHODS_WITH_DECLARATION_SITE_WILDCARDS = setOf(
BUILTIN_NAMES.mutableMap.child("putAll")
)
fun TypeMappingMode.updateArgumentModeFromAnnotations(type: KotlinType): TypeMappingMode {
type.suppressWildcardsMode()?.let {
fun TypeMappingMode.updateArgumentModeFromAnnotations(
type: KotlinTypeMarker, typeSystem: TypeSystemCommonBackendContext
): TypeMappingMode {
type.suppressWildcardsMode(typeSystem)?.let {
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = it,
isForAnnotationParameter = isForAnnotationParameter,
@@ -91,12 +95,12 @@ fun TypeMappingMode.updateArgumentModeFromAnnotations(type: KotlinType): TypeMap
)
}
if (type.annotations.hasAnnotation(JVM_WILDCARD_ANNOTATION_FQ_NAME)) {
if (with(typeSystem) { type.hasAnnotation(JVM_WILDCARD_ANNOTATION_FQ_NAME) }) {
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = false,
isForAnnotationParameter = isForAnnotationParameter,
fallbackMode = this,
needInlineClassWrapping = needInlineClassWrapping
skipDeclarationSiteWildcards = false,
isForAnnotationParameter = isForAnnotationParameter,
fallbackMode = this,
needInlineClassWrapping = needInlineClassWrapping
)
}
@@ -108,7 +112,7 @@ internal fun extractTypeMappingModeFromAnnotation(
outerType: KotlinType,
isForAnnotationParameter: Boolean
): TypeMappingMode? =
(outerType.suppressWildcardsMode() ?: callableDescriptor?.suppressWildcardsMode())?.let {
(outerType.suppressWildcardsMode(SimpleClassicTypeSystemContext) ?: callableDescriptor?.suppressWildcardsMode())?.let {
if (outerType.arguments.isNotEmpty())
TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
skipDeclarationSiteWildcards = it,
@@ -122,14 +126,17 @@ internal fun extractTypeMappingModeFromAnnotation(
private fun DeclarationDescriptor.suppressWildcardsMode(): Boolean? =
parentsWithSelf.mapNotNull {
it.annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME)
}.firstOrNull().suppressWildcardsMode()
}.firstOrNull()?.suppressWildcardsMode()
private fun KotlinType.suppressWildcardsMode(): Boolean? =
annotations.findAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME).suppressWildcardsMode()
private fun KotlinTypeMarker.suppressWildcardsMode(typeSystem: TypeSystemCommonBackendContext): Boolean? =
with(typeSystem) {
if (hasAnnotation(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME))
getAnnotationFirstArgumentValue(JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME) as? Boolean ?: true
else null
}
private fun AnnotationDescriptor?.suppressWildcardsMode(): Boolean? {
return (this ?: return null).allValueArguments.values.firstOrNull()?.value as? Boolean ?: true
}
private fun AnnotationDescriptor.suppressWildcardsMode(): Boolean? =
allValueArguments.values.firstOrNull()?.value as? Boolean ?: true
val JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSuppressWildcards")
val JVM_WILDCARD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmWildcard")
@@ -5,9 +5,23 @@
package org.jetbrains.kotlin.types
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSystemContext
interface TypeSystemCommonBackendContext : TypeSystemContext {
fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean
fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean
/**
* @return value of the first argument of the annotation with the given [fqName], if the annotation is present and
* the argument is of a primitive type or a String, or null otherwise.
*
* Note that this method returns null if no arguments are provided, even if the corresponding annotation parameter has a default value.
*
* TODO: provide a more granular & elaborate API here to reduce confusion
*/
fun KotlinTypeMarker.getAnnotationFirstArgumentValue(fqName: FqName): Any?
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation
@@ -485,6 +486,15 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return this is NewCapturedTypeConstructor
}
override fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean {
require(this is KotlinType, this::errorMessage)
return annotations.hasAnnotation(fqName)
}
override fun KotlinTypeMarker.getAnnotationFirstArgumentValue(fqName: FqName): Any? {
require(this is KotlinType, this::errorMessage)
return annotations.findAnnotation(fqName)?.allValueArguments?.values?.firstOrNull()?.value
}
}
fun TypeVariance.convertVariance(): Variance {
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
private typealias SubstitutionMap = Map<String, Pair<KtTypeParameter, KtTypeProjection>>
@@ -145,7 +146,7 @@ class ErrorTypeCorrector(
RETURN_TYPE -> TypeMappingMode.getOptimalModeForReturnType(kotlinType, false)
METHOD_PARAMETER_TYPE -> TypeMappingMode.getOptimalModeForValueParameter(kotlinType)
SUPER_TYPE -> TypeMappingMode.SUPER_TYPE
}.updateArgumentModeFromAnnotations(kotlinType)
}.updateArgumentModeFromAnnotations(kotlinType, SimpleClassicTypeSystemContext)
val typeParameters = (target as? ClassifierDescriptor)?.typeConstructor?.parameters
return treeMaker.TypeApply(baseExpression, mapJListIndexed(arguments) { index, projection ->