From a1b52b2f908bd6f5b44a70542865644ea382ace8 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 3 Jul 2019 19:35:11 +0300 Subject: [PATCH] [API Usage] Inject Refiner into KotlinTypeChecker, use it for subtyping --- .../jetbrains/kotlin/frontend/di/injection.kt | 12 +++++++++++- .../expressions/ExpressionTypingComponents.java | 8 ++++++++ .../types/checker/ClassicTypeCheckerContext.kt | 16 ++++++++++++++-- .../kotlin/types/checker/NewKotlinTypeChecker.kt | 12 ++++++++---- .../kotlin/types/AbstractTypeChecker.kt | 16 +++++++++++----- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt b/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt index 94b73474206..e0ab82b9322 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/frontend/di/injection.kt @@ -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() + + if (languageVersionSettings.isTypeRefinementEnabled) { + useImpl() + } else { + useInstance(KotlinTypeRefiner.Default) + } + configurePlatformIndependentComponents() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java index d0224c7633a..dd435a35f84 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java @@ -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; + } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt index 18ba91b4414..4f5c8b00484 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt @@ -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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index 2842402b1ea..de3ced2948b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -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) diff --git a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index 3430c142319..5b88636fe83 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -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() } }