~~~~ WIP: make ConeIntersectionType not ConeSimpleKotlinType
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt
index 01c5295..9ff84fc 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt
@@ -232,7 +232,7 @@
     fun FirClassLikeSymbol<*>.typeParameters(): List<FirTypeParameterSymbol> =
         (fir as? FirTypeParameterRefsOwner)?.typeParameters?.map { it.symbol }.orEmpty()
 
-    private fun simpleType(typeReference: KtTypeReference, attributes: ConeAttributes): ConeRigidType? {
+    private fun simpleType(typeReference: KtTypeReference, attributes: ConeAttributes): ConeDenotableType? {
         val constructor = typeSymbol(typeReference) ?: return null
         val isNullable = typeReference.typeElement is KtNullableType
         if (constructor is ConeTypeParameterLookupTag) {
@@ -276,7 +276,7 @@
         )
     }
 
-    private fun simpleTypeOrError(typeReference: KtTypeReference, attributes: ConeAttributes): ConeRigidType =
+    private fun simpleTypeOrError(typeReference: KtTypeReference, attributes: ConeAttributes): ConeDenotableType =
         simpleType(typeReference, attributes) ?: ConeErrorType(ConeSimpleDiagnostic("?!id:0", DiagnosticKind.DeserializationError))
 
     private fun KtElementImplStub<*>.getAllModifierLists(): Array<out KtDeclarationModifierList> =
diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt
index d65a8e4..0b84e5b 100644
--- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt
+++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt
@@ -141,6 +141,13 @@
 
     private fun ConeRigidType.removeOutProjection(isCovariant: Boolean): ConeRigidType {
         return when (this) {
+            is ConeDenotableType -> removeOutProjection(isCovariant)
+            is ConeIntersectionType -> mapTypes { it.removeOutProjection(isCovariant) }
+        }
+    }
+
+    private fun ConeDenotableType.removeOutProjection(isCovariant: Boolean): ConeDenotableType {
+        return when (this) {
             is ConeSimpleKotlinType -> removeOutProjection(isCovariant)
             is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(isCovariant))
         }
@@ -158,7 +165,6 @@
                     )
                 },
             )
-            is ConeIntersectionType -> mapTypes { it.removeOutProjection(isCovariant) }
             is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
                 lookupTag,
                 typeArguments.map { it.removeOutProjection(isCovariant) }.toTypedArray(),
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirAnnotationHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirAnnotationHelpers.kt
index 168b1f7..80f2fb5 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirAnnotationHelpers.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirAnnotationHelpers.kt
@@ -94,7 +94,7 @@
         is FirClassReferenceExpression -> {
             val classTypeRef = argument.classTypeRef
             val coneType = classTypeRef.coneType.unwrapToSimpleTypeUsingLowerBound()
-            coneType.fullyExpandedType(session).toRegularClassSymbol(session)
+            coneType?.fullyExpandedType(session)?.toRegularClassSymbol(session)
         }
         else -> null
     }
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt
index f093a7e..8827b1a 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt
@@ -39,7 +39,7 @@
         context: CheckerContext,
     ): FirTypeParameterSymbol? {
         val expandedDelegateClassLikeType =
-            delegate.resolvedType.unwrapToSimpleTypeUsingLowerBound().fullyExpandedType(context.session) as? ConeClassLikeType
+            delegate.resolvedType.unwrapToSimpleTypeUsingLowerBound()?.fullyExpandedType(context.session) as? ConeClassLikeType
                 ?: return null
         val delegateClassSymbol = expandedDelegateClassLikeType.lookupTag.toClassSymbol(context.session) ?: return null
         val delegateClassScope by lazy(LazyThreadSafetyMode.NONE) { delegateClassSymbol.unsubstitutedScope(context) }
diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt
index 0e8b7db..b385f1f 100644
--- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt
+++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt
@@ -22,14 +22,14 @@
 val ConeKotlinType.isMarkedOrFlexiblyNullable: Boolean
     get() = when (this) {
         is ConeFlexibleType -> upperBound.isMarkedNullable
-        is ConeRigidType -> isMarkedNullable
+        is ConeDenotableType, is ConeIntersectionType -> isMarkedNullable
     }
 
 @Deprecated(
     "`isMarkedOrFlexiblyNullable` on non-flexible types is the same as `isMarkedNullable`. Also consider using `canBeNull()`.",
     level = DeprecationLevel.ERROR
 )
-val ConeRigidType.isMarkedOrFlexiblyNullable: Boolean get() = isMarkedNullable
+val ConeDenotableType.isMarkedOrFlexiblyNullable: Boolean get() = isMarkedNullable
 
 /**
  * Returns `true` if the type is marked as nullable.
@@ -110,11 +110,12 @@
 
 // ----------------------------------- Transformations -----------------------------------
 
-fun ConeKotlinType.unwrapLowerBound(): ConeSimpleKotlinType {
-    return when(this) {
-        is ConeDefinitelyNotNullType -> original.unwrapLowerBound()
+fun ConeKotlinType.unwrapLowerBound(): ConeRigidType {
+    return when (this) {
+        is ConeDefinitelyNotNullType -> original
         is ConeFlexibleType -> lowerBound.unwrapLowerBound()
         is ConeSimpleKotlinType -> this
+        is ConeIntersectionType -> this
     }
 }
 
@@ -123,6 +124,7 @@
         is ConeSimpleKotlinType -> this
         is ConeFlexibleType -> upperBound
         is ConeDefinitelyNotNullType -> this
+        is ConeIntersectionType -> this
     }
 }
 
@@ -131,6 +133,7 @@
         is ConeSimpleKotlinType -> this
         is ConeFlexibleType -> lowerBound
         is ConeDefinitelyNotNullType -> this
+        is ConeIntersectionType -> this
     }
 }
 
@@ -139,7 +142,7 @@
 }
 
 inline fun ConeIntersectionType.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionType {
-    return ConeIntersectionType(intersectedTypes.map { func(it) as ConeRigidType }, upperBoundForApproximation?.let(func))
+    return ConeIntersectionType(intersectedTypes.map { func(it) as ConeDenotableType }, upperBoundForApproximation?.let(func))
 }
 
 fun ConeClassLikeType.withArguments(typeArguments: Array<out ConeTypeProjection>): ConeClassLikeType = when (this) {
diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt
index 2c74e23..e59a135 100644
--- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt
+++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt
@@ -41,22 +41,24 @@
     abstract override fun hashCode(): Int
 }
 
+sealed class ConeRigidType : ConeKotlinType(), RigidTypeMarker
+
 /**
  * Normally should represent a type with one related constructor, see [getConstructor],
  * but still can require unwrapping, as [ConeDefinitelyNotNullType].
  *
- * Known properties of [ConeRigidType] are:
+ * Known properties of [ConeDenotableType] are:
  * - it does not have bounds as [ConeFlexibleType]
  * - it has one related constructor. [ConeIntersectionType] is currently an exception, see [KT-70049](https://youtrack.jetbrains.com/issue/KT-70049).
  * - it can require unwrapping
  *
  */
-sealed class ConeRigidType : ConeKotlinType(), RigidTypeMarker
+sealed class ConeDenotableType : ConeRigidType(), DenotableTypeMarker
 
 /**
  * Normally should represent a type with one related constructor that does not require unwrapping.
  */
-sealed class ConeSimpleKotlinType : ConeRigidType(), SimpleTypeMarker
+sealed class ConeSimpleKotlinType : ConeDenotableType(), SimpleTypeMarker
 
 class ConeClassLikeErrorLookupTag(override val classId: ClassId) : ConeClassLikeLookupTag()
 
@@ -128,15 +130,19 @@
     companion object
 }
 
-private fun ConeRigidType.unwrapDefinitelyNotNull(): ConeSimpleKotlinType {
+fun ConeDenotableType.unwrapDefinitelyNotNull(): ConeSimpleKotlinType {
     return when (this) {
         is ConeDefinitelyNotNullType -> original
         is ConeSimpleKotlinType -> this
     }
 }
 
-fun ConeKotlinType.unwrapToSimpleTypeUsingLowerBound(): ConeSimpleKotlinType {
-    return lowerBoundIfFlexible().unwrapDefinitelyNotNull()
+fun ConeKotlinType.unwrapToSimpleTypeUsingLowerBound(): ConeSimpleKotlinType? {
+    val rigidType = lowerBoundIfFlexible()
+    return when (rigidType) {
+        is ConeIntersectionType -> null
+        is ConeDenotableType -> rigidType.unwrapDefinitelyNotNull()
+    }
 }
 
 sealed interface ConeTypeConstructorMarker : TypeConstructorMarker
@@ -202,7 +208,7 @@
  */
 data class ConeDefinitelyNotNullType(
     val original: ConeSimpleKotlinType
-) : ConeRigidType(), DefinitelyNotNullTypeMarker {
+) : ConeDenotableType(), DefinitelyNotNullTypeMarker {
     override val typeArguments: Array<out ConeTypeProjection>
         get() = EMPTY_ARRAY
 
@@ -258,9 +264,9 @@
  * @param upperBoundForApproximation a super-type (upper bound), if it's known, to be used as an approximation.
  */
 class ConeIntersectionType(
-    val intersectedTypes: Collection<ConeRigidType>,
+    val intersectedTypes: Collection<ConeDenotableType>,
     val upperBoundForApproximation: ConeKotlinType? = null,
-) : ConeSimpleKotlinType(), IntersectionTypeConstructorMarker, ConeTypeConstructorMarker {
+) : ConeRigidType(), IntersectionTypeConstructorMarker, ConeTypeConstructorMarker {
     // TODO: consider inheriting directly from ConeKotlinType (KT-70049)
     override val typeArguments: Array<out ConeTypeProjection>
         get() = EMPTY_ARRAY
diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt
index b353a62..98a7c99 100644
--- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt
+++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt
@@ -226,9 +226,9 @@
             classProto.loadValueClassRepresentation(
                 context.nameResolver,
                 context.typeTable,
-                { context.typeDeserializer.rigidType(it) }) { name ->
+                { context.typeDeserializer.rigidType(it) as ConeDenotableType }) { name ->
                 val member = declarations.singleOrNull { it is FirProperty && it.receiverParameter == null && it.name == name }
-                (member as FirProperty?)?.returnTypeRef?.coneType as ConeRigidType
+                (member as FirProperty?)?.returnTypeRef?.coneType as ConeDenotableType
             } ?: computeValueClassRepresentation(this, session)
 
         replaceAnnotations(
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrDataClassMembersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrDataClassMembersGenerator.kt
index 239ef90..ad04323 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrDataClassMembersGenerator.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrDataClassMembersGenerator.kt
@@ -351,7 +351,7 @@
                 val (symbol, hasDispatchReceiver) = when {
                     type.isArrayOrPrimitiveArray(checkUnsignedArrays = false) -> context.irBuiltIns.dataClassArrayMemberHashCodeSymbol to false
                     else -> {
-                        val preparedType = type.unwrapToSimpleTypeUsingLowerBound().coerceToAny()
+                        val preparedType = (type as ConeDenotableType).unwrapDefinitelyNotNull().coerceToAny()
                         val classForType = when (val classifier = preparedType.toSymbol(session)?.fir) {
                             is FirRegularClass -> classifier
                             is FirTypeParameter -> classifier.erasedUpperBound
diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt
index 5dce9c1..27c6840 100644
--- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt
+++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt
@@ -91,7 +91,7 @@
     subtreeSizes: List<Int>,
     isFromDefinitelyNotNullType: Boolean,
     convertErrorToWarning: Boolean,
-): ConeRigidType? {
+): ConeDenotableType? {
     if (this is ConeDefinitelyNotNullType) {
         return original.enhanceInflexibleType(session, position, qualifiers, index, subtreeSizes, isFromDefinitelyNotNullType = true, convertErrorToWarning)
     }
@@ -164,7 +164,7 @@
     nullabilityFromQualifiers: NullabilityQualifier?,
     enhancedTag: ConeClassifierLookupTag,
     convertNestedErrorsToWarnings: Boolean,
-): ConeRigidType? {
+): ConeDenotableType? {
     val enhancedIsNullable = when (nullabilityFromQualifiers) {
         NullabilityQualifier.NULLABLE -> true
         NullabilityQualifier.NOT_NULL -> false
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt
index 36808df..1897446 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt
@@ -35,9 +35,9 @@
     return symbol.fir.inlineClassRepresentation?.underlyingType
 }
 
-fun computeValueClassRepresentation(klass: FirRegularClass, session: FirSession): ValueClassRepresentation<ConeRigidType>? {
+fun computeValueClassRepresentation(klass: FirRegularClass, session: FirSession): ValueClassRepresentation<ConeDenotableType>? {
     val parameters = klass.getValueClassUnderlyingParameters(session)?.takeIf { it.isNotEmpty() } ?: return null
-    val fields = parameters.map { it.name to it.symbol.resolvedReturnType as ConeRigidType }
+    val fields = parameters.map { it.name to it.symbol.resolvedReturnType as ConeDenotableType }
     fields.singleOrNull()?.let { (name, type) ->
         if (isRecursiveSingleFieldValueClass(type, session, mutableSetOf(type))) { // escape stack overflow
             return InlineClassRepresentation(name, type)
@@ -53,21 +53,21 @@
 }
 
 private fun isRecursiveSingleFieldValueClass(
-    type: ConeRigidType,
+    type: ConeDenotableType,
     session: FirSession,
-    visited: MutableSet<ConeRigidType>
+    visited: MutableSet<ConeDenotableType>
 ): Boolean {
     val nextType = type.valueClassRepresentationTypeMarkersList(session)?.singleOrNull()?.second ?: return false
     return !visited.add(nextType) || isRecursiveSingleFieldValueClass(nextType, session, visited)
 }
 
-private fun ConeRigidType.valueClassRepresentationTypeMarkersList(session: FirSession): List<Pair<Name, ConeRigidType>>? {
+private fun ConeDenotableType.valueClassRepresentationTypeMarkersList(session: FirSession): List<Pair<Name, ConeDenotableType>>? {
     val symbol = this.toRegularClassSymbol(session) ?: return null
     if (!symbol.fir.isInline) return null
     symbol.fir.valueClassRepresentation?.let { return it.underlyingPropertyNamesToTypes }
 
     val constructorSymbol = symbol.fir.primaryConstructorIfAny(session) ?: return null
-    return constructorSymbol.valueParameterSymbols.map { it.name to it.resolvedReturnType as ConeRigidType }
+    return constructorSymbol.valueParameterSymbols.map { it.name to it.resolvedReturnType as ConeDenotableType }
 }
 
 fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean =
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/expressions/FirConstChecks.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/expressions/FirConstChecks.kt
index 016cd25..08336b4 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/expressions/FirConstChecks.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/expressions/FirConstChecks.kt
@@ -452,7 +452,7 @@
     }
 
     private fun FirExpression.hasAllowedCompileTimeType(): Boolean {
-        val expClassId = resolvedType.unwrapToSimpleTypeUsingLowerBound().fullyExpandedType(session).classId
+        val expClassId = resolvedType.unwrapToSimpleTypeUsingLowerBound()?.fullyExpandedType(session)?.classId
         // TODO, KT-59823: add annotation for allowed constant types
         return expClassId in StandardClassIds.constantAllowedTypes
     }
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt
index 6c636e2..4067231 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt
@@ -114,7 +114,8 @@
         intersectedTypes.mapNotNullTo(mutableListOf()) {
             it.scope(useSiteSession, scopeSession, requiredMembersPhase)
         },
-        this
+        // !!!!!!!!!!
+        this as ConeSimpleKotlinType
     )
 
     is ConeDefinitelyNotNullType -> original.scope(useSiteSession, scopeSession, requiredMembersPhase)
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt
index 555d401..cd24f7a 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt
@@ -54,9 +54,12 @@
     val lookupTags = mutableListOf<ConeClassLikeLookupTag>()
 
     fun ConeKotlinType.collectClassIds() {
-        when (val unwrappedType = unwrapToSimpleTypeUsingLowerBound().fullyExpandedType(useSiteSession)) {
+        if (this is ConeIntersectionType) {
+            intersectedTypes.forEach { it.collectClassIds() }
+            return
+        }
+        when (val unwrappedType = unwrapToSimpleTypeUsingLowerBound()?.fullyExpandedType(useSiteSession)) {
             is ConeClassLikeType -> lookupTags.addIfNotNull(unwrappedType.lookupTag)
-            is ConeIntersectionType -> unwrappedType.intersectedTypes.forEach { it.collectClassIds() }
             else -> {}
         }
     }
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt
index a19dbc0..73454fd 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt
@@ -69,7 +69,7 @@
         val expandedUpper = upperBound.fullyExpandedType(useSiteSession, expandedConeType)
         when {
             expandedLower === lowerBound && expandedUpper === upperBound -> this
-            this is ConeRawType -> ConeRawType.create(expandedLower, expandedUpper)
+            this is ConeRawType -> ConeRawType.create(expandedLower as ConeDenotableType, expandedUpper as ConeDenotableType)
             else -> ConeFlexibleType(expandedLower, expandedUpper)
         }
     }
@@ -93,14 +93,27 @@
 /**
  * @see fullyExpandedType (the first function in the file)
  */
+fun ConeDenotableType.fullyExpandedType(
+    useSiteSession: FirSession,
+    expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = FirTypeAlias::expandedConeTypeWithEnsuredPhase,
+): ConeDenotableType {
+    return when (this) {
+        is ConeSimpleKotlinType -> fullyExpandedType(useSiteSession, expandedConeType)
+        // Expanding DNN type makes no sense, as its original type cannot be class-like type
+        is ConeDefinitelyNotNullType -> this
+    }
+}
+
+/**
+ * @see fullyExpandedType (the first function in the file)
+ */
 fun ConeRigidType.fullyExpandedType(
     useSiteSession: FirSession,
     expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = FirTypeAlias::expandedConeTypeWithEnsuredPhase,
 ): ConeRigidType {
     return when (this) {
-        is ConeSimpleKotlinType -> fullyExpandedType(useSiteSession, expandedConeType)
-        // Expanding DNN type makes no sense, as its original type cannot be class-like type
-        is ConeDefinitelyNotNullType -> this
+        is ConeDenotableType -> fullyExpandedType(useSiteSession, expandedConeType)
+        is ConeIntersectionType -> this
     }
 }
 
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/AbstractConeSubstitutor.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/AbstractConeSubstitutor.kt
index 7c7b8ef..0362a6a 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/AbstractConeSubstitutor.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/AbstractConeSubstitutor.kt
@@ -84,10 +84,10 @@
     }
 
     private fun ConeIntersectionType.substituteIntersectedTypes(): ConeIntersectionType? {
-        val substitutedTypes = ArrayList<ConeRigidType>(intersectedTypes.size)
+        val substitutedTypes = ArrayList<ConeDenotableType>(intersectedTypes.size)
         var somethingIsSubstituted = false
         for (type in intersectedTypes) {
-            val substitutedType = (substituteOrNull(type) as? ConeRigidType)?.also {
+            val substitutedType = (substituteOrNull(type) as? ConeDenotableType)?.also {
                 somethingIsSubstituted = true
             } ?: type
             substitutedTypes += substitutedType
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 96cd05d..e0e299a 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
@@ -98,14 +98,7 @@
                 nullable,
                 coneAttributes
             )
-            is ConeIntersectionType -> if (coneAttributes === constructor.attributes) {
-                constructor
-            } else {
-                ConeIntersectionType(
-                    constructor.intersectedTypes.map { it.withAttributes(coneAttributes) },
-                    constructor.upperBoundForApproximation?.withAttributes(coneAttributes)
-                )
-            }
+            is ConeIntersectionType,
             is ConeCapturedTypeConstructor,
             is ConeIntegerLiteralType,
             is ConeStubTypeConstructor,
@@ -163,6 +156,7 @@
             is ConeSimpleKotlinType -> typeDepth()
             is ConeFlexibleType -> maxOf(lowerBound().typeDepth(), upperBound().typeDepth())
             is ConeDefinitelyNotNullType -> original.typeDepth()
+            is ConeIntersectionType -> 1
         }
     }
 
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt
index 77ee146..a247526 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt
@@ -88,6 +88,19 @@
         }
     }
 
+    override fun KotlinTypeMarker.asDenotableType(): DenotableTypeMarker? {
+        assert(this is ConeKotlinType)
+        return when (this) {
+            is ConeClassLikeType -> fullyExpandedType(session)
+            is ConeDenotableType -> this
+            is ConeRigidType -> null
+            is ConeFlexibleType -> null
+            else -> errorWithAttachment("Unknown simpleType: ${this::class}") {
+                withConeTypeEntry("type", this@asDenotableType as? ConeKotlinType)
+            }
+        }
+    }
+
     override fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker? {
         assert(this is ConeKotlinType)
         return this as? ConeFlexibleType
@@ -440,11 +453,11 @@
         return this.variable.typeConstructor
     }
 
-    override fun intersectTypes(types: Collection<SimpleTypeMarker>): SimpleTypeMarker {
+    override fun intersectTypes(types: Collection<SimpleTypeMarker>): ConeRigidType {
         @Suppress("UNCHECKED_CAST")
         return ConeTypeIntersector.intersectTypes(
             this as ConeInferenceContext, types as Collection<ConeSimpleKotlinType>
-        ) as SimpleTypeMarker
+        ) as ConeRigidType
     }
 
     override fun intersectTypes(types: Collection<KotlinTypeMarker>): ConeKotlinType {
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt
index 7b2bf2b..0a3fa16 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeIntersector.kt
@@ -44,7 +44,7 @@
         val inputTypesMadeNotNullIfNeeded = inputTypes.mapTo(LinkedHashSet<ConeKotlinType>()) {
             if (isResultNotNullable) it.makeConeTypeDefinitelyNotNullOrNotNull(context) else it
         }
-        if (inputTypesMadeNotNullIfNeeded.size == 1) return inputTypesMadeNotNullIfNeeded.single() as ConeRigidType
+        if (inputTypesMadeNotNullIfNeeded.size == 1) return inputTypesMadeNotNullIfNeeded.single() as ConeDenotableType
 
         /*
          * Here we drop types from intersection set for cases like that:
@@ -67,9 +67,9 @@
         assert(resultList.isNotEmpty()) { "no types left after removing equal types: ${inputTypes.joinToString()}" }
         // Sometimes we can return raw type here
         return resultList.singleOrNull() ?: run {
-            require(resultList.all { it is ConeRigidType })
+            require(resultList.all { it is ConeDenotableType })
             @Suppress("UNCHECKED_CAST")
-            ConeIntersectionType(resultList as List<ConeRigidType>)
+            ConeIntersectionType(resultList as List<ConeDenotableType>)
         }
     }
 
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt
index 6741241..b75300a 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt
@@ -98,6 +98,7 @@
         is ConeSimpleKotlinType -> runIf(typeContext.makesSenseToBeDefinitelyNotNull(original, avoidComprehensiveCheck)) {
             ConeDefinitelyNotNullType(original)
         }
+        is ConeIntersectionType -> null
     }
 }
 
@@ -129,7 +130,7 @@
 
     if (this is ConeIntersectionType) {
         return ConeIntersectionType(intersectedTypes.map {
-            it.makeConeTypeDefinitelyNotNullOrNotNull(typeContext, avoidComprehensiveCheck) as ConeRigidType
+            it.makeConeTypeDefinitelyNotNullOrNotNull(typeContext, avoidComprehensiveCheck) as ConeDenotableType
         })
     }
     return ConeDefinitelyNotNullType.create(this, typeContext, avoidComprehensiveCheck)
@@ -295,7 +296,7 @@
 }
 
 fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean {
-    val type = this.unwrapToSimpleTypeUsingLowerBound().fullyExpandedType(session)
+    val type = this.unwrapToSimpleTypeUsingLowerBound()?.fullyExpandedType(session) ?: return false
     return type.attributes.extensionFunctionType != null
 }
 
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/stages/CheckArguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/stages/CheckArguments.kt
index 3d0b400..f9c9abe 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/stages/CheckArguments.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/stages/CheckArguments.kt
@@ -215,7 +215,7 @@
             session, scopeSession, classLikeExpectedFunctionType, shouldCalculateReturnTypesOfFakeOverrides = false
         ) ?: return false
     // Make sure the contributed `invoke` is indeed a wanted functional type by checking if types are compatible.
-    val expectedReturnType = classLikeExpectedFunctionType.returnType(session).unwrapToSimpleTypeUsingLowerBound()
+    val expectedReturnType = classLikeExpectedFunctionType.returnType(session).unwrapToSimpleTypeUsingLowerBound()!!
     val returnTypeCompatible =
         // TODO: can we remove is ConeTypeParameterType check here?
         expectedReturnType is ConeTypeParameterType ||
@@ -247,7 +247,7 @@
                         stubTypesEqualToAnything = true
                     ),
                     invokeParameter.returnTypeRef.coneType,
-                    expectedParameterType,
+                    expectedParameterType!!,
                     isFromNullabilityConstraint = false
                 )
     }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
index 21954bf..f8437601 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
@@ -545,9 +545,4 @@
     return true
 }
 
-private fun ConeKotlinType.unwrap(): ConeSimpleKotlinType = lowerBoundIfFlexible().let {
-    when (it) {
-        is ConeDefinitelyNotNullType -> it.original.unwrap()
-        is ConeSimpleKotlinType -> it
-    }
-}
+private fun ConeKotlinType.unwrap(): ConeSimpleKotlinType? = unwrapToSimpleTypeUsingLowerBound()
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt
index 0278dba..633dab4 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt
@@ -307,14 +307,14 @@
                     if (!lowerBound.isNullableType()) {
                         this@makeConeFlexibleTypeWithNotNullableLowerBound
                     } else {
-                        ConeFlexibleType(lowerBound.makeConeTypeDefinitelyNotNullOrNotNull(typeContext) as ConeRigidType, upperBound)
+                        ConeFlexibleType(lowerBound.makeConeTypeDefinitelyNotNullOrNotNull(typeContext) as ConeDenotableType, upperBound)
                     }
                 }
                 is ConeIntersectionType -> ConeIntersectionType(
-                    intersectedTypes.map { it.makeConeFlexibleTypeWithNotNullableLowerBound(typeContext) as ConeRigidType }
+                    intersectedTypes.map { it.makeConeFlexibleTypeWithNotNullableLowerBound(typeContext) as ConeDenotableType }
                 )
                 is ConeSimpleKotlinType -> ConeFlexibleType(
-                    makeConeTypeDefinitelyNotNullOrNotNull(typeContext) as ConeRigidType,
+                    makeConeTypeDefinitelyNotNullOrNotNull(typeContext) as ConeDenotableType,
                     this@makeConeFlexibleTypeWithNotNullableLowerBound
                 )
             }
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt
index 707404a..b69e93b 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt
@@ -8,17 +8,17 @@
 import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
 import org.jetbrains.kotlin.descriptors.MultiFieldValueClassRepresentation
 import org.jetbrains.kotlin.descriptors.ValueClassRepresentation
-import org.jetbrains.kotlin.fir.types.ConeRigidType
+import org.jetbrains.kotlin.fir.types.ConeDenotableType
 
 private object FirValueClassRepresentationKey : FirDeclarationDataKey()
 
-var FirRegularClass.valueClassRepresentation: ValueClassRepresentation<ConeRigidType>?
+var FirRegularClass.valueClassRepresentation: ValueClassRepresentation<ConeDenotableType>?
         by FirDeclarationDataRegistry.data(FirValueClassRepresentationKey)
 
-val FirRegularClass.inlineClassRepresentation: InlineClassRepresentation<ConeRigidType>?
-    get() = valueClassRepresentation as? InlineClassRepresentation<ConeRigidType>
+val FirRegularClass.inlineClassRepresentation: InlineClassRepresentation<ConeDenotableType>?
+    get() = valueClassRepresentation as? InlineClassRepresentation<ConeDenotableType>
 
-val FirRegularClass.multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation<ConeRigidType>?
-    get() = valueClassRepresentation as? MultiFieldValueClassRepresentation<ConeRigidType>
+val FirRegularClass.multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation<ConeDenotableType>?
+    get() = valueClassRepresentation as? MultiFieldValueClassRepresentation<ConeDenotableType>
 
 
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt
index 50aada0..2d8b20f 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt
@@ -11,7 +11,7 @@
 import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
 import org.jetbrains.kotlin.fir.types.ConeClassLikeLookupTag
-import org.jetbrains.kotlin.fir.types.ConeRigidType
+import org.jetbrains.kotlin.fir.types.ConeDenotableType
 import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
 import org.jetbrains.kotlin.fir.types.toLookupTag
 import org.jetbrains.kotlin.mpp.ClassLikeSymbolMarker
@@ -64,8 +64,8 @@
             return fir.superTypeRefs as List<FirResolvedTypeRef>
         }
 
-    val resolvedSuperTypes: List<ConeRigidType>
-        get() = resolvedSuperTypeRefs.map { it.coneType as ConeRigidType }
+    val resolvedSuperTypes: List<ConeDenotableType>
+        get() = resolvedSuperTypeRefs.map { it.coneType as ConeDenotableType }
 
     val declarationSymbols: List<FirBasedSymbol<*>>
         get() = fir.declarations.map { it.symbol }
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt
index a6e42fe..f3974c9 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt
@@ -43,6 +43,8 @@
 
     override fun KotlinTypeMarker.asRigidType() = this as? SimpleTypeMarker
 
+    override fun KotlinTypeMarker.asDenotableType() = this as? SimpleTypeMarker
+
     override fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker? = this as? FlexibleTypeMarker
 
     override fun KotlinTypeMarker.isError() = this is IrErrorType
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt
index ea66412..e2482ba 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt
@@ -108,7 +108,7 @@
     }
 
     private fun TypeSystemCommonSuperTypesContext.isCapturedStubTypeForVariableInSubtyping(type: RigidTypeMarker) =
-        type.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() }
+        type.asDenotableType()?.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() }
             ?.getType()?.asRigidType()?.isStubTypeForVariableInSubtyping() == true
 
     private fun TypeSystemCommonSuperTypesContext.refineNullabilityForUndefinedNullability(
@@ -248,7 +248,7 @@
 
     private fun TypeSystemCommonSuperTypesContext.isCapturedTypeVariable(type: RigidTypeMarker): Boolean {
         val projectedType =
-            type.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.projection()?.takeUnless {
+            type.asDenotableType()?.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.projection()?.takeUnless {
                 it.isStarProjection()
             }?.getType() ?: return false
         return projectedType.asRigidType()?.isStubTypeForVariableInSubtyping() == true
@@ -380,7 +380,7 @@
     }
 
     private fun TypeSystemCommonSuperTypesContext.uncaptureFromSubtyping(typeArgument: TypeArgumentMarker): TypeArgumentMarker {
-        val capturedType = typeArgument.getType()?.asRigidType()?.asCapturedTypeUnwrappingDnn() ?: return typeArgument
+        val capturedType = typeArgument.getType()?.asDenotableType()?.asCapturedTypeUnwrappingDnn() ?: return typeArgument
         if (capturedType.captureStatus() != CaptureStatus.FOR_SUBTYPING) return typeArgument
 
         return capturedType.typeConstructor().projection()
@@ -439,8 +439,9 @@
         return true
     }
 
-    private fun TypeSystemCommonSuperTypesContext.typeConstructorsWithExpandedStarProjections(types: Set<SimpleTypeMarker>) = sequence {
+    private fun TypeSystemCommonSuperTypesContext.typeConstructorsWithExpandedStarProjections(types: Set<RigidTypeMarker>) = sequence {
         for (type in types) {
+            if (type !is SimpleTypeMarker) continue
             if (isCapturedStarProjection(type)) {
                 for (supertype in supertypesIfCapturedStarProjection(type).orEmpty()) {
                     yield(supertype.lowerBoundIfFlexible().typeConstructor())
@@ -454,7 +455,8 @@
     private fun TypeSystemCommonSuperTypesContext.isCapturedStarProjection(type: SimpleTypeMarker): Boolean =
         type.asCapturedType()?.typeConstructor()?.projection()?.isStarProjection() == true
 
-    private fun TypeSystemCommonSuperTypesContext.supertypesIfCapturedStarProjection(type: SimpleTypeMarker): Collection<KotlinTypeMarker>? {
+    private fun TypeSystemCommonSuperTypesContext.supertypesIfCapturedStarProjection(type: RigidTypeMarker): Collection<KotlinTypeMarker>? {
+        if (type !is SimpleTypeMarker) return null
         val constructor = type.asCapturedType()?.typeConstructor() ?: return null
         return if (constructor.projection().isStarProjection())
             constructor.supertypes()
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerStateForConstraintSystem.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerStateForConstraintSystem.kt
index 59a3b8b..36222ef 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerStateForConstraintSystem.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerStateForConstraintSystem.kt
@@ -100,7 +100,7 @@
     }
 
     private fun extractTypeForProjectedType(type: KotlinTypeMarker, out: Boolean): KotlinTypeMarker? = with(extensionTypeContext) {
-        val rigidType = type.asRigidType()
+        val rigidType = type.asDenotableType()
         val typeMarker = rigidType?.asCapturedTypeUnwrappingDnn() ?: return null
 
         val projection = typeMarker.typeConstructorProjection()
@@ -158,7 +158,7 @@
     private fun extractTypeVariableForSubtype(subType: KotlinTypeMarker, superType: KotlinTypeMarker): KotlinTypeMarker? =
         with(extensionTypeContext) {
 
-            val typeMarker = subType.asRigidType()?.asCapturedTypeUnwrappingDnn() ?: return null
+            val typeMarker = subType.asDenotableType()?.asCapturedTypeUnwrappingDnn() ?: return null
 
             val projection = typeMarker.typeConstructorProjection()
             if (projection.isStarProjection()) return null
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
index e34e62d..a337e1c 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
@@ -295,7 +295,7 @@
             addAll(extractProjectionsForAllCapturedTypes(flexibleType.upperBound()))
         }
     }
-    val simpleBaseType = baseType.asRigidType()?.asCapturedTypeUnwrappingDnn()
+    val simpleBaseType = baseType.asDenotableType()?.asCapturedTypeUnwrappingDnn()
 
     return buildSet {
         val projectionType = if (simpleBaseType != null) {
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
index c9300cb..385bddc 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
@@ -410,7 +410,7 @@
 
     private fun isProperTypeImpl(type: KotlinTypeMarker): Boolean =
         !type.contains {
-            val capturedType = it.asRigidType()?.asCapturedTypeUnwrappingDnn()
+            val capturedType = it.asDenotableType()?.asCapturedTypeUnwrappingDnn()
 
             val typeToCheck = if (capturedType is CapturedTypeMarker && capturedType.captureStatus() == CaptureStatus.FROM_EXPRESSION)
                 capturedType.typeConstructorProjection().getType()
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt
index d6ed023..e69fd1c 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt
@@ -457,7 +457,7 @@
         // A similar replacement for baseSubType looks unnecessary, no hits in the tests.
 
         fun TypeArgumentMarker.unwrapForComparison(): CapturedTypeMarker? {
-            return getType()?.lowerBoundIfFlexible()?.asCapturedTypeUnwrappingDnn()
+            return getType()?.lowerBoundIfFlexible()?.asDenotableType()?.asCapturedTypeUnwrappingDnn()
         }
 
         return if (isK2 && getArguments().any { it.unwrapForComparison() == capturedType }) {
@@ -490,14 +490,18 @@
             return approximateParametrizedType(type, conf, toSuper, depth + 1)
         }
 
-        val definitelyNotNullType = type.asDefinitelyNotNullType()
+        val typeConstructor = type.typeConstructor()
+        if (typeConstructor.isIntersection()) {
+            return approximateIntersectionType(type, conf, toSuper, depth)
+        }
+
+        val definitelyNotNullType = (type as? DenotableTypeMarker)?.asDefinitelyNotNullType()
         if (definitelyNotNullType != null) {
             return approximateDefinitelyNotNullType(definitelyNotNullType, conf, toSuper, depth)
         }
 
-        // DNN case is handled above
+        // DNN & intersection cases are handled above
         require(type is SimpleTypeMarker)
-        val typeConstructor = type.typeConstructor()
 
         if (typeConstructor.isCapturedTypeConstructor()) {
             val capturedType = type.asCapturedType()
@@ -509,10 +513,6 @@
             return approximateCapturedType(capturedType, conf, toSuper, depth)
         }
 
-        if (typeConstructor.isIntersection()) {
-            return approximateIntersectionType(type, conf, toSuper, depth)
-        }
-
         if (typeConstructor is TypeVariableTypeConstructorMarker) {
             return if (!conf.shouldApproximateTypeVariableBasedType(typeConstructor, isK2)) null else type.defaultResult(toSuper)
         }
@@ -599,7 +599,7 @@
 
             val effectiveVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
 
-            val capturedType = argumentType.lowerBoundIfFlexible().asCapturedTypeUnwrappingDnn()
+            val capturedType = argumentType.lowerBoundIfFlexible().asDenotableType()?.asCapturedTypeUnwrappingDnn()
 
             val capturedStarProjectionOrNull =
                 capturedType?.typeConstructorProjection()?.takeIf { it.isStarProjection() }
@@ -774,7 +774,7 @@
 
     private fun KotlinTypeMarker.isFlexibleOrCapturedWithFlexibleSuperTypes(): Boolean {
         return hasFlexibleNullability() ||
-                (asRigidType()?.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.supertypes()?.all {
+                (asDenotableType()?.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.supertypes()?.all {
                     it.hasFlexibleNullability()
                 } == true)
     }
diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt
index 36179fd..9204a9f 100644
--- a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt
+++ b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt
@@ -561,8 +561,15 @@
         if (subType.isStubType() || superType.isStubType())
             return state.isStubTypeEqualsToAnything
 
+        val superTypeConstructor = superType.typeConstructor()
+        if (superTypeConstructor.isIntersection()) {
+            assert(!superType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $superType" }
+
+            return superTypeConstructor.supertypes().all { isSubtypeOf(state, subType, it) }
+        }
+
         // superType might be a definitely notNull type (see KT-42824)
-        val superTypeCaptured = superType.asCapturedTypeUnwrappingDnn()
+        val superTypeCaptured = (superType as DenotableTypeMarker).asCapturedTypeUnwrappingDnn()
         val lowerType = superTypeCaptured?.lowerType()
         if (superTypeCaptured != null && lowerType != null) {
             // If superType is nullable, e.g., to check if Foo? a subtype of Captured<in Foo>?, we check the LHS, Foo?,
@@ -579,13 +586,6 @@
             }
         }
 
-        val superTypeConstructor = superType.typeConstructor()
-        if (superTypeConstructor.isIntersection()) {
-            assert(!superType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $superType" }
-
-            return superTypeConstructor.supertypes().all { isSubtypeOf(state, subType, it) }
-        }
-
         /*
          * We handle cases like CapturedType(out Bar) <: Foo<CapturedType(out Bar)> separately here.
          * If Foo is a self type i.g. Foo<E: Foo<E>>, then argument for E will certainly be subtype of Foo<same_argument_for_E>,
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 55b1e1f..d9e7ba4 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
@@ -22,8 +22,9 @@
 interface FlexibleTypeMarker : KotlinTypeMarker
 interface DynamicTypeMarker : FlexibleTypeMarker
 
-interface DefinitelyNotNullTypeMarker : RigidTypeMarker
-interface SimpleTypeMarker : RigidTypeMarker
+interface DenotableTypeMarker : RigidTypeMarker
+interface DefinitelyNotNullTypeMarker : DenotableTypeMarker
+interface SimpleTypeMarker : DenotableTypeMarker
 
 interface CapturedTypeMarker : SimpleTypeMarker
 interface StubTypeMarker : SimpleTypeMarker
@@ -363,6 +364,10 @@
     fun KotlinTypeMarker.asRigidType(): RigidTypeMarker?
 
     @Deprecated(level = DeprecationLevel.ERROR, message = "This call does effectively nothing, please drop it")
+    fun DenotableTypeMarker.asDenotableType(): DenotableTypeMarker = this
+    fun KotlinTypeMarker.asDenotableType(): DenotableTypeMarker?
+
+    @Deprecated(level = DeprecationLevel.ERROR, message = "This call does effectively nothing, please drop it")
     fun FlexibleTypeMarker.asFlexibleType(): FlexibleTypeMarker = this
     fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker?
 
@@ -385,9 +390,9 @@
 
     @Deprecated(level = DeprecationLevel.ERROR, message = "This call does effectively nothing, please drop it")
     fun CapturedTypeMarker.asCapturedTypeUnwrappingDnn(): CapturedTypeMarker = this
-    fun RigidTypeMarker.asCapturedTypeUnwrappingDnn(): CapturedTypeMarker? = originalIfDefinitelyNotNullable().asCapturedType()
+    fun DenotableTypeMarker.asCapturedTypeUnwrappingDnn(): CapturedTypeMarker? = originalIfDefinitelyNotNullable().asCapturedType()
 
-    fun KotlinTypeMarker.isCapturedType() = asRigidType()?.asCapturedTypeUnwrappingDnn() != null
+    fun KotlinTypeMarker.isCapturedType() = asDenotableType()?.asCapturedTypeUnwrappingDnn() != null
 
     @Deprecated(level = DeprecationLevel.ERROR, message = "This call does effectively nothing, please drop it")
     fun DefinitelyNotNullTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker = this
@@ -396,7 +401,10 @@
 
     @Deprecated(level = DeprecationLevel.ERROR, message = "This call does effectively nothing, please drop it")
     fun SimpleTypeMarker.originalIfDefinitelyNotNullable(): SimpleTypeMarker = this
-    fun RigidTypeMarker.originalIfDefinitelyNotNullable(): SimpleTypeMarker =
+    fun DenotableTypeMarker.originalIfDefinitelyNotNullable(): SimpleTypeMarker =
+        asDefinitelyNotNullType()?.original() ?: this as SimpleTypeMarker
+
+    fun RigidTypeMarker.originalIfDefinitelyNotNullable(): RigidTypeMarker =
         asDefinitelyNotNullType()?.original() ?: this as SimpleTypeMarker
 
     @Deprecated(level = DeprecationLevel.ERROR, message = "This call does effectively nothing, please drop it")
@@ -487,10 +495,10 @@
 
     fun KotlinTypeMarker.isDynamic(): Boolean = asFlexibleType()?.asDynamicType() != null
     fun KotlinTypeMarker.isCapturedDynamic(): Boolean =
-        asRigidType()?.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.projection()?.getType()?.isDynamic() == true
+        asDenotableType()?.asCapturedTypeUnwrappingDnn()?.typeConstructor()?.projection()?.getType()?.isDynamic() == true
 
-    fun KotlinTypeMarker.isDefinitelyNotNullType(): Boolean = asRigidType()?.asDefinitelyNotNullType() != null
-    fun RigidTypeMarker.isDefinitelyNotNullType(): Boolean = asDefinitelyNotNullType() != null
+    fun KotlinTypeMarker.isDefinitelyNotNullType(): Boolean = asDenotableType()?.asDefinitelyNotNullType() != null
+    fun DenotableTypeMarker.isDefinitelyNotNullType(): Boolean = asDefinitelyNotNullType() != null
 
     // This kind of types is obsolete (expected to be removed at 1.7) and shouldn't be used further in a new code
     // Now, such types are being replaced with definitely non-nullable types
@@ -575,7 +583,7 @@
     fun RigidTypeMarker.isSingleClassifierType(): Boolean
 
     fun intersectTypes(types: Collection<KotlinTypeMarker>): KotlinTypeMarker
-    fun intersectTypes(types: Collection<SimpleTypeMarker>): SimpleTypeMarker
+    fun intersectTypes(types: Collection<SimpleTypeMarker>): RigidTypeMarker
 
     fun KotlinTypeMarker.isRigidType(): Boolean = asRigidType() != null
 
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 4bdbed1..dda21db 100644
--- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt
+++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt
@@ -143,6 +143,11 @@
         return this.unwrap() as? SimpleType
     }
 
+    override fun KotlinTypeMarker.asDenotableType(): SimpleTypeMarker? {
+        require(this is KotlinType, this::errorMessage)
+        return this.unwrap() as? SimpleType
+    }
+
     override fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker? {
         require(this is KotlinType, this::errorMessage)
         return this.unwrap() as? FlexibleType
diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt
index 7f20988..3d4b42c 100644
--- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt
+++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt
@@ -282,6 +282,7 @@
         is ConeSimpleKotlinType -> toClassSymbol(session)
         is ConeFlexibleType -> upperBound.toClassSymbol(session)
         is ConeDefinitelyNotNullType -> original.toClassSymbol(session)
+        is ConeIntersectionType -> null
     }
 }