[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:
@@ -10,8 +10,11 @@ import org.jetbrains.kotlin.fir.types.ConeTypeContext
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
||||
|
||||
private class SessionBasedTypeContext(override val session: FirSession) : ConeTypeContext {
|
||||
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext {
|
||||
return ConeTypeCheckerContext(errorTypesEqualToAnything, session)
|
||||
override fun newBaseTypeCheckerContext(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext {
|
||||
return ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -85,9 +85,11 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
|
||||
return ConeStarProjection
|
||||
}
|
||||
|
||||
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext {
|
||||
return ConeTypeCheckerContext(errorTypesEqualToAnything, session)
|
||||
}
|
||||
override fun newBaseTypeCheckerContext(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext =
|
||||
ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)
|
||||
|
||||
override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean {
|
||||
require(this is ConeKotlinType)
|
||||
@@ -167,7 +169,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext,
|
||||
override fun Collection<KotlinTypeMarker>.singleBestRepresentative(): KotlinTypeMarker? {
|
||||
if (this.size == 1) return this.first()
|
||||
|
||||
val context = newBaseTypeCheckerContext(true)
|
||||
val context = newBaseTypeCheckerContext(errorTypesEqualToAnything = true, stubTypesEqualToAnything = true)
|
||||
return this.firstOrNull { candidate ->
|
||||
this.all { other ->
|
||||
// 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) :
|
||||
AbstractTypeCheckerContext(), ConeTypeContext {
|
||||
class ConeTypeCheckerContext(
|
||||
override val isErrorTypeEqualsToAnything: Boolean,
|
||||
override val isStubTypeEqualsToAnything: Boolean,
|
||||
override val session: FirSession
|
||||
) : AbstractTypeCheckerContext(), ConeTypeContext {
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy {
|
||||
if (type.argumentsCount() == 0) return SupertypesPolicy.LowerIfFlexible
|
||||
require(type is ConeKotlinType)
|
||||
@@ -539,10 +542,13 @@ class ConeTypeCheckerContext(override val isErrorTypeEqualsToAnything: Boolean,
|
||||
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
||||
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)
|
||||
this
|
||||
else
|
||||
ConeTypeCheckerContext(errorTypesEqualToAnything, session)
|
||||
ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session)
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
|
||||
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)
|
||||
|
||||
fun getCorrespondingSupertypes(
|
||||
|
||||
@@ -12,7 +12,7 @@ object ConeNullabilityChecker {
|
||||
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
|
||||
val actualType = with(context) { type.lowerBoundIfFlexible() }
|
||||
return with(AbstractNullabilityChecker) {
|
||||
context.newBaseTypeCheckerContext(false)
|
||||
context.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
|
||||
.hasNotNullSupertype(actualType, AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible)
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -10176,6 +10176,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
|
||||
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")
|
||||
public void testDontCaptureTypeVariable() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testKt3372toCollection() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testPostponedCompletionWithExactAnnotation() throws Exception {
|
||||
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.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.model.KotlinTypeMarker
|
||||
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 val isErrorTypeEqualsToAnything = false
|
||||
override val isErrorTypeEqualsToAnything get() = false
|
||||
override val isStubTypeEqualsToAnything get() = false
|
||||
|
||||
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
||||
get() = false
|
||||
|
||||
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext {
|
||||
return IrTypeCheckerContext(irBuiltIns)
|
||||
}
|
||||
override fun newBaseTypeCheckerContext(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext = IrTypeCheckerContext(irBuiltIns)
|
||||
|
||||
override fun KotlinTypeMarker.isUninferredParameter(): Boolean = false
|
||||
|
||||
|
||||
+46
-12
@@ -68,7 +68,8 @@ object NewCommonSuperTypeCalculator {
|
||||
depth: Int
|
||||
): SimpleTypeMarker {
|
||||
// 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 commonSuperType = commonSuperTypeForNotNullTypes(notNullTypes, depth)
|
||||
@@ -94,7 +95,8 @@ object NewCommonSuperTypeCalculator {
|
||||
val uniqueTypes = arrayListOf<SimpleTypeMarker>()
|
||||
for (type in types) {
|
||||
val isNewUniqueType = uniqueTypes.all {
|
||||
!AbstractTypeChecker.equalTypes(this, it, type) || it.typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
!AbstractTypeChecker.equalTypes(this, it, type, stubTypesEqualToAnything = false) ||
|
||||
it.typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
}
|
||||
if (isNewUniqueType) {
|
||||
uniqueTypes += type
|
||||
@@ -111,7 +113,9 @@ object NewCommonSuperTypeCalculator {
|
||||
while (iterator.hasNext()) {
|
||||
val potentialSubtype = iterator.next()
|
||||
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()
|
||||
@@ -120,13 +124,26 @@ object NewCommonSuperTypeCalculator {
|
||||
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(
|
||||
types: List<SimpleTypeMarker>,
|
||||
depth: Int
|
||||
): SimpleTypeMarker {
|
||||
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()
|
||||
|
||||
val explicitSupertypes = filterSupertypes(uniqueTypes)
|
||||
@@ -134,12 +151,23 @@ object NewCommonSuperTypeCalculator {
|
||||
findErrorTypeInSupertypesIfItIsNeeded(explicitSupertypes)?.let { return it }
|
||||
|
||||
findCommonIntegerLiteralTypesSuperType(explicitSupertypes)?.let { return it }
|
||||
// IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
|
||||
|
||||
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
|
||||
for (type in types) {
|
||||
collectAllSupertypes(type).firstOrNull { it.isError() }?.let { return it.toErrorType() }
|
||||
@@ -187,7 +215,7 @@ object NewCommonSuperTypeCalculator {
|
||||
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>.
|
||||
@@ -206,11 +234,17 @@ object NewCommonSuperTypeCalculator {
|
||||
val parameter = constructor.getParameter(index)
|
||||
var thereIsStar = false
|
||||
val typeProjections = correspondingSuperTypes.mapNotNull {
|
||||
it.getArgumentOrNull(index)?.let {
|
||||
if (it.isStarProjection()) {
|
||||
thereIsStar = true
|
||||
null
|
||||
} else it
|
||||
it.getArgumentOrNull(index)?.let { typeArgument ->
|
||||
when {
|
||||
typeArgument.isStarProjection() -> {
|
||||
thereIsStar = true
|
||||
null
|
||||
}
|
||||
|
||||
typeArgument.getType().lowerBoundIfFlexible().isStubType() -> null
|
||||
|
||||
else -> typeArgument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ class PostponedArgumentsAnalyzer(
|
||||
) {
|
||||
interface Context : TypeSystemInferenceExtensionContext {
|
||||
fun buildCurrentSubstitutor(additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>): TypeSubstitutorMarker
|
||||
fun buildNotFixedVariablesToStubTypesSubstitutor(): TypeSubstitutorMarker
|
||||
fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker>
|
||||
|
||||
// type can be proper if it not contains not fixed type variables
|
||||
|
||||
+6
-4
@@ -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.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.types.model.TypeSubstitutorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
|
||||
fun ConstraintStorage.buildCurrentSubstitutor(
|
||||
context: TypeSystemInferenceExtensionContext,
|
||||
@@ -50,6 +47,11 @@ fun ConstraintStorage.buildAbstractResultingSubstitutor(context: TypeSystemInfer
|
||||
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 {
|
||||
return buildAbstractResultingSubstitutor(context) as NewTypeSubstitutor
|
||||
}
|
||||
|
||||
+3
@@ -18,6 +18,9 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
|
||||
override val isErrorTypeEqualsToAnything: Boolean
|
||||
get() = true
|
||||
|
||||
override val isStubTypeEqualsToAnything: Boolean
|
||||
get() = true
|
||||
|
||||
abstract fun isMyTypeVariable(type: SimpleTypeMarker): Boolean
|
||||
|
||||
// super and sub type isSingleClassifierType
|
||||
|
||||
+1
-2
@@ -65,7 +65,6 @@ class ConstraintInjector(
|
||||
addSubTypeConstraintAndIncorporateIt(c, b, a, incorporationPosition)
|
||||
}
|
||||
|
||||
|
||||
private fun addSubTypeConstraintAndIncorporateIt(
|
||||
c: Context,
|
||||
lowerType: KotlinTypeMarker,
|
||||
@@ -126,7 +125,7 @@ class ConstraintInjector(
|
||||
val possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>
|
||||
) : AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c {
|
||||
|
||||
val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything)
|
||||
val baseContext: AbstractTypeCheckerContext = newBaseTypeCheckerContext(isErrorTypeEqualsToAnything, isStubTypeEqualsToAnything)
|
||||
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy {
|
||||
return baseContext.substitutionSupertypePolicy(type)
|
||||
|
||||
+27
-18
@@ -73,29 +73,26 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker {
|
||||
"and class: ${type::class.java.canonicalName}. type.toString() = $type"
|
||||
}
|
||||
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(
|
||||
"Illegal type substitutor: $this, " +
|
||||
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
|
||||
"original lower type: '${capturedType.lowerType}"
|
||||
)
|
||||
val innerType = capturedType.lowerType ?: capturedType.constructor.projection.type.unwrap()
|
||||
val substitutedInnerType = substitute(innerType, keepAnnotation, runCapturedChecks = false)
|
||||
|
||||
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) {
|
||||
typeConstructor.supertypes.forEach { supertype ->
|
||||
substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let {
|
||||
throw IllegalStateException(
|
||||
"Illegal type substitutor: $this, " +
|
||||
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
|
||||
"original supertype: '$supertype'"
|
||||
)
|
||||
throwExceptionAboutInvalidCapturedSubstitution(capturedType, supertype, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +127,18 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker {
|
||||
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(
|
||||
type: SimpleType,
|
||||
keepAnnotation: Boolean,
|
||||
|
||||
+33
-3
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
||||
|
||||
class ResultTypeResolver(
|
||||
@@ -30,6 +31,7 @@ class ResultTypeResolver(
|
||||
) {
|
||||
interface Context : TypeSystemInferenceExtensionContext {
|
||||
fun isProperType(type: KotlinTypeMarker): Boolean
|
||||
fun buildNotFixedVariablesToStubTypesSubstitutor(): TypeSubstitutorMarker
|
||||
}
|
||||
|
||||
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker {
|
||||
@@ -83,9 +85,10 @@ class ResultTypeResolver(
|
||||
}
|
||||
|
||||
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 lowerConstraintTypes = prepareLowerConstraints(variableWithConstraints.constraints)
|
||||
|
||||
if (lowerConstraintTypes.isNotEmpty()) {
|
||||
val types = sinkIntegerLiteralTypes(lowerConstraintTypes)
|
||||
val commonSuperType = with(NewCommonSuperTypeCalculator) {
|
||||
this@findSubType.commonSuperType(types)
|
||||
}
|
||||
@@ -116,6 +119,33 @@ class ResultTypeResolver(
|
||||
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> {
|
||||
return types.sortedBy { type ->
|
||||
|
||||
|
||||
+5
@@ -307,6 +307,11 @@ class NewConstraintSystemImpl(
|
||||
return storage.buildCurrentSubstitutor(this, additionalBindings)
|
||||
}
|
||||
|
||||
override fun buildNotFixedVariablesToStubTypesSubstitutor(): TypeSubstitutorMarker {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
return storage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(this)
|
||||
}
|
||||
|
||||
override fun bindingStubsForPostponedVariables(): Map<TypeVariableMarker, StubTypeMarker> {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
// 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"
|
||||
}
|
||||
+3
-3
@@ -9,9 +9,9 @@ class None<T> : Option<T>
|
||||
fun <T> bind(r: Option<T>): Option<T> {
|
||||
return if (r is Some) {
|
||||
// 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
|
||||
if (true) None() else <!NI;DEBUG_INFO_SMARTCAST!>r<!>
|
||||
if (true) None() else r
|
||||
}
|
||||
else r
|
||||
}
|
||||
@@ -36,7 +36,7 @@ fun <T> bindWhen(r: Option<T>): Option<T> {
|
||||
return when (r) {
|
||||
is Some -> {
|
||||
// Works correctly
|
||||
if (true) None() else <!NI;DEBUG_INFO_SMARTCAST!>r<!>
|
||||
if (true) None() else r
|
||||
}
|
||||
else -> r
|
||||
}
|
||||
|
||||
Vendored
+90
@@ -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<!>
|
||||
}
|
||||
compiler/testData/diagnostics/tests/inference/commonSystem/cstWithTypeContainingNonFixedVariable.txt
Vendored
+23
@@ -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
|
||||
Vendored
+30
@@ -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)
|
||||
}
|
||||
Vendored
+22
@@ -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!>!
|
||||
}
|
||||
Vendored
+12
@@ -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))
|
||||
}
|
||||
Vendored
+12
@@ -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
|
||||
}
|
||||
+2
-2
@@ -11,13 +11,13 @@ fun <K> elvisExact(x: K?, y: K): @kotlin.internal.Exact K = y
|
||||
fun <T : Number> materialize(): T? = null
|
||||
|
||||
fun test(nullableSample: ISample, any: Any) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!>elvisSimple(
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample?")!>elvisSimple(
|
||||
nullableSample,
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("{ISample & Number}?")!>materialize()<!>
|
||||
)<!>
|
||||
|
||||
elvisSimple(
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!>elvisSimple(nullableSample, materialize())<!>,
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample?")!>elvisSimple(nullableSample, materialize())<!>,
|
||||
any
|
||||
)
|
||||
|
||||
|
||||
@@ -10183,6 +10183,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
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")
|
||||
public void testDontCaptureTypeVariable() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testKt3372toCollection() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testPostponedCompletionWithExactAnnotation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt");
|
||||
|
||||
Generated
+25
@@ -10178,6 +10178,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
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")
|
||||
public void testDontCaptureTypeVariable() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testKt3372toCollection() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testPostponedCompletionWithExactAnnotation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt");
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGenericNull() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGenericNull() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGenericNull() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
|
||||
open class ClassicTypeCheckerContext(
|
||||
val errorTypeEqualsToAnything: Boolean,
|
||||
val stubTypeEqualsToAnything: Boolean = true,
|
||||
val allowedTypeVariable: Boolean = true,
|
||||
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default
|
||||
) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
|
||||
@@ -43,6 +44,9 @@ open class ClassicTypeCheckerContext(
|
||||
override val isErrorTypeEqualsToAnything: Boolean
|
||||
get() = errorTypeEqualsToAnything
|
||||
|
||||
override val isStubTypeEqualsToAnything: Boolean
|
||||
get() = stubTypeEqualsToAnything
|
||||
|
||||
override fun areEqualTypeConstructors(a: TypeConstructorMarker, b: TypeConstructorMarker): Boolean {
|
||||
require(a is TypeConstructor, a::errorMessage)
|
||||
require(b is TypeConstructor, b::errorMessage)
|
||||
|
||||
@@ -321,8 +321,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
|
||||
}
|
||||
|
||||
|
||||
override fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext {
|
||||
return ClassicTypeCheckerContext(errorTypesEqualToAnything)
|
||||
override fun newBaseTypeCheckerContext(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext {
|
||||
return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything)
|
||||
}
|
||||
|
||||
override fun nullableNothingType(): SimpleTypeMarker {
|
||||
|
||||
@@ -148,7 +148,7 @@ object NullabilityChecker {
|
||||
|
||||
fun isSubtypeOfAny(type: UnwrappedType): Boolean =
|
||||
SimpleClassicTypeSystemContext
|
||||
.newBaseTypeCheckerContext(false)
|
||||
.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
|
||||
.hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
|
||||
abstract val isErrorTypeEqualsToAnything: Boolean
|
||||
|
||||
abstract val isStubTypeEqualsToAnything: Boolean
|
||||
|
||||
protected var argumentsDepth = 0
|
||||
|
||||
|
||||
@@ -151,12 +153,22 @@ object AbstractTypeChecker {
|
||||
@JvmField
|
||||
var RUN_SLOW_ASSERTIONS = false
|
||||
|
||||
fun isSubtypeOf(context: TypeCheckerProviderContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true), subType, superType)
|
||||
fun isSubtypeOf(
|
||||
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 {
|
||||
return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false), a, b)
|
||||
fun equalTypes(
|
||||
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 {
|
||||
@@ -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 lowerType = superTypeCaptured?.lowerType()
|
||||
@@ -482,7 +494,13 @@ object AbstractNullabilityChecker {
|
||||
context.runIsPossibleSubtype(subType, superType)
|
||||
|
||||
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 =
|
||||
with(context) {
|
||||
@@ -540,12 +558,22 @@ object AbstractNullabilityChecker {
|
||||
}
|
||||
|
||||
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) =
|
||||
anySupertype(start, {
|
||||
it.isNothing() || (!it.isMarkedNullable() && isEqualTypeConstructors(it.typeConstructor(), end))
|
||||
}) {
|
||||
if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
anySupertype(
|
||||
start,
|
||||
{ isApplicableAsEndNode(it, end) },
|
||||
{ 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 {
|
||||
fun newBaseTypeCheckerContext(errorTypesEqualToAnything: Boolean): AbstractTypeCheckerContext
|
||||
fun newBaseTypeCheckerContext(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext
|
||||
}
|
||||
|
||||
interface TypeSystemCommonSuperTypesContext : TypeSystemContext, TypeSystemTypeFactoryContext, TypeCheckerProviderContext {
|
||||
@@ -74,9 +77,12 @@ interface TypeSystemCommonSuperTypesContext : TypeSystemContext, TypeSystemTypeF
|
||||
val isErrorTypeAllowed: Boolean
|
||||
|
||||
fun KotlinTypeMarker.anySuperTypeConstructor(predicate: (TypeConstructorMarker) -> Boolean) =
|
||||
newBaseTypeCheckerContext(false).anySupertype(lowerBoundIfFlexible(), {
|
||||
predicate(it.typeConstructor())
|
||||
}, { AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible })
|
||||
newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
|
||||
.anySupertype(
|
||||
lowerBoundIfFlexible(),
|
||||
{ predicate(it.typeConstructor()) },
|
||||
{ AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible }
|
||||
)
|
||||
|
||||
fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean
|
||||
|
||||
|
||||
Generated
+10
@@ -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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGenericNull() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGenericNull() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/elvis/genericNull.kt");
|
||||
|
||||
Reference in New Issue
Block a user