diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index 336ffea6973..59f3f4a6c38 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -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 } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt index 72acdac9bb2..1934c35a434 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/typeMappingUtil.kt @@ -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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt new file mode 100644 index 00000000000..6f602f12512 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt @@ -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 +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 77adc010a6c..94a235cae49 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -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 {