diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 0533b997d18..42079334048 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -426,6 +426,8 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo return withAttributes(attributes.remove(CompilerConeAttributes.Exact)) } + override fun KotlinTypeMarker.canHaveSubtypes(typeChecker: AbstractTypeChecker): Boolean? = null + override fun TypeConstructorMarker.toErrorType(): SimpleTypeMarker { if (this is ErrorTypeConstructor) return createErrorType(reason) if (this is ConeClassLikeLookupTag) return createErrorType("Not found classifier: $classId") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 76e08ed6d0b..b3fda263cfc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -64,6 +64,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.error.ErrorTypeKind; import org.jetbrains.kotlin.types.error.ErrorUtils; import org.jetbrains.kotlin.types.expressions.*; +import org.jetbrains.kotlin.types.model.KotlinTypeMarker; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import java.util.*; @@ -619,7 +620,8 @@ public class DescriptorResolver { @NotNull TypeParameterDescriptor parameter, @NotNull KtTypeParameter typeParameter ) { - if (KotlinBuiltIns.isNothing(TypeIntersector.getUpperBoundsAsType(parameter))) { + List bounds = parameter.getUpperBounds(); + if (TypeUtilsKt.isEmptyIntersectionTypeCompatible(bounds.toArray(new KotlinTypeMarker[0]))) { trace.report(CONFLICTING_UPPER_BOUNDS.on(typeParameter, parameter)); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/EqualityCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/EqualityCallChecker.kt index d0a26f88264..8cb44b68375 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/EqualityCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/EqualityCallChecker.kt @@ -16,12 +16,12 @@ import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceSession import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeIntersector import org.jetbrains.kotlin.types.checkEnumsForCompatibility import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.SenselessComparisonChecker.checkSenselessComparisonWithNull import org.jetbrains.kotlin.types.typeUtil.builtIns +import org.jetbrains.kotlin.types.typeUtil.isEmptyIntersectionTypeCompatible import org.jetbrains.kotlin.util.OperatorNameConventions object EqualityCallChecker : CallChecker { @@ -90,7 +90,7 @@ object EqualityCallChecker : CallChecker { val leftType = context.trace.getType(left) ?: return val rightType = context.trace.getType(right) ?: return - if (TypeIntersector.isIntersectionEmpty(leftType, rightType)) { + if (isEmptyIntersectionTypeCompatible(leftType, rightType)) { val isProperEqualityChecksEnabled = context.languageVersionSettings.supportsFeature(LanguageFeature.ProperEqualityChecksInBuilderInferenceCalls) val shouldReportWarnings = !isProperEqualityChecksEnabled diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt index 8665ae6ab8a..7e37d724152 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionStatelessCallbacksImpl.kt @@ -39,8 +39,6 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeIntersector import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -104,10 +102,6 @@ class KotlinResolutionStatelessCallbacksImpl( return org.jetbrains.kotlin.resolve.calls.inference.isApplicableCallForBuilderInference(descriptor, languageVersionSettings) } - override fun isOldIntersectionIsEmpty(types: Collection): Boolean { - return TypeIntersector.intersectTypes(types) == null - } - override fun createConstraintSystemForOverloadResolution( constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns ): SimpleConstraintSystem { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt index c2926616969..2483b126bdf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt @@ -29,8 +29,10 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure +import org.jetbrains.kotlin.types.checker.intersectTypes import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext +import org.jetbrains.kotlin.types.typeUtil.isEmptyIntersectionTypeCompatible import org.jetbrains.kotlin.types.typeUtil.makeNotNullable object CastDiagnosticsUtil { @@ -223,7 +225,11 @@ object CastDiagnosticsUtil { targetType: KotlinType, shouldCheckForExactType: Boolean ): Boolean { - val intersectedType = TypeIntersector.intersectTypes(possibleTypes.map { it.upperIfFlexible() }) ?: return false + val types = possibleTypes.map { it.upperIfFlexible() } + + if (isEmptyIntersectionTypeCompatible(*types.toTypedArray())) return false + + val intersectedType = intersectTypes(possibleTypes.map { it.upperIfFlexible() }) return if (shouldCheckForExactType) isExactTypeCast(intersectedType, targetType) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/CommonSupertypes.java b/compiler/frontend/src/org/jetbrains/kotlin/types/CommonSupertypes.java index 20bd05be0ec..b0d4c1f2fca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/CommonSupertypes.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/CommonSupertypes.java @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.scopes.MemberScope; +import org.jetbrains.kotlin.types.checker.IntersectionTypeKt; import org.jetbrains.kotlin.types.error.ErrorScopeKind; import org.jetbrains.kotlin.types.error.ErrorTypeKind; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; @@ -344,7 +345,7 @@ public class CommonSupertypes { } if (ins != null) { assert !ins.isEmpty() : "In projections is empty for parameter " + parameterDescriptor + ", type projections " + typeProjections; - KotlinType intersection = TypeIntersector.intersectTypes(ins); + KotlinType intersection = IntersectionTypeKt.intersectWrappedTypes(ins); if (intersection == null) { return TypeUtils.makeStarProjection(parameterDescriptor); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index a0e2ea0ce4c..588cb7542f1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -78,6 +78,7 @@ import org.jetbrains.kotlin.types.expressions.unqualifiedSuper.UnqualifiedSuperK import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import org.jetbrains.kotlin.util.OperatorNameConventions; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -1147,7 +1148,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { boolean isBuilderInferenceContext = context.inferenceSession instanceof BuilderInferenceSession; - if (leftType != null && rightType != null && !TypeIntersector.isIntersectionEmpty(leftType, rightType) && isBuilderInferenceContext) { + if ( + leftType != null && + rightType != null && + !TypeUtilsKt.isEmptyIntersectionTypeCompatible(leftType, rightType) && + isBuilderInferenceContext + ) { context.trace.record(MARKED_EQUALIY_CALL_PROPER_IN_BUILDER_INFERENCE, expression); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt index 5be3005aa66..7b9036ab957 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo import org.jetbrains.kotlin.types.typeUtil.containsError import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny +import org.jetbrains.kotlin.types.typeUtil.isEmptyIntersectionTypeCompatible import java.util.* class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) { @@ -700,7 +701,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping reportErrorOn: KtElement ): Boolean { // TODO : Take smart casts into account? - if (TypeIntersector.isIntersectionEmpty(type, subjectType)) { + if (isEmptyIntersectionTypeCompatible(type, subjectType)) { context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType)) return false } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt index 7b8d4160060..a261b82479e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt @@ -48,8 +48,6 @@ interface KotlinResolutionStatelessCallbacks { fun isBuilderInferenceCall(argument: KotlinCallArgument, parameter: ValueParameterDescriptor): Boolean fun isApplicableCallForBuilderInference(descriptor: CallableDescriptor, languageVersionSettings: LanguageVersionSettings): Boolean - fun isOldIntersectionIsEmpty(types: Collection): Boolean - fun createConstraintSystemForOverloadResolution( constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns ): SimpleConstraintSystem diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index b0a2c6d639e..ffdfd73fbaa 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.types.error.ErrorUtils import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.utils.SmartList -import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.compactIfPossible import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -885,8 +884,8 @@ internal object CheckIncompatibleTypeVariableUpperBounds : ResolutionPart() { * Check if the candidate was already discriminated by `CompatibilityOfTypeVariableAsIntersectionTypePart` resolution part * If it's true we shouldn't mark the candidate with warning, but should mark with error, to repeat the existing proper behaviour */ - private fun ResolutionCandidate.wasPreviouslyDiscriminated(upperTypes: List) = - callComponents.statelessCallbacks.isOldIntersectionIsEmpty(upperTypes.cast()) + private fun wasPreviouslyDiscriminated(upperTypes: List) = + isEmptyIntersectionTypeCompatible(*upperTypes.toTypedArray()) override fun ResolutionCandidate.process(workIndex: Int) = with(getSystem().asConstraintSystemCompleterContext()) { val constraintSystem = getSystem() diff --git a/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/EmptyIntersectionTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/EmptyIntersectionTypeChecker.kt index 326fd9bcdd4..940f519e575 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/EmptyIntersectionTypeChecker.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/EmptyIntersectionTypeChecker.kt @@ -11,10 +11,11 @@ import org.jetbrains.kotlin.types.isDefinitelyEmpty import org.jetbrains.kotlin.types.isPossiblyEmpty import org.jetbrains.kotlin.types.model.* -internal object EmptyIntersectionTypeChecker { +object EmptyIntersectionTypeChecker { fun computeEmptyIntersectionEmptiness( context: TypeSystemInferenceExtensionContext, - types: Collection + types: Collection, + compatibilityModeEnabled: Boolean = false ): EmptyIntersectionTypeInfo? = with(context) { if (types.isEmpty()) return null @@ -34,6 +35,11 @@ internal object EmptyIntersectionTypeChecker { if (!mayCauseEmptyIntersection(secondType)) continue + if (compatibilityModeEnabled) { + val compatibleKind = computeEmptyIntersectionEmptinessCompatible(firstType, secondType) + if (compatibleKind != null) return compatibleKind else continue + } + val secondSubstitutedType = secondType.eraseContainingTypeParameters() if (!mayCauseEmptyIntersection(secondSubstitutedType) && !mayCauseEmptyIntersection(firstSubstitutedType)) continue @@ -286,6 +292,31 @@ internal object EmptyIntersectionTypeChecker { val type = argument.getType() return if (type is CapturedTypeMarker) type.typeConstructorProjection() else argument } + + private fun TypeSystemInferenceExtensionContext.computeEmptyIntersectionEmptinessCompatible( + firstType: KotlinTypeMarker, + secondType: KotlinTypeMarker + ): EmptyIntersectionTypeInfo? { + @Suppress("NAME_SHADOWING") + val firstType = firstType.withNullability(false) + + @Suppress("NAME_SHADOWING") + val secondType = secondType.withNullability(false) + + val firstErasedType by lazy { firstType.eraseContainingTypeParameters() } + val secondErasedType by lazy { secondType.eraseContainingTypeParameters() } + + if (AbstractTypeChecker.areRelatedBySubtyping(this, firstErasedType, secondErasedType)) + return null + + val canBothHaveSubtypes = firstType.withNullability(false).canHaveSubtypes(AbstractTypeChecker) == true + && secondType.withNullability(false).canHaveSubtypes(AbstractTypeChecker) == true + + if (canBothHaveSubtypes) + return null + + return EmptyIntersectionTypeInfo(EmptyIntersectionTypeKind.COMPATIBLE, firstErasedType, secondErasedType) + } } -class EmptyIntersectionTypeInfo(val kind: EmptyIntersectionTypeKind, vararg val casingTypes: KotlinTypeMarker) \ No newline at end of file +class EmptyIntersectionTypeInfo(val kind: EmptyIntersectionTypeKind, vararg val casingTypes: KotlinTypeMarker) diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/EmptyIntersectionTypeKind.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/EmptyIntersectionTypeKind.kt index 6671e650a94..52a71eeb2f5 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/EmptyIntersectionTypeKind.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/EmptyIntersectionTypeKind.kt @@ -9,7 +9,11 @@ enum class EmptyIntersectionTypeKind(val description: String) { MULTIPLE_CLASSES("multiple incompatible classes"), INCOMPATIBLE_SUPERTYPES("incompatible supertypes"), INCOMPATIBLE_TYPE_ARGUMENTS("incompatible type arguments"), - SINGLE_FINAL_CLASS("final class and interface") + SINGLE_FINAL_CLASS("final class and interface"), + + // This kind corresponds to migrated logic from old TypeIntersector + // Now it's used for determining types compatibility for is/as/equality checks + COMPATIBLE("") } fun EmptyIntersectionTypeKind.isDefinitelyEmpty(): Boolean = diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 6123013605c..0604d4e1349 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -179,6 +179,8 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun KotlinTypeMarker.removeAnnotations(): KotlinTypeMarker fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker + fun KotlinTypeMarker.canHaveSubtypes(typeChecker: AbstractTypeChecker): Boolean? + fun SimpleTypeMarker.replaceArguments(newArguments: List): SimpleTypeMarker fun SimpleTypeMarker.replaceArguments(replacement: (TypeArgumentMarker) -> TypeArgumentMarker): SimpleTypeMarker diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 0d66bdb0193..dc6dc7df1a5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.inference.isCaptured +import org.jetbrains.kotlin.resolve.checkers.EmptyIntersectionTypeChecker import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.* @@ -30,6 +31,7 @@ import org.jetbrains.kotlin.types.model.TypeArgumentMarker import org.jetbrains.kotlin.types.model.TypeVariableTypeConstructorMarker import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.types.error.ErrorUtils +import org.jetbrains.kotlin.types.model.KotlinTypeMarker import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -395,3 +397,8 @@ fun isUnresolvedType(type: KotlinType): Boolean { } return type is ErrorType && type.kind.isUnresolved } + +fun isEmptyIntersectionTypeCompatible(vararg types: KotlinTypeMarker): Boolean = + EmptyIntersectionTypeChecker.computeEmptyIntersectionEmptiness( + SimpleClassicTypeSystemContext, types.toList(), compatibilityModeEnabled = true + )?.kind == EmptyIntersectionTypeKind.COMPATIBLE 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 28997a49e70..0ff52d47a78 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -425,11 +425,10 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return when (this) { is SimpleTypeMarker -> this.withNullability(nullable) is FlexibleTypeMarker -> createFlexibleType(lowerBound().withNullability(nullable), upperBound().withNullability(nullable)) - else -> error("sealed") + else -> asSimpleType()?.withNullability(nullable) ?: error("Unwrapped type should be simple") } } - override fun newTypeCheckerState( errorTypesEqualToAnything: Boolean, stubTypesEqualToAnything: Boolean @@ -478,6 +477,20 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return this.replaceAnnotations(Annotations.create(annotationsWithoutExact)) } + override fun KotlinTypeMarker.canHaveSubtypes(typeChecker: AbstractTypeChecker): Boolean? { + require(this is KotlinType, this::errorMessage) + + val kotlinTypeChecker = object : KotlinTypeChecker { + override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean = + typeChecker.isSubtypeOf(this@ClassicTypeSystemContext, subtype, supertype) + + override fun equalTypes(a: KotlinType, b: KotlinType): Boolean = + typeChecker.equalTypes(this@ClassicTypeSystemContext, a, b) + } + + return TypeUtils.canHaveSubtypes(kotlinTypeChecker, this) + } + override fun KotlinTypeMarker.hasExactAnnotation(): Boolean { require(this is UnwrappedType, this::errorMessage) return hasExactInternal(this)