Abstract NewInference & related from KotlinType

Cleanup TypeConstructors & KotlinTypes in VariableFixationFinder
Cleanup TypeConstructors & KotlinTypes in TypeVariableDirectionCalculator
Cleanup KotlinTypes in TypeCheckerContext for ConstraintSystem
Cleanup KotlinTypes in NewCommonSuperTypeCalculator
Cleanup KotlinTypes in TypeApproximator
Cleanup type substitution
Cleanup NewTypeVariable
Cleanup StubType
Cleanup TypeCheckerContext creation, extract common supertype context
Provide TypeSystemInferenceExtensionContext via dependency injection
This commit is contained in:
Simon Ogorodnik
2019-02-18 20:19:33 +03:00
parent 0ffded5bac
commit 3998e842f1
47 changed files with 1347 additions and 661 deletions
@@ -333,6 +333,23 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
symbol is FirTypeParameterSymbol
}
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
TODO("not implemented")
}
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
TODO("not implemented")
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
TODO("not implemented")
}
override fun SimpleTypeMarker.isStubType(): Boolean {
TODO("not implemented")
}
}
@@ -359,4 +376,8 @@ class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean,
get() = false
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return super<ConeTypeContext>.prepareType(type)
}
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbacksImpl
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
@@ -72,6 +73,7 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
useImpl<ExperimentalUsageChecker>()
useImpl<ExperimentalUsageChecker.Overrides>()
useImpl<ExperimentalUsageChecker.ClassifierUsage>()
useImpl<ClassicTypeSystemContextForCS>()
}
fun StorageComponentContainer.configureModule(
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class DiagnosticReporterByTrackingStrategy(
@@ -212,19 +213,19 @@ class DiagnosticReporterByTrackingStrategy(
val expression = it.psiExpression ?: return
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
if (reportConstantTypeMismatch(constraintError, deparenthesized)) return
trace.report(Errors.TYPE_MISMATCH.on(deparenthesized, constraintError.upperType, constraintError.lowerType))
trace.report(Errors.TYPE_MISMATCH.on(deparenthesized, constraintError.upperKotlinType, constraintError.lowerKotlinType))
}
(position as? ExpectedTypeConstraintPosition)?.let {
val call = it.topLevelCall.psiKotlinCall.psiCall.callElement.safeAs<KtExpression>()
reportIfNonNull(call) {
trace.report(Errors.TYPE_MISMATCH.on(it, constraintError.upperType, constraintError.lowerType))
trace.report(Errors.TYPE_MISMATCH.on(it, constraintError.upperKotlinType, constraintError.lowerKotlinType))
}
}
(position as? ExplicitTypeParameterConstraintPosition)?.let {
val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperType, constraintError.lowerType))
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperKotlinType, constraintError.lowerKotlinType))
}
}
CapturedTypeFromSubtyping::class.java -> {
@@ -247,10 +248,14 @@ class DiagnosticReporterByTrackingStrategy(
val module = context.scope.ownerDescriptor.module
val constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, trace, context.expectedType)
val hasConstantTypeError = CompileTimeConstantChecker(context, module, true)
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
.checkConstantExpressionType(constantValue, expression, constraintError.upperKotlinType)
if (hasConstantTypeError) return true
}
return false
}
}
}
val NewConstraintError.upperKotlinType get() = upperType as KotlinType
val NewConstraintError.lowerKotlinType get() = lowerType as KotlinType
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.components.CompletedCallInfo
import org.jetbrains.kotlin.resolve.calls.components.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.utils.addToStdlib.cast
class CoroutineInferenceSession(
psiCallResolver: PSICallResolver,
@@ -88,7 +90,7 @@ class CoroutineInferenceSession(
updateCalls(lambda, commonSystem)
return commonSystem.fixedTypeVariables
return commonSystem.fixedTypeVariables.cast() // TODO: SUB
}
private fun createNonFixedTypeToVariableSubstitutor(): NewTypeSubstitutorByConstructorMap {
@@ -117,8 +119,8 @@ class CoroutineInferenceSession(
val callSubstitutor = storage.buildResultingSubstitutor() // substitutor only for fixed variables
for (initialConstraint in storage.initialConstraints) {
val lower = nonFixedToVariablesSubstitutor.safeSubstitute(callSubstitutor.safeSubstitute(initialConstraint.a))
val upper = nonFixedToVariablesSubstitutor.safeSubstitute(callSubstitutor.safeSubstitute(initialConstraint.b))
val lower = nonFixedToVariablesSubstitutor.safeSubstitute(callSubstitutor.safeSubstitute(initialConstraint.a as UnwrappedType)) // TODO: SUB
val upper = nonFixedToVariablesSubstitutor.safeSubstitute(callSubstitutor.safeSubstitute(initialConstraint.b as UnwrappedType)) // TODO: SUB
if (commonSystem.isProperType(lower) && commonSystem.isProperType(upper)) continue
@@ -183,9 +185,9 @@ class CoroutineInferenceSession(
nonFixedTypesToResult: Map<TypeConstructor, UnwrappedType>
) {
val resultingCallSubstitutor = completedCall.callResolutionResult.constraintSystem.fixedTypeVariables.entries
.associate { it.key to nonFixedTypesToResultSubstitutor.safeSubstitute(it.value) }
.associate { it.key to nonFixedTypesToResultSubstitutor.safeSubstitute(it.value as UnwrappedType) } // TODO: SUB
val resultingSubstitutor = NewTypeSubstitutorByConstructorMap(resultingCallSubstitutor + nonFixedTypesToResult)
val resultingSubstitutor = NewTypeSubstitutorByConstructorMap((resultingCallSubstitutor + nonFixedTypesToResult).cast()) // TODO: SUB
val atomCompleter = createResolvedAtomCompleter(resultingSubstitutor, completedCall.context)
val resultCallAtom = completedCall.callResolutionResult.resultCallAtom
@@ -665,7 +665,9 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: substituted
TypeApproximator(substituted.constructor.builtIns)
.approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation)
?: substituted
}
calculateExpedtedTypeForSamConvertedArgumentMap(substitutor)
@@ -134,7 +134,7 @@ class ResolvedAtomCompleter(
}
val approximatedReturnType =
TypeApproximator().approximateDeclarationType(
TypeApproximator(builtIns).approximateDeclarationType(
returnType,
local = true,
languageVersionSettings = topLevelCallContext.languageVersionSettings
@@ -28,7 +28,7 @@ internal val jvmCoercionToUnitPhase = makeIrFilePhase(
class JvmCoercionToUnitPatcher(val context: JvmBackendContext) :
InsertImplicitCasts(
context.builtIns, context.irBuiltIns,
TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings),
TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings, context.builtIns),
JvmGeneratorExtensions.samConversion
),
FileLoweringPass {
@@ -40,7 +40,7 @@ class GeneratorContext(
) : IrGeneratorContext() {
val constantValueGenerator: ConstantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
val typeTranslator: TypeTranslator = TypeTranslator(symbolTable, languageVersionSettings)
val typeTranslator: TypeTranslator = TypeTranslator(symbolTable, languageVersionSettings, builtIns = moduleDescriptor.builtIns)
init {
typeTranslator.constantValueGenerator = constantValueGenerator
@@ -45,7 +45,7 @@ class DeclarationStubGenerator(
}
private val typeTranslator = TypeTranslator(lazyTable, languageVersionSettings, LazyScopedTypeParametersResolver(lazyTable), true)
private val typeTranslator = TypeTranslator(lazyTable, languageVersionSettings, moduleDescriptor.builtIns, LazyScopedTypeParametersResolver(lazyTable), true)
private val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, lazyTable)
init {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -25,11 +26,12 @@ import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
class TypeTranslator(
private val symbolTable: ReferenceSymbolTable,
val languageVersionSettings: LanguageVersionSettings,
builtIns: KotlinBuiltIns,
private val typeParametersResolver: TypeParametersResolver = ScopedTypeParametersResolver(),
private val enterTableScope: Boolean = false
) {
private val typeApproximatorForNI = TypeApproximator()
private val typeApproximatorForNI = TypeApproximator(builtIns)
lateinit var constantValueGenerator: ConstantValueGenerator
fun enterScope(irElement: IrTypeParametersContainer) {
@@ -124,7 +126,11 @@ class TypeTranslator(
if (ktType.constructor.isDenotable) return ktType
return if (languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
typeApproximatorForNI.approximateDeclarationType(ktType, local = false, languageVersionSettings = languageVersionSettings)
typeApproximatorForNI.approximateDeclarationType(
ktType,
local = false,
languageVersionSettings = languageVersionSettings
)
else
approximateCapturedTypes(ktType).upper
}
@@ -21,17 +21,24 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.canHaveUndefinedNullability
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes
import org.jetbrains.kotlin.types.model.*
object NewCommonSuperTypeCalculator {
// TODO: Bridge for old calls
fun commonSuperType(types: List<UnwrappedType>): UnwrappedType {
val ctx = object : ClassicTypeSystemContext {}
return ctx.commonSuperType(types) as UnwrappedType
}
fun TypeSystemCommonSuperTypesContext.commonSuperType(types: List<KotlinTypeMarker>): KotlinTypeMarker {
val maxDepth = types.maxBy { it.typeDepth() }?.typeDepth() ?: 0
return commonSuperType(types, -maxDepth)
}
private fun commonSuperType(types: List<UnwrappedType>, depth: Int): UnwrappedType {
private fun TypeSystemCommonSuperTypesContext.commonSuperType(types: List<KotlinTypeMarker>, depth: Int): KotlinTypeMarker {
if (types.isEmpty()) throw IllegalStateException("Empty collection for input")
types.singleOrNull()?.let { return it }
@@ -40,49 +47,57 @@ object NewCommonSuperTypeCalculator {
val lowers = types.map {
when (it) {
is SimpleType -> it
is FlexibleType -> {
if (it is DynamicType) return it
is SimpleTypeMarker -> it
is FlexibleTypeMarker -> {
if (it.isDynamic()) return it
// raw types are allowed here and will be transformed to FlexibleTypes
thereIsFlexibleTypes = true
it.lowerBound
it.lowerBound()
}
else -> error("sealed")
}
}
val lowerSuperType = commonSuperTypeForSimpleTypes(lowers, depth)
if (!thereIsFlexibleTypes) return lowerSuperType
val upperSuperType = commonSuperTypeForSimpleTypes(types.map { it.upperIfFlexible() }, depth)
return KotlinTypeFactory.flexibleType(lowerSuperType, upperSuperType)
val upperSuperType = commonSuperTypeForSimpleTypes(types.map { it.upperBoundIfFlexible() }, depth)
return createFlexibleType(lowerSuperType, upperSuperType)
}
private fun commonSuperTypeForSimpleTypes(types: List<SimpleType>, depth: Int): SimpleType {
private fun TypeSystemCommonSuperTypesContext.commonSuperTypeForSimpleTypes(
types: List<SimpleTypeMarker>,
depth: Int
): SimpleTypeMarker {
// i.e. result type also should be marked nullable
val notAllNotNull = types.any { !NullabilityChecker.isSubtypeOfAny(it) }
val notNullTypes = if (notAllNotNull) types.map { it.makeNullableAsSpecified(false) } else types
val notAllNotNull = types.any { !AbstractNullabilityChecker.isSubtypeOfAny(this, it) }
val notNullTypes = if (notAllNotNull) types.map { it.withNullability(false) } else types
val commonSuperType = commonSuperTypeForNotNullTypes(notNullTypes, depth)
return if (notAllNotNull)
refineNullabilityForUndefinedNullability(types, commonSuperType) ?: commonSuperType.makeNullableAsSpecified(true)
refineNullabilityForUndefinedNullability(types, commonSuperType) ?: commonSuperType.withNullability(true)
else
commonSuperType
}
private fun refineNullabilityForUndefinedNullability(types: List<SimpleType>, commonSuperType: SimpleType): SimpleType? {
if (!commonSuperType.unwrap().canHaveUndefinedNullability()) return null
private fun TypeSystemCommonSuperTypesContext.refineNullabilityForUndefinedNullability(
types: List<SimpleTypeMarker>,
commonSuperType: SimpleTypeMarker
): SimpleTypeMarker? {
if (!commonSuperType.canHaveUndefinedNullability()) return null
val actuallyNotNull = types.all { NullabilityChecker.hasPathByNotMarkedNullableNodes(it, commonSuperType.constructor) }
val actuallyNotNull =
types.all { hasPathByNotMarkedNullableNodes(it, commonSuperType.typeConstructor()) }
return if (actuallyNotNull) commonSuperType else null
}
// Makes representative sample, i.e. (A, B, A) -> (A, B)
private fun List<SimpleType>.uniquify(): List<SimpleType> {
val uniqueTypes = arrayListOf<SimpleType>()
for (type in this) {
private fun TypeSystemCommonSuperTypesContext.uniquify(types: List<SimpleTypeMarker>): List<SimpleTypeMarker> {
val uniqueTypes = arrayListOf<SimpleTypeMarker>()
for (type in types) {
val isNewUniqueType = uniqueTypes.all {
!NewKotlinTypeChecker.equalTypes(it, type) || it.constructor is IntegerLiteralTypeConstructor
!AbstractTypeChecker.equalTypes(this, it, type) || it.typeConstructor().isIntegerLiteralTypeConstructor()
}
if (isNewUniqueType) {
uniqueTypes += type
@@ -93,13 +108,13 @@ object NewCommonSuperTypeCalculator {
// This function leaves only supertypes, i.e. A0 is a strong supertype for A iff A != A0 && A <: A0
// Explanation: consider types (A : A0, B : B0, A0, B0), then CST(A, B, A0, B0) == CST(CST(A, A0), CST(B, B0)) == CST(A0, B0)
private fun List<SimpleType>.filterSupertypes(): List<SimpleType> {
val supertypes = this.toMutableList()
private fun TypeSystemCommonSuperTypesContext.filterSupertypes(list: List<SimpleTypeMarker>): List<SimpleTypeMarker> {
val supertypes = list.toMutableList()
val iterator = supertypes.iterator()
while (iterator.hasNext()) {
val potentialSubtype = iterator.next()
val isSubtype = supertypes.any { supertype ->
supertype !== potentialSubtype && NewKotlinTypeChecker.isSubtypeOf(potentialSubtype, supertype)
supertype !== potentialSubtype && AbstractTypeChecker.isSubtypeOf(this, potentialSubtype, supertype)
}
if (isSubtype) iterator.remove()
@@ -108,28 +123,35 @@ object NewCommonSuperTypeCalculator {
return supertypes
}
private fun commonSuperTypeForNotNullTypes(types: List<SimpleType>, depth: Int): SimpleType {
private fun TypeSystemCommonSuperTypesContext.commonSuperTypeForNotNullTypes(
types: List<SimpleTypeMarker>,
depth: Int
): SimpleTypeMarker {
if (types.size == 1) return types.single()
val uniqueTypes = types.uniquify()
val uniqueTypes = uniquify(types)
if (uniqueTypes.size == 1) return uniqueTypes.single()
val explicitSupertypes = uniqueTypes.filterSupertypes()
val explicitSupertypes = filterSupertypes(uniqueTypes)
if (explicitSupertypes.size == 1) return explicitSupertypes.single()
IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
findCommonIntegerLiteralTypesSuperType(explicitSupertypes)?.let { return it }
// IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth)
}
private fun findSuperTypeConstructorsAndIntersectResult(types: List<SimpleType>, depth: Int): SimpleType {
private fun TypeSystemCommonSuperTypesContext.findSuperTypeConstructorsAndIntersectResult(
types: List<SimpleTypeMarker>,
depth: Int
): SimpleTypeMarker {
return intersectTypes(allCommonSuperTypeConstructors(types).map { superTypeWithGivenConstructor(types, it, depth) })
}
/**
* Note that if there is captured type C, then no one else is not subtype of C => lowerType cannot help here
*/
private fun allCommonSuperTypeConstructors(types: List<SimpleType>): List<TypeConstructor> {
private fun TypeSystemCommonSuperTypesContext.allCommonSuperTypeConstructors(types: List<SimpleTypeMarker>): List<TypeConstructorMarker> {
val result = collectAllSupertypes(types.first())
for (type in types) {
if (type === types.first()) continue
@@ -138,22 +160,22 @@ object NewCommonSuperTypeCalculator {
}
return result.filterNot { target ->
result.any { other ->
other != target && other.supertypes.any { it.constructor == target }
other != target && other.supertypes().any { it.typeConstructor() == target }
}
}
}
private fun collectAllSupertypes(type: SimpleType) = LinkedHashSet<TypeConstructor>().apply {
type.anySuperTypeConstructor { add(it); false }
}
private fun TypeSystemCommonSuperTypesContext.collectAllSupertypes(type: SimpleTypeMarker) =
LinkedHashSet<TypeConstructorMarker>().apply {
type.anySuperTypeConstructor { add(it); false }
}
private fun superTypeWithGivenConstructor(
types: List<SimpleType>,
constructor: TypeConstructor,
private fun TypeSystemCommonSuperTypesContext.superTypeWithGivenConstructor(
types: List<SimpleTypeMarker>,
constructor: TypeConstructorMarker,
depth: Int
): SimpleType {
if (constructor.parameters.isEmpty()) return KotlinTypeFactory.simpleType(
Annotations.EMPTY,
): SimpleTypeMarker {
if (constructor.parametersCount() == 0) return createSimpleType(
constructor,
emptyList(),
nullable = false
@@ -168,17 +190,18 @@ object NewCommonSuperTypeCalculator {
* but it is too complicated and we will return not so accurate type: CS(List<Int>, List<Double>, List<String>)
*/
val correspondingSuperTypes = types.flatMap {
with(NewKotlinTypeChecker) {
with(AbstractTypeChecker) {
typeCheckerContext.findCorrespondingSupertypes(it, constructor)
}
}
val arguments = ArrayList<TypeProjection>(constructor.parameters.size)
for ((index, parameter) in constructor.parameters.withIndex()) {
val arguments = ArrayList<TypeArgumentMarker>(constructor.parametersCount())
for (index in 0 until constructor.parametersCount()) {
val parameter = constructor.getParameter(index)
var thereIsStar = false
val typeProjections = correspondingSuperTypes.mapNotNull {
it.arguments.getOrNull(index)?.let {
if (it.isStarProjection) {
it.getArgumentOrNull(index)?.let {
if (it.isStarProjection()) {
thereIsStar = true
null
} else it
@@ -187,38 +210,42 @@ object NewCommonSuperTypeCalculator {
val argument =
if (thereIsStar || typeProjections.isEmpty()) {
StarProjectionImpl(parameter)
createStarProjection(parameter)
} else {
calculateArgument(parameter, typeProjections, depth)
}
arguments.add(argument)
}
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, arguments, nullable = false)
return createSimpleType(constructor, arguments, nullable = false)
}
// no star projections in arguments
private fun calculateArgument(parameter: TypeParameterDescriptor, arguments: List<TypeProjection>, depth: Int): TypeProjection {
private fun TypeSystemCommonSuperTypesContext.calculateArgument(
parameter: TypeParameterMarker,
arguments: List<TypeArgumentMarker>,
depth: Int
): TypeArgumentMarker {
if (depth > 3) {
return StarProjectionImpl(parameter)
return createStarProjection(parameter)
}
// Inv<A>, Inv<A> = Inv<A>
if (parameter.variance == Variance.INVARIANT && arguments.all { it.projectionKind == Variance.INVARIANT }) {
if (parameter.getVariance() == TypeVariance.INV && arguments.all { it.getVariance() == TypeVariance.INV }) {
val first = arguments.first()
if (arguments.all { it.type == first.type }) return first
if (arguments.all { it.getType() == first.getType() }) return first
}
val asOut: Boolean
if (parameter.variance != Variance.INVARIANT) {
asOut = parameter.variance == Variance.OUT_VARIANCE
if (parameter.getVariance() != TypeVariance.INV) {
asOut = parameter.getVariance() == TypeVariance.OUT
} else {
val thereIsOut = arguments.any { it.projectionKind == Variance.OUT_VARIANCE }
val thereIsIn = arguments.any { it.projectionKind == Variance.IN_VARIANCE }
val thereIsOut = arguments.any { it.getVariance() == TypeVariance.OUT }
val thereIsIn = arguments.any { it.getVariance() == TypeVariance.IN }
if (thereIsOut) {
if (thereIsIn) {
// CS(Inv<out X>, Inv<in Y>) = Inv<*>
return StarProjectionImpl(parameter)
return createStarProjection(parameter)
} else {
asOut = true
}
@@ -230,16 +257,16 @@ object NewCommonSuperTypeCalculator {
// CS(Out<X>, Out<Y>) = Out<CS(X, Y)>
// CS(In<X>, In<Y>) = In<X & Y>
if (asOut) {
val type = commonSuperType(arguments.map { it.type.unwrap() }, depth + 1)
return if (parameter.variance != Variance.INVARIANT) return type.asTypeProjection() else TypeProjectionImpl(
Variance.OUT_VARIANCE,
type
val type = commonSuperType(arguments.map { it.getType() }, depth + 1)
return if (parameter.getVariance() != TypeVariance.INV) return type.asTypeArgument() else createTypeArgument(
type,
TypeVariance.OUT
)
} else {
val type = intersectTypes(arguments.map { it.type.unwrap() })
return if (parameter.variance != Variance.INVARIANT) return type.asTypeProjection() else TypeProjectionImpl(
Variance.IN_VARIANCE,
type
val type = intersectTypes(arguments.map { it.getType() })
return if (parameter.getVariance() != TypeVariance.INV) return type.asTypeArgument() else createTypeArgument(
type,
TypeVariance.IN
)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
interface BuiltInsProvider {
val builtIns: KotlinBuiltIns
}
internal val ConstraintSystemBuilder.builtIns: KotlinBuiltIns get() = ((this as NewConstraintSystemImpl).typeSystemContext as BuiltInsProvider).builtIns
internal val NewConstraintSystem.builtIns: KotlinBuiltIns get() = ((this as NewConstraintSystemImpl).typeSystemContext as BuiltInsProvider).builtIns
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.addToStdlib.cast
class ClassicTypeSystemContextForCS(override val builtIns: KotlinBuiltIns) : TypeSystemInferenceExtensionContextDelegate,
ClassicTypeSystemContext,
BuiltInsProvider {
override fun TypeVariableMarker.defaultType(): SimpleTypeMarker {
require(this is NewTypeVariable, this::errorMessage)
return this.defaultType
}
override fun TypeVariableMarker.freshTypeConstructor(): TypeConstructorMarker {
require(this is NewTypeVariable, this::errorMessage)
return this.freshTypeConstructor
}
override fun createCapturedType(
constructorProjection: TypeArgumentMarker,
constructorSupertypes: List<KotlinTypeMarker>,
lowerType: KotlinTypeMarker?,
captureStatus: CaptureStatus
): CapturedTypeMarker {
require(lowerType is UnwrappedType?, lowerType::errorMessage)
require(constructorProjection is TypeProjectionImpl, constructorProjection::errorMessage)
@Suppress("UNCHECKED_CAST")
val newCapturedTypeConstructor = NewCapturedTypeConstructor(
constructorProjection,
constructorSupertypes as List<UnwrappedType>
)
return NewCapturedType(
CaptureStatus.FOR_INCORPORATION,
newCapturedTypeConstructor,
lowerType = lowerType
)
}
override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker {
return NewTypeSubstitutorByConstructorMap(map.cast())
}
override fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker {
require(type is UnwrappedType, this::errorMessage)
require(this is NewTypeSubstitutor, this::errorMessage)
return this.safeSubstitute(type)
}
override fun createStubType(typeVariable: TypeVariableMarker): StubTypeMarker {
return StubType(typeVariable.freshTypeConstructor() as TypeConstructor, typeVariable.defaultType().isMarkedNullable())
}
}
@Suppress("NOTHING_TO_INLINE")
private inline fun Any?.errorMessage(): String {
return "ClassicTypeSystemContextForCS couldn't handle: $this, ${this?.let { it::class }}"
}
@Suppress("FunctionName")
fun NewConstraintSystemImpl(
constraintInjector: ConstraintInjector,
builtIns: KotlinBuiltIns
): NewConstraintSystemImpl {
return NewConstraintSystemImpl(constraintInjector, ClassicTypeSystemContextForCS(builtIns))
}
@@ -14,10 +14,10 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empt
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
class KotlinCallCompleter(
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
@@ -196,13 +196,16 @@ class KotlinCallCompleter(
private fun KotlinResolutionCandidate.hasProperNonTrivialLowerConstraints(typeVariable: UnwrappedType): Boolean {
assert(csBuilder.isTypeVariable(typeVariable)) { "$typeVariable is not a type variable" }
val context = getSystem() as TypeSystemInferenceExtensionContext
val constructor = typeVariable.constructor
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
val constraints = variableWithConstraints.constraints
return constraints.isNotEmpty() && constraints.all {
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) && it.type.constructor !is IntegerLiteralTypeConstructor &&
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) &&
with(context) { !it.type.typeConstructor().isIntegerLiteralTypeConstructor() } &&
it.kind.isLower() && csBuilder.isProperType(it.type)
}
}
private fun KotlinResolutionCandidate.computeReturnTypeWithSmartCastInfo(
@@ -19,10 +19,13 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.LHSArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -141,7 +144,8 @@ private fun preprocessCallableReference(
if (expectedType == null) return result
val notCallableTypeConstructor =
csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) }
csBuilder.getProperSuperTypeConstructors(expectedType)
.firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it.requireIs()) }
argument.lhsResult.safeAs<LHSResult.Type>()?.let {
val lhsType = it.unboundDetailedReceiver.stableType
@@ -151,7 +155,13 @@ private fun preprocessCallableReference(
}
}
if (notCallableTypeConstructor != null) {
diagnosticsHolder.addDiagnostic(NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor))
diagnosticsHolder.addDiagnostic(
NotCallableExpectedType(
argument,
expectedType,
notCallableTypeConstructor.requireIs()
)
)
}
return result
}
@@ -163,3 +173,8 @@ private fun preprocessCollectionLiteralArgument(
// todo add some checks about expected type
return ResolvedCollectionLiteralAtom(collectionLiteralArgument, expectedType)
}
internal inline fun <reified T : Any> Any.requireIs(): T {
require(this is T)
return this
}
@@ -10,22 +10,22 @@ import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemFromArgument
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.utils.addToStdlib.cast
class PostponedArgumentsAnalyzer(
private val callableReferenceResolver: CallableReferenceResolver
) {
interface Context {
fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructor, StubType>): NewTypeSubstitutor
fun bindingStubsForPostponedVariables(): Map<NewTypeVariable, StubType>
interface Context : TypeSystemInferenceExtensionContext {
fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>): NewTypeSubstitutor
fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker>
// type can be proper if it not contains not fixed type variables
fun canBeProper(type: UnwrappedType): Boolean
fun canBeProper(type: KotlinTypeMarker): Boolean
fun hasUpperOrEqualUnitConstraint(type: UnwrappedType): Boolean
fun hasUpperOrEqualUnitConstraint(type: KotlinTypeMarker): Boolean
// mutable operations
fun addOtherSystem(otherSystem: ConstraintStorage)
@@ -64,7 +64,7 @@ class PostponedArgumentsAnalyzer(
diagnosticHolder: KotlinDiagnosticsHolder
) {
val stubsForPostponedVariables = c.bindingStubsForPostponedVariables()
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor })
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor(c) })
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type)
@@ -87,7 +87,7 @@ class PostponedArgumentsAnalyzer(
receiver,
parameters,
expectedTypeForReturnArguments,
stubsForPostponedVariables
stubsForPostponedVariables.cast()
)
returnArguments.forEach { c.addSubsystemFromArgument(it) }
@@ -115,7 +115,7 @@ class PostponedArgumentsAnalyzer(
val variable = variableWithConstraints.typeVariable
c.getBuilder().unmarkPostponedVariable(variable)
c.getBuilder().addEqualityConstraint(variable.defaultType, resultType, CoroutinePosition())
c.getBuilder().addEqualityConstraint(variable.defaultType(c), resultType, CoroutinePosition())
}
}
}
@@ -24,27 +24,29 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
interface ConstraintSystemOperation {
val hasContradiction: Boolean
fun registerVariable(variable: NewTypeVariable)
fun markPostponedVariable(variable: NewTypeVariable)
fun unmarkPostponedVariable(variable: NewTypeVariable)
fun registerVariable(variable: TypeVariableMarker)
fun markPostponedVariable(variable: TypeVariableMarker)
fun unmarkPostponedVariable(variable: TypeVariableMarker)
fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition)
fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition)
fun addSubtypeConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition)
fun addEqualityConstraint(a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition)
fun isProperType(type: UnwrappedType): Boolean
fun isTypeVariable(type: UnwrappedType): Boolean
fun isPostponedTypeVariable(typeVariable: NewTypeVariable): Boolean
fun isProperType(type: KotlinTypeMarker): Boolean
fun isTypeVariable(type: KotlinTypeMarker): Boolean
fun isPostponedTypeVariable(typeVariable: TypeVariableMarker): Boolean
fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor>
fun getProperSuperTypeConstructors(type: KotlinTypeMarker): List<TypeConstructorMarker>
}
interface ConstraintSystemBuilder : ConstraintSystemOperation {
val builtIns: KotlinBuiltIns
//val builtIns: KotlinBuiltIns
// if runOperations return true, then this operation will be applied, and function return true
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
@@ -54,8 +56,8 @@ interface ConstraintSystemBuilder : ConstraintSystemOperation {
}
fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(
lowerType: UnwrappedType,
upperType: UnwrappedType,
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
position: ConstraintPosition
) =
runTransaction {
@@ -20,11 +20,15 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.StubTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.utils.addToStdlib.cast
fun ConstraintStorage.buildCurrentSubstitutor(additionalBindings: Map<TypeConstructor, StubType>): NewTypeSubstitutorByConstructorMap =
NewTypeSubstitutorByConstructorMap(fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings)
fun ConstraintStorage.buildCurrentSubstitutor(additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>): NewTypeSubstitutorByConstructorMap =
NewTypeSubstitutorByConstructorMap( (fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings).cast() ) // TODO: SUB
fun ConstraintStorage.buildResultingSubstitutor(): NewTypeSubstitutor {
val currentSubstitutorMap = fixedTypeVariables.entries.associate {
@@ -33,11 +37,11 @@ fun ConstraintStorage.buildResultingSubstitutor(): NewTypeSubstitutor {
val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor(
"Uninferred type",
typeVariable.typeVariable.freshTypeConstructor
(typeVariable.typeVariable as NewTypeVariable).freshTypeConstructor// TODO: SUB
)
}
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
return NewTypeSubstitutorByConstructorMap((currentSubstitutorMap + uninferredSubstitutorMap).cast()) // TODO: SUB
}
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
@@ -63,7 +67,7 @@ fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTyp
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation)
TypeApproximator(builtIns).approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation)
?: substitutedType
}
}
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
interface NewConstraintSystem {
val builtIns: KotlinBuiltIns
// val builtIns: KotlinBuiltIns
val hasContradiction: Boolean
val diagnostics: List<KotlinCallDiagnostic>
@@ -5,34 +5,28 @@
package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.hasNoInferAnnotation
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinTypeFactory.flexibleType
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.checker.*
import org.jetbrains.kotlin.types.model.CapturedTypeMarker
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.model.*
abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) {
abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheckerContext(), TypeSystemInferenceExtensionContext {
abstract fun isMyTypeVariable(type: SimpleType): Boolean
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = false
override val isErrorTypeEqualsToAnything: Boolean
get() = true
abstract fun isMyTypeVariable(type: SimpleTypeMarker): Boolean
// super and sub type isSingleClassifierType
abstract fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType)
abstract fun addUpperConstraint(typeVariable: TypeConstructorMarker, superType: KotlinTypeMarker)
abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType)
abstract fun addLowerConstraint(typeVariable: TypeConstructorMarker, subType: KotlinTypeMarker)
override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy {
require(subType is SimpleType)
require(superType is NewCapturedType)
return getLowerCapturedTypePolicy(subType, superType)
}
private fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = when {
override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy = when {
isMyTypeVariable(subType) -> LowerCapturedTypePolicy.SKIP_LOWER
subType.contains { it.anyBound(this::isMyTypeVariable) } -> LowerCapturedTypePolicy.CHECK_ONLY_LOWER
else -> LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER
@@ -45,16 +39,14 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
* override val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.TAKE_FIRST_FOR_SUBTYPING
*/
final override fun addSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
require(subType is UnwrappedType)
require(superType is UnwrappedType)
val hasNoInfer = subType.isTypeVariableWithNoInfer() || superType.isTypeVariableWithNoInfer()
if (hasNoInfer) return true
val hasExact = subType.isTypeVariableWithExact() || superType.isTypeVariableWithExact()
// we should strip annotation's because we have incorporation operation and they should be not affected
val mySubType = if (hasExact) subType.replaceAnnotations(Annotations.EMPTY) else subType
val mySuperType = if (hasExact) superType.replaceAnnotations(Annotations.EMPTY) else superType
val mySubType = if (hasExact) subType.removeAnnotations() else subType
val mySuperType = if (hasExact) superType.removeAnnotations() else superType
val result = internalAddSubtypeConstraint(mySubType, mySuperType)
if (!hasExact) return result
@@ -65,13 +57,13 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
return (result ?: true) && (result2 ?: true)
}
private fun UnwrappedType.isTypeVariableWithExact() =
anyBound(this@TypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasExactAnnotation()
private fun KotlinTypeMarker.isTypeVariableWithExact() =
anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasExactAnnotation()
private fun UnwrappedType.isTypeVariableWithNoInfer() =
anyBound(this@TypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasNoInferAnnotation()
private fun KotlinTypeMarker.isTypeVariableWithNoInfer() =
anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasNoInferAnnotation()
private fun internalAddSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
private fun internalAddSubtypeConstraint(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
assertInputTypes(subType, superType)
var answer: Boolean? = null
@@ -92,12 +84,13 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
}
// extract type variable only from type like Captured(out T)
private fun extractTypeVariableForSubtype(type: UnwrappedType): UnwrappedType? {
if (type !is NewCapturedType) return null
private fun extractTypeVariableForSubtype(type: KotlinTypeMarker): KotlinTypeMarker? {
val projection = type.constructor.projection
return if (projection.projectionKind == Variance.OUT_VARIANCE)
projection.type.takeIf { it is SimpleType && isMyTypeVariable(it) }?.unwrap()
val type = type.asSimpleType()?.asCapturedType() ?: return null
val projection = type.typeConstructorProjection()
return if (projection.getVariance() == TypeVariance.OUT)
projection.getType().takeIf { it is SimpleTypeMarker && isMyTypeVariable(it) }?.asSimpleType()
else
null
}
@@ -139,35 +132,38 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
*
* => (Foo..Bar) <: T! -- (Foo!! .. Bar) <: T
*/
private fun simplifyLowerConstraint(typeVariable: UnwrappedType, subType: UnwrappedType): Boolean {
private fun simplifyLowerConstraint(typeVariable: KotlinTypeMarker, subType: KotlinTypeMarker): Boolean {
val lowerConstraint = when (typeVariable) {
is SimpleType ->
is SimpleTypeMarker ->
// Foo <: T or
// Foo <: T? -- Foo!! <: T
if (typeVariable.isMarkedNullable) subType.makeDefinitelyNotNullOrNotNull() else subType
if (typeVariable.isMarkedNullable()) subType.makeDefinitelyNotNullOrNotNull() else subType
is FlexibleType -> {
is FlexibleTypeMarker -> {
assertFlexibleTypeVariable(typeVariable)
when (subType) {
is SimpleType ->
is SimpleTypeMarker ->
// Foo <: T! -- (Foo!! .. Foo) <: T
flexibleType(subType.makeSimpleTypeDefinitelyNotNullOrNotNull(), subType)
createFlexibleType(subType.makeSimpleTypeDefinitelyNotNullOrNotNull(), subType)
is FlexibleType ->
is FlexibleTypeMarker ->
// (Foo..Bar) <: T! -- (Foo!! .. Bar) <: T
flexibleType(subType.lowerBound.makeSimpleTypeDefinitelyNotNullOrNotNull(), subType.upperBound)
createFlexibleType(subType.lowerBound().makeSimpleTypeDefinitelyNotNullOrNotNull(), subType.upperBound())
else -> error("sealed")
}
}
else -> error("sealed")
}
addLowerConstraint(typeVariable.constructor, lowerConstraint)
addLowerConstraint(typeVariable.typeConstructor(), lowerConstraint)
return true
}
private fun assertFlexibleTypeVariable(typeVariable: FlexibleType) {
assert(typeVariable.lowerBound.constructor == typeVariable.upperBound.constructor) {
private fun assertFlexibleTypeVariable(typeVariable: FlexibleTypeMarker) {
assert(typeVariable.lowerBound().typeConstructor() == typeVariable.upperBound().typeConstructor()) {
"Flexible type variable ($typeVariable) should have bounds with the same type constructor, i.e. (T..T?)"
}
}
@@ -177,40 +173,46 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
* T? <: Foo <=> T <: Foo && Nothing? <: Foo
* T <: Foo -- leave as is
*/
private fun simplifyUpperConstraint(typeVariable: UnwrappedType, superType: UnwrappedType): Boolean {
private fun simplifyUpperConstraint(typeVariable: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
@Suppress("NAME_SHADOWING")
val typeVariable = typeVariable.lowerIfFlexible()
val typeVariable = typeVariable.lowerBoundIfFlexible()
@Suppress("NAME_SHADOWING")
val superType = if (typeVariable is DefinitelyNotNullType) superType.makeNullableAsSpecified(true) else superType
val superType = if (typeVariable.isDefinitelyNotNullType()) superType.withNullability(true) else superType
addUpperConstraint(typeVariable.constructor, superType)
addUpperConstraint(typeVariable.typeConstructor(), superType)
if (typeVariable.isMarkedNullable) {
if (typeVariable.isMarkedNullable()) {
// here is important that superType is singleClassifierType
return superType.anyBound(this::isMyTypeVariable) ||
isSubtypeOfByTypeChecker(typeVariable.builtIns.nullableNothingType, superType)
isSubtypeOfByTypeChecker(nullableNothingType(), superType)
}
return true
}
private fun simplifyConstraintForPossibleIntersectionSubType(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
private fun simplifyConstraintForPossibleIntersectionSubType(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? {
@Suppress("NAME_SHADOWING")
val subType = subType.lowerIfFlexible()
val subType = subType.lowerBoundIfFlexible()
if (!subType.isIntersectionType) return null
if (!subType.typeConstructor().isIntersection()) return null
assert(!subType.isMarkedNullable) { "Intersection type should not be marked nullable!: $subType" }
assert(!subType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $subType" }
// TODO: may be we lose flexibility here
val subIntersectionTypes = (subType.constructor as IntersectionTypeConstructor).supertypes.map { it.lowerIfFlexible() }
val subIntersectionTypes = (subType.typeConstructor().supertypes()).map { it.lowerBoundIfFlexible() }
val typeVariables = subIntersectionTypes.filter(this::isMyTypeVariable).takeIf { it.isNotEmpty() } ?: return null
val notTypeVariables = subIntersectionTypes.filterNot(this::isMyTypeVariable)
// todo: may be we can do better then that.
if (notTypeVariables.isNotEmpty() && NewKotlinTypeChecker.isSubtypeOf(intersectTypes(notTypeVariables) as KotlinType, superType)) {
if (notTypeVariables.isNotEmpty() &&
AbstractTypeChecker.isSubtypeOf(
this as TypeCheckerProviderContext,
intersectTypes(notTypeVariables),
superType
)
) {
return true
}
@@ -229,22 +231,22 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
// here we try to add constraint {Any & T} <: S from `id(a)`
// Previously we thought that if `Any` isn't a subtype of S => T <: S, which is wrong, now we use weaker upper constraint
// TODO: rethink, maybe we should take nullability into account somewhere else
if (notTypeVariables.any { NullabilityChecker.isSubtypeOfAny(it) }) {
return typeVariables.all { simplifyUpperConstraint(it, superType.makeNullableAsSpecified(true)) }
if (notTypeVariables.any { AbstractNullabilityChecker.isSubtypeOfAny(this as TypeCheckerProviderContext, it) }) {
return typeVariables.all { simplifyUpperConstraint(it, superType.withNullability(true)) }
}
return typeVariables.all { simplifyUpperConstraint(it, superType) }
}
private fun isSubtypeOfByTypeChecker(subType: UnwrappedType, superType: UnwrappedType) =
with(NewKotlinTypeChecker) { this@TypeCheckerContextForConstraintSystem.isSubtypeOf(subType, superType) }
private fun isSubtypeOfByTypeChecker(subType: KotlinTypeMarker, superType: KotlinTypeMarker) =
AbstractTypeChecker.isSubtypeOf(this as AbstractTypeCheckerContext, subType, superType)
private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) {
fun correctSubType(subType: SimpleType) =
subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError || subType.isIntegerLiteralType
private fun assertInputTypes(subType: KotlinTypeMarker, superType: KotlinTypeMarker) {
fun correctSubType(subType: SimpleTypeMarker) =
subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || isMyTypeVariable(subType) || subType.isError() || subType.isIntegerLiteralType()
fun correctSuperType(superType: SimpleType) =
superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError || superType.isIntegerLiteralType
fun correctSuperType(superType: SimpleTypeMarker) =
superType.isSingleClassifierType() || superType.typeConstructor().isIntersection() || isMyTypeVariable(superType) || superType.isError() || superType.isIntegerLiteralType()
assert(subType.bothBounds(::correctSubType)) {
"Not singleClassifierType and not intersection subType: $subType"
@@ -254,13 +256,15 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
}
}
private inline fun UnwrappedType.bothBounds(f: (SimpleType) -> Boolean) = when (this) {
is SimpleType -> f(this)
is FlexibleType -> f(lowerBound) && f(upperBound)
private inline fun KotlinTypeMarker.bothBounds(f: (SimpleTypeMarker) -> Boolean) = when (this) {
is SimpleTypeMarker -> f(this)
is FlexibleTypeMarker -> f(lowerBound()) && f(upperBound())
else -> error("sealed")
}
private inline fun UnwrappedType.anyBound(f: (SimpleType) -> Boolean) = when (this) {
is SimpleType -> f(this)
is FlexibleType -> f(lowerBound) || f(upperBound)
private inline fun KotlinTypeMarker.anyBound(f: (SimpleTypeMarker) -> Boolean) = when (this) {
is SimpleTypeMarker -> f(this)
is FlexibleTypeMarker -> f(lowerBound()) || f(upperBound())
else -> error("sealed")
}
}
@@ -7,13 +7,9 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
@@ -24,130 +20,161 @@ class ConstraintIncorporator(
val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
) {
interface Context {
interface Context : TypeSystemInferenceExtensionContext {
val allTypeVariablesWithConstraints: Collection<VariableWithConstraints>
// if such type variable is fixed then it is error
fun getTypeVariable(typeConstructor: TypeConstructor): NewTypeVariable?
fun getTypeVariable(typeConstructor: TypeConstructorMarker): TypeVariableMarker?
fun getConstraintsForVariable(typeVariable: NewTypeVariable): Collection<Constraint>
fun getConstraintsForVariable(typeVariable: TypeVariableMarker): Collection<Constraint>
fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType)
fun addNewIncorporatedConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker)
}
// \alpha is typeVariable, \beta -- other type variable registered in ConstraintStorage
fun incorporate(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
fun incorporate(c: Context, typeVariable: TypeVariableMarker, constraint: Constraint) {
// we shouldn't incorporate recursive constraint -- It is too dangerous
if (constraint.type.contains { it.constructor == typeVariable.freshTypeConstructor }) return
with(c) {
if (constraint.type.contains { it.typeConstructor() == typeVariable.freshTypeConstructor() }) return
}
directWithVariable(c, typeVariable, constraint)
otherInsideMyConstraint(c, typeVariable, constraint)
insideOtherConstraint(c, typeVariable, constraint)
c.directWithVariable(typeVariable, constraint)
c.otherInsideMyConstraint(typeVariable, constraint)
c.insideOtherConstraint(typeVariable, constraint)
}
// A <:(=) \alpha <:(=) B => A <: B
private fun directWithVariable(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
private fun Context.directWithVariable(
typeVariable: TypeVariableMarker,
constraint: Constraint
) {
// \alpha <: constraint.type
if (constraint.kind != ConstraintKind.LOWER) {
c.getConstraintsForVariable(typeVariable).forEach {
getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.UPPER) {
c.addNewIncorporatedConstraint(it.type, constraint.type)
addNewIncorporatedConstraint(it.type, constraint.type)
}
}
}
// constraint.type <: \alpha
if (constraint.kind != ConstraintKind.UPPER) {
c.getConstraintsForVariable(typeVariable).forEach {
getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.LOWER) {
c.addNewIncorporatedConstraint(constraint.type, it.type)
addNewIncorporatedConstraint(constraint.type, it.type)
}
}
}
}
// \alpha <: Inv<\beta>, \beta <: Number => \alpha <: Inv<out Number>
private fun otherInsideMyConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
val otherInMyConstraint = SmartSet.create<NewTypeVariable>()
private fun Context.otherInsideMyConstraint(
typeVariable: TypeVariableMarker,
constraint: Constraint
) {
val otherInMyConstraint = SmartSet.create<TypeVariableMarker>()
constraint.type.contains {
otherInMyConstraint.addIfNotNull(c.getTypeVariable(it.constructor))
otherInMyConstraint.addIfNotNull(this.getTypeVariable(it.typeConstructor()))
false
}
for (otherTypeVariable in otherInMyConstraint) {
// to avoid ConcurrentModificationException
val otherConstraints = ArrayList(c.getConstraintsForVariable(otherTypeVariable))
val otherConstraints = ArrayList(this.getConstraintsForVariable(otherTypeVariable))
for (otherConstraint in otherConstraints) {
generateNewConstraint(c, typeVariable, constraint, otherTypeVariable, otherConstraint)
generateNewConstraint(typeVariable, constraint, otherTypeVariable, otherConstraint)
}
}
}
// \alpha <: Number, \beta <: Inv<\alpha> => \beta <: Inv<out Number>
private fun insideOtherConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
for (typeVariableWithConstraint in c.allTypeVariablesWithConstraints) {
private fun Context.insideOtherConstraint(
typeVariable: TypeVariableMarker,
constraint: Constraint
) {
for (typeVariableWithConstraint in this@insideOtherConstraint.allTypeVariablesWithConstraints) {
val constraintsWhichConstraintMyVariable = typeVariableWithConstraint.constraints.filter {
it.type.contains { it.constructor == typeVariable.freshTypeConstructor }
it.type.contains { it.typeConstructor() == typeVariable.freshTypeConstructor() }
}
constraintsWhichConstraintMyVariable.forEach {
generateNewConstraint(c, typeVariableWithConstraint.typeVariable, it, typeVariable, constraint)
generateNewConstraint(typeVariableWithConstraint.typeVariable, it, typeVariable, constraint)
}
}
}
private fun generateNewConstraint(
c: Context,
targetVariable: NewTypeVariable,
private fun Context.generateNewConstraint(
targetVariable: TypeVariableMarker,
baseConstraint: Constraint,
otherVariable: NewTypeVariable,
otherVariable: TypeVariableMarker,
otherConstraint: Constraint
) {
val baseConstraintType = baseConstraint.type
val typeForApproximation = when (otherConstraint.kind) {
ConstraintKind.EQUALITY -> {
baseConstraintType.substituteTypeVariable(otherVariable, otherConstraint.type)
baseConstraintType.substitute(this, otherVariable, otherConstraint.type)
}
ConstraintKind.UPPER -> {
val newCapturedTypeConstructor = NewCapturedTypeConstructor(
TypeProjectionImpl(Variance.OUT_VARIANCE, otherConstraint.type),
listOf(otherConstraint.type)
val temporaryCapturedType = createCapturedType(
createTypeArgument(otherConstraint.type, TypeVariance.OUT),
listOf(otherConstraint.type),
null,
CaptureStatus.FOR_INCORPORATION
)
val temporaryCapturedType = NewCapturedType(
CaptureStatus.FOR_INCORPORATION,
newCapturedTypeConstructor,
lowerType = null
)
baseConstraintType.substituteTypeVariable(otherVariable, temporaryCapturedType)
// val newCapturedTypeConstructor = NewCapturedTypeConstructor(
// TypeProjectionImpl(Variance.OUT_VARIANCE, otherConstraint.type),
// listOf(otherConstraint.type)
// )
// val temporaryCapturedType = NewCapturedType(
// CaptureStatus.FOR_INCORPORATION,
// newCapturedTypeConstructor,
// lowerType = null
// )
baseConstraintType.substitute(this, otherVariable, temporaryCapturedType)
}
ConstraintKind.LOWER -> {
val newCapturedTypeConstructor = NewCapturedTypeConstructor(
TypeProjectionImpl(Variance.IN_VARIANCE, otherConstraint.type),
emptyList()
val temporaryCapturedType = createCapturedType(
createTypeArgument(otherConstraint.type, TypeVariance.IN),
emptyList(),
otherConstraint.type,
CaptureStatus.FOR_INCORPORATION
)
val temporaryCapturedType = NewCapturedType(
CaptureStatus.FOR_INCORPORATION,
newCapturedTypeConstructor,
lowerType = otherConstraint.type
)
baseConstraintType.substituteTypeVariable(otherVariable, temporaryCapturedType)
// val newCapturedTypeConstructor = NewCapturedTypeConstructor(
// TypeProjectionImpl(Variance.IN_VARIANCE, otherConstraint.type),
// emptyList()
// )
// val temporaryCapturedType = NewCapturedType(
// CaptureStatus.FOR_INCORPORATION,
// newCapturedTypeConstructor,
// lowerType = otherConstraint.type
// )
baseConstraintType.substitute(this, otherVariable, temporaryCapturedType)
}
}
if (baseConstraint.kind != ConstraintKind.UPPER) {
val generatedConstraintType = approximateCapturedTypes(typeForApproximation, toSuper = false)
if (!trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(otherConstraint, generatedConstraintType)) {
c.addNewIncorporatedConstraint(generatedConstraintType, targetVariable.defaultType)
addNewIncorporatedConstraint(generatedConstraintType, targetVariable.defaultType())
}
}
if (baseConstraint.kind != ConstraintKind.LOWER) {
val generatedConstraintType = approximateCapturedTypes(typeForApproximation, toSuper = true)
if (!trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(otherConstraint, generatedConstraintType)) {
c.addNewIncorporatedConstraint(targetVariable.defaultType, generatedConstraintType)
addNewIncorporatedConstraint(targetVariable.defaultType(), generatedConstraintType)
}
}
}
private fun approximateCapturedTypes(type: UnwrappedType, toSuper: Boolean): UnwrappedType =
private fun KotlinTypeMarker.substitute(c: Context, typeVariable: TypeVariableMarker, value: KotlinTypeMarker): KotlinTypeMarker {
val substitutor = c.typeSubstitutorByTypeConstructor(mapOf(typeVariable.freshTypeConstructor(c) to value))
return substitutor.safeSubstitute(c, this)
}
private fun approximateCapturedTypes(type: KotlinTypeMarker, toSuper: Boolean): KotlinTypeMarker =
if (toSuper) typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.IncorporationConfiguration) ?: type
else typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.IncorporationConfiguration) ?: type
}
@@ -16,35 +16,31 @@
package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.LOWER
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.UPPER
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
import org.jetbrains.kotlin.types.model.*
import java.util.*
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val typeApproximator: TypeApproximator) {
private val ALLOWED_DEPTH_DELTA_FOR_INCORPORATION = 1
interface Context {
val allTypeVariables: Map<TypeConstructor, NewTypeVariable>
interface Context : TypeSystemInferenceExtensionContext {
val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker>
var maxTypeDepthFromInitialConstraints: Int
val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints>
val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType>
val notFixedTypeVariables: MutableMap<TypeConstructorMarker, MutableVariableWithConstraints>
val fixedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker>
fun addInitialConstraint(initialConstraint: InitialConstraint)
fun addError(error: KotlinCallDiagnostic)
}
fun addInitialSubtypeConstraint(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
fun addInitialSubtypeConstraint(c: Context, lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) {
val initialConstraint = InitialConstraint(lowerType, upperType, UPPER, position)
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
c.addInitialConstraint(initialConstraint)
@@ -53,7 +49,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, incorporationPosition)
}
fun addInitialEqualityConstraint(c: Context, a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) {
fun addInitialEqualityConstraint(c: Context, a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition) {
val initialConstraint = InitialConstraint(a, b, ConstraintKind.EQUALITY, position)
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
c.addInitialConstraint(initialConstraint)
@@ -66,11 +62,11 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
private fun addSubTypeConstraintAndIncorporateIt(
c: Context,
lowerType: UnwrappedType,
upperType: UnwrappedType,
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
incorporatePosition: IncorporationConstraintPosition
) {
val possibleNewConstraints = Stack<Pair<NewTypeVariable, Constraint>>()
val possibleNewConstraints = Stack<Pair<TypeVariableMarker, Constraint>>()
val typeCheckerContext = TypeCheckerContext(c, incorporatePosition, lowerType, upperType, possibleNewConstraints)
typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
@@ -79,7 +75,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
val constraints =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
c.notFixedTypeVariables[typeVariable.freshTypeConstructor(c)] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
constraints.addConstraint(constraint)?.let {
@@ -88,59 +84,71 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
}
}
private fun updateAllowedTypeDepth(c: Context, initialType: UnwrappedType) {
private fun updateAllowedTypeDepth(c: Context, initialType: KotlinTypeMarker) = with(c) {
c.maxTypeDepthFromInitialConstraints = Math.max(c.maxTypeDepthFromInitialConstraints, initialType.typeDepth())
}
private fun Context.shouldWeSkipConstraint(typeVariable: NewTypeVariable, constraint: Constraint): Boolean {
private fun Context.shouldWeSkipConstraint(typeVariable: TypeVariableMarker, constraint: Constraint): Boolean {
assert(constraint.kind != ConstraintKind.EQUALITY)
val constraintType = constraint.type
if (!isAllowedType(constraintType)) return true
if (constraintType.constructor == typeVariable.freshTypeConstructor) {
if (constraintType.lowerIfFlexible().isMarkedNullable && constraint.kind == LOWER) return false // T? <: T
if (constraintType.typeConstructor() == typeVariable.freshTypeConstructor()) {
if (constraintType.lowerBoundIfFlexible().isMarkedNullable() && constraint.kind == LOWER) return false // T? <: T
return true // T <: T(?!)
}
if (constraintType is SimpleType) {
if (constraintType.isSimpleType()) {
if (constraint.kind == UPPER && constraintType.isNullableAny()) return true // T <: Any?
}
return false
}
private fun Context.isAllowedType(type: UnwrappedType) =
private fun Context.isAllowedType(type: KotlinTypeMarker) =
type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
private inner class TypeCheckerContext(
val c: Context,
val position: IncorporationConstraintPosition,
val baseLowerType: UnwrappedType,
val baseUpperType: UnwrappedType,
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>>
) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context {
val baseLowerType: KotlinTypeMarker,
val baseUpperType: KotlinTypeMarker,
val possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>
) : AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c {
fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) {
with(NewKotlinTypeChecker) {
if (!this@TypeCheckerContext.isSubtypeOf(lowerType, upperType)) {
// todo improve error reporting -- add information about base types
c.addError(NewConstraintError(lowerType, upperType, position))
}
val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything)
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
return baseContext.substitutionSupertypePolicy(type)
}
override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean {
return baseContext.areEqualTypeConstructors(a, b)
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return baseContext.prepareType(type)
}
fun runIsSubtypeOf(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) {
if (!AbstractTypeChecker.isSubtypeOf(this@TypeCheckerContext as AbstractTypeCheckerContext, lowerType, upperType)) {
// todo improve error reporting -- add information about base types
c.addError(NewConstraintError(lowerType, upperType, position))
}
}
// from TypeCheckerContextForConstraintSystem
override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor)
// from AbstractTypeCheckerContextForConstraintSystem
override fun isMyTypeVariable(type: SimpleTypeMarker): Boolean = c.allTypeVariables.containsKey(type.typeConstructor())
override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) =
override fun addUpperConstraint(typeVariable: TypeConstructorMarker, superType: KotlinTypeMarker) =
addConstraint(typeVariable, superType, UPPER)
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
override fun addLowerConstraint(typeVariable: TypeConstructorMarker, subType: KotlinTypeMarker) =
addConstraint(typeVariable, subType, LOWER)
private fun isCapturedTypeFromSubtyping(type: UnwrappedType) =
private fun isCapturedTypeFromSubtyping(type: KotlinTypeMarker) =
when ((type as? NewCapturedType)?.captureStatus) {
null, CaptureStatus.FROM_EXPRESSION -> false
CaptureStatus.FOR_SUBTYPING -> true
@@ -148,12 +156,12 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
error("Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint())
}
private fun addConstraint(typeVariableConstructor: TypeConstructor, type: UnwrappedType, kind: ConstraintKind) {
private fun addConstraint(typeVariableConstructor: TypeConstructorMarker, type: KotlinTypeMarker, kind: ConstraintKind) {
val typeVariable = c.allTypeVariables[typeVariableConstructor]
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
var targetType = type
if (targetType.isError) {
if (targetType.isError()) {
c.addError(ConstrainingTypeIsError(typeVariable, targetType, position))
return
}
@@ -163,7 +171,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
if (kind == UPPER) {
val subType =
typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) {
if (subType != null && !subType.typeConstructor().isNothingConstructor()) {
targetType = subType
}
}
@@ -171,7 +179,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
if (kind == LOWER) {
val superType =
typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases
if (superType != null && !superType.typeConstructor().isAnyConstructor()) { // todo rethink error reporting for Any cases
targetType = superType
}
}
@@ -186,7 +194,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
}
// from ConstraintIncorporator.Context
override fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType) {
override fun addNewIncorporatedConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) {
if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
runIsSubtypeOf(lowerType, upperType)
}
@@ -195,7 +203,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
override val allTypeVariablesWithConstraints: Collection<VariableWithConstraints>
get() = c.notFixedTypeVariables.values
override fun getTypeVariable(typeConstructor: TypeConstructor): NewTypeVariable? {
override fun getTypeVariable(typeConstructor: TypeConstructorMarker): TypeVariableMarker? {
val typeVariable = c.allTypeVariables[typeConstructor]
if (typeVariable != null && !c.notFixedTypeVariables.containsKey(typeConstructor)) {
fixedTypeVariable(typeVariable)
@@ -203,11 +211,11 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
return typeVariable
}
override fun getConstraintsForVariable(typeVariable: NewTypeVariable) =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.constraints
override fun getConstraintsForVariable(typeVariable: TypeVariableMarker) =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor()]?.constraints
?: fixedTypeVariable(typeVariable)
fun fixedTypeVariable(variable: NewTypeVariable): Nothing {
fun fixedTypeVariable(variable: TypeVariableMarker): Nothing {
error(
"Type variable $variable should not be fixed!\n" +
renderBaseConstraint()
@@ -11,7 +11,11 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraint
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -25,19 +29,19 @@ class KotlinConstraintSystemCompleter(
}
interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context {
override val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
override val notFixedTypeVariables: Map<TypeConstructorMarker, VariableWithConstraints>
override val postponedTypeVariables: List<NewTypeVariable>
override val postponedTypeVariables: List<TypeVariableMarker>
// type can be proper if it not contains not fixed type variables
fun canBeProper(type: UnwrappedType): Boolean
fun canBeProper(type: KotlinTypeMarker): Boolean
fun containsOnlyFixedOrPostponedVariables(type: UnwrappedType): Boolean
fun containsOnlyFixedOrPostponedVariables(type: KotlinTypeMarker): Boolean
// mutable operations
fun addError(error: KotlinCallDiagnostic)
fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType)
fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker)
}
fun runCompletion(
@@ -157,7 +161,7 @@ class KotlinConstraintSystemCompleter(
c: Context,
collectVariablesFromContext: Boolean,
topLevelAtoms: List<ResolvedAtom>
): List<TypeConstructor> {
): List<TypeConstructorMarker> {
if (collectVariablesFromContext) return c.notFixedTypeVariables.keys.toList()
fun ResolvedAtom.process(to: LinkedHashSet<TypeConstructor>) {
@@ -12,8 +12,9 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.checker.intersectTypes
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
interface NewTypeSubstitutor {
interface NewTypeSubstitutor: TypeSubstitutorMarker {
fun substituteNotNullTypeWithConstructor(constructor: TypeConstructor): UnwrappedType?
fun safeSubstitute(type: UnwrappedType): UnwrappedType = substitute(type, runCapturedChecks = true, keepAnnotation = false) ?: type
@@ -24,33 +24,31 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraint
import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.intersectTypes
import org.jetbrains.kotlin.types.checker.isIntegerLiteralType
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
class ResultTypeResolver(
val typeApproximator: TypeApproximator,
val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
) {
interface Context {
fun isProperType(type: UnwrappedType): Boolean
interface Context : TypeSystemInferenceExtensionContext {
fun isProperType(type: KotlinTypeMarker): Boolean
}
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): UnwrappedType {
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker {
findResultTypeOrNull(c, variableWithConstraints, direction)?.let { return it }
// no proper constraints
return variableWithConstraints.typeVariable.freshTypeConstructor.builtIns.run {
if (direction == ResolveDirection.TO_SUBTYPE) nothingType else nullableAnyType
return run {
if (direction == ResolveDirection.TO_SUBTYPE) c.nothingType() else c.nullableAnyType()
}
}
fun findResultTypeOrNull(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): UnwrappedType? {
fun findResultTypeOrNull(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker? {
findResultIfThereIsEqualsConstraint(c, variableWithConstraints)?.let { return it }
val subType = findSubType(c, variableWithConstraints)
val superType = findSuperType(c, variableWithConstraints)
val subType = c.findSubType(variableWithConstraints)
val superType = c.findSuperType(variableWithConstraints)
val result = if (direction == ResolveDirection.TO_SUBTYPE || direction == ResolveDirection.UNKNOWN) {
c.resultType(subType, superType, variableWithConstraints)
} else {
@@ -61,10 +59,10 @@ class ResultTypeResolver(
}
private fun Context.resultType(
firstCandidate: UnwrappedType?,
secondCandidate: UnwrappedType?,
firstCandidate: KotlinTypeMarker?,
secondCandidate: KotlinTypeMarker?,
variableWithConstraints: VariableWithConstraints
): UnwrappedType? {
): KotlinTypeMarker? {
if (firstCandidate == null || secondCandidate == null) return firstCandidate ?: secondCandidate
if (isSuitableType(firstCandidate, variableWithConstraints)) return firstCandidate
@@ -76,7 +74,7 @@ class ResultTypeResolver(
}
}
private fun Context.isSuitableType(resultType: UnwrappedType, variableWithConstraints: VariableWithConstraints): Boolean {
private fun Context.isSuitableType(resultType: KotlinTypeMarker, variableWithConstraints: VariableWithConstraints): Boolean {
for (constraint in variableWithConstraints.constraints) {
if (!isProperType(constraint.type)) continue
if (!checkConstraint(constraint.type, constraint.kind, resultType)) return false
@@ -87,11 +85,11 @@ class ResultTypeResolver(
return true
}
private fun findSubType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? {
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) }
private fun Context.findSubType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && isProperType(it.type) }
if (lowerConstraints.isNotEmpty()) {
val types = sinkIntegerLiteralTypes(lowerConstraints.map { it.type })
val commonSuperType = NewCommonSuperTypeCalculator.commonSuperType(types)
val commonSuperType = with(NewCommonSuperTypeCalculator) { commonSuperType(types) }
/**
*
* fun <T> Array<out T>.intersect(other: Iterable<T>) {
@@ -119,16 +117,16 @@ class ResultTypeResolver(
return null
}
private fun sinkIntegerLiteralTypes(types: List<UnwrappedType>): List<UnwrappedType> {
private fun Context.sinkIntegerLiteralTypes(types: List<KotlinTypeMarker>): List<KotlinTypeMarker> {
return types.sortedBy { type ->
val containsILT = type.contains { it.unwrap().safeAs<SimpleType>()?.isIntegerLiteralType ?: false }
val containsILT = type.contains { it.asSimpleType()?.isIntegerLiteralType() ?: false }
if (containsILT) 1 else 0
}
}
private fun findSuperType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? {
val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) }
private fun Context.findSuperType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && this@findSuperType.isProperType(it.type) }
if (upperConstraints.isNotEmpty()) {
val upperType = intersectTypes(upperConstraints.map { it.type })
@@ -137,22 +135,22 @@ class ResultTypeResolver(
return null
}
fun findResultIfThereIsEqualsConstraint(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? {
fun findResultIfThereIsEqualsConstraint(c: Context, variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? = with(c) {
val properEqualityConstraints = variableWithConstraints.constraints.filter {
it.kind == ConstraintKind.EQUALITY && c.isProperType(it.type)
}
return representativeFromEqualityConstraints(properEqualityConstraints)
return c.representativeFromEqualityConstraints(properEqualityConstraints)
}
// Discriminate integer literal types as they are less specific than separate integer types (Int, Short...)
private fun representativeFromEqualityConstraints(constraints: List<Constraint>): UnwrappedType? {
private fun Context.representativeFromEqualityConstraints(constraints: List<Constraint>): KotlinTypeMarker? {
if (constraints.isEmpty()) return null
val constraintTypes = constraints.map { it.type }
val nonLiteralTypes = constraintTypes.filter { it.constructor !is IntegerLiteralTypeConstructor }
return nonLiteralTypes.singleBestRepresentative()?.unwrap()
?: constraintTypes.singleBestRepresentative()?.unwrap()
val nonLiteralTypes = constraintTypes.filter { it.typeConstructor() !is IntegerLiteralTypeConstructor }
return nonLiteralTypes.singleBestRepresentative()
?: constraintTypes.singleBestRepresentative()
?: constraintTypes.first() // seems like constraint system has contradiction
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
@@ -31,7 +32,8 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
class SimpleConstraintSystemImpl(constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns) : SimpleConstraintSystem {
val csBuilder: ConstraintSystemBuilder = NewConstraintSystemImpl(constraintInjector, builtIns).getBuilder()
val csBuilder: ConstraintSystemBuilder =
NewConstraintSystemImpl(constraintInjector, ClassicTypeSystemContextForCS(builtIns)).getBuilder()
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor {
val substitutionMap = typeParameters.associate {
@@ -7,26 +7,29 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContextDelegate
class TrivialConstraintTypeInferenceOracle {
class TrivialConstraintTypeInferenceOracle(context: TypeSystemInferenceExtensionContextDelegate) :
TypeSystemInferenceExtensionContext by context {
// The idea is to add knowledge that constraint `Nothing(?) <: T` is quite useless and
// it's totally fine to go and resolve postponed argument without fixation T to Nothing(?).
// In other words, constraint `Nothing(?) <: T` is *not* proper
fun isTrivialConstraint(constraint: Constraint): Boolean {
fun isTrivialConstraint(
constraint: Constraint
): Boolean {
// TODO: probably we also can take into account `T <: Any(?)` constraints
return constraint.kind == ConstraintKind.LOWER && constraint.type.isNothingOrNullableNothing()
return constraint.kind == ConstraintKind.LOWER && constraint.type.typeConstructor().isNothingConstructor()
}
// This function controls the choice between sub and super result type
// Even that Nothing(?) is the most specific type for subtype, it doesn't bring valuable information to the user,
// therefore it is discriminated in favor of supertype
fun isSuitableResultedType(resultType: UnwrappedType): Boolean {
return !resultType.isNothingOrNullableNothing()
fun isSuitableResultedType(
resultType: KotlinTypeMarker
): Boolean {
return !resultType.typeConstructor().isNothingConstructor()
}
// It's possible to generate Nothing-like constraints inside incorporation mechanism:
@@ -36,7 +39,7 @@ class TrivialConstraintTypeInferenceOracle {
// Therefore, here we avoid adding such trivial constraints to have stable constraint system
fun isGeneratedConstraintTrivial(
otherConstraint: Constraint,
generatedConstraintType: UnwrappedType
generatedConstraintType: KotlinTypeMarker
): Boolean {
if (generatedConstraintType.isNothing()) return true
@@ -49,10 +52,13 @@ class TrivialConstraintTypeInferenceOracle {
return false
}
private fun KotlinTypeMarker.isNothingOrNullableNothing(): Boolean =
typeConstructor().isNothingConstructor()
private fun KotlinTypeMarker.containsOnlyNonNullableNothing(): Boolean =
contains { it.isNothing() } && !contains { it.isNullableNothing() }
}
private fun UnwrappedType.isNothingOrNullableNothing(): Boolean =
isNothing() || isNullableNothing()
private fun UnwrappedType.containsOnlyNonNullableNothing(): Boolean =
contains { it.isNothing() } && !contains { it.isNullableNothing() }
@@ -18,24 +18,26 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
import org.jetbrains.kotlin.types.model.freshTypeConstructor
import org.jetbrains.kotlin.utils.SmartSet
class TypeVariableDependencyInformationProvider(
private val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>,
private val notFixedTypeVariables: Map<TypeConstructorMarker, VariableWithConstraints>,
private val postponedKtPrimitives: List<PostponedResolvedAtom>,
private val topLevelType: UnwrappedType?
private val topLevelType: KotlinTypeMarker?,
private val typeSystemContext: TypeSystemInferenceExtensionContext
) {
// not oriented edges
private val constrainEdges: MutableMap<TypeConstructor, MutableSet<TypeConstructor>> = hashMapOf()
private val constrainEdges: MutableMap<TypeConstructorMarker, MutableSet<TypeConstructorMarker>> = hashMapOf()
// oriented edges
private val postponeArgumentsEdges: MutableMap<TypeConstructor, MutableSet<TypeConstructor>> = hashMapOf()
private val postponeArgumentsEdges: MutableMap<TypeConstructorMarker, MutableSet<TypeConstructorMarker>> = hashMapOf()
private val relatedToAllOutputTypes: MutableSet<TypeConstructor> = hashSetOf()
private val relatedToTopLevelType: MutableSet<TypeConstructor> = hashSetOf()
private val relatedToAllOutputTypes: MutableSet<TypeConstructorMarker> = hashSetOf()
private val relatedToTopLevelType: MutableSet<TypeConstructorMarker> = hashSetOf()
init {
computeConstraintEdges()
@@ -44,17 +46,17 @@ class TypeVariableDependencyInformationProvider(
computeRelatedToTopLevelType()
}
fun isVariableRelatedToTopLevelType(variable: TypeConstructor) = relatedToTopLevelType.contains(variable)
fun isVariableRelatedToAnyOutputType(variable: TypeConstructor) = relatedToAllOutputTypes.contains(variable)
fun isVariableRelatedToTopLevelType(variable: TypeConstructorMarker) = relatedToTopLevelType.contains(variable)
fun isVariableRelatedToAnyOutputType(variable: TypeConstructorMarker) = relatedToAllOutputTypes.contains(variable)
private fun computeConstraintEdges() {
fun addConstraintEdge(from: TypeConstructor, to: TypeConstructor) {
fun addConstraintEdge(from: TypeConstructorMarker, to: TypeConstructorMarker) {
constrainEdges.getOrPut(from) { hashSetOf() }.add(to)
constrainEdges.getOrPut(to) { hashSetOf() }.add(from)
}
for (variableWithConstraints in notFixedTypeVariables.values) {
val from = variableWithConstraints.typeVariable.freshTypeConstructor
val from = variableWithConstraints.typeVariable.freshTypeConstructor(typeSystemContext)
for (constraint in variableWithConstraints.constraints) {
constraint.type.forAllMyTypeVariables {
@@ -67,14 +69,14 @@ class TypeVariableDependencyInformationProvider(
}
private fun computePostponeArgumentsEdges() {
fun addPostponeArgumentsEdges(from: TypeConstructor, to: TypeConstructor) {
fun addPostponeArgumentsEdges(from: TypeConstructorMarker, to: TypeConstructorMarker) {
postponeArgumentsEdges.getOrPut(from) { hashSetOf() }.add(to)
}
for (argument in postponedKtPrimitives) {
if (argument.analyzed) continue
val typeVariablesInOutputType = SmartSet.create<TypeConstructor>()
val typeVariablesInOutputType = SmartSet.create<TypeConstructorMarker>()
(argument.outputType ?: continue).forAllMyTypeVariables { typeVariablesInOutputType.add(it) }
if (typeVariablesInOutputType.isEmpty()) continue
@@ -104,18 +106,21 @@ class TypeVariableDependencyInformationProvider(
}
}
private fun isMyTypeVariable(typeConstructor: TypeConstructor) = notFixedTypeVariables.containsKey(typeConstructor)
private fun isMyTypeVariable(typeConstructor: TypeConstructorMarker) = notFixedTypeVariables.containsKey(typeConstructor)
private fun UnwrappedType.forAllMyTypeVariables(action: (TypeConstructor) -> Unit) = this.contains {
if (isMyTypeVariable(it.constructor)) action(it.constructor)
private fun KotlinTypeMarker.forAllMyTypeVariables(action: (TypeConstructorMarker) -> Unit) =
with(typeSystemContext) {
contains {
if (isMyTypeVariable(it.typeConstructor())) action(it.typeConstructor())
false
}
}
false
}
private fun getConstraintEdges(from: TypeConstructor): Set<TypeConstructor> = constrainEdges[from] ?: emptySet()
private fun getPostponeEdges(from: TypeConstructor): Set<TypeConstructor> = postponeArgumentsEdges[from] ?: emptySet()
private fun getConstraintEdges(from: TypeConstructorMarker): Set<TypeConstructorMarker> = constrainEdges[from] ?: emptySet()
private fun getPostponeEdges(from: TypeConstructorMarker): Set<TypeConstructorMarker> = postponeArgumentsEdges[from] ?: emptySet()
private fun addAllRelatedNodes(to: MutableSet<TypeConstructor>, node: TypeConstructor, includePostponedEdges: Boolean) {
private fun addAllRelatedNodes(to: MutableSet<TypeConstructorMarker>, node: TypeConstructorMarker, includePostponedEdges: Boolean) {
if (to.add(node)) {
for (relatedNode in getConstraintEdges(node)) {
addAllRelatedNodes(to, relatedNode, includePostponedEdges)
@@ -20,12 +20,11 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.types.checker.isIntersectionType
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.model.FlexibleTypeMarker
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariance
import org.jetbrains.kotlin.utils.SmartList
@@ -34,7 +33,7 @@ private typealias Variable = VariableWithConstraints
class TypeVariableDirectionCalculator(
private val c: VariableFixationFinder.Context,
private val postponedKtPrimitives: List<PostponedResolvedAtom>,
topLevelType: UnwrappedType
topLevelType: KotlinTypeMarker
) {
enum class ResolveDirection {
TO_SUBTYPE,
@@ -55,7 +54,7 @@ class TypeVariableDirectionCalculator(
fun getDirection(typeVariable: Variable): ResolveDirection =
directions.getOrDefault(typeVariable, ResolveDirection.UNKNOWN)
private fun setupDirections(topReturnType: UnwrappedType) {
private fun setupDirections(topReturnType: KotlinTypeMarker) {
topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
enterToNode(variableWithConstraints, direction)
}
@@ -105,47 +104,54 @@ class TypeVariableDirectionCalculator(
!(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) &&
!(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER)
private fun UnwrappedType.visitType(
private fun KotlinTypeMarker.visitType(
startDirection: ResolveDirection,
action: (variable: Variable, direction: ResolveDirection) -> Unit
) =
when (this) {
is SimpleType -> visitType(startDirection, action)
is FlexibleType -> {
lowerBound.visitType(startDirection, action)
upperBound.visitType(startDirection, action)
) = when (this) {
is SimpleTypeMarker -> visitType(startDirection, action)
is FlexibleTypeMarker -> {
with(c) {
lowerBound().visitType(startDirection, action)
upperBound().visitType(startDirection, action)
}
}
else -> error("?!")
}
private fun SimpleType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) {
if (isIntersectionType) {
constructor.supertypes.forEach {
it.unwrap().visitType(startDirection, action)
private fun SimpleTypeMarker.visitType(
startDirection: ResolveDirection,
action: (variable: Variable, direction: ResolveDirection) -> Unit
): Unit = with(c) {
val constructor = typeConstructor()
if (constructor.isIntersection()) {
constructor.supertypes().forEach {
it.visitType(startDirection, action)
}
return
}
if (arguments.isEmpty()) {
if (argumentsCount() == 0) {
c.notFixedTypeVariables[constructor]?.let {
action(it, startDirection)
}
return
}
val parameters = constructor.parameters
if (parameters.size != arguments.size) return // incorrect type
if (constructor.parametersCount() != argumentsCount()) return // incorrect type
for ((argument, parameter) in arguments.zip(parameters)) {
if (argument.isStarProjection) continue
for (index in 0 until constructor.parametersCount()) {
val parameter = constructor.getParameter(index)
val argument = getArgument(index)
if (argument.isStarProjection()) continue
val variance = NewKotlinTypeChecker.effectiveVariance(parameter.variance, argument.projectionKind) ?: Variance.INVARIANT
val variance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance()) ?: TypeVariance.INV
val innerDirection = when (variance) {
Variance.INVARIANT -> ResolveDirection.UNKNOWN
Variance.OUT_VARIANCE -> startDirection
Variance.IN_VARIANCE -> startDirection.opposite()
TypeVariance.INV -> ResolveDirection.UNKNOWN
TypeVariance.OUT -> startDirection
TypeVariance.IN -> startDirection.opposite()
}
argument.type.unwrap().visitType(innerDirection, action)
argument.getType().visitType(innerDirection, action)
}
}
@@ -20,30 +20,31 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintS
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
import org.jetbrains.kotlin.types.model.TypeVariableMarker
class VariableFixationFinder(
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
) {
interface Context {
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
val postponedTypeVariables: List<NewTypeVariable>
interface Context : TypeSystemInferenceExtensionContext {
val notFixedTypeVariables: Map<TypeConstructorMarker, VariableWithConstraints>
val postponedTypeVariables: List<TypeVariableMarker>
}
data class VariableForFixation(
val variable: TypeConstructor,
val variable: TypeConstructorMarker,
val hasProperConstraint: Boolean,
val hasOnlyTrivialProperConstraint: Boolean = false
)
fun findFirstVariableForFixation(
c: Context,
allTypeVariables: List<TypeConstructor>,
allTypeVariables: List<TypeConstructorMarker>,
postponedKtPrimitives: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode,
topLevelType: UnwrappedType
@@ -59,7 +60,7 @@ class VariableFixationFinder(
}
private fun Context.getTypeVariableReadiness(
variable: TypeConstructor,
variable: TypeConstructorMarker,
dependencyProvider: TypeVariableDependencyInformationProvider
): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) ||
@@ -72,13 +73,13 @@ class VariableFixationFinder(
}
private fun Context.findTypeVariableForFixation(
allTypeVariables: List<TypeConstructor>,
allTypeVariables: List<TypeConstructorMarker>,
postponedArguments: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode,
topLevelType: UnwrappedType
topLevelType: KotlinTypeMarker
): VariableForFixation? {
val dependencyProvider = TypeVariableDependencyInformationProvider(
notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }
notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }, this
)
val candidate = allTypeVariables.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
@@ -94,29 +95,29 @@ class VariableFixationFinder(
}
}
private fun Context.hasDependencyToOtherTypeVariables(typeVariable: TypeConstructor): Boolean {
private fun Context.hasDependencyToOtherTypeVariables(typeVariable: TypeConstructorMarker): Boolean {
for (constraint in notFixedTypeVariables[typeVariable]?.constraints ?: return false) {
if (constraint.type.arguments.isNotEmpty() && constraint.type.contains { notFixedTypeVariables.containsKey(it.constructor) }) {
if (constraint.type.lowerBoundIfFlexible().argumentsCount() != 0 && constraint.type.contains { notFixedTypeVariables.containsKey(it.typeConstructor()) }) {
return true
}
}
return false
}
private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructor): Boolean {
private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean {
return notFixedTypeVariables[variable]?.constraints?.all { constraint ->
val isProperConstraint = isProperArgumentConstraint(constraint)
isProperConstraint && trivialConstraintTypeInferenceOracle.isTrivialConstraint(constraint) || !isProperConstraint
} ?: false
}
private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructor): Boolean =
private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructorMarker): Boolean =
notFixedTypeVariables[variable]?.constraints?.any { isProperArgumentConstraint(it) } ?: false
private fun Context.isProperArgumentConstraint(c: Constraint) =
isProperType(c.type) && c.position.initialConstraint.position !is DeclaredUpperBoundConstraintPosition
private fun Context.isProperType(type: UnwrappedType): Boolean =
!type.contains { notFixedTypeVariables.containsKey(it.constructor) }
private fun Context.isProperType(type: KotlinTypeMarker): Boolean =
!type.contains { notFixedTypeVariables.containsKey(it.typeConstructor()) }
}
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
sealed class ConstraintPosition
@@ -48,7 +50,7 @@ class ReceiverConstraintPosition(val argument: KotlinCallArgument) : ConstraintP
override fun toString() = "Receiver $argument"
}
class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintPosition() {
class FixVariableConstraintPosition(val variable: TypeVariableMarker) : ConstraintPosition() {
override fun toString() = "Fix variable $variable"
}
@@ -88,21 +90,21 @@ abstract class ConstraintSystemCallDiagnostic(applicability: ResolutionCandidate
}
class NewConstraintError(
val lowerType: UnwrappedType,
val upperType: UnwrappedType,
val lowerType: KotlinTypeMarker,
val upperType: KotlinTypeMarker,
val position: IncorporationConstraintPosition
) : ConstraintSystemCallDiagnostic(if (position.from is ReceiverConstraintPosition) INAPPLICABLE_WRONG_RECEIVER else INAPPLICABLE)
class CapturedTypeFromSubtyping(
val typeVariable: NewTypeVariable,
val constraintType: UnwrappedType,
val typeVariable: TypeVariableMarker,
val constraintType: KotlinTypeMarker,
val position: ConstraintPosition
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class NotEnoughInformationForTypeParameter(val typeVariable: NewTypeVariable) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class NotEnoughInformationForTypeParameter(val typeVariable: TypeVariableMarker) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class ConstrainingTypeIsError(
val typeVariable: NewTypeVariable,
val constraintType: UnwrappedType,
val typeVariable: TypeVariableMarker,
val constraintType: KotlinTypeMarker,
val position: IncorporationConstraintPosition
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.resolve.calls.inference.model
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.substitute
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
/**
* Every type variable can be in the following states:
@@ -36,24 +36,24 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
*/
interface ConstraintStorage {
val allTypeVariables: Map<TypeConstructor, NewTypeVariable>
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker>
val notFixedTypeVariables: Map<TypeConstructorMarker, VariableWithConstraints>
val initialConstraints: List<InitialConstraint>
val maxTypeDepthFromInitialConstraints: Int
val errors: List<KotlinCallDiagnostic>
val hasContradiction: Boolean
val fixedTypeVariables: Map<TypeConstructor, UnwrappedType>
val postponedTypeVariables: List<NewTypeVariable>
val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
val postponedTypeVariables: List<TypeVariableMarker>
object Empty : ConstraintStorage {
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() = emptyMap()
override val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints> get() = emptyMap()
override val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker> get() = emptyMap()
override val notFixedTypeVariables: Map<TypeConstructorMarker, VariableWithConstraints> get() = emptyMap()
override val initialConstraints: List<InitialConstraint> get() = emptyList()
override val maxTypeDepthFromInitialConstraints: Int get() = 1
override val errors: List<KotlinCallDiagnostic> get() = emptyList()
override val hasContradiction: Boolean get() = false
override val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> get() = emptyMap()
override val postponedTypeVariables: List<NewTypeVariable> get() = emptyList()
override val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> get() = emptyMap()
override val postponedTypeVariables: List<TypeVariableMarker> get() = emptyList()
}
}
@@ -69,7 +69,7 @@ enum class ConstraintKind {
class Constraint(
val kind: ConstraintKind,
val type: UnwrappedType, // flexible types here is allowed
val type: KotlinTypeMarker, // flexible types here is allowed
val position: IncorporationConstraintPosition,
val typeHashCode: Int = type.hashCode()
) {
@@ -93,13 +93,13 @@ class Constraint(
}
interface VariableWithConstraints {
val typeVariable: NewTypeVariable
val typeVariable: TypeVariableMarker
val constraints: List<Constraint>
}
class InitialConstraint(
val a: UnwrappedType,
val b: UnwrappedType,
val a: KotlinTypeMarker,
val b: KotlinTypeMarker,
val constraintKind: ConstraintKind, // see [checkConstraint]
val position: ConstraintPosition
) {
@@ -114,13 +114,17 @@ class InitialConstraint(
}
}
fun InitialConstraint.checkConstraint(substitutor: TypeSubstitutor): Boolean {
val newA = substitutor.substitute(a)
val newB = substitutor.substitute(a)
return checkConstraint(newB, constraintKind, newA)
}
//fun InitialConstraint.checkConstraint(substitutor: TypeSubstitutor): Boolean {
// val newA = substitutor.substitute(a)
// val newB = substitutor.substitute(b)
// return checkConstraint(newB as KotlinTypeMarker, constraintKind, newA as KotlinTypeMarker)
//}
fun checkConstraint(constraintType: KotlinTypeMarker, constraintKind: ConstraintKind, resultType: KotlinTypeMarker): Boolean {
require(constraintType is UnwrappedType)
require(resultType is UnwrappedType)
fun checkConstraint(constraintType: UnwrappedType, constraintKind: ConstraintKind, resultType: UnwrappedType): Boolean {
val typeChecker = KotlinTypeChecker.DEFAULT
return when (constraintKind) {
ConstraintKind.EQUALITY -> typeChecker.equalTypes(constraintType, resultType)
@@ -11,12 +11,15 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
import kotlin.collections.ArrayList
import kotlin.collections.LinkedHashMap
class MutableVariableWithConstraints(
override val typeVariable: NewTypeVariable,
override val typeVariable: TypeVariableMarker,
constraints: Collection<Constraint> = emptyList()
) : VariableWithConstraints {
override val constraints: List<Constraint>
@@ -89,12 +92,12 @@ class MutableVariableWithConstraints(
internal class MutableConstraintStorage : ConstraintStorage {
override val allTypeVariables: MutableMap<TypeConstructor, NewTypeVariable> = LinkedHashMap()
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints> = LinkedHashMap()
override val allTypeVariables: MutableMap<TypeConstructorMarker, TypeVariableMarker> = LinkedHashMap()
override val notFixedTypeVariables: MutableMap<TypeConstructorMarker, MutableVariableWithConstraints> = LinkedHashMap()
override val initialConstraints: MutableList<InitialConstraint> = ArrayList()
override var maxTypeDepthFromInitialConstraints: Int = 1
override val errors: MutableList<KotlinCallDiagnostic> = ArrayList()
override val hasContradiction: Boolean get() = errors.any { !it.candidateApplicability.isSuccess }
override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType> = LinkedHashMap()
override val postponedTypeVariables: ArrayList<NewTypeVariable> = ArrayList()
override val fixedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker> = LinkedHashMap()
override val postponedTypeVariables: ArrayList<TypeVariableMarker> = ArrayList()
}
@@ -6,24 +6,28 @@
package org.jetbrains.kotlin.resolve.calls.inference.model
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.components.BuiltInsProvider
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.*
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.components.*
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.cast
class NewConstraintSystemImpl(
private val constraintInjector: ConstraintInjector,
override val builtIns: KotlinBuiltIns
val typeSystemContext: TypeSystemInferenceExtensionContext//,
//override val builtIns: KotlinBuiltIns
) :
TypeSystemInferenceExtensionContext by typeSystemContext,
NewConstraintSystem,
ConstraintSystemBuilder,
ConstraintInjector.Context,
@@ -32,7 +36,7 @@ class NewConstraintSystemImpl(
PostponedArgumentsAnalyzer.Context {
private val storage = MutableConstraintStorage()
private var state = State.BUILDING
private val typeVariablesTransaction: MutableList<NewTypeVariable> = SmartList()
private val typeVariablesTransaction: MutableList<TypeVariableMarker> = SmartList()
private enum class State {
BUILDING,
@@ -63,23 +67,23 @@ class NewConstraintSystemImpl(
override fun asPostponedArgumentsAnalyzerContext() = apply { checkState(State.BUILDING) }
// ConstraintSystemOperation
override fun registerVariable(variable: NewTypeVariable) {
override fun registerVariable(variable: TypeVariableMarker) {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
transactionRegisterVariable(variable)
storage.allTypeVariables[variable.freshTypeConstructor] = variable
storage.notFixedTypeVariables[variable.freshTypeConstructor] = MutableVariableWithConstraints(variable)
storage.allTypeVariables[variable.freshTypeConstructor()] = variable
storage.notFixedTypeVariables[variable.freshTypeConstructor()] = MutableVariableWithConstraints(variable)
}
override fun markPostponedVariable(variable: NewTypeVariable) {
override fun markPostponedVariable(variable: TypeVariableMarker) {
storage.postponedTypeVariables += variable
}
override fun unmarkPostponedVariable(variable: NewTypeVariable) {
override fun unmarkPostponedVariable(variable: TypeVariableMarker) {
storage.postponedTypeVariables -= variable
}
override fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
override fun addSubtypeConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker, position: ConstraintPosition) =
constraintInjector.addInitialSubtypeConstraint(
apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
lowerType,
@@ -87,7 +91,7 @@ class NewConstraintSystemImpl(
position
)
override fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) =
override fun addEqualityConstraint(a: KotlinTypeMarker, b: KotlinTypeMarker, position: ConstraintPosition) =
constraintInjector.addInitialEqualityConstraint(
apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
a,
@@ -95,18 +99,18 @@ class NewConstraintSystemImpl(
position
)
override fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor> {
override fun getProperSuperTypeConstructors(type: KotlinTypeMarker): List<TypeConstructorMarker> {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
val variableWithConstraints = notFixedTypeVariables[type.constructor] ?: return listOf(type.constructor)
val variableWithConstraints = notFixedTypeVariables[type.typeConstructor()] ?: return listOf(type.typeConstructor())
return variableWithConstraints.constraints.mapNotNull {
if (it.kind == ConstraintKind.LOWER) return@mapNotNull null
it.type.constructor.takeUnless { allTypeVariables.containsKey(it) }
it.type.typeConstructor().takeUnless { allTypeVariables.containsKey(it) }
}
}
// ConstraintSystemBuilder
private fun transactionRegisterVariable(variable: NewTypeVariable) {
private fun transactionRegisterVariable(variable: TypeVariableMarker) {
if (state != State.TRANSACTION) return
typeVariablesTransaction.add(variable)
}
@@ -132,8 +136,8 @@ class NewConstraintSystemImpl(
}
for (addedTypeVariable in typeVariablesTransaction) {
storage.allTypeVariables.remove(addedTypeVariable.freshTypeConstructor)
storage.notFixedTypeVariables.remove(addedTypeVariable.freshTypeConstructor)
storage.allTypeVariables.remove(addedTypeVariable.freshTypeConstructor())
storage.notFixedTypeVariables.remove(addedTypeVariable.freshTypeConstructor())
}
storage.maxTypeDepthFromInitialConstraints = beforeMaxTypeDepthFromInitialConstraints
storage.errors.trimToSize(beforeErrorsCount)
@@ -169,32 +173,32 @@ class NewConstraintSystemImpl(
}
storage.initialConstraints.addAll(otherSystem.initialConstraints)
storage.maxTypeDepthFromInitialConstraints =
Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints)
Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints)
storage.errors.addAll(otherSystem.errors)
storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables)
storage.postponedTypeVariables.addAll(otherSystem.postponedTypeVariables)
}
// ResultTypeResolver.Context, ConstraintSystemBuilder
override fun isProperType(type: UnwrappedType): Boolean {
override fun isProperType(type: KotlinTypeMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return !type.contains {
storage.allTypeVariables.containsKey(it.constructor)
storage.allTypeVariables.containsKey(it.typeConstructor())
}
}
override fun isTypeVariable(type: UnwrappedType): Boolean {
override fun isTypeVariable(type: KotlinTypeMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return notFixedTypeVariables.containsKey(type.constructor)
return notFixedTypeVariables.containsKey(type.typeConstructor())
}
override fun isPostponedTypeVariable(typeVariable: NewTypeVariable): Boolean {
override fun isPostponedTypeVariable(typeVariable: TypeVariableMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return typeVariable in postponedTypeVariables
}
// ConstraintInjector.Context
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable>
override val allTypeVariables: Map<TypeConstructorMarker, TypeVariableMarker>
get() {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return storage.allTypeVariables
@@ -213,19 +217,19 @@ class NewConstraintSystemImpl(
}
// ConstraintInjector.Context, FixationOrderCalculator.Context
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints>
override val notFixedTypeVariables: MutableMap<TypeConstructorMarker, MutableVariableWithConstraints>
get() {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return storage.notFixedTypeVariables
}
override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType>
override val fixedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker>
get() {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return storage.fixedTypeVariables
}
override val postponedTypeVariables: List<NewTypeVariable>
override val postponedTypeVariables: List<TypeVariableMarker>
get() {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
return storage.postponedTypeVariables
@@ -238,32 +242,32 @@ class NewConstraintSystemImpl(
}
// KotlinConstraintSystemCompleter.Context
override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) {
override fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker) {
checkState(State.BUILDING, State.COMPLETION)
constraintInjector.addInitialEqualityConstraint(this, variable.defaultType, resultType, FixVariableConstraintPosition(variable))
notFixedTypeVariables.remove(variable.freshTypeConstructor)
constraintInjector.addInitialEqualityConstraint(this, variable.defaultType(), resultType, FixVariableConstraintPosition(variable))
notFixedTypeVariables.remove(variable.freshTypeConstructor())
for (variableWithConstraint in notFixedTypeVariables.values) {
variableWithConstraint.removeConstrains {
it.type.contains { it.constructor == variable.freshTypeConstructor }
it.type.contains { it.typeConstructor() == variable.freshTypeConstructor() }
}
}
storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType
storage.fixedTypeVariables[variable.freshTypeConstructor()] = resultType
}
// KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context
override fun canBeProper(type: UnwrappedType): Boolean {
override fun canBeProper(type: KotlinTypeMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION)
return !type.contains { storage.notFixedTypeVariables.containsKey(it.constructor) }
return !type.contains { storage.notFixedTypeVariables.containsKey(it.typeConstructor()) }
}
override fun containsOnlyFixedOrPostponedVariables(type: UnwrappedType): Boolean {
override fun containsOnlyFixedOrPostponedVariables(type: KotlinTypeMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION)
return !type.contains {
val variable = storage.notFixedTypeVariables[it.constructor]?.typeVariable
variable !in storage.postponedTypeVariables && storage.notFixedTypeVariables.containsKey(it.constructor)
val variable = storage.notFixedTypeVariables[it.typeConstructor()]?.typeVariable
variable !in storage.postponedTypeVariables && storage.notFixedTypeVariables.containsKey(it.typeConstructor())
}
}
@@ -273,14 +277,15 @@ class NewConstraintSystemImpl(
return buildCurrentSubstitutor(emptyMap())
}
override fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructor, StubType>): NewTypeSubstitutor {
override fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>): NewTypeSubstitutor {
checkState(State.BUILDING, State.COMPLETION)
return storage.buildCurrentSubstitutor(additionalBindings)
}
override fun bindingStubsForPostponedVariables(): Map<NewTypeVariable, StubType> {
override fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker> {
checkState(State.BUILDING, State.COMPLETION)
return storage.postponedTypeVariables.associate { it to StubType(it.freshTypeConstructor, it.defaultType.isMarkedNullable) }
// TODO: SUB
return storage.postponedTypeVariables.associate { it to createStubType(it)/*StubType(it.freshTypeConstructor() as TypeConstructor, it.defaultType().isMarkedNullable())*/ }
}
override fun currentStorage(): ConstraintStorage {
@@ -289,10 +294,10 @@ class NewConstraintSystemImpl(
}
// PostponedArgumentsAnalyzer.Context
override fun hasUpperOrEqualUnitConstraint(type: UnwrappedType): Boolean {
override fun hasUpperOrEqualUnitConstraint(type: KotlinTypeMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION, State.FREEZED)
val constraints = storage.notFixedTypeVariables[type.constructor]?.constraints ?: return false
val constraints = storage.notFixedTypeVariables[type.typeConstructor()]?.constraints ?: return false
return constraints.any { (it.kind == ConstraintKind.UPPER || it.kind == ConstraintKind.EQUALITY) && it.type.isUnit() }
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
import org.jetbrains.kotlin.types.model.TypeVariableMarker
class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debugName: String) : TypeConstructor,
@@ -42,7 +43,7 @@ class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debu
override fun toString() = "TypeVariable($debugName)"
}
sealed class NewTypeVariable(builtIns: KotlinBuiltIns, name: String) {
sealed class NewTypeVariable(builtIns: KotlinBuiltIns, name: String) : TypeVariableMarker {
val freshTypeConstructor: TypeConstructor = TypeVariableTypeConstructor(builtIns, name)
// member scope is used if we have receiver with type TypeVariable(T)
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.calls.components.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
@@ -27,7 +28,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImp
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.UnwrappedType
abstract class ResolutionPart {
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCa
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject
import org.jetbrains.kotlin.resolve.calls.util.isLowPriorityFromStdlibJre7Or8
import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST
import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.hasHidesMembersAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
@@ -135,7 +132,7 @@ internal class MemberScopeTowerLevel(
private fun CallableDescriptor.approximateCapturedTypes(): CallableDescriptor {
if (!isNewInferenceEnabled) return this
val approximator = TypeApproximator()
val approximator = TypeApproximator(builtIns)
val wrappedSubstitution = object : TypeSubstitution() {
override fun get(key: KotlinType): TypeProjection? = null
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = when (position) {
@@ -16,19 +16,19 @@
package org.jetbrains.kotlin.types
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
import org.jetbrains.kotlin.types.checker.*
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.model.CaptureStatus.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
open class TypeApproximatorConfiguration {
@@ -89,10 +89,8 @@ open class TypeApproximatorConfiguration {
}
}
class TypeApproximator {
private val referenceApproximateToSuperType = this::approximateSimpleToSuperType
private val referenceApproximateToSubType = this::approximateSimpleToSubType
class TypeApproximator(builtIns: KotlinBuiltIns) : AbstractTypeApproximator(ClassicTypeSystemContextForCS(builtIns)) {
fun approximateDeclarationType(baseType: KotlinType, local: Boolean, languageVersionSettings: LanguageVersionSettings): UnwrappedType {
if (!languageVersionSettings.supportsFeature(LanguageFeature.NewInference)) return baseType.unwrap()
@@ -103,49 +101,68 @@ class TypeApproximator {
// null means that this input type is the result, i.e. input type not contains not-allowed kind of types
// type <: resultType
fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? =
approximateToSuperType(type, conf, -type.typeDepth())
super.approximateToSuperType(type, conf) as UnwrappedType?
// resultType <: type
fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? =
super.approximateToSubType(type, conf) as UnwrappedType?
}
abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionContext) : TypeSystemInferenceExtensionContext by ctx {
private val referenceApproximateToSuperType = this::approximateSimpleToSuperType
private val referenceApproximateToSubType = this::approximateSimpleToSubType
// null means that this input type is the result, i.e. input type not contains not-allowed kind of types
// type <: resultType
fun approximateToSuperType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration): KotlinTypeMarker? =
approximateToSuperType(type, conf, -type.typeDepth())
// resultType <: type
fun approximateToSubType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration): KotlinTypeMarker? =
approximateToSubType(type, conf, -type.typeDepth())
private fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration, depth: Int): UnwrappedType? {
private fun approximateToSuperType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration, depth: Int): KotlinTypeMarker? {
if (type is TypeUtils.SpecialType) return null
return approximateTo(
NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::upperBound,
prepareType(type), conf, { upperBound() },
referenceApproximateToSuperType, depth
)
}
private fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration, depth: Int): UnwrappedType? {
private fun approximateToSubType(type: KotlinTypeMarker, conf: TypeApproximatorConfiguration, depth: Int): KotlinTypeMarker? {
if (type is TypeUtils.SpecialType) return null
return approximateTo(
NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::lowerBound,
prepareType(type), conf, { lowerBound() },
referenceApproximateToSubType, depth
)
}
// comments for case bound = upperBound, approximateTo = toSuperType
private fun approximateTo(
type: UnwrappedType,
type: KotlinTypeMarker,
conf: TypeApproximatorConfiguration,
bound: FlexibleType.() -> SimpleType,
approximateTo: (SimpleType, TypeApproximatorConfiguration, depth: Int) -> UnwrappedType?,
bound: FlexibleTypeMarker.() -> SimpleTypeMarker,
approximateTo: (SimpleTypeMarker, TypeApproximatorConfiguration, depth: Int) -> KotlinTypeMarker?,
depth: Int
): UnwrappedType? {
): KotlinTypeMarker? {
when (type) {
is SimpleType -> return approximateTo(type, conf, depth)
is FlexibleType -> {
if (type is DynamicType) {
is SimpleTypeMarker -> return approximateTo(type, conf, depth)
is FlexibleTypeMarker -> {
if (type.isDynamic()) {
return if (conf.dynamic) null else type.bound()
} else if (type is RawType) {
} else if (type.asRawType() != null) {
return if (conf.rawType) null else type.bound()
}
// TODO: currently we can lose information about enhancement, should be fixed later
assert(type is FlexibleTypeImpl || type is FlexibleTypeWithEnhancement) {
"Unexpected subclass of FlexibleType: ${type::class.java.canonicalName}, type = $type"
}
// TODO: Restore check
// // TODO: currently we can lose information about enhancement, should be fixed later
// assert(type is FlexibleTypeImpl || type is FlexibleTypeWithEnhancement) {
// "Unexpected subclass of FlexibleType: ${type::class.java.canonicalName}, type = $type"
// }
if (conf.flexible) {
/**
@@ -158,8 +175,8 @@ class TypeApproximator {
* I.e. for every type B such as L_2 <: B, L_1 <: B. For example B = L_2.
*/
val lowerResult = approximateTo(type.lowerBound, conf, depth)
val upperResult = approximateTo(type.upperBound, conf, depth)
val lowerResult = approximateTo(type.lowerBound(), conf, depth)
val upperResult = approximateTo(type.upperBound(), conf, depth)
if (lowerResult == null && upperResult == null) return null
/**
@@ -169,38 +186,39 @@ class TypeApproximator {
*
* If U_1 <: U_2.lower .. U_2.upper, then we know only that U_1 <: U_2.upper.
*/
return KotlinTypeFactory.flexibleType(
lowerResult?.lowerIfFlexible() ?: type.lowerBound,
upperResult?.upperIfFlexible() ?: type.upperBound
return createFlexibleType(
lowerResult?.lowerBoundIfFlexible() ?: type.lowerBound(),
upperResult?.upperBoundIfFlexible() ?: type.upperBound()
)
} else {
return type.bound().let { approximateTo(it, conf, depth) ?: it }
}
}
else -> error("sealed")
}
}
private fun approximateIntersectionType(
type: SimpleType,
type: SimpleTypeMarker,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): UnwrappedType? {
val typeConstructor = type.constructor
assert(typeConstructor is IntersectionTypeConstructor) {
): KotlinTypeMarker? {
val typeConstructor = type.typeConstructor()
assert(typeConstructor.isIntersection()) {
"Should be intersection type: $type, typeConstructor class: ${typeConstructor::class.java.canonicalName}"
}
assert(typeConstructor.supertypes.isNotEmpty()) {
assert(typeConstructor.supertypes().isNotEmpty()) {
"Supertypes for intersection type should not be empty: $type"
}
var thereIsApproximation = false
val newTypes = typeConstructor.supertypes.map {
val newType = if (toSuper) approximateToSuperType(it.unwrap(), conf, depth) else approximateToSubType(it.unwrap(), conf, depth)
val newTypes = typeConstructor.supertypes().map {
val newType = if (toSuper) approximateToSuperType(it, conf, depth) else approximateToSubType(it, conf, depth)
if (newType != null) {
thereIsApproximation = true
newType
} else it.unwrap()
} else it
}
/**
@@ -215,12 +233,12 @@ class TypeApproximator {
// commonSupertypeCalculator should handle flexible types correctly
TO_COMMON_SUPERTYPE -> {
if (!toSuper) return type.defaultResult(toSuper = false)
val resultType = NewCommonSuperTypeCalculator.commonSuperType(newTypes)
approximateToSuperType(resultType.unwrap(), conf) ?: resultType.unwrap()
val resultType = with(NewCommonSuperTypeCalculator) { commonSuperType(newTypes) }
approximateToSuperType(resultType, conf) ?: resultType
}
}
return if (type.isMarkedNullable) baseResult.makeNullableAsSpecified(true) else baseResult
return if (type.isMarkedNullable()) baseResult.withNullability(true) else baseResult
}
private fun approximateCapturedType(
@@ -228,30 +246,30 @@ class TypeApproximator {
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): UnwrappedType? {
val supertypes = type.constructor.supertypes
): KotlinTypeMarker? {
val supertypes = type.typeConstructor().supertypes()
val baseSuperType = when (supertypes.size) {
0 -> type.builtIns.nullableAnyType // Let C = in Int, then superType for C and C? is Any?
1 -> supertypes.single()
// Consider the following example:
// A.getA()::class.java, where `getA()` returns some class from Java
// From `::class` we are getting type KClass<Cap<out A!>>, where Cap<out A!> have two supertypes:
// - Any (from declared upper bound of type parameter for KClass)
// - (A..A?) -- from A!, projection type of captured type
// Consider the following example:
// A.getA()::class.java, where `getA()` returns some class from Java
// From `::class` we are getting type KClass<Cap<out A!>>, where Cap<out A!> have two supertypes:
// - Any (from declared upper bound of type parameter for KClass)
// - (A..A?) -- from A!, projection type of captured type
// Now, after approximation we were getting type `KClass<out A>`, because { Any & (A..A?) } = A,
// but in old inference type was equal to `KClass<out A!>`.
// Now, after approximation we were getting type `KClass<out A>`, because { Any & (A..A?) } = A,
// but in old inference type was equal to `KClass<out A!>`.
// Important note that from the point of type system first type is more specific:
// Here, approximation of KClass<Cap<out A!>> is a type KClass<T> such that KClass<Cap<out A!>> <: KClass<out T> =>
// So, the the more specific type for T would be "some non-null (because of declared upper bound type) subtype of A", which is `out A`
// Important note that from the point of type system first type is more specific:
// Here, approximation of KClass<Cap<out A!>> is a type KClass<T> such that KClass<Cap<out A!>> <: KClass<out T> =>
// So, the the more specific type for T would be "some non-null (because of declared upper bound type) subtype of A", which is `out A`
// But for now, to reduce differences in behaviour of old and new inference, we'll approximate such types to `KClass<out A!>`
// But for now, to reduce differences in behaviour of old and new inference, we'll approximate such types to `KClass<out A!>`
// Once NI will be more stabilized, we'll use more specific type
// Once NI will be more stabilized, we'll use more specific type
else -> type.constructor.projection.type.unwrap()
else -> type.typeConstructorProjection().getType()//.unwrap()
}
val baseSubType = type.lowerType ?: type.builtIns.nothingType
@@ -276,32 +294,38 @@ class TypeApproximator {
// C = in Int, Int <: C => Int? <: C?
// C = out Number, C <: Number => C? <: Number?
return if (type.isMarkedNullable) baseResult.makeNullableAsSpecified(true) else baseResult
return if (type.isMarkedNullable) baseResult.withNullability(true) else baseResult
}
private fun approximateSimpleToSuperType(type: SimpleType, conf: TypeApproximatorConfiguration, depth: Int) =
private fun approximateSimpleToSuperType(type: SimpleTypeMarker, conf: TypeApproximatorConfiguration, depth: Int) =
approximateTo(type, conf, toSuper = true, depth = depth)
private fun approximateSimpleToSubType(type: SimpleType, conf: TypeApproximatorConfiguration, depth: Int) =
private fun approximateSimpleToSubType(type: SimpleTypeMarker, conf: TypeApproximatorConfiguration, depth: Int) =
approximateTo(type, conf, toSuper = false, depth = depth)
private fun approximateTo(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean, depth: Int): UnwrappedType? {
if (type.isError) {
private fun approximateTo(
type: SimpleTypeMarker,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): KotlinTypeMarker? {
if (type.isError()) {
// todo -- fix builtIns. Now builtIns here is DefaultBuiltIns
return if (conf.errorType) null else type.defaultResult(toSuper)
}
if (depth > 3) return type.defaultResult(toSuper)
if (type.arguments.isNotEmpty()) {
if (type.argumentsCount() != 0) {
return approximateParametrizedType(type, conf, toSuper, depth + 1)
}
if (type is DefinitelyNotNullType) {
return approximateDefinitelyNotNullType(type, conf, toSuper, depth)
val definitelyNotNullType = type.asDefinitelyNotNullType()
if (definitelyNotNullType != null) {
return approximateDefinitelyNotNullType(definitelyNotNullType, conf, toSuper, depth)
}
val typeConstructor = type.constructor
val typeConstructor = type.typeConstructor()
if (typeConstructor is NewCapturedTypeConstructor) {
assert(type is NewCapturedType) {
@@ -312,7 +336,7 @@ class TypeApproximator {
return approximateCapturedType(type as NewCapturedType, conf, toSuper, depth)
}
if (typeConstructor is IntersectionTypeConstructor) {
if (typeConstructor.isIntersection()) {
return approximateIntersectionType(type, conf, toSuper, depth)
}
@@ -320,9 +344,9 @@ class TypeApproximator {
return if (conf.typeVariable(typeConstructor)) null else type.defaultResult(toSuper)
}
if (typeConstructor is IntegerLiteralTypeConstructor) {
if (typeConstructor.isIntegerLiteralTypeConstructor()) {
return if (conf.integerLiteralType)
typeConstructor.getApproximatedType().unwrap().makeNullableAsSpecified(type.isMarkedNullable)
typeConstructor.getApproximatedIntegerLiteralType().withNullability(type.isMarkedNullable())
else
null
}
@@ -331,63 +355,64 @@ class TypeApproximator {
}
private fun approximateDefinitelyNotNullType(
type: DefinitelyNotNullType,
type: DefinitelyNotNullTypeMarker,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): UnwrappedType? {
val approximatedOriginalType = approximateTo(type.original, conf, toSuper, depth)
): KotlinTypeMarker? {
val approximatedOriginalType = approximateTo(type.original(), conf, toSuper, depth)
return if (conf.definitelyNotNullType) {
approximatedOriginalType?.makeDefinitelyNotNullOrNotNull()
} else {
if (toSuper)
(approximatedOriginalType ?: type.original).makeNullableAsSpecified(false)
(approximatedOriginalType ?: type.original()).withNullability(false)
else
type.defaultResult(toSuper)
}
}
private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) =
private fun isApproximateDirectionToSuper(effectiveVariance: TypeVariance, toSuper: Boolean) =
when (effectiveVariance) {
Variance.OUT_VARIANCE -> toSuper
Variance.IN_VARIANCE -> !toSuper
Variance.INVARIANT -> throw AssertionError("Incorrect variance $effectiveVariance")
TypeVariance.OUT -> toSuper
TypeVariance.IN -> !toSuper
TypeVariance.INV -> throw AssertionError("Incorrect variance $effectiveVariance")
}
private fun approximateParametrizedType(
type: SimpleType,
type: SimpleTypeMarker,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): SimpleType? {
val parameters = type.constructor.parameters
val arguments = type.arguments
if (parameters.size != arguments.size) {
): SimpleTypeMarker? {
val typeConstructor = type.typeConstructor()
// val parameters = type.typeConstructor().parameters
// val arguments = type.arguments
if (typeConstructor.parametersCount() != type.argumentsCount()) {
return if (conf.errorType) {
ErrorUtils.createErrorType("Inconsistent type: $type (parameters.size = ${parameters.size}, arguments.size = ${arguments.size})")
ErrorUtils.createErrorType("Inconsistent type: $type (parameters.size = ${typeConstructor.parametersCount()}, arguments.size = ${type.argumentsCount()})")
} else type.defaultResult(toSuper)
}
val newArguments = arrayOfNulls<TypeProjection?>(arguments.size)
val newArguments = arrayOfNulls<TypeArgumentMarker?>(type.argumentsCount())
loop@ for (index in arguments.indices) {
val parameter = parameters[index]
val argument = arguments[index]
loop@ for (index in 0 until type.argumentsCount()) {
val parameter = typeConstructor.getParameter(index)
val argument = type.getArgument(index)
if (argument.isStarProjection) continue
if (argument.isStarProjection()) continue
val argumentType = argument.type.unwrap()
val effectiveVariance = NewKotlinTypeChecker.effectiveVariance(parameter.variance, argument.projectionKind)
val argumentType = argument.getType()//.unwrap()
val effectiveVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
when (effectiveVariance) {
null -> {
return if (conf.errorType) {
ErrorUtils.createErrorType(
"Inconsistent type: $type ($index parameter has declared variance: ${parameter.variance}, " +
"but argument variance is ${argument.projectionKind})"
"Inconsistent type: $type ($index parameter has declared variance: ${parameter.getVariance()}, " +
"but argument variance is ${argument.getVariance()})"
)
} else type.defaultResult(toSuper)
}
Variance.OUT_VARIANCE, Variance.IN_VARIANCE -> {
TypeVariance.OUT, TypeVariance.IN -> {
/**
* Out<Foo> <: Out<superType(Foo)>
* Inv<out Foo> <: Inv<out superType(Foo)>
@@ -403,22 +428,27 @@ class TypeApproximator {
}
} ?: continue@loop
if (parameter.variance == Variance.INVARIANT) {
newArguments[index] = TypeProjectionImpl(effectiveVariance, approximatedArgument)
if (parameter.getVariance() == TypeVariance.INV) {
newArguments[index] = createTypeArgument(approximatedArgument, effectiveVariance)
} else {
newArguments[index] = approximatedArgument.asTypeProjection()
newArguments[index] = approximatedArgument.asTypeArgument()
}
}
Variance.INVARIANT -> {
TypeVariance.INV -> {
if (!toSuper) {
// Inv<Foo> cannot be approximated to subType
val toSubType = approximateToSubType(argumentType, conf, depth) ?: continue@loop
// Inv<Foo!> is supertype for Inv<Foo?>
if (!NewKotlinTypeChecker.equalTypes(argumentType, toSubType)) return type.defaultResult(toSuper)
if (!AbstractTypeChecker.equalTypes(
this,
argumentType,
toSubType
)
) return type.defaultResult(toSuper)
// also Captured(out Nothing) = Nothing
newArguments[index] = toSubType.asTypeProjection()
newArguments[index] = toSubType.asTypeArgument()
continue@loop
}
@@ -433,10 +463,10 @@ class TypeApproximator {
* Note that for case Inv<C> we will chose Inv<in Int>, because it is more informative then Inv<out Any?>.
* May be we should do the same for deeper types, but not now.
*/
if (argumentType.constructor is NewCapturedTypeConstructor) {
if (argumentType.typeConstructor() is NewCapturedTypeConstructor) {
val subType = approximateToSubType(argumentType, conf, depth) ?: continue@loop
if (!subType.isTrivialSub()) {
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, subType)
newArguments[index] = createTypeArgument(subType, TypeVariance.IN)
continue@loop
}
}
@@ -447,15 +477,15 @@ class TypeApproximator {
val approximatedSubType =
approximateToSubType(argumentType, conf, depth) ?: continue@loop // seems like this is never null
if (!approximatedSubType.isTrivialSub()) {
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, approximatedSubType)
newArguments[index] = createTypeArgument(approximatedSubType, TypeVariance.IN)
continue@loop
}
}
if (NewKotlinTypeChecker.equalTypes(argumentType, approximatedSuperType)) {
newArguments[index] = approximatedSuperType.asTypeProjection()
if (AbstractTypeChecker.equalTypes(this, argumentType, approximatedSuperType)) {
newArguments[index] = approximatedSuperType.asTypeArgument()
} else {
newArguments[index] = TypeProjectionImpl(Variance.OUT_VARIANCE, approximatedSuperType)
newArguments[index] = createTypeArgument(approximatedSuperType, TypeVariance.OUT)
}
}
}
@@ -463,33 +493,33 @@ class TypeApproximator {
if (newArguments.all { it == null }) return null
val newArgumentsList = arguments.mapIndexed { index, oldArgument -> newArguments[index] ?: oldArgument }
return type.replace(newArgumentsList)
val newArgumentsList = List(type.argumentsCount()) { index -> newArguments[index] ?: type.getArgument(index) }
return type.replaceArguments(newArgumentsList)
}
private fun SimpleType.defaultResult(toSuper: Boolean) = if (toSuper) builtIns.nullableAnyType else {
if (isMarkedNullable) builtIns.nullableNothingType else builtIns.nothingType
private fun SimpleTypeMarker.defaultResult(toSuper: Boolean) = if (toSuper) nullableAnyType() else {
if (isMarkedNullable()) nullableNothingType() else nothingType()
}
// Any? or Any!
private fun UnwrappedType.isTrivialSuper() = upperIfFlexible().isNullableAny()
private fun KotlinTypeMarker.isTrivialSuper() = upperBoundIfFlexible().isNullableAny()
// Nothing or Nothing!
private fun UnwrappedType.isTrivialSub() = lowerIfFlexible().isNothing()
}
internal fun UnwrappedType.typeDepth() =
when (this) {
is SimpleType -> typeDepth()
is FlexibleType -> Math.max(lowerBound.typeDepth(), upperBound.typeDepth())
}
internal fun SimpleType.typeDepth(): Int {
if (this is TypeUtils.SpecialType) return 0
val maxInArguments = arguments.asSequence().map {
if (it.isStarProjection) 1 else it.type.unwrap().typeDepth()
}.max() ?: 0
return maxInArguments + 1
private fun KotlinTypeMarker.isTrivialSub() = lowerBoundIfFlexible().isNothing()
}
//
//internal fun KotlinTypeMarker.typeDepth() =
// when (this) {
// is SimpleTypeMarker -> typeDepth()
// is FlexibleType -> Math.max(lowerBound.typeDepth(), upperBound.typeDepth())
// }
//
//internal fun SimpleTypeMarker.typeDepth(): Int {
// if (this is TypeUtils.SpecialType) return 0
//
// val maxInArguments = arguments.asSequence().map {
// if (it.isStarProjection) 1 else it.type.unwrap().typeDepth()
// }.max() ?: 0
//
// return maxInArguments + 1
//}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.types
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.model.StubTypeMarker
// This type is used as a stub for postponed type variables, which are important for coroutine inference
class StubType(
@@ -16,7 +17,7 @@ class StubType(
ErrorUtils.createErrorTypeConstructor("Constructor for non fixed type: $originalTypeVariable"),
override val memberScope: MemberScope =
ErrorUtils.createErrorScope("Scope for non fixed type: $originalTypeVariable")
) : SimpleType() {
) : SimpleType(), StubTypeMarker {
override val arguments: List<TypeProjection>
get() = emptyList()
@@ -24,13 +24,9 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowedTypeVariable: Boolean = true) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
@Suppress("UNCHECKED_CAST")
return org.jetbrains.kotlin.types.checker.intersectTypes(types as List<UnwrappedType>)
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return super.prepareType(transformToNewType((type as KotlinType).unwrap()))
return transformToNewType((type as KotlinType).unwrap())
}
override val isErrorTypeEqualsToAnything: Boolean
@@ -54,22 +50,26 @@ open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val
}
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
require(type is SimpleType, type::errorMessage)
return classicSubstitutionSupertypePolicy(type)
}
val substitutor = TypeConstructorSubstitution.create(type).buildSubstitutor()
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is UnwrappedType && allowedTypeVariable && constructor is NewTypeVariableConstructor
return object : SupertypesPolicy.DoCustomTransform() {
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker {
return substitutor.safeSubstitute(
type.lowerBoundIfFlexible() as KotlinType,
Variance.INVARIANT
).asSimpleType()!!
companion object {
fun ClassicTypeSystemContext.classicSubstitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
require(type is SimpleType, type::errorMessage)
val substitutor = TypeConstructorSubstitution.create(type).buildSubstitutor()
return object : SupertypesPolicy.DoCustomTransform() {
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker {
return substitutor.safeSubstitute(
type.lowerBoundIfFlexible() as KotlinType,
Variance.INVARIANT
).asSimpleType()!!
}
}
}
}
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is UnwrappedType && allowedTypeVariable && constructor is NewTypeVariableConstructor
}
private fun Any.errorMessage(): String {
@@ -8,14 +8,18 @@ package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.hasNoInferAnnotation
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.contains
interface ClassicTypeSystemContext : TypeSystemContext {
interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
override fun TypeConstructorMarker.isDenotable(): Boolean {
require(this is TypeConstructor, this::errorMessage)
return this.isDenotable
@@ -134,6 +138,13 @@ interface ClassicTypeSystemContext : TypeSystemContext {
}
private fun TypeVariance.convertVariance(): Variance {
return when (this) {
TypeVariance.INV -> Variance.INVARIANT
TypeVariance.IN -> Variance.IN_VARIANCE
TypeVariance.OUT -> Variance.OUT_VARIANCE
}
}
override fun TypeArgumentMarker.getType(): KotlinTypeMarker {
require(this is TypeProjection, this::errorMessage)
@@ -220,6 +231,11 @@ interface ClassicTypeSystemContext : TypeSystemContext {
return this.asTypeProjection()
}
override fun TypeConstructorMarker.isUnitTypeConstructor(): Boolean {
require(this is TypeConstructor, this::errorMessage)
return KotlinBuiltIns.isTypeConstructorForGivenClass(this, FQ_NAMES.unit)
}
/**
*
* SingleClassifierType is one of the following types:
@@ -240,6 +256,231 @@ interface ClassicTypeSystemContext : TypeSystemContext {
require(this is KotlinType, this::errorMessage)
return typeConstructor().isNothingConstructor() && !TypeUtils.isNullableType(this)
}
override fun KotlinTypeMarker.contains(predicate: (KotlinTypeMarker) -> Boolean): Boolean {
require(this is KotlinType, this::errorMessage)
return containsInternal(this, predicate)
}
override fun SimpleTypeMarker.typeDepth(): Int {
require(this is SimpleType, this::errorMessage)
return this.typeDepthInternal()
}
override fun KotlinTypeMarker.typeDepth(): Int {
require(this is UnwrappedType, this::errorMessage)
return this.typeDepthInternal()
}
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
@Suppress("UNCHECKED_CAST")
return org.jetbrains.kotlin.types.checker.intersectTypes(types as List<UnwrappedType>)
}
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
@Suppress("UNCHECKED_CAST")
return org.jetbrains.kotlin.types.checker.intersectTypes(types as List<SimpleType>)
}
override fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker? {
@Suppress("UNCHECKED_CAST")
return singleBestRepresentative(this as Collection<KotlinType>)
}
override fun KotlinTypeMarker.isUnit(): Boolean {
require(this is UnwrappedType, this::errorMessage)
return KotlinBuiltIns.isUnit(this)
}
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
require(lowerBound is SimpleType, this::errorMessage)
require(upperBound is SimpleType, this::errorMessage)
return KotlinTypeFactory.flexibleType(lowerBound, upperBound)
}
override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker {
return when (this) {
is SimpleTypeMarker -> this.withNullability(nullable)
is FlexibleTypeMarker -> createFlexibleType(lowerBound().withNullability(nullable), upperBound().withNullability(nullable))
else -> error("sealed")
}
}
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext {
return ClassicTypeCheckerContext(errorTypesEqualToAnything)
}
override fun nullableNothingType(): SimpleTypeMarker {
return builtIns.nullableNothingType
}
override fun nullableAnyType(): SimpleTypeMarker {
return builtIns.nullableAnyType
}
override fun nothingType(): SimpleTypeMarker {
return builtIns.nothingType
}
val builtIns: KotlinBuiltIns get() = throw UnsupportedOperationException("Not supported")
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
require(this is UnwrappedType, this::errorMessage)
return makeDefinitelyNotNullOrNotNullInternal(this)
}
override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker {
require(this is SimpleType, this::errorMessage)
return makeSimpleTypeDefinitelyNotNullOrNotNullInternal(this)
}
override fun KotlinTypeMarker.removeAnnotations(): KotlinTypeMarker {
require(this is UnwrappedType, this::errorMessage)
return this.replaceAnnotations(Annotations.EMPTY)
}
override fun KotlinTypeMarker.hasExactAnnotation(): Boolean {
require(this is UnwrappedType, this::errorMessage)
return hasExactInternal(this)
}
override fun KotlinTypeMarker.hasNoInferAnnotation(): Boolean {
require(this is UnwrappedType, this::errorMessage)
return hasNoInferInternal(this)
}
override fun TypeVariableMarker.freshTypeConstructor(): TypeConstructorMarker {
errorSupportedOnlyInTypeInference()
}
override fun CapturedTypeMarker.typeConstructorProjection(): TypeArgumentMarker {
require(this is NewCapturedType, this::errorMessage)
return this.constructor.projection
}
override fun KotlinTypeMarker.isNullableType(): Boolean {
require(this is KotlinType, this::errorMessage)
return TypeUtils.isNullableType(this)
}
override fun createSimpleType(
constructor: TypeConstructorMarker,
arguments: List<TypeArgumentMarker>,
nullable: Boolean
): SimpleTypeMarker {
require(constructor is TypeConstructor, constructor::errorMessage)
@Suppress("UNCHECKED_CAST")
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, arguments as List<TypeProjection>, nullable)
}
override fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker {
require(type is KotlinType, type::errorMessage)
return TypeProjectionImpl(variance.convertVariance(), type)
}
override fun createStarProjection(typeParameter: TypeParameterMarker): TypeArgumentMarker {
require(typeParameter is TypeParameterDescriptor, typeParameter::errorMessage)
return StarProjectionImpl(typeParameter)
}
override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean {
require(this is UnwrappedType, this::errorMessage)
return constructor is NewTypeVariableConstructor ||
constructor.declarationDescriptor is TypeParameterDescriptor ||
this is NewCapturedType
}
override fun SimpleTypeMarker.replaceArguments(newArguments: List<TypeArgumentMarker>): SimpleTypeMarker {
require(this is SimpleType, this::errorMessage)
return this.replace(newArguments as List<TypeProjection>)
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
require(type is UnwrappedType, type::errorMessage)
return NewKotlinTypeChecker.transformToNewType(type)
}
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
require(this is DefinitelyNotNullType, this::errorMessage)
return this.original
}
override fun createCapturedType(
constructorProjection: TypeArgumentMarker,
constructorSupertypes: List<KotlinTypeMarker>,
lowerType: KotlinTypeMarker?,
captureStatus: CaptureStatus
): CapturedTypeMarker {
errorSupportedOnlyInTypeInference()
}
override fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker {
errorSupportedOnlyInTypeInference()
}
override fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker {
errorSupportedOnlyInTypeInference()
}
override fun TypeVariableMarker.defaultType(): SimpleTypeMarker {
errorSupportedOnlyInTypeInference()
}
override fun createStubType(typeVariable: TypeVariableMarker): StubTypeMarker {
errorSupportedOnlyInTypeInference()
}
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
@Suppress("UNCHECKED_CAST")
explicitSupertypes as List<SimpleType>
return IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)
}
override fun TypeConstructorMarker.getApproximatedIntegerLiteralType(): KotlinTypeMarker {
require(this is IntegerLiteralTypeConstructor, this::errorMessage)
return this.getApproximatedType().unwrap()
}
}
private fun hasNoInferInternal(type: UnwrappedType): Boolean {
return type.hasNoInferAnnotation()
}
private fun hasExactInternal(type: UnwrappedType): Boolean {
return type.hasExactAnnotation()
}
private fun makeDefinitelyNotNullOrNotNullInternal(type: UnwrappedType): UnwrappedType {
return type.makeDefinitelyNotNullOrNotNull()
}
private fun makeSimpleTypeDefinitelyNotNullOrNotNullInternal(type: SimpleType): SimpleType {
return type.makeSimpleTypeDefinitelyNotNullOrNotNull()
}
private fun containsInternal(type: KotlinType, predicate: (KotlinTypeMarker) -> Boolean): Boolean = type.contains(predicate)
private fun singleBestRepresentative(collection: Collection<KotlinType>) = collection.singleBestRepresentative()
internal fun UnwrappedType.typeDepthInternal() =
when (this) {
is SimpleType -> typeDepthInternal()
is FlexibleType -> Math.max(lowerBound.typeDepthInternal(), upperBound.typeDepthInternal())
}
internal fun SimpleType.typeDepthInternal(): Int {
if (this is TypeUtils.SpecialType) return 0
val maxInArguments = arguments.asSequence().map {
if (it.isStarProjection) 1 else it.type.unwrap().typeDepthInternal()
}.max() ?: 0
return maxInArguments + 1
}
@@ -248,6 +489,10 @@ private inline fun Any.errorMessage(): String {
return "ClassicTypeSystemContext couldn't handle: $this, ${this::class}"
}
private fun errorSupportedOnlyInTypeInference(): Nothing {
error("supported only in type inference context")
}
fun Variance.convertVariance(): TypeVariance {
return when (this) {
Variance.INVARIANT -> TypeVariance.INV
@@ -30,20 +30,21 @@ import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.addToStdlib.cast
object SimpleClassicTypeSystemContext : ClassicTypeSystemContext
object StrictEqualityTypeChecker {
private val context = object : ClassicTypeSystemContext {}
/**
* String! != String & A<String!> != A<String>, also A<in Nothing> != A<out Any?>
* also A<*> != A<out Any?>
* different error types non-equals even errorTypeEqualToAnything
*/
fun strictEqualTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
return AbstractStrictEqualityTypeChecker.strictEqualTypes(context, a, b)
return AbstractStrictEqualityTypeChecker.strictEqualTypes(SimpleClassicTypeSystemContext, a, b)
}
fun strictEqualTypes(a: SimpleType, b: SimpleType): Boolean {
return AbstractStrictEqualityTypeChecker.strictEqualTypes(context, a, b)
return AbstractStrictEqualityTypeChecker.strictEqualTypes(SimpleClassicTypeSystemContext, a, b)
}
}
@@ -64,11 +65,11 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
ClassicTypeCheckerContext(false).equalTypes(a.unwrap(), b.unwrap())
fun ClassicTypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
return AbstractTypeChecker.equalTypes(this, a, b)
return AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b)
}
fun ClassicTypeCheckerContext.isSubtypeOf(subType: UnwrappedType, superType: UnwrappedType): Boolean {
return AbstractTypeChecker.isSubtypeOf(this, subType, superType)
return AbstractTypeChecker.isSubtypeOf(this as AbstractTypeCheckerContext, subType, superType)
}
fun transformToNewType(type: SimpleType): SimpleType {
@@ -156,10 +157,9 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
object NullabilityChecker {
fun isSubtypeOfAny(type: UnwrappedType): Boolean =
ClassicTypeCheckerContext(false).hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
fun hasPathByNotMarkedNullableNodes(start: SimpleType, end: TypeConstructor) =
ClassicTypeCheckerContext(false).hasPathByNotMarkedNullableNodes(start, end)
SimpleClassicTypeSystemContext
.newBaseTypeCheckerContext(false)
.hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
}
fun UnwrappedType.hasSupertypeWithGivenTypeConstructor(typeConstructor: TypeConstructor) =
@@ -21,9 +21,7 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
abstract fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean
abstract fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker
open fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return type
}
@@ -146,6 +144,15 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
}
object AbstractTypeChecker {
fun isSubtypeOf(context: TypeCheckerProviderContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true), subType, superType)
}
fun equalTypes(context: TypeCheckerProviderContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean {
return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false), a, b)
}
fun isSubtypeOf(context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
if (subType === superType) return true
return context.completeIsSubTypeOf(context.prepareType(subType), context.prepareType(superType))
@@ -312,7 +319,7 @@ object AbstractTypeChecker {
!type.isDynamic() && !type.isDefinitelyNotNullType() &&
type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor()
private fun effectiveVariance(declared: TypeVariance, useSite: TypeVariance): TypeVariance? {
fun effectiveVariance(declared: TypeVariance, useSite: TypeVariance): TypeVariance? {
if (declared == TypeVariance.INV) return useSite
if (useSite == TypeVariance.INV) return declared
@@ -453,6 +460,14 @@ object AbstractNullabilityChecker {
fun isPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean =
context.runIsPossibleSubtype(subType, superType)
fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean =
AbstractNullabilityChecker.isSubtypeOfAny(context.newBaseTypeCheckerContext(false), type)
fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean =
with(context) {
hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible)
}
private fun AbstractTypeCheckerContext.runIsPossibleSubtype(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean {
// it makes for case String? & Any <: String
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) {
@@ -501,6 +516,9 @@ object AbstractNullabilityChecker {
if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy
}
fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
newBaseTypeCheckerContext(false).hasPathByNotMarkedNullableNodes(start, end)
fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
anySupertype(start, {
it.isNotNullNothing() || (!it.isMarkedNullable() && isEqualTypeConstructors(it.typeConstructor(), end))
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.types.model
fun TypeVariableMarker.freshTypeConstructor(c: TypeSystemInferenceExtensionContext) = with(c) { freshTypeConstructor() }
fun TypeSubstitutorMarker.safeSubstitute(
c: TypeSystemInferenceExtensionContext,
type: KotlinTypeMarker
) = with(c) { safeSubstitute(type) }
fun TypeVariableMarker.defaultType(c: TypeSystemInferenceExtensionContext) = with(c) { defaultType() }
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.types.model
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
interface KotlinTypeMarker
interface TypeArgumentMarker
interface TypeConstructorMarker
@@ -17,14 +19,21 @@ interface DefinitelyNotNullTypeMarker : SimpleTypeMarker
interface FlexibleTypeMarker : KotlinTypeMarker
interface DynamicTypeMarker : FlexibleTypeMarker
interface RawTypeMarker : FlexibleTypeMarker
interface StubTypeMarker : SimpleTypeMarker
interface TypeArgumentListMarker
interface TypeVariableMarker
enum class TypeVariance {
IN,
OUT,
INV
interface TypeSubstitutorMarker
enum class TypeVariance(val presentation: String) {
IN("in"),
OUT("out"),
INV("");
override fun toString(): String = presentation
}
@@ -35,6 +44,96 @@ interface TypeSystemOptimizationContext {
fun identicalArguments(a: SimpleTypeMarker, b: SimpleTypeMarker) = false
}
interface TypeSystemBuiltInsContext {
fun nullableNothingType(): SimpleTypeMarker
fun nullableAnyType(): SimpleTypeMarker
fun nothingType(): SimpleTypeMarker
}
interface TypeSystemTypeFactoryContext {
fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker
fun createSimpleType(constructor: TypeConstructorMarker, arguments: List<TypeArgumentMarker>, nullable: Boolean): SimpleTypeMarker
fun createTypeArgument(type: KotlinTypeMarker, variance: TypeVariance): TypeArgumentMarker
fun createStarProjection(typeParameter: TypeParameterMarker): TypeArgumentMarker
}
interface TypeCheckerProviderContext {
fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext
}
interface TypeSystemCommonSuperTypesContext : TypeSystemContext, TypeSystemTypeFactoryContext, TypeCheckerProviderContext {
fun KotlinTypeMarker.anySuperTypeConstructor(predicate: (TypeConstructorMarker) -> Boolean) =
newBaseTypeCheckerContext(false).anySupertype(lowerBoundIfFlexible(), {
predicate(it.typeConstructor())
}, { AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible })
fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean
fun SimpleTypeMarker.typeDepth(): Int
fun KotlinTypeMarker.typeDepth(): Int
fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker?
}
interface TypeSystemInferenceExtensionContextDelegate : TypeSystemInferenceExtensionContext
interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBuiltInsContext, TypeSystemCommonSuperTypesContext {
fun KotlinTypeMarker.contains(predicate: (KotlinTypeMarker) -> Boolean): Boolean
fun TypeConstructorMarker.isUnitTypeConstructor(): Boolean
fun TypeConstructorMarker.getApproximatedIntegerLiteralType(): KotlinTypeMarker
fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker?
fun KotlinTypeMarker.isUnit(): Boolean
fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker
fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker
fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker
fun createCapturedType(
constructorProjection: TypeArgumentMarker,
constructorSupertypes: List<KotlinTypeMarker>,
lowerType: KotlinTypeMarker?,
captureStatus: CaptureStatus
): CapturedTypeMarker
fun createStubType(typeVariable: TypeVariableMarker): StubTypeMarker
fun KotlinTypeMarker.removeAnnotations(): KotlinTypeMarker
fun SimpleTypeMarker.replaceArguments(newArguments: List<TypeArgumentMarker>): SimpleTypeMarker
fun KotlinTypeMarker.hasExactAnnotation(): Boolean
fun KotlinTypeMarker.hasNoInferAnnotation(): Boolean
fun TypeVariableMarker.freshTypeConstructor(): TypeConstructorMarker
fun CapturedTypeMarker.typeConstructorProjection(): TypeArgumentMarker
fun KotlinTypeMarker.isNullableType(): Boolean
fun KotlinTypeMarker.isNullableAny() = this.typeConstructor().isAnyConstructor() && this.isNullableType()
fun KotlinTypeMarker.isNothing() = this.typeConstructor().isNothingConstructor() && !this.isNullableType()
fun KotlinTypeMarker.isNullableNothing() = this.typeConstructor().isNothingConstructor() && this.isNullableType()
fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker
fun typeSubstitutorByTypeConstructor(map: Map<TypeConstructorMarker, KotlinTypeMarker>): TypeSubstitutorMarker
fun TypeSubstitutorMarker.safeSubstitute(type: KotlinTypeMarker): KotlinTypeMarker
fun TypeVariableMarker.defaultType(): SimpleTypeMarker
}
class ArgumentList(initialSize: Int) : ArrayList<TypeArgumentMarker>(initialSize), TypeArgumentListMarker
@@ -53,6 +152,8 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker
fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker?
fun KotlinTypeMarker.isCapturedType() = asSimpleType()?.asCapturedType() != null
fun SimpleTypeMarker.asDefinitelyNotNullType(): DefinitelyNotNullTypeMarker?
fun SimpleTypeMarker.isMarkedNullable(): Boolean
fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker
@@ -66,7 +167,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
return null
}
fun SimpleTypeMarker.isStubType(): Boolean = false
fun SimpleTypeMarker.isStubType(): Boolean
fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker
@@ -150,6 +251,13 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
* Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor
*/
fun SimpleTypeMarker.isSingleClassifierType(): Boolean
fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker
fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker
fun KotlinTypeMarker.isSimpleType() = asSimpleType() != null
fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker
}
enum class CaptureStatus {
@@ -44,7 +44,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable
internal fun BackendContext.createTypeTranslator(moduleDescriptor: ModuleDescriptor): TypeTranslator =
TypeTranslator(externalSymbols, irBuiltIns.languageVersionSettings).apply {
TypeTranslator(externalSymbols, irBuiltIns.languageVersionSettings, moduleDescriptor.builtIns).apply {
constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable = externalSymbols)
constantValueGenerator.typeTranslator = this
}
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.type.MapPsiToAsmDesc
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isInterface
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.uast.*
@@ -232,7 +233,7 @@ internal fun KotlinType.toPsiType(lightDeclaration: PsiModifierListOwner?, conte
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
val typeMappingMode = if (boxed) TypeMappingMode.GENERIC_ARGUMENT else TypeMappingMode.DEFAULT
val approximatedType = TypeApproximator().approximateDeclarationType(this, true, languageVersionSettings)
val approximatedType = TypeApproximator(this.builtIns).approximateDeclarationType(this, true, languageVersionSettings)
typeMapper.mapType(approximatedType, signatureWriter, typeMappingMode)
val signature = StringCharacterIterator(signatureWriter.toString())