[MPP] Fix false positive expect-actual mismatch
Use type refiner to correctly expand actual type alias - expect class chains, produced by the commonizer. In a case when type refiner doesn't exist for module create a one-shot thread local instance. This might happen with modules without source code in project (coming from build system model). ^KT-46691 Fixed
This commit is contained in:
committed by
teamcityserver
parent
2d91917ac7
commit
19467861c9
+58
-21
@@ -5,27 +5,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.multiplatform
|
||||
|
||||
import org.jetbrains.kotlin.types.KotlinTypeRefinerImpl
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Compatible
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
@@ -257,22 +252,64 @@ object ExpectedActualResolver {
|
||||
false
|
||||
}
|
||||
|
||||
@OptIn(TypeRefinement::class)
|
||||
private fun areCompatibleTypes(a: KotlinType?, b: KotlinType?, platformModule: ModuleDescriptor): Boolean {
|
||||
if (a == null) return b == null
|
||||
if (b == null) return false
|
||||
|
||||
with(NewKotlinTypeChecker.Default) {
|
||||
val context = object : ClassicTypeSystemContext {
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor)
|
||||
require(c2 is TypeConstructor)
|
||||
return isExpectedClassAndActualTypeAlias(c1, c2, platformModule) ||
|
||||
isExpectedClassAndActualTypeAlias(c2, c1, platformModule) ||
|
||||
super.areEqualTypeConstructors(c1, c2)
|
||||
}
|
||||
return if (platformModule.isTypeRefinementEnabled()) {
|
||||
areCompatibleTypesViaTypeRefinement(a, b, platformModule)
|
||||
} else {
|
||||
areCompatibleTypesViaTypeContext(a, b, platformModule)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(TypeRefinement::class)
|
||||
private fun areCompatibleTypesViaTypeRefinement(a: KotlinType, b: KotlinType, platformModule: ModuleDescriptor): Boolean {
|
||||
val typeRefinerForPlatformModule = platformModule.getKotlinTypeRefiner().let { moduleRefiner ->
|
||||
if (moduleRefiner is KotlinTypeRefiner.Default)
|
||||
KotlinTypeRefinerImpl.createStandaloneInstanceFor(platformModule)
|
||||
else
|
||||
moduleRefiner
|
||||
}
|
||||
|
||||
return areCompatibleTypes(
|
||||
a, b,
|
||||
typeSystemContext = SimpleClassicTypeSystemContext,
|
||||
kotlinTypeRefiner = typeRefinerForPlatformModule,
|
||||
)
|
||||
}
|
||||
|
||||
private fun areCompatibleTypesViaTypeContext(a: KotlinType, b: KotlinType, platformModule: ModuleDescriptor): Boolean {
|
||||
val typeSystemContext = object : ClassicTypeSystemContext {
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor)
|
||||
require(c2 is TypeConstructor)
|
||||
return isExpectedClassAndActualTypeAlias(c1, c2, platformModule) ||
|
||||
isExpectedClassAndActualTypeAlias(c2, c1, platformModule) ||
|
||||
super.areEqualTypeConstructors(c1, c2)
|
||||
}
|
||||
return ClassicTypeCheckerContext(errorTypeEqualsToAnything = false, typeSystemContext = context)
|
||||
.equalTypes(a.unwrap(), b.unwrap())
|
||||
}
|
||||
|
||||
return areCompatibleTypes(
|
||||
a, b,
|
||||
typeSystemContext = typeSystemContext,
|
||||
kotlinTypeRefiner = KotlinTypeRefiner.Default,
|
||||
)
|
||||
}
|
||||
|
||||
private fun areCompatibleTypes(
|
||||
a: KotlinType,
|
||||
b: KotlinType,
|
||||
typeSystemContext: ClassicTypeSystemContext,
|
||||
kotlinTypeRefiner: KotlinTypeRefiner,
|
||||
): Boolean {
|
||||
with(NewKotlinTypeCheckerImpl(kotlinTypeRefiner)) {
|
||||
return ClassicTypeCheckerContext(
|
||||
errorTypeEqualsToAnything = false,
|
||||
typeSystemContext = typeSystemContext,
|
||||
kotlinTypeRefiner = kotlinTypeRefiner,
|
||||
).equalTypes(a.unwrap(), b.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||
@@ -24,8 +25,20 @@ class KotlinTypeRefinerImpl(
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
storageManager: StorageManager
|
||||
) : KotlinTypeRefiner() {
|
||||
private var isStandalone: Boolean = false
|
||||
|
||||
private constructor(
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
isStandalone: Boolean
|
||||
) : this(moduleDescriptor, storageManager) {
|
||||
this.isStandalone = isStandalone
|
||||
}
|
||||
|
||||
init {
|
||||
moduleDescriptor.getCapability(REFINER_CAPABILITY)?.value = TypeRefinementSupport.Enabled(this)
|
||||
if (!isStandalone) {
|
||||
moduleDescriptor.getCapability(REFINER_CAPABILITY)?.value = TypeRefinementSupport.Enabled(this)
|
||||
}
|
||||
}
|
||||
|
||||
private val refinedTypeCache = storageManager.createCacheWithNotNullValues<TypeConstructor, KotlinType>()
|
||||
@@ -148,6 +161,15 @@ class KotlinTypeRefinerImpl(
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Create a new *thread unsafe* type refiner instance for the specified module.
|
||||
* Note, that module's type refiner capability won't be changed.
|
||||
*/
|
||||
fun createStandaloneInstanceFor(moduleDescriptor: ModuleDescriptor): KotlinTypeRefinerImpl =
|
||||
KotlinTypeRefinerImpl(moduleDescriptor, LockBasedStorageManager.NO_LOCKS, isStandalone = true)
|
||||
}
|
||||
}
|
||||
|
||||
private val TypeConstructor.allDependentTypeConstructors: Collection<TypeConstructor>
|
||||
|
||||
Reference in New Issue
Block a user