[NI] Improve CST algorithm to handle non-fixed variables

#KT-32456 Fixed
 #KT-32423 Fixed
 #KT-32818 Fixed
 #KT-33197 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-08-28 01:23:18 +03:00
parent ba6648d535
commit ca8da22569
41 changed files with 605 additions and 81 deletions
@@ -10,8 +10,11 @@ import org.jetbrains.kotlin.fir.types.ConeTypeContext
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
private class SessionBasedTypeContext(override val session: FirSession) : ConeTypeContext { private class SessionBasedTypeContext(override val session: FirSession) : ConeTypeContext {
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext { override fun newBaseTypeCheckerContext(
return ConeTypeCheckerContext(errorTypesEqualToAnything, session) errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext {
return ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)
} }
} }
@@ -85,9 +85,11 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
return ConeStarProjection return ConeStarProjection
} }
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext { override fun newBaseTypeCheckerContext(
return ConeTypeCheckerContext(errorTypesEqualToAnything, session) errorTypesEqualToAnything: Boolean,
} stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext =
ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)
override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean { override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean {
require(this is ConeKotlinType) require(this is ConeKotlinType)
@@ -167,7 +169,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
override fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker? { override fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker? {
if (this.size == 1) return this.first() if (this.size == 1) return this.first()
val context = newBaseTypeCheckerContext(true) val context = newBaseTypeCheckerContext(errorTypesEqualToAnything = true, stubTypesEqualToAnything = true)
return this.firstOrNull { candidate -> return this.firstOrNull { candidate ->
this.all { other -> this.all { other ->
// We consider error types equal to anything here, so that intersections like // We consider error types equal to anything here, so that intersections like
@@ -498,8 +498,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
} }
} }
class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean, override val session: FirSession) : class ConeTypeCheckerContext(
AbstractTypeCheckerContext(), ConeTypeContext { override val isErrorTypeEqualsToAnything: Boolean,
override val isStubTypeEqualsToAnything: Boolean,
override val session: FirSession
) : AbstractTypeCheckerContext(), ConeTypeContext {
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy { override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy {
if (type.argumentsCount() == 0) return SupertypesPolicy.LowerIfFlexible if (type.argumentsCount() == 0) return SupertypesPolicy.LowerIfFlexible
require(type is ConeKotlinType) require(type is ConeKotlinType)
@@ -539,10 +542,13 @@ class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean,
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = this is ConeKotlinType && this is ConeTypeVariableType get() = this is ConeKotlinType && this is ConeTypeVariableType
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext = override fun newBaseTypeCheckerContext(
errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext =
if (this.isErrorTypeEqualsToAnything == errorTypesEqualToAnything) if (this.isErrorTypeEqualsToAnything == errorTypesEqualToAnything)
this this
else else
ConeTypeCheckerContext(errorTypesEqualToAnything, session) ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)
} }
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker
class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSessionComponent { class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSessionComponent {
private val context = ConeTypeCheckerContext(false, session) private val context = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = true, session = session)
private val cache = HashMap<FirClassLikeSymbol<*>, Map<FirClassLikeSymbol<*>, List<ConeClassLikeType>>?>(1000, 0.5f) private val cache = HashMap<FirClassLikeSymbol<*>, Map<FirClassLikeSymbol<*>, List<ConeClassLikeType>>?>(1000, 0.5f)
fun getCorrespondingSupertypes( fun getCorrespondingSupertypes(
@@ -12,7 +12,7 @@ object ConeNullabilityChecker {
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean { fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
val actualType = with(context) { type.lowerBoundIfFlexible() } val actualType = with(context) { type.lowerBoundIfFlexible() }
return with(AbstractNullabilityChecker) { return with(AbstractNullabilityChecker) {
context.newBaseTypeCheckerContext(false) context.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
.hasNotNullSupertype(actualType, AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible) .hasNotNullSupertype(actualType, AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible)
} }
} }
@@ -10176,6 +10176,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstFromNullableChildAndNonParameterizedType.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstFromNullableChildAndNonParameterizedType.kt");
} }
@TestMetadata("cstWithTypeContainingNonFixedVariable.kt")
public void testCstWithTypeContainingNonFixedVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstWithTypeContainingNonFixedVariable.kt");
}
@TestMetadata("dontCaptureTypeVariable.kt") @TestMetadata("dontCaptureTypeVariable.kt")
public void testDontCaptureTypeVariable() throws Exception { public void testDontCaptureTypeVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/dontCaptureTypeVariable.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/dontCaptureTypeVariable.kt");
@@ -10206,6 +10211,16 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt31969.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt31969.kt");
} }
@TestMetadata("kt32818.kt")
public void testKt32818() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt32818.kt");
}
@TestMetadata("kt33197.kt")
public void testKt33197() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt33197.kt");
}
@TestMetadata("kt3372toCollection.kt") @TestMetadata("kt3372toCollection.kt")
public void testKt3372toCollection() throws Exception { public void testKt3372toCollection() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt");
@@ -10231,6 +10246,16 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt");
} }
@TestMetadata("nonFixedVariableInsideFlexibleType.kt")
public void testNonFixedVariableInsideFlexibleType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableInsideFlexibleType.kt");
}
@TestMetadata("outProjectedTypeToOutProjected.kt")
public void testOutProjectedTypeToOutProjected() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/outProjectedTypeToOutProjected.kt");
}
@TestMetadata("postponedCompletionWithExactAnnotation.kt") @TestMetadata("postponedCompletionWithExactAnnotation.kt")
public void testPostponedCompletionWithExactAnnotation() throws Exception { public void testPostponedCompletionWithExactAnnotation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt");
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.ir.types
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker
@@ -31,13 +29,16 @@ class IrTypeCheckerContext(override val irBuiltIns: IrBuiltIns) : IrTypeSystemCo
override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker) = super.isEqualTypeConstructors(a, b) override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker) = super.isEqualTypeConstructors(a, b)
override val isErrorTypeEqualsToAnything = false override val isErrorTypeEqualsToAnything get() = false
override val isStubTypeEqualsToAnything get() = false
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = false get() = false
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext { override fun newBaseTypeCheckerContext(
return IrTypeCheckerContext(irBuiltIns) errorTypesEqualToAnything: Boolean,
} stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext = IrTypeCheckerContext(irBuiltIns)
override fun KotlinTypeMarker.isUninferredParameter(): Boolean = false override fun KotlinTypeMarker.isUninferredParameter(): Boolean = false
@@ -68,7 +68,8 @@ object NewCommonSuperTypeCalculator {
depth: Int depth: Int
): SimpleTypeMarker { ): SimpleTypeMarker {
// i.e. result type also should be marked nullable // i.e. result type also should be marked nullable
val notAllNotNull = types.any { !AbstractNullabilityChecker.isSubtypeOfAny(this, it) } val notAllNotNull =
types.any { !isStubRelatedType(it) && !AbstractNullabilityChecker.isSubtypeOfAny(contextStubTypesEqualToAnything, it) }
val notNullTypes = if (notAllNotNull) types.map { it.withNullability(false) } else types val notNullTypes = if (notAllNotNull) types.map { it.withNullability(false) } else types
val commonSuperType = commonSuperTypeForNotNullTypes(notNullTypes, depth) val commonSuperType = commonSuperTypeForNotNullTypes(notNullTypes, depth)
@@ -94,7 +95,8 @@ object NewCommonSuperTypeCalculator {
val uniqueTypes = arrayListOf<SimpleTypeMarker>() val uniqueTypes = arrayListOf<SimpleTypeMarker>()
for (type in types) { for (type in types) {
val isNewUniqueType = uniqueTypes.all { val isNewUniqueType = uniqueTypes.all {
!AbstractTypeChecker.equalTypes(this, it, type) || it.typeConstructor().isIntegerLiteralTypeConstructor() !AbstractTypeChecker.equalTypes(this, it, type, stubTypesEqualToAnything = false) ||
it.typeConstructor().isIntegerLiteralTypeConstructor()
} }
if (isNewUniqueType) { if (isNewUniqueType) {
uniqueTypes += type uniqueTypes += type
@@ -111,7 +113,9 @@ object NewCommonSuperTypeCalculator {
while (iterator.hasNext()) { while (iterator.hasNext()) {
val potentialSubtype = iterator.next() val potentialSubtype = iterator.next()
val isSubtype = supertypes.any { supertype -> val isSubtype = supertypes.any { supertype ->
supertype !== potentialSubtype && AbstractTypeChecker.isSubtypeOf(this, potentialSubtype, supertype) supertype !== potentialSubtype && AbstractTypeChecker.isSubtypeOf(
this, potentialSubtype, supertype, stubTypesEqualToAnything = false
)
} }
if (isSubtype) iterator.remove() if (isSubtype) iterator.remove()
@@ -120,13 +124,26 @@ object NewCommonSuperTypeCalculator {
return supertypes return supertypes
} }
/*
* Common Supertype calculator works with proper types and stub types (which is a replacement for non-proper types)
* Also, there are two invariant related to stub types:
* - resulting type should be only proper type
* - one of the input types is definitely proper type
* */
private fun TypeSystemCommonSuperTypesContext.commonSuperTypeForNotNullTypes( private fun TypeSystemCommonSuperTypesContext.commonSuperTypeForNotNullTypes(
types: List<SimpleTypeMarker>, types: List<SimpleTypeMarker>,
depth: Int depth: Int
): SimpleTypeMarker { ): SimpleTypeMarker {
if (types.size == 1) return types.single() if (types.size == 1) return types.single()
val uniqueTypes = uniquify(types) val nonStubTypes = types.filter { !isStubRelatedType(it) }
if (nonStubTypes.size == 1) return nonStubTypes.single()
assert(nonStubTypes.isNotEmpty()) {
"There should be at least one non-stub type to compute common supertype but there are: $types"
}
val uniqueTypes = uniquify(nonStubTypes)
if (uniqueTypes.size == 1) return uniqueTypes.single() if (uniqueTypes.size == 1) return uniqueTypes.single()
val explicitSupertypes = filterSupertypes(uniqueTypes) val explicitSupertypes = filterSupertypes(uniqueTypes)
@@ -134,12 +151,23 @@ object NewCommonSuperTypeCalculator {
findErrorTypeInSupertypesIfItIsNeeded(explicitSupertypes)?.let { return it } findErrorTypeInSupertypesIfItIsNeeded(explicitSupertypes)?.let { return it }
findCommonIntegerLiteralTypesSuperType(explicitSupertypes)?.let { return it } findCommonIntegerLiteralTypesSuperType(explicitSupertypes)?.let { return it }
// IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth) return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth)
} }
private fun TypeSystemCommonSuperTypesContext.findErrorTypeInSupertypesIfItIsNeeded(types: List<SimpleTypeMarker>): SimpleTypeMarker? { private fun TypeSystemCommonSuperTypesContext.isStubRelatedType(type: SimpleTypeMarker): Boolean {
return type.isStubType() || isCapturedStubType(type)
}
private fun TypeSystemCommonSuperTypesContext.isCapturedStubType(type: SimpleTypeMarker): Boolean {
val projectedType = type.asCapturedType()?.typeConstructor()?.projection()?.getType() ?: return false
return projectedType.asSimpleType()?.isStubType() == true
}
private fun TypeSystemCommonSuperTypesContext.findErrorTypeInSupertypesIfItIsNeeded(
types: List<SimpleTypeMarker>,
contextStubTypesEqualToAnything: AbstractTypeCheckerContext
): SimpleTypeMarker? {
if (isErrorTypeAllowed) return null if (isErrorTypeAllowed) return null
for (type in types) { for (type in types) {
collectAllSupertypes(type).firstOrNull { it.isError() }?.let { return it.toErrorType() } collectAllSupertypes(type).firstOrNull { it.isError() }?.let { return it.toErrorType() }
@@ -187,7 +215,7 @@ object NewCommonSuperTypeCalculator {
nullable = false nullable = false
) )
val typeCheckerContext = newBaseTypeCheckerContext(false) val typeCheckerContext = newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
/** /**
* Sometimes one type can have several supertypes with given type constructor, suppose A <: List<Int> and A <: List<Double>. * Sometimes one type can have several supertypes with given type constructor, suppose A <: List<Int> and A <: List<Double>.
@@ -206,11 +234,17 @@ object NewCommonSuperTypeCalculator {
val parameter = constructor.getParameter(index) val parameter = constructor.getParameter(index)
var thereIsStar = false var thereIsStar = false
val typeProjections = correspondingSuperTypes.mapNotNull { val typeProjections = correspondingSuperTypes.mapNotNull {
it.getArgumentOrNull(index)?.let { it.getArgumentOrNull(index)?.let { typeArgument ->
if (it.isStarProjection()) { when {
thereIsStar = true typeArgument.isStarProjection() -> {
null thereIsStar = true
} else it null
}
typeArgument.getType().lowerBoundIfFlexible().isStubType() -> null
else -> typeArgument
}
} }
} }
@@ -23,6 +23,7 @@ class PostponedArgumentsAnalyzer(
) { ) {
interface Context : TypeSystemInferenceExtensionContext { interface Context : TypeSystemInferenceExtensionContext {
fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>): TypeSubstitutorMarker fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>): TypeSubstitutorMarker
fun buildNotFixedVariablesToStubTypesSubstitutor(): TypeSubstitutorMarker
fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker> fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker>
// type can be proper if it not contains not fixed type variables // type can be proper if it not contains not fixed type variables
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstituto
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.StubTypeMarker import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
fun ConstraintStorage.buildCurrentSubstitutor( fun ConstraintStorage.buildCurrentSubstitutor(
context: TypeSystemInferenceExtensionContext, context: TypeSystemInferenceExtensionContext,
@@ -50,6 +47,11 @@ fun ConstraintStorage.buildAbstractResultingSubstitutor(context: TypeSystemInfer
return context.typeSubstitutorByTypeConstructor(currentSubstitutorMap + uninferredSubstitutorMap) return context.typeSubstitutorByTypeConstructor(currentSubstitutorMap + uninferredSubstitutorMap)
} }
fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(context: TypeSystemInferenceExtensionContext) =
context.typeSubstitutorByTypeConstructor(
notFixedTypeVariables.mapValues { context.createStubType(it.value.typeVariable) }
)
fun ConstraintStorage.buildResultingSubstitutor(context: TypeSystemInferenceExtensionContext): NewTypeSubstitutor { fun ConstraintStorage.buildResultingSubstitutor(context: TypeSystemInferenceExtensionContext): NewTypeSubstitutor {
return buildAbstractResultingSubstitutor(context) as NewTypeSubstitutor return buildAbstractResultingSubstitutor(context) as NewTypeSubstitutor
} }
@@ -18,6 +18,9 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
override val isErrorTypeEqualsToAnything: Boolean override val isErrorTypeEqualsToAnything: Boolean
get() = true get() = true
override val isStubTypeEqualsToAnything: Boolean
get() = true
abstract fun isMyTypeVariable(type: SimpleTypeMarker): Boolean abstract fun isMyTypeVariable(type: SimpleTypeMarker): Boolean
// super and sub type isSingleClassifierType // super and sub type isSingleClassifierType
@@ -65,7 +65,6 @@ class ConstraintInjector(
addSubTypeConstraintAndIncorporateIt(c, b, a, incorporationPosition) addSubTypeConstraintAndIncorporateIt(c, b, a, incorporationPosition)
} }
private fun addSubTypeConstraintAndIncorporateIt( private fun addSubTypeConstraintAndIncorporateIt(
c: Context, c: Context,
lowerType: KotlinTypeMarker, lowerType: KotlinTypeMarker,
@@ -126,7 +125,7 @@ class ConstraintInjector(
val possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>> val possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>
) : AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c { ) : AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c {
val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything) val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything, isStubTypeEqualsToAnything)
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy { override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy {
return baseContext.substitutionSupertypePolicy(type) return baseContext.substitutionSupertypePolicy(type)
@@ -73,29 +73,26 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker {
"and class: ${type::class.java.canonicalName}. type.toString() = $type" "and class: ${type::class.java.canonicalName}. type.toString() = $type"
} }
val capturedType = if (type is DefinitelyNotNullType) type.original as NewCapturedType else type as NewCapturedType val capturedType = if (type is DefinitelyNotNullType) type.original as NewCapturedType else type as NewCapturedType
val lower = capturedType.lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) }
if (lower != null && capturedType.lowerType is StubType) {
return NewCapturedType(
capturedType.captureStatus,
NewCapturedTypeConstructor(TypeProjectionImpl(typeConstructor.projection.projectionKind, lower)),
lower
)
}
if (lower != null) throw IllegalStateException( val innerType = capturedType.lowerType ?: capturedType.constructor.projection.type.unwrap()
"Illegal type substitutor: $this, " + val substitutedInnerType = substitute(innerType, keepAnnotation, runCapturedChecks = false)
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
"original lower type: '${capturedType.lowerType}" if (substitutedInnerType != null) {
) if (innerType is StubType || substitutedInnerType is StubType) {
return NewCapturedType(
capturedType.captureStatus,
NewCapturedTypeConstructor(TypeProjectionImpl(typeConstructor.projection.projectionKind, substitutedInnerType)),
lowerType = if (capturedType.lowerType != null) substitutedInnerType else null
)
} else {
throwExceptionAboutInvalidCapturedSubstitution(capturedType, innerType, substitutedInnerType)
}
}
if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) {
typeConstructor.supertypes.forEach { supertype -> typeConstructor.supertypes.forEach { supertype ->
substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let { substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let {
throw IllegalStateException( throwExceptionAboutInvalidCapturedSubstitution(capturedType, supertype, it)
"Illegal type substitutor: $this, " +
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
"original supertype: '$supertype'"
)
} }
} }
} }
@@ -130,6 +127,18 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker {
return replacement return replacement
} }
private fun throwExceptionAboutInvalidCapturedSubstitution(
capturedType: SimpleType,
innerType: UnwrappedType,
substitutedInnerType: UnwrappedType
): Nothing =
throw IllegalStateException(
"Illegal type substitutor: $this, " +
"because for captured type '$capturedType' supertype approximation should be null, but it is: '$innerType'," +
"original supertype: '$substitutedInnerType'"
)
private fun substituteParametrizedType( private fun substituteParametrizedType(
type: SimpleType, type: SimpleType,
keepAnnotation: Boolean, keepAnnotation: Boolean,
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
class ResultTypeResolver( class ResultTypeResolver(
@@ -30,6 +31,7 @@ class ResultTypeResolver(
) { ) {
interface Context : TypeSystemInferenceExtensionContext { interface Context : TypeSystemInferenceExtensionContext {
fun isProperType(type: KotlinTypeMarker): Boolean fun isProperType(type: KotlinTypeMarker): Boolean
fun buildNotFixedVariablesToStubTypesSubstitutor(): TypeSubstitutorMarker
} }
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker { fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker {
@@ -83,9 +85,10 @@ class ResultTypeResolver(
} }
private fun Context.findSubType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? { private fun Context.findSubType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && isProperType(it.type) } val lowerConstraintTypes = prepareLowerConstraints(variableWithConstraints.constraints)
if (lowerConstraints.isNotEmpty()) {
val types = sinkIntegerLiteralTypes(lowerConstraints.map { it.type }) if (lowerConstraintTypes.isNotEmpty()) {
val types = sinkIntegerLiteralTypes(lowerConstraintTypes)
val commonSuperType = with(NewCommonSuperTypeCalculator) { val commonSuperType = with(NewCommonSuperTypeCalculator) {
this@findSubType.commonSuperType(types) this@findSubType.commonSuperType(types)
} }
@@ -116,6 +119,33 @@ class ResultTypeResolver(
return null return null
} }
private fun Context.prepareLowerConstraints(constraints: List<Constraint>): List<KotlinTypeMarker> {
var atLeastOneProper = false
var atLeastOneNonProper = false
val lowerConstraintTypes = mutableListOf<KotlinTypeMarker>()
for (constraint in constraints) {
if (constraint.kind != ConstraintKind.LOWER) continue
val type = constraint.type
lowerConstraintTypes.add(type)
if (isProperType(type)) {
atLeastOneProper = true
} else {
atLeastOneNonProper = true
}
}
if (!atLeastOneProper) return emptyList()
if (!atLeastOneNonProper) return lowerConstraintTypes
val notFixedToStubTypesSubstitutor = buildNotFixedVariablesToStubTypesSubstitutor()
return lowerConstraintTypes.map { if (isProperType(it)) it else notFixedToStubTypesSubstitutor.safeSubstitute(it) }
}
private fun Context.sinkIntegerLiteralTypes(types: List<KotlinTypeMarker>): List<KotlinTypeMarker> { private fun Context.sinkIntegerLiteralTypes(types: List<KotlinTypeMarker>): List<KotlinTypeMarker> {
return types.sortedBy { type -> return types.sortedBy { type ->
@@ -307,6 +307,11 @@ class NewConstraintSystemImpl(
return storage.buildCurrentSubstitutor(this, additionalBindings) return storage.buildCurrentSubstitutor(this, additionalBindings)
} }
override fun buildNotFixedVariablesToStubTypesSubstitutor(): TypeSubstitutorMarker {
checkState(State.BUILDING, State.COMPLETION)
return storage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(this)
}
override fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker> { override fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker> {
checkState(State.BUILDING, State.COMPLETION) checkState(State.BUILDING, State.COMPLETION)
// TODO: SUB // TODO: SUB
@@ -0,0 +1,18 @@
// !LANGUAGE: +NewInference
// WITH_RUNTIME
// IGNORE_BACKEND: JS_IR
fun test(foo: MutableList<String>?): List<String> {
val bar = foo ?: listOf()
return bar
}
fun box(): String {
val a = test(null)
if (a.isNotEmpty()) return "Fail 1"
val b = test(mutableListOf("a"))
if (b.size != 1) return "Fail 2"
return "OK"
}
@@ -0,0 +1,23 @@
// WITH_RUNTIME
// IGNORE_BACKEND: JS_IR
fun test() {
fun returnMutableList(): MutableList<Int>? = null
fun returnsList(): List<Int>? = null
var mutableList: MutableList<Int>? = null
var list: List<Int>? = null
mutableListOf<Int>().addAll(returnMutableList() ?: emptyList<Int>())
mutableListOf<Int>().addAll(returnsList() ?: emptyList())
mutableListOf<Int>().addAll(list ?: emptyList())
mutableListOf<Int>().addAll(returnMutableList() ?: emptyList())
mutableListOf<Int>().addAll(mutableList ?: emptyList())
mutableListOf<Int>().addAll(null ?: emptyList())
}
fun box(): String {
test()
return "OK"
}
@@ -9,9 +9,9 @@ class None<T> : Option<T>
fun <T> bind(r: Option<T>): Option<T> { fun <T> bind(r: Option<T>): Option<T> {
return if (r is Some) { return if (r is Some) {
// Ideally we should infer Option<T> here (see KT-10896) // Ideally we should infer Option<T> here (see KT-10896)
(<!OI;TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT!>if<!> (true) <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>None()<!> else <!DEBUG_INFO_SMARTCAST!>r<!>) checkType { <!NI;DEBUG_INFO_UNRESOLVED_WITH_TARGET, NI;UNRESOLVED_REFERENCE_WRONG_RECEIVER, OI;TYPE_MISMATCH!>_<!><Option<T>>() } (<!OI;TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT!>if<!> (true) <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>None()<!> else <!OI;DEBUG_INFO_SMARTCAST!>r<!>) checkType { <!OI;TYPE_MISMATCH!>_<!><Option<T>>() }
// Works correctly // Works correctly
if (true) None() else <!NI;DEBUG_INFO_SMARTCAST!>r<!> if (true) None() else r
} }
else r else r
} }
@@ -36,7 +36,7 @@ fun <T> bindWhen(r: Option<T>): Option<T> {
return when (r) { return when (r) {
is Some -> { is Some -> {
// Works correctly // Works correctly
if (true) None() else <!NI;DEBUG_INFO_SMARTCAST!>r<!> if (true) None() else r
} }
else -> r else -> r
} }
@@ -0,0 +1,90 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
fun <T> select(x: T, y: T): T = x
open class Inv<K>
class SubInv<V> : Inv<V>()
fun testSimple() {
val a0 = select(Inv<Int>(), SubInv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>a0<!>
val a1 = select(SubInv<Int>(), Inv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>a1<!>
}
fun testNullability() {
val n1 = select(Inv<Int?>(), SubInv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int?>")!>n1<!>
val n2 = select(SubInv<Int?>(), Inv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int?>")!>n2<!>
}
fun testNested() {
val n1 = select(Inv<Inv<Int>>(), SubInv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<Inv<kotlin.Int>>")!>n1<!>
val n2 = select(SubInv<SubInv<Int>>(), Inv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<SubInv<kotlin.Int>>")!>n2<!>
fun <K> createInvInv(): Inv<Inv<K>> = TODO()
val n3 = select(SubInv<SubInv<Int>>(), createInvInv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out Inv<kotlin.Int>>")!>n3<!>
}
fun testCaptured(cSub: SubInv<out Number>, cInv: Inv<out Number>) {
val c1 = select(cInv, SubInv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c1<!>
val c2 = select(cSub, Inv())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c2<!>
}
fun testVariableWithBound() {
fun <K : Number> createWithNumberBound(): Inv<K> = TODO()
fun <K : <!FINAL_UPPER_BOUND!>Int<!>> createWithIntBound(): Inv<K> = TODO()
val c1 = select(SubInv<Int>(), createWithNumberBound())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>c1<!>
// should be an error after variable fixation
val c2 = select(SubInv<String>(), createWithNumberBound())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.String>")!>c2<!>
// should be an error after variable fixation
val c3 = select(SubInv<Double>(), createWithIntBound())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Double>")!>c3<!>
}
fun testCapturedVariable() {
fun <K> createInvOut(): Inv<out K> = TODO()
fun <V> createSubInvOut(): SubInv<out V> = TODO()
fun <K> createInvIn(): Inv<in K> = TODO()
val c1 = select(SubInv<Number>(), createInvOut())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Number>")!>c1<!>
val c2 = select(createSubInvOut<Number>(), createInvOut())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c2<!>
val c3 = select(SubInv<Number>(), createInvIn())
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c3<!>
}
@@ -0,0 +1,23 @@
package
public fun </*0*/ T> select(/*0*/ x: T, /*1*/ y: T): T
public fun testCaptured(/*0*/ cSub: SubInv<out kotlin.Number>, /*1*/ cInv: Inv<out kotlin.Number>): kotlin.Unit
public fun testCapturedVariable(): kotlin.Unit
public fun testNested(): kotlin.Unit
public fun testNullability(): kotlin.Unit
public fun testSimple(): kotlin.Unit
public fun testVariableWithBound(): kotlin.Unit
public open class Inv</*0*/ K> {
public constructor Inv</*0*/ K>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class SubInv</*0*/ V> : Inv<V> {
public constructor SubInv</*0*/ V>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,5 @@
// !WITH_NEW_INFERENCE
fun <T : Any> nullable(): T? = null
val value = nullable<Int>() ?: <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>nullable()<!>
@@ -0,0 +1,4 @@
package
public val value: kotlin.Int
public fun </*0*/ T : kotlin.Any> nullable(): T?
@@ -0,0 +1,19 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_EXPRESSION
fun test(condition: Boolean) {
val list1 =
if (condition) mutableListOf<Int>()
else emptyList()
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Int>")!>list1<!>
val list2 =
if (condition) mutableListOf()
else emptyList<Int>()
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Int>")!>list2<!>
}
fun <T> mutableListOf(): MutableList<T> = TODO()
fun <T> emptyList(): List<T> = TODO()
@@ -0,0 +1,5 @@
package
public fun </*0*/ T> emptyList(): kotlin.collections.List<T>
public fun </*0*/ T> mutableListOf(): kotlin.collections.MutableList<T>
public fun test(/*0*/ condition: kotlin.Boolean): kotlin.Unit
@@ -0,0 +1,30 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
// FILE: Inv2.java
public class Inv2<K, V> {}
// FILE: JavaSet.java
public class JavaSet {
public static <E> java.util.Set<E> newIdentityHashSet() { return null; }
public static <K, V> V get(Inv2<K, V> slice, K key) { return null; }
}
// FILE: test.kt
fun <K> select(x: K, y: K): K = x
fun <K, T> addElementToSlice(
slice: Inv2<K, MutableCollection<T>>,
key: K,
element: T
) {
val a = select(JavaSet.get(slice, key), JavaSet.newIdentityHashSet())
<!DEBUG_INFO_EXPRESSION_TYPE("(kotlin.collections.MutableCollection<T>..kotlin.collections.Collection<T>?)")!>a<!>
a.add(element)
}
@@ -0,0 +1,22 @@
package
public fun </*0*/ K, /*1*/ T> addElementToSlice(/*0*/ slice: Inv2<K, kotlin.collections.MutableCollection<T>>, /*1*/ key: K, /*2*/ element: T): kotlin.Unit
public fun </*0*/ K> select(/*0*/ x: K, /*1*/ y: K): K
public open class Inv2</*0*/ K : kotlin.Any!, /*1*/ V : kotlin.Any!> {
public constructor Inv2</*0*/ K : kotlin.Any!, /*1*/ V : kotlin.Any!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class JavaSet {
public constructor JavaSet()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun </*0*/ K : kotlin.Any!, /*1*/ V : kotlin.Any!> get(/*0*/ slice: Inv2<K!, V!>!, /*1*/ key: K!): V!
public open fun </*0*/ E : kotlin.Any!> newIdentityHashSet(): kotlin.collections.(Mutable)Set<E!>!
}
@@ -0,0 +1,12 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
class Inv<T>
fun <K> select(x: K, y: K): K = x
fun <V> outToOut(x: Inv<out V>): Inv<out V> = TODO()
fun test(invOutAny: Inv<out Any>, invAny: Inv<Any>) {
val a: Inv<out Any> = select(invAny, outToOut(invOutAny))
}
@@ -0,0 +1,12 @@
package
public fun </*0*/ V> outToOut(/*0*/ x: Inv<out V>): Inv<out V>
public fun </*0*/ K> select(/*0*/ x: K, /*1*/ y: K): K
public fun test(/*0*/ invOutAny: Inv<out kotlin.Any>, /*1*/ invAny: Inv<kotlin.Any>): kotlin.Unit
public final class Inv</*0*/ T> {
public constructor Inv</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -11,13 +11,13 @@ fun <K> elvisExact(x: K?, y: K): @kotlin.internal.Exact K = y
fun <T : Number> materialize(): T? = null fun <T : Number> materialize(): T? = null
fun test(nullableSample: ISample, any: Any) { fun test(nullableSample: ISample, any: Any) {
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!>elvisSimple( <!DEBUG_INFO_EXPRESSION_TYPE("ISample?")!>elvisSimple(
nullableSample, nullableSample,
<!DEBUG_INFO_EXPRESSION_TYPE("{ISample & Number}?")!>materialize()<!> <!DEBUG_INFO_EXPRESSION_TYPE("{ISample & Number}?")!>materialize()<!>
)<!> )<!>
elvisSimple( elvisSimple(
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!>elvisSimple(nullableSample, materialize())<!>, <!DEBUG_INFO_EXPRESSION_TYPE("ISample?")!>elvisSimple(nullableSample, materialize())<!>,
any any
) )
@@ -10183,6 +10183,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstFromNullableChildAndNonParameterizedType.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstFromNullableChildAndNonParameterizedType.kt");
} }
@TestMetadata("cstWithTypeContainingNonFixedVariable.kt")
public void testCstWithTypeContainingNonFixedVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstWithTypeContainingNonFixedVariable.kt");
}
@TestMetadata("dontCaptureTypeVariable.kt") @TestMetadata("dontCaptureTypeVariable.kt")
public void testDontCaptureTypeVariable() throws Exception { public void testDontCaptureTypeVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/dontCaptureTypeVariable.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/dontCaptureTypeVariable.kt");
@@ -10213,6 +10218,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt31969.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt31969.kt");
} }
@TestMetadata("kt32818.kt")
public void testKt32818() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt32818.kt");
}
@TestMetadata("kt33197.kt")
public void testKt33197() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt33197.kt");
}
@TestMetadata("kt3372toCollection.kt") @TestMetadata("kt3372toCollection.kt")
public void testKt3372toCollection() throws Exception { public void testKt3372toCollection() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt");
@@ -10238,6 +10253,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt");
} }
@TestMetadata("nonFixedVariableInsideFlexibleType.kt")
public void testNonFixedVariableInsideFlexibleType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableInsideFlexibleType.kt");
}
@TestMetadata("outProjectedTypeToOutProjected.kt")
public void testOutProjectedTypeToOutProjected() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/outProjectedTypeToOutProjected.kt");
}
@TestMetadata("postponedCompletionWithExactAnnotation.kt") @TestMetadata("postponedCompletionWithExactAnnotation.kt")
public void testPostponedCompletionWithExactAnnotation() throws Exception { public void testPostponedCompletionWithExactAnnotation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt");
@@ -10178,6 +10178,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstFromNullableChildAndNonParameterizedType.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstFromNullableChildAndNonParameterizedType.kt");
} }
@TestMetadata("cstWithTypeContainingNonFixedVariable.kt")
public void testCstWithTypeContainingNonFixedVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/cstWithTypeContainingNonFixedVariable.kt");
}
@TestMetadata("dontCaptureTypeVariable.kt") @TestMetadata("dontCaptureTypeVariable.kt")
public void testDontCaptureTypeVariable() throws Exception { public void testDontCaptureTypeVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/dontCaptureTypeVariable.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/dontCaptureTypeVariable.kt");
@@ -10208,6 +10213,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt31969.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt31969.kt");
} }
@TestMetadata("kt32818.kt")
public void testKt32818() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt32818.kt");
}
@TestMetadata("kt33197.kt")
public void testKt33197() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt33197.kt");
}
@TestMetadata("kt3372toCollection.kt") @TestMetadata("kt3372toCollection.kt")
public void testKt3372toCollection() throws Exception { public void testKt3372toCollection() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt");
@@ -10233,6 +10248,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt");
} }
@TestMetadata("nonFixedVariableInsideFlexibleType.kt")
public void testNonFixedVariableInsideFlexibleType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nonFixedVariableInsideFlexibleType.kt");
}
@TestMetadata("outProjectedTypeToOutProjected.kt")
public void testOutProjectedTypeToOutProjected() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/outProjectedTypeToOutProjected.kt");
}
@TestMetadata("postponedCompletionWithExactAnnotation.kt") @TestMetadata("postponedCompletionWithExactAnnotation.kt")
public void testPostponedCompletionWithExactAnnotation() throws Exception { public void testPostponedCompletionWithExactAnnotation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt"); runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt");
@@ -10334,6 +10334,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("genericElvisWithMoreSpecificLHS.kt")
public void testGenericElvisWithMoreSpecificLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithMoreSpecificLHS.kt");
}
@TestMetadata("genericElvisWithNullLHS.kt")
public void testGenericElvisWithNullLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithNullLHS.kt");
}
@TestMetadata("genericNull.kt") @TestMetadata("genericNull.kt")
public void testGenericNull() throws Exception { public void testGenericNull() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericNull.kt"); runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
@@ -10334,6 +10334,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("genericElvisWithMoreSpecificLHS.kt")
public void testGenericElvisWithMoreSpecificLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithMoreSpecificLHS.kt");
}
@TestMetadata("genericElvisWithNullLHS.kt")
public void testGenericElvisWithNullLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithNullLHS.kt");
}
@TestMetadata("genericNull.kt") @TestMetadata("genericNull.kt")
public void testGenericNull() throws Exception { public void testGenericNull() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericNull.kt"); runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
@@ -9214,6 +9214,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
} }
@TestMetadata("genericElvisWithMoreSpecificLHS.kt")
public void testGenericElvisWithMoreSpecificLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithMoreSpecificLHS.kt");
}
@TestMetadata("genericElvisWithNullLHS.kt")
public void testGenericElvisWithNullLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithNullLHS.kt");
}
@TestMetadata("genericNull.kt") @TestMetadata("genericNull.kt")
public void testGenericNull() throws Exception { public void testGenericNull() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericNull.kt"); runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.types.refinement.TypeRefinement
open class ClassicTypeCheckerContext( open class ClassicTypeCheckerContext(
val errorTypeEqualsToAnything: Boolean, val errorTypeEqualsToAnything: Boolean,
val stubTypeEqualsToAnything: Boolean = true,
val allowedTypeVariable: Boolean = true, val allowedTypeVariable: Boolean = true,
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default
) : ClassicTypeSystemContext, AbstractTypeCheckerContext() { ) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
@@ -43,6 +44,9 @@ open class ClassicTypeCheckerContext(
override val isErrorTypeEqualsToAnything: Boolean override val isErrorTypeEqualsToAnything: Boolean
get() = errorTypeEqualsToAnything get() = errorTypeEqualsToAnything
override val isStubTypeEqualsToAnything: Boolean
get() = stubTypeEqualsToAnything
override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean { override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean {
require(a is TypeConstructor, a::errorMessage) require(a is TypeConstructor, a::errorMessage)
require(b is TypeConstructor, b::errorMessage) require(b is TypeConstructor, b::errorMessage)
@@ -321,8 +321,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
} }
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext { override fun newBaseTypeCheckerContext(
return ClassicTypeCheckerContext(errorTypesEqualToAnything) errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext {
return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything)
} }
override fun nullableNothingType(): SimpleTypeMarker { override fun nullableNothingType(): SimpleTypeMarker {
@@ -148,7 +148,7 @@ object NullabilityChecker {
fun isSubtypeOfAny(type: UnwrappedType): Boolean = fun isSubtypeOfAny(type: UnwrappedType): Boolean =
SimpleClassicTypeSystemContext SimpleClassicTypeSystemContext
.newBaseTypeCheckerContext(false) .newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
.hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible) .hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
} }
@@ -31,6 +31,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
abstract val isErrorTypeEqualsToAnything: Boolean abstract val isErrorTypeEqualsToAnything: Boolean
abstract val isStubTypeEqualsToAnything: Boolean
protected var argumentsDepth = 0 protected var argumentsDepth = 0
@@ -151,12 +153,22 @@ object AbstractTypeChecker {
@JvmField @JvmField
var RUN_SLOW_ASSERTIONS = false var RUN_SLOW_ASSERTIONS = false
fun isSubtypeOf(context: TypeCheckerProviderContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean { fun isSubtypeOf(
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true), subType, superType) context: TypeCheckerProviderContext,
subType: KotlinTypeMarker,
superType: KotlinTypeMarker,
stubTypesEqualToAnything: Boolean = true
): Boolean {
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true, stubTypesEqualToAnything), subType, superType)
} }
fun equalTypes(context: TypeCheckerProviderContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean { fun equalTypes(
return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false), a, b) context: TypeCheckerProviderContext,
a: KotlinTypeMarker,
b: KotlinTypeMarker,
stubTypesEqualToAnything: Boolean = true
): Boolean {
return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b)
} }
fun isSubtypeOf(context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean { fun isSubtypeOf(context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
@@ -358,7 +370,7 @@ object AbstractTypeChecker {
) )
} }
if (subType.isStubType() || superType.isStubType()) return true if (subType.isStubType() || superType.isStubType()) return isStubTypeEqualsToAnything
val superTypeCaptured = superType.asCapturedType() val superTypeCaptured = superType.asCapturedType()
val lowerType = superTypeCaptured?.lowerType() val lowerType = superTypeCaptured?.lowerType()
@@ -482,7 +494,13 @@ object AbstractNullabilityChecker {
context.runIsPossibleSubtype(subType, superType) context.runIsPossibleSubtype(subType, superType)
fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean = fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean =
AbstractNullabilityChecker.isSubtypeOfAny(context.newBaseTypeCheckerContext(false), type) AbstractNullabilityChecker.isSubtypeOfAny(
context.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = true
),
type
)
fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean = fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean =
with(context) { with(context) {
@@ -540,12 +558,22 @@ object AbstractNullabilityChecker {
} }
fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) = fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
newBaseTypeCheckerContext(false).hasPathByNotMarkedNullableNodes(start, end) newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
.hasPathByNotMarkedNullableNodes(start, end)
fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) = fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
anySupertype(start, { anySupertype(
it.isNothing() || (!it.isMarkedNullable() && isEqualTypeConstructors(it.typeConstructor(), end)) start,
}) { { isApplicableAsEndNode(it, end) },
if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible { if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible }
} )
private fun AbstractTypeCheckerContext.isApplicableAsEndNode(type: SimpleTypeMarker, end: TypeConstructorMarker): Boolean {
if (type.isNothing()) return true
if (type.isMarkedNullable()) return false
if (isStubTypeEqualsToAnything && type.isStubType()) return true
return isEqualTypeConstructors(type.typeConstructor(), end)
}
} }
@@ -63,7 +63,10 @@ interface TypeSystemTypeFactoryContext {
interface TypeCheckerProviderContext { interface TypeCheckerProviderContext {
fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext fun newBaseTypeCheckerContext(
errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext
} }
interface TypeSystemCommonSuperTypesContext : TypeSystemContext, TypeSystemTypeFactoryContext, TypeCheckerProviderContext { interface TypeSystemCommonSuperTypesContext : TypeSystemContext, TypeSystemTypeFactoryContext, TypeCheckerProviderContext {
@@ -74,9 +77,12 @@ interface TypeSystemCommonSuperTypesContext : TypeSystemContext, TypeSystemTypeF
val isErrorTypeAllowed: Boolean val isErrorTypeAllowed: Boolean
fun KotlinTypeMarker.anySuperTypeConstructor(predicate: (TypeConstructorMarker) -> Boolean) = fun KotlinTypeMarker.anySuperTypeConstructor(predicate: (TypeConstructorMarker) -> Boolean) =
newBaseTypeCheckerContext(false).anySupertype(lowerBoundIfFlexible(), { newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
predicate(it.typeConstructor()) .anySupertype(
}, { AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible }) lowerBoundIfFlexible(),
{ predicate(it.typeConstructor()) },
{ AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible }
)
fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean
@@ -7954,6 +7954,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
} }
@TestMetadata("genericElvisWithMoreSpecificLHS.kt")
public void testGenericElvisWithMoreSpecificLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithMoreSpecificLHS.kt");
}
@TestMetadata("genericElvisWithNullLHS.kt")
public void testGenericElvisWithNullLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithNullLHS.kt");
}
@TestMetadata("genericNull.kt") @TestMetadata("genericNull.kt")
public void testGenericNull() throws Exception { public void testGenericNull() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericNull.kt"); runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
@@ -9039,6 +9039,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/elvis"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
} }
@TestMetadata("genericElvisWithMoreSpecificLHS.kt")
public void testGenericElvisWithMoreSpecificLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithMoreSpecificLHS.kt");
}
@TestMetadata("genericElvisWithNullLHS.kt")
public void testGenericElvisWithNullLHS() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericElvisWithNullLHS.kt");
}
@TestMetadata("genericNull.kt") @TestMetadata("genericNull.kt")
public void testGenericNull() throws Exception { public void testGenericNull() throws Exception {
runTest("compiler/testData/codegen/box/elvis/genericNull.kt"); runTest("compiler/testData/codegen/box/elvis/genericNull.kt");