[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:
Pavel Kirpichenkov
2021-07-16 16:36:49 +03:00
committed by teamcityserver
parent 2d91917ac7
commit 19467861c9
2 changed files with 81 additions and 22 deletions
@@ -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>