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.types.*
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.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSystemContext
import org.jetbrains.kotlin.types.model.TypeVariance
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
@@ -1468,9 +1467,14 @@ class KotlinTypeMapper @JvmOverloads constructor(
return false
}
fun getVarianceForWildcard(parameter: TypeParameterDescriptor, projection: TypeProjection, mode: TypeMappingMode): Variance {
val projectionKind = projection.projectionKind
val parameterVariance = parameter.variance
fun getVarianceForWildcard(parameter: TypeParameterDescriptor, projection: TypeProjection, mode: TypeMappingMode): Variance =
SimpleClassicTypeSystemContext.getVarianceForWildcard(parameter, projection, mode)
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) {
return projectionKind
@@ -1481,12 +1485,12 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
if (projectionKind == Variance.INVARIANT || projectionKind == parameterVariance) {
if (mode.skipDeclarationSiteWildcardsIfPossible && !projection.isStarProjection) {
if (parameterVariance == Variance.OUT_VARIANCE && projection.type.isMostPreciseCovariantArgument()) {
if (mode.skipDeclarationSiteWildcardsIfPossible && !projection.isStarProjection()) {
if (parameterVariance == Variance.OUT_VARIANCE && isMostPreciseCovariantArgument(projection.getType())) {
return Variance.INVARIANT
}
if (parameterVariance == Variance.IN_VARIANCE && projection.type.isMostPreciseContravariantArgument(parameter)) {
if (parameterVariance == Variance.IN_VARIANCE && isMostPreciseContravariantArgument(projection.getType(), parameter)) {
return Variance.INVARIANT
}
}
@@ -17,8 +17,9 @@
@file:JvmName("TypeMappingUtil")
package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
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.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.convertVariance
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
fun KotlinType.isMostPreciseContravariantArgument(parameter: TypeParameterDescriptor): Boolean =
// TODO: probably class upper bound should be used
KotlinBuiltIns.isAnyOrNullableAny(this)
// TODO: probably class upper bound should be used
@Suppress("UNUSED_PARAMETER")
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 {
val constructor = constructor
val descriptor = constructor.declarationDescriptor
private fun TypeSystemCommonBackendContext.canHaveSubtypesIgnoringNullability(kotlinType: KotlinTypeMarker): Boolean {
val constructor = kotlinType.typeConstructor()
when (descriptor) {
is TypeParameterDescriptor -> return true
is ClassDescriptor -> if (!descriptor.isFinalClass) return true
}
if (!constructor.isClassTypeConstructor() || !constructor.isFinalClassOrEnumEntryOrAnnotationClassConstructor()) return true
for ((parameter, argument) in constructor.parameters.zip(arguments)) {
if (argument.isStarProjection) return true
val projectionKind = argument.projectionKind
val type = argument.type
for (i in 0 until constructor.parametersCount()) {
val parameter = constructor.getParameter(i)
val argument = kotlinType.getArgument(i)
if (argument.isStarProjection()) return true
val effectiveVariance = getEffectiveVariance(parameter.variance, projectionKind)
if (effectiveVariance == Variance.OUT_VARIANCE && !type.isMostPreciseCovariantArgument()) return true
if (effectiveVariance == Variance.IN_VARIANCE && !type.isMostPreciseContravariantArgument(parameter)) return true
val projectionKind = argument.getVariance().convertVariance()
val type = argument.getType()
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
@@ -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.contract
interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSystemCommonBackendContext {
override fun TypeConstructorMarker.isDenotable(): Boolean {
require(this is TypeConstructor, this::errorMessage)
return this.isDenotable
@@ -145,15 +145,6 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
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 {
require(this is TypeProjection, this::errorMessage)
return this.type.unwrap()
@@ -214,6 +205,12 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
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 {
require(this is SimpleType, this::errorMessage)
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 hasNoInferInternal(type: UnwrappedType): Boolean {