Introduce TypeSystemCommonBackendContext, use in KotlinTypeMapper.getVarianceForWildcard

This commit is contained in:
Alexander Udalov
2019-06-19 19:30:42 +02:00
parent 0460b2990f
commit 2585ce0aa7
4 changed files with 67 additions and 39 deletions
@@ -67,10 +67,9 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Descriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.convertVariance
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.* import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.model.TypeSystemContext
import org.jetbrains.kotlin.types.model.TypeVariance
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -1468,9 +1467,14 @@ class KotlinTypeMapper @JvmOverloads constructor(
return false return false
} }
fun getVarianceForWildcard(parameter: TypeParameterDescriptor, projection: TypeProjection, mode: TypeMappingMode): Variance { fun getVarianceForWildcard(parameter: TypeParameterDescriptor, projection: TypeProjection, mode: TypeMappingMode): Variance =
val projectionKind = projection.projectionKind SimpleClassicTypeSystemContext.getVarianceForWildcard(parameter, projection, mode)
val parameterVariance = parameter.variance
private fun TypeSystemCommonBackendContext.getVarianceForWildcard(
parameter: TypeParameterMarker, projection: TypeArgumentMarker, mode: TypeMappingMode
): Variance {
val projectionKind = projection.getVariance().convertVariance()
val parameterVariance = parameter.getVariance().convertVariance()
if (parameterVariance == Variance.INVARIANT) { if (parameterVariance == Variance.INVARIANT) {
return projectionKind return projectionKind
@@ -1481,12 +1485,12 @@ class KotlinTypeMapper @JvmOverloads constructor(
} }
if (projectionKind == Variance.INVARIANT || projectionKind == parameterVariance) { if (projectionKind == Variance.INVARIANT || projectionKind == parameterVariance) {
if (mode.skipDeclarationSiteWildcardsIfPossible && !projection.isStarProjection) { if (mode.skipDeclarationSiteWildcardsIfPossible && !projection.isStarProjection()) {
if (parameterVariance == Variance.OUT_VARIANCE && projection.type.isMostPreciseCovariantArgument()) { if (parameterVariance == Variance.OUT_VARIANCE && isMostPreciseCovariantArgument(projection.getType())) {
return Variance.INVARIANT return Variance.INVARIANT
} }
if (parameterVariance == Variance.IN_VARIANCE && projection.type.isMostPreciseContravariantArgument(parameter)) { if (parameterVariance == Variance.IN_VARIANCE && isMostPreciseContravariantArgument(projection.getType(), parameter)) {
return Variance.INVARIANT return Variance.INVARIANT
} }
} }
@@ -17,8 +17,9 @@
@file:JvmName("TypeMappingUtil") @file:JvmName("TypeMappingUtil")
package org.jetbrains.kotlin.codegen.state package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -29,33 +30,38 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.convertVariance
import org.jetbrains.kotlin.types.getEffectiveVariance import org.jetbrains.kotlin.types.getEffectiveVariance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES as BUILTIN_NAMES import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES as BUILTIN_NAMES
fun KotlinType.isMostPreciseContravariantArgument(parameter: TypeParameterDescriptor): Boolean = // TODO: probably class upper bound should be used
// TODO: probably class upper bound should be used @Suppress("UNUSED_PARAMETER")
KotlinBuiltIns.isAnyOrNullableAny(this) fun TypeSystemCommonBackendContext.isMostPreciseContravariantArgument(type: KotlinTypeMarker, parameter: TypeParameterMarker): Boolean =
type.typeConstructor().isAnyConstructor()
fun KotlinType.isMostPreciseCovariantArgument(): Boolean = !canHaveSubtypesIgnoringNullability() fun TypeSystemCommonBackendContext.isMostPreciseCovariantArgument(type: KotlinTypeMarker): Boolean =
!canHaveSubtypesIgnoringNullability(type)
private fun KotlinType.canHaveSubtypesIgnoringNullability(): Boolean { private fun TypeSystemCommonBackendContext.canHaveSubtypesIgnoringNullability(kotlinType: KotlinTypeMarker): Boolean {
val constructor = constructor val constructor = kotlinType.typeConstructor()
val descriptor = constructor.declarationDescriptor
when (descriptor) { if (!constructor.isClassTypeConstructor() || !constructor.isFinalClassOrEnumEntryOrAnnotationClassConstructor()) return true
is TypeParameterDescriptor -> return true
is ClassDescriptor -> if (!descriptor.isFinalClass) return true
}
for ((parameter, argument) in constructor.parameters.zip(arguments)) { for (i in 0 until constructor.parametersCount()) {
if (argument.isStarProjection) return true val parameter = constructor.getParameter(i)
val projectionKind = argument.projectionKind val argument = kotlinType.getArgument(i)
val type = argument.type if (argument.isStarProjection()) return true
val effectiveVariance = getEffectiveVariance(parameter.variance, projectionKind) val projectionKind = argument.getVariance().convertVariance()
if (effectiveVariance == Variance.OUT_VARIANCE && !type.isMostPreciseCovariantArgument()) return true val type = argument.getType()
if (effectiveVariance == Variance.IN_VARIANCE && !type.isMostPreciseContravariantArgument(parameter)) return true
val effectiveVariance = getEffectiveVariance(parameter.getVariance().convertVariance(), projectionKind)
if (effectiveVariance == Variance.OUT_VARIANCE && !isMostPreciseCovariantArgument(type)) return true
if (effectiveVariance == Variance.IN_VARIANCE && !isMostPreciseContravariantArgument(type, parameter)) return true
} }
return false return false
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.types
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSystemContext
interface TypeSystemCommonBackendContext : TypeSystemContext {
fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean
}
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.types.typeUtil.contains
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext { interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSystemCommonBackendContext {
override fun TypeConstructorMarker.isDenotable(): Boolean { override fun TypeConstructorMarker.isDenotable(): Boolean {
require(this is TypeConstructor, this::errorMessage) require(this is TypeConstructor, this::errorMessage)
return this.isDenotable return this.isDenotable
@@ -145,15 +145,6 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
return this.projectionKind.convertVariance() return this.projectionKind.convertVariance()
} }
private fun TypeVariance.convertVariance(): Variance {
return when (this) {
TypeVariance.INV -> Variance.INVARIANT
TypeVariance.IN -> Variance.IN_VARIANCE
TypeVariance.OUT -> Variance.OUT_VARIANCE
}
}
override fun TypeArgumentMarker.getType(): KotlinTypeMarker { override fun TypeArgumentMarker.getType(): KotlinTypeMarker {
require(this is TypeProjection, this::errorMessage) require(this is TypeProjection, this::errorMessage)
return this.type.unwrap() return this.type.unwrap()
@@ -214,6 +205,12 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
classDescriptor.kind != ClassKind.ANNOTATION_CLASS classDescriptor.kind != ClassKind.ANNOTATION_CLASS
} }
override fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean {
require(this is TypeConstructor, this::errorMessage)
val classDescriptor = declarationDescriptor
return classDescriptor is ClassDescriptor && classDescriptor.isFinalClass
}
override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker { override fun SimpleTypeMarker.asArgumentList(): TypeArgumentListMarker {
require(this is SimpleType, this::errorMessage) require(this is SimpleType, this::errorMessage)
return this return this
@@ -490,6 +487,14 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
} }
fun TypeVariance.convertVariance(): Variance {
return when (this) {
TypeVariance.INV -> Variance.INVARIANT
TypeVariance.IN -> Variance.IN_VARIANCE
TypeVariance.OUT -> Variance.OUT_VARIANCE
}
}
private fun captureFromExpressionInternal(type: UnwrappedType) = captureFromExpression(type) private fun captureFromExpressionInternal(type: UnwrappedType) = captureFromExpression(type)
private fun hasNoInferInternal(type: UnwrappedType): Boolean { private fun hasNoInferInternal(type: UnwrappedType): Boolean {