[API Usage] Inject Refiner into KotlinTypeChecker, use it for subtyping

This commit is contained in:
Dmitriy Novozhilov
2019-07-03 19:35:11 +03:00
committed by Dmitry Savvinov
parent 9047ddfc2f
commit a1b52b2f90
5 changed files with 52 additions and 12 deletions
@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.frontend.di
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
@@ -36,6 +36,8 @@ import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.types.checker.NewKotlinTypeCheckerImpl
import org.jetbrains.kotlin.types.expressions.DeclarationScopeProviderForLocalClassifierAnalyzer
import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
@@ -66,6 +68,14 @@ fun StorageComponentContainer.configureModule(
extension.registerModuleComponents(this, platform, moduleContext.module)
}
useImpl<NewKotlinTypeCheckerImpl>()
if (languageVersionSettings.isTypeRefinementEnabled) {
useImpl<KotlinTypeRefinerImpl>()
} else {
useInstance(KotlinTypeRefiner.Default)
}
configurePlatformIndependentComponents()
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver;
import org.jetbrains.kotlin.types.WrappedTypeFactory;
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker;
import javax.inject.Inject;
@@ -62,6 +63,8 @@ public class ExpressionTypingComponents {
/*package*/ EffectSystem effectSystem;
/*package*/ ContractParsingServices contractParsingServices;
/*package*/ DataFlowValueFactory dataFlowValueFactory;
/*package*/ NewKotlinTypeChecker kotlinTypeChecker;
@Inject
public void setGlobalContext(@NotNull GlobalContext globalContext) {
@@ -237,4 +240,9 @@ public class ExpressionTypingComponents {
public void setDataFlowValueFactory(@NotNull DataFlowValueFactory dataFlowValueFactory) {
this.dataFlowValueFactory = dataFlowValueFactory;
}
@Inject
public void setKotlinTypeChecker(@NotNull NewKotlinTypeChecker kotlinTypeChecker) {
this.kotlinTypeChecker = kotlinTypeChecker;
}
}
@@ -22,11 +22,23 @@ import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewTyp
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.refinement.TypeRefinement
open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowedTypeVariable: Boolean = true) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
open class ClassicTypeCheckerContext(
val errorTypeEqualsToAnything: Boolean,
val allowedTypeVariable: Boolean = true,
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default
) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return transformToNewType((type as KotlinType).unwrap())
require(type is KotlinType, type::errorMessage)
return transformToNewType(type.unwrap())
}
@UseExperimental(TypeRefinement::class)
override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
require(type is KotlinType, type::errorMessage)
return kotlinTypeRefiner.refineType(type)
}
override val isErrorTypeEqualsToAnything: Boolean
@@ -56,20 +56,24 @@ object ErrorTypesAreEqualToAnything : KotlinTypeChecker {
}
interface NewKotlinTypeChecker : KotlinTypeChecker {
val kotlinTypeRefiner: KotlinTypeRefiner
fun transformToNewType(type: UnwrappedType): UnwrappedType
companion object {
val Default = NewKotlinTypeCheckerImpl()
val Default = NewKotlinTypeCheckerImpl(KotlinTypeRefiner.Default)
}
}
class NewKotlinTypeCheckerImpl() : NewKotlinTypeChecker {
class NewKotlinTypeCheckerImpl(override val kotlinTypeRefiner: KotlinTypeRefiner) : NewKotlinTypeChecker {
override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean =
ClassicTypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything
ClassicTypeCheckerContext(true, kotlinTypeRefiner = kotlinTypeRefiner)
.isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything
override fun equalTypes(a: KotlinType, b: KotlinType): Boolean =
ClassicTypeCheckerContext(false).equalTypes(a.unwrap(), b.unwrap())
ClassicTypeCheckerContext(false, kotlinTypeRefiner = kotlinTypeRefiner).equalTypes(a.unwrap(), b.unwrap())
fun ClassicTypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
return AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b)
@@ -25,6 +25,10 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
return type
}
open fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
return type
}
abstract val isErrorTypeEqualsToAnything: Boolean
protected var argumentsDepth = 0
@@ -157,19 +161,21 @@ object AbstractTypeChecker {
fun isSubtypeOf(context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
if (subType === superType) return true
return context.completeIsSubTypeOf(context.prepareType(subType), context.prepareType(superType))
return with(context) { completeIsSubTypeOf(prepareType(refineType(subType)), prepareType(refineType(superType))) }
}
fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean = with(context) {
if (a === b) return true
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
val simpleA = a.lowerBoundIfFlexible()
if (!areEqualTypeConstructors(a.typeConstructor(), b.typeConstructor())) return false
val refinedA = refineType(a)
val refinedB = refineType(b)
val simpleA = refinedA.lowerBoundIfFlexible()
if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false
if (simpleA.argumentsCount() == 0) {
if (a.hasFlexibleNullability() || b.hasFlexibleNullability()) return true
if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true
return simpleA.isMarkedNullable() == b.lowerBoundIfFlexible().isMarkedNullable()
return simpleA.isMarkedNullable() == refinedB.lowerBoundIfFlexible().isMarkedNullable()
}
}